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;
}
}