概述:
在开发中我们需要将用户的访问记录当作日志写入数据库中,如果给每个Controller层方法都加上相同的记录日志的代码,这样无疑会造成代码的冗余,也不利于程序的扩展,所以我们可以通过aop编程,利用横切技术,动态给每个方法添加记录日志功能;
步骤:
1)、开启aop注解支持;
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
2)、编写切面类;
在切面类上添加@Component(将切面类添加到IOC容器)、@Aspect(声明该类为切面类)
3)、编写环绕通知;
在环绕通知的方法上加入@Around注解;
代码展示:
@Around("execution(* com.itheima.controller.*.*(..))")
public Object around(ProceedingJoinPoint pjp){
Object obj = null;
try {
//得到访问时间
Date visitTime = new Date();
//获取到目标对象的字节码对象
Class clazz = pjp.getTarget().getClass();
//得到当前目标对象中方法的参数
Object[] args = pjp.getArgs();
//放行方法
obj = pjp.proceed(args);
if(!pjp.getSignature().getName().equals("ininBinder")){
//得到一个日志对象
SysLog log = new SysLog();
//通过目标字节码对象获取该对象的类名以及被代理方法的方法名;
log.setMethod("类名为:"+clazz.getName()+"方法名为:"+pjp.getSignature().getName());//"类名为:"+XXX+"方法名为:"+XXX
log.setExecutionTime(new Date().getTime()-visitTime.getTime());
log.setIp(request.getRemoteAddr());//通过request域对象获取IP;
log.setUrl(request.getRequestURI());//通过request域对象获取URI
log.setUsername(request.getRemoteUser());//通过request域对象获取登录的用户名
log.setVisitTime(visitTime);
//日志入库
logService.save(log);
}
}catch (Throwable t){
//还原异常(使用AOP编程时一定要注意还原异常,否则权限不足时会出现404)
if(t.getMessage().equals("Access is denied")){
throw new AccessDeniedException("权限不足!");
}else {
try {
throw new Exception("权限不足!");
} catch (Exception e) {
e.printStackTrace();
}
}
t.printStackTrace();
}
return obj;//返回被代理方法的返回值;
}
4)、在配置文件中添加扫描切面类所在的包;
<context:component-scan base-package="切面类所在的包名"/>
说明:
在步骤三中需要用到request域对象,所以在切面类中注入request域对象,注入request域对象前提是IOC容器中拥有request域对象,我们可以通过在web.xml文件中添加一个监听器,用来监听request域对象的创建,request域对象创建完成后自动放入IOC容器;
代码实现:
<listener>
<!--监听request对象的创建,request创建完成后将其放入ioc容器-->
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
关注点:
1)、代码冗余时使用AOP编程;(例:事务、日志......)
2)、在封装日志对象时,有几个参数需要通过request域对象获取比较方便;(例:ip、url、username)
获取ip:request.getRemoteAddr();
获取url:request.getRequestURL();
获取username:request.getRemoteUser();
说明:如果不使用request域对象获取,也可以使用反射方法式(比较麻烦);
3)、获取请求所访问的类名+方法名:
如果我们想要在通知中获取目标对象的类名以及当前被增强方法的方法名,我们通过反射即可实现;
1)、通过ProceedingJoinPoint对象即可获取目标对象的字节码;
代码:ProceedingJoinPoint.getTarget().getClass();
2)、通过ProceedingJoinPoint对象也可获取当前被增强方法的方法名;
代码:ProceedingJoinPoint.getSignature().getName();
4)、由于我们需要用到request域对象所以我们需要监听request域对象的创建;
<listener>
<!--监听request对象的创建,request创建完成后将其放入ioc容器-->
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
网友评论