元注解
- @Documented:注解表明这个注解应该被 javadoc工具记录. 默认情况下,javadoc是不包括注解的. 但如果声明注解时指定了 @Documented,则它会被 javadoc 之类的工具处理, 所以注解类型信息也会被包括在生成的文档中,是一个标记注解
- @Target:注解的作用目标
@Target(ElementType.TYPE)——接口、类、枚举、注解
@Target(ElementType.FIELD)——字段、枚举的常量
@Target(ElementType.METHOD)——方法
@Target(ElementType.PARAMETER)——方法参数
@Target(ElementType.CONSTRUCTOR) ——构造函数
@Target(ElementType.LOCAL_VARIABLE)——局部变量
@Target(ElementType.ANNOTATION_TYPE)——注解
@Target(ElementType.PACKAGE)——包 - @Retention表示注解的有效范围
RetentionPolicy.SOURCE - 当前注解只在源代码中有效,一旦编译成class文件,注解就会丢失
RetentionPolicy.CLASS - 注解在源码和字节码中有效,一旦运行就会丢失
RetentionPolicy.RUNTIME - 注解在源码、字节码和运行时都会保留
注解定义方法
-
语法:方法返回值类型 方法名() [default 默认值] ;
-
注意:
1、注解中方法的名字如果刚好叫value,则使用注解时,可以忽略方法名
2、如果使用注解时,需要设置多个方法的返回值,则value不能省略
3、如果一个方法的返回值是数组类型,并且只需要设置一个值时,大括号可以省略
4、如果在使用的时候不想给某个方法赋值,需要在定义该方法的时候设置默认值。 -
举例
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface IsLogin {
int value() default 0;
String[] values() default {};
}
SpringBoot整合自定义注解+aop
- 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
- 自定义注解
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface IsLogin {
boolean mustUser() default false;
}
- 自定义切面实现全局有用
@Aspect // 标记这是一个切面
@Component // 让Spring容器识别到
public class LoginAOP {
@Around("@annotation(IsLogin)") // 对加了这个@IsLogin的方法进行环绕
public Object handlerLogin(ProceedingJoinPoint point){
Object proceed = null;
try {
System.out.println("环绕开始。。。");
proceed = point.proceed();
System.out.println("环绕结束。。。");
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return proceed;
}
}
- Controller方法使用
@RequestMapping(value = "/to1")
@IsLogin
public String to1(){
System.out.println("SSOController.to1");
return "login";
}
}
AOP统一身份认证
- 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.8.RELEASE</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.qf.test</groupId>
<artifactId>shop_entity</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
- 自定义登录注解
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface IsLogin {
boolean mustUser() default false;
}
- AOP全局登录认证
@Aspect // 标记这是一个切面
@Component // 让Spring容器识别到
public class LoginAOP {
@Autowired
private RedisTemplate redisTemplate;
@Around("@annotation(IsLogin)") // 对加了这个@IsLogin的方法进行环绕
public Object handlerLogin(ProceedingJoinPoint point){
// 1.获取目标法方法
MethodSignature methodSignature = (MethodSignature)point.getSignature();
Method method = methodSignature.getMethod();
// 2.得到isLogin注解
IsLogin isLogin = method.getAnnotation(IsLogin.class);
// 3.获取req对象
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = servletRequestAttributes.getRequest();
// 4.获取token
String userTokenKey = CookieUtils.getValue("userToken");
User user = null;
if(!StringUtils.isEmpty(userTokenKey)){
// 从redis中查询token
user = (User) redisTemplate.opsForValue().get(userTokenKey);
}
// 5.判断是否登录
if(user == null){
// 3.判断是否需要注入user对象
if(isLogin.mustUser()){
// 记录当前url
String returnUrl = request.getRequestURL().toString();
try {
returnUrl = URLEncoder.encode(returnUrl,"utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
// 强制跳转到的登录页面
return "redirect:http://localhost:8084/toLogin?returnUrl="+returnUrl;
}
}
// 给user参数赋值
Object[] args = point.getArgs();
for(int i =0;i<args.length;i++){
if(args[i] != null && args[i].getClass() == User.class){
args[i]=user;
break;
}
}
Object proceed = null;
try {
// 调用目标方法
proceed = point.proceed(args);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return proceed;
}
}