您的位置:首页 > 产品设计 > UI/UE

filter修改request参数

2017-11-16 20:20 253 查看
前言:根据项目要求,需要将request中的请求参数进行修改

body: {
//adsfasdfasdf为加密后的json串(如加密前{name:'张三','age':'18'})
'data':'adsfasdfasdf'加密后的数据
}


转化为

body: {
name : 张三,
age : 18
}


所以在网上查看了很多资料发现可以用HttpServletRequestWrapper来实现,具体实现如下:

PS:在粘贴代码前先来知道一个从request中获取请求参数的方法

1、request.getParameter(name);


2、request.getParameterValues(name);


3、
@RequestMapping("/getRequestParameter")
@ResponseBody
public int getRequestParameter(String name, Integer age){
return 1;
}


我们一般在时候springmvc的时候会用如下3中方法来回去数据(3和2是一样的调用getParameterValues(name)方法)

现在我们知道了怎么来获取参数就好办了。

HttpServletRequestWrapper extends ServletRequestWrapper implements HttpServletRequest
extends ServletRequest
ServletRequestWrapper implements ServletRequest


其实我们在调用1、2方法的时候是在调用ServletRequest的getParameter(name)和getParameterValues(name)方法,所以要想修改请求参数只要在传递参数的时候用不同的实现类即可,恰好HttpServletRequestWrapper给了我们这个机会,查看一下HttpServletRequestWrapper 的源码可以发现其实内部的所有重写的方法都是调用ServletRequestWrapper的方法,而ServletRequestWrapper类中正好有一个ServletRequest属性,所以我们只需要重写HttpServletRequestWrapper中的getParameter(name)和getParameterValues(name)即可。

妈的,说了一堆废话直接上代码:

package com.example.demo;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class RequestWrapper extends HttpServletRequestWrapper {
//注意这里我们要创建一个map,让后续getParameter和getParameterValues方法直接从map中获取即可
private Hash
4000
Map<String, String> parameter;

public RequestWrapper(HttpServletRequest request, HashMap<String, String> parameters) {
super(request);
parameter = new HashMap<String, String>();
for(Map.Entry<String, String> entry : parameters.entrySet()) {
parameter.put(entry.getKey(), entry.getValue());
}
}

@Override
public String getParameter(String name) {
return parameter.get(name);
}

@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public Map getParameterMap() {
return parameter;
}

@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Enumeration getParameterNames() {
return new Vector(parameter.keySet()).elements();
}

@Override
public String[] getParameterValues(String name) {
String[] result = null;
Object v = parameter.get(name);
if (v == null) {
result =  null;
} else if (v instanceof String[]) {
result =  (String[]) v;
} else if (v instanceof String) {
result =  new String[] { (String) v };
} else {
result =  new String[] { v.toString() };
}
return result;
}

}


上面代码中有几个刚才没有说过的代码,当我们在controller中调用request的什么方法,在RequestWrapper 中就要重写这个方法。

———————————————————————————

filter中的方法连同修改response一起搞出来[b]*********[/b]

我擦现在项目又有需求了,要将controller中返回的明文数据进行加密(我们总不能封装一个加密方法之后再所有的接口上都加上加密方法在输出吧,这样太虎了,冗余还显得不高端,不利于后续维护),所以我的想法是在filter中将返回的response进行拦截。于是顺着上面的例子我找到了

HttpServletResponseWrapper extends ServletResponseWrapper implements HttpServletResponse
extends ServletResponse
ServletResponseWrapper implements ServletResponse


发现一个问题我们在使用response的时候可以有两种方式进行输出

httpServletResponse.getOutputStream().write("".getBytes());
httpServletResponse.getWriter().write("");


然而在我们在controller层直接返回对象的时候,实际上调用的是ServletResponse.getOutputStream().write(int b)方法;

所以我们只需要继承HttpServletResponseWrapper重写HttpServletResponseWrapper中个getOutputStream方法(因为返回的是ServletOutputStream是一个抽象类没有实现write(int b)方法所以要创建一个类来实现此方法),墨迹这么多代码如下:

package com.example.demo;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class ResponseWrapper extends HttpServletResponseWrapper{

private ByteArrayOutputStream buffer = null;
private ServletOutputStream out = null;

public ResponseWrapper(HttpServletResponse resp) throws IOException {
super(resp);
buffer = new ByteArrayOutputStream();
out = new WapperedOutputStream(buffer);
}

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

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

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

/** 将out、writer中的数据强制输出到WapperedResponse的buffer里面,否则取不到数据 */
public String getResponseContent() throws IOException {
flushBuffer();
return new String(buffer.toByteArray(), this.getCharacterEncoding());
}

/** 内部类,对ServletOutputStream进行包装 */
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 boolean isReady() {
return false;
}

@Override
public void setWriteListener(WriteListener listener) {

}
}
}


值得注意的是如下:

1。因为我们重写了write(int b)方法所以我们要指定一个字节数组的输出流往其内部进行书写

2。要有一个获取字节数字的方法(方法前一定要flush防止数据缺失)

现在要写filter方法

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest)request;
HttpServletResponse httpServletResponse = (HttpServletResponse)response;
RequestWrapper requestWrapper = new RequestWrapper(httpServletRequest, bodyParameters);
ResponseWrapper responseWrapper = new ResponseWrapper(httpServletResponse);
chain.doFilter(requestWrapper, responseWrapper);
String responseContent= responseWrapper.getResponseContent();
//response.setContentLength(-1);
PrintWriter out = response.getWriter();
String string = "原內容:" + responseContent + "加密后的内容" + "1234567890asdfghjkl";
out.write(string);
out.flush();
out.close();
}


当我们完成了这次操作的时候会发现一个问题,比如说我们在controlle返回的是”123456789”(UTF-8)

我们在out.write(“我爱你亲爱的姑娘”);的时候会发现前台只返回了”我爱你”;

这里注意response.setContentLength(-1);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: