post请求无法保证数据安全,所以平时对一些敏感信息的传输时候,通常都是使用前端加密,后端解密的方式来实现。
解密方法千千万万,但是核心都是为了讲一串加密过的字符还原其本来的意思。
本文讲解的方法是在controller上面加一个自定义注解,全局统一解密,让加密参数在方法体中使用前就进行了解密。
步骤:
1、自定义注解
类的修饰符是class,接口的修饰符是interface,注解的修饰符是@interface。Java提供的元注解有四个,本文使用其中的两个,@Target(使用范围,在哪里使用方法、接口、类、常量等),
@Retention(该注解的生命周期)
如下就是定义了一个名为DecryptRequest的注解,该注解的生命周期是虚拟机的整个运行期间,使用范围是方法上
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)
public @interface DecryptRequest {
}
定义完就可以在方法头上使用该注解了
@PostMapping("postTest")
@DecryptRequest
public ModelAndView test(String name,String passowrd){
System.out.println("name:"+name);
System.out.println("passowrd:"+passowrd);
return null;
}
但是目前该注解没有进行任何操作,下面将赋予该注解解密功能,实现RequestBodyAdvice接口的作用是:只对使用该注解的body参数起作用。@ControllerAdvice注解的作用是让其运行在普通controller之前
package com.graduation.advice;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import org.apache.commons.io.IOUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
import com.graduation.annotation.DecryptRequest;
/**
* 自定义实现类DecryptRequestBodyAdvice,该类实现RequestBodyAdvice接口,然后重写下面四个方法
* 实现RequestBodyAdvice接口的作用是:只对使用该注解的body参数起作用
*
* @author lollipop
*
*/
@ControllerAdvice
public class DecryptRequestBodyAdvice implements RequestBodyAdvice {
@Override
public Object afterBodyRead(Object arg0, HttpInputMessage arg1, MethodParameter arg2, Type arg3,
Class<? extends HttpMessageConverter<?>> arg4) {
// 无条件放行数据
return arg0;
}
/*
* 该方法是在原使用DecryptRequest注解的方法体中使用body参数之前对里面的参数进行操作
*/
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage arg0, MethodParameter arg1, Type arg2,
Class<? extends HttpMessageConverter<?>> arg3) throws IOException {
//先判断有没有使用该注解
boolean isAnnotationPresent = arg1.getMethod().isAnnotationPresent(DecryptRequest.class);
if(isAnnotationPresent){
return new DecryptHttpInputMessage(arg0, "UTF-8");
}
return arg0;
}
@Override
public Object handleEmptyBody(Object arg0, HttpInputMessage arg1, MethodParameter arg2, Type arg3,
Class<? extends HttpMessageConverter<?>> arg4) {
// 无条件放行数据
return arg0;
}
@Override
public boolean supports(MethodParameter arg0, Type arg1, Class<? extends HttpMessageConverter<?>> arg2) {
// 原本是false,将其改成true
return true;
}
private class DecryptHttpInputMessage implements HttpInputMessage{
private HttpInputMessage httpInputMessage;
private String charset;
@Override
public HttpHeaders getHeaders() {
return httpInputMessage.getHeaders();
}
public DecryptHttpInputMessage(HttpInputMessage httpInputMessage, String charset) {
this.httpInputMessage = httpInputMessage;
this.charset = charset;
}
@Override
public InputStream getBody() throws IOException {
//读取body的数据
String decrypt = IOUtils.toString(httpInputMessage.getBody(), charset);
System.out.println("前端传进来的数据:"+decrypt);
//把数据解密,具体的解密方式因人而异,具体需要根据前端的加密方式来解密,这里只是简单的把它替换了
decrypt="9999";
return IOUtils.toInputStream(decrypt, charset);
}
}
}
我的controller
@PostMapping(value="postTest",headers = {"content-type=application/json"})
@DecryptRequest
public ModelAndView test(@RequestBody String password,@RequestParam String name){
System.out.println("controller方法体中的密码:"+password);
System.out.println("controller方法体中的名字:"+name);
return null;
}
postman截图
运行结果图: