springMVC自定义注解,用AOP来实现日志记录的方法
作者:没有桃子的阿狸 发布时间:2023-11-29 13:58:53
标签:springMVC,自定义,注解,AOP,日志记录
需求背景
最近的一个项目,在项目基本完工的阶段,客户提出要将所有业务操作的日志记录到数据库中,并且要提取一些业务的关键信息(比如交易单号)体现在日志中。
为了保证工期,在查阅了资料以后,决定用AOP+自定义注解的方式来完成这个需求。
准备工作
自定义注解需要依赖的jar包有 aspectjrt-XXX.jar ,aspectjweaver-XXX.jar,XXX代表版本号。
自定义注解
在项目下单独建立了一个log包,来存放日志相关的内容
**.common.log.annotation //自定义注解存放位置
**.common.log.aop //aop工具类存放位置
在annotation包下面新建自定义注解类:
package **.common.log.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface XXXOperateLog {
/**
* 操作类型描述
* @return
*/
String operateTypeDesc() default "";
/**
* 操作类型
* @return
*/
long operateType() default -1;
/**
* 模块编码
* @return
*/
String moudleCode() default "M30";
/**
* 模块名称
* @return
*/
String moudleName() default "XX模块";
/**
* 业务类型
* @return
*/
String bussType() default "";
/**
* 业务类型描述
* @return
*/
String bussTypeDesc() default "";
}
在aop包下新建XXXOperateLogAop
package **.common.log.aop;
import ** ;//省略
@Aspect
@Component
public class XXXOperateLogAop{
@Autowired
SystemLogService systemLogService;
HttpServletRequest request = null;
Logger logger = LoggerFactory.getLogger(XXXOperateLogAop.class);
ThreadLocal<Long> time = new ThreadLocal<Long>();
//用于生成操作日志的唯一标识,用于业务流程审计日志调用
public static ThreadLocal<String> tag = new ThreadLocal<String>();
//声明AOP切入点,凡是使用了XXXOperateLog的方法均被拦截
@Pointcut("@annotation(**.common.log.annotation.XXXOperateLog)")
public void log() {
System.out.println("我是一个切入点");
}
/**
* 在所有标注@Log的地方切入
* @param joinPoint
*/
@Before("log()")
public void beforeExec(JoinPoint joinPoint) {
time.set(System.currentTimeMillis());
info(joinPoint);
//设置日志记录的唯一标识号
tag.set(UUID.randomUUID().toString());
request= ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
}
@After("log()")
public void afterExec(JoinPoint joinPoint) {
MethodSignature ms = (MethodSignature) joinPoint.getSignature();
Method method = ms.getMethod();
logger.debug("标记为" + tag.get() + "的方法" + method.getName()
+ "运行消耗" + (System.currentTimeMillis() - time.get()) + "ms");
}
//在执行目标方法的过程中,会执行这个方法,可以在这里实现日志的记录
@Around("log()")
public Object aroundExec(ProceedingJoinPoint pjp) throws Throwable {
Object ret = pjp.proceed();
try {
Object[] orgs = pjp.getArgs();
SystemLog valueReturn = null;
for (int i = 0; i < orgs.length; i++) {
if(orgs[i] instanceof SystemLog){
valueReturn = (SystemLog) orgs[i];
}
}
if(valueReturn==null){
valueReturn = new SystemLog();
}
if(valueReturn!=null&&request!=null){
MethodSignature ms = (MethodSignature) pjp.getSignature();
Method method = ms.getMethod();
//获取注解的操作日志信息
XXXOperateLog log = method.getAnnotation(XXXOperateLog.class);
String businessType = log.bussType();
String businessDesc = log.bussTypeDesc();
HashMap requestMap = ServletUtils.getParametersToHashMap(request) ;
//从参数中寻找业务类型
if(businessType.equals(""))
{
Object objBusinessType = requestMap.get("business_type");
businessType = objBusinessType == null ? "" : objBusinessType.toString();
}
//从执行结果的申请单中找业务类型
Object apply = request.getAttribute("apply") ;
if(apply != null){
JSONObject obj = JSONFactory.toJSONAbstractEntity(apply);
if(obj != null)
{
valueReturn.setOtherDesc("申请单号:"+obj.getString("apply_no"));
if(businessType.equals(""))
{
businessType = obj.getString("business_type");
}
}
}
//从方法的执行过程参数中找业务类型(一般是手动设置)
if(businessType.equals(""))
{
businessType = (String) request.getAttribute("business_type");
businessType = businessType == null ? "" : businessType;
}
if(!businessType.equals("") && businessDesc.equals(""))
{
businessDesc = XXXSysConstant.BUSINESS_TYPE.getName(businessType);
}
valueReturn.setBussType(XXXSysConstant.BUSINESS_TYPE.getNumber(businessType));
valueReturn.setBussTypeDesc(businessDesc);
valueReturn.setMoudleCode(log.moudleCode());
valueReturn.setMoudleName(log.moudleName());
valueReturn.setOperateResult(XXXSysConstant.YesOrNo.YES);
valueReturn.setOperateType(log.operateType());
valueReturn.setInputUserId(((UserContext)WebUtils.getSessionAttribute(request, "XXXuserContext")).getSysUser().getId());
valueReturn.setOperateTypeDesc(log.operateTypeDesc());
valueReturn.setRequestIp(getRemoteHost(request));
valueReturn.setRequestUrl(request.getRequestURI());
valueReturn.setServerIp(request.getLocalAddr());
valueReturn.setUids(tag.get());
//保存操作日志
systemLogService.saveSystemLog(valueReturn);
}else{
logger.info("不记录日志信息");
}
//保存操作结果
} catch (Exception e) {
e.printStackTrace();
}
return ret;
}
//记录异常日志
@AfterThrowing(pointcut = "log()",throwing="e")
public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
try {
info(joinPoint);
Object[] orgs = joinPoint.getArgs();
SystemLog valueReturn = null;
for (int i = 0; i < orgs.length; i++) {
if(orgs[i] instanceof SystemLog){
valueReturn = (SystemLog) orgs[i];
}
}
if(valueReturn==null){
valueReturn = new SystemLog();
}
if(valueReturn!=null&&request!=null){
MethodSignature ms = (MethodSignature) joinPoint.getSignature();
Method method = ms.getMethod();
XXXOperateLog log = method.getAnnotation(XXXOperateLog.class);
String businessType = log.bussType();
String businessDesc = log.bussTypeDesc();
if(businessType.equals(""))
{
Object objBusinessType = ServletUtils.getParametersToHashMap(request).get("business_type");
businessType = objBusinessType == null ? "" : objBusinessType.toString();
businessDesc = XXXSysConstant.BUSINESS_TYPE.getName(businessType);
}
valueReturn.setBussType(XXXSysConstant.BUSINESS_TYPE.getNumber(businessType));
valueReturn.setBussTypeDesc(businessDesc);
valueReturn.setMoudleCode(log.moudleCode());
valueReturn.setMoudleName(log.moudleName());
valueReturn.setOperateType(log.operateType());
valueReturn.setOperateTypeDesc(log.operateTypeDesc());
valueReturn.setInputUserId(((UserContext)WebUtils.getSessionAttribute(request, "XXXuserContext")).getSysUser().getId());
valueReturn.setOperateResult(XXXSysConstant.YesOrNo.NO);
String errMes = e.getMessage();
if(errMes!=null && errMes.length()>800){
errMes = errMes.substring(0, 800);
}
valueReturn.setErrorMessage(errMes);
valueReturn.setRequestIp(getRemoteHost(request));
valueReturn.setRequestUrl(request.getRequestURI());
valueReturn.setServerIp(request.getLocalAddr());
valueReturn.setUids(tag.get());
systemLogService.saveSystemLog(valueReturn);
}else{
logger.info("不记录日志信息");
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
private void info(JoinPoint joinPoint) {
logger.debug("--------------------------------------------------");
logger.debug("King:\t" + joinPoint.getKind());
logger.debug("Target:\t" + joinPoint.getTarget().toString());
Object[] os = joinPoint.getArgs();
logger.debug("Args:");
for (int i = 0; i < os.length; i++) {
logger.debug("\t==>参数[" + i + "]:\t" + os[i].toString());
}
logger.debug("Signature:\t" + joinPoint.getSignature());
logger.debug("SourceLocation:\t" + joinPoint.getSourceLocation());
logger.debug("StaticPart:\t" + joinPoint.getStaticPart());
logger.debug("--------------------------------------------------");
}
/**
* 获取远程客户端Ip
* @param request
* @return
*/
private String getRemoteHost(javax.servlet.http.HttpServletRequest request){
String ip = request.getHeader("x-forwarded-for");
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
ip = request.getHeader("Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
ip = request.getHeader("WL-Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
ip = request.getRemoteAddr();
}
return ip.equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip;
}
}
修改配置文件spring-mvc.xml,添加如下配置
<!-- 开启AOP拦截 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
<mvc:annotation-driven />
<!-- 定义Spring描述Bean的范围 -->
<context:component-scan base-package="**.common.log" >
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
需要注意的是,上述配置必须放在同一个xml文件里面,要么spring-mvc.xml,要么spring-context.xml,否则可能不生效,暂时还未查明是为什么。
注解的使用
@XXXOperateLog(
bussType=XXXSysConstant.BUSINESS_TYPE.YYYY
,bussTypeDesc="业务类型描述"
,operateType = XXXSysConstant.LogOperateType.QUERY
,operateTypeDesc = "操作描述"
)
@RequestMapping(value = "/**/**/queryXXXXX4DataGrid.json", method = RequestMethod.POST)
public void queryXXXXX4DataGrid(HttpServletRequest request, HttpServletResponse arg1, Model model, Writer writer)
{
logger.info("==========验票查询(出库)交易信息 开始=====================");
try {
//do something for business
} catch (SystemException se) {
throw se;
} catch (BusinessException be) {
throw be;
} catch (Exception e) {
throw new SystemException(e);
}
}
来源:http://blog.csdn.net/yang_lover/article/details/53037323
0
投稿
猜你喜欢
- 前言: 之前安装了Ubuntu 18.04,结果在安装Codeblocks / VScode还是安装gcc,c/c++的时候出现了一堆错误(
- 首先需要一个自定义view用来签字使用,可以修改颜色和画笔的粗细,可以擦拭重新画package com.android.tcm.view;i
- 原项目基于mybatis开发,新功能基于mybatis-plus开发,同时依赖如下两个jar包mybatis-spring-boot-sta
- 1.用途在SpringBoot中,通过jasypt可以进行加密解密. 这个是双向的, 且可以配置密钥.2.使用:2.1通过UT创建工具类,并
- 本文实例为大家分享Winform版计算器的具体实现方法,供大家参考,具体内容如下前台页面设计后台代码实现using System;using
- 如今APP越来越多,我们每天所使用的的软件也越来越多,可是在我们不付费的情况下,App制造商如何实现,实现收入甚至是盈利呢?答案就是在我们打
- 单例模式创建唯一的一个变量(对象),在类中将构造函数设为protected或者private(析构函数设为相对应的访问权限),故外部不能实例
- 默认情况下Spring Boot使用了内嵌的Tomcat服务器,项目最终被打成jar包运行,每个jar包可以被看作一个独立的Web服务器。传
- 概述本文基于示例的方式解释控制反转,再看控制反转之前,我们先看下常规控制流程,以数据库访问为例示例并没有实际访问数据,而是基于service
- 如何下载并配置JDK 15进入官网下载JDK 15。官网地址:https://www.oracle.com/index.html脚本之家下载
- 一、简介在上篇 ElasticSearch 文章中,我们详细的介绍了 ElasticSearch 的各种 api 使用。实际的项目开发过程中
- springboot和vue结合的方案网络上的主要有以下两种:1. 【不推荐】在html中直接使用script标签引入vue和一些常用的组件
- 本文实例讲述了WinForm通过操作注册表实现限制软件使用次数的方法。分享给大家供大家参考,具体如下:1.创建注册表文件:打开记事本,输入一
- 类加载子系统classLoader 只负责对字节码文件的加载,至于是否可以运行,还要看执行引擎。加载的类信息存放于方法区的内存空间,除了类信
- 目录1、对于A、B两种排队方式,说法正确的是2、Inter-process communication (IPC) is the trans
- 在开发中我们经常需要把我们的应用设置为全屏,有两种方法,一中是在代码中设置,另一种方法是在配置文件里改!一、在代码中设置:package c
- 在Eclipse中创建Android项目,利用之前学过的WebView控件和中国天气网提供的天气数据接口,实现获取指定城市的天气预报。布局文
- 使用场景EntityListeners在jpa中使用,如果你是mybatis是不可以用的它的意义对实体属性变化的跟踪,它提供了保存前,保存后
- Swagger是一款遵循 Restful 风格的接口文档开发神器,支持基于 API 自动生成接口文档,接口文档始终与 API 保持同步,不再
- 本文实例讲述了C#实现带阴历显示的日期代码,分享给大家供大家参考。具体方法如下:这是一个用于酒店预定功能的带日期控件,类似去哪网酒店预定,由