最近,项目中遇到一个这样的需求,接口的参数一部需要调用方传入,一部分需要服务端自行处理追加,两者合并后才能调用接口返回响应数据。参数是以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();
    }
}

至此,就实现了对参数的拦截和动态设置

🔎借鉴文章 向Filter过滤器中的Request对象添加额外的参数