包装request,把header中的token取出来,写入body中,controller用@RequestBody注解解析成pojo,token可以自动注入值到入参类中
继承HttpServletRequestWrapper
public class RequestWrapper extends HttpServletRequestWrapper {
/**
* getInputStream使用,构造器写入
*/
private byte[] byteArray;
/**
* request.getParameter()使用
*/
private Map<String , String[]> paramMap = new HashMap<>();
private Map<String , String> headerMap = new HashMap<>();
public RequestWrapper(HttpServletRequest request) {
super(request);
paramMap.putAll(request.getParameterMap());
}
/**
* 获取原body中的内容JSONObject,并且把header中的值取出来放入,写入内存字节流,并且把值存入map中,读取单个参数值时用到
* @param request
* @param newParams
*/
public RequestWrapper(HttpServletRequest request, JSONObject newParams) {
super(request);
byteArray = newParams.toString().getBytes(Charset.forName("UTF-8"));
//v.toString()会产生npe
newParams.forEach((k, v) -> paramMap.put(k, new String[]{v + ""}));
putHeader("Content-length", byteArray.length + "");
}
/**
* 重写输入流,从内存字节流中读取
* @return
* @throws IOException
*/
@Override
public ServletInputStream getInputStream() throws IOException {
ByteArrayInputStream bais = new ByteArrayInputStream(byteArray);
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
@Override
public int read() throws IOException {
//return 0;//死循环,必须重写
return bais.read();
}
};
}
/**
* 重写读取单个参数方法,从新的map中读取
* @param name
* @return
*/
@Override
public String getParameter(String name) {
String[] array = paramMap.get(name);
return array[0];
}
@Override
public String[] getParameterValues(String name) {//同上
return paramMap.get(name);
}
@Override
public Map<String, String[]> getParameterMap() {
return paramMap;
}
private void addAllParameters(Map<String, Object> extendParams) {
for(Map.Entry<String , Object> entry : extendParams.entrySet()) {
paramMap.put(entry.getKey() , new String[] {entry.getValue() + ""});
}
}
public void putHeader(String name, String value) {
this.headerMap.put(name, value);
}
@Override
public String getHeader(String name) {
// check the custom headers first
String headerValue = headerMap.get(name);
if (headerValue != null) {
return headerValue;
}
// else return from into the original wrapped object
return ((HttpServletRequest) getRequest()).getHeader(name);
}
@Override
public Enumeration<String> getHeaderNames() {
// create a set of the custom header names
Set<String> set = new HashSet<>(headerMap.keySet());
// now add the headers from the wrapped request object
Enumeration<String> e = ((HttpServletRequest) getRequest()).getHeaderNames();
while (e.hasMoreElements()) {
// add the names of the request headers into the list
String n = e.nextElement();
set.add(n);
}
// create an enumeration from the set and return
return Collections.enumeration(set);
}
@Override
public int getContentLength() {
return byteArray.length;
}
@Override
public long getContentLengthLong() {
return byteArray.length;
}
}
包装response,因为获取输出流只能一次,当有两个filter时,后面的filter就拿不到返回内容了
tomcat源码
public class Response implements HttpServletResponse {
/**
* Using output stream flag.
*/
protected boolean usingOutputStream = false;
/**
* Using writer flag.
*/
protected boolean usingWriter = false;
/**
* @return the servlet output stream associated with this Response.
*
* @exception IllegalStateException if <code>getWriter</code> has
* already been called for this response
* @exception IOException if an input/output error occurs
*/
@Override
public ServletOutputStream getOutputStream()
throws IOException {
if (usingWriter) {
throw new IllegalStateException
(sm.getString("coyoteResponse.getOutputStream.ise"));
}
usingOutputStream = true;
if (outputStream == null) {
outputStream = new CoyoteOutputStream(outputBuffer);
}
return outputStream;
}
/**
* @return the writer associated with this Response.
*
* @exception IllegalStateException if <code>getOutputStream</code> has
* already been called for this response
* @exception IOException if an input/output error occurs
*/
@Override
public PrintWriter getWriter()
throws IOException {
if (usingOutputStream) {
throw new IllegalStateException
(sm.getString("coyoteResponse.getWriter.ise"));
}
if (ENFORCE_ENCODING_IN_GET_WRITER) {
/*
* If the response's character encoding has not been specified as
* described in <code>getCharacterEncoding</code> (i.e., the method
* just returns the default value <code>ISO-8859-1</code>),
* <code>getWriter</code> updates it to <code>ISO-8859-1</code>
* (with the effect that a subsequent call to getContentType() will
* include a charset=ISO-8859-1 component which will also be
* reflected in the Content-Type response header, thereby satisfying
* the Servlet spec requirement that containers must communicate the
* character encoding used for the servlet response's writer to the
* client).
*/
setCharacterEncoding(getCharacterEncoding());
}
usingWriter = true;
outputBuffer.checkConverter();
if (writer == null) {
writer = new CoyoteWriter(outputBuffer);
}
return writer;
}
}
可以看出,Writer和OutPutStream总共只能获取一次,获取一个,其他就不能拿了
继承HttpServletResponseWrapper,
public class ResponseWrapper extends HttpServletResponseWrapper {
private ServletOutputStream outputStream = null;
private ByteArrayOutputStream baos = null;
public ResponseWrapper(HttpServletResponse response) {
super(response);
response.setCharacterEncoding("utf-8");
response.setContentType("application/json; charset=utf-8");
baos = new ByteArrayOutputStream();
try {
outputStream = response.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
public void responseMessage(String result) {
try {
PrintWriter out = getWriterForResponse();
out.print(result);
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
if (outputStream == null) {
outputStream = new ServletOutputStream() {
@Override
public boolean isReady() {
return false;
}
@Override
public void setWriteListener(WriteListener listener) {
}
@Override
public void write(int b) throws IOException {
baos.write(b);
}
};
}
return outputStream;
}
@Override
public PrintWriter getWriter() throws IOException {
return new PrintWriter(new OutputStream() {
@Override
public void write(int b) throws IOException {
baos.write(b);
}
});
}
public PrintWriter getWriterForResponse() throws IOException {
return new PrintWriter(new OutputStream() {
@Override
public void write(int b) throws IOException {
outputStream.write(b);
}
});
}
public void closeWriter(Writer writer) {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public String getResponseContent() {
return new String(baos.toByteArray());
}
}
使用
TokenFilter
@Component
public class TokenFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) servletResponse);
String errorMsg = "";
try {
HttpServletRequest request = (HttpServletRequest) servletRequest;
String token = request.getHeader("token");
if (!StringUtils.hasText(token)) {
errorMsg = "令牌缺失";
return;
}
String bodyString = HttpUtil.getBodyString(request);
JSONObject jo = JSONObject.parseObject(bodyString);
jo.put("token", token);
RequestWrapper requestWrapper = new RequestWrapper(request, jo);
filterChain.doFilter(requestWrapper, responseWrapper);
} finally {
if (!StringUtils.isEmpty(errorMsg)) {
responseWrapper.responseMessage(errorMsg);
}
}
}
@Override
public void destroy() {
}
}
SignFilter
@Component
public class SignFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) servletResponse);
String errorMsg = "";
try {
HttpServletRequest request = (HttpServletRequest) servletRequest;
String sign = request.getHeader("sign");
if (!StringUtils.hasText(sign)) {
errorMsg = "签名缺失";
return;
}
String bodyString = HttpUtil.getBodyString(request);
JSONObject jo = JSONObject.parseObject(bodyString);
jo.put("sign", sign);
RequestWrapper requestWrapper = new RequestWrapper(request, jo);
filterChain.doFilter(requestWrapper, responseWrapper);
} finally {
if (!StringUtils.isEmpty(errorMsg)) {
responseWrapper.responseMessage(errorMsg);
}
}
}
@Override
public void destroy() {
}
}
测试
@RestController
@RequestMapping("user")
public class UserController {
//http://localhost:8080/user/list
@RequestMapping("list")
public Object listUser(@RequestBody UserQuery query, HttpServletRequest request) {
System.out.println(request.getParameter("token"));
return "ok";
}
}
参考项目https://github.com/mingwulipo/web-demo