在MyBatis中,可以通过使用一些特定的标签(
这使得SQL查询可以根据不同的条件动态生成,从而提高查询的灵活性和可维护性。
本文以订单列表简单查询为例, 对mybatis条件判断及动态sql进行简单拓展。
建表语句
CREATE TABLE `wwtms`.`order_table` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '订单序号',
`order_type` varchar(255) NULL COMMENT '订单类型',
`status` varchar(255) NULL COMMENT '订单状态',
`customer_id` bigint(20) NULL COMMENT '所属客户id',
`quantity` double NULL COMMENT '数量',
`address` varchar(500) NULL COMMENT '收货地',
PRIMARY KEY (`id`)
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '订单表';
条件判断及动态sql
以
语法
<if test="判断条件">
SQL语句
</if>
简单使用
判断数值:
<if test="id != null ">
and id = #{id,jdbcType=BIGINT}
</if>
判断字符:
// 判断是否为空
<if test="orderType != null and orderType.trim().length() > 0">
sql语句
</if>
// 判断是否包含某个字符
<if test="orderType != null and orderType eq 'customer'">
sql语句
</if>
判断集合:
<if test="idSet != null and idSet.size > 0">
and id in
<foreach collection="idSet" item="item" separator="," open="(" close=")">
#{item}
</foreach>
</if>
简单拓展
标签与常用Java工具类结合
// 判空
<if test="@java.util.Objects@nonNull(customerId)">
sql语句
</if>
<if test="@org.apache.commons.lang3.StringUtils@isNotBlank(status)">
sql语句
</if>
// 判断是否相等
<if test="@java.util.Objects@equals(1,flag)">
sql语句
</if>
<if test='@org.apache.commons.lang3.StringUtils@equals("customer",status)' >
sql语句
</if>
// 判断集合是否为空
<if test="@org.apache.commons.collections.CollectionUtils@isNotEmpty(idSet)">
and id in
<foreach collection="idSet" item="item" open="(" close=")" separator=",">
#{item}
</foreach>
</if>
同理
// 判断两个字段同时不为空
<if test="@org.apache.commons.lang3.ObjectUtils@allNotNull(flag1,flag2)">
sql语句
</if>
// 判断集合中只要包含某一个字段
<if test="@org.apache.commons.collections.CollectionUtils@containsAny(flagList, "1")">
sql语句
</if>
等等...
同理, 别的标签也适用;
对查询字段的特殊处理
列表查询中,有时需要对某些字段做特殊的处理查询, 例: 对数值字段进行特殊处理查询(>、<、>=、<=、!=), 对某些文本字段的查询做特殊处理..., 我们可以巧用占位符来实现这些处理。
在MyBatis中,# 和 $ 是两种不同的占位符,用于在SQL语句中插入参数。
占位符:用于安全的参数绑定和转义,防止SQL注入,适用于大多数情况。
$ 占位符:用于直接文本替换,不进行转义,适用于动态SQL片段或表名等非用户输入的值,但要特别注意SQL注入风险。
通过合理使用这两种占位符,可以在确保安全的前提下实现灵活的SQL查询。
数值字段特殊处理
新建枚举类(OperationFlagEnum), 事先与前端规定操作符的传递;
操作符枚举
/**
* 操作标识枚举
*
* @author alin
* @date 2024-06-11
*/
@Getter
@AllArgsConstructor
public enum OperationFlagEnum {
EQUAL("EQUAL", "="),
NOT_EQUAL("NOT_EQUAL", "!="),
LARGER("LARGER", ">"),
LESS("LESS", "<"),
LARGER_OR_EQUAL("LARGER_OR_EQUAL", ">="),
LESS_OR_EQUAL("LESS_OR_EQUAL", "<=");
private String code;
private String value;
private static final Map<String, OperationFlagEnum> VALUE_MAP = new HashMap<>(values().length);
static {
Arrays.stream(OperationFlagEnum.values()).forEach(c -> VALUE_MAP.put(c.getCode(), c));
}
public static OperationFlagEnum getByCode(String code) {
return StringUtils.isBlank(code) ? null : VALUE_MAP.get(code);
}
public static String getValueByCodeDefault(String code) {
OperationFlagEnum flagEnum = null;
if(StringUtils.isNotEmpty(code)){
flagEnum = getByCode(code);
}
return flagEnum == null ? EQUAL.getValue(): flagEnum.value;
}
}
mapper文件中的动态sql
<if test="quantity != null">
and quantity
${@com.vx.tms.common.enums.OperationFlagEnum@getValueByCodeDefault(quantityFlag)}
${quantity}
</if>
文本字段特殊处理
若文本字段中含有某些特殊字符, 则对这个字段进行特殊处理, 例: 若某些字段值中间含有空格(或别的字符), 则对此字段用空格切割后进行范围查询;
新建mapper工具类: MapperUtils, 用于特殊处理;
/**
* @author alin
* @date 2024-06-11
*/
public class Mapperutils {
private static final String SPACE = " ";
public static final String EQUALS = " = #{${propertyField},jdbcType=VARCHAR}";
public static final String IN = " in ('${propertyField}')";
/**
* 获取通用字符串查询模板
*
* @param propertyField model字段属性
* @param value 对应值
* @return
*/
public static String getQuery(String propertyField, String value) {
if (StringUtils.contains(value.trim(), SPACE)) {
// sql注入过滤
sqlInject(value);
return replace(IN, StringUtils.join(StringUtils.split(value, SPACE), "','"));
} else if(...) {
.....
}
//sql注入过滤
sqlInject(value);
//等值查询
return replace(EQUALS, propertyField);
}
/**
* 替代
*
* @param type
* @param propertyField
* @return
*/
public static String replace(String type, String propertyField) {
Map<String, Object> params = Maps.newHashMap();
params.put("propertyField", propertyField);
return new StrSubstitutor(params).replace(type);
}
/**
* SQL注入过滤
*
* @param str 待验证的字符串
* @throws
*/
public static void sqlInject(String str) {
if (StringUtils.isBlank(str)) {
return;
}
//去掉'|"|;|\字符
str = StringUtils.replace(str, "'", "");
str = StringUtils.replace(str, "\"", "");
str = StringUtils.replace(str, ";", "");
str = StringUtils.replace(str, "\\", "");
//转换成小写
str = str.toLowerCase();
//非法字符
String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alert", "create", "drop"};
//判断是否包含非法字符
for (String keyword : keywords) {
if (str.contains(keyword)) {
throw new RuntimeException("查询输入条件存在非法字符!");
}
}
}
}
mapper文件中的动态sql
<if test="@org.apache.commons.lang3.StringUtils@isNotBlank(address)">
and ord.address ${@com.vx.tms.common.utils.MapperHelp@getQuery("ord.address",address)}
</if>
标签:语句,String,拓展,public,str,sql,mybatis,StringUtils
From: https://www.cnblogs.com/menghl/p/18242539