博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【系统日志笔记二】——撸起袖子写个自定义日志注解
阅读量:6967 次
发布时间:2019-06-27

本文共 8707 字,大约阅读时间需要 29 分钟。

hot3.png

背景

最近手头一个项目进入转测阶段,测试组长提出要求把所有http请求的入参以及相应的json报文详细输出到日志文件,为了方便测试组小伙伴对每一个接口的验证。虽说不是功能性的需求,但是这样的要求确实有道理,让我无法抗拒啊。

步骤详解

自定义注解

  • Logc.java
import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * 
自定义日志记录注解
* * @author xubin
* @version 1.0
* @taskId
* @CreateDate 2019/4/12
*/@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Logc { /** * Description:
* * @author xubin
* @taskId
* @return
*/ String value() default "";}

使用AOP

  • pom.xml 引入依赖
org.springframework.boot
spring-boot-starter-aop
ch.qos.logback
logback-classic
  • MainLogAspect.java
import javax.servlet.http.HttpServletRequest;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.Signature;import org.aspectj.lang.annotation.AfterReturning;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;import org.springframework.stereotype.Component;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import lombok.extern.slf4j.Slf4j;/** * 
日志切面
* * @author xubin
* @version 1.0
* @taskId
* @CreateDate 2019/4/12
*/@Aspect@Slf4j@Componentpublic class MainLogAspect { /** * Description: 自定义切点
* * @author xubin
* @taskId
*/ @Pointcut("@annotation(com.minicore.salmon.aop.Logc)") public void pointCut() { } /** * Description: 前置通知-记录请求信息
* * @author xubin
* @taskId
* @param joinPoint
*/ @Before("pointCut()") public void doBeforeAdvice(JoinPoint joinPoint) { Signature signature = joinPoint.getSignature(); ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = sra.getRequest(); // 获取目标方法的参数信息 Object[] obj = joinPoint.getArgs(); log.info("[MainLogAspect]-request url:{}, class: {}, method: {}, param: {}", request.getRequestURI(), signature .getDeclaringTypeName(), signature.getName(), obj[0].toString()); } /** * Description: 后置通知-记录返回信息
* * @author xubin
* @taskId
* @param joinPoint
* @param result
*/ @AfterReturning(returning = "result", pointcut = "pointCut()") public void doAfterReturningAdvice(JoinPoint joinPoint, Object result) { Signature signature = joinPoint.getSignature(); ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = sra.getRequest(); log.info("[MainLogAspect]-response url:{}, class: {}, method: {}, param: {}", request.getRequestURI(), signature .getDeclaringTypeName(), signature.getName(), result.toString()); } /** * Description: 后置异常通知-记录返回出现异常
* * @author xubin
* @taskId
* @param joinPoint
* @param exception
*/ @AfterThrowing(value = "pointCut()", throwing = "exception") public void doAfterThrowingAdvice(JoinPoint joinPoint, Throwable exception) { Signature signature = joinPoint.getSignature(); ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = sra.getRequest(); log.info("[MainLogAspect]-response exception url:{}, class: {}, method: {}", request.getRequestURI(), signature .getDeclaringTypeName(), signature.getName()); }}

使用示例

  • 在web层需要输出日志的方法上加上注解@Logc
/**     * Description: 分页查询设备列表-无层级
* * @author xubin
* @taskId
* @param queryDeviceParamReq 查询条件 * @param request HttpServletRequest * @return
*/ @Logc @PostMapping(value = "/queryDeviceListByPage") public String queryDeviceListByPage(@RequestBody QueryDeviceInfoReq queryDeviceParamReq, HttpServletRequest request) { try { ValidateUtil.validate(queryDeviceParamReq); } catch (Exception e) { log.error("[DeviceApi]-queryDeviceList fail, param : {}, exception : {}", queryDeviceParamReq.toString(), e.getMessage()); return JsonUtil.getErrorJson(WebConstant.PARAM_EXCEPTION); } DeviceInfoBO deviceInfoBO = new DeviceInfoBO(); BeanUtils.copyProperties(queryDeviceParamReq, deviceInfoBO); deviceInfoBO.setAppKey(request.getHeader(CommonConstant.APP_KEY)); PageInfo
page = deviceInfoService.queryDeviceListByPage(deviceInfoBO, Optional.ofNullable(queryDeviceParamReq.getPageNum()).orElse(CommonConstant.DEFAULT_PAGE_NUM), Optional.ofNullable(queryDeviceParamReq.getPageSize()).orElse(CommonConstant.DEFAULT_PAGE_SIZE)); return JsonUtil.getSucc4data(Optional.ofNullable(page).orElse(new PageInfo
())); }
  • 日志输出
2019-05-29 14:40:52.223 INFO  http-nio-55001-exec-5 [com.minicore.salmon.aop.MainLogAspect:56]-[MainLogAspect]-request url:/salmon_device/deviceInfoApi/queryDeviceListByPage, class: com.minicore.salmon.rest.api.DeviceApi, method: queryDeviceListByPage, param: QueryDeviceInfoReq(pageNum=1, pageSize=20, deviceName=null, deviceCode=1559068230635, deviceType=null, deviceState=null, deviceMac=null, isOnline=null, isActivated=null)2019-05-29 14:40:52.263 DEBUG http-nio-55001-exec-5 [com.minicore.salmon.mapper.DeviceInfoEntityMapper.queryDeviceInfoList_COUNT:159]-==>  Preparing: SELECT count(0) FROM t_device_info d LEFT JOIN t_device_state ds ON d.device_state = ds.id LEFT JOIN t_device_type dt ON d.device_type = dt.id WHERE d.is_delete = 0 AND d.device_code = ? 2019-05-29 14:40:52.264 DEBUG http-nio-55001-exec-5 [com.minicore.salmon.mapper.DeviceInfoEntityMapper.queryDeviceInfoList_COUNT:159]-==> Parameters: 1559068230635(String)2019-05-29 14:40:52.265 DEBUG http-nio-55001-exec-5 [com.minicore.salmon.mapper.DeviceInfoEntityMapper.queryDeviceInfoList_COUNT:159]-<==      Total: 12019-05-29 14:40:52.266 DEBUG http-nio-55001-exec-5 [com.minicore.salmon.mapper.DeviceInfoEntityMapper.queryDeviceInfoList:159]-==>  Preparing: SELECT d.id, d.app_key, d.device_name, d.device_code, d.device_desc, d.device_type, dt.type_name AS device_type_name, dt.type_code AS device_type_code, d.is_online, d.is_online_upd_time, d.is_activated, d.activate_time, d.device_state, d.version, ds.state_name AS device_state_name, ds.state_code AS device_state_code, d.device_ipv4, d.device_mac, d.p_id, d.is_delete, d.create_time, d.creator, d.creator_id, d.update_time, d.modifier, d.modifier_id FROM t_device_info d LEFT JOIN t_device_state ds ON d.device_state = ds.id LEFT JOIN t_device_type dt ON d.device_type = dt.id WHERE d.is_delete = 0 AND d.device_code = ? ORDER BY d.create_time DESC LIMIT 20 2019-05-29 14:40:52.267 DEBUG http-nio-55001-exec-5 [com.minicore.salmon.mapper.DeviceInfoEntityMapper.queryDeviceInfoList:159]-==> Parameters: 1559068230635(String)2019-05-29 14:40:52.270 DEBUG http-nio-55001-exec-5 [com.minicore.salmon.mapper.DeviceInfoEntityMapper.queryDeviceInfoList:159]-<==      Total: 12019-05-29 14:40:52.272 INFO  http-nio-55001-exec-5 [com.minicore.salmon.aop.MainLogAspect:74]-[MainLogAspect]-response url:/salmon_device/deviceInfoApi/queryDeviceListByPage, class: com.minicore.salmon.rest.api.DeviceApi, method: queryDeviceListByPage, param: {"resCode":1,"resData":{"pageNum":1,"pageSize":20,"rows":[{"activateTime":null,"appKey":"7bbf10d0bdca560edb30dabb1254964d","createTime":"2019-05-29 02:30:31","creator":"","creatorId":"","deviceCode":"1559068230635","deviceDesc":"","deviceIpv4":"","deviceMac":"","deviceName":"1559068230635","deviceState":"","deviceStateCode":"","deviceStateName":"","deviceType":"6188028fb7f24f90a91e4c6ccd06798f","deviceTypeCode":"box","deviceTypeName":"anfang-pad","id":"0e26a36fd614467d8c3d7c8e9e99402b","isActivated":"1","isDelete":"0","isOnline":"1","isOnlineUpdTime":1559068230676,"modifier":"","modifierId":"","pId":"-1","subDeviceList":[],"updateTime":"2019-05-29 02:30:30","version":""}],"total":1},"resMsg":[]}

上面的日志会输出控制台,如何输出到指定的日志文件,可以参考另一篇log4j2配置示例

总结

     aop的灵活应用确实可以为我们省下很多重复性的工作,注解的使用让代码更加规范、简洁,这种代码动手撸一把真的可以让自己很放松???

转载于:https://my.oschina.net/u/872813/blog/3055584

你可能感兴趣的文章
MySQL索引的学习和研究
查看>>
Docker部署文档
查看>>
VS中的路径宏 vc++中OutDir、ProjectDir、SolutionDir各种路径
查看>>
Ubuntu下安装ruby的三种方式
查看>>
nginx location 配置详细解释
查看>>
nginx FastCGI错误Primary script unknown解决办法
查看>>
Systemd 笔记
查看>>
AngularJS实现产品列表(页面搜索,排序)
查看>>
php后台守护进程+进程信号处理
查看>>
Effective Python 小笔记之 zip 函数
查看>>
组网中交换机虚拟化技术的应用
查看>>
面向对象的最后一课
查看>>
rsync使用小结
查看>>
Docker安装mysql容器
查看>>
win7 64位系统连接xp 32位共享打印机办法
查看>>
使用功能开关更好地实现持续部署
查看>>
熔断,限流,降级 一些理解
查看>>
FreeBSD下安装配置Hadoop集群(四)
查看>>
cPanel之EasyApache (Apache Update)的使用
查看>>
VS2008修改工程名
查看>>