曲线橄榄球免安装绿色版
469M · 2025-09-27
本文通过代码展示如何自定义一个mybatis拦截器以实现SQL语句的再次封装。
为了在特定业务场景下实现SQL语句的全局封装,而无需在多个逻辑类中手动调用转换方法。这里为了实现输入%或者_时能够查找到带%或_字符的数据内容,一般来说%和_是数据库的特殊字符,是一种通配符,会把所有内容模糊查找出来。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
<!-- sql性能分析插件 -->
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
</dependency>
</dependencies>
#这里省略其他mybatis的默认配置
spring:
datasource:
type:com.alibaba.druid.pool.DruidDataSource
driverClassName:com.p6spy.engine.spy.P6SpyDriver #使用P6Spy驱动
url:jdbc:p6spy:mysql://192.168.233.129:3306/CoffeeBeansDB?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
username:xxx
password:xxx
mybatis:
custom-search:
fields:search,input # 自定义拦截指定的搜索字段
package org.coffeebeans.config;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* <li>ClassName: SearchParamsConfig </li>
* <li>Author: OakWang </li>
*/
@Component
@Getter
@Setter
@ConfigurationProperties(prefix = "mybatis.custom-search")
public class SearchParamsConfig {
private List<String> fields;
}
package org.coffeebeans.config;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.*;
/**
* <li>ClassName: QueryInterceptor </li>
* <li>Author: OakWang </li>
*/
@Component
@Intercepts({
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class QueryInterceptor implements Interceptor {
@Autowired
private SearchParamsConfig searchParamsConfig;
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object[] args = invocation.getArgs();
Object parameter = args[1];
if (searchParamsConfig.getFields() == null || searchParamsConfig.getFields().isEmpty()) {
return invocation.proceed(); // 如果没有配置字段,则直接返回
}
if (parameter instanceof Map) {
handleMapParameter((Map<String, Object>) parameter);
} else {
handlePojoParameter(parameter);
}
return invocation.proceed();
}
private void handleMapParameter(Map<String, Object> paramMap) {
for (String fieldName : searchParamsConfig.getFields()) {
if (paramMap.containsKey(fieldName)) {
String value = (String) paramMap.get(fieldName);
if (value != null) {
paramMap.put(fieldName, "%" + value.replace("%", "%").replace("_", "_") + "%");
}
}
}
//TODO 扩展 转义 % 和 _(根据数据库类型调整)
// if (isMySQL()) {
// //
// } else if (isSQLServer()) {
// //
// } else if (isPostgreSQL()) {
// //
// }
}
private void handlePojoParameter(Object pojo) {
for (String fieldName : searchParamsConfig.getFields()) {
try {
Field field = pojo.getClass().getDeclaredField(fieldName);
field.setAccessible(true); //实现不区分大小写的字段匹配(需自行处理大小写转换)
Object value = field.get(pojo);
if (value instanceof String) {
field.set(pojo, "%" + ((String)value).replace("%", "%").replace("_", "_") + "%");
}
} catch (NoSuchFieldException | IllegalAccessException ignored) {
// 如果字段不存在或不可访问,则跳过
}
}
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// 不需要额外处理
}
}
package org.coffeebeans.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
/**
* <li>ClassName: User </li>
* <li>Author: OakWang </li>
*/
@Data
public class User {
@TableField("id")
private Long id;
@TableField("name")
private String name;
@TableField("create_time")
private String createTime;
}
package org.coffeebeans.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.coffeebeans.entity.User;
import java.util.List;
@Mapper
public interface UserMapper {
List<User> selectBySearch(@Param("search") String search);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.coffeebeans.mapper.UserMapper">
<select id="selectBySearch" resultType="org.coffeebeans.entity.User">
SELECT * FROM User WHERE name LIKE #{search}
</select>
</mapper>
package org.coffeebeans;
import lombok.extern.slf4j.Slf4j;
import org.coffeebeans.service.InterceptorService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* <li>ClassName: org.org.coffeebeans.InterceptorTest </li>
* <li>Author: OakWang </li>
*/
@Slf4j
@SpringBootTest
public class InterceptorTest {
@Autowired
private InterceptorService interceptorService;
@Test
void test1() {
interceptorService.selectBySearch("1%");
}
@Test
void test2() {
interceptorService.selectBySearch("张_");
}
}
只找“1%”的数据,而不是所有带“1”的数据
只找“张_”的数据,而不是以“张”开头的数据
以上我们了解了如何在springboot项目中自定义mybatis拦截器以实现sql的全局封装。
在这里,我们专注于软件技术的交流与成长,分享开发心得与笔记,涵盖编程、AI、资讯、面试等多个领域。无论是前沿科技的探索,还是实用技巧的总结,我们都致力于为大家呈现有价值的内容。期待与你共同进步,开启技术之旅。