之前写过一篇关于过滤器实现加密解密功能的文章,但是在实际开发业务中发现,还是有一些问题的,在此特地说明。

第一:过滤器走两遍的问题:

1.过滤器上,添加了两个注解

第一个:@Compent   将此Filter交给Spring容器管理

第二个:@WebFilter通过WebFilter进行Filter声明,这样容器在进行部署的时候就会处理该Filter

2.启动类上添加的注解

@ServletComponentScan  作用:Servlet、Filter、Listener 可以直接通过 @WebServlet、@WebFilter、@WebListener 注解自动注册(自动扫描带有过滤器注解的包)

3.问题:项目启动后,一个请求执行两次

原因:@Compent 启动时,会加载Filter.  @ServletComponentScan 也会扫描过滤器。所以会加载两次

4.解决措施:

去掉过滤器上的@Compent 注解之后,请求过滤一次。

第二:响应结果跟加密结果不一致的问题

1.之前使用的包装类,不知道为何,加密的结果和最终响应的结果不一致,并且是有规律的少。

各位大神,如果知道为什么的话,麻烦指点一下。

 

2.解决办法:直接换了一个包装类,代码如下:

包装类代码:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;

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

/**
 * reponse包装类,对reponse响应进行处理后,传给客户端
 * @Author: kiki
 * @Date: 2018/12/18
 */
public class WrapperedResponse extends HttpServletResponseWrapper {
    private ByteArrayOutputStream buffer = null;
    private ServletOutputStream out = null;
    private PrintWriter writer = null;

    public WrapperedResponse(HttpServletResponse resp) throws IOException {
        super(resp);
        buffer = new ByteArrayOutputStream();//真正存储数据的流
        out = new WrapperedResponse.WapperedOutputStream(buffer);
        writer = new PrintWriter(new OutputStreamWriter(buffer, this.getCharacterEncoding()));
    }

    //重载父类获取outputstream的方法
    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return out;
    }

    //重载父类获取writer的方法
    @Override
    public PrintWriter getWriter() throws UnsupportedEncodingException {
        return writer;
    }

    //重载父类获取flushBuffer的方法
    @Override
    public void flushBuffer() throws IOException {
        if (out != null) {
            out.flush();
        }
        if (writer != null) {
            writer.flush();
        }
    }

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

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

    //内部类,对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 boolean isReady() {
            return false;
        }

        @Override
        public void setWriteListener(WriteListener listener) {

        }
    }
}

 过滤器代码:

/**
 * 过滤器拦截请求,实现加密解密功能
 * 
 * @Component 将此Filter交给Spring容器管理
 * @WebFilter 通过WebFilter进行Filter声明,这样容器在进行部署的时候就会处理该Filter
 *
 * @author kiki
 */
@WebFilter(urlPatterns = "/HMService/*", filterName = "dataFilter")
public class DataFilter implements Filter {

    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
            
            //解密请求
        
            //使用包装类 对request/response进行修改和响应
            WrapperedRequest wrapRequest = new WrapperedRequest((HttpServletRequest) request, requestBodyMw);
            WrapperedResponse wrapResponse = new WrapperedResponse((HttpServletResponse) response);
            chain.doFilter(wrapRequest, wrapResponse);
            String content = wrapResponse.getContent();
            String responseBodyMw = DES3Util.encodeCBC(content);
            logger.info("【加密返回数据为】 responseBodyMw = {}", responseBodyMw);
            response.setContentLength(-1);
                PrintWriter out = response.getWriter();
                System.out.println(responseString.length());
                out.write(responseBodyMw);
                out.flush();
                out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
    }

}

 

修改之后,加密的结果和响应的结果一致。

 

说明:这是个大坑呀,刚开始没有发现这个问题,返回的是加密的字符串就认为是对的,但是客户端就是解析不了。我才知道,加密的结果和最终响应的结果不一样,特此记录。