Spring-Aop处理记录日志

    xiaoxiao2025-08-26  5

    AOP的几种通知类型:

    1,前置通知(Before advice):在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行 配置文件中使用 <aop:before>进行声明 注解使用 @Before 进行声明 2,后置通知(After advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。 配置文件中使用<aop:after>进行声明 注解使用 @After 进行声明 3,返回后通知(After return advice):在某连接点正常完成后执行的通知,不包括抛出异常的情况。 配置文件中使用<after-returning>进行声明 注解使用 @AfterReturning 进行声明 4,环绕通知(Around advice):包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。 可以在方法的调用前后完成自定义的行为,也可以选择不执行。 配置文件中使用<aop:around>进行声明 注解使用 @Around 进行声明 5,抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知。 配置文件中使用<aop:after-throwing>进行声明 注解使用 @AfterThrowing 进行声明

    需要先引入相关jar包, 如果用Maven则在pom文件中加入下面配置,此时Maven会自动导入相关jar包

    <!-- 引入AOP所需要的jar包 --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.7.2</version> </dependency>

    Spring的applicationContext.xml 文件中的配置

    这三个是aop的 xmlns:aop=”http://www.springframework.org/schema/aop

    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:task="http://www.springframework.org/schema/task" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"> <!---注解配置开始 如果使用注解配置Aop则需要配置这两个参数 --> <!-- 激活组件扫描功能,在包cn.ysh.studio.spring.aop及其子包下面自动扫描通过注解配置的组件 --> <!-- <context:component-scan base-package="cn.ysh.studio.spring.aop"/> --> <!-- 激活自动代理功能 --> <!-- <aop:aspectj-autoproxy proxy-target-class="true"/> --> <!---注解配置结束 --> <aop:config> <!-- 声明一个切面,并注入切面Bean,相当于@Aspect --> <aop:aspect id="myAop" ref="auditLogAop"> <!--配置一个切点,相当于@Pointcut * 表示通配所有类型返回值或则没有返回值都可以 com.unionpay.techjoin.common.service..*.*(..) 表示com.unionpay.techjoin.common.service包下所以类 (..)表示所有参数类型 --> <aop:pointcut id="myAuditLog" expression="execution(* com.unionpay.techjoin.common.service..*.*(..))" /> <!--配置环绕通知 相当于@Around--> <aop:around method="addAuditLog" pointcut-ref="myAuditLog"/> </aop:aspect> </aop:config>

    如果需要通知中获取Request对象,则需要在web.xml中加入如下配置

    <listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener>

    日志实体类

    package com.unionpay.techjoin.common.domain; import java.io.Serializable; import java.sql.Timestamp; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; /** * 审计日志实体类 * @author mszhou * */ @Entity @Table(name = "tbl_tjmgm_audit_log") public class AuditLog implements Serializable { /** * */ private static final long serialVersionUID = 1L; /**主键id*/ @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; /**类别 01表示产品 02表示解决方案 03表示API 04表示FAQ 05表示文档*/ @Column(name = "target_type") private String targetType; /**关联id */ @Column(name = "target_id") private Integer targetId; /**该操作简单的简单描述 如 “admin修改产品” */ @Column(name = "operate_content") private String operateContent; /**操作类别 01表示新增 02表示修改 03表示删除*/ @Column(name = "operate_type") private String operateType; /**操作人Id*/ @Column(name = "operator_id") private String operatorId; /** 操作时间 */ @Column(name = "operate_ts") private Timestamp operateTs; /**操作人的IP*/ @Column(name = "operator_ip") private String operatorIp; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getTargetType() { return targetType; } public void setTargetType(String targetType) { this.targetType = targetType; } public Integer getTargetId() { return targetId; } public void setTargetId(Integer targetId) { this.targetId = targetId; } public String getOperateContent() { return operateContent; } public void setOperateContent(String operateContent) { this.operateContent = operateContent; } public String getOperateType() { return operateType; } public void setOperateType(String operateType) { this.operateType = operateType; } public String getOperatorId() { return operatorId; } public void setOperatorId(String operatorId) { this.operatorId = operatorId; } public Timestamp getOperateTs() { return operateTs; } public void setOperateTs(Timestamp operateTs) { this.operateTs = operateTs; } public String getOperatorIp() { return operatorIp; } public void setOperatorIp(String operatorIp) { this.operatorIp = operatorIp; } }

    日志Dao类

    package com.unionpay.techjoin.common.dao; import java.io.Serializable; import org.springframework.stereotype.Repository; import com.unionpay.techjoin.common.domain.AuditLog; /** * 审计日志Dao * @author mszhou */ @Repository public class AuditLogDao extends HibernateBaseDao<AuditLog,Serializable> { }

    日志业务类

    package com.unionpay.techjoin.common.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.unionpay.techjoin.common.dao.AuditLogDao; import com.unionpay.techjoin.common.domain.AuditLog; @Service @Transactional public class AuditLogService { @Autowired private AuditLogDao auditLogDao; /** * 新增 * @param auditLog * @author mszhou */ public void add(AuditLog auditLog){ auditLogDao.save(auditLog); } }

    切面类

    package com.unionpay.techjoin.admin.controller; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.sql.Timestamp; import java.util.Date; import javax.servlet.http.HttpServletRequest; import org.aspectj.lang.ProceedingJoinPoint; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import com.unionpay.common.authorization.user.UserDetail; import com.unionpay.techjoin.admin.utils.UserInfoUtil; import com.unionpay.techjoin.common.domain.AuditLog; import com.unionpay.techjoin.common.service.AuditLogService; @Component(value="auditLogAop")//实例化注解 public class AuditLogAop { @Autowired private AuditLogService auditLogService; /* *(环绕通知) -日志切点 * 参数 JoinPoint joinPoint * ProceedingJoinPoint是JoinPoint的子类,在环绕通知中用到 * 其它通知则直接用JoinPoint类型参数 * * 环绕通知也可以这样写 * ((ProceedingJoinPoint) joinPoint).proceed(); */ @SuppressWarnings("finally") public Object addAuditLog(ProceedingJoinPoint pjp) throws Throwable{ Object obj=pjp.proceed();//执行方法 //========生成日志开姿============ try{ //得到Request对象 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); if(request!=null){ //pjp.getTarget().getClass().getName()得到请求的Service类全名(包名.类名) //调用方法getTargetType得到类型01表示产品 02表示解决方案 03表示API 04表示FAQ 05表示文档 String targetType =getTargetType(pjp.getTarget().getClass().getName()); //pjp.getSignature().getName()得到请求的方法名 //调用getOperateType方法得到操作类型 01表示新增 02表示修改 03表示删除 String operateType=getOperateType(pjp.getSignature().getName());//方法 if(targetType!=null&&!"".equals(targetType)&&operateType!=null&&!"".equals(operateType)){ //获取当前用户,这里调用了UserInfoUtil工具类 UserDetail user= UserInfoUtil.getUserInfo(request); AuditLog auditLog=new AuditLog();//创建审计日志对象 auditLog.setTargetType(targetType);//设置请求类别 //设置关联Id,这里调用了下面getpArgs方法得到id auditLog.setTargetId(getpArgs(pjp,operateType)); //设置简单操作描述,这里调用了下面getOperateContent方法获得 auditLog.setOperateContent(getOperateContent(user.getUserId(),targetType,operateType)); auditLog.setOperateType(operateType);//设置操作类别 auditLog.setOperatorId(user.getUserId());//设置操作人id auditLog.setOperateTs(new Timestamp(new Date().getTime()));//设置操作时间 //获取请求ip String ip = request.getRemoteAddr(); auditLog.setOperatorIp(ip);//设置操作人ip auditLogService.add(auditLog);//保存审计日志 } } }catch(Exception e){ e.printStackTrace(); }finally{ return obj; } //=======生成日志结束========== } /** * 转换请求类型 01表示产品 02表示解决方案 03表示API 04表示FAQ 05表示文档 * @param className * @return */ private String getTargetType(String className){ String returnType=null; if(className!=null){ String name=className.substring(className.lastIndexOf(".")+1); if(name!=null){ if("ProductService".equals(name)){//01 产品 returnType="01"; }else if("SolutionService".equals(name)){//02 解决方案 returnType="02"; }else if("APIInfoService".equals(name)){//03 API returnType="03"; }else if("FaqService".equals(name)){//04 FAQ returnType="04"; }else if("FileInfoService".equals(name)){//05 文档 returnType="05"; } } } return returnType; } /** * 转换操作类别 01表示新增 02表示修改 03表示删除 * @param methodName * @return */ private String getOperateType(String methodName){ String returnType=null; if(methodName!=null){ if(methodName.startsWith("add")||methodName.startsWith("save")){//01 新增 returnType="01"; }else if(methodName.startsWith("upd")||methodName.startsWith("modify")){//02 修改 returnType="02"; }else if(methodName.startsWith("del")){//03 删除 returnType="03"; } } return returnType; } /** * 获取所有请求参敿 * @param pjp * @return * @throws InvocationTargetException * @throws IllegalAccessException * @throws IllegalArgumentException */ private Integer getpArgs(ProceedingJoinPoint pjp,String operateType) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException{ Integer id=0; Object[] objs=pjp.getArgs();//得到所有参数 if(objs==null||objs.length<=0){ return id; } //判断如果是删除,则直接取参数中的第一个参数表示id, //否则通过反射判断对象中是否有getId方法, //如果有则通过反射调用该方法得到对应的id //例如 是新增产品,则得到的是产品id if("03".equals(operateType)){//是删除 Object obj = objs[0];//获取第一个参数 if(obj!=null){//判断不为空 String strNum=obj.toString();//转String if(strNum!=null&&!"".equals(strNum)){ //将id转换成Integer类型 id=new Integer(strNum); } } }else{//不是删除,是增加或修改 for (Object info : objs) {//遍历参数对象 //获取该参数对象的所有方法 Method[] methods = info.getClass().getDeclaredMethods(); //遍历所有方法 for (Method method : methods){ //得到方法名称 String methodName = method.getName(); //判断是否为getId方法 if (methodName!=null&&methodName.endsWith("getId")) { //调用该方法 Object obj = method.invoke(info); //返回值不能空 if(obj!=null){ //转String String strNum=obj.toString(); if(strNum!=null&&!"".equals(strNum)){ //将id转换成Integer类型 id=new Integer(strNum); } } } } } } return id;//返回id } /** * 转换简单的操作描述 * @param targetType * @param operateType * @return */ private String getOperateContent(String userName,String targetType,String operateType){ String result=userName; if("01".equals(operateType)){//01 新增 result+="新增"; }else if("02".equals(operateType)){//02 修改 result+="修改"; }else if("03".equals(operateType)){//03 删除 result+="删除"; } if("01".equals(targetType)){ result+="产品"; }else if("02".equals(targetType)){//02 result+="解决方案"; }else if("03".equals(targetType)){//03 result+="API"; }else if("04".equals(targetType)){//04 result+="FAQ"; }else if("05".equals(targetType)){//05 result+="文档"; } return result; } }

    注解方式配置切面类

    package com.unionpay.techjoin.admin.controller; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.sql.Timestamp; import java.util.Date; import javax.servlet.http.HttpServletRequest; import org.aspectj.lang.ProceedingJoinPoint; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import com.unionpay.common.authorization.user.UserDetail; import com.unionpay.techjoin.admin.utils.UserInfoUtil; import com.unionpay.techjoin.common.domain.AuditLog; import com.unionpay.techjoin.common.service.AuditLogService; import org.aspectj.lang.annotation.Aspect @Component(value="auditLogAop")//实例化注解 @Aspect//声明这是一个切面Bean public class AuditLogAop { @Autowired private AuditLogService auditLogService; //配置切入点,该方法无方法体,主要为方便同类中其他方法使用此处配置的切入点 //aspect 该方法名自己取的 @Pointcut("execution(* com.unionpay.techjoin.common.service..*.*(..))") public void aspect(){ } /* * (环绕通知) -日志切点 * 参数 JoinPoint joinPoint * ProceedingJoinPoint是JoinPoint的子类,在环绕通知中用到 * 其它通知则直接用JoinPoint类型参数 * * 环绕通知也可以这样写 * ((ProceedingJoinPoint) joinPoint).proceed(); */ @SuppressWarnings("finally") @Around("aspect()")//配置环绕通知,使用在方法aspect()上注册的切入点 public Object addAuditLog(ProceedingJoinPoint pjp) throws Throwable{ Object obj=pjp.proceed();//执行方法 //========生成日志开姿============ try{ //得到Request对象 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); if(request!=null){ //pjp.getTarget().getClass().getName()得到请求的Service类全名(包名.类名) //调用方法getTargetType得到类型01表示产品 02表示解决方案 03表示API 04表示FAQ 05表示文档 String targetType =getTargetType(pjp.getTarget().getClass().getName()); //pjp.getSignature().getName()得到请求的方法名 //调用getOperateType方法得到操作类型 01表示新增 02表示修改 03表示删除 String operateType=getOperateType(pjp.getSignature().getName());//方法 if(targetType!=null&&!"".equals(targetType)&&operateType!=null&&!"".equals(operateType)){ //获取当前用户,这里调用了UserInfoUtil工具类 UserDetail user= UserInfoUtil.getUserInfo(request); AuditLog auditLog=new AuditLog();//创建审计日志对象 auditLog.setTargetType(targetType);//设置请求类别 //设置关联Id,这里调用了下面getpArgs方法得到id auditLog.setTargetId(getpArgs(pjp,operateType)); //设置简单操作描述,这里调用了下面getOperateContent方法获得 auditLog.setOperateContent(getOperateContent(user.getUserId(),targetType,operateType)); auditLog.setOperateType(operateType);//设置操作类别 auditLog.setOperatorId(user.getUserId());//设置操作人id auditLog.setOperateTs(new Timestamp(new Date().getTime()));//设置操作时间 //获取请求ip String ip = request.getRemoteAddr(); auditLog.setOperatorIp(ip);//设置操作人ip auditLogService.add(auditLog);//保存审计日志 } } }catch(Exception e){ e.printStackTrace(); }finally{ return obj; } //=======生成日志结束========== } /** * 转换请求类型 01表示产品 02表示解决方案 03表示API 04表示FAQ 05表示文档 * @param className * @return */ private String getTargetType(String className){ String returnType=null; if(className!=null){ String name=className.substring(className.lastIndexOf(".")+1); if(name!=null){ if("ProductService".equals(name)){//01 产品 returnType="01"; }else if("SolutionService".equals(name)){//02 解决方案 returnType="02"; }else if("APIInfoService".equals(name)){//03 API returnType="03"; }else if("FaqService".equals(name)){//04 FAQ returnType="04"; }else if("FileInfoService".equals(name)){//05 文档 returnType="05"; } } } return returnType; } /** * 转换操作类别 01表示新增 02表示修改 03表示删除 * @param methodName * @return */ private String getOperateType(String methodName){ String returnType=null; if(methodName!=null){ if(methodName.startsWith("add")||methodName.startsWith("save")){//01 新增 returnType="01"; }else if(methodName.startsWith("upd")||methodName.startsWith("modify")){//02 修改 returnType="02"; }else if(methodName.startsWith("del")){//03 删除 returnType="03"; } } return returnType; } /** * 获取所有请求参敿 * @param pjp * @return * @throws InvocationTargetException * @throws IllegalAccessException * @throws IllegalArgumentException */ private Integer getpArgs(ProceedingJoinPoint pjp,String operateType) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException{ Integer id=0; Object[] objs=pjp.getArgs();//得到所有参数 if(objs==null||objs.length<=0){ return id; } //判断如果是删除,则直接取参数中的第一个参数表示id, //否则通过反射判断对象中是否有getId方法, //如果有则通过反射调用该方法得到对应的id //例如 是新增产品,则得到的是产品id if("03".equals(operateType)){//是删除 Object obj = objs[0];//获取第一个参数 if(obj!=null){//判断不为空 String strNum=obj.toString();//转String if(strNum!=null&&!"".equals(strNum)){ //将id转换成Integer类型 id=new Integer(strNum); } } }else{//不是删除,是增加或修改 for (Object info : objs) {//遍历参数对象 //获取该参数对象的所有方法 Method[] methods = info.getClass().getDeclaredMethods(); //遍历所有方法 for (Method method : methods){ //得到方法名称 String methodName = method.getName(); //判断是否为getId方法 if (methodName!=null&&methodName.endsWith("getId")) { //调用该方法 Object obj = method.invoke(info); //返回值不能空 if(obj!=null){ //转String String strNum=obj.toString(); if(strNum!=null&&!"".equals(strNum)){ //将id转换成Integer类型 id=new Integer(strNum); } } } } } } return id;//返回id } /** * 转换简单的操作描述 * @param targetType * @param operateType * @return */ private String getOperateContent(String userName,String targetType,String operateType){ String result=userName; if("01".equals(operateType)){//01 新增 result+="新增"; }else if("02".equals(operateType)){//02 修改 result+="修改"; }else if("03".equals(operateType)){//03 删除 result+="删除"; } if("01".equals(targetType)){ result+="产品"; }else if("02".equals(targetType)){//02 result+="解决方案"; }else if("03".equals(targetType)){//03 result+="API"; }else if("04".equals(targetType)){//04 result+="FAQ"; }else if("05".equals(targetType)){//05 result+="文档"; } return result; } } 相关资源:AOP日志处理
    最新回复(0)