zoukankan      html  css  js  c++  java
  • day23 框架之基础加强

    day23 框架之基础加强

    今日任务

    aptana(javascript的eclipse插件):http://www.cnblogs.com/terrylin/archive/2012/06/20/2555962.html

    jquery技术,查询文档。

    • 今天的总思路:读取配置文件,反射获取类信息,创建对象,监控方法的执行

    SSH : struts2 spring hibernate

    SSM :springMVC spring Mybaties

    spring 核心:IOC——控制反转,创建对象,不再由着程序员,创建对象由spring管理

                     AOP——面向切面编程,面向整个功能(功能的实现,不止一个类)

    1. 反射技术
    2. 动态代理
    3. 注解技术

    注解技术:老程序员看不上,新程序员特别喜欢。

    使用配置文件:特别多,特别复杂(新程序员讨厌原因)

    注解:简单,方便,内容少。(新程序员特别喜欢) 注解的配置:都在类上或者方法上,代码维护代价高,注解性能问题(老程序员看不上)

    课堂笔记

    读取配置文件的三种方式

    第一种:String realPath = this.getServletContext().getRealPath("/upload");

    只能在web工程中使用。

    第二种:InputStream in = ClassLoader.getSystemResourceAsStream("peizhi.properties");

    使用类加载器读取配置文件的方法(类加载器:加载类的对象),任何工程都可以使用

    任何java工程都需要类加载器来,帮助我们加载类,运行,所以任何工程都可以使用类加载器加载配置文件。

    ClassLoader是什么:加载类的对象。

    第三种:ResourceBundle bundle = ResourceBundle.getBundle("peizhi");

    注意:专门用来读取properties文件

    演示读取配置文件的方式(第二种和第三种):

    准备接口和实现类:

    配置文件准备:

    思路:

    1. 定义接口
    2. 书写实现类
    3. 定义配置文件

       

    模拟框架开发:接口定义好的,如何知道程序员定义的实现类?

    配置文件——定义好了接口的实现类。

    通过读取配置文件,可以获取到实现类的全路径,通过反射获取实现类的对象

    第二种代码演示:

    /**

         * 测试使用类加载器,读取配置文件

         * @throws Exception

         */

        @Test

        public void test1() throws Exception{

            //获取输入流,读取配置文件

            InputStream in = ClassLoader.getSystemResourceAsStream("peizhi.properties");

            //InputStreamReader: 他的构造函数需要InputStream对象,将字节流转换成字符流

            BufferedReader reader = new BufferedReader(new InputStreamReader(in));

            

            String line = null;

            while((line = reader.readLine()) != null){

                System.out.println(line);

            }

        }

    效果:

    第三种代码演示:

    /**

         * 测试使用ResourceBundle,读取配置文件

         * @throws Exception

         */

        @Test

        public void test2() throws Exception{

            //创建对象,读取配置文件

            //ResourceBundle 专门读取properties文件

            ResourceBundle bundle = ResourceBundle.getBundle("peizhi");

            String value = bundle.getString("servlet");

            System.out.println(value);

        }

    效果:

    注意:任何配置文件,修改过后,都需要重新启动java虚拟机。

    原因:读取配置文件的动作只有一次。

    如果想要不重新启动java虚拟机,将数据保存在数据库,然后,从数据库获取数据,再进行操作——这样的数据,一般叫做系统变量。

    1、反射技术回顾

    1.1、Class回顾

    Class:相当于工厂在制作产品之前,先设计好的产品图纸。

    反射的作用:可以动态的创建某个类的对象,然后动态调用这个类中的成员(方法和属性)。

        

    1. 对象的getClass方法
    2. 类名.class
    3. Class类forName方法

    代码演示:

    /**

         * 演示获取Class对象的三种方式

         * @throws ClassNotFoundException

         */

        @Test

        public void test3() throws ClassNotFoundException {

            MyServlet myServlet = new MyServlet();

            System.out.println(myServlet.getClass());

            

            System.out.println(MyServlet.class);

            //clazz:这是一个源远流长的习惯

            //框架经常使用第三种方式

            Class clazz = Class.forName("cn.itcast.web.impl.MyServlet");

            System.out.println(clazz);

        }

    效果:

    1.2、反射类中的成员回顾

        第一步:反射类中的构造方法:

        通过构造方法,就可以创建类的对象

    Class:

    Constructor:

    /**

         * 演示获取对象的构造方法

         * @throws Exception

         */

        @Test

        public void test4() throws Exception{

            //读取配置文件

            ResourceBundle bundle = ResourceBundle.getBundle("peizhi");

            //获取类全名

            String className = bundle.getString("servlet");

            

            //获取类的构造方法

            Class<?> clazz = Class.forName(className);

            /*Constructor[] constructors = clazz.getConstructors();

            for (Constructor constructor : constructors) {

                System.out.println(constructor);

            }*/

            

            //获取指定的构造方法

            //parameterTypes:给的是构造函数的参数

            Constructor<?> constructor = clazz.getConstructor(null);

            System.out.println(constructor);

            

            Constructor<?> constructor2 = clazz.getConstructor(String.class,String.class);

            System.out.println(constructor2);

            

            //根据构造函数创建对象

            //initargs:构造函数使用需要的参数

            Object newInstance = constructor.newInstance(null);

            System.out.println(newInstance);

            

            Object newInstance2 = constructor2.newInstance("req","res");

            System.out.println(newInstance2);

        }

    效果:

        反射类中的成员变量:

    Class:

    /**

         * 演示获取成员变量(属性)

         *

         * @throws Exception

         */

        @Test

        public void test5() throws Exception {

            // 读取配置文件

            ResourceBundle bundle = ResourceBundle.getBundle("peizhi");

            // 获取类全名

            String className = bundle.getString("servlet");

            // 获取Class对象

            Class<?> clazz = Class.forName(className);

            

            Field[] declaredFields = clazz.getDeclaredFields();

            /*for (Field field : declaredFields) {

                System.out.println(field);

            }*/

            Field declaredField = clazz.getDeclaredField("request");

            System.out.println(declaredField);

        }

    效果:

        

        反射类中的成员方法:

    获取所有方法:

    /**

         * 演示获取类中的成员方法

         *

         * @throws Exception

         */

        @Test

        public void test6() throws Exception {

            // 读取配置文件

            ResourceBundle bundle = ResourceBundle.getBundle("peizhi");

            // 获取类全名

            String className = bundle.getString("servlet");

            // 获取Class对象

            Class<?> clazz = Class.forName(className);

            

            Method[] methods = clazz.getMethods();

            for (Method method : methods) {

                System.out.println(method);

            }

            

            System.out.println("================");

            Method method = clazz.getMethod("doGet", java.lang.String.class,java.lang.String.class);

            System.out.println(method);

            System.out.println("==============");

            //演示调用方法obj:调用方法的对象,args:方法的参数

            Object invoke = method.invoke(clazz.newInstance(), "haha","hehe");

            System.out.println(invoke);

        }

     

    效果:

    案例:模拟BeanUtils封装数据演示:

    思路:

    1. 需要一个封装数据的对象(Person)
    2. 需要一个封装数据的map集合(key值和Person的字段名称一致)
    3. 获取Person的Class对象,只有获取Class对象,才能获取到所有的字段(属性)
    4. 获取所有字段
    5. 循环所有字段和map集合,当key值和字段名称一致,就封装数据

    要使用的API:

    Class:

    Field:

    代码演示:

    测试类:

    /**

         * 演示模拟beanUtils封装数据

         *

         * @throws Exception

         */

        @Test

        public void test7() throws Exception {

            //第一步:创建要被封装数据的对象

            User u = new User();

            System.out.println(u);

            //String:用来保存属性的名称(对应User中的属性)

            //Object:要被封装的数据,任意类型

            Map<String, Object> map = new HashMap<String, Object>();

            map.put("name", "张三");

            map.put("age", 11);

            //封装数据,使用BeanUtils.populate(u, map);

            BeanUtils.populate(u, map);

            System.out.println(u);

        }

    工具类:

    package cn.itcast.utils;

     

    import java.lang.reflect.Field;

    import java.util.Map;

     

    public class BeanUtils {

     

        public static void populate(Object obj, Map<String, Object> map) {

            //第一步:通过Class对象来获取obj对象中的成员变量

            Class<?> clazz = obj.getClass();

            Field[] declaredFields = clazz.getDeclaredFields();

            //第二步:遍历循环所有的字段,将数据封装进去

            for (Field field : declaredFields) {

                for (String key : map.keySet()) {

                    //判断,当前的字段名称是否和map集合中key值,一致,一致,才能封装数据

                    if(key.equals(field.getName())){

                        //封装数据

                        //取消访问的检查

                        field.setAccessible(true);

                        try {

                            field.set(obj, map.get(key));

                        } catch (Exception e) {

                            e.printStackTrace();

                        }

                    }

                }

            }

        }

     

    }

    效果:

    2、动态代理

    2.1、动态代理介绍

    struts2 、 hibernate 底层使用的动态代理。

    Spring 在AOP当中,使用了大量的动态代理,JDK自带的接口代理(有接口才能代理),子类代理(cglib代理)

    动态代理:访问被代理的类,进行拦截,处理,处理完了,放行

    代理设计模式:

    注意:以上还只是代理设计模式,怎么变成动态代理?上面的故事,如果改成,看到姐姐之后,直接上帝创建了妹妹,就是动态代理。

    2.2、动态代理演示

    1、先获取创建代理对象的类,调用它的方法,创建出一个代理对象

    2、代理对象具体要做什么事情(代理策略),需要设置

    创建代理类的对象:

    创建代理对象的方法:

     

    代理策略对象:

    代理策略方法:

     

     

    需求和步骤(模拟框架读取配置文件,创建代理对象,并调用接口方法):

    1. 读取配置文件
    2. 获取类全名
    3. 反射获取Class对象
    4. 获取当前类接口(根据接口做代理)

    5. 创建代理类(Proxy)
    6. 代理策略:监控方法执行
    7. 获取代理类的接口方法,调用执行

    代码演示:

    /**

         * 演示动态代理

         */

        @Test

        public void test8()throws Exception{

            //1    读取配置文件

            ResourceBundle bundle = ResourceBundle.getBundle("peizhi");

            //2    获取类全名

            String className = bundle.getString("servlet");

            //3    反射获取Class对象

            final Class<?> clazz = Class.forName(className);

            

            //4    获取当前类接口(根据接口做代理)

            Class<?>[] interfaces = clazz.getInterfaces();

            //以上都是反射操作

            //5    创建代理类(Proxy),设置了代理的策略

            Object obj = Proxy.newProxyInstance(clazz.getClassLoader(), interfaces, new InvocationHandler() {

                

                @Override

                public Object invoke(Object proxy, Method method, Object[] args)

                        throws Throwable {

                    //6    代理策略:监控方法执行

                    //method 当前被调用的方法

                    //args 是调用方法时候的参数

                    System.out.println("======方法启动=====");

                    System.out.println("method:"+method);

                    for (Object dd : args) {

                        System.out.println(dd);

                    }

                    //method是一个方法对象,可以调用它的invoke方法,让他去执行

                    if(method.getName().equals("doGet")){

                        

                        Object invoke = method.invoke(clazz.newInstance(), args);

                    }

                    System.out.println("======执行完成=====");

                    return null;

                }

            });

              

            

            //7    获取代理类的接口方法,调用执行

            //通过接口数组的第一个接口,获取第一个接口中的所有方法

            Method[] methods = interfaces[0].getMethods();

            //通过操作methods方法数组,获取第一个方法对象,通过他的invoke方法,调用方法执行

            methods[0].invoke(obj, "req","res");

        }

          

        

        //为什么要用动态代理?

        //1)可以通过代理对象,对指定的类的方法进行修改(拦截或者增强),使用动态代理修改类,不需要修改原来的代码,因为我们是创建一个新的类

        //2)一次动态代理,可以对当前指定的类,的所有方法,进行拦截或者增强的操作

        

        /**

         * 继承

         * 当你要写的这个类,与原来要被增强的那个类是同一类型事物(animal cat dog

         *

         * 装饰设计模式

         * 当你要写的这个类,与原来要被增强的那个类不是同一类型事物(animal dianziGou / request对象进行增强,也是使用装饰设计模式

         *

         * 动态代理

         * 需要,在java虚拟机启动之后,再去修改指定的类,那么就使用动态代理

         *

         * 怎么就突然出现了一个类呢?

         * Person.java -->javac命令 Person.class

         * 创建代理类,底层机制类似javac命令,所以不属于java范畴,后期,入职sun公司,请回来告诉我。

         *

         * */

    总结:

    使用动态代理中,可以一个类的方法执行前后做增强和过滤的动作

    2.3、动态代理完成全站乱码处理

    过滤器:全站乱码过滤器

    需求:使用动态代理方式,处理乱码

    1. 过滤器:对请求进行增强
    2. 过滤器:过滤任务写在doFilter方法
    3. 过滤任务:通过创建代理对象来增强原来的request
    4. 根据不同请求方式处理:
    5. Post:setCharacterEncoding("utf-8")'
    6. Get:根据不同的方法,不同处理
    7. getParameter方法:new String();
    8. getParameterValues方法:遍历循环,new String();
    9. getParameterMap:循环遍历,new String();
    10. request对象还要其他方法,其他方法执行不做任何处理

    package cn.itcast.filter;

     

    import java.io.IOException;

    import java.lang.reflect.InvocationHandler;

    import java.lang.reflect.Method;

    import java.lang.reflect.Proxy;

    import java.util.Map;

    import java.util.Set;

     

    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 EncodingFilter2 implements Filter {

     

        @Override

        public void init(FilterConfig filterConfig) throws ServletException {

        }

     

        @Override

        public void doFilter(ServletRequest request, ServletResponse response,

                FilterChain chain) throws IOException, ServletException {

            final HttpServletRequest req = (HttpServletRequest) request;

            HttpServletResponse res = (HttpServletResponse) response;

            res.setContentType("text/html;charset=utf-8");

     

            // 使用动态代理创建代理对象,对request进行增强

            HttpServletRequest myrequest = (HttpServletRequest) Proxy

                    .newProxyInstance(req.getClass().getClassLoader(), req

                            .getClass().getInterfaces(), new InvocationHandler() {

     

                        @Override

                        public Object invoke(Object proxy, Method method,

                                Object[] args) throws Throwable {

                            // 设置代理策略,对request的获取数据的方法进行增强

     

                            //获取请求方式

                            String method2 = req.getMethod();

                            if(method2.equalsIgnoreCase("post")){

                                req.setCharacterEncoding("utf-8");

                                return method.invoke(req, args);

                            }else if(method2.equalsIgnoreCase("get")){

                                //获取请求参数的方法

                                //根据不同的方法,进行不同增强操作

                                if("getParameter".equals(method.getName())){

                                    String parameter = req.getParameter((String)args[0]);

                                    if(parameter != null){

                                        parameter = new String(parameter.getBytes("iso-8859-1"),"utf-8");

                                    }

                                    return parameter;

                                }else if("getParameterValues".equals(method.getName())){

                                    

                                    String[] values = req.getParameterValues((String)args[0]);

                                    if(values != null){

                                        for (int i = 0; i < values.length; i++) {

                                            values[i] = new String(values[i].getBytes("iso-8859-1"),"utf-8");

                                        }

                                    }

                                    return values;

                                }else if("getParameterMap".equals(method.getName())){

                                    Map<String, String[]> map = req.getParameterMap();

                                    if(map != null){

                                        Set<String> keySet = map.keySet();

                                        for (String key : keySet) {

                                            String[] values = map.get(key);

                                            for (int i = 0; i < values.length; i++) {

                                                values[i] = new String(values[i].getBytes("iso-8859-1"),"utf-8");

                                            }

                                        }

                                    }

                                    return map;

                                }else{

                                    return method.invoke(req, args);

                                }

                            }else{

                                return method.invoke(req, args);

                            }

                        }

                    });

     

            chain.doFilter(myrequest, res);

        }

     

        @Override

        public void destroy() {

        }

     

    }

        

    3、注解技术

    3.1、注解和注释区别

        注释:它是对程序中的代码进行解释说明。注释是给人看。

        注解:它是给程序使用的。在程序运行的时候(编译的时候),会根据相应的注解,然后完成对应的操作。注解经常需要和反射一起使用。

        早期的程序:

            基本是程序配合配置文件一起工作,在程序运行的时候,会读取配置文件中的数据。

            

        现在程序:

            在程序运行的时候,不再使用配置文件(少量使用配置文件),而是在程序加入注解来代替配置文件。

    3.2、注解格式和JDK注解简单演示

        注解的格式:@注解的名称( key=value , key=value, key=value。。。。。。 )

    JDK中自带的3个注解:

            1、方法复写的时候注解:

                使用Override注解声明当前方法是复写父类的方法,或者是实现了接口中的方法

                

                jdk1.5@override不支持接口的方法复写,1.6以上可以

                

                

            2、过时的方法注解:

    @Deprecated它声明某个方法已经过时。

                

                        

    3、消除程序中的警告

    @SuppressWarnings 消除警告。            

                

    3.3、自己定义注解的实现

        自己定义注解:

        格式:public @interface 注解名字{

    定义注解的成员变量;

    }

        

        第一步:

        

        

        效果:

        

        自定义注解:

    自定义注解使用:

          

        

    3.4、注解的细节

    @Test注解不能出现在类上:

    获取Junit源代码:

    第一步:找到junit在eclipse中的位置

    第二步:使用反编译神器,将class文件还原成.java文件

    发现:在@Test注解的底层类上有两个注解

    @Retention(RetentionPolicy.RUNTIME)

    指定注解什么时候存在

    @Target({java.lang.annotation.ElementType.METHOD})

    指定注解可以写在什么位置

    1、在定义注解的时候,可以指定注解什么时候存在——@Retention

            这个注解是存在于源代码上,还是编译之后的class文件上,还是运行时期也要存在。

            @Retention 使用jdk中的Retention 来声明自己的注解将来在程序中存活的具体时间

            RetentionPolicy:声明注解存活的时间:

    代码演示:

    注意:声明注解的存活时间时,使用runtime是给反射程序使用的。

        2、在定义注解的时候,指定注解可以写在什么位置——@Target

            注解是使用在类上,方法上,构造方法上,成员变量,或者是其他注解上。

            在Java中提供的@Target注解,声明自己 定义的注解在其他的类中的存在位置。

            

    代码演示:

    效果:

     

            演示代码(反射获取注解):

    @Test

        @MyAnnotation

        public void test9() throws Exception{

            

            Method method = this.getClass().getMethod("test9", null);

            MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);

            System.out.println(annotation);

        }

        

     

    效果:

     

    1. 在注解中定义成员变量

      格式:数据类型 变量名() default 默认值

      测试代码:

                            

                效果:

                

            

            

    3.5、使用注解完成数据库连接的获取

        定义注解:

    package cn.itcast.zhujie;

     

    import java.lang.annotation.Retention;

    import java.lang.annotation.Target;

    import java.lang.annotation.RetentionPolicy;

     

    @Retention(RetentionPolicy.RUNTIME)

    @Target({java.lang.annotation.ElementType.METHOD})

    public @interface MyAnnotation {

     

        String driverClass();

        String jdbcUrl();

        String user();

        String password();

    }

     

    使用注解:

    package cn.itcast.test;

     

    import java.lang.annotation.Annotation;

    import java.lang.reflect.Method;

    import java.sql.Connection;

    import java.sql.DriverManager;

     

    import org.junit.Test;

     

    import cn.itcast.zhujie.MyAnnotation;

     

     

     

    public class TestUtils2 {

        @MyAnnotation(driverClass="com.mysql.jdbc.Driver",jdbcUrl="jdbc:mysql:///day14",user="root",password="root")

        @Test

        public void test() throws Exception{

            //获取注解上的值,获取数据库连接

            Method method = this.getClass().getMethod("test", null);

            MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);

            String driverClass = annotation.driverClass();

            String jdbcUrl = annotation.jdbcUrl();

            String user = annotation.user();

            String password = annotation.password();

            

            Class.forName(driverClass);

            

            Connection connection = DriverManager.getConnection(jdbcUrl, user, password);

            System.out.println(connection);

            

        }

    }

  • 相关阅读:
    Java入门
    Java入门
    字符串常用方法(转载--https://www.cnblogs.com/ABook/p/5527341.html)
    SSM-8FastDfs搭建
    SSM7-nginx的反向代理和负载均衡
    SSM-6nginx Linux下的安装
    SSM-5zookeeper在LINUX上自启
    SSM4-Linux上jdk、tomcat、zookeeper------tar zxvf的安装
    SSM3-SVN的安装和搭建环境
    SSM2-搭建maven常见的错误以及解决方法
  • 原文地址:https://www.cnblogs.com/beyondcj/p/6270922.html
Copyright © 2011-2022 走看看