如何获取MyBatis Plus执行的完整的SQL语句
作者:梁云亮
这篇文章主要介绍了如何获取MyBatis Plus执行的完整的SQL语句问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
注意:本示例介绍的方法仅支持MyBatis Plus
原理
自定义插件,将SQL语句中的?替换成具体的参数值。
实现
自定义插件
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; import com.tiku.utils.LogUtil; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.ParameterMapping; import org.apache.ibatis.reflection.MetaObject; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.apache.ibatis.type.TypeHandlerRegistry; import java.sql.SQLException; import java.text.DateFormat; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.regex.Matcher; public class MyBatisPlusSqlLogInterceptor implements InnerInterceptor { private static boolean printSQL = true; @Override public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { if (printSQL) { MappedStatement mappedStatement = ms; String sqlId = mappedStatement.getId(); Configuration configuration = mappedStatement.getConfiguration(); String sql = getSql(configuration, boundSql, sqlId); final String ip = RequestUtil.getIp(); final String requestType = RequestUtil.getMethod(); final String url = RequestUtil.getRequestUrl(); final String parameters = RequestUtil.getParameters(); String userAgent = RequestUtil.getUserAgent(); UserAgent agent = UserAgent.parseUserAgentString(userAgent); final String browser = agent.getBrowser().getName(); final String os = agent.getOperatingSystem().getName(); LogUtil.println("用户访问了:{},浏览器是:{},操作系统是:{},IP是:{},请求方式是:{},请求参数是:{},SQL语句是:{}", url, browser, os, ip, requestType, parameters, sql); } } @Override public void beforeUpdate(Executor executor, MappedStatement ms, Object parameter) throws SQLException { if (printSQL) { MappedStatement mappedStatement = ms; String sqlId = mappedStatement.getId(); Configuration configuration = mappedStatement.getConfiguration(); BoundSql boundSql = mappedStatement.getBoundSql(parameter); String sql = getSql(configuration, boundSql, sqlId); final String ip = RequestUtil.getIp(); final String requestType = RequestUtil.getMethod(); final String url = RequestUtil.getRequestUrl(); final String parameters = RequestUtil.getParameters(); String userAgent = RequestUtil.getUserAgent(); UserAgent agent = UserAgent.parseUserAgentString(userAgent); final String browser = agent.getBrowser().getName(); final String os = agent.getOperatingSystem().getName(); LogUtil.println("用户访问了:{},浏览器是:{},操作系统是:{},IP是:{},请求方式是:{},请求参数是:{},SQL语句是:{}", url, browser, os, ip, requestType, parameters, sql); } } private String getSql(Configuration configuration, BoundSql boundSql, String sqlId) { try { String sql = showSql(configuration, boundSql); StringBuilder str = new StringBuilder(100); str.append(sqlId); str.append(" ==> "); str.append(sql); str.append(";"); return str.toString(); } catch (Error e) { LogUtil.error("解析 sql 异常", e); } return ""; } private String showSql(Configuration configuration, BoundSql boundSql) { Object parameterObject = boundSql.getParameterObject(); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); String sql = boundSql.getSql().replaceAll("[\\s]+", " "); if (parameterMappings != null && parameterMappings.size() > 0 && parameterObject != null) { TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(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("\\?", Matcher.quoteReplacement(getParameterValue(obj))); } else if (boundSql.hasAdditionalParameter(propertyName)) { Object obj = boundSql.getAdditionalParameter(propertyName); sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(obj))); } } } } return sql; } private String getParameterValue(Object obj) { String value = null; if (obj instanceof String) { value = "'" + obj.toString() + "'"; } else if (obj instanceof Date) { DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.CHINA); value = "'" + formatter.format(obj) + "'"; } else if (obj instanceof LocalDate) { value = "'" + ((LocalDate) obj).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + "'"; } else if (obj instanceof LocalDateTime) { value = "'" + ((LocalDateTime) obj).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + "'"; } else { if (obj != null) { value = obj.toString(); } else { value = ""; } } return value; } }
上面代码用到的两个工具类:
- RequestUtil.java
import com.tiku.enums.ResultEnum; import com.tiku.ex.GlobalException; import jakarta.servlet.http.HttpServletRequest; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** * @author hc */ public class RequestUtil { /** * 私有构造方法,防止实例化 */ private RequestUtil() { } /** * 获取所有的请求参数及值 * * @return eg:pageNum=3&pageSize=5&state=0 */ public static String getParameters() { HttpServletRequest request = SpringContextUtil.getRequest(); if (null == request) { return null; } Enumeration<String> paraNames = request.getParameterNames(); if (paraNames == null) { return null; } StringBuilder sb = new StringBuilder(); while (paraNames.hasMoreElements()) { String paraName = paraNames.nextElement(); sb.append("&").append(paraName).append("=").append(request.getParameter(paraName)); } return sb.toString(); } public static Map<String, String> getParameterMap(HttpServletRequest request) { // 参数Map Map<String, String[]> properties = request.getParameterMap(); // 返回值Map Map<String, String> returnMap = new HashMap<>(16); Iterator<Map.Entry<String, String[]>> entries = properties.entrySet().iterator(); Map.Entry<String, String[]> entry; String name; String value = ""; while (entries.hasNext()) { entry = entries.next(); name = entry.getKey(); Object valueObj = entry.getValue(); if (null == valueObj) { value = ""; } else { String[] values = (String[]) valueObj; for (String value1 : values) { value = value1 + ","; } value = value.substring(0, value.length() - 1); } returnMap.put(name, value); } return returnMap; } /** * 获取用户所有的请求参数,以Map的形式返回 * * @return */ public static Map<String, String[]> getParametersMap() { HttpServletRequest request = SpringContextUtil.getRequest(); if (null == request) { return new HashMap<>(); } return request.getParameterMap(); } /** * 获取请求头中指定名称的值 * * @param name * @return */ public static String getHeader(String name) { HttpServletRequest request = SpringContextUtil.getRequest(); if (null == request) { return null; } return request.getHeader(name); } public static String getReferer() { return getHeader("Referer"); } /** * 获取用户代理对象 * * @return */ public static String getUserAgent() { return getHeader("User-Agent"); } /** * 获取请求用户的IP地址 * * @return */ public static String getIp() { HttpServletRequest request = SpringContextUtil.getRequest(); if (null == request) { return null; } return IPUtil.getIpAddr(request); } /** * 获取用户请求的Controller的路径 * * @return 比如:http://localhost/list */ public static String getRequestUrl() { HttpServletRequest request = SpringContextUtil.getRequest(); if (null == request) { return null; } return request.getRequestURL().toString(); } /** * 获取URI * * @return */ public static String getRequestUri() { HttpServletRequest request = SpringContextUtil.getRequest(); if (null == request) { return null; } return request.getRequestURI(); } /** * 获取用户请求的方式,值有: POST GET 3 PUT DELETE * * @return */ public static String getMethod() { HttpServletRequest request = SpringContextUtil.getRequest(); if (null == request) { return null; } return request.getMethod(); } /** * 判断用户的请求是否是AJAX请求 * * @param request * @return */ public static boolean isAjax(HttpServletRequest request) { if (null == request) { request = SpringContextUtil.getRequest(); } if (null == request) { return false; } // 解析原错误信息,封装后返回,此处返回非法的字段名称,原始值,错误信息 // 使用HttpServletRequest中的header检测请求是否为ajax, 如果是ajax则返回json, 如果为非ajax则返回view(即ModelAndView) String contentTypeHeader = request.getHeader("Content-Type"); String acceptHeader = request.getHeader("Accept"); String xRequestedWith = request.getHeader("X-Requested-With"); return (contentTypeHeader != null && contentTypeHeader.contains("application/json")) || (acceptHeader != null && acceptHeader.contains("application/json")) || "XMLHttpRequest".equalsIgnoreCase(xRequestedWith); } /** * 从HttpServletReqeust对象中获取key对应的值 先从Reqeust Parameter中获取,如果没有再从Header中获取 * * @param key * @return */ public static String getValueFromRequest(String key) { HttpServletRequest request = SpringContextUtil.getRequest(); return getValueFromRequest(request, key); } /** * 从HttpServletReqeust对象中获取key对应的值 先从Reqeust Parameter中获取,如果没有再从Header中获取 * * @param request * @param key * @return */ public static String getValueFromRequest(HttpServletRequest request, String key) { String token = request.getParameter(key); // 从header中获取值 if (token == null) { token = request.getHeader(key); } if (token == null) { throw new GlobalException(ResultEnum.TOKEN_INVALID); } return token; } }
- UserAgent
该工具类是第三方jar包中定义的:UserAgentUtils-1.21.jar
注册插件
@Configuration public class MyBatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new MyBatisPlusSqlLogInterceptor()); return interceptor; } }
这样在执行CRUD操作数据时,就会在控制台中输出相应的完整的SQL语句
比如:
2024-05-20 07:46:22.365 [INFO ] [] 6868 -- SqlLogInterceptor.beforeQuery() Line: 48 Line:100 : 用户访问了:http://127.0.0.1:8081/tiku/user/v1/login,浏览器是:Chrome 12,操作系统是:Windows 10,IP是:127.0.0.1,请求方式是:POST,请求参数是:,SQL语句是:com.tiku.mapper.UserDetailsMapper.selectById ==> SELECT id,num,nickname,`name`,avatar,gender,birth,email,tel,qq,wechat,credit,interest,country_id,addr,verify_time,login_time,login_ip,login_addr,creator_id,updater_id,info,priority,create_time,update_time FROM sys_user_details WHERE id=1;
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。