记录:277
场景:在过滤器Filter的doFilter中,拦截一个http请求。对请求对象ServletRequest,按照业务需求进行处理,比如参数验证、SQL注入拦截、日志审计等。对应答对象ServletResponse,按照业务需求进行处理,比如统一返回数据格式,加密返回数据,压缩返回数据等。
版本:Spring Boot 2.6.3
一、案例场景
1.发起一个http请求(POST请求),入参是JSON数据。
2.在Filter的doFilter中,使用ServletRequest接口的包装类,获取请求的入参并处理。
3.发布Restful的Controller处理业务请求,并返回JSON字符串数据。
4.在Filter的doFilter中,使用ServletResponse接口的包装类,处理应答数据,增加一个应答数据。
二、使用类
1.请求对象关系
javax.servlet.ServletRequest,接口。
javax.servlet.http.HttpServletRequest,接口。
javax.servlet.ServletRequestWrapper,包装类。
javax.servlet.http.HttpServletRequestWrapper,包装类。
2.应答对象关系
javax.servlet.ServletResponse,接口。
javax.servlet.http.HttpServletResponse,接口。
javax.servlet.ServletResponseWrapper,包装类。
javax.servlet.http.HttpServletResponseWrapper,包装类。
三、代码
1.CustomRequestWrapper
CustomRequestWrapper,继承HttpServletRequestWrapper,重写相关方法。
public class CustomRequestWrapper extends HttpServletRequestWrapper {
private final String body;
public CustomRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
StringBuilder sb = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(
inputStream, StandardCharsets.UTF_8));
char[] charBuffer = new char[512];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
sb.append(charBuffer, 0, bytesRead);
}
} else {
sb.append("");
}
} catch (IOException e) {
e.printStackTrace();
throw e;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
throw e;
}
}
}
body = sb.toString();
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(
body.getBytes("UTF-8"));
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() {
return bais.read();
}
};
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(
this.getInputStream(), StandardCharsets.UTF_8));
}
public String getBody() {
return this.body;
}
@Override
public String getParameter(String name) {
return super.getParameter(name);
}
@Override
public Map<String, String[]> getParameterMap() {
return super.getParameterMap();
}
@Override
public Enumeration<String> getParameterNames() {
return super.getParameterNames();
}
@Override
public String[] getParameterValues(String name) {
return super.getParameterValues(name);
}
}
2.CustomResponseWrapper
CustomResponseWrapper,继承HttpServletResponseWrapper,重写相关方法。
public class CustomResponseWrapper extends HttpServletResponseWrapper {
private ByteArrayOutputStream byteArrayOutputStream = null;
private ServletOutputStream servletOutputStream = null;
private PrintWriter printWriter = null;
public CustomResponseWrapper(HttpServletResponse response) {
super(response);
// 数据流输出到此对象
byteArrayOutputStream = new ByteArrayOutputStream();
}
/**
* 重载
* javax.servlet.ServletResponseWrapper的
* getOutputStream方法
*/
@Override
public ServletOutputStream getOutputStream() throws IOException {
if (servletOutputStream == null) {
servletOutputStream = new WrapperOutputStream(
byteArrayOutputStream);
}
return servletOutputStream;
}
/**
* 重载
* javax.servlet.ServletResponseWrapper的
* getWriter方法
*/
@Override
public PrintWriter getWriter() throws IOException {
if (printWriter == null) {
printWriter = new PrintWriter(new OutputStreamWriter(
byteArrayOutputStream,
this.getCharacterEncoding()));
}
return printWriter;
}
@Override
public void flushBuffer() throws IOException {
if (servletOutputStream != null) {
servletOutputStream.flush();
}
if (printWriter != null) {
printWriter.flush();
}
}
public byte[] getResponseByteData() throws IOException {
flushBuffer();
return byteArrayOutputStream.toByteArray();
}
public String getResponseStringData() throws IOException {
flushBuffer();
return byteArrayOutputStream.toString("utf-8");
}
public Map getResponseMapResult() {
String contentType = getContentType();
if (StringUtils.isNotBlank(contentType)
&& contentType.toLowerCase().contains("application/json")) {
try {
String jsonData = getResponseStringData();
Map mapJson = JSON.parseObject(jsonData, Map.class);
return mapJson;
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
private class WrapperOutputStream extends ServletOutputStream {
private ByteArrayOutputStream bos = null;
public WrapperOutputStream(ByteArrayOutputStream bos) {
super();
this.bos = bos;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setWriteListener(WriteListener writeListener) {
}
@Override
public void write(int b) throws IOException {
bos.write(b);
}
}
}
3.ExampleFilter
ExampleFilter,实现Filter接口,重写相关方法。在doFilter中实现具体逻辑。
@Slf4j
public class ExampleFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
// 1.创建请求包装类: CustomRequestWrapper
CustomRequestWrapper requestWrapper = new CustomRequestWrapper(httpRequest);
if ("POST".equals(httpRequest.getMethod().toUpperCase())) {
// 2. 从requestWrapper获取请求参数,可按需拦截,并做业务处理
String body = requestWrapper.getBody();
log.info("ExampleFilter—>doFilter,从request的InputStream,获取数据: " + body.toString());
}
// 3.创建响应包装类: CustomResponseWrapper
CustomResponseWrapper responseWrapper = new CustomResponseWrapper(httpResponse);
try {
log.info("ExampleFilter—>doFilter,在FilterChain,传入requestWrapper和responseWrapper.");
log.info("ExampleFilter—>doFilter,触发requestWrapper的getInputStream调用.");
log.info("ExampleFilter—>doFilter,触发responseWrapper的getOutputStream调用.");
// 4. 过滤器链执行(请求包装类,应答不装类)
// 4.1 触发调用requestWrapper的getInputStream,将读取数据回写到ServletInputStream
// 4.2 触发调用responseWrapper的getOutputStream,将数据写到responseWrapper的byteArrayOutputStream
filterChain.doFilter(requestWrapper, responseWrapper);
// 5. 从responseWrapper获取应答结果,可按需拦截,并做业务处理
Map mapTemp = responseWrapper.getResponseMapResult();
log.info("ExampleFilter—>doFilter,从responseWrapper的OutputStream,获取数据: " + JSON.toJSONString(mapTemp));
if (mapTemp != null && mapTemp.size() > 0) {
mapTemp.put("checkFlagDate", DateUtil.format(new Date(),"yyyy-MM-dd"));
}
log.info("ExampleFilter—>doFilter,加工后写入response的OutputStream数据: " + JSON.toJSONString(mapTemp));
// 6. 应答数据回写到response的OutputStream中
httpResponse.getOutputStream().write(
JSON.toJSONString(mapTemp).getBytes(StandardCharsets.UTF_8));
httpResponse.getOutputStream().flush();
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
}
4.FilterConfiguration
FilterConfiguration,注册过滤器。
@Configuration
public class FilterConfiguration {
@Bean("exampleFilter")
public ExampleFilter sqlInjectFilter() {
return new ExampleFilter();
}
@Bean
public FilterRegistrationBean<ExampleFilter> sqlFilterRegistrationBean() {
FilterRegistrationBean<ExampleFilter> filterReg = new FilterRegistrationBean<>();
filterReg.setFilter(sqlInjectFilter());
filterReg.addUrlPatterns("/*");
filterReg.setOrder(1);
return filterReg;
}
}
5.FilterController
FilterController,提供resiful方法。
@Slf4j
@RestController
@RequestMapping("/filter")
public class FilterController {
@PostMapping("/f1")
public Object f1(@RequestBody Object obj) {
log.info("FilterController->f1,接收参数,obj = " + obj.toString());
Map objMap = (Map) obj;
return ResultObj.builder().code("200").message("成功").build();
}
}
6.ResultObj
ResultObj,全局返回对象。
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ResultObj {
private String code;
private String message;
}
7.测试
测试URL: http://127.0.0.1:8080/server/filter/f1
入参:
{"userName": "HangZhou","tradeName": "Vue进阶教程"}
返回:
{"code": "200","checkFlagDate": "2022-06-20","message": "成功"}
输出日志:
以上,感谢
2022年6月21日