-
目标
使用自定义注解标记controller,前端传参调用该controller时,使用切面捕获方法,对传递来的参数添加createTime和createPerson(person从Session中获取),免去在每一个服务类中都要set这两个值
-
自定义注解
1. 注解基础
1.1 注解的形式
public @interface Insert{}
1.2 元注解
可以给注解添加的注解称为“元注解”
1.2.1 @Retention: 定义注解的保留策略
属性字段 保留策略 @Retention(RetentionPolicy.SOURCE) 注解仅存在于源码中,在class字节码文件中不包含 @Retention(RetentionPolicy.CLASS) 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得 @Retention(RetentionPolicy.RUNTIME) 注解会在class字节码文件中存在,在运行时可以通过反射获取到 【注】生命周期 SOURCE < CLASS < RUNTIME ,即后者作用域包含前者
1.2.2 @Target:定义注解的作用目标
属性字段 作用目标 @Target(ElementType.TYPE) 接口、类、枚举、注解 @Target(ElementType.FIELD) 字段、枚举的常量 @Target(ElementType.METHOD) 方法 @Target(ElementType.PARAMETER) 方法参数 @Target(ElementType.CONSTRUCTOR) 构造函数 @Target(ElementType.LOCAL_VARIABLE) 局部变量 @Target(ElementType.ANNOTATION_TYPE) 注解 @Target(ElementType.PACKAGE) 包 1.2.3 @Document:说明该注解将被包含在javadoc中
1.2.4 @Inherited:说明子类可以继承父类中的该注解
2. 自定义注解
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Insert { }
自定义一个Insert注解,用于添加在controller方法上,生命周期为RUNTIME,用于识别是数据插入操作
-
AOP切面
1. AOP基础
1.1 注解基础
1.1.1 通知
属性字段 作用域 @Before 在方法调用之前调用通知 @After 在方法完成之后调用通知,无论方法执行成功与否 @AfterReturning 在方法执行成功之后调用通知 @AfterThrowing 在方法抛出异常后进行通知 @Around 通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为 1.1.2 连接点
- 连接点是一个应用执行过程中能够插入一个切面的点。
- 连接点可以是调用方法时、抛出异常时、甚至修改字段时
1.1.3 切点
- 切点定义了AOP执行的位置
- 切点是连接点的集合,通常使用正则表达式匹配多个连接点
- 在SpringAOP中定义切点(使用AspectJ的切点表达式)
指示器 作用域 arg () 限制连接点的指定参数为指定类型的执行方法 @args () 限制连接点匹配参数由指定注解标注的执行方法 execution () 用于匹配连接点的执行方法 this () 限制连接点匹配 AOP 代理的 Bean 引用为指定类型的类 target () 限制连接点匹配特定的执行对象,这些对象对应的类要具备指定类型注解 within() 限制连接点匹配指定类型 @within() 限制连接点匹配指定注释所标注的类型 @annotation 限制匹配带有指定注释的连接点 1.1.4 切面
- 切面是通知和切点的集合,定义了AOP执行什么和在哪执行
1.1.5 引入
- 引入允许我们向现有的类中添加方法或属性
1.1.6 织入
2. 自定义 AOP
@Component
@Aspect
public class SQLOperateAspect {
//设置切点为@Insert标注的方法
@Before(value="@annotation(com.fzu.oqn.Insert)")
public void dofore(JoinPoint jp) {
try {
//获取方法入参对象
Object[] objects = jp.getArgs();
//获取入参对象的setCreateTime方法
Method setCreateTime = objects[0].getClass().getMethod("setCreateTime", java.util.Date.class);
//获取入参对象的setCreatePerson方法
Method setCreatePerson = objects[0].getClass().getMethod("setCreatePerson", java.lang.String.class);
//获取session对象的getAttribute方法
Method session_getAttribute = objects[1].getClass().getMethod("getAttribute", java.lang.String.class);
//通过反射获得Session对象中的信息
User user = (User)session_getAttribute.invoke(objects[1], "loginUser");
//通过反射操作函数赋值
setCreateTime.invoke(objects[0], new Date());
setCreatePerson.invoke(objects[0], user.getUserName());
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
2.1 JoinPoint 对象
方法名 | 功能 |
---|---|
Signature getSignature(); | 获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息 |
Object[] getArgs(); | 获取传入目标方法的参数对象 |
Object getTarget(); | 获取被代理的对象 |
Object getThis(); | 获取代理对象 |
@RequestMapping(value="/publishPaper",method= RequestMethod.POST)
@Insert
public ResponseMessage publishPaper(@RequestBody QuestionnairePublishVO questionnairePublishVO,HttpSession session) {
User user = (User)session.getAttribute("loginUser");
return myPapersService.publishPaper(questionnairePublishVO);
}
在Controller上添加@Insert注解,调用该方法时AOP会进行拦截,获取第二个参数Session中的登陆者信息,赋值给第一个参数questionnairePublishVO中的createTime和createPerson属性