1.创建自定义注解
@Target({ElementType.METHOD , ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestDecrypt {
boolean value() default true;
}
说明:
1.)@Retention – 定义该注解的生命周期
● RetentionPolicy.SOURCE : 在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。@Override, @SuppressWarnings都属于这类注解。
● RetentionPolicy.CLASS : 在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式
● RetentionPolicy.RUNTIME : 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。
2.)Target – 表示该注解用于什么地方。默认值为任何元素,表示该注解用于什么地方。可用的ElementType 参数包括
● ElementType.CONSTRUCTOR: 用于描述构造器
● ElementType.FIELD: 成员变量、对象、属性(包括enum实例)
● ElementType.LOCAL_VARIABLE: 用于描述局部变量
● ElementType.METHOD: 用于描述方法
● ElementType.PACKAGE: 用于描述包
● ElementType.PARAMETER: 用于描述参数
● ElementType.TYPE: 用于描述类、接口(包括注解类型) 或enum声明
2.自定义注解处理方法
public class NeedCrypto {
public static boolean needEncrypt(MethodParameter returnType) {
boolean encrypt = false;
boolean classPresentAnno = returnType.getContainingClass().isAnnotationPresent(ResponseEncrypt.class);
boolean methodPresentAnno = Objects.requireNonNull(returnType.getMethod()).isAnnotationPresent(ResponseEncrypt.class);
if (classPresentAnno) {
encrypt = returnType.getContainingClass().getAnnotation(ResponseEncrypt.class).value();
if (!encrypt) return false;
}
if (methodPresentAnno) encrypt = returnType.getMethod().getAnnotation(ResponseEncrypt.class).value();
return encrypt;
}
public static boolean needDecrypt(MethodParameter parameter) {
boolean decrypt = false;
boolean classPresentAnno = parameter.getContainingClass().isAnnotationPresent(RequestDecrypt.class);
boolean methodPresentAnno = Objects.requireNonNull(parameter.getMethod()).isAnnotationPresent(RequestDecrypt.class);
if (classPresentAnno) {
decrypt = parameter.getContainingClass().getAnnotation(RequestDecrypt.class).value();
if (!decrypt) return false;
}
if (methodPresentAnno) decrypt = parameter.getMethod().getAnnotation(RequestDecrypt.class).value();
return decrypt;
}
}
说明:
//判断类上是否有该注解
boolean classPresentAnno = returnType.getContainingClass().isAnnotationPresent(ResponseEncrypt.class);
//判断方法上是否有该注解
boolean methodPresentAnno = Objects.requireNonNull(returnType.getMethod()).isAnnotationPresent(ResponseEncrypt.class);
if (classPresentAnno) {
//获取类上注解的值
encrypt = returnType.getContainingClass().getAnnotation(ResponseEncrypt.class).value();
if (!encrypt) return false;
}
//获取方法上注解的值
if (methodPresentAnno) encrypt = returnType.getMethod().getAnnotation(ResponseEncrypt.class).value();
3.配套RequestDecryptAdvice使用
@Slf4j
@RestControllerAdvice
public class RequestDecryptAdvice implements RequestBodyAdvice {
@Override
public boolean supports(@NonNull MethodParameter methodParameter,
@NonNull Type type,
@NonNull Class<? extends HttpMessageConverter<?>> aClass) {
//return false;
//log.info(“supports >> methodParameter={},type={},aClass={}”, methodParameter, type, aClass.getSimpleName());
return true;
}
@Override
public @NonNull
HttpInputMessage beforeBodyRead(@NonNull HttpInputMessage httpInputMessage,
@NonNull MethodParameter methodParameter,
@NonNull Type type,
@NonNull Class<? extends HttpMessageConverter<?>> aClass) {
//return null;
if (NeedCrypto.needDecrypt(methodParameter)) {
//log.info("type={},aClass={}",type,aClass);
//log.info("**************************我是RequestDecryptAdvice解密操作**************************");
return new HttpInputMessage() {
@Override
public @NonNull
InputStream getBody() throws IOException {
String bodyStr = IOUtils.toString(httpInputMessage.getBody(), StandardCharsets.UTF_8);
String newBodyStr=null;
try {
newBodyStr = AES.decrypt(bodyStr);
log.debug("请求密文={}",bodyStr);
log.info("请求明文={}",newBodyStr);
} catch (Exception exception) {
log.error("bodyStr={},newBodyStr={}",bodyStr,newBodyStr);
log.error(exception.getLocalizedMessage(),exception);
throw new IOException(exception.getMessage(),exception);
}
//log.info("bodyStr={},newBodyStr={}",bodyStr,newBodyStr);
return IOUtils.toInputStream(newBodyStr,StandardCharsets.UTF_8);
}
@Override
public @NonNull
HttpHeaders getHeaders() {
return httpInputMessage.getHeaders();
}
};
}
return httpInputMessage;
}
@Override
public @NonNull
Object afterBodyRead(@NonNull Object o,
@NonNull HttpInputMessage httpInputMessage,
@NonNull MethodParameter methodParameter,
@NonNull Type type,
@NonNull Class<? extends HttpMessageConverter<?>> aClass) {
//return null;
//log.info("afterBodyRead >> object={},httpInputMessage={},methodParameter={},type={},aClass={}", o, httpInputMessage, methodParameter, type, aClass.getSimpleName());
return o;
}
@Override
public Object handleEmptyBody(Object o,
@NonNull HttpInputMessage httpInputMessage,
@NonNull MethodParameter methodParameter,
@NonNull Type type,
@NonNull Class<? extends HttpMessageConverter<?>> aClass) {
//return null;
//log.info("handleEmptyBody >> object={},httpInputMessage={},methodParameter={},type={},aClass={}", o, httpInputMessage, methodParameter, type, aClass.getSimpleName());
return o;
}
}
4.加在类上或者方法上
@RequestDecrypt
@ResponseEncrypt
@CrossOrigin(origins = {""}, allowCredentials = “true”, allowedHeaders = {""})
public class AppAlarmCenterController {}