忽略命名规范!!!
自定义注解可以解决一个公用的问题,比如登陆日志以及权限鉴定等等。。。
1、首先导包:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2、创建一个包下面定义一个注解类
package com.springboot.Demo.zhujie;
import java.lang.annotation.*;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)// 注解会在class字节码文件中存在,在运行时可以通过反射获取到
@Documented//说明该注解将被包含在javadoc中
//最高优先级
@Order(Ordered.HIGHEST_PRECEDENCE)
public @interface Token {
String value();
}
注解:
@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) ///包
里面的参数是可以多选的,使用方法比如@Target({ElementType.METHOD,ElementType.TYPE})。
@Retention
这个注解是保留说明,也就是表明这个注解所注解的类能在哪里保留,他有三个属性值:
RetentionPolicy.SOURCE —— 这种类型的Annotations只在源代码级别保留,编译时就会被忽略
RetentionPolicy.CLASS —— 这种类型的Annotations编译时被保留,在class文件中存在,但JVM将会忽略
RetentionPolicy.RUNTIME —— 这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用。
从上面可以看出一般使用的事第三个属性,其余两个属性,说实话 我也不清楚什么情况下使用这两种。
@Documented
@Documented 注解表明这个注解应该被 javadoc工具记录. 默认情况下,javadoc是不包括注解的. 但如果声明注解时指定了 @Documented,则它会被 javadoc 之类的工具处理, 所以注解类型信息也会被包括在生成的文档中。
@Order
@Order标记定义了组件的加载顺序,这个标记包含一个value属性。属性接受整形值。如:1,2 等等。值越小拥有越高的优先级。Ordered.HIGHEST_PRECEDENCE这个属性值是最高优先级的属性,它的值是-2147483648,对应的最低属性值是Ordered.LOWEST_PRECEDENCE,它的值是2147483647。
至于这个类里面的方法,就是注解时需要传入的参数了。
以下面的的说明一下
String behaviorDes() default “”;
很简单 我们可以分成三部分,String \ behaviorDes()\default “”
我们先看第二个,这个是我们注解时需要传入的参数值的名称,比如上述的用的事behaviorDes,那么我们在注解时就应该这样注解@LogAnnotation(behaviorDes=”测试”),当然如果你只有一个参数需要传的,那么建议各位使用value(),这样注解时会默认传入的,这样我们就可以向其他注解一样@LogAnnotation(“测试”)。
第一部分的String 是代表这个注解的参数类型。
第三部分是需要给注解一个默认值,因为如果如果开发人员没有传入值,而且没有默认值的话,会报错。
3、对这个注解类进行个性化处理
package com.springboot.Demo.acpect;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.springboot.Demo.zhujie.Token;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Aspect//表明aop切面
@Component//放入spring容器中
@SuppressWarnings({"unused"})//取消部分警告
public class Acppt {
public static final Logger logger = LoggerFactory.getLogger(Acppt.class);
public static final String TOKEN_KEY = "token";
@Pointcut("@annotation(com.springboot.Demo.zhujie.Token)")
public void annotationPointcut() {
}
@Before("annotationPointcut()")//第二
public void beforePointcut(JoinPoint joinPoint) {
System.out.println("注解开始");
System.out.println(joinPoint.toString());
}
@Around("annotationPointcut()")//第一
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
HttpServletRequest request = ((ServletRequestAttributes)ra).getRequest();
System.out.println(request.getHeader("x-access-token"));//获取消息头中参数
System.out.println(request.getRequestURL().toString());//获取请求路径
System.out.println(request.getRemoteAddr());//请求ip
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
String[] params = methodSignature.getParameterNames();// 获取参数名称
Object[] args = joinPoint.getArgs();// 获取参数值
if (null == params || params.length == 0){//没有参数
throw new Exception();
}
boolean hasToken = false;
int index = 0;
for (int i = 0; i < params.length; i++) {
if (TOKEN_KEY.equals(params[i])) {//获取需要验证的特定参数
hasToken = true;
index = i;
break;
}
}
Method method = methodSignature.getMethod();//注解中的参数
Token token=(Token)method.getAnnotation(Token.class);
System.out.println(token.value());
this.checkToken(String.valueOf(args[index]));//进行参数检验
return joinPoint.proceed();
}
/**
* 在切入点return内容之后切入内容(可以用来对处理返回值做一些加工处理)
* @param joinPoint
*/
@AfterReturning("annotationPointcut()")//第四
public void doAfterReturning(JoinPoint joinPoint) {
System.out.println("注解结束");
System.out.println(joinPoint.toString());
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
HttpServletResponse response=((ServletRequestAttributes)ra).getResponse();
response.getStatus();//获取状态码
}
private void checkToken(String token) {
try {
//此处进行参数验证,不符合抛出异常或者返回异常状态码
} catch (Exception e) {
logger.info(e.getMessage());
throw new RuntimeException(e.getMessage());
}
}
}
4、测试代码
@GetMapping(value = "/token")
@ResponseBody
@Token("测试")
public String test1(@RequestParam String token) {
System.out.println(token);//第三
return "";
}
5、测试结果