springBoot-如何修改请求和返回参数

一、 需求      

       有时候做项目,我们希望在请求未到达controller层,修改请求参数,为什么有这种需求,比如:参数需要验签和加解密之后赋值使用,如果没有进行验签和解密显然请求会异常。ServletRequest和HttpServletRequest中的请求参数是不能进行修改的,因此有了ServletRequestWrapper和HttpServletRequestWrapper可以进行修改请求参数,controller中的请求参数,都是通过getParameter(String name) 或者 getParameterValues(String name)这两个方法类赋值转换的,因此重新定义类来修改请求参数,我们继承HttpServletRequestWrapper,然后重写getParameter(String name)、getParameterValues(String name)。(这里用到了装饰者模式)

       同样通过自定义类来修改返回参数,可以保护重要信息,比如对返回参数加密或者脱敏处理等

二、 实现

1、pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.1.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.cn.dl</groupId>
	<artifactId>springbootfilterdemo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springbootfilterdemo</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.47</version>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
		<dependency>
			<groupId>com.google.inject</groupId>
			<artifactId>guice</artifactId>
			<version>4.1.0</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>javax.validation</groupId>
			<artifactId>validation-api</artifactId>
		</dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

2、ParameterServletRequestWrapper:处理请求参数

package com.cn.dl.config;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class ParameterServletRequestWrapper extends HttpServletRequestWrapper {

    private Map<String , String[]> params = new HashMap<String, String[]>();
    
    public ParameterServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        this.params.putAll(request.getParameterMap());
    }

    /**
     * 重载一个构造方法
     * @param request
     * @param extendParams
     */
    public ParameterServletRequestWrapper(HttpServletRequest request , Map<String , String[]> extendParams) throws IOException {
        this(request);
        addAllParameters(extendParams);
    }

    @Override
    public String getParameter(String name) {
        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);
    }

    public void addAllParameters(Map<String , String[]>otherParams) {
        for(Map.Entry<String , String[]>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)});
            }
        }
    }
}

3、ParameterServletResponseWrapper :处理返回参数

package com.cn.dl.config;

import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.*;

public class ParameterServletResponseWrapper extends HttpServletResponseWrapper {

    private ByteArrayOutputStream buffer;
    private ServletOutputStream out;
    private PrintWriter writer;

    public ParameterServletResponseWrapper(HttpServletResponse resp) throws IOException {
        super(resp);
        buffer = new ByteArrayOutputStream();
        out = new WapperedOutputStream(buffer);
        writer = new PrintWriter(new OutputStreamWriter(buffer,
                this.getCharacterEncoding()));
    }

    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return out;
    }

    @Override
    public PrintWriter getWriter() throws UnsupportedEncodingException {
        return writer;
    }

    @Override
    public void flushBuffer() throws IOException {
        if (out != null) {
            out.flush();
        }
        if (writer != null) {
            writer.flush();
        }
    }

    @Override
    public void reset() {
        buffer.reset();
    }

    public byte[] getResponseData() throws IOException {
        flushBuffer();
        return buffer.toByteArray();
    }

    private class WapperedOutputStream extends ServletOutputStream {
        private ByteArrayOutputStream bos = null;

        public WapperedOutputStream(ByteArrayOutputStream stream)
                throws IOException {
            bos = stream;
        }

        @Override
        public void write(int b) throws IOException {
            bos.write(b);
        }

        @Override
        public void write(byte[] b) throws IOException {
            bos.write(b, 0, b.length);
        }

        @Override
        public void setWriteListener(WriteListener writeListener) {

        }

        @Override
        public boolean isReady() {
            return false;
        }
    }

}

4、RequestParam

package com.cn.dl.bean;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * Created by yanshao on 2019/2/12.
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RequestParam implements Serializable {

    private static final long serialVersionUID = 8608875806674149703L;

    private String data1;
    private String data2;
    private String data3;
    private int data4;

    @Override
    public String toString() {
        //将bean转换成bean string
        return JSON.toJSONString(this);
    }
}

