• JavaWeb之动态代理解决request请求编码问题


    动态代理解决编码问题

    1.设计模式

    出现原因:软件开发过程中,遇到相似问题,将问题的解决方法抽取模型(套路)

    常见设计模式:单例,工厂,适配器,装饰者,动态代理。

    2.装饰者模式简单介绍

    谷歌汽车开发场景

    1.Java定义了汽车开发约定

    interface ICar{start , run , stop}
    calss GooleCar implements ICar{}
    

    2.目的:将谷歌Car接入导生态平台时,增强汽车功能

    3.问题:谷歌Car的代码无法获取,且无法继承,不能直接操作其源码

    装饰者模式

    场景:在二次开发时,无法获取源码,且不能被继承的情况下,对以存在对象上的功能进行增强。

    前提:可以获取被装饰的对象的所有实现接口

    实现思路:自定义对象继承被装饰对象的接口,为自定义装饰类传递被装饰的对象

    装饰者模式的弊端

    如果被实现的接口中方法过的,则其所有方法都要被重写,装饰类会显得冗杂。

    3.动态代理

    解决装饰者模式的弊端

    a.原理

    通过虚拟机在内存创建类似MyCar.Class文件

    要创建MyCar.Class文件来告诉虚拟机:

    ​ 1.被创建的字节码文件上需要哪些方法

    字节码加载器

    jdk有一些程序专业将各种字节码文件加载到内存,这类程序称为字节码加载器

    如何将字节码文件class文件加载到内存?

    底层提供IO技术,获取文件中的数据加载到内存。

    字节码加载器有3种

    public class TestClassLoader {
    	public static void main(String[] args) {
    		
    		//获取String类的加载器
    		ClassLoader classLoader = String.class.getClassLoader();
    		System.out.println(classLoader);
    		//由于String.class ,int.class等字节码文件需要频繁的被加载内存,速度必须快,底层用其他语言来实现c c++
    		
    		//获取ext(extendtion)包下的某个类的字节码加载器   ExtClassLoader:扩展类加载器
    		ClassLoader classLoader2 = sun.net.spi.nameservice.dns.DNSNameService.class.getClassLoader();
    		System.out.println(classLoader2);
    	
    		//应用类:程序员实现的所有的类都属于应用类
    		//获取应用类加载器 AppClassLoader
    		ClassLoader classLoader3 = TestClassLoader.class.getClassLoader();
    		System.out.println(classLoader3);
    	}
    }
    

    动态代理简单案例

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.util.Arrays;
    
    public class TestCar {
    	public static void main(String[] args) {
    		
    		//1param: 固定值: 告诉虚拟机用哪个字节码加载器加载内存中创建出的字节码文件
    		//2param: 告诉虚拟机内存中正在被创建的字节码文件中应该有哪些方法
    		//3param: 告诉虚拟机正在被创建的字节码上的各个方法如何处理
    		ICar car=(ICar)Proxy.newProxyInstance(TestCar.class.getClassLoader(), GoogleCar.class.getInterfaces(),new InvocationHandler() {
    			
    			//method:代表正在执行的方法
    			//args:代表正在执行的方法中的参数
    			//Object:代表方法执行完毕之后的返回值
    			@Override
    			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    				//经过测试得知:method代表当前正在执行的每个方法
    				//System.out.println(method.getName());
    				//执行当前的方法
    				//method.invoke(new GoogleCar(), args);
    				
    				//代表每个方法执行完毕之后返回对象
    				Object obj=null;
    				
    				if(method.getName().equalsIgnoreCase("start")){
    					System.out.println("检查天气是否良好");
    
    					//打印args中的内容
    					System.out.println(Arrays.toString(args));
    					
    					obj=method.invoke(new GoogleCar(), args);
    					System.out.println("检查路况是否拥堵");
    					
    				}else{
    					obj=method.invoke(new GoogleCar(), args);	
    				}
    				return obj;
    			}
    		});
    		String cc=car.start(1,4);
    		System.out.println(cc);
    		car.run();
    		car.stop();
    	}
    }
    
    class MyCC implements InvocationHandler{
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		return null;
    	}
    }
    

    动态代理解决servlet的get请求的中文编码问题

    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;
    
    public class EncodingFilter implements Filter {
    
        public EncodingFilter() {
        }
    
    	public void destroy() {
    	}
    	public void init(FilterConfig fConfig) throws ServletException {
    	}
    	
    	
    	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    		//将request对象转换为HttpServletRequest
    		final HttpServletRequest req=(HttpServletRequest)request;
    		//让JDK在内存中生成代理对象:增强了req对象上的getParameter(name);API
    		HttpServletRequest myReq=(HttpServletRequest)Proxy.newProxyInstance(EncodingFilter.class.getClassLoader(), req.getClass().getInterfaces(), new InvocationHandler() {
    			
    			@Override
    			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    				
    				Object obj=null;
    				
    				if(method.getName().equalsIgnoreCase("getParameter")){
    					//获取本次请求方式
    					String md=req.getMethod();
    					if("get".equalsIgnoreCase(md)){
    						//get方式的请求
    						//调用req对象上的getParameter方法
    						String v=(String)method.invoke(req, args);
    						//转码
    						String vv=new String(v.getBytes("iso-8859-1"),"utf-8");
    						return vv;
    						
    					}else{
    						//post方式的请求
    						req.setCharacterEncoding("utf-8");
    						obj=method.invoke(req, args);
    					}
    					
    					
    				}else{
    					obj=method.invoke(req, args);
    				}
    				return obj;
    			}
    		});
    		//打印代理对象哈希码
    		System.out.println(myReq.hashCode());
    		//将代理对象放行
    		chain.doFilter(myReq, response);
    	}
    }
    
  • 相关阅读:
    希尔排序
    插入排序
    Unity创建一个简易的弹簧(弹动)效果
    看到个美到爆的菜单,忍不住扒下来~
    用avalon实现一个完整的todomvc(带router)
    页面动态加入<script>标签并执行代码
    一个简单粗暴的前后端分离方案
    常用的HTML5、CSS3新特性能力检测写法
    犀利的background-clip:text,实现K歌字幕效果
    用canvas开发H5游戏小记
  • 原文地址:https://www.cnblogs.com/wf614/p/11673835.html
Copyright © 2020-2023  润新知