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

Wesley13
• 阅读 368

动态代理解决编码问题

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);
    }
}
点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
JS 苹果手机日期显示NaN问题
问题描述newDate("2019122910:30:00")在IOS下显示为NaN原因分析带的日期IOS下存在兼容问题解决方法字符串替换letdateStr"2019122910:30:00";datedateStr.repl
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
2年前
00_设计模式之语言选择
设计模式之语言选择设计模式简介背景设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。设计模式(Designpattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这