(这是我的第五次反馈)
本次所上的内容是:
1.用动态代理技术解决全站乱码问题
2.用动态代理技术解决压缩输出问题
1.1用动态代理技术解决全站乱码问题思路
在这里我们用到了JavaWeb中的Filter技术
在以前我们在Filter中放行的时候所传的对象是HttpServletRequest和HttpServletResponse,通过这两个对象直接设置编码会解决全站的post请求的乱码
而单单靠这两个原始对象不能解决get请求的乱码
通过动态代理技术我们可以产生一个request的代理对象,通过这个代理对象中的方法可以对getParameter方法进行拦截
然后再将得到的数据进行手动转换
最后放行,解决全站乱码问题
核心代码如下:
package filter;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CharacterEncodingFilter implements Filter{
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
//解决了post请求下的乱码问题
final HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;character=UTF-8");
//在Filter放行之前我们要对request包装一把来对get请求拦截处理
chain.doFilter((ServletRequest) Proxy.newProxyInstance(CharacterEncodingFilter.class.getClassLoader(),request.getClass().getInterfaces(),new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if(!method.getName().equals("getParameter")){
return method.invoke(request, args);
}
if(!request.getMethod().equalsIgnoreCase("get")){
return method.invoke(request, args);
}
//到了这里肯定就是get方法所带过来的数据
String value = (String) method.invoke(request, args);//手动转换
if(value == null){
return null;
}
return new String(value.getBytes("iso8859-1"),"UTF-8");
}
}), response);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
@Override
public void destroy() {
}
}
2.1解决压缩输出问题的思路
首先我们要压缩的数据是来自于服务器端的
servlet会通过response给客户机输出数据
而重点就是response会直接给客户机输出数据不会压缩之后输出数据
在此我们又用到了Filter(拦截器)对输出的数据进行拦截然后压缩打给客户机以减少流量
具体来说response输出数据的方式有两种 getWriter和getOutPutStream
其中getOutPutStream得到的对象自己没有带缓冲流所以我们先要new一个缓冲流对象
然后重写它的write方法,让数据写到我们所new的缓冲流对象中然后压缩输出给客户机
然后getWriter得到的对象自己带有缓冲流
所以我们用OutputStreamWriter作为桥梁来将数据写到我们自己的缓冲流中
最后一并压缩输出
具体的思路见代码
package filter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.zip.GZIPOutputStream;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
public class GzipFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) req;
final HttpServletResponse response = (HttpServletResponse) res;
final ByteArrayOutputStream bout = new ByteArrayOutputStream();
final PrintWriter pw = new PrintWriter(new OutputStreamWriter(bout,"UTF-8"));
chain.doFilter(request, (ServletResponse) Proxy.newProxyInstance(GzipFilter.class.getClassLoader(),response.getClass().getInterfaces(),new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if(method.getName().equalsIgnoreCase("getWriter")){
return pw;
}else if(method.getName().equalsIgnoreCase("getOutPutStream")){
//返回我们的自定义流
return new MyOutputStream(bout);
}else{
return null;
}
}
}));
pw.close();//让pw的数据释放确保都到了bout里面
byte[] result = bout.toByteArray();//让流中的数据还原到一个比特数组中准备压缩输出
System.out.println("原始大小:"+result.length);
ByteArrayOutputStream bout2 = new ByteArrayOutputStream();//它是存储压缩后的数据的
GZIPOutputStream gzip = new GZIPOutputStream(bout2);//写到Bout的缓存里面
gzip.write(result);//这就是那个压缩过程
gzip.close();//保证写到了bout2里面
result = bout2.toByteArray();//bout2还原数据
System.out.println("压缩后的数据大小:"+result.length);
response.setHeader("content-encoding","gzip");
response.setContentLength(result.length);
response.getOutputStream().write(result);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
class MyOutputStream extends ServletOutputStream{
private ByteArrayOutputStream bout = new ByteArrayOutputStream();
public MyOutputStream(ByteArrayOutputStream bout) {
this.bout = bout;
}
@Override
public void write(int b) throws IOException {
bout.write(b);//把数据写到这个字节数组中
}
}
在此特别感谢方立勋老师!