SpringAop实现切面

首先自定义注解@Login,后面在需要用到切面的方法上加上这个注解即可使用其功能。

package com.example.config;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Login {
}

java用  @interface Annotation{ } 定义一个注解 @Annotation,一个注解是一个类

@Override,@Deprecated,@SuppressWarnings为常见的3个注解。
注解相当于一种标记,在程序中加上了注解就等于为程序加上了某种标记,以后,
JAVAC编译器,开发工具和其他程序可以用反射来了解你的类以及各种元素上有无任何标记,看你有什么标记,就去干相应的事

注解@Retention可以用来修饰注解,是注解的注解,称为元注解

Retention注解有一个属性value,是RetentionPolicy类型的,Enum RetentionPolicy是一个枚举类型,
这个枚举决定了Retention注解应该如何去保持,也可理解为Rentention 搭配 RententionPolicy使用。RetentionPolicy有3个值:CLASS  RUNTIME   SOURCE
用@Retention(RetentionPolicy.CLASS)修饰的注解,表示注解的信息被保留在class文件(字节码文件)中当程序编译时,但不会被虚拟机读取在运行的时候;
用@Retention(RetentionPolicy.SOURCE )修饰的注解,表示注解的信息会被编译器抛弃,不会留在class文件中,注解的信息只会留在源文件中;
用@Retention(RetentionPolicy.RUNTIME )修饰的注解,表示注解的信息被保留在class文件(字节码文件)中当程序编译时,会被虚拟机保留在运行时,
所以他们可以用反射的方式读取。RetentionPolicy.RUNTIME 可以让你从JVM中读取Annotation注解的信息,以便在分析程序的时候使用.

注解@Target也是用来修饰注解的元注解,它有一个属性ElementType也是枚举类型

如@Target(ElementType.METHOD) 修饰的注解表示该注解只能用来修饰在方法上

下面定义AOP拦截类,所有@Pointcut("execution(* com.example.controller.*.*(..))") 被 包含在里面的类都会被拦截,下面的表达式表示在com.example.controller下的所有包及子包中的类的方法都会被此类拦截。所有包含@Login注解的方法将会执行操作。

package com.example.config;

import com.example.dao.User;
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.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * @author
 * 使用AOP实现登陆鉴权
 */
@Aspect
@Component
public class AuthHandler {
    private static final String NEED_LOGIN = "请先登录";
    private static final String NEED_ADMIN = "只有管理员有权操作";

    @Pointcut("execution(* com.example.controller.*.*(..))")
    public void start() {

    }

    @Around("start()")
    public Object access(ProceedingJoinPoint joinPoint) {
        User user = getUser();
        MethodSignature joinPointObject = (MethodSignature) joinPoint.getSignature();
        //获得请求的方法
        Method method = joinPointObject.getMethod();
        //判断是否需要登陆(含有login注解)
        if (hasAnnotationOnMethod(method, Login.class)) {
            if(user == null){
                //用户未登陆
                return "请登陆";
            }
        }
        Object obj = null;
        try {
            obj = joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return obj;
    }

    /**
     * 从session中获取当前用户
     *
     * @return
     */
    private User getUser() {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        HttpSession session = request.getSession();
        User user = (User) session.getAttribute("user");
        return user;
    }

    /**
     * 判断某个方法上是否含有某注解
     * @param method
     * @param annotationClazz
     * @return
     */
    private boolean hasAnnotationOnMethod(Method method, Class annotationClazz) {
        //使用反射获取注解信息
        Annotation a = method.getAnnotation(annotationClazz);
        if (a == null) {
            return false;
        }
        return true;
    }

}

以下index类的index方法将不能成功返回“login"而是会返回"请登陆"

@Controller
public class index {

    @Login
    @RequestMapping(value="/index")
    @ResponseBody
    public String index(){
        return "login";
    }
}

猜你喜欢

转载自blog.csdn.net/qq_39727896/article/details/85016580