装饰模式-包装request和response

包装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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值