新增:利元亨线程,增加mocksql接口,用于测试内网生产sql性能
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
package com.sdm.outbridge.dao;
|
||||
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface DynamicSqlExecutorMapper {
|
||||
@Select("${sql}") // 核心:用${sql}直接拼接传入的SQL字符串
|
||||
List<Map<String, Object>> executeCustomSql(@Param("sql") String sql);
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import com.sdm.outbridge.mode.FreelinkAndDingdingInformReq;
|
||||
import com.sdm.outbridge.mode.GetProcessDataReq;
|
||||
import com.sdm.outbridge.mode.HkUploadFileReq;
|
||||
import com.sdm.outbridge.service.lyric.*;
|
||||
import com.sdm.pbs.service.lyricDbMock.DynamicSqlExecutor;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -15,6 +16,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@@ -38,6 +40,9 @@ public class TestSecondDbController {
|
||||
@Autowired
|
||||
private LyricVTodoInfoService lyricVTodoInfoService;
|
||||
|
||||
@Autowired
|
||||
private DynamicSqlExecutor dynamicSqlExecutor;
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -154,6 +159,92 @@ public class TestSecondDbController {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 执行查询SQL接口
|
||||
* @return SQL执行结果
|
||||
*/
|
||||
@PostMapping("/mockSql")
|
||||
public SdmResponse<List<Map<String, Object>>> executeSql(@RequestBody Map paramMap) {
|
||||
try {
|
||||
String sql = paramMap.get("sql").toString().trim();
|
||||
// 安全校验:禁止执行危险SQL(生产环境必须加!)
|
||||
validateSql(sql);
|
||||
List<Map<String, Object>> result = dynamicSqlExecutor.executeQuery(sql);
|
||||
return SdmResponse.success( result);
|
||||
} catch (Exception e) {
|
||||
return SdmResponse.failed("执行失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* SQL安全校验(生产环境必须实现)
|
||||
* 1. 禁止DROP/ALTER/TRUNCATE等危险操作
|
||||
* 2. 仅允许SELECT语句
|
||||
* 3. SELECT语句必须以LIMIT结尾(支持空格、换行、注释等边界情况)
|
||||
*/
|
||||
private void validateSql(String sql) {
|
||||
// 1. 空值校验
|
||||
if (sql == null || sql.trim().isEmpty()) {
|
||||
throw new RuntimeException("SQL语句不能为空");
|
||||
}
|
||||
|
||||
// 2. SQL预处理:去除注释、多余空格/换行,统一格式
|
||||
String processedSql = preprocessSql(sql);
|
||||
String lowerSql = processedSql.toLowerCase();
|
||||
|
||||
// 3. 禁止的危险关键字(精准匹配独立关键字,避免误判)
|
||||
String[] forbiddenKeywords = {"drop", "alter", "truncate", "delete", "update", "insert", "create",
|
||||
"rename", "replace", "grant", "revoke", "call", "execute"};
|
||||
for (String keyword : forbiddenKeywords) {
|
||||
if (containsIndependentKeyword(lowerSql, keyword)) {
|
||||
throw new RuntimeException("禁止执行包含[" + keyword + "]的SQL语句");
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 确保是SELECT语句
|
||||
if (!lowerSql.startsWith("select")) {
|
||||
throw new RuntimeException("仅允许执行SELECT查询语句");
|
||||
}
|
||||
|
||||
// 5. 新增:SELECT语句必须以LIMIT结尾(支持LIMIT 数字 / LIMIT 数字,数字 / LIMIT 数字 OFFSET 数字)
|
||||
if (!isEndWithValidLimit(lowerSql)) {
|
||||
throw new RuntimeException("SELECT语句必须以LIMIT子句结尾,格式支持:LIMIT [数字] 或 LIMIT [数字],[数字] 或 LIMIT [数字] OFFSET [数字]");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 私有方法:SQL预处理(去除注释、多余空格/换行)
|
||||
*/
|
||||
private String preprocessSql(String sql) {
|
||||
// 去除多行注释 /* ... */
|
||||
String noMultiComment = sql.replaceAll("/\\*.*?\\*/", "");
|
||||
|
||||
// 去除单行注释 -- ...(正确使用Pattern.MULTILINE,避免参数错误)
|
||||
Pattern singleCommentPattern = Pattern.compile("--.*?$", Pattern.MULTILINE);
|
||||
String noSingleComment = singleCommentPattern.matcher(noMultiComment).replaceAll("");
|
||||
|
||||
// 去除所有多余空白符(空格、换行、制表符等),压缩为单个空格
|
||||
String noExtraSpace = noSingleComment.replaceAll("\\s+", " ").trim();
|
||||
return noExtraSpace;
|
||||
}
|
||||
|
||||
/**
|
||||
* 私有方法:检查是否包含独立的关键字(避免误判,如update_time不会匹配update)
|
||||
*/
|
||||
private boolean containsIndependentKeyword(String sql, String keyword) {
|
||||
Pattern pattern = Pattern.compile("(^|\\W)" + keyword + "(\\W|$)");
|
||||
return pattern.matcher(sql).find();
|
||||
}
|
||||
|
||||
/**
|
||||
* 私有方法:检查SQL是否以合法的LIMIT子句结尾
|
||||
*/
|
||||
private boolean isEndWithValidLimit(String lowerSql) {
|
||||
// 正则匹配规则:支持 LIMIT 数字 / LIMIT 数字,数字 / LIMIT 数字 OFFSET 数字
|
||||
Pattern limitPattern = Pattern.compile("^.*limit\\s+\\d+(\\s*,\\s*\\d+)?(\\s+offset\\s+\\d+)?$");
|
||||
return limitPattern.matcher(lowerSql).matches();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.sdm.pbs.service.lyricDbMock;
|
||||
|
||||
import com.sdm.outbridge.dao.DynamicSqlExecutorMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 动态SQL执行工具类(适配多数据源)
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class DynamicSqlExecutor {
|
||||
|
||||
// 注入纯注解版Mapper接口(多数据源需加@Qualifier指定)
|
||||
@Autowired
|
||||
private DynamicSqlExecutorMapper dynamicSqlExecutorMapper;
|
||||
|
||||
/**
|
||||
* 执行查询SQL,返回List<Map>(通用格式)
|
||||
* 关键修复2:直接使用SqlSessionTemplate的selectList方法(无需获取原生SqlSession)
|
||||
*/
|
||||
public List<Map<String, Object>> executeQuery(String sql) {
|
||||
try {
|
||||
long start = System.currentTimeMillis();
|
||||
// MyBatis执行动态SQL的通用方式:使用STATEMENT类型执行原生SQL
|
||||
List<Map<String, Object>> maps = dynamicSqlExecutorMapper.executeCustomSql(sql);
|
||||
long end = System.currentTimeMillis();
|
||||
log.info("mockSql:{},本次查询返回:{}条,耗时:{} s",sql,maps.size(),(end - start)/1000);
|
||||
return maps;
|
||||
} catch (Exception e) {
|
||||
log.error("执行动态SQL失败{}", e.getMessage());
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException("执行SQL出错: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,7 +22,4 @@ public class FormConfigure{
|
||||
|
||||
public String userId;
|
||||
|
||||
// 图表是1 动态表格2
|
||||
public String type;
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user