配置applicationContext.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://mybatis.org/schema/mybatis-spring
http://mybatis.org/schema/mybatis-spring.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
spring的配置省略.......
<!-- 日志切面 这里的路径是处理日志的方法路径 -->
<context:component-scan base-package="com.test.log.LogAspect"></context:component-scan>
<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"></aop:aspectj-autoproxy>
写一个注解类
凡是需要记录日志的就在方法上加入这个注解
@Target({ElementType.PARAMETER,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface LogAnnotation {
/** 日志描述 */
String description() default "";
/** 操作模块*/
String czmk();
/** 操作类型*/
String czlx();
/**
* 用于区分一个方法使用不同的表的情况
* 2 是操作日志 1 是登录日志
* */
int type() default 2;
}
接口中注解使用
@Api(tags="用户登陆")
@Controller
@RequestMapping("/login")
public class LoginController {
@ApiOperation(value = "用户登陆",httpMethod="POST",notes = "")
@RequestMapping(value="init", method=RequestMethod.POST)
@ResponseBody
@LogAnnotation(description = "登录系统验证用户名密码",czlx = "登录",czmk = "系统登录",type = 1)
public Object initLogin(@RequestBody XtUser xTuser, String remeber) {
j.setCode(200);
j.setMsg("用户验证成功!");
j.setSuccess(true);
return j;
}
}
写一个日志处理的类
下面有两种方法处理
第一种
@Aspect
@Component
public class LogAspect {
@Autowired
private UserService userService ;
/**
* 定义一个切点
*/
@Pointcut("@annotation(com.test.web.log.LogAnnotation)")
private void accAspect() {
}
/**
* 切面处理
* @param joinPoint
* @param result
* @throws Throwable
*/
@AfterReturning(pointcut = "accAspect()", returning = "result")
public void around(JoinPoint joinPoint, Object result) throws Throwable {
}
第二种
@Aspect
@Component
public class LogAspect {
` /**
* @Around 环绕通知:
* 环绕通知非常强大,可以决定目标方法是否执行,什么时候执行,执行时是否需要替换方法参数,执行完毕是否需要替换返回值。
* 环绕通知第一个参数必须是org.aspectj.lang.ProceedingJoinPoint类型
*/
/**
* 项目日志新增操作日志记录
*
* @param point
* @throws Throwable
*/
@Around("execution(com.test.service.ProjectService.addProject(..))")
public Object processAddProjectConfig(ProceedingJoinPoint point) throws Throwable {
}
/**
* 项目日志修改操作日志记录
*
* @param point
* @throws Throwable
*/
@Around("execution(com.test.service.ProjectService.updateProject(..))")
public Object processUpdateProjectConfig(ProceedingJoinPoint point) throws Throwable {
注意
两者的区别是:
- 将切面提取出来了 可以共用一个切面控制
- 单独控制切面, 不同的接口使用不同的方法控制日志
也可以写多个注解类,在不同的类上使用
@AfterReturning标签属性分析:
value值: 可以写Aop的表达式,如execution、args、within等,多个之间使用&& || !作为连接; 也可以使用引用其他Pointcut;
pointcut值:和value值用法一样
returning值:给被增强方法返回值取个名字,给后面引用;(使用了日志控制的类的返回值)
argNames值:方法入参的名字,Spring4.2.x测试时候发现写不写都可以实现Aop,具体看下面测试.
如果只需要记录方法返回值的话,只需要配置returning属性,方法入参配置上对应返回值类型或其父类即可,写Object应该肯定没问题吧;
知识点1.returning属性的值和增强方法的入参是按照名称来匹配;
当增强方法入参名称和returning不一致时,就会抛出异常Returning argument name ‘val’ was not bound in advice arguments
知识点2. 增强方法入参不能出现多余(JoinPoint不算多余),否则会匹配不上; 如果想要获取被增强方法入参,方式有两种,下面有介绍.
1). 增强方法入参类型必须是 被增强方法返回值类型或者父类,否则增强方法无法执行; void类型的方法返回值是null,可以使用Object类型来接收
2)查看源码可以得到解释, AspectJAfterReturningAdvice的afterReturning会先判断类型是否匹配来决定执行不执行后置增强;