Merge remote-tracking branch 'ruoyi/master'

# Conflicts:
#	README.md
#	ruoyi-ui/src/views/index.vue
#	ruoyi-ui/vue.config.js
rf
tony 2024-03-12 08:10:01 +08:00
commit f4b69ac55a
21 changed files with 193 additions and 48 deletions

10
pom.xml
View File

@ -24,9 +24,8 @@
<kaptcha.version>2.3.3</kaptcha.version>
<pagehelper.boot.version>1.4.7</pagehelper.boot.version>
<fastjson.version>2.0.43</fastjson.version>
<oshi.version>6.4.8</oshi.version>
<oshi.version>6.4.13</oshi.version>
<commons.io.version>2.13.0</commons.io.version>
<commons.collections.version>3.2.2</commons.collections.version>
<poi.version>4.1.2</poi.version>
<velocity.version>2.3</velocity.version>
<jwt.version>0.9.1</jwt.version>
@ -108,13 +107,6 @@
<version>${velocity.version}</version>
</dependency>
<!-- collections工具类 -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>${commons.collections.version}</version>
</dependency>
<!-- 阿里JSON解析器 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>

View File

@ -5,7 +5,7 @@ ruoyi:
# 版本
version: 3.8.7
# 版权年份
copyrightYear: 2023
copyrightYear: 2024
# 文件路径 示例( Windows配置D:/ruoyi/uploadPathLinux配置 /home/ruoyi/uploadPath
profile: D:/ruoyi/uploadPath
# 获取ip地址开关

View File

@ -157,11 +157,11 @@ public class Constants
/**
* 访
*/
public static final String[] JOB_WHITELIST_STR = { "com.ruoyi" };
public static final String[] JOB_WHITELIST_STR = { "com.ruoyi.quartz.task" };
/**
*
*/
public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
"org.springframework", "org.apache", "com.ruoyi.common.utils.file", "com.ruoyi.common.config" };
"org.springframework", "org.apache", "com.ruoyi.common.utils.file", "com.ruoyi.common.config", "com.ruoyi.generator" };
}

View File

@ -74,7 +74,7 @@ public class HttpUtils
URLConnection connection = realUrl.openConnection();
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
connection.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
connection.connect();
in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));
String line;
@ -136,7 +136,7 @@ public class HttpUtils
URLConnection conn = realUrl.openConnection();
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("contentType", "utf-8");
conn.setDoOutput(true);
@ -202,7 +202,7 @@ public class HttpUtils
HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("contentType", "utf-8");
conn.setDoOutput(true);

View File

@ -27,8 +27,13 @@ public class XssValidator implements ConstraintValidator<Xss, String>
public static boolean containsHtml(String value)
{
StringBuilder sHtml = new StringBuilder();
Pattern pattern = Pattern.compile(HTML_PATTERN);
Matcher matcher = pattern.matcher(value);
return matcher.matches();
while (matcher.find())
{
sHtml.append(matcher.group());
}
return pattern.matcher(sHtml).matches();
}
}

View File

@ -12,6 +12,7 @@ import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.manager.AsyncManager;
@ -45,8 +46,8 @@ public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler
// 删除用户缓存记录
tokenService.delLoginUser(loginUser.getToken());
// 记录用户退出日志
AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, "退出成功"));
AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, MessageUtils.message("user.logout.success")));
}
ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.success("退出成功")));
ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.success(MessageUtils.message("user.logout.success"))));
}
}

View File

