一.XML配置
SpringMVC如果要使用AOP注解,必須將放在spring-servlet.xml(配置MVC的XML)中
<!-- 啟用CGliB -->
<aop:aspectj-autoproxy proxy-target-class="true" />
二.自定義注解
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemLogAnnotation {
public String controller() default "";
public String method() default "";
}
1. @Documented – 表示使用該注解的元素應被javadoc或類似工具文檔化,它應用於類型聲明,類型聲明的注解會影響客戶端對注解元素的使用。如果一個類型聲明添加了Documented注解,那么它的注解會成為被注解元素的公共API的一部分。
2. @Target – 表示支持注解的程序元素的種類,一些可能的值有TYPE, METHOD, CONSTRUCTOR, FIELD等等。如果Target元注解不存在,那么該注解就可以使用在任何程序元素之上。
3. @Inherited – 表示一個注解類型會被自動繼承,如果用戶在類聲明的時候查詢注解類型,同時類聲明中也沒有這個類型的注解,那么注解類型會自動查詢該類的父類,這個過程將會不停地重復,直到該類型的注解被找到為止,或是到達類結構的頂層(Object)。
4. @Retention – 表示注解類型保留時間的長短,它接收RetentionPolicy參數,可能的值有SOURCE(源文件中起作用), CLASS, 以及RUNTIME(保留到運行時起作用)。
三.建切面類
@Before – 目標方法執行前執行
@After – 目標方法執行后執行
@AfterReturning – 目標方法返回后執行,如果發生異常不執行
@AfterThrowing – 異常時執行
@Around – 在執行上面其他操作的同時也執行這個方法
這里記錄日志,選用@AfterReturning(pointcut切入點,指定目錄下所有方法)
@AfterReturning(pointcut="execution(* com.web.webapp.controller.*.*.*(..))")
public void afterManage(JoinPoint point) {
SystemLogAnnotation systemlogAnnotation = null;
try{
systemlogAnnotation = this.getLogAnnotation(point);
if (systemlogAnnotation == null) {
return;
}
//請求參數
Map<String, Object> map = getRequestParameterJson(request);
String argsJson = JSON.toJSONString(map);
//記錄日志(controller,method,description,url,args等等)
OperationLog OperationLog = new OperationLog();
OperationLog.setController(systemlogAnnotation.controller());
OperationLog.setMethod(systemlogAnnotation.method());
OperationLog.setRequestParameters(argsJson);
//保存
save(OperationLog)
}catch(Exception e){
logger.error("日志異常" , e);
}
}
/**
*是否存在注解,如果存在就獲取
*/
private SystemLogAnnotation getLogAnnotation(JoinPoint joinPoint) throws Exception {
SystemLogAnnotation obj = null;
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] method = targetClass.getMethods();
for (Method m : method) {
if (m.getName().equals(methodName)) {
Class[] tmpCs = m.getParameterTypes();
if (tmpCs.length == arguments.length) {
obj = m.getAnnotation(SystemLogAnnotation.class);
break;
}
}
}
return obj;
}
/**
*對值過於長的參數進行過濾(視情況而定)
*/
private Map<String, Object> getRequestParameterJson(HttpServletRequest request) {
Map<String, Object> map = new ConcurrentHashMap<String, Object>();
map.putAll(request.getParameterMap());
Iterator<String> keyIt = map.keySet().iterator();
while (keyIt.hasNext()) {
String key = keyIt.next();
String[] value = (String[]) map.get(key);
if (value != null) {
String valueStr = Arrays.toString(value);
if (valueStr.length() > 500) {
keyIt.remove();
map.remove(key);
}
}
}
return map;
}
四.測試類
@Controller
public class Controller {
private static final Logger log = LoggerFactory.getLogger(Controller.class);
@RequestMapping("/hello")
//自定義注解,當方法上寫這個注解時,就會進入切面類中
@SystemLogAnnotation(controller="testController",method="testMethod")
public String sayHello() {
log.info("HelloController sayHello:{}","hello world!");
return "hello";
}
}