之前写过一篇关于过滤器实现加密解密功能的文章,但是在实际开发业务中发现,还是有一些问题的,在此特地说明。
第一:过滤器走两遍的问题:
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
}
}
修改之后,加密的结果和响应的结果一致。
说明:这是个大坑呀,刚开始没有发现这个问题,返回的是加密的字符串就认为是对的,但是客户端就是解析不了。我才知道,加密的结果和最终响应的结果不一样,特此记录。