Filter高级应用:
Decorator模式
1)包装类需要和被包装对象 实现相同接口,或者继承相同父类
2)包装类需要持有 被包装对象的引用
在包装类中定义成员变量,通过包装类构造方法,传入被包装对象
3)在包装类中,可以控制原来那些方法需要加强
不需要加强 ,调用被包装对象的方法
需要加强,编写增强代码逻辑
ServletRequestWrapper 和 HttpServletRequestWrapper
提供对request对象进行包装的方法,但是默认情况下每个方法都是调用原来request对象的方法,
也就是说包装类并没有对request进行增强
如果要增强就可以在这两个包装类基础上,继承HttpServletRequestWrapper 和 HttpServletRequestWrapper 覆盖需要增强的方法即可
6.完全解决get和post乱码的过滤器
在Filter中,对request对象进行包装,增强获得参数的方法
getParameter
getParameterValues
getParameterMap
参考代码:
public class GenericEncodingFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 转型为与协议相关对象
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
// 对request包装增强
HttpServletRequest myrequest = new MyRequest(httpServletRequest);
chain.doFilter(myrequest, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
// 自定义request对象
class MyRequest extends HttpServletRequestWrapper { private HttpServletRequest request; private boolean hasEncode; public MyRequest(HttpServletRequest request) {
super(request);// super必须写
this.request = request;
}
// 对需要增强方法 进行覆盖
@Override
public Map getParameterMap() {
// 先获得请求方式
String method = request.getMethod();
if (method.equalsIgnoreCase("post")) {
// post请求
try {
// 处理post乱码
request.setCharacterEncoding("utf-8");
return request.getParameterMap();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} else if (method.equalsIgnoreCase("get")) {
// get请求
Map<String, String[]> parameterMap = request.getParameterMap();
if (!hasEncode) { // 确保get手动编码逻辑只运行一次
for (String parameterName : parameterMap.keySet()) {
String[] values = parameterMap.get(parameterName);
if (values != null) {
for (int i = 0; i < values.length; i++) {
try {
// 处理get乱码
values[i] = new String(values[i]
.getBytes("ISO-8859-1"), "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
}
hasEncode = true;
}
return parameterMap;
}
return super.getParameterMap();
}
@Override
public String getParameter(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
if (values == null) {
return null;
}
return values[0]; // 取回参数的第一个值
}
@Override
public String[] getParameterValues(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
return values;
}
}
增强Response对象,对响应数据进行压缩
先说一下在Tomcat服务器内,提供对响应压缩 配置实现
在conf/server.xml 中
<Connector port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"/> 添加 compressableMimeType="text/html,text/xml,text/plain" compression="on"
public class GzipFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 自定义缓冲区,重写response的getWriter和getOutputStream
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
// 字节缓存区
// 将数据写入内存数组中
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
HttpServletResponse myresponse = new HttpServletResponseWrapper(
httpServletResponse) {
private PrintWriter out;
@Override
// 重写getWriter 流获得是对 getOutputStream 编码获得
public PrintWriter getWriter() throws IOException {
System.out.println("getWriter...");
if (out == null) {
// 确保PrintWriter只有一个对象,flushbuffer中输出缓冲区内容
out = new PrintWriter(new OutputStreamWriter(
byteArrayOutputStream, getCharacterEncoding()));
}
return out;
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
System.out.println("getOutputStream...");
return new ServletOutputStream() {
@Override
// 将数据写到哪
public void write(int b) throws IOException {
// 将响应数据 写入自定义缓存区
byteArrayOutputStream.write(b);
}
};
}
@Override
public void flushBuffer() throws IOException {
getOutputStream().flush();
getWriter().flush();
}
};
// 目标资源执行,只有目标资源执行后,才有响应数据
chain.doFilter(request, myresponse);
myresponse.flushBuffer();
// 目标资源已经执行过,数据已经在 byteArrayOutputStream 缓存区
byte[] data = byteArrayOutputStream.toByteArray(); // data是未压缩数据
System.out.println("未压缩数据长度:" + data.length);
// 读data数据进行压缩
byte[] gzipData = gzip(data);// gzipData是压缩后数据
System.out.println("压缩后数据长度:" + gzipData.length);
// 原来response 目的地是客户端浏览器
httpServletResponse.setHeader("Content-Encoding", "gzip");
httpServletResponse.setContentLength(gzipData.length);
httpServletResponse.getOutputStream().write(gzipData);
httpServletResponse.getOutputStream().flush();
}
// 对data数据进行gzip压缩
public byte[] gzip(byte[] data) {
// 定义字节缓存区,用gzip方式向缓存区写数据
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
try {
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(
arrayOutputStream);
gzipOutputStream.write(data);// 将原数据 压缩gzip格式写入新的缓存区\
gzipOutputStream.close();
arrayOutputStream.flush();
return arrayOutputStream.toByteArray();// 返回压缩后的内容
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("压缩失败!");
}
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
天下代码一般仿写:http://blog.csdn.net/javadaddy/article/details/8142559