5、WebFilterParam:对请求和返回进行过滤处理

在项目中我们一般都是继承servlet中的Filter来实现过滤,而现在推荐使用OncePerRequestFilter,OncePerRequestFilter能够确保一次请求只过滤一次,不会重复执行,我们经常用的servlet Filter,servlet版本不一样,过滤请求的情况都不一样,而OncePerRequestFilter能够兼容不同的servlet版本和运行环境。

package com.cn.dl.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cn.dl.bean.RequestParam;
import com.cn.dl.config.ParameterServletRequestWrapper;
import com.cn.dl.config.ParameterServletResponseWrapper;
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.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by yanshao on 2019/2/12.
 */
public class WebFilterParam extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        PrintWriter out = response.getWriter();

        Map<String, String[]> parameterMap = new HashMap<>(request.getParameterMap());
        //修改请求参数
        parameterMap.put("data1",new String[]{"data1"});
        parameterMap.put("data2",new String[]{"data2"});
        parameterMap.put("data3",new String[]{"data3"});
        parameterMap.put("data4",new String[]{"44"});
        ParameterServletRequestWrapper req = new ParameterServletRequestWrapper(request, parameterMap);
        ParameterServletResponseWrapper resp = new ParameterServletResponseWrapper(response);

        //调用对应的controller
        super.doFilter(req,resp,filterChain);

        //对返回参数进行处理
        resp.setContentLength(-1);
        RequestParam requestParam = JSONObject.toJavaObject(JSON.parseObject(new String(resp.getResponseData())), RequestParam.class);
        requestParam.setData1("****");
        requestParam.setData2("****");
        out.print(requestParam.toString());
        out.flush();
        out.close();
    }
}

6、WebConfig:配置过滤器

package com.cn.dl.config;

import com.cn.dl.filter.WebFilterParam;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


/**
 * Created by yanshao on 2018/12/26.
 */
@Configuration
public class WebConfig{

//    @Bean
//    public FilterRegistrationBean WebFilterDemo(){
//         TODO: 2018/12/26 配置了过滤器
//        FilterRegistrationBean frBean = new FilterRegistrationBean();
//        frBean.setFilter(new WebFilterDemo());
//        frBean.addUrlPatterns("/*");
//        frBean.setName("webFilterDemo");
//        return frBean;
//    }
    @Bean
    public FilterRegistrationBean WebFilterDemo(){
        //配置过滤器
        FilterRegistrationBean frBean = new FilterRegistrationBean();
        frBean.setFilter(new WebFilterParam());
        frBean.addUrlPatterns("/*");
        frBean.setName("webFilterDemo");
        //springBoot会按照order值的大小,从小到大的顺序来依次过滤。
        frBean.setOrder(0);
        return frBean;
    }
}

7、WebFilterParamControllerDemo:controller测试类

package com.cn.dl.controller;

import com.cn.dl.bean.RequestParam;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Created by yanshao on 2019/2/12.
 */
@RestController
@RequestMapping(value = {"/web_request"})
public class WebFilterParamControllerDemo {


    @PostMapping(value = "test1")
    public String webReqestParamTest(RequestParam requestParam){
        System.out.println("webReqestParamTest>>>>>>>>>>>>");
        System.out.println(requestParam.toString());
        return requestParam.toString();

    }

    @GetMapping (value = "test2")
    public String webReqestParamTest2(RequestParam requestParam){
        System.out.println("webReqestParamTest>>>>>>>>>>>>");
        System.out.println(requestParam.toString());
        return requestParam.toString();
    }

}

三、测试

1、data1至data3的值在到达controller层之前被修改为value1、value2、value3,data4被修改为44,返回时,data1和data2值为*****,最后请求和返回实际输出结果与预期一致

2、data1至data3的值在到达controller层之前被修改为value1、value2、value3,data4未赋值,data4的值应该为0,返回时,data1和data2值为*****,最后请求和返回实际输出结果与预期一致

  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

燕少༒江湖

给我一份鼓励!谢谢!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值