注:文章皆为个人纪录,可用性请以最终结果为准,若有错还请大佬们指出,谢谢!
此文章可对自定义注解与拦截器进行综合学习,讲解简洁明了
步骤一:创建自定义注解 @TestDefinition
(自定义注解我个人一般用来做标记使用,为了体现它的“属性作用”,此处仅加一个属性“value”)
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义注解
*
* Target(ElementType.METHOD) 设置自定义注解的作用类型,有类、方法、参数等
* Retention(RetentionPolicy.RUNTIME) 设置自定义注解的生命周期,一般选择运行时
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestDefinition {
String value() default "默认值"; // 可以定义一些属性,并可以给这些属性设默认值
/**
* 自定义参数
*/
String index();
/**
* 自定义参数
*/
String type();
}
源码解析:
类型与生命周期的切换分别用ElementType,RetentionPolicy对象去调就行了,查看源码发现有如下类型与生命周期可供选择
/* * @author Joshua Bloch * @since 1.5 * @jls 9.6.4.1 @Target * @jls 4.1 The Kinds of Types and Values */ public enum ElementType { /** Class, interface (including annotation type), or enum declaration */ TYPE, // 类、接口、枚举 /** Field declaration (includes enum constants) */ FIELD, // 成员属性 /** Method declaration */ METHOD, // 方法 /** Formal parameter declaration */ PARAMETER, // 方法参数 /** Constructor declaration */ CONSTRUCTOR, // 构造器 /** Local variable declaration */ LOCAL_VARIABLE, // 局部变量 /** Annotation type declaration */ ANNOTATION_TYPE, // 注解 /** Package declaration */ PACKAGE, // 包 }
/* * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package java.lang.annotation; /** * Annotation retention policy. The constants of this enumerated type * describe the various policies for retaining annotations. They are used * in conjunction with the {@link Retention} meta-annotation type to specify * how long annotations are to be retained. * * @author Joshua Bloch * @since 1.5 */ public enum RetentionPolicy { /** * Annotations are to be discarded by the compiler. */ SOURCE, // 表示自定义注解的生命周期在源码阶段,编译后结束 /** * Annotations are to be recorded in the class file by the compiler * but need not be retained by the VM at run time. This is the default * behavior. */ CLASS, // 表示自定义注解的生命周期在编译阶段,运行后结束(默认这种) /** * Annotations are to be recorded in the class file by the compiler and * retained by the VM at run time, so they may be read reflectively. * * @see java.lang.reflect.AnnotatedElement */ RUNTIME // 表示自定义注解的生命周期在运行阶段(最常用) }
步骤二:创建两个方法待测试时使用
由于ElementType 的类型选择了METHOD,所以@TestDefinition只能作用于方法
其中testStudy2方法使用自定义注解 @TestDefinition
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
@RequestMapping("/testStudy1")
public Object testStudy1() {
log.info("没加自定义注解的方法666");
return "666";
}
@RequestMapping("/testStudy2")
@TestDefinition // ------------------使用自定义注解
public Object testStudy2() {
log.info("加了自定义注解的方法777");
return "777";
}
}
步骤三:创建拦截器StudyInterceptorTest,并制定拦截规则
说明:如果是初学者,建议将所有的拦截器写入专门放拦截器的包中,别当作普通的类瞎jb放
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
/**
* 拦截器
*
* StudyInterceptorTest 为自定义拦截器名称
* HandlerInterceptor 为拦截器接口(都继承这玩意儿实现方法)
*/
@Component
@Slf4j
public class StudyInterceptorTest implements HandlerInterceptor {
/**
* 前置拦截
*
* @param httpServletRequest 请求
* @param httpServletResponse 响应
* @param o 当前进入拦截器的对象
* @return true放行 false拦截
* @throws Exception 异常
*/
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws Exception {
log.info("########### 开始进入拦截器");
HandlerMethod handlerMethod = (HandlerMethod)handler; // 控制器方法
Method method = handlerMethod.getMethod(); // 当前进入拦截器的方法
TestDefinition annotation = method.getAnnotation(TestDefinition.class); // 当前进入拦截器的方法上的TestDefinition注解
// 如果需要匹配类注解,用反射对象调用isAnnotationPresent(自定义注解.class)方法来判断类上是否用上了这个自定义注解
// 如果需要匹配Controller的url则:if (request.getRequestURI().equalsIgnoreCase("/user/testInterceptor")) {...}
if (annotation == null) {
log.info("########### 放行");
return true; // 放行
}
log.info("########### 拦截");
log.info("########### 获得自定义注解中设置的参数value[{}]", annotation.value()); // 获取自定义注解中的参数
httpServletResponse.getWriter().print("被拦截");
return false; // 拦截
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
log.info("########### postHandle拦截器");
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
log.info("########### afterCompletion拦截器");
}
}
步骤四:创建拦截器配置类 HandlerInterceptorConfiguration
继承 WebMvcConfigurer 接口即可管理拦截器
步骤五:实现一大堆WebMvcConfigurer API
找到 addInterceptors 方法,添加拦截器 StudyInterceptorTest 至管理器,并路径匹配规则
@Override
public void addInterceptors(InterceptorRegistry interceptorRegistry) {
interceptorRegistry.addInterceptor(new StudyInterceptorTest()).addPathPatterns("/**"); // 路径匹配规则
// 一个*:只匹配字符,不匹配路径(/)两个**:匹配字符,和路径(/)
// 如 .addPathPatterns("/secure/*", "/admin/**", "/profile/**");
}
测试:
调用未使用自定义注解的方法:testStudy1
控制台查看结果
########### 开始进入拦截器
########### 放行
没加自定义注解的方法666
########### postHandle拦截器
########### afterCompletion拦截器
调用使用了自定义注解的方法:testStudy2
控制台查看结果
########### 开始进入拦截器
########### 拦截
########### 获得自定义注解中设置的参数value[默认值]