• mybatis条件判断及动态sql的简单拓展


    在MyBatis中,可以通过使用一些特定的标签(if、choose...)以及其他动态SQL功能来实现条件判断。
    这使得SQL查询可以根据不同的条件动态生成,从而提高查询的灵活性和可维护性。
    本文以订单列表简单查询为例, 对mybatis条件判断及动态sql进行简单拓展。

    建表语句

    1. CREATE TABLE order_table (
    2. `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '订单序号',
    3. `order_type` varchar(255) NULL COMMENT '订单类型',
    4. `status` varchar(255) NULL COMMENT '订单状态',
    5. `customer_id` bigint(20) NULL COMMENT '所属客户id',
    6. `quantity` double NULL COMMENT '数量',
    7. `address` varchar(500) NULL COMMENT '收货地',
    8. PRIMARY KEY (`id`)
    9. ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '订单表';

    条件判断及动态sql

    以if标签为例,if标签类似于 Java 中的 if 语句, 是mybatis中最常用的判断标签。

    1. 语法
    2. <if test="判断条件">
    3. SQL语句
    4. if>
    5. 简单使用
    6. 判断数值:
    7. <if test="id != null ">
    8. and id = #{id,jdbcType=BIGINT}
    9. if>
    10. 判断字符:
    11. // 判断是否为空
    12. <if test="orderType != null and orderType.trim().length() > 0">
    13. sql语句
    14. if>
    15. // 判断是否包含某个字符
    16. <if test="orderType != null and orderType eq 'customer'">
    17. sql语句
    18. if>
    19. 判断集合:
    20. <if test="idSet != null and idSet.size > 0">
    21. and id in
    22. "idSet" item="item" separator="," open="(" close=")">
    23. #{item}
    24. if>

    简单拓展

    if标签与常用Java工具类结合

    1. // 判空
    2. <if test="@java.util.Objects@nonNull(customerId)">
    3. sql语句
    4. if>
    5. <if test="@org.apache.commons.lang3.StringUtils@isNotBlank(status)">
    6. sql语句
    7. if>
    8. // 判断是否相等
    9. <if test="@java.util.Objects@equals(1,flag)">
    10. sql语句
    11. if>
    12. <if test='@org.apache.commons.lang3.StringUtils@equals("customer",status)' >
    13. sql语句
    14. if>
    15. // 判断集合是否为空
    16. <if test="@org.apache.commons.collections.CollectionUtils@isNotEmpty(idSet)">
    17. and id in
    18. "idSet" item="item" open="(" close=")" separator=",">
    19. #{item}
    20. if>
    21. 同理
    22. // 判断两个字段同时不为空
    23. <if test="@org.apache.commons.lang3.ObjectUtils@allNotNull(flag1,flag2)">
    24. sql语句
    25. if>
    26. // 判断集合中只要包含某一个字段
    27. <if test="@org.apache.commons.collections.CollectionUtils@containsAny(flagList, "1")">
    28. sql语句
    29. if>
    30. 等等...

    同理, 别的标签也适用;

    对查询字段的特殊处理

    列表查询中,有时需要对某些字段做特殊的处理查询, 例: 对数值字段进行特殊处理查询(>、<、>=、<=、!=), 对某些文本字段的查询做特殊处理..., 我们可以巧用占位符来实现这些处理。
    在MyBatis中,# 和 $ 是两种不同的占位符,用于在SQL语句中插入参数。

    占位符:用于安全的参数绑定和转义,防止SQL注入,适用于大多数情况。
    $ 占位符:用于直接文本替换,不进行转义,适用于动态SQL片段或表名等非用户输入的值,但要特别注意SQL注入风险。
    通过合理使用这两种占位符,可以在确保安全的前提下实现灵活的SQL查询。

    数值字段特殊处理

    新建枚举类(OperationFlagEnum), 事先与前端规定操作符的传递;
    操作符枚举

    1. /**
    2. * 操作标识枚举
    3. *
    4. * @author alin
    5. * @date 2024-06-11
    6. */
    7. @Getter
    8. @AllArgsConstructor
    9. public enum OperationFlagEnum {
    10. EQUAL("EQUAL", "="),
    11. NOT_EQUAL("NOT_EQUAL", "!="),
    12. LARGER("LARGER", ">"),
    13. LESS("LESS", "<"),
    14. LARGER_OR_EQUAL("LARGER_OR_EQUAL", ">="),
    15. LESS_OR_EQUAL("LESS_OR_EQUAL", "<=");
    16. private String code;
    17. private String value;
    18. private static final Map VALUE_MAP = new HashMap<>(values().length);
    19. static {
    20. Arrays.stream(OperationFlagEnum.values()).forEach(c -> VALUE_MAP.put(c.getCode(), c));
    21. }
    22. public static OperationFlagEnum getByCode(String code) {
    23. return StringUtils.isBlank(code) ? null : VALUE_MAP.get(code);
    24. }
    25. public static String getValueByCodeDefault(String code) {
    26. OperationFlagEnum flagEnum = null;
    27. if(StringUtils.isNotEmpty(code)){
    28. flagEnum = getByCode(code);
    29. }
    30. return flagEnum == null ? EQUAL.getValue(): flagEnum.value;
    31. }
    32. }

    mapper文件中的动态sql

    1. <if test="quantity != null">
    2. and quantity
    3. ${@com.alin.common.enums.OperationFlagEnum@getValueByCodeDefault(quantityFlag)}
    4. ${quantity}
    5. if>

    文本字段特殊处理

    若文本字段中含有某些特殊字符, 则对这个字段进行特殊处理, 例: 若某些字段值中间含有空格(或别的字符), 则对此字段用空格切割后进行范围查询;
    新建mapper工具类: MapperUtils, 用于特殊处理;

    1. /**
    2. * @author alin
    3. * @date 2024-06-11
    4. */
    5. public class Mapperutils {
    6. private static final String SPACE = " ";
    7. public static final String EQUALS = " = #{${propertyField},jdbcType=VARCHAR}";
    8. public static final String IN = " in ('${propertyField}')";
    9. /**
    10. * 获取通用字符串查询模板
    11. *
    12. * @param propertyField model字段属性
    13. * @param value 对应值
    14. * @return
    15. */
    16. public static String getQuery(String propertyField, String value) {
    17. if (StringUtils.contains(value.trim(), SPACE)) {
    18. // sql注入过滤
    19. sqlInject(value);
    20. return replace(IN, StringUtils.join(StringUtils.split(value, SPACE), "','"));
    21. } else if(...) {
    22. .....
    23. }
    24. //sql注入过滤
    25. sqlInject(value);
    26. //等值查询
    27. return replace(EQUALS, propertyField);
    28. }
    29. /**
    30. * 替代
    31. *
    32. * @param type
    33. * @param propertyField
    34. * @return
    35. */
    36. public static String replace(String type, String propertyField) {
    37. Map params = Maps.newHashMap();
    38. params.put("propertyField", propertyField);
    39. return new StrSubstitutor(params).replace(type);
    40. }
    41. /**
    42. * SQL注入过滤
    43. *
    44. * @param str 待验证的字符串
    45. * @throws
    46. */
    47. public static void sqlInject(String str) {
    48. if (StringUtils.isBlank(str)) {
    49. return;
    50. }
    51. //去掉'|"|;|\字符
    52. str = StringUtils.replace(str, "'", "");
    53. str = StringUtils.replace(str, "\"", "");
    54. str = StringUtils.replace(str, ";", "");
    55. str = StringUtils.replace(str, "\\", "");
    56. //转换成小写
    57. str = str.toLowerCase();
    58. //非法字符
    59. String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alert", "create", "drop"};
    60. //判断是否包含非法字符
    61. for (String keyword : keywords) {
    62. if (str.contains(keyword)) {
    63. throw new RuntimeException("查询输入条件存在非法字符!");
    64. }
    65. }
    66. }
    67. }

    mapper文件中的动态sql

    1. <if test="@org.apache.commons.lang3.StringUtils@isNotBlank(address)">
    2. and ord.address ${@com.alin.common.utils.MapperUtils@getQuery("ord.address",address)}
    3. if>

  • 相关阅读:
    【Linux网络编程】序列化与反序列化
    华为OD机试 - 单词接龙 - 数据结构map、list (Java 2023 B卷 100分)
    Linux磁盘管理
    JavaCV音视频开发宝典:UDP广播推流 使用UDP方式推送广播TS流 实现UDP一对多广播
    管理团队按这个模板做,让你成为优秀管理者
    上海控安携汽车网络安全新研产品出席AUTOSEMO“恒以致远,共创共赢”主题研讨会
    2022最新版-李宏毅机器学习深度学习课程-P26 Recurrent Neural Network
    websocket加鉴权 @ServerEndpoint方式
    《Python编程:从入门到实战》(第2版)学习笔记 第5章 if语句
    手写Promise.all/race/any/settled方法
  • 原文地址:https://blog.csdn.net/qq_38140936/article/details/139650004