1. 程式人生 > >利用Java Annotation 和 Spring AOP實現在Controller層面的操作日誌記錄

利用Java Annotation 和 Spring AOP實現在Controller層面的操作日誌記錄

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 {

。。。

}