From fb0e30ad636c6564e7402e1df72592e3fe70a8da Mon Sep 17 00:00:00 2001 From: wyt <414651037@qq.com> Date: Thu, 11 Dec 2025 10:53:28 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=BB=84=E5=90=88=E7=AD=9B?= =?UTF-8?q?=E9=80=89=E6=9F=A5=E8=AF=A2=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/base/mapper/SheepFileMapper.java | 14 ++ .../base/mapper/SheepFileSqlProvider.java | 182 ++++++++++++++++++ .../service/impl/SheepFileServiceImpl.java | 110 +++++++---- .../resources/mapper/base/SheepFileMapper.xml | 77 ++++---- 4 files changed, 304 insertions(+), 79 deletions(-) create mode 100644 zhyc-module/src/main/java/com/zhyc/module/base/mapper/SheepFileSqlProvider.java diff --git a/zhyc-module/src/main/java/com/zhyc/module/base/mapper/SheepFileMapper.java b/zhyc-module/src/main/java/com/zhyc/module/base/mapper/SheepFileMapper.java index 1a95888..cc04161 100644 --- a/zhyc-module/src/main/java/com/zhyc/module/base/mapper/SheepFileMapper.java +++ b/zhyc-module/src/main/java/com/zhyc/module/base/mapper/SheepFileMapper.java @@ -3,6 +3,8 @@ package com.zhyc.module.base.mapper; import com.zhyc.module.base.domain.SheepFile; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.ResultMap; +import org.apache.ibatis.annotations.SelectProvider; import java.util.List; import java.util.Map; @@ -86,5 +88,17 @@ public interface SheepFileMapper @Param("sheepFile") SheepFile sheepFile ); + // 修改:使用 @SelectProvider 并指定 ResultMap + @SelectProvider(type = SheepFileSqlProvider.class, method = "selectByCondition") + @ResultMap("SheepFileResult") // 重要:指定使用 XML 中定义的 ResultMap + List selectByCondition( + @Param("sheepFile") SheepFile sheepFile, + @Param("conditions") Map conditions + ); + + // 修改:获取字段值的方法 + @SelectProvider(type = SheepFileSqlProvider.class, method = "selectFieldValues") + List selectFieldValuesByProvider(@Param("fieldName") String fieldName); + } diff --git a/zhyc-module/src/main/java/com/zhyc/module/base/mapper/SheepFileSqlProvider.java b/zhyc-module/src/main/java/com/zhyc/module/base/mapper/SheepFileSqlProvider.java new file mode 100644 index 0000000..b6b1a2b --- /dev/null +++ b/zhyc-module/src/main/java/com/zhyc/module/base/mapper/SheepFileSqlProvider.java @@ -0,0 +1,182 @@ +package com.zhyc.module.base.mapper; + +import com.zhyc.module.base.domain.SheepFile; +import org.apache.ibatis.jdbc.SQL; +import org.springframework.util.StringUtils; + +import java.util.Map; + +/** + * MyBatis SQL 提供者类 + */ +public class SheepFileSqlProvider { + + /** + * 生成动态查询的 SQL + */ + public String selectByCondition(Map params) { + SheepFile sheepFile = (SheepFile) params.get("sheepFile"); + Map conditions = (Map) params.get("conditions"); + + // 使用 SQL 构建器 + SQL sql = new SQL(); + + // 重要:使用与 XML 中完全相同的字段列表 + selectAllColumns(sql); + + sql.FROM("sheep_file"); + sql.WHERE("is_delete = 0"); + + // 添加 SheepFile 条件 + addSheepFileConditions(sql, sheepFile); + + // 添加动态条件 + addDynamicConditions(sql, conditions); + + sql.ORDER_BY("id DESC"); + + return sql.toString(); + } + + /** + * 选择所有列(与 XML 中的 selectSheepFileVo 保持一致) + */ + private void selectAllColumns(SQL sql) { + sql.SELECT( + "id, bs_manage_tags, ranch_id, dr_ranch, sheepfold_id, sheepfold_name, " + + "electronic_tags, variety_id, variety, family, name, gender, birthday, " + + "day_age, month_age, parity, birth_weight, weaning_date, status_id, " + + "weaning_weight, current_weight, weaning_day_age, weaning_daily_gain, " + + "breed_status_id, breed, bs_father_id, father_manage_tags, bs_mother_id, " + + "mother_manage_tags, receptor_id, receptor_manage_tags, father_father_id, " + + "grandfather_manage_tags, father_mother_id, grandmother_manage_tags, " + + "father_id, maternal_grandfather_manage_tags, mother_id, " + + "maternal_grandmother_manage_tags, mating_date, mating_type_id, " + + "preg_date, lambing_date, lambing_day, mating_day, gestation_day, " + + "expected_date, post_lambing_day, lactation_day, anestrous_day, " + + "mating_counts, mating_total, miscarriage_counts, comment, " + + "controlled, body, breast, source, source_date, source_ranch_id, " + + "source_ranch, update_by, update_time, create_by, create_time, " + + "is_delete" + ); + } + + /** + * 添加 SheepFile 对象中的条件 + */ + private void addSheepFileConditions(SQL sql, SheepFile sheepFile) { + if (sheepFile == null) { + return; + } + + if (StringUtils.hasText(sheepFile.getBsManageTags())) { + sql.WHERE("bs_manage_tags LIKE CONCAT('%', #{sheepFile.bsManageTags}, '%')"); + } + if (StringUtils.hasText(sheepFile.getElectronicTags())) { + sql.WHERE("electronic_tags LIKE CONCAT('%', #{sheepFile.electronicTags}, '%')"); + } + if (StringUtils.hasText(sheepFile.getDrRanch())) { + sql.WHERE("dr_ranch LIKE CONCAT('%', #{sheepFile.drRanch}, '%')"); + } + if (StringUtils.hasText(sheepFile.getVariety())) { + sql.WHERE("variety LIKE CONCAT('%', #{sheepFile.variety}, '%')"); + } + if (StringUtils.hasText(sheepFile.getName())) { + sql.WHERE("name LIKE CONCAT('%', #{sheepFile.name}, '%')"); + } + if (sheepFile.getGender() != null) { + sql.WHERE("gender = #{sheepFile.gender}"); + } + if (sheepFile.getStatusId() != null) { + sql.WHERE("status_id = #{sheepFile.statusId}"); + } + if (StringUtils.hasText(sheepFile.getBreed())) { + sql.WHERE("breed LIKE CONCAT('%', #{sheepFile.breed}, '%')"); + } + } + + /** + * 简化的动态条件处理 + */ + private void addDynamicConditions(SQL sql, Map conditions) { + if (conditions == null || conditions.isEmpty()) { + return; + } + + for (Map.Entry entry : conditions.entrySet()) { + String field = entry.getKey(); + Object value = entry.getValue(); + + if (value == null) { + continue; + } + + String strValue = value.toString(); + + // 处理空值条件 + if ("IS_NULL".equals(strValue)) { + sql.WHERE(field + " IS NULL"); + } else if ("NOT_NULL".equals(strValue)) { + sql.WHERE(field + " IS NOT NULL"); + } + // 处理范围条件 + else if (strValue.startsWith("GT:") || strValue.startsWith("LT:") || + strValue.startsWith("GE:") || strValue.startsWith("LE:")) { + String operator = strValue.substring(0, 2); + String numValue = strValue.substring(3); + if (isNumeric(numValue)) { + sql.WHERE(field + " " + operator + " " + numValue); + } + } + // 处理IN条件 + else if (strValue.contains(",")) { + String[] values = strValue.split(","); + StringBuilder inClause = new StringBuilder(field + " IN ("); + for (int i = 0; i < values.length; i++) { + inClause.append("'").append(values[i].trim()).append("'"); + if (i < values.length - 1) { + inClause.append(","); + } + } + inClause.append(")"); + sql.WHERE(inClause.toString()); + } + // 默认条件:使用等值查询 + else { + sql.WHERE(field + " = #{conditions." + field + "}"); + } + } + } + + /** + * 判断字符串是否为数字 + */ + private boolean isNumeric(String str) { + if (str == null || str.trim().isEmpty()) { + return false; + } + try { + Double.parseDouble(str.trim()); + return true; + } catch (NumberFormatException e) { + return false; + } + } + + /** + * 生成获取字段值的 SQL + */ + public String selectFieldValues(Map params) { + String fieldName = (String) params.get("fieldName"); + + SQL sql = new SQL(); + sql.SELECT("DISTINCT " + fieldName + " AS field_value"); + sql.FROM("sheep_file"); + sql.WHERE(fieldName + " IS NOT NULL"); + sql.WHERE(fieldName + " != ''"); + sql.WHERE(fieldName + " != 'null'"); + sql.ORDER_BY(fieldName + " ASC"); + + return sql.toString(); + } +} \ No newline at end of file diff --git a/zhyc-module/src/main/java/com/zhyc/module/base/service/impl/SheepFileServiceImpl.java b/zhyc-module/src/main/java/com/zhyc/module/base/service/impl/SheepFileServiceImpl.java index a616dff..1015935 100644 --- a/zhyc-module/src/main/java/com/zhyc/module/base/service/impl/SheepFileServiceImpl.java +++ b/zhyc-module/src/main/java/com/zhyc/module/base/service/impl/SheepFileServiceImpl.java @@ -72,58 +72,96 @@ public class SheepFileServiceImpl implements ISheepFileService { /** * 获取指定字段的唯一值列表 - * - * 这个方法实现了获取字段唯一值的核心逻辑 - * 包含安全验证和业务处理 - * - * @param fieldName 字段名 - * @return 该字段的所有唯一值列表 - * @throws IllegalArgumentException 当字段名不在白名单中时抛出异常 */ @Override public List getFieldValues(String fieldName) { // 第一步:安全性验证 - 防止SQL注入攻击 - // 只允许预定义的字段名,确保查询的安全性 if (!isValidFieldName(fieldName)) { - // 如果字段名不在白名单中,抛出异常并记录日志 throw new IllegalArgumentException("非法的字段名: " + fieldName + ",请检查字段名是否正确"); } - // 第二步:调用Mapper层执行数据库查询 - // 这里会执行类似 SELECT DISTINCT fieldName FROM sheep_file 的SQL - List fieldValues = sheepFileMapper.selectFieldValues(fieldName); - - // 第三步:返回查询结果 - return fieldValues; + // 第二步:调用新的 Provider 方法 + // 注意:这里调用的是 selectFieldValuesByProvider,不是 selectFieldValues + return sheepFileMapper.selectFieldValuesByProvider(fieldName); } @Override public List selectSheepFileListByCondition(Map params, SheepFile sheepFile) { - // 验证参数中的字段名,防止SQL注入 - if (params != null && !params.isEmpty()) { - Map safeParams = new HashMap<>(); + // 验证并处理参数 + Map safeConditions = processConditions(params); - for (Map.Entry entry : params.entrySet()) { - String fieldName = entry.getKey(); - Object value = entry.getValue(); + // 调用新的 Provider 方法 + List result = sheepFileMapper.selectByCondition(sheepFile, safeConditions); - // 将前端字段名转换为数据库字段名 - String dbFieldName = convertToDbFieldName(fieldName); - // 验证字段名是否安全(使用白名单) - if (isValidFieldName(dbFieldName)) { - safeParams.put(dbFieldName, value); - } else { - // 记录日志或抛出异常 - System.out.println("警告:忽略非法字段名: " + fieldName); - } - } + return result; - return sheepFileMapper.selectSheepFileListByCondition(safeParams, sheepFile); + } + + /** + * 处理条件参数,确保安全 + */ + private Map processConditions(Map params) { + if (params == null || params.isEmpty()) { + return new HashMap<>(); } - // 如果没有额外参数,使用原有的查询方法 - return sheepFileMapper.selectSheepFileList(sheepFile); + Map safeParams = new HashMap<>(); + + for (Map.Entry entry : params.entrySet()) { + String fieldName = entry.getKey(); + Object value = entry.getValue(); + + // 将前端字段名转换为数据库字段名 + String dbFieldName = convertToDbFieldName(fieldName); + + // 验证字段名是否安全 + if (isValidFieldName(dbFieldName)) { + // 处理值,确保不是 Character 类型 + Object safeValue = value; + if (value != null) { + String strValue = value.toString(); + + // 特殊处理范围条件:确保数字值的安全性 + if (strValue.startsWith("GT:") || strValue.startsWith("LT:") || + strValue.startsWith("GE:") || strValue.startsWith("LE:")) { + String numPart = strValue.substring(3); + // 验证数字部分是否安全(防止 SQL 注入) + if (isNumeric(numPart)) { + safeValue = strValue; + } else { + // 如果不是数字,忽略这个条件 + System.out.println("警告:范围条件的值不是数字: " + fieldName + " = " + strValue); + continue; + } + } else { + // 其他值直接使用字符串 + safeValue = strValue; + } + } + safeParams.put(dbFieldName, safeValue); + } else { + // 记录日志 + System.out.println("警告:忽略非法字段名: " + fieldName + " -> " + dbFieldName); + } + } + + return safeParams; + } + + /** + * 判断字符串是否为数字 + */ + private boolean isNumeric(String str) { + if (str == null || str.isEmpty()) { + return false; + } + try { + Double.parseDouble(str); + return true; + } catch (NumberFormatException e) { + return false; + } } /** @@ -131,10 +169,10 @@ public class SheepFileServiceImpl implements ISheepFileService { */ private String convertToDbFieldName(String fieldName) { // 将驼峰命名转换为下划线命名 - String result = fieldName.replaceAll("([a-z])([A-Z])", "$1_$2").toLowerCase(); - return result; + return fieldName.replaceAll("([a-z])([A-Z])", "$1_$2").toLowerCase(); } + /** * 扩展字段名白名单验证 */ diff --git a/zhyc-module/src/main/resources/mapper/base/SheepFileMapper.xml b/zhyc-module/src/main/resources/mapper/base/SheepFileMapper.xml index e7d43e9..1301555 100644 --- a/zhyc-module/src/main/resources/mapper/base/SheepFileMapper.xml +++ b/zhyc-module/src/main/resources/mapper/base/SheepFileMapper.xml @@ -200,33 +200,38 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - + AND ${key} IS NULL - + AND ${key} IS NOT NULL - - AND ${key} > #{value.toString().substring(3)} - - - AND ${key} < #{value.toString().substring(3)} - - - AND ${key} >= #{value.toString().substring(3)} - - - AND ${key} <= #{value.toString().substring(3)} + + + + + AND ${key} > #{value.toString().substring(3)} + + + AND ${key} < #{value.toString().substring(3)} + + + AND ${key} >= #{value.toString().substring(3)} + + + AND ${key} <= #{value.toString().substring(3)} + + - + AND ${key} IN #{item} @@ -236,35 +241,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - - AND ${key} LIKE CONCAT('%', #{value}, '%') - - - - - - - AND ${key} = #{value} + + + + AND ${key} LIKE CONCAT('%', #{value}, '%') + + + + AND ${key} = #{value} + +