项目场景:
在项目开发的过程当中,我们想通过注解标识的形式实现,那些接口需要记录日志。本项目是基于SpringBoot框架的基础之上记录,注解在实战用的应用。
操作步骤:
1、编写@interface注解类
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogAnnotation {
/**
* 操作
*/
public OperationTypeEnum operatorType() default OperationTypeEnum.SELECT;
/**
* 是否保存请求的参数
*/
public boolean isSaveRequestData() default true;
/**
* 是否保存响应的参数
*/
public boolean isSaveResponseData() default true;
/**
* 备注信息
*/
public String remarks() default "";
}
2、编写切面处理类
@Aspect
@Component
public class LogAspect {
@Pointcut("@annotation(com.xyy.annotation.LogAnnotation)")
public void logPointCut() {
}
@AfterReturning(pointcut = "@annotation(log)", returning = "ret")
public void doAfterReturning(JoinPoint joinPoint, LogAnnotation log, Object ret) {
handleLog(joinPoint, log, ret);
}
@AfterThrowing(value = "@annotation(log)", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, LogAnnotation log, Exception e) {
handleLException(joinPoint,log,e);
}
/**
* 处理请求返回信息
*/
protected void handleLog(JoinPoint joinPoint, LogAnnotation log, Object ret) {
HttpServletRequest request = ServletUtils.getRequest();
String ipAddress = IpUtils.getIpAddr(request);//IP 地址
LoginUser loginUser = tokenUtils.getLoginUser(request); //用户信息,暂时不处理
BusLog busLog = packageBusLog(joinPoint, ipAddress, log, loginUser);
String responseParameters = JSONUtil.toJsonStr(ret);//返回参数字符串
busLog.setResponseParam(responseParameters.getBytes(StandardCharsets.UTF_8));
busLogService.save(busLog);
}
/**
* 处理请求异常信息
*/
protected void handleLException(JoinPoint joinPoint, LogAnnotation log, Exception e) {
HttpServletRequest request = ServletUtils.getRequest();
LoginUser loginUser = tokenUtils.getLoginUser(request); //用户信息,暂时不用处理
String ipAddress = IpUtils.getIpAddr(request);//IP 地址
BusLog busLog = packageBusLog(joinPoint, ipAddress, log, loginUser);
busLog.setExceptionInfo(e.getMessage());
busLogService.save(busLog);
}
/**
* 处理请求参数,封装请求参数为JSON字符串
*/
protected static Map<String, String> handleRequestParameters(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
Object[] args = joinPoint.getArgs();
MethodSignature methodSignature = (MethodSignature) signature;
String[] parameterNames = methodSignature.getParameterNames(); /**获取方法签名*/
Type[] genericParameterTypes = methodSignature.getMethod().getGenericParameterTypes();/**获取所有的参数类型*/
Map resultMap = new HashMap();
for (int i = 0; i < args.length; i++) {
System.out.println("参数类型--------------->" + genericParameterTypes[i]);
System.out.println(parameterNames[i]);
System.out.println(JSONUtil.toJsonStr(args[i]));
if (foundationType(genericParameterTypes[i].toString())) {
resultMap.put(parameterNames[i], args[i]);
} else {
resultMap.put(parameterNames[i], JSONUtil.toJsonStr(args[i]));
}
}
return resultMap;
}
/**
* 处理JSONUtils中把基础类型数据转换成{}对象的问题,JSON传递Interger和Long的时,JSONUtil.toJsonStr()处理不了
*/
protected static boolean foundationType(String params) {
if (params.indexOf("Long") > -1) {
return true;
}
if (params.indexOf("long") > -1) {
return true;
}
if (params.indexOf("Integer") > -1) {
return true;
}
if (params.indexOf("int") > -1) {
return true;
}
return false;
}
}
3、使用方法
使用方法:在方法上标识注解标识,补充自己定义的注解标识字段对应的值。
@LogAnnotation(operatorType = OperationTypeEnum.SELECT) /**注意:这里=前面的是自定义注解的方法名,如果是枚举类型的话,处理类中获取对应的值(本例子中,在切面类中获取枚举对应的值)*/
@Override
public AjaxResult bookInfo(BooKInfoRequest booKInfoRequest) {
BookInfo bookInfo = httpRequestUtils.queryBookInfo(booKInfoRequest.getBarCode());
LoginUser loginUser = tokenUtils.getLoginUser(ServletUtils.getRequest());
System.out.println(JSONUtil.toJsonStr(loginUser));
BookInfoResponse bookInfoResponse = new BookInfoResponse();
String [] ignoreProperties={"createTime","dueDate","holdPickupDate","recallDate","transactionDate","updateTime"};
Date transactionDate = DateUtil.parse(bookInfo.getTransactionDate().replaceAll(" ",""));
BeanUtil.copyProperties(bookInfo,bookInfoResponse,ignoreProperties);
bookInfoResponse.setTransactionDate(transactionDate);
System.out.println(JSONUtil.toJsonStr(bookInfoResponse));
return AjaxResult.success(bookInfoResponse);
}
填坑总结:
1、自定义注解类中定义的都是方法(自己编写的时候,写成了属性,各位大佬见笑)。
2、枚举类中获取参数的时候,在业务处理类中获取枚举类对应的参数
3、Hutool使用过程中,遇到前端传来的参数是Long或者Integer相关的变量时,在使用JSONUtil.toJsonStr()时,返回是空。
4、在handleRequestParameters()方法中,可以通过joinPoint获取相关参数的的方式,有需要的同学可以自取。
5、BeanUtil 工具在使用的过程当中可以忽略默写字段不进行属性值的copy。 BeanUtil.copyProperties(bookInfo,bookInfoResponse,ignoreProperties);