Spring AOP 最常用的地方之一就是记录日志,这里记录除了记录日志描述外,还记录了方法请求的参数,并将记录保存到数据库。这里用到了自定义注解,使用如下
1. 创建 log 日志类,并生产相应的pojo,pojo如下
public class OperationLog implements Serializable {
/**
*
*/
private static final long serialVersionUID = 7087799444017468909L;
private Integer id;
private String userId;
private String operatType;
private String content;
private String remarks;
private Date create;
// getXXX()和setXXX()省略
}
2. 创建注解类 SystemServiceLog
/**
* AOP 日志记录,自定义注解
* @author xxx
* @since JDK1.8
*/
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemServiceLog {
// 日志描述
String description() default "";
// 操作类型
int tableType() default 0;
}
省略创建dao和service的代码
3. 创建拦截方法,这里只在请求前拦截
@Aspect
@Component
public class SystemLogAspect {
@Autowired
private OperationLogService operationLogService;
@Pointcut("@annotation(com.xxx.common.annotation.SystemServiceLog)")
public void serviceAspect() {
}
@After("serviceAspect()")
public void doServiceLog(JoinPoint joinPoint) {
// 获取用户信息
Session session = SecurityUtils.getSubject().getSession();
UserInfo user = (UserInfo) session.getAttribute(ShiroDbRealm.SESSIOIN_USER_KEY);
OperationLog log = new OperationLog();
try {
String content = getServiceMthodDescription(joinPoint);
log.setContent(user.getRealName() + content);
log.setRemarks(getServiceMethodParams(joinPoint));
log.setUserId(user.getId());
String operatType = getServiceMthodTableType(joinPoint);
log.setOperatType(operatType);
operationLogService.insert(log);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获取注解中对方法的描述信息 用于service层注解
* @param joinPoint 切点
* @return 方法描述
* @throws ClassNotFoundException
*/
private String getServiceMthodDescription(JoinPoint joinPoint) throws ClassNotFoundException {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] methods = targetClass.getMethods();
String description = "";
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
description = method.getAnnotation(SystemServiceLog.class).description();
break;
}
}
}
return description;
}
/**
* 获取注解方法中的描述信息 用于 Service 层注解
* @param joinPoint 切点
* @return 方法描述
* @throws ClassNotFoundException
*/
private String getServiceMthodTableType(JoinPoint joinPoint) throws ClassNotFoundException {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] methods = targetClass.getMethods();
String description = "";
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
description = method.getAnnotation(SystemServiceLog.class).description();
break;
}
}
}
return description;
}
/**
* 获取json格式的参数<br>
*
* @param joinPoint
* @return
* @since JDK1.8
*/
private String getServiceMethodParams(JoinPoint joinPoint) {
Object[] arguments = joinPoint.getArgs();
if (arguments == null || arguments.length == 0) {
return "无参数";
}
List<Object> list = new ArrayList<>(Arrays.asList(arguments));
String params = JsonUtil.getJsonStringFromPOJO(list);
return params;
}
}
4. 在service的实现类的方法上使用自定义注解记录日志
@Override
@Transactional
@SystemServiceLog(description=Constants.CLIENT_SELECT_LIST, tableType=Constants.USER_TABLE_TYPE)
public Map<String, Object> queryXXX(String name, String address) {
Map<String, Object> map = new HashMap<>();
// 省略
return map;
}