@ -6,15 +6,11 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.exception.user.UserPasswordRetryLimitExceedException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.framework.security.context.AuthenticationContextHolder;
/**
@ -60,16 +56,12 @@ public class SysPasswordService
if (retryCount >= Integer.valueOf(maxRetryCount).intValue())
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL,
MessageUtils.message("user.password.retry.limit.exceed", maxRetryCount, lockTime)));
throw new UserPasswordRetryLimitExceedException(maxRetryCount, lockTime);
}
if (!matches(user, password))
{
retryCount = retryCount + 1;
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL,
MessageUtils.message("user.password.retry.limit.count", retryCount)));
redisCache.setCacheObject(getCacheKey(username), retryCount, lockTime, TimeUnit.MINUTES);
throw new UserPasswordNotMatchException();
}

View File

@ -17,24 +17,24 @@
<dependencies>
<!--velocity代码生成使用模板 -->
<!-- velocity代码生成使用模板 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
</dependency>
<!-- collections工具类 -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
</dependency>
<!-- 通用工具-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
</dependency>
<!-- 阿里数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,6 +1,7 @@
package com.ruoyi.generator.controller;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -17,12 +18,18 @@ import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.sql.SqlUtil;
import com.ruoyi.generator.domain.GenTable;
import com.ruoyi.generator.domain.GenTableColumn;
import com.ruoyi.generator.service.IGenTableColumnService;
@ -109,10 +116,47 @@ public class GenController extends BaseController
String[] tableNames = Convert.toStrArray(tables);
// 查询表信息
List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames);
genTableService.importGenTable(tableList);
genTableService.importGenTable(tableList, SecurityUtils.getUsername());
return success();
}
/**
*
*/
@PreAuthorize("@ss.hasRole('admin')")
@Log(title = "创建表", businessType = BusinessType.OTHER)
@PostMapping("/createTable")
public AjaxResult createTableSave(String sql)
{
try
{
SqlUtil.filterKeyword(sql);
List<SQLStatement> sqlStatements = SQLUtils.parseStatements(sql, DbType.mysql);
List<String> tableNames = new ArrayList<>();
for (SQLStatement sqlStatement : sqlStatements)
{
if (sqlStatement instanceof MySqlCreateTableStatement)
{
MySqlCreateTableStatement createTableStatement = (MySqlCreateTableStatement) sqlStatement;
if (genTableService.createTable(createTableStatement.toString()))
{
String tableName = createTableStatement.getTableName().replaceAll("`", "");
tableNames.add(tableName);
}
}
}
List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames.toArray(new String[tableNames.size()]));
String operName = SecurityUtils.getUsername();
genTableService.importGenTable(tableList, operName);
return AjaxResult.success();
}
catch (Exception e)
{
logger.error(e.getMessage(), e);
return AjaxResult.error("创建表结构异常");
}
}
/**
*
*/

View File

@ -80,4 +80,12 @@ public interface GenTableMapper
* @return
*/
public int deleteGenTableByIds(Long[] ids);
/**
*
*
* @param sql
* @return
*/
public int createTable(String sql);
}

View File

