有时候做项目,我们希望在请求未到达controller层,修改请求参数,为什么有这种需求,比如:参数需要验签和加解密之后赋值使用,如果没有进行验签和解密显然请求会异常。ServletRequest和HttpServletRequest中的请求参数是不能进行修改的,因此有了ServletRequestWrapper和HttpServletRequestWrapper可以进行修改请求参数,controller中的请求参数,都是通过getParameter(String name) 或者 getParameterValues(String name)这两个方法类赋值转换的,因此重新定义类来修改请求参数,我们继承HttpServletRequestWrapper,然后重写getParameter(String name)、getParameterValues(String name)。(这里用到了装饰者模式)
同样通过自定义类来修改返回参数,可以保护重要信息,比如对返回参数加密或者脱敏处理等
1、pom文件
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.1.1.RELEASE
com.cn.dl
springbootfilterdemo
0.0.1-SNAPSHOT
springbootfilterdemo
Demo project for Spring Boot
1.8
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
com.alibaba
fastjson
1.2.47
org.projectlombok
lombok
com.google.inject
guice
4.1.0
test
javax.validation
validation-api
commons-io
commons-io
2.6
org.springframework.boot
spring-boot-maven-plugin
2、ParameterServletRequestWrapper:处理请求参数
package com.cn.dl.config;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class ParameterServletRequestWrapper extends HttpServletRequestWrapper {
private Map params = new HashMap();
public ParameterServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
this.params.putAll(request.getParameterMap());
}
/**
* 重载一个构造方法
* @param request
* @param extendParams
*/
public ParameterServletRequestWrapper(HttpServletRequest request , Map extendParams) throws IOException {
this(request);
addAllParameters(extendParams);
}
@Override
public String getParameter(String name) {
String[]values = params.get(name);
if(values == null || values.length == 0) {
return null;
}
return values[0];
}
@Override
public String[] getParameterValues(String name) {
return params.get(name);
}
public void addAllParameters(MapotherParams) {
for(Map.Entryentry : otherParams.entrySet()) {
addParameter(entry.getKey() , entry.getValue());
}
}
public void addParameter(String name , Object value) {
if(value != null) {
if(value instanceof String[]) {
params.put(name , (String[])value);
}else if(value instanceof String) {
params.put(name , new String[] {(String)value});
}else {
params.put(name , new String[] {String.valueOf(value)});
}
}
}
}
3、ParameterServletResponseWrapper :处理返回参数
package com.cn.dl.config;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.*;
public class ParameterServletResponseWrapper extends HttpServletResponseWrapper {
private ByteArrayOutputStream buffer;
private ServletOutputStream out;
private PrintWriter writer;
public ParameterServletResponseWrapper(HttpServletResponse resp) throws IOException {
super(resp);
buffer = new ByteArrayOutputStream();
out = new WapperedOutputStream(buffer);
writer = new PrintWriter(new OutputStreamWriter(buffer,
this.getCharacterEncoding()));
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return out;
}
@Override
public PrintWriter getWriter() throws UnsupportedEncodingException {
return writer;
}
@Override
public void flushBuffer() throws IOException {
if (out != null) {
out.flush();
}
if (writer != null) {
writer.flush();
}
}
@Override
public void reset() {
buffer.reset();
}
public byte[] getResponseData() throws IOException {
flushBuffer();
return buffer.toByteArray();
}
private class WapperedOutputStream extends ServletOutputStream {
private ByteArrayOutputStream bos = null;
public WapperedOutputStream(ByteArrayOutputStream stream)
throws IOException {
bos = stream;
}
@Override
public void write(int b) throws IOException {
bos.write(b);
}
@Override
public void write(byte[] b) throws IOException {
bos.write(b, 0, b.length);
}
@Override
public void setWriteListener(WriteListener writeListener) {
}
@Override
public boolean isReady() {
return false;
}
}
}
4、RequestParam
package com.cn.dl.bean;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* Created by yanshao on 2019/2/12.
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RequestParam implements Serializable {
private static final long serialVersionUID = 8608875806674149703L;
private String data1;
private String data2;
private String data3;
private int data4;
@Override
public String toString() {
//将bean转换成bean string
return JSON.toJSONString(this);
}
}
5、WebFilterParam:对请求和返回进行过滤处理
在项目中我们一般都是继承servlet中的Filter来实现过滤,而现在推荐使用OncePerRequestFilter,OncePerRequestFilter能够确保一次请求只过滤一次,不会重复执行,我们经常用的servlet Filter,servlet版本不一样,过滤请求的情况都不一样,而OncePerRequestFilter能够兼容不同的servlet版本和运行环境。
package com.cn.dl.filter;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cn.dl.bean.RequestParam;
import com.cn.dl.config.ParameterServletRequestWrapper;
import com.cn.dl.config.ParameterServletResponseWrapper;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
/**
* Created by yanshao on 2019/2/12.
*/
public class WebFilterParam extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
PrintWriter out = response.getWriter();
Map parameterMap = new HashMap<>(request.getParameterMap());
//修改请求参数
parameterMap.put("data1",new String[]{"data1"});
parameterMap.put("data2",new String[]{"data2"});
parameterMap.put("data3",new String[]{"data3"});
parameterMap.put("data4",new String[]{"44"});
ParameterServletRequestWrapper req = new ParameterServletRequestWrapper(request, parameterMap);
ParameterServletResponseWrapper resp = new ParameterServletResponseWrapper(response);
//调用对应的controller
super.doFilter(req,resp,filterChain);
//对返回参数进行处理
resp.setContentLength(-1);
RequestParam requestParam = JSONObject.toJavaObject(JSON.parseObject(new String(resp.getResponseData())), RequestParam.class);
requestParam.setData1("****");
requestParam.setData2("****");
out.print(requestParam.toString());
out.flush();
out.close();
}
}
6、WebConfig:配置过滤器
package com.cn.dl.config;
import com.cn.dl.filter.WebFilterParam;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Created by yanshao on 2018/12/26.
*/
@Configuration
public class WebConfig{
// @Bean
// public FilterRegistrationBean WebFilterDemo(){
// TODO: 2018/12/26 配置了过滤器
// FilterRegistrationBean frBean = new FilterRegistrationBean();
// frBean.setFilter(new WebFilterDemo());
// frBean.addUrlPatterns("/*");
// frBean.setName("webFilterDemo");
// return frBean;
// }
@Bean
public FilterRegistrationBean WebFilterDemo(){
//配置过滤器
FilterRegistrationBean frBean = new FilterRegistrationBean();
frBean.setFilter(new WebFilterParam());
frBean.addUrlPatterns("/*");
frBean.setName("webFilterDemo");
//springBoot会按照order值的大小,从小到大的顺序来依次过滤。
frBean.setOrder(0);
return frBean;
}
}
7、WebFilterParamControllerDemo:controller测试类
package com.cn.dl.controller;
import com.cn.dl.bean.RequestParam;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Created by yanshao on 2019/2/12.
*/
@RestController
@RequestMapping(value = {"/web_request"})
public class WebFilterParamControllerDemo {
@PostMapping(value = "test1")
public String webReqestParamTest(RequestParam requestParam){
System.out.println("webReqestParamTest>>>>>>>>>>>>");
System.out.println(requestParam.toString());
return requestParam.toString();
}
@GetMapping (value = "test2")
public String webReqestParamTest2(RequestParam requestParam){
System.out.println("webReqestParamTest>>>>>>>>>>>>");
System.out.println(requestParam.toString());
return requestParam.toString();
}
}
1、data1至data3的值在到达controller层之前被修改为value1、value2、value3,data4被修改为44,返回时,data1和data2值为*****,最后请求和返回实际输出结果与预期一致
2、data1至data3的值在到达controller层之前被修改为value1、value2、value3,data4未赋值,data4的值应该为0,返回时,data1和data2值为*****,最后请求和返回实际输出结果与预期一致