项目应用:使用自定义注解完成对controller的aop控制

在项目进行过程中,需要使用aop对api传入或者传出数据进行日志记录。考虑实际应用,放弃了使用拦截器,转而使用aop的前置通知和返回通知中加入日志记录操作。

在spring中,controller会被JDK自动代理。当使用自定义标签时controller已经实例化不会在通过aop,因此需要走cglib代理。

xml配置:

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:task="http://www.springframework.org/schema/task"
<span style="color:#FF6666;">    <!-- 启动对@AspectJ注解的支持 -->  
    <aop:aspectj-autoproxy/>  
    
    <!--通知spring使用cglib而不是jdk的来生成代理方法 AOP可以拦截到Controller--> 
    <aop:aspectj-autoproxy proxy-target-class="true" />  </span><span style="color:#FF6666;">       xmlns:aop="http://www.springframework.org/schema/aop"</span>
       xsi:schemaLocation="http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/task
        http://www.springframework.org/schema/task/spring-task.xsd
<span style="color:#FF6666;">        http://www.springframework.org/schema/aop   
        http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

    <!-- 启动对@AspectJ注解的支持 -->  
    <aop:aspectj-autoproxy/>  
    
    <!--通知spring使用cglib而不是jdk的来生成代理方法 AOP可以拦截到Controller-->  
    <aop:aspectj-autoproxy proxy-target-class="true" />  

</span>

自定义标签:

package com.xiaoma.universe.video.aspect;

import java.lang.annotation.*;

@Target({ElementType.PARAMETER, ElementType.METHOD})  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
public @interface ControllerLog {
    
    String description() default "";//自定义标签属性

}

实现aspect:

package com.xiaoma.universe.video.aspect;  

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

@Aspect  
@Component  
public  class LogAspect {  

	//本地异常日志记录对象  
	private  static  final Logger logger = LoggerFactory.getLogger(LogAspect.class);  
	
	//Controller层切点  
	@Pointcut("@annotation(com.xiaoma.universe.video.aspect.ControllerLog)")
	public  void controllerAspect() {  
	}  

	/** 
	 * 前置通知 用于拦截Controller层记录用户的操作 
	 * 
	 * @param joinPoint 切点 
	 */  
	@Before("controllerAspect()")  
	public  void doBefore(JoinPoint joinPoint) {
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		System.out.println("请求"+request.getCharacterEncoding());
	}  


	/** 
	 * 获取注解中对方法的描述信息 用于Controller层注解 
	 * 
	 * @param joinPoint 切点 
	 * @return 方法描述 
	 * @throws Exception 
	 */  
	public  static String getControllerMethodDescription(JoinPoint joinPoint)  throws Exception {  
 		Class<?> clazz = joinPoint.getTarget().getClass();
		String name = joinPoint.getSignature().getName();
		Object[] parameterTypes = joinPoint.getArgs();
		for (Method method : clazz.getDeclaredMethods()) {
			if (method.getName().equals(name) && method.getParameterTypes().length == parameterTypes.length) {
				ControllerLog methodLog = method.getAnnotation(ControllerLog. class);
				if (methodLog != null) {
					return methodLog.description();
				}
				break;
			}
		}
		return "";		 
	}  
}  
在controller中使用:

	@RequestMapping( method=RequestMethod.GET)
	@ResponseBody
	@ControllerLog(description="123")
	public JSONObject list(HttpServletRequest request, HttpServletResponse response ,VideoCourses videoCourses, BaseModel model ,@TokenUser UserInfo user,String channel,String queryType)
	{
            return null;
        }


获取自定义注解修饰的Controller参数值,可以使用 AOP方法拦截请求,并在拦截方法获取参数值。具体步骤如下: 1. 定义一个自定义注解,例如 @MyAnnotation。 2. 在需要拦截的 Controller 方法参数上添加 @MyAnnotation 注解。 3. 编写一个切面类,在类上添加 @Aspect 注解,并定义一个切点方法使用 @Around 注解指定需要拦截的方法。 4. 在切点方法使用 JoinPoint 对象获取目标方法的参数,通过反射获取参数上的 @MyAnnotation 注解,从而获取注解的值。 示例代码如下: ```java @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) public @interface MyAnnotation { String value(); } @Controller public class UserController { @GetMapping("/users/{id}") public String getUser(@MyAnnotation("user_id") @PathVariable Long id) { // ... } } @Aspect @Component public class MyAspect { @Around("execution(* com.example.controller.*.*(..))") public Object around(ProceedingJoinPoint point) throws Throwable { Object[] args = point.getArgs(); for (Object arg : args) { MyAnnotation annotation = arg.getClass().getAnnotation(MyAnnotation.class); if (annotation != null) { String value = annotation.value(); // TODO: 处理注解值 } } return point.proceed(); } } ``` 在上面的示例,我们定义了一个 @MyAnnotation 注解用于修饰 Controller 方法的参数。在 UserController ,我们使用 @MyAnnotation 注解修饰了 getUser 方法的 id 参数,注解的值为 "user_id"。 然后,在 MyAspect 类,我们使用 @Around 注解指定需要拦截的方法,并通过 JoinPoint 对象获取目标方法的参数。我们遍历参数列表,使用反射获取参数上的 @MyAnnotation 注解,并从注解获取值,最终可以进行处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值