一、继承HttpServletRequestWrapper创建自定义请求包装器
需要重写的方法
1、getParameterMap
2、getParameter
3、getParameterValues
4、getInputStream
5、getReader
代码如下
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Map;
/**
* 特殊字符转义请求包装器
* 请求中含有特殊字符的数据进行转义
*/
public class SpecialCharRequestWrapper extends HttpServletRequestWrapper {
/**
* 特殊字符映射集合
* 示例:{"<", "<"}
*/
private final Map<String, String> map;
/**
* 构造器
*
* @param request 请求
* @param map 特殊字符映射集合
*/
public SpecialCharRequestWrapper(HttpServletRequest request, Map<String, String> map) {
super(request);
this.map = map;
}
/**
* 获取参数map集合
*/
@Override
public Map<String, String[]> getParameterMap() {
Map<String, String[]> parameterMap = super.getParameterMap();
if (parameterMap != null) {
parameterMap.forEach((key, value) -> parameterMap.put(key, this.getParameterValues(key)));
}
return parameterMap;
}
/**
* 根据参数名获取值
*/
@Override
public String getParameter(String name) {
return escape(super.getParameter(name));
}
/**
* 根据参数名获取所有的值
*/
@Override
public String[] getParameterValues(String name) {
String[] parameterValues = super.getParameterValues(name);
if (parameterValues != null) {
for (int i = 0; i < parameterValues.length; i++) {
parameterValues[i] = escape(parameterValues[i]);
}
}
return parameterValues;
}
/**
* 获取body数据
*/
@Override
public ServletInputStream getInputStream() throws IOException {
// 读取body
ServletInputStream sis = super.getInputStream();
// 加载body
ObjectMapper om = new ObjectMapper();
JsonNode jsonNode = om.readTree(sis);
// 创建待处理列表并添加节点
LinkedList<JsonNode> linkedList = new LinkedList<>();
linkedList.add(jsonNode);
// 循环对body进行转义
while (!linkedList.isEmpty()) {
JsonNode node = linkedList.removeFirst();
// 检查是否为对象节点
if (node.isObject()) {
ObjectNode on = (ObjectNode) node;
// 遍历对象节点
node.fields().forEachRemaining(entry -> {
// 获取节点各字段的值
JsonNode entryValue = entry.getValue();
if (!entryValue.isNull()) {
// 检查值是否为文本
if (entryValue.isTextual()) {
// 对值进行转义,并对节点重新赋值
on.put(entry.getKey(), escape(entryValue.asText()));
}
// 检查值是否为对象节点或数组节点
if (entryValue.isObject() || entryValue.isArray()) {
// 节点加入待处理列表中
linkedList.add(entryValue);
}
}
});
}
// 检查是否为数组节点
if (node.isArray()) {
ArrayNode an = (ArrayNode) node;
// 遍历数组节点
for (int i = 0; i < node.size(); i++) {
// 获取数组节点索引位置的值
JsonNode arrayValue = node.get(i);
if (!arrayValue.isNull()) {
// 检查值是否为文本
if (arrayValue.isTextual()) {
// 对值进行转义,并对节点重新赋值
an.set(i, new TextNode(escape(arrayValue.asText())));
}
// 检查值是否为对象节点或数组节点
if (arrayValue.isObject() || arrayValue.isArray()) {
// 节点加入待处理列表中
linkedList.add(arrayValue);
}
}
}
}
}
// 把转义完的json数据转成字节数组输入流
final ByteArrayInputStream bais = new ByteArrayInputStream(om.writeValueAsBytes(jsonNode));
// 创建新的流
return new ServletInputStream() {
@Override
public boolean isFinished() {
// todo 自定义操作
return false;
}
@Override
public boolean isReady() {
// todo 自定义操作
return false;
}
@Override
public void setReadListener(ReadListener listener) {
// todo 自定义操作
}
@Override
public int read() throws IOException {
// 通过bais读取转义完的数据
return bais.read();
}
};
}
/**
* 获取body读取器
*/
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
/**
* 转义方法
*/
private String escape(String value) {
// 空值直接返回
if (value == null) {
return null;
}
// 遍历字符串检查各个字符是否为特殊字符并进行转义
StringBuilder sb = new StringBuilder();
for (int i = 0; i < value.length(); i++) {
String charValue = String.valueOf(value.charAt(i));
sb.append(map.getOrDefault(charValue, charValue));
}
return sb.toString();
}
}
二、继承OncePerRequestFilter或者实现Filter创建自定义过滤器
两种方式选择其中一个
继承OncePerRequestFilter(Spring中)
1、创建过滤器
import org.springframework.context.annotation.Configuration;
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.util.HashMap;
import java.util.Map;
/**
* 特殊字符过滤器
*/
@Configuration
public class SpecialCharFilter extends OncePerRequestFilter {
/**
* 特殊字符集合
*/
private Map<String, String> map = new HashMap<String, String>() {{
put("\"", """);
put("<", "<");
put(">", ">");
put("?", "¡");
put("¥", "¥");
put("|", "¦");
put("′", "´");
}};
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// 传入自定义的请求包装器
filterChain.doFilter(new SpecialCharRequestWrapper(request, map), response);
}
}
实现Filter(Spring中)
1、创建过滤器
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* 特殊字符过滤器
*/
public class SpecialCharFilter implements Filter {
/**
* 特殊字符集合
*/
private Map<String, String> map = new HashMap<String, String>() {{
put("\"", """);
put("<", "<");
put(">", ">");
put("?", "¡");
put("¥", "¥");
put("|", "¦");
put("′", "´");
}};
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 传入自定义的请求包装器
chain.doFilter(new SpecialCharRequestWrapper((HttpServletRequest) request, map), response);
}
}
2、注册过滤器
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<SpecialCharFilter> getSpecialCharFilter() {
FilterRegistrationBean<SpecialCharFilter> registrationBean = new FilterRegistrationBean<>();
// 添加过滤器
registrationBean.setFilter(new SpecialCharFilter());
// 全部路径都过滤
registrationBean.addUrlPatterns("/*");
return registrationBean;
}
}