一.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";
}
}