最近,项目中遇到一个这样的需求,接口的参数一部需要调用方传入,一部分需要服务端自行处理追加,两者合并后才能调用接口返回响应数据。参数是以form表单形式提交的,那么在Zuul中需要通过Request来获取传入的参数,剩下的参数需要和前端传入的参数进行合并后,路由到具体的服务接口。
首先,需要重写Request中的部分方法,目的是动态配置修改Request中的Parameter参数。如下
/**
* Created by IntelliJ IDEA 2020.
* FileName: ParameterRequestWrapper.java
*
* @Author: Shingmo Yeung
* @Date: 2020/6/4 13:04
* @Version: 1.0
* To change this template use File Or Preferences | Settings | Editor | File and Code Templates.
* File Description: 重新HttpServletRequest,用于动态调整请求参数
*/
public class ParameterRequestWrapper extends HttpServletRequestWrapper {
/**
* 初始化参数Map集合
*/
private final Map<String, String[]> paramsMap = Maps.newHashMap();
/**
* 构造方法
*
* @param httpServletRequest HttpServletRequest
*/
public ParameterRequestWrapper(HttpServletRequest httpServletRequest) {
//将request交给父类,以便于调用对应方法的时候,将其输出,其实父亲类的实现方式和第一种new的方式类似
super(httpServletRequest);
//将参数表,赋予给当前的Map以便于持有request中的参数
this.paramsMap.putAll(httpServletRequest.getParameterMap());
}
/**
* 重载一个构造方法
*
* @param httpServletRequest HttpServletRequest
* @param extendParams 扩展参数
*/
public ParameterRequestWrapper(HttpServletRequest httpServletRequest, Map<String, Object> extendParams) {
this(httpServletRequest);
//这里将扩展参数写入参数表
this.setMultiParameters(extendParams);
}
/**
* 重写getParameter,代表参数从当前类中的map获取
*
* @param name 参数名称
* @return String
*/
@Override
public String getParameter(String name) {
String[] values = this.paramsMap.get(name);
if (values == null || values.length == 0) {
return null;
}
return values[0];
}
/**
* 重写getParameterValues,代表参数从当前类中的map获取
*
* @param name 参数名称
* @return String[]
*/
@Override
public String[] getParameterValues(String name) {
return this.paramsMap.get(name);
}
/**
* 重写getParameterMap
*
* @return Map<String, String[]>
*/
@Override
public Map<String, String[]> getParameterMap() {
this.paramsMap.putAll(this.getRequest().getParameterMap());
return paramsMap;
}
/**
* 增加多个参数
*
* @param otherParams 参数Map
*/
public void setMultiParameters(Map<String, Object> otherParams) {
for (Map.Entry<String, Object> entry : otherParams.entrySet()) {
this.setParameter(entry.getKey(), entry.getValue());
}
}
/**
* 增加参数
*
* @param name 参数名称
* @param value 参数值
*/
public void setParameter(String name, Object value) {
if (value != null) {
if (value instanceof String[]) {
this.paramsMap.put(name, (String[]) value);
} else if (value instanceof String) {
this.paramsMap.put(name, new String[]{(String) value});
} else {
this.paramsMap.put(name, new String[]{String.valueOf(value)});
}
}
}
}
通过以下过滤器,动态配置参数
/**
* Created by IntelliJ IDEA 2020.
* FileName: ParameterRequestFilter.java
*
* @Author: Shingmo Yeung
* @Date: 2020/6/4 13:15
* @Version: 1.0
* To change this template use File Or Preferences | Settings | Editor | File and Code Templates.
* File Description: 自定义参数过滤器,用于动态设置请求参数
*/
@Component
public class ParameterRequestFilter implements Filter, LoggerInterface {
/**
* 下单uri
*/
@Value(value = "${filter.request.orderplace.uri}")
private String orderPlaceUri;
/**
* 初始化
*
* @param filterConfig FilterConfig
*/
@Override
public void init(FilterConfig filterConfig) {
logger.warn("初始化自定义filter,用于动态设置Request请求参数");
}
/**
* 过滤执行方法
*
* @param servletRequest ServletRequest
* @param servletResponse ServletResponse
* @param filterChain FilterChain
* @throws IOException 异常
* @throws ServletException 异常
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
ParameterRequestWrapper requestWrapper = new ParameterRequestWrapper(httpServletRequest);
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
Enumeration<String> stringEnumeration = httpServletRequest.getParameterNames();
while (stringEnumeration.hasMoreElements()) {
String key = stringEnumeration.nextElement();
String[] vals = httpServletRequest.getParameterValues(key);
if (vals != null && vals.length > 0) {
String[] strs = new String[vals.length];
for (int i = 0; i < vals.length; i++) {
requestWrapper.setParameter(key, strs);
}
} else {
requestWrapper.setParameter(key, vals);
}
}
//调用下单接口,后端追加外部订单号参数
if (StringUtils.equals(httpServletRequest.getRequestURI(), this.orderPlaceUri)) {
requestWrapper.setParameter(PARAM_NAME_OUTER_ORDER_ID, IdUtil.generateOuterOrderId());
}
filterChain.doFilter(requestWrapper, httpServletResponse);
}
/**
* 销毁方法
*/
@Override
public void destroy() {
logger.warn("自定义filter销毁,用于动态设置Request请求参数");
}
}
如果自定义的filter类没有在容器管理下,则需要的启动入口程序中,注入此Filter的实现类
/**
* Created by IntelliJ IDEA 2019.
* User: shingmoyeung.
* Date: 2019/9/23.
* Time: 15:56.
* To change this template use File Or Preferences | Settings | Editor | File and Code Templates.
* File Description: 启动入口类
*/
@EnableZuulProxy
@WeCloudApplication
@MapperScan(value = {"com.autoai.oilpayment.mapper"})
public class OilPaymentApplication implements LoggerInterface {
/**
* 加油支付服务启动入口
*
* @param args 命令行参数
*/
public static void main(String[] args) {
logger.error("加油支付服务启动中......");
SpringApplication.run(OilPaymentApplication.class, args);
logger.error("加油支付服务已启动");
}
/**
* 注入自定义过滤器
*
* @return ParameterRequestFilter 自定义参数过滤器,用于动态设置请求参数
*/
@Bean
public Filter requestFilter() {
return new ParameterRequestFilter();
}
}
至此,就实现了对参数的拦截和动态设置