@liayun
        
        2016-09-20T09:31:31.000000Z
        字数 5771
        阅读 1903
    java基础加强
在动态代理技术里,由于不管用户调用代理对象的什么方法,都是调用开发人员编写的处理器的invoke方法(这相当于invoke方法拦截到了代理对象的方法调用),并且开发人员通过invoke方法的参数,还可以在拦截的同时,知道用户调用的是什么方法,因此利用这两个特性,就可以实现一些特殊需求,例如:拦截用户的访问请求,以检查用户是否有访问权限、动态为某个对象添加额外的功能。
还记得我们以前在学习过滤器的高级开发时,使用Decorator模式包装request对象解决get和post请求方式下的中文乱码问题吗?要是忘记了,可以参见我的笔记Filter高级开发(一)——使用Decorator模式包装request对象解决get和post请求方式下的中文乱码问题。现在我们学习了动态代理技术,就可以利用其来将解决同样的问题了。 
我们首先利用动态代理技术编写一个用于处理全站中文乱码的过滤器CharacterEncodingFilter,代码如下:
public class CharacterEncodingFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// TODO Auto-generated method stub}@Overridepublic void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)throws IOException, ServletException {final HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) resp;request.setCharacterEncoding("UTF-8"); // 解决post方式请求下的中文乱码问题 get:request.getParameter()// servlet-----> requestRroxy.getCookie()chain.doFilter((ServletRequest) Proxy.newProxyInstance(CharacterEncodingFilter.class.getClassLoader(), request.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {/** 判断在Servlet那端调用的是不是getParameter方法,* 如不是则不需要拦截,直接放行,直接调用tomcat的request(真的request)帮你把事情干了,* 并且args参数还要接着往下传*/if (!method.getName().equals("getParameter")) {return method.invoke(request, args); // 由于是内部类,所以request需要声明为final(但在Java8中没这个必要了)}// 判断客户端的请求方式是不是getif (!request.getMethod().equalsIgnoreCase("get")) {return method.invoke(request, args);}String value = (String) method.invoke(request, args);if (value == null) {return null;}// return new String(value.getBytes("ISO8859-1"), "UTF-8");return new String(value.getBytes("UTF-8"), "UTF-8");}}), response);}@Overridepublic void destroy() {// TODO Auto-generated method stub}}
在web.xml文件中配置CharacterEncodingFilter。
<filter><filter-name>CharacterEncodingFilter</filter-name><filter-class>cn.itcast.web.filter.CharacterEncodingFilter</filter-class></filter><filter-mapping><filter-name>CharacterEncodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>
编写jsp测试页面,如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>使用动态代理技术包装request对象解决get和post请求方式下的中文乱码问题</title></head><body><form action="/day24_proxy/ServletDemo1" method="get"><input type="text" name="username"><input type="submit" value="提交"></form></body></html>
编写处理用户请求的ServletDemo1。
public class ServletDemo1 extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {String username = request.getParameter("username");System.out.println(username);}protected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
测试,这时在form.jsp表单中输入李阿昀玲这样的字符串,在Eclipse的控制台中不会显示为乱码:????,而是正常显示
李阿昀玲
还记得我们以前在学习过滤器的高级开发时,使用Decorator设计模式增强response对象的案例——压缩响应正文内容吗?若是没学过,可参见我的笔记Filter高级开发(三)——压缩响应正文内容。现在我们学习了动态代理技术,就可以利用其来将解决同样的问题了。 
我们首先利用动态代理技术编写这样一个用于响应正文内容的过滤器GzipFilter,代码如下:
public class GzipFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// TODO Auto-generated method stub}@Overridepublic void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)throws IOException, ServletException {final HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) resp;ResponseProxy proxy = new ResponseProxy(response);chain.doFilter(request, proxy.createProxy()); // ResponseProxy.getXxx()...byte[] out = proxy.getBuffer(); // 得到目标资源的输出System.out.println(new String(out, "UTF-8"));}// 内部类class ResponseProxy {private ByteArrayOutputStream bout = new ByteArrayOutputStream();private PrintWriter pw = null;private HttpServletResponse response;public ResponseProxy(HttpServletResponse response) {this.response = response;}public byte[] getBuffer() {if (pw != null) {pw.close();}return bout.toByteArray();}public HttpServletResponse createProxy() {return (HttpServletResponse) Proxy.newProxyInstance(GzipFilter.class.getClassLoader(), response.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (!method.getName().equals("getWriter") && !method.getName().equals("getOutputStream")) {method.invoke(response, args);}if (method.getName().equals("getWriter")) { // PrintWriterpw = new PrintWriter(new OutputStreamWriter(bout, "UTF-8"));return pw;}if (method.getName().equals("getOutputStream")) { // ServletOutputStreamreturn new ServletOutputStream() {@Overridepublic void write(int b) throws IOException {bout.write(b);}@Overridepublic void setWriteListener(WriteListener listener) {// TODO Auto-generated method stub}@Overridepublic boolean isReady() {// TODO Auto-generated method stubreturn false;}};}return null;}});}}@Overridepublic void destroy() {// TODO Auto-generated method stub}}
我并不打算详讲这样的一个压缩过滤器是如何编写出来的,因为在我的笔记Filter高级开发(三)——压缩响应正文内容中就已经详细地介绍过了。注意:我们并没有真正地进行压缩,只是得到目标资源的输出之后,将其打印在Eclipse的控制台上。 
接着在web.xml中配置压缩过滤器。
<filter><filter-name>GzipFilter</filter-name><filter-class>cn.itcast.web.filter.GzipFilter</filter-class></filter><filter-mapping><filter-name>GzipFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>
最后进行测试,编写一个Servlet——ServletDemo2.java,其代码为:
public class ServletDemo2 extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.getWriter().write("我爱你,李阿昀");}protected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
这样当通过浏览器去访问该Servlet时,Eclipse的控制台打印:
我爱你,李阿昀