Annotation,Spring,AOP之类的概念这里就不在介绍了,网上的相关知识一搜在大堆,而且也是各大公司面试之必考内容。目前AOP技术的应用场景中应该很大一部分是用来实现操作日志记录的,由于每个公司几乎都有自己的开发框架,而且很多框架都对CRUD之类的操作进行了高度封装,Service层面几乎省去了90%的代码,这样利用AOP记录每个模块的CRUD操作变得有些麻烦,下面分享一种利用Annotation在Controller层面记录日志的方法:
1.首页创建一个Annotation类
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Traced {
String name() default "";// 默认为空
}
2.创建核心AOP操作类:ControllerTraceAspect
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
@Aspect
public class ControllerTraceAspect{
protected Logger logger = LoggerFactory.getLogger(getClass());
/**
*所有查询方法
*/
@Around("execution(* org.tshark.core.orm.hibernate.EntityManager.search(..)) ")
public Object searchAground(ProceedingJoinPoint pjp) throws Throwable {
if (TraceContextHolderFactory.getTraceContextHolder().getContext() == null) {
return pjp.proceed();
} else {
return doAround(null, getUserCode(), getRemoteHost(), pjp);
}
}
//只对Controller进行pointcut
@Pointcut("within(@org.springframework.stereotype.Controller *)")
public void controllerPointcut() {
}
/**
* 对有@Traced标记的方法,记录其执行参数及返回结果.
*/
@Pointcut("@annotation(org.tshark.framework.trace.Traced)")
public void tracedMethodPointcut() {
}
@Around("controllerPointcut() && tracedMethodPointcut()")
public Object traceAround(ProceedingJoinPoint pjp) throws Throwable {
return doAroundController(pjp);
}
private Object doAroundController(ProceedingJoinPoint pjp) throws Throwable {
String methodName = pjp.getSignature().getName();
Object[] args = pjp.getArgs();
Class[] argsClazz = new Class[args.length];
//Controller中所有方法的参数,前两个分别为:Request,Response
argsClazz[0] = HttpServletRequest.class;
argsClazz[1] = HttpServletResponse.class;
//第三个为保存中的上传的Model
if (args.length == 3) {
argsClazz[2] = args[2].getClass();
}
Traced tracedAnnotation = AnnotationUtils.findAnnotation(pjp.getTarget().getClass().getDeclaredMethod(methodName, argsClazz),
Traced.class);
String traceName = tracedAnnotation.name();
return doAround(traceName, getUserCode(), getRemoteHost(), pjp);
}
//获取当前登录用户
private String getUserCode() {
String userCode = "_system";
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal != null && principal instanceof UserDetails) {
userCode = ((UserDetails) principal).getUsername();
}
return userCode;
}
//获取当前用户IP
private String getRemoteHost() {
String host = null;
WebAuthenticationDetails authDetails = (WebAuthenticationDetails) SecurityContextHolder.getContext().getAuthentication()
.getDetails();
if (authDetails != null) {
host = authDetails.getRemoteAddress();
}
return host;
}
private String getOperateContext(Object[] args) {
StringBuffer strBuffer = new StringBuffer();
for (int i = 0; i < args.length; i++) {
if(i==2){//第三个参数为Model
strBuffer.append(ToStringBuilder.reflectionToString(args[i]));
}
}
return strBuffer.toString();
}
protected Object doAround(String traceName, String currUser, String host, ProceedingJoinPoint pjp) throws Throwable {
//日志记录
}
}
3.Spring 配置文件
web.xml中的配置
<servlet>
<servlet-name>TS-Dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:action-servlet.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>TS-Dispatcher</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
action-servlet.xml中的相关配置(以下配置必须放在 action-servlet.xml不能放在service的配置文件中)
<?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:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-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/jee http://www.springframework.org/schema/jee/spring-jee-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"
default-lazy-init="true">
<context:component-scan base-package="org.tshark.**.action" />
<aop:aspectj-autoproxy proxy-target-class="true" >
<aop:include name="controllerAspect" />
</aop:aspectj-autoproxy>
<bean id="controllerAspect" class="org.tshark.framework.trace.ControllerTraceAspect" />
4.使用方法,在需要记录的Controller上加上 @Traced(name="基础管理>用户管理:新增或修改用户")
例如:
@Traced(name="基础管理>用户管理:新增或修改用户")
@RequestMapping(value = "/save", method = RequestMethod.POST)
public void save(HttpServletRequest request, HttpServletResponse response, UserModel userModel) throws Exception {
。。。
}