MybatisPlus拦截器打印完整SQL、分页、自动填充处理
MybatisPlus拦截器打印完整SQL
MybatisPlus 虽然也自带了一个打印 SQL 的配置,但是不方便查看,也没有时间统计
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
拦截器PrintSqlInterceptor
/**
* @author CoderKK
* @date 2020-09-01 00:13
*/
@Slf4j
@Intercepts({
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class,
RowBounds.class, ResultHandler.class})})
public class PrintSqlInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
Object parameter = null;
if (invocation.getArgs().length > 1) {
parameter = invocation.getArgs()[1];
}
String sqlId = mappedStatement.getId();
BoundSql boundSql = mappedStatement.getBoundSql(parameter);
Configuration configuration = mappedStatement.getConfiguration();
long start = System.currentTimeMillis();
Object returnValue = invocation.proceed();
long time = System.currentTimeMillis() - start;
showSql(configuration, boundSql, time, sqlId);
return returnValue;
}
private static void showSql(Configuration configuration, BoundSql boundSql, long time, String sqlId) {
Object parameterObject = boundSql.getParameterObject();
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
//替换空格、换行、tab缩进等
String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
if (parameterMappings.size() > 0 && parameterObject != null) {
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
sql = sql.replaceFirst("\\?", getParameterValue(parameterObject));
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
for (ParameterMapping parameterMapping : parameterMappings) {
String propertyName = parameterMapping.getProperty();
if (metaObject.hasGetter(propertyName)) {
Object obj = metaObject.getValue(propertyName);
sql = sql.replaceFirst("\\?", getParameterValue(obj));
} else if (boundSql.hasAdditionalParameter(propertyName)) {
Object obj = boundSql.getAdditionalParameter(propertyName);
sql = sql.replaceFirst("\\?", getParameterValue(obj));
}
}
}
}
logs(time, sql, sqlId);
}
private static String getParameterValue(Object obj) {
String value;
if (obj instanceof String) {
value = "'" + obj + "'";
} else if (obj instanceof Date) {
DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.CHINA);
value = "'" + formatter.format(new Date()) + "'";
} else {
if (obj != null) {
value = obj.toString();
} else {
value = "";
}
}
return value.replace("$", "\\$");
}
private static void logs(long time, String sql, String sqlId) {
StringBuilder sb = new StringBuilder()
.append(" Time:").append(time)
.append(" ms - ID:").append(sqlId)
.append(StringPool.NEWLINE).append("Execute SQL:")
.append(sql).append(StringPool.NEWLINE);
log.info(sb.toString());
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties0) {
}
}
MybatisPlus配置 MybatisPlusConfig
package com.example.demojs.config;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.example.demojs.common.PrintSqlInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
@Configuration
public class MybatisPlusConfig {
/**
* mybatis-plus分页插件
*/
/*
// 旧版
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
// paginationInterceptor.setLimit(500);
// 开启 count 的 join 优化,只针对部分 left join
paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return paginationInterceptor;
}
// 新版
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
// 如何区分新旧版呢?其实你把这两种代码都复制到你的项目里,哪个类存在就用哪个方法。
// 3.4.0版本对此部分有更新,如果是旧版本升级,会出现分页失效问题,同时idea会提示PaginationInterceptor过时,新版本改用了MybatisPlusInterceptor
*/
/**
*自定义mybatis插件 注入方式一
*/
/*
@Bean
public MybatisPlusInterceptor mybatisInterceptor() {
MybatisPlusInterceptor mybatisInterceptor = new MybatisPlusInterceptor();
Properties properties = new Properties();
properties.setProperty("name", name);
mybatisInterceptor.setProperties(properties);
return mybatisInterceptor;
}
*/
/**
*自定义mybatis插件 注入方式二
*/
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> {
//插件拦截链采用了责任链模式,执行顺序和加入连接链的顺序有关
//MybatisInterceptor mybatisInterceptor = new MybatisInterceptor();
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
//设置参数,比如阈值等,可以在配置文件中配置
Properties properties = new Properties();
//properties.setProperty("name", name);
mybatisPlusInterceptor.setProperties(properties);
//自定义打印SQL
PrintSqlInterceptor printSqlInterceptor = new PrintSqlInterceptor();
configuration.addInterceptor(printSqlInterceptor);
};
}
/**
* mybatis-plus SQL执行效率插件【生产环境可以关闭】 3.3.2版本移除了该功能,3.0.3和3.0.3之前版本支持。
*/
/*
@Bean
public PerformanceInterceptor performanceInterceptor() {
return new PerformanceInterceptor();
}
*/
}
打印效果
2022-08-29 16:42:03.782 INFO 17476 --- [nio-8080-exec-2] c.e.demojs.common.PrintSqlInterceptor : Time:397 ms - ID:com.example.demojs.dao.UserMapper.insert
Execute SQL:INSERT INTO test_user ( id, user_id, phone, birthday, sex ) VALUES ( 1564171509361389569, 'abc', '13988776664', 2022-08-29T16:41:59.514, 1 )
自动填充插件
/**
* @author CoderKK
* @date 2020/9/6 15:21
* @desc 自动填充处理器类
*/
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* 插入时的填充策略
*
* @param metaObject
*/
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime", LocalDateTime.now(), metaObject);
this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
}
/**
* 更新时的填充策略
*
* @param metaObject
*/
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
}
}
实体类记得加注解
@TableField(value = "create_time", fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm", timezone = "GMT+8")
private LocalDateTime createTime;
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm", timezone = "GMT+8")
private LocalDateTime updateTime;
分页插件
注入分页插件后,如何使用呢?
mapper写法:
// 这是mapper自己提供的方法,参数是wrapper 适用于单表查
<P extends IPage<T>> P selectPage(P page, @Param("ew") Wrapper<T> queryWrapper);
// 自定义sql,适用于多表联查
IPage<UserVO> queryUserList(Page<UserVO> page, @Param("dto") ConditionDTO conditionDTO);
📢注意的点:
1.Page为IPage的实现类,分页返回和传入Page是同一个对象
2.Page类必须放在第一位
3.第二个参数和后续参数必须加@Param,(基本类型和实体类型都需要加),否则会报找不到属性错误。
mapper.xml:
<select id="queryUserList" resultType="com.test.vo.UserVO">
select *
from auth_user
where sex = #{dto.sex}
and cancat_ws(':',name,phone) like concat('%',#{dto.searchKey,'%'})
</select>
service调用mapper
public PageDataVO<UserVO> getUserList( ConditionDTO conditionDTO) {
// 分页查询
Page<UserVO> page = new Page<>(conditionDTO.getPageNum(), conditionDTO.getPageSize());
IPage<UserVO> result = userMapper.queryUserList(page, conditionDTO);
//构建自己的分页实体类
return new PageDataVO<WorkReviewVO>().build(result);
}
参考
https://www.modb.pro/db/229426
我的技术博客 https://blog.52ipc.top/
本文来自博客园,作者:Micky233,转载请注明原文链接:https://www.cnblogs.com/geek233/p/16643272.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~