@ -27,7 +27,6 @@ import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.GenConstants;
import com.ruoyi.common.core.text.CharsetKit;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.generator.domain.GenTable;
import com.ruoyi.generator.domain.GenTableColumn;
@ -150,6 +149,18 @@ public class GenTableServiceImpl implements IGenTableService
genTableColumnMapper.deleteGenTableColumnByIds(tableIds);
}
/**
*
*
* @param sql
* @return
*/
@Override
public boolean createTable(String sql)
{
return genTableMapper.createTable(sql) == 0;
}
/**
*
*
@ -157,9 +168,8 @@ public class GenTableServiceImpl implements IGenTableService
*/
@Override
@Transactional
public void importGenTable(List<GenTable> tableList)
public void importGenTable(List<GenTable> tableList, String operName)
{
String operName = SecurityUtils.getUsername();
try
{
for (GenTable table : tableList)

View File

@ -67,11 +67,20 @@ public interface IGenTableService
public void deleteGenTableByIds(Long[] tableIds);
/**
*
*
* @param tableList
*
*
* @param sql
* @return
*/
public void importGenTable(List<GenTable> tableList);
public boolean createTable(String sql);
/**
*
*
* @param tableList
* @param operName
*/
public void importGenTable(List<GenTable> tableList, String operName);
/**
*

View File

@ -171,6 +171,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
)
</insert>
<update id="createTable">
${sql}
</update>
<update id="updateGenTable" parameterType="GenTable">
update gen_table
<set>

View File

@ -42,6 +42,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
and date_format(create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
</if>
</where>
order by create_time desc
</select>
<select id="selectJobLogAll" resultMap="SysJobLogResult">

View File

@ -43,6 +43,15 @@ export function importTable(data) {
})
}
// 创建表
export function createTable(data) {
return request({
url: '/tool/gen/createTable',
method: 'post',
params: data
})
}
// 预览生成代码
export function previewTable(tableId) {
return request({

View File

@ -56,7 +56,7 @@
</el-form>
<!-- 底部 -->
<div class="el-login-footer">
<span>Copyright © 2018-2023 ruoyi.vip All Rights Reserved.</span>
<span>Copyright © 2018-2024 ruoyi.vip All Rights Reserved.</span>
</div>
</div>
</template>

View File

@ -61,7 +61,7 @@
</el-form>
<!-- 底部 -->
<div class="el-register-footer">
<span>Copyright © 2018-2023 ruoyi.vip All Rights Reserved.</span>
<span>Copyright © 2018-2024 ruoyi.vip All Rights Reserved.</span>
</div>
</div>
</template>
@ -95,7 +95,8 @@ export default {
],
password: [
{ required: true, trigger: "blur", message: "请输入您的密码" },
{ min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' }
{ min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" },
{ pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }
],
confirmPassword: [
{ required: true, trigger: "blur", message: "请再次输入您的密码" },

View File

@ -433,7 +433,8 @@ export default {
],
password: [
{ required: true, message: "用户密码不能为空", trigger: "blur" },
{ min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' }
{ min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' },
{ pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }
],
email: [
{
@ -591,7 +592,12 @@ export default {
cancelButtonText: "取消",
closeOnClickModal: false,
inputPattern: /^.{5,20}$/,
inputErrorMessage: "用户密码长度必须介于 5 和 20 之间"
inputErrorMessage: "用户密码长度必须介于 5 和 20 之间",
inputValidator: (value) => {
if (/<|>|"|'|\||\\/.test(value)) {
return "不能包含非法字符:< > \" ' \\\ |"
}
},
}).then(({ value }) => {
resetUserPwd(row.userId, value).then(response => {
this.$modal.msgSuccess("修改成功,新密码是:" + value);

View File

@ -41,7 +41,8 @@ export default {
],
newPassword: [
{ required: true, message: "新密码不能为空", trigger: "blur" },
{ min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" }
{ min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" },
{ pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }
],
confirmPassword: [
{ required: true, message: "确认密码不能为空", trigger: "blur" },

View File

@ -0,0 +1,45 @@
<template>
<!-- 创建表 -->
<el-dialog title="创建表" :visible.sync="visible" width="800px" top="5vh" append-to-body>
<span>创建表语句(支持多个建表语句)</span>
<el-input type="textarea" :rows="10" placeholder="请输入文本" v-model="content"></el-input>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="handleCreateTable"> </el-button>
<el-button @click="visible = false"> </el-button>
</div>
</el-dialog>
</template>
<script>
import { createTable } from "@/api/tool/gen";
export default {
data() {
return {
//
visible: false,
//
content: ""
};
},
methods: {
//
show() {
this.visible = true;
},
/** 创建按钮操作 */
handleCreateTable() {
if (this.content === "") {
this.$modal.msgError("请输入建表语句");
return;
}
createTable({ sql: this.content }).then(res => {
this.$modal.msgSuccess(res.msg);
if (res.code === 200) {
this.visible = false;
this.$emit("ok");
}
});
}
}
};
</script>

View File

@ -41,10 +41,21 @@
plain
icon="el-icon-download"
size="mini"
:disabled="multiple"
@click="handleGenTable"
v-hasPermi="['tool:gen:code']"
>生成</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="openCreateTable"
v-hasRole="['admin']"
>创建</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
@ -172,12 +183,14 @@
</el-tabs>
</el-dialog>
<import-table ref="import" @ok="handleQuery" />
<create-table ref="create" @ok="handleQuery" />
</div>
</template>
<script>
import { listTable, previewTable, delTable, genCode, synchDb } from "@/api/tool/gen";
import importTable from "./importTable";
import createTable from "./createTable";
import hljs from "highlight.js/lib/highlight";
import "highlight.js/styles/github-gist.css";
hljs.registerLanguage("java", require("highlight.js/lib/languages/java"));
@ -189,7 +202,7 @@ hljs.registerLanguage("sql", require("highlight.js/lib/languages/sql"));
export default {
name: "Gen",
components: { importTable },
components: { importTable, createTable },
data() {
return {
//
@ -283,6 +296,10 @@ export default {
openImportTable() {
this.$refs.import.show();
},
/** 打开创建表弹窗 */
openCreateTable() {
this.$refs.create.show();
},
/** 重置按钮操作 */
resetQuery() {
this.dateRange = [];