浏览代码

最后一次更新

liu 2 周之前
父节点
当前提交
acdb1bbeff

二进制
db/unidia206.db


+ 1 - 1
src/main/java/com/bfkj/unidia/Core/DataServices.java

@@ -342,7 +342,7 @@ public class DataServices {
             // 构造查询条件
             Map<String, Object> conditions = Map.of("key_name", key);
             // 执行数据库查询
-            Result<List<Map<String, Object>>> queryResult = dbExecutor.query(
+            Result<List<Map<String, Object>>> queryResult = dbExecutor. query(
                     systemEnvCache.getDbInfo(),
                     "system_cache_algorithm",
                     Map.of("dataContent", Map.of("conditions", conditions)),

+ 23 - 10
src/main/java/com/bfkj/unidia/Core/ServiceController.java

@@ -610,14 +610,16 @@ public class ServiceController {
             Map<String, Object> map = result.getData().get(0);
             Object time = map.get("last_time");
             Long last_time = Objects.nonNull(time) ? Long.valueOf(time.toString()): null; // 上一次服务执行时间
-            Object last_container_code =  map.get("last_container_code");
-            String lastContainerCode = last_container_code != null ? (String) last_container_code : null; // 上一次服务执行时间
+            String lastContainerCode =  map.getOrDefault("last_container_code","").toString();
+//            String lastContainerCode = last_container_code != null ? (String) last_container_code : null; // 上一次服务执行时间
 
-            if (StringUtils.isBlank(lastContainerCode)){
+            if (StringUtils.isBlank(lastContainerCode)||Objects.isNull(last_time)){
                 // 执行抢占
                int num = preemptive(containerCode,serviceCode,last_time,lastContainerCode);
                if (num>0){
                    return true;
+               }else {
+                   logger.error("抢占更新失败");
                }
             }
 //            否则如果当前时间减最后活跃时间超过8秒
@@ -626,8 +628,14 @@ public class ServiceController {
                 int num = preemptive(containerCode, serviceCode, last_time, lastContainerCode);
                 if (num > 0) {
                     return true;
+                }else {
+                    logger.error("抢占更新失败");
                 }
+            }else {
+                logger.error("最后活跃时间小于八秒,无法抢占别人的");
             }
+        }else {
+            logger.info("没有一条serviceInfo的数据");
         }
 
 
@@ -670,14 +678,19 @@ public class ServiceController {
                         )
                 );
             }else {
-                conditionsMap = Map.of(
-                        "last_time", last_time,
-                        "last_container_code", lastContainerCode,
-                        "service_code", serviceCode
-                );
+                if (Objects.isNull(last_time)){
+                    conditionsMap = Map.of(
+                            "last_container_code", lastContainerCode,
+                            "service_code", serviceCode
+                    );
+                }else {
+                    conditionsMap = Map.of(
+                            "last_time",last_time,
+                            "last_container_code", lastContainerCode,
+                            "service_code", serviceCode
+                    );
+                }
             }
-//        lastContainerCode == null  ? conditions : conditionsMap
-
         Result<Integer> result = dbExecutor.dbUpdate(systemEnvCache.getDbInfo(), serviceTableName,
                 Map.of("dataContent", Map.of(
                         "data", Map.of(

+ 34 - 7
src/main/java/com/bfkj/unidia/DataBaseUtils/DbExecutor.java

@@ -3,6 +3,8 @@ package com.bfkj.unidia.DataBaseUtils;
 import com.bfkj.unidia.Result;
 import com.github.benmanes.caffeine.cache.Cache;
 import com.github.benmanes.caffeine.cache.Caffeine;
+import org.json.JSONArray;
+import org.json.JSONObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -13,6 +15,7 @@ import org.springframework.util.StringUtils;
 import java.sql.ResultSet;
 import java.util.*;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Function;
 
@@ -425,24 +428,48 @@ public class DbExecutor {
      * sql查询,用问号作为占位符,必须严格按照顺序执行查询
      * @param dbConfig
      * @param params
-     * @param sql
      * @return
      */
-    public  Result<List<Map<String, Object>>> searchBySql(Map<String, String> dbConfig, Map<String, Object> params,String sql){
+    public  Result<List<Map<String, Object>>> searchBySql(Map<String, String> dbConfig, Map<String, Object> params){
         //从 params 参数 获取
         List<Object> whereParam = new CopyOnWriteArrayList<>();
         String event = params.getOrDefault("event","").toString();
         if(!StringUtils.hasText(event)||!event.equalsIgnoreCase("SELECT")){
             return Result.fail("event 不存在或为空");
         }
-        Map<String,Object> dataContent = (Map<String, Object>) params.get("dataContent");
+        String sql = params.getOrDefault("sql","").toString();
+        Object dataContent =  params.get("dataContent");
+
+        logger.info("查询入参:{}", JSONObject.wrap(params).toString());
+
         if (Objects.nonNull(dataContent)){
-            List<Object> object = (List<Object>) dataContent.get("conditions");
-            if (!CollectionUtils.isEmpty(object)){
-                whereParam = object;
+            if (dataContent instanceof Map<?,?>){ // 只查询单个
+                logger.info("单个查询");
+                 Map<String, Object> obj =  (Map<String, Object>)dataContent;
+                List<Object> object = (List<Object>) obj.get("conditions");
+                if (!CollectionUtils.isEmpty(object)){
+                    whereParam = object;
+                    return jdbcExecutor.queryForSql(dbConfig,sql, whereParam);
+                }else {
+                    return Result.fail("参数解析异常");
+                }
+            }else if (dataContent instanceof List<?> dataContentList) { // 如果是多个conditions 那么会循环查询,将结果合并,不去重
+                // 集合查询
+                Set<Map<String, Object>> set = new CopyOnWriteArraySet<>();
+                for (Object o : dataContentList) {
+                    Map<String,Object> queryParam = (Map<String,Object>) o;
+                    if (Objects.isNull(queryParam)) continue;
+                    List<Object> aDefault = (List<Object>) queryParam.getOrDefault("conditions", null);
+                    if (CollectionUtils.isEmpty(aDefault)) continue;
+                    Result<List<Map<String, Object>>> result = jdbcExecutor.queryForSql(dbConfig, sql, aDefault);
+                    if (result.isSuccess()&&!CollectionUtils.isEmpty(result.getData())&&result.getData().size()>0){
+                        set.addAll(result.getData());
+                    }
+                }
+                return Result.success(new ArrayList<>(set));
             }
         }
-        return jdbcExecutor.queryForSql(dbConfig,sql, whereParam);
+        return Result.fail("参数格式不正确");
     }
 
     /**

+ 75 - 4
src/main/java/com/bfkj/unidia/DataBaseUtils/JdbcExecutor.java

@@ -23,6 +23,7 @@ import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
 import org.springframework.jdbc.core.namedparam.SqlParameterSource;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
 
 import java.sql.*;
 import java.util.*;
@@ -129,7 +130,10 @@ public class JdbcExecutor {
     public Result<List<Map<String, Object>>> queryForSql(Map<String, String> dbConfig,
                                                         String sql,
                                                         List<Object> params ) {
-        return queryWithDatasource(dbConfig, sql, dataSource -> {
+        if (!StringUtils.hasText(sql)){
+            return Result.fail("sql 不存在或为空");
+        }
+        return customQueryWithDatasource(dbConfig, sql, dataSource -> {
             try(Connection connection = dataSource.getConnection()) {
                 try(PreparedStatement ps = connection.prepareStatement(sql)){
                     // 设置参数
@@ -138,8 +142,7 @@ public class JdbcExecutor {
                             ps.setObject(i + 1, params.get(i)); // 参数从 1 开始
                         }
                     }
-                    logger.info("ps.toString():{}", ps.toString());
-                    logger.info("Executing paginated SQL: {}", sql);
+                    logger.info("执行 SQL: {}", sql);
                     List<Map<String, Object>> resultList = new ArrayList<>();
                     try (ResultSet rs = ps.executeQuery()) {
                         ResultSetMetaData metaData = rs.getMetaData();
@@ -333,6 +336,7 @@ public class JdbcExecutor {
             Function<ResultSet, T> rowMapper) {
         return CompletableFuture.supplyAsync(() -> query(dbConfig, sql, params, rowMapper), executor);
     }
+
     /**
      * 执行数据库查询操作
      *
@@ -376,6 +380,23 @@ public class JdbcExecutor {
         }
         return operation.apply(dataSourceResult.getData());
     }
+    private <T> Result<T> customQueryWithDatasource(Map<String, String> dbConfig,String sql, Function<HikariDataSource, Result<T>> operation) {
+        // 检查SQL语句中是否包含潜在的SQL注入风险
+        if (customerHandelSqlInjection(sql,"query")) {
+            logger.warn("检测到潜在 SQL 注入风险: {}", sql);
+            return Result.fail("SQL 含非法字符");
+        }
+        if (!rateLimiter.allowRequest()) {
+            logger.warn("请求被限流");
+            return Result.fail("请求被限流,请稍后重试");
+        }
+        //查询直接使用JdbcTemplate即可,性能与原生没有区别,代码要简化很多
+        Result<HikariDataSource> dataSourceResult = poolManager.getDataSource(dbConfig);
+        if(!dataSourceResult.isSuccess()){
+            return Result.fail(dataSourceResult.getError());
+        }
+        return operation.apply(dataSourceResult.getData());
+    }
     /**
      * 根据不同数据库应用分页逻辑
      */
@@ -415,6 +436,7 @@ public class JdbcExecutor {
             try (Connection connection = dataSource.getConnection()){
                 connection.setAutoCommit(false);
                 try (PreparedStatement ps = connection.prepareStatement(sql)) {
+                    logger.info("sql:{}",sql);
                     setParameters(ps, params);// 设置 SQL 语句的参数,防止 SQL 注入
                     int executedUpdate = ps.executeUpdate();// 执行更新操作
                     connection.commit();// 提交事务
@@ -683,24 +705,73 @@ public class JdbcExecutor {
         try {
             //优先使用正则表达式检测非法SQL关键词
             Matcher matcher = SQL_INJECTION_PATTERN.matcher(sql);
-            if(matcher.find()) return true;
+            if(matcher.find()) {
+                logger.info("SQL_INJECTION_PATTERN.matcher(sql); 692");
+                return true;
+            }
             // 使用CCJSqlParser解析SQL语句,以便进行进一步的检查
             Statement stmt = CCJSqlParserUtil.parse(sql);
             // 检查解析后的SQL语句是否包含危险操作
             boolean isInject = containsDangerousOperation(stmt,type);
             // 如果包含危险操作,则将该SQL语句添加到白名单缓存中,避免重复检测
             if (!isInject) {
+                logger.info("containsDangerousOperation(stmt,type); 701");
                 safeSqlCache.put(sql, true); // 白名单缓存
             }
             // 返回检测结果
             return isInject;
         } catch (JSQLParserException e) {
             // 如果SQL解析失败,记录警告日志并认为该SQL语句疑似注入
+            logger.error("抛出异常:\n",e);
             logger.warn("SQL 解析失败:{};疑似注入: {}",e.getMessage(), sql);
             return true;
         }
     }
 
+    /**
+     * 自定义sql验证
+     * @param sql
+     * @param type
+     * @return
+     */
+    public boolean customerHandelSqlInjection(String sql,String type) {
+        if (sql == null || sql.isEmpty()) return false;
+        if(type == null || type.isEmpty()) {
+            logger.warn("未指定数据操作类型type");
+            return true;
+        }
+        // 首先尝试从缓存中获取该SQL语句的安全性信息
+        Boolean cached = safeSqlCache.getIfPresent(sql);
+        // 如果缓存中存在且值为false,则说明该SQL语句已被标记为不安全,直接返回false
+        if (Boolean.TRUE.equals(cached)) {
+            return false;
+        }
+
+        try {
+            //优先使用正则表达式检测非法SQL关键词
+            // todo 暂且注释掉,自定义sql被拦住了
+            /*Matcher matcher = SQL_INJECTION_PATTERN.matcher(sql);
+            if(matcher.find()) {
+                logger.info("SQL_INJECTION_PATTERN.matcher(sql); 692");
+                return true;
+            }*/
+            // 使用CCJSqlParser解析SQL语句,以便进行进一步的检查
+            Statement stmt = CCJSqlParserUtil.parse(sql);
+            // 检查解析后的SQL语句是否包含危险操作
+            boolean isInject = containsDangerousOperation(stmt,type);
+            // 如果包含危险操作,则将该SQL语句添加到白名单缓存中,避免重复检测
+            if (!isInject) {
+                safeSqlCache.put(sql, true); // 白名单缓存
+            }
+            // 返回检测结果
+            return isInject;
+        } catch (JSQLParserException e) {
+            // 如果SQL解析失败,记录警告日志并认为该SQL语句疑似注入
+            logger.error("抛出异常:\n",e);
+            logger.warn("SQL 解析失败:{};疑似注入: {}",e.getMessage(), sql);
+            return true;
+        }
+    }
     /**
      * 判断 SQL 是否包含危险操作
      */

+ 4 - 4
src/main/resources/application.properties

@@ -1,9 +1,9 @@
 #????
 spring.application.name=UNIDIA206
 #Web??
-server.port=8989
+server.port=18090
 #??????
-logging.file.path=/log/data-processing
+logging.file.path=./log/data-processing
 logging.level.root=info
 #logging.level.com.yourpackage=debug # ???????debug??
 
@@ -26,8 +26,8 @@ app.directories.temp=tmp
 
 # SQLite ?????
 #spring.datasource.url=jdbc:sqlite:file:G:\\WorkSpace\\UNIDIA\\db\\unidia206.db   # ????????????????????
-spring.datasource.url=jdbc:sqlite:file:G:\\sqlliteDB\\localDb\\unidia206.db   # ????????????????????
-#spring.datasource.url=jdbc:sqlite:/app/service/db/unidia206.db
+#spring.datasource.url=jdbc:sqlite:file:G:\\sqlliteDB\\localDb\\unidia206.db   # ????????????????????
+spring.datasource.url=jdbc:sqlite:/app/service/db/unidia206.db
 spring.datasource.username=
 spring.datasource.password=
 spring.datasource.driver-class-name=org.sqlite.JDBC

+ 66 - 26
src/test/java/com/bfkj/unidia/UnidiaApplicationTests.java

@@ -58,32 +58,38 @@ class UnidiaApplicationTests {
 
     @Test
     void testQuery(){
-        HashMap<String, Object> p1 = new HashMap<>();
-        p1.put("column","user_status");
-        p1.put("comparison","=");
-        p1.put("value","1");
-        p1.put("connection","OR");
-        p1.put("right","");
-        HashMap<String, Object> p2 = new HashMap<>();
-        p2.put("column","token_valid_duration");
-        p2.put("comparison",">");
-        p2.put("value","4000");
-        p2.put("connection","AND");
-        p2.put("left","(");
-        HashMap<String, Object> p3 = new HashMap<>();
-        p3.put("column","token_valid_duration");
-        p3.put("comparison","<");
-        p3.put("value","10000");
-        p3.put("connection","AND"); // 连接符必须是大写
-        p3.put("right",")");
-        List<HashMap<String, Object>> maps = Arrays.asList(p1, p2, p3);
         HashMap<String, Object> map = new HashMap<>();
-        map.put("dataContent",Map.of("conditions",maps));
+        map.put("dataContent",Arrays.asList(
+                Map.of("conditions",Map.of("carrierFlights","CA123","carrierFlightsDate","2023-05-01","luggageNum","BAG001")),
+                Map.of("conditions",Map.of("carrierFlights","CA123","carrierFlightsDate","2023-05-01","luggageNum","BAG001"))
+
+                )
+        );
         map.put("event","SELECT");
-        map.put("page",2);
-        map.put("pageSize",3);
-        Result<List<Map<String, Object>>> res = dbExecutor.search(systemEnvCache.getDbInfo(), "t_user", map);
-        List<Map<String, Object>> list = res.getData();
+//        map.put("page",2);
+//        map.put("pageSize",3);
+        Result<List<Map<String, Object>>> result = dbExecutor.find(
+                systemEnvCache.getDbInfo(),
+                "baggage_tracking",
+                map,
+                (rs) -> {
+                    // 可自定义结果映射逻辑,这里使用默认 Map 映射
+                    Map<String, Object> row = new HashMap<>();
+                    try {
+                        for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
+                            row.put(rs.getMetaData().getColumnName(i), rs.getObject(i));
+                        }
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                    return row;
+                },
+                true  // 是否启用缓存,根据实际需求调整
+        );
+        System.out.println(result.getError());
+        List<Map<String, Object>> list = result.getData();
+        System.out.println(list);
+        System.out.println("\n-----------------------------------");
         System.out.println(JSONObject.wrap(map).toString());
 
     }
@@ -97,15 +103,48 @@ class UnidiaApplicationTests {
     @Test
     void sqlQuery(){
         HashMap<String, Object> map = new HashMap<>();
-        map.put("dataContent",Map.of("conditions",Arrays.asList("$2a222","222","111")));
+        map.put("dataContent",Arrays.asList(
+                Map.of("conditions",Arrays.asList("$2a222","222","111")),
+                Map.of("conditions",Arrays.asList("$2a222","222","111"))
+        ));
         map.put("event","SELECT");
         String sql = "select * from t_user where user_pwd = ? and user_token = ? and  token_valid_time=?";
-        Result<List<Map<String, Object>>> res = dbExecutor.searchBySql(systemEnvCache.getDbInfo(), map,sql);
+        map.put("sql",sql);
+        Result<List<Map<String, Object>>> res = dbExecutor.searchBySql(systemEnvCache.getDbInfo(), map);
         List<Map<String, Object>> list = res.getData();
+        System.out.println(JSONObject.wrap(list).toString());
         System.out.println(JSONObject.wrap(map).toString());
 //        user_pwd	user_token	token_valid_time
 //        $2a222	222	111
     }
+
+    public static List<Object> getList(){
+        List<Object> list = new ArrayList<>();
+        list.add(getOneMap());
+//        list.add(getTwoMap());
+        return list;
+    }
+
+    public static Map<String,Object> getOneMap(){
+        HashMap<String, Object> hashMap = new HashMap<>();
+        hashMap.put("conditions",Arrays.asList(
+                Map.of("carrierFlights","CA123","carrierFlightsDate","2023-05-01","luggageNum","BAG001"),
+                Map.of("carrierFlights","CA123","carrierFlightsDate","2023-05-01","luggageNum","BAG001")));
+        return hashMap;
+    }
+
+    public static Map<String,Object> getTwoMap(){
+        HashMap<String, Object> hashMap = new HashMap<>();
+        hashMap.put("conditions",Map.of("user_pwd","$2a$10$xJ4Q2Lk9Xz1ZQ7Ew","user_token","eyJhbGciOiJIUzI1NiIs...","token_valid_time","1704067199000"));
+        return hashMap;
+    }
+
+
+
+
+
+
+
     // 获取解密参数和加密密码
     @Test
     void getPwd(){
@@ -121,3 +160,4 @@ class UnidiaApplicationTests {
 //        driverName=com.mysql.cj.jdbc.Driver
 //        url=jdbc:mysql://127.0.0.1:3306/unidia206?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8
 //        username=db_admin
+//{"dataContent":{"conditions":["$2a222","222","111"]},"event":"SELECT"}