springbootHandlerIntercepter修改requestbody数
据的操作
实际⼯作中学习技术是最快、最深刻的。当然,⾃⾝的持续学习意识是必须的
技术栈版本:
spring boot 2.0.2
遇到事⼉了
近来做业务需求,前端同学fe将userId和userName放到request header中了。
后端api接⼝要想使⽤userId和userName,每个接⼝都要从header中获取。
试想⼀下,如果你有⼗个接⼝,那么每个接⼝都要写⼀遍
Object.Header("userId"))
正如下⾯代码段
@RestController
@Validated
@RequestMapping("/template")
public class TemplateController {
// ⼀个feign client
@Autowired
TemplateClient templateClient
@PostMapping(value = "/create", produces = MediaType.APPLICATION_JSON_VALUE)
public ResultVO create(@RequestBody @Valid TemplateParam param, HttpServletRequest request) {
// 每个接⼝都要写⼀遍setXXX()⽅法
param.Header("userId"));
param.Header("userName"));
ateTemplate(param).toResultVO();
}
}
@Data
public class TemplateParam{
private Long templateId;
private Long userId;
private String userName;
}
解决办法
⼤家都知道的两⼤利器,
tomcat的Filter和spring的Intercepter(具体为HandlerIntercepter)
实现原理
具体⽅法为定义⼀个Filter实现类和⼀个HandlerIntercepter的实现类。再定义⼀个HttpServletRequest实现类,其作⽤分别为
Filter实现类:UserInfoFilter
创建⼀个⼊⼝,在这个⼊⼝中定义⼀个机会:将我们⾃定义的CustomHttpServletRequestWrapper代替HttpServletRequest随着请求传递下去
HttpServletRequest实现类:customHttpServletRequestWrapper
因为HttpServletRequest对象的body数据只能get,不能set,即不能再次赋值。
⽽我们的需求是需要给HttpServletRequest赋值,所以需要定义⼀个HttpServletRequest实现类:customHttpServletRequestWrapper,这个实现类可以被赋值来满⾜我们的需求。
HandlerIntercepter的实现类:CustomInterceptor
拦截请求,获取接⼝⽅法相关信息(⽅法名,参数,返回值等)。从⽽实现统⼀的给request body动态赋值
实现思路如上所述,具体的实现代码如下
代码实现
声明基础bean: UserInfoParam
UserInfoParam:定义了包含userId,userName的实体bean,要想将⽤户信息注⼊进⼊,需要⼊参对象XXXParam继承UserInfoParam,中只处理@Requestbody中实现了UserInfoParam类的bean。
如上⽂controller中create⽅法的⼊参:TemplateParam,继承UserInfoParam
@Data
public class TemplateParam extends UserInfoParam{
private Long templateId;
// private Long userId;
// private String userName;
}
@Data
public class UserInfoParam {
// ⽤户id
private Long userId;
// ⽤户名称
private String userName;
}
定义Filter实现类: UserInfoFilter
@Slf4j
public class UserInfoFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
CustomHttpServletRequestWrapper customHttpServletRequestWrapper = null;
try {
HttpServletRequest req = (HttpServletRequest)request;
customHttpServletRequestWrapper = new CustomHttpServletRequestWrapper(req);
}catch (Exception e){
log.warn("customHttpServletRequestWrapper Error:", e);
}
chain.doFilter((Objects.isNull(customHttpServletRequestWrapper) ? request : customHttpServletRequestWrapper), response);
}
}
HttpServletRequest实现类:CustomHttpServletRequestWrapper
public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {
// 保存request body的数据
private String body;
// 解析request的inputStream(即body)数据,转成字符串
public CustomHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
InputStream inputStream = null;
try {
inputStream = InputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = ad(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
} finally {
if (inputStream != null) {
try {
inputStream.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
if (bufferedReader != null) {
try {
bufferedReader.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
body = String();
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new Bytes());        ServletInputStream servletInputStream = new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() throws IOException {
ad();
}
};
return servletInputStream;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStream()));
}
public String getBody() {
return this.body;
}
// 赋值给body字段
public void setBody(String body) {
this.body = body;
}restful接口详解
}
HandlerIntercepter的实现类:CustomInterceptor
@Slf4j
public class CustomInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)        throws Exception {
if (!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod)handler;
pushUserInfo2Body(request, handlerMethod);
return true;
}
private void pushUserInfo2Body(HttpServletRequest request, HandlerMethod handlerMethod) {
try{
String userId = Header("userId");
String userName = Header("userName");
MethodParameter[] methodParameters = MethodParameters();
if(ArrayUtils.isEmpty(methodParameters)) {
return;
}
for (MethodParameter methodParameter : methodParameters) {
Class clazz = ParameterType();
if(ClassUtils.isAssignable(UserInfoParam.class, clazz)){
if(request instanceof CustomHttpServletRequestWrapper){
CustomHttpServletRequestWrapper requestWrapper = (CustomHttpServletRequestWrapper)request;                        String body = Body();
JSONObject param = JSONObject.parseObject(body);
param.put("userId", userId);
param.put("userName", Objects.isNull(userName) ? null : URLDecoder.decode(userName, "UTF-8"));                        requestWrapper.JSONString(param));
}
}
}
}catch (Exception e){
log.warn("fill userInfo to request body Error ", e);
}
}
定义Configuration class,增加和过滤器的配置
WebMvcConfigurer⼦类:CustomWebMvcConfigurer
@Configuration
public class CustomWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
CustomInterceptor customInterceptor= new CustomInterceptor();
registry.addInterceptor(customInterceptor);
}
@Bean
public FilterRegistrationBean servletRegistrationBean() {
UserInfoFilter userInfoFilter = new UserInfoFilter();
FilterRegistrationBean<UserInfoFilter> bean = new FilterRegistrationBean<>();
bean.setFilter(userInfoFilter);
bean.setName("userInfoFilter");
bean.addUrlPatterns("/*");
bean.setOrder(Ordered.LOWEST_PRECEDENCE);
return bean;
}
}
到此,实现功能的代码撸完了。启动spring boot App,就可以curl访问restful接⼝了
http访问
curl -X POST \
localhost:8080/template/create
-H 'Content-Type: application/json'
-H 'username: tiankong天空'
-H 'userId: 11'
-d '{
"templateId": 1000}
效果
可以看到ate(…)打出的信息,userId和username的值正是header中传的值
toDo
剩下的就看你的了,以上为个⼈经验,希望能给⼤家⼀个参考,也希望⼤家多多⽀持。