前言:对于HttpServletRequest 在拦截器中我们只能对其请求参数进行读取,却不能添加或者修改请求参数,如果确实需要对HttpServletRequest 进行统一参数的添加,需要怎么处理,有没有一种类我们可以通过继承或者实现,重写覆盖方法,或者我们自己定义方法完成对请求参数的添加呢;
1 通过自定义类并且继承HttpServletRequestWrapper:
import com.alibaba.fastjson2.JSONObject;
import org.springframework.util.StringUtils;
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.HashMap;
import java.util.Map;
/**
* request 请求参数添加
*
* @Description TODO
* @Date 2022/12/13 09:41
* @Author lgx
* @Version 1.0
*/
public class ParameterRequestWrapper extends HttpServletRequestWrapper {
private Map<String, String[]> params = new HashMap<String, String[]>();
private byte[] body;
@SuppressWarnings("unchecked")
public ParameterRequestWrapper(HttpServletRequest request) {
// 将request交给父类,以便于调用对应方法的时候,将其输出,
// 其实父亲类的实现方式和第一种new的方式类似
super(request);
//将参数表,赋予给当前的Map以便于持有request中的参数
//由于request并没有提供现成的获取json字符串的方法,所以我们需要将body中的流转为字符串
String json = getPostData(request);
if (!StringUtils.isEmpty(json)) {
// body 赋值
this.body = getData(json).getBytes();
}
// 请求参数赋值
this.params.putAll(request.getParameterMap());
}
/**
* 重载一个构造方法-- 扩展参数
*
* @param request
* @param extendParams
*/
public ParameterRequestWrapper(HttpServletRequest request, Map<String, Object> extendParams) {
this(request);
//这里将扩展参数写入参数表
addAllParameters(extendParams);
}
/**
* 增加多个参数
*
* @param otherParams
*/
public void addAllParameters(Map<String, Object> otherParams) {
for (Map.Entry<String, Object> entry : 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)});
}
}
}
/**
* 增加body 参数
*
* @param name
* @param value
*/
public void addParameterToBody(String name, Object value) {
byte[] json = this.body;
if (null == json) {
return;
}
String jsonStr = new String(json);
try {
Map<String, Object> mapData = JSONObject.parseObject(jsonStr, Map.class);
if (value != null) {
mapData.put(name, value);
this.body = JSONObject.toJSONString(mapData).getBytes();
}
} catch (Exception ex) {
// 转换异常
}
}
/**
* body中参数解密
*
* @param json
* @return
*/
private String getData(String json) {
//加密,如果传过来的是加密数据,先解密,未加密直接返回原json
// if(StringUtils.isNotEmpty(json)){
// json = AES256Util.decode(json);
// if(StringUtils.isEmpty(json)){
// return "";
// }
// JSONObject object = JSONUtil.parseObj(json);
// return JSONUtil.toJsonStr(object);
// }
//不加密
return json;
}
/**
* 获取body 参数
*
* @param request
* @return
*/
public static String getPostData(HttpServletRequest request) {
StringBuilder data = new StringBuilder();
String line;
BufferedReader reader;
try {
reader = request.getReader();
while (null != (line = reader.readLine())) {
data.append(line);
}
} catch (IOException e) {
return null;
}
return data.toString();
}
@Override
public String getParameter(String name) {//重写getParameter,代表参数从当前类中的map获取
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);
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
/**
* 在使用@RequestBody注解的时候,其实框架是调用了getInputStream()方法,所以我们要重写这个方法
*
* @return
* @throws IOException
*/
@Override
public ServletInputStream getInputStream() throws IOException {
if (body == null) {
body = new byte[0];
}
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
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() throws IOException {
return bais.read();
}
};
}
}
2 自定义过滤器完成参数的追加:
import com.cric.gx.modules.user.constant.UserConstant;
import com.cric.gx.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@WebFilter
@Order(1)
@Component
public class AppendParametersFilter implements Filter {
@Autowired
private RedisUtil redisUtil;
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
ParameterRequestWrapper requestWrapper = new ParameterRequestWrapper((HttpServletRequest) request);
// 请求的参数 拼接
Map<String, String> rtnMap = converMap(request);
// 请求参数 body
Set<String> keySet = rtnMap.keySet();
//解密value
for (String str : keySet) {
String value = rtnMap.get(str);
// 将参数追加到request url 之后
requestWrapper.addParameter(str, value);
// 将参数追加到request 的body 中
requestWrapper.addParameterToBody(str, value);
}
// 过滤链调用
chain.doFilter(requestWrapper, response);
}
/**
* 转换request 请求参数并追加要添加的参数
*
* @param request
*/
public Map<String, String> converMap(ServletRequest request) {
Map<String, String> rtnMap = new HashMap<String, String>(2);
HttpServletRequest request1 = (HttpServletRequest) request;
String authorization = request1.getHeader(UserConstant.mAuthorization);
if (StringUtils.isEmpty(authorization)){
return rtnMap;
}
Object userIdObj = redisUtil.hGet(UserConstant.wxLogin, authorization);
String userId = null == userIdObj ? null : userIdObj.toString();
rtnMap.put(UserConstant.userId, userId);
rtnMap.put(UserConstant.openId, authorization);
rtnMap.put(UserConstant.openIdOne, authorization);
return rtnMap;
}
}
3 使用:
/**
* 测试用户信息,请求参数获取
* @param reqDto
* @param openId
* @param userId
* @return
*/
@NeedUserPhoneAnnotation
@PostMapping(value = "/test")
public Map saveUser(@RequestBody @Valid UserInfoReqDto reqDto, @RequestParam(value = "wxUseropenId") String openId,
@RequestParam(value = "userId") Integer userId){
return new HashMap<>(0);
}
注意过滤器和拦截器的顺序:一个请求来到后是先经过过滤器,放行后才到达拦截器