AOP
大约 3 分钟languagejava
获取 request
项目 https://gitee.com/chanchaw/zipperdye.git MybatisAspect.java 中有下面代码
import org.springframework.web.context.request.RequestContextHolder;
@Before("logDao()")
public void logDaoBefore(JoinPoint joinPoint) throws Exception {
// 获取 request
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 前端的请求地址:http://localhost:7075/zipperdye/contact/selectByPrimaryKey/12
log.info("dao请求地址:" + request.getRequestURL().toString());
// 请求方法:GET
log.info("dao请求类型:" + request.getMethod());
// 获得请求头中指定名称属性的值
String barreluser = request.getHeader("barreluser");
log.info("请求头barreluser:{}", barreluser);
String methodName = joinPoint.getSignature().getDeclaringTypeName()+"."+joinPoint.getSignature().getName();
log.info("SqlSessionFactory:" + sqlSessionFactory);//org.apache.ibatis.session.defaults.DefaultSqlSessionFactory
log.info("dao实现方法:" + methodName);//com.xdf.zipperdye.dao.business.ContactMapper.selectByPrimaryKey
log.info("dao参数:" + Arrays.toString(joinPoint.getArgs()));//获取发送请求时候传递来的参数(数组):[12]
打印带参 mybatis sql
使用 aop 在执行前打印出拼接参数后的 sql。初次试验在项目 https://gitee.com/chanchaw/zipperdye 改造步骤:
- pom.xml 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
- springboot 项目开启 aop 功能
@EnableAspectJAutoProxy
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
public class ZipperdyeApplication {...}
- Mybatis工具类 - 拼接参数到 sql 中
package com.xdf.zipperdye.utils;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.session.SqlSessionFactory;
import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author chanchaw
* @create 2022-09-30 9:37
*/
public class MyBatisSqlUtils {
public String execute(String sqlId, Object[] args, SqlSessionFactory sqlSessionFactory) throws Exception {
Map<String, Object> paramMap = initParamMap(args);
MappedStatement ms = sqlSessionFactory.getConfiguration().getMappedStatement(sqlId);
BoundSql boundSql = ms.getBoundSql(paramMap);
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
List<Object> paramValues = getParamValues(paramMap, parameterMappings);
// 获取执行的sql,此时未设置参数
String sql = boundSql.getSql();
// if(args!=null&&args.length==1&&(args[0] instanceof String)){
// paramValues.add(args[0]);
// }
for (int i = 0; i < args.length; i++) {
paramValues.add(args[0]);
}
String execSql = getExecuteSql(sql, paramValues.stream().filter(item -> item !=null).collect(Collectors.toList()));
return execSql;
}
/**
* 设置查询参数值,返回可直接执行的sql
*/
private String getExecuteSql(String sql, List<Object> paramValues) {
while(sql.indexOf("?") != -1 && paramValues!=null&¶mValues.size() > 0&& paramValues.get(0)!=null) {
Object paramValue = paramValues.get(0);
if (paramValue != null) {
String value = paramValue.toString();
if (paramValue instanceof String) {
value = "'" + paramValue.toString() + "'";
}
else if (paramValue instanceof Date || paramValue instanceof Timestamp) {
// value = DateUtil.dateToStr((Date) paramValue,"yyyy-MM-dd HH:mm:ss");
try {
// 将日期类型转换为格式 "yyyy-MM-dd HH:mm:ss" 的字符串,赋值给 value
value = DatetimeUtils.formatDate((Date)paramValue);
} catch (Exception e) {
throw new RuntimeException(e);
}
value = "str_to_date('" + value + "','%Y-%m-%d %T')";
}
sql = sql.replaceFirst("\\?", value);
paramValues.remove(0);
}
}
return sql;
}
/**
* 根据动态查询条件获取查询参数值
*/
private List<Object> getParamValues(Map<String,Object> paramMap,
List<ParameterMapping> parameterMappings) {
if (parameterMappings == null) {
return new ArrayList<Object>();
}
List<Object> paramValues = new ArrayList<Object>();
for (ParameterMapping pm : parameterMappings) {
if (pm.getMode() != ParameterMode.OUT) {
String paramName = pm.getProperty();
Object paramValue = paramMap.get(paramName);
paramValues.add(paramValue);
}
}
return paramValues;
}
/**
* 初始化查询参数
*/
private Map<String, Object> initParamMap(Object[] args) {
Map<String, Object> paramMap = new HashMap<String, Object>();
for (Object obj : args) {
if (obj instanceof Map) {
paramMap = (Map<String, Object>) obj;
}
}
return paramMap;
}
}
- 制作切面类
package com.xdf.zipperdye.aop;
import com.xdf.zipperdye.utils.MyBatisSqlUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
/**
* @author chanchaw
* @create 2022-09-30 9:26
*/
@Component
@Aspect
@Slf4j
public class MybatisAspect {
@Autowired
private SqlSessionFactory sqlSessionFactory;
// @Autowired
// private ApplicationContext applicationContext;
@Pointcut("execution(* com.xdf.zipperdye.dao.business.ContactMapper.*(..))")
public void logDao(){}
@Before("logDao()")
public void logDaoBefore(JoinPoint joinPoint) throws Exception {
log.info("RequestContextHolder.currentRequestAttributes:" + String.valueOf(RequestContextHolder.currentRequestAttributes()));
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
Assert.notNull(attributes,"通过上下文holder获取到了空的属性对象!");
HttpServletRequest request = attributes.getRequest();
log.info("dao请求地址:" + request.getRequestURL().toString());
log.info("dao请求类型:" + request.getMethod());
//
// SqlSessionFactory sqlSessionFactory = applicationContext.getBean(SqlSessionFactory.class);
String methodName = joinPoint.getSignature().getDeclaringTypeName()+"."+joinPoint.getSignature().getName();
log.info("SqlSessionFactory:" + sqlSessionFactory);
log.info("dao实现方法:" + methodName);
log.info("dao参数:" + Arrays.toString(joinPoint.getArgs()));
//仅获取无参数语句
String sqlRaw =sqlSessionFactory.getConfiguration().getMappedStatement(joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()).getBoundSql(null).getSql();
//获取最终执行的sql语句
log.info("joinPoint.getSignature().getDeclaringTypeName():" + joinPoint.getSignature().getDeclaringTypeName());
log.info("joinPoint.getSignature().getDeclaringType():" + joinPoint.getSignature().getDeclaringType());
log.info("joinPoint.getSignature().toString():" + joinPoint.getSignature().toString());
String sql=new MyBatisSqlUtils().execute(methodName, joinPoint.getArgs(),sqlSessionFactory);
log.info("无参SQL:" + sqlRaw);
log.info("拼接后的SQL:" + sql);
}
}
