Maven

  • 核心概念

    • pom:项目对象模型,构建maven项目,管理jar包依赖。


    <modelVersion>4.0.0</modelVersion> <!--maven模型的版本 -->
    <groupId>org.example</groupId> <!--组织id,一般为公司域名的倒写或域名倒写+项目名字 -->
    <artifactId>Spring1</artifactId> <!--项目名称 -->
    <version>1.0-SNAPSHOT</version> <!-- 项目版本号,通常在版本后加-SNAPSHOT(快照)-->

    <!-- 搜索使用的中央仓库:https://mvnrepository.com/,使用groupId或者artifactId搜索 -->

    <packaging> <packaging> 项目打包的类型,默认为jar

    <dependencies>
    <dependency> <!--添加依赖,从本地仓库中查找,没有从远程下载。-->
    <!-- 坐标 -->
    <scope> </scope> <!--依赖使用的范围:compile(默认,所有阶段),test,provided(编译,测试时有效,打包部署时不需要)-->
    </dependency>
    </dependencies>

    <properties> <!-- 设置属性 -->
    <!--自定义全局变量,一般为统一版本号-->
    <name>版本号</name>
    <!--使用方式:在其他地方${name} -->
    </properties>

    <build> <!--maven项目在构建是,配置信息,使用的插件或者编译使用的jdk-->
    <plugins>
    <plugin>
    <configuration>
    <source> </source> <!--编译jdk版本-->
    <target> </target> <!--运行jdk版本-->
    </configuration>
    </plugin>

    <resources>
    <resource>
    <!--
    没有该标签时,mavn将src/main/resources拷贝到target/classes下,src/main/java目录下的其他文件不拷贝
    -->
    <!-- 该标签:需要将src/main/java目录下的其他文件不拷贝-->

    <directory>src/main/java</directory>
    <includes>
    <include>**/*.xml</include>
    <include>**/*.properties</include>
    </includes>
    <!-- *.properties已经启过滤器作用-->
    <filtering>false</filtering>
    </resource>
    </resources>

    </plugins>
    </build>
    • 约定的目录结构:

      HELLO 					<!--项目文件夹 -->
      |---src
      |---|---main <!--主程序 -->
      |---|---|---java <!--主程序java文件和程序包-->
      |---|---|---resources <!--主程序使用的配置文件-->

      |---|---test
      |---|---|---java <!--测试java文件和程序包-->
      |---|---|---resources <!--测试使用的配置文件-->

      |---pom.xml <!--maven的配置文件-->
    • 坐标:唯一的字符串,用于表示资源,必须

      <groupId>org.example</groupId>		<!--组织id,一般为公司域名的倒写或域名倒写+项目名字-->
      <artifactId>Spring1</artifactId> <!--项目名称-->
      <version>1.0-SNAPSHOT</version> <!--项目版本号,通常在版本后加-SNAPSHOT(快照)-->
    • 依赖管理:管理jar包依赖。

    • 仓库管理:资源存放的仓库管理

      • 存放maven使用的jar包和项目使用的jar包
      • 分类
        • 本地仓库:在maven 目录下settings.xml中配置本地仓库
        • 远程仓库:需要联网下载
          1. 中央仓库(欧洲)
          2. 中央仓库的镜像。
          3. 私服:局域网中使用的仓库。
        • 仓库使用过程
          • 首先查看本地仓库
          • 在私服中查找
          • 镜像中查找
          • 中央仓库
    • 生命周期:maven构建项目过程,清理,编译,测试,报告,打包,安装,部署

  • 常用命令:使用jar文件中的插件实现

    mvn clean	#--清理target文件
    mvn compile #编译src/main目录下所有java文件,生成target文件

    mvn test-compile
    mvn test #会执行前面的步骤

    mvn package #打包:会进行编译,测试编译,测试,按照pom文件进行打包生成在target目录下,只有src/main中的东西,
    mvn install #将本地工程按照坐标保存到本地仓库
    mvn deploy #将本地工程按照坐标保存到本地仓库,保存到私服仓库中,且自动将项目部署到web容器中

IOC

  • 控制反转:对象创建,赋值,管理工作由代码之外的容器外部资源实现。

    • 控制:创建对象,属性赋值,对象之间的关系管理
    • 反转:创建对象的权限转移给代码之外的容器实现。由容器代替开发人员管理对象。创建对象,给属性赋值。
      • 容器:服务器\框架。
    • IOC目的:减少代码改动,实现更多的功能,实现解耦合。
  • 创建对象:

    • 构造方法:

    • 反射:

      • Java特征之一,允许运行中的java程序获取自身的信息,并且操作或者对象的内部属性。

      • 通过反射,可以在运行时获得程序中的每一个类型的成员活动成员的信息。

      • 对象是在编译时确定的,java反射机制可以动态地创建对象并且调用相关的属性,这些对象的类型在编译时未知。

      • 因此可以通过反射创建对象。即使在编译时对象的类型是未知的。

      • 反射提供功能:

        • 在运行时判断任意一个对象所属的类
        • 在运行时构造任意一个类的对象
        • 在运行时判断任意一个类所具有的成员变量和方法,可以通过反射调用private方法
        • 在运行时调用任意一个对象的方法
      • 反射的核心思想:JVM在动态运行时才加载类,调用方法或者访问属性,不需要再编译的时候知道运行的对象是什么。

      • 原理:

        • WAF4eS.jpg

        • class的加载:JVM使用ClassLoader将编译好的class文件加载到方法区内存中:此方法返回一个Class对象

          Class clazz = ClassLoader.getSystemClassLoader().loadClass("com.mypackage.MyClass");

        详细一点的过程:

        • WAASnf.jpg

        • 类加载器:加载.class文件步骤

          • 检查是否已经加载
          • 未加载,遵循父优先加载机制,加载.class文件
          • 调用findclass(name)读取.class文件,创建字节数组,创建Class对象。
          • WAEds0.jpg
        • ReflectionData缓存:

          • 提高反射性能,Class内中有一个useCaches静态变量标记是否使用缓存。外部使用sun.reflect.noCaches来禁用缓存。Class内中有一个ReflectionData内部类用于存放反射数据的缓存,声明了一个reflectionData域,按照需要延迟加载并没有指向一个实例化的ReflectionData对象。

          • Class类:Class类的构造器是私有的,因此无法手动new一个Class对象,只能由JVM创建,JVM通过类加载器创建Class对象。

          • Class对象:修饰符,类名,参数化信息(泛化信息),接口,注解,字段构造器方法

            // 标记是否使用缓存,可以通过外部的sun.reflect.noCaches配置是否禁用缓存
            private static boolean useCaches = true;

            static class ReflectionData<T> {
            volatile Field[] declaredFields;
            volatile Field[] publicFields;
            volatile Method[] declaredMethods;
            volatile Method[] publicMethods;
            volatile Constructor<T>[] declaredConstructors;
            volatile Constructors<T>[] publicConstructors;
            volatile Field[] declaredPublicFields;
            volatile Method[] declaredPublicMethods;
            final int redefinedCount;

            ReflectionData(int redefinedCount) {
            this.redefinedCount = redefinedCount;
            }
            }

            // 这个是SoftReference,在内存资源紧张的时候可能会被回收
            // volatile保证多线程环境下读写的正确性
            private volatile transient SoftReference<RefelectionData<T>> reflectionData;

            // 这个主要用于和ReflectionData中的redefinedCount进行比较
            // 如果两个值不相等,说明ReflectionData缓存的数据已经过期了
            private volatile transient classRedefinedCount = 0;
          • Class构造器为私有的,只能由JVM创建,需要传入类加载器。

        • 反射的运用:

          • 用于框架的开发

          • 各种容器实现的核心

          • 反射中各类API:依赖与四个类:Class,Constructor,Field,Method;

            • 获得构造器的方法:

              Constructor getConstructor(Class[] params) //获得使用特殊的参数类型的公共构造函数,   
              Constructor[] getConstructors() //获得类的所有公共构造函数 Constructor
              Constructor getDeclaredConstructor(Class[] params) //获得使用特定参数类型的构造函数(与接入级别无关)
              Constructor[] getDeclaredConstructors() //获得类的所有构造函数(与接入级别无关)
            • 获取字段信息(属性):

              Field getField(String name) //获得命名的公共字段 

              Field[] getFields() //获得类的所有公共字段

              Field getDeclaredField(String name) //获得类声明的命名的字段

              Field[] getDeclaredFields() //获得类声明的所有字段
            • 获取方法信息:

              Method getMethod(String name, Class[] params) //使用特定的参数类型,获得命名的公共方法 

              Method[] getMethods() //获得类的所有公共方法 ,可获得父类的方法。

              Method getDeclaredMethod(String name, Class[] params) //使用特写的参数类型,获得类声明的命名的方法

              Method[] getDeclaredMethods() //获得类声明的所有方法
            • 创建Class对象:

              • 对象.getClass();
              • 类.class
              • Class.forName(“包名.类名”)静态方法
            • 反射API调用方法

              • 通过Class对象获得实例化对象:

                • class对象.newInstance()必须存在一个无参的构造方法,底层调用的是无参的构造器。否则需要找到一个构造方法去调用:

                  Class clazz = Class.forName(" ");
                  Object O = clazz.newInstance();
                • 通过getConstructor(String.class,int.class);获得构造器,然后con.newInstance(String,int):

                  Class clazz = Class.forName(" ");
                  Constructor con = clazz.getConstructor(int.class);
                  Object O = con.newInstanceof(1);
              • Class对象的getMethod需要传入方法名参数类型的Class对象引用:确保找到唯一匹配的方法

                public Object invoke(Object obj, Object ... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {}
                • method.invoke(obj,args)传入对象参数,保证执行方法时知道是哪个对象的数据,如果是静态方法就不需要。
              • Class对象获得属性

            • 反射创建数组

              //通过Array.newInstance()创建数组对象。

              public static Object newInstance(Class<?> componentType, int length) throws NegativeArraySizeException {
              return newArray(componentType, length);
              }
              public static void TestAraary() Throws ClassNotFoundException{
              Class<?> clazz = Class.forName("java.lang.String");//创建String的Class对象。
              Object array = Array.newInstance(clazz,25);//创建Array对象。

              Array.set(array,0,"a");
              Array.set(array,0,"b");
              Array.set(array,0,"c");
              Array.set(array,0,"d");
              //添加数组成员

              //获取数组成员
              Array.get(array,0);
              Array.get(array,1);
              }
              //set 与 get方法都是native方法 (C/C++实现的)
    • 序列化:就是把对象通过流的方式存储到文件中:可以是网络文件或磁盘设备。此对象 要重写Serializable 接口才能被序列化。

      • 永久保存数据

      • 只有实现了Serializable和Externalizable接口的类的对象才能被序列化,不想序列化的属性可以加上,transient关键字。

      • java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。

      • 步骤:

        • 1) 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;
        • 2) 通过对象输出流的writeObject()方法写对象。
      • 反序列化步骤:

        • 1) 创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;
        • 2) 通过对象输入流的readObject()方法读取对象。
        class Person implements Serializable {

        private int age;
        private String name;
        private String sex;

        public int getAge() {
        return age;
        }

        public String getName() {

        return name;
        }

        public String getSex() {

        return sex;
        }

        public void setAge(int age) {

        this.age = age;
        }

        public void setName(String name) {

        this.name = name;
        }

        public void setSex(String sex) {

        this.sex = sex;
        }
        }
        public class test(){
        public static void main(){
        //序列化:
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File("test.txt")));
        out.writeObject(person);
        System.out.println("Person对象序列化成功!");
        out.close();

        //反序列化:
        ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File("test.txt")));
        Person person = in.readObject();
        System.out.println(person.getName());
        System.out.println("Person对象反序列化成功!");
        }
        }

    • 克隆:clone方法来源于java中object类,在jdk中的解释为:该方法返回一个此对象的副本。clone顾名思义就是复制的意思。所谓复制对象就是在内存中分配一个和原一模一样的空间,在此创建新的对象。内容一致但是指向的内存空间不同。由于Object类中clone方法是protected 修饰的,所以我们必须在需要克隆的类中重写克隆方法。

      package Coding;

      /* 深复制 ,在对clone方法进行重写时手动对要复制的对象的引用进行复制*/
      public class Clone implements Cloneable{

      class Head implements Cloneable{
      public Head(){
      }
      protected Object clone() throws CloneNotSupportedException {
      return super.clone();
      }
      }
      public Head head = new Head();
      @Override
      protected Object clone() throws CloneNotSupportedException {
      Clone new_clone = (Clone) super.clone();
      new_clone.head = (Head) head.clone();
      return new_clone;
      }
      public static void main(String[] args) throws CloneNotSupportedException {
      Clone C = new Clone();
      Clone C1 = C;
      if(C1 == C ){
      System.out.println("两对象指向同一地址");
      }
      else {
      System.out.println("两对象指向不同地址");
      }

      Clone C2 = (Clone) C.clone();

      if(C2 == C){
      System.out.println("两对象指向同一地址");
      }
      else {
      System.out.println("两对象指向不同地址");
      }

      System.out.println(C.head);
      System.out.println(C2.head);
      }
      }

    • IOC:容器创建对象。

      • DI:依赖注入实现IOC技术:通过名字从容器中拿到对象,对象属性赋值
      • 在程序中提供使用的对象的名称,对象的创建,赋值,查找由容器管理。
    • Spring使用DI实现IOC功能,底层使用反射机制。

      • 使用Spring创建对象

        • 创建maven

        • 加入maven依赖->spring依赖

        • 创建类(接口和他的实现类)

        • 创建Spring需要使用的配置文件:声明类,这些类由Spring创建,管理

          <!--
          beans:根标签,spring把java对象成为bean
          spring-beans.xsd为约束文件
          -->

          <!--
          声明bean,告诉Spring创建某个类对象
          两个属性:
          id:对象的自定义名称,唯一值。通过此名称找到对象
          class:类的全限定名称,不能为接口,Spring通过反射机制创建类。

          spring通过反射机制完成对象创建
          Spring将创建好的对象放入map中:springmap.put(id,对象)
          -->
          <bean id="myservice" class="com.example.Ser.service">
        • 获取Spring创建的对象

          • 指定spring配置文件名:String name

          • 通过ppApplicationContext接口创建实现类获取对象。

            Application spring = new Application();

            //两个的实现类:
            new FileSystemXmlApplicationContext() //从磁盘中读配置文件,不常用
            new ClassPathXmlApplicationContext() //配置文件在当前项目中

            //从类路径中加载配置文件,mvn时会讲resources路径下额配置文件拷贝到target下
            ApplicationContext cont = new ClassPathXmlApplicationContext(config);

            //例如:
            public static void main(String[] args )
            {
            String config = "bean.xml"; //加载配置文件
            ApplicationContext cont = new ClassPathXmlApplicationContext(config);//创建spring容器,读取配置文件,并创建所有对象。

            serviceimpl serv1 = (serviceimpl) cont.getBean("myservice"); //获取对象
            serv1.doThins(); //调用方法

            }
        • 获取容器中对象的信息:

           String config = "bean.xml";			
          ApplicationContext cont = new ClassPathXmlApplicationContext(config);

          //创建对象:默认调用无参构造方法函数返回的时Object对象,因此需要向下转型:强制转换
          serviceimpl serv1 = (serviceimpl) cont.getBean("myservice");

          //获取容器中对象的数量:
          int cont.getBeanDefinitionCount();

          //获取容器中对象的名称
          String []names = cont.getBeanDefinitionNames();

    • Spring中给对象属性赋值

      • 基于XML的DI

        • set注入(设置注入):spring调用类的set方法实现赋值

          <!--简单类型:基本数据类型和String-->
          <!--spring只会去找name值的set方法,和有无此属性无关-->
          <bean id = "student_1" class = "org.example.DI_CREATE.Student" >
          <property name = "age" value = "20" />
          <property name = "matt" value = "21" />
          </bean>

          <!--引用类型:使用ref指定引用类型的对象名,在使用bean创建对象 -->

          <bean id = "student_1" class = "org.example.DI_SET.Student">
          <property name = "age" value = "19" /> <!-- 执行setage()方法-->
          <property name = "name" value = "matt"/> <!--执行setname()方法-->
          <property name="school" ref="school1" />
          </bean>
          <bean id="school1" class ="org.example.DI_SET.School">
          <property name="name" value="电子科技大学"/>
          <property name="addr" value="成都市成华区"/>
          </bean>
        • 构造注入:spring调用类的构造方法实现赋值

          <!-- 默认调用的时无参构造创建对象 -->
          <!-- 调用构造方法进行属性赋值:使用constructor-arg标签
          name:构造方法形参名
          index:(参数索引值)构造方法参数位置,从0开始
          value:参数值
          -->
          <bean id = "student_1" class = "org.example.DI_SET.Student">
          <constructor-arg name = "age" value = "19" /> <!-- 执行构造方法-->
          <constructor-arg name = "name" value = "matt"/> <!--执行构造方法-->
          <constructor-arg name="school" ref="school1" />
          </bean>
          <bean id="school1" class ="org.example.DI_SET.School">
          <constructor-arg name="name" value="电子科技大学"/>
          <constructor-arg name="addr" value="成都市成华区"/>
          </bean>
        • 引用类型自动注入

          • ByName:按名称注入,将配置文件中bean标签id和类中引用类型属性名一致,且数据类型相同,既可自动注入

            <bean id = "student_1" class = "org.example.DI_ByName.Student" autowire="byName">
            <property name="name" value="matt"/>
            <property name="age" value="19"/>

            </bean>
            <bean id="school" class ="org.example.DI_ByName.School" >
            <property name="name" value="UESTC"/>
            <property name="addr" value="成华大道建设路"/>
            </bean>
            <!-- spring自动将和Student类中同名的引用类型属性名school 注入 -->
          • Bytype:按类型注入,类中引用类型和spring容器中bean标签的class属性是同源关系(相同或继承或接口实现类关系)

          <bean id = "student_1" class = "org.example.DI_ByName.Student" autowire="byType">
          <property name="name" value="matt"/>
          <property name="age" value="19"/>
          </bean>
          <bean id="school_1" class ="org.example.DI_ByName.School" >
          <property name="name" value="UESTC"/>
          <property name="addr" value="成华大道建设路"/>
          </bean>

          <!-- 多个同源关系会报错:没有唯一的匹配 -->
        • 多配置文件分类

          • 按功能模块分:

            • 主模块配置文件没有对象,用来指定其他配置文件的位置:
            <import resource="classpath:classes 文件下配置文件路径"/>

            <!--使用通配符:文件在同一级目录。注意不要把自己文件加载进去,防止死循环 -->

            <import resource="classpath:classes *.xml"/>
          • 按类的功能类:数据库/事务/service

        • 常用对象:dao类,service类,contoller类,工具类

        • 不放入Spring:实体类对象,servlet,listener,filter。

      • 基于注解的DI:使用的是spring-context依赖中的spring-aop依赖。在spring配置文件中,加入一个组件扫描器标签,说明注解在项目中的位置。

        • @Component

          /*
          @Component注解:创建对象,功能类似于<bean>
          属性:value为对象的名称:bean中id的值
          value的值唯一的,整个spring容器中就一个
          位置:在类的上面

          */
          /*
          其他用法:
          不指定value值,由spring指定默认的值:类名只有首字母大写的话变成小写/其他不变
          */
          @Component(value = "student_1")
          public class Student {
          private String name;
          private int age;

          public Student(){
          this.name = "vin";
          this.age = 18;
          }
          public void setName(String name) {
          this.name = name;
          }

          public void setAge(int age) {
          this.age = age;
          }

          @Override
          public String toString() {
          return "Student{" +
          "name='" + name + '\'' +
          ", age=" + age +
          '}';
          }
          }

          配置文件中:添加组件扫描器

           <!--组件扫描器:组件:java对象
          base_package:指定注解在项目中的包名
          组件扫描器工作方式:扫描base-package指定的包,以及包中和子包中所有的类,找到类中的注解,按照注解创建对象或给属性赋值
          加入component-scan标签后:配置文件:
          1. 加入了一个新的约束文件spring-contex.xsd
          2. 给这个新的约束文件起个新的命名空间:http://www.springframework.org/schema/context,指定一个url的约束文件xsd地址
          再通过一个标签context指定此命名空间
          -->
          <beans>
          <context:component-scan base-package="org.example.Component"/>
          </beans>
        • @Respository

        /*	持久层
        放在dao的实现类上面,表示创建dao对象,dao对象访问数据库
        */
        • @Service
        /* 
        用在业务层,放在service实现类上面
        创建service对象,service对象做业务处理,可以有事物等功能。
        */
        • @Controller
        /* 
        用在控制器上面
        创建控制器对象,接受用户提交的参数,显示请求的处理结果。servlet功能。
        */

        以上三个注解语法与component一样创建对象。但也有额外的功能,用于给项目对象分层。

        • 扫描多个包

          • 使用多个组件扫描器
          • 使用分隔符;或者,分隔多个包名
          • 指定父包:递归扫描
        • @Value

        <!-- 简单类型赋值 -->
        /*
        @Value:简单类型的属性赋值
        属性:value:String类型,表示简单类型的属性值,反射原理。
        位置:直接再属性的上面,无需set方法:推荐使用
        在set方法之上
        */

        @Component("student_1")
        public class Student {
        @Value(value = "matt")
        private String name;

        @Value(value = "20")
        private int age;


        public Student(){
        this.name = "vin";
        this.age = 18;
        }
        public void setName(String name) {
        this.name = name;
        }

        public void setAge(int age) {
        this.age = age;
        }

        @Override
        public String toString() {
        return "Student{" +
        "name='" + name + '\'' +
        ", age=" + age +
        '}';
        }
        }
        • @Autowired
        /*
        @Autowired:spring实现引用类型的赋值
        属性:require = true:表示引用类型赋值失败,程序报错终止执行。
        require = false :引用类型赋值失败,则赋值为null,程序不终止。

        使用的是自动注入方法,支持,ByName,ByType
        默认使用的是ByType

        使用ByName方式:
        @Autowired
        @Qualifier("school_1")
        */
        • Resource
        /*
        @Resource来自JDK的注解,spring提供支持,可以给引用类型赋值
        给引用类型赋值,应用类型变量上或set方法
        默认ByName方式:先使用ByName,失败再使用ByType

        只是用ByName方式:
        @Resource(name="")
        */

        使用自定义属性变量:${}

        //引入自定义属性变量文件
        <context:property-placeholder location="classpath:my.properties"/>
      • IOC实现了解耦合:业务对象之间的解耦合:service和dao和controller

AOP:面向切面编程

  • 代理:基于反射机制。功能增强,控制访问

  • 静态代理:代理类是手工实现;目标类是确定的。设计模式中:代理模式

    • 用户不能直接访问目标类中方法实现功能,而代理类可以且必须。

    • 缺点:目标类增多时,代理类数量会增加

      ​ 接口中功能增加。修改,会影响实现类:目标类与代理类。

  • 动态代理:目标类很多,代理类数量可以很少, 修改接口后,不回影响代理类。

    • JDK动态代理:在程序运行过程中,通过反射机制,直接创建代理对象,动态指定代理目标。

      • 目标对象必须为接口,目标类与代理类实现相同的接口。java.lang.reflect包提供三个类支持代理模式:Proxy,Method和InvocationHandler

        • InvocationHanler接口:invoke()方法:代理类完成的功能写在此方法中。

          public Object invoke(Object proxy,Method method,Object[] args)
          /*
          参数依次为:
          proxy:代理类对象,无需赋值:使用静态方法:
          public static Object newProxyInstance(ClassLoader loader,Class<?>[] interface,InvocationHandler h)
          目标对象的类加载器
          接口,目标对象实现的接口
          InvocationHandler :自己写的代理类

          Method:目标类中方法的Method对象,jdk提供,执行的反射中的
          public Object Method.invoke(Object obj,Object[] args)

          args:目标类方法参数,jdk提供

          */

          /*
          创建接口实现类
          重写invoke方法实现代理类中的功能。
          */
        • 使用步骤

          • ​ 创建InvocationHandler实现类,重写invoke方法:使用反射的Method.invoke()执行目标类中方法,需要动态传入目标类对象。

          • ​ 使用:创建目标类对象

            ​ 创建InvocationHandler对象,传入目标类对象。

            ​ 创建Proxy对象:通过静态方法newProxyInstance(ClassLoader loader,Class<?>[] interface,InvocationHandler h),转型为接口类型

          • 通过代理执行接口中方法。

          • 使用场景:

            • 系统中存在的类修改功能:增加功能。
            • 给项目中多个类增加相同的功能。
            • 给业务方法增加事物,日志输出
          • 优点:

            • 改变接口不会影响代理类,直接通过代理对象带调用想要调用的方法。
            • 不用写许多代理类,而是通过Proxy中静态方法创建创建代理对象。
            • 不改变源码的情况下增加功能
            • 减少代码重复
            • 解耦合
            • 专注业务逻辑
            package Coding.Dynamic_Proxy;


            import java.lang.reflect.InvocationHandler;
            import java.lang.reflect.Method;
            import java.lang.reflect.Proxy;

            interface FindJob{
            public void find();
            }

            //目标类
            class Person implements FindJob {
            @Override
            public void find(){
            System.out.println("hand in resume");
            }
            }

            class My_Proxy implements InvocationHandler{

            //通过构造方法传入目标对象
            private Object object;
            public My_Proxy(Object object){
            this.object = object;
            }
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

            System.out.println("accept proxy");
            method.invoke(object,args);
            System.out.println("proxy answer");
            System.out.println("proxy end");
            return null;
            }
            }

            public class Dynamic_Proxy {
            public static void main(String[] args) {

            Person person = new Person();
            InvocationHandler handler = new My_Proxy(person);

            FindJob findJob = (FindJob) Proxy.newProxyInstance(person.getClass().getClassLoader(),person.getClass().getInterfaces(),handler);

            findJob.find();
            }
            }
    • CGLIB动态代理:第三方工具库。无接口的类实现动态代理:通过继承的方式重写父类的方法实现代理。因此目标类和方法不能是final。

  • AOP:底层使用动态代理,两种动态代理都可以使用。动态代理的规范化,用一种统一的方式,使用动态代理。

    • Aspect:切面:给目标类增加的功能
      • 一般是非业务方法。
      • 常见切面功能:日志,事物,统计信息,参数检查,权限验证。
    • JoinPoint:连接点,连接业务和和切面的位置。某类中的业务方法。
    • Pointcut:切入点,指多个连接点方法的集合。多个方法。切面执行的位置
    • 目标对象:给哪个类增加功能。
    • Advice:通知,表示切面功能执行的时间
  • AOP的实现:spring框架,在事物处理时使用aop,但是比较笨重。常用的是aspectJ:一个开源的aop框架。spring集成了aspectJ的功能:

    • 使用xml方式。

    • 使用注解,一般使用注解。

    • 切面的执行时间:Advice(通知,增强)

      • 在aspectJ中使用注解表示,也可以使用xml标签。

        @Before//前置通知
        @AfterReturning
        @Around
        @AfterThrowing
        @After
    • 切面的执行位置:Pointcut使用切入点表达式

      execution(modiduers-pattern? ret-type-pattern declaring-type-pattern?name_pattern(param-pattern) throws-pattern?)

      modifiers-pattern:访问权限类型
      ret-type-pattern: 返回值类型
      declaring-type-pattern 包名类型
      name-pattern(param-pattern):方法名(参数列表)
      throws-pattern:抛出异常类型
      ?:表示可选部分

      execution(访问权限 方法返回值 包名 方法声明(参数列表) 异常抛出类型)
      必有得:方法返回值,方法声明。
      • 模式可以使用通配符:

        • *0到多个字符

        • …:方法参数中,可变参数

          ​ 包名之后:当前包及其子包

        • +:类名之后:表示当前类及其子类

          ​ 接口之后:表示当前接口及其实现类

      • 举例:

      execution(public * *(..))//所有公共方法
      execution(* set*(..)) //所有的set方法,省略了权限控制符
      execution(* com.xyz.service.*.*(..))//service包中所有类中的所有方法
      execution(* com.xyz.service..*.*(..))//service下所有子包的所有类的所有方法
      execution(* *..service.*.*(..)) //任意级service包中所有类的所有方法
      • 步骤:

        • 加入Aspect依赖

          • 创建目标类和其接口:方法为void类型方法

          • 创建切面类:普通类

            • 在类上加入@Aspect

            • 类中定义方法,切面的执行功能

            • 在方法上面加入aspectj的通知注解有需要指定切入点表达式指定需要增强的目标类。

            • :前置通知@Before注解

              /*
              方法定义要求
              公共方法
              没有返回值
              有参数的话不能自定义:选择参数Joinpoint:代表业务方法,加入切面功能的方法
              作用:在通知方法中获取方法执行时的信息,方法名称与实参
              有框架赋值,必须是第一个位置的参数
              */

              @Aspect
              public class Aspect_1 {

              @Before(value = "execution(void *..Serviceimp.do*(String,int))")
              public void func_1(JoinPoint joinPoint){
              System.out.println("方法的签名:" + joinPoint.getSignature());
              System.out.println("方法的名称:" + joinPoint.getSignature().getName());

              Object[] args = joinPoint.getArgs();
              for(Object arg:args){
              System.out.println("方法的参数:" + arg);
              }


              System.out.println("在目标类前完成日志:");
              System.out.println("日期:" + new Date());
              }

              }
            • 后置通知@AfterReturning注解

            package org.example.Aspect;

            import org.aspectj.lang.annotation.After;
            import org.aspectj.lang.annotation.AfterReturning;
            import org.aspectj.lang.annotation.Aspect;

            @Aspect
            public class Aspect_after {

            @AfterReturning(value = "execution(* *..do_other(String,int))",returning = "res")
            /*
            两个属性:
            value:切入点表达式
            returning:自定义变量,用于存放目标方法的返回值
            变量名必须与下面的通知方法形参名一致。
            因此可以捕获到方法的返回值,也可以修改
            执行过程:
            Object res = do_other();
            after_func(res);
            */

            public void after_func(Object res){
            /*
            此res形参为方法的返回值,与注解中returning 值相同
            */
            System.out.println("后置通知执行,获取的返回值为:"+res);

            res = -1;

            }
            }

          • @Around注解:

          package org.example.Aspect;

          import org.aspectj.lang.ProceedingJoinPoint;
          import org.aspectj.lang.annotation.Around;
          import org.aspectj.lang.annotation.Aspect;

          import java.util.Date;

          @Aspect
          public class Aspect_around {
          @Around(value = "execution( * *..Serviceimp.do_first(..))")
          /*
          public
          必须有一个返回值
          固定参数ProceedingJoinpoint:用于执行目标方法。

          1. 功能最强的,在前后都执行
          2. 控制目标方法是否被调用执行
          3. 可以修改原来的执行结果
          4. 等价于JDK动态代理:InvocationHandler
          5. 可以直接通过ProceedingJoinPoint(继承于JointPoint接口)获取参数的值
          6. 常做事物,在目标方法前开启事务,目标方法执行完提交事物。
          */
          public Object func_around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
          Object res;
          Object []args = proceedingJoinPoint.getArgs();
          String name =(String) args[0];

          System.out.println("====目标方法前时间:=====" + new Date());
          if("matt".equals(name)) {
          res = proceedingJoinPoint.proceed();
          }
          System.out.println("====目标方法后提交:=====" + new Date());
          return "suceess_around";
          }

          }

          • 异常通知@AtfterThrowing
          package org.example.Aspect;

          import org.aspectj.lang.annotation.AfterThrowing;
          import org.aspectj.lang.annotation.Aspect;

          @Aspect
          public class Aspect_afterthrowing {
          @AfterThrowing(value = "execution( * *..*.do_second())",throwing = "e")

          /*
          value:切入点表达式
          throwing:目标方法抛出的异常对象,于通知方法中异常的参数名相同。
          作用:
          1.做监控程序,监控目标方法是否有异常
          有异常可以做其他事务:邮件,消息
          */

          /*
          无返回值
          参数Exception,或者JointPoint
          */
          public void atferthrwoing_func(Exception e){
          System.out.println("捕获到异常:" + e.getMessage() );

          }

          }

          • 最终通知@After
          package org.example.Aspect;

          import org.aspectj.lang.annotation.After;
          import org.aspectj.lang.annotation.Aspect;

          @Aspect
          public class Aspect_After {
          @After(value = "execution(* *..*.*())")
          /*
          value:切入点表达式
          特点:总是执行,在目标方法后执行,一般做资源释放工作
          */

          /*
          无参数通知
          参数可为:JoinPoint
          */
          public void After_func(){
          System.out.println("执行最终通知");
          }
          }

          • 辅助注解@Pointcut
          package org.example.Aspect;

          import org.aspectj.lang.JoinPoint;
          import org.aspectj.lang.annotation.After;
          import org.aspectj.lang.annotation.Aspect;
          import org.aspectj.lang.annotation.Before;
          import org.aspectj.lang.annotation.Pointcut;

          import java.util.Date;

          /*
          @Pointcut:管理多个相同的切入点表达式
          使用:在一个通知方法上面使用@Pointcut注解
          指定value切入点表达式的值,则此通知方法就可以作为切入点表达式的别名。
          */
          @Aspect
          public class Aspect_PointCut {
          @Pointcut(value = "execution(void *..Serviceimp.do*(..))")
          private void pointcut_1(){

          }

          @After(value ="pointcut_1()")
          public void After_func(){
          System.out.println("执行最终通知");
          }

          @Before(value = "pointcut_1()")
          public void beforen_func(JoinPoint joinPoint){
          System.out.println("方法的签名:" + joinPoint.getSignature());
          System.out.println("方法的名称:" + joinPoint.getSignature().getName());

          Object[] args = joinPoint.getArgs();
          for(Object arg:args){
          System.out.println("方法的参数:" + arg);
          }


          System.out.println("在目标类前完成日志:");
          System.out.println("日期:" + new Date());
          }


          }

          • 配置spring配置文件

            • 声明对象,把对象交给容器管理

              • 目标对象
              • 切面对象
              • aspectJ框架中的自动代理生成器标签
                • 自动代理生成器:完成代理对象的自动创建功能
              <?xml version="1.0" encoding="UTF-8"?>
              <beans xmlns="http://www.springframework.org/schema/beans"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns:aop="http://www.springframework.org/schema/aop"
              xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/aop
              https://www.springframework.org/schema/aop/spring-aop.xsd">

              <bean id = "service_1" class= "org.example.ServiceImp.Serviceimp"/>
              <bean id = "aspect_1" class = "org.example.Aspect.Aspect_1"/>
              <aop:aspectj-autoproxy/>
              </beans>
          • 从spring容器中获取目标对象,强转为接口类型(多态)。

          /* 
          test方法
          */
          package org.example;

          import static org.junit.Assert.assertTrue;

          import org.example.Service.Service;
          import org.junit.Test;
          import org.springframework.context.ApplicationContext;
          import org.springframework.context.support.ClassPathXmlApplicationContext;

          /**
          * Unit test for simple App.
          */
          public class AppTest
          {
          /**
          * Rigorous Test :-)
          */
          @Test
          public void test_1()
          {
          String config = "applicationContext.xml";
          ApplicationContext con = new ClassPathXmlApplicationContext(config);
          Service service =(Service) con.getBean("service_1");
          System.out.println(service.getClass().getName());
          service.do_service("matt",19);

          }
          }
        • 目标类没有接口:通过CGLIB实现动态代理

          //目标类:
          package org.example.Service;

          public class Service_1 {
          public void CGLIB_func(){
          System.out.println("===执行无接口的类方法===");
          }
          }

          //切面
          package org.example.Aspect;

          import org.aspectj.lang.ProceedingJoinPoint;
          import org.aspectj.lang.annotation.Around;
          import org.aspectj.lang.annotation.Aspect;

          @Aspect
          public class Aspect_CGLIB {
          @Around(value = "execution(* *.*(..))")
          public Object fun_CGLIB(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

          System.out.println("通过CGLIB执行动态代理:" );
          proceedingJoinPoint.proceed();
          System.out.println("完成CGLIB执行动态代理:" );
          return "success";
          }
          }

        • 有接口也可以使用CGLIB事项动态代理:在配置文件中指明

          <aop:aspectj-autoproxy proxy-target-class="true"/>
          <!--可能效率高点-->
  • Spring集成Mybatis‘

    • 使用ioc:通过ioc创建Mybatis中的对象,由Spring容器进行管理。
  • Web中使用Spring对象。

  • SpringMVC:基于spring的框架:实际就是spring的一个模块:可以使用AOP和IOC ,可以理解为servlet的一个升级。

    • 三层架构:

      • 第一层:SpringMVC:界面层:接受请求,显示处理结果
      • 第二层:Spring,业务层:处理业务逻辑,Spring创建service,dao,工具类等对象。
      • 第三层:MyBatis,持久层,访问数据库。
    • springmvc容器中放控制器对象,使用@Controller注解创建的是一个普通的对象,不是Servlet对象。springMVC赋予了控制器对象额外的功能。

    • web开发底层是servlet,springmvc中有一个对象是Servlet:DispatherServlet负责接收用户的所有请求,之后DispatcherServlet把请求转发给Controller对象。

      • index.jsp-------------->DispatcherServlet(Servlet对象)----------转发,分配--------->Controller对象(@Controller注解创建的对象)。
    • @Controller创建处理器对象,@Service创建业务对象,@Autowired或@Resource在控制器类中注入Service,Service类中注入Dao。

    • 步骤

      1. 加入spring-webmvc依赖,间接加入spring依赖

      2. 加入servlet依赖以及前端页面jsp等依赖

      3. 重点:在web.xml中注册springmvc框架的核心对象DispatherServlet

      4. DispatherServlet也叫中央调度器,是一个Servlet,继承于HttpServlet

        • 作用

          • 创建WebApplicationContext对象,指定读取配置spring配置文件,创建控制器对象
          • 是一个Servlet对象,通过Servlet-Mapping接收用户请求并进行调度
        • 也叫前端控制器

        • 负责接受用户的请求,调用其他的控制器对象,请求处理结果显示给用户

        • 在web.xml中通过Servlet-Mapping配置请求映射,将不同类的请求给指定的中央调度器,中央调度器通过@Controller对象中@RequestMapping指定的请求方法完成请求并返回数据。

        <!--web.xml文件-->

        <?xml version="1.0" encoding="UTF-8"?>
        <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
        version="4.0">

        <!--声明注册核心对象DispatcherServlet
        在tomcat服务器启动后就创建对象实例。
        在创建DispatcherServlet对象时,会同时创建springmvc容器对象
        读取sprinmvc配置文件,把所有对象都创建好,在请求时就可以直接使用。

        DisapatcherServlet的init()方法:
        创建容器读取配置文件:
        WebApplicationContext cont = new ClassPathXmlApplicationContext("springmvc.xml");
        把容器对象放到ServletContext中
        getServlet().setAttribute(key,cont);
        -->
        <servlet>
        <servlet-name>springmvc_controller</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <!--在启动时,创建Servlet对象
        load-on-starup标签:表示在启动后创建对象的顺序。值为整数,值越小,tomcat创建对象得时间越早。
        默认读取的配置文件位置:/WEB-INF/<servlet-name>-servlet.xml
        自定义mvc读取配置文件的位置L:
        -->
        <init-param>
        <!--springmvc配置文件的位置属性:-->
        <param-name>contextConfigLocation</param-name>
        <!--指定自定义文件的位置-->
        <param-value>classpath:springmvc.xml</param-value>
        </init-param>

        <load-on-startup>1</load-on-startup>
        </servlet>

        <servlet-mapping>
        <servlet-name>springmvc_controller</servlet-name>
        <!-- 两种url -pattern的值
        1.使用扩展名,语法:*.xxx,xxx为自定义扩展名。常用*.do,*.action,*.mvc等
        如:http://localhsot:8080/springmvc_controller/service.do
        2.使用斜杠"/"
        -->
        <url-pattern>*.do</url-pattern>
        </servlet-mapping>
        </web-app>
      5. 创建请求页面:

        <%--
        Created by IntelliJ IDEA.
        User: OMEN
        Date: 2021/7/20
        Time: 21:04
        To change this template use File | Settings | File Templates.
        --%>
        <%-- 通过<a href> 指定链接请求的地址--%>
        <%@ page contentType="text/html;charset=UTF-8" language="java" %>
        <html>
        <head>
        <title>Title</title>
        </head>
        <body>
        <p>测试请求</p>
        <p><a href="service.do">发起service.do请求</a></p>
        </body>
        </html>
      6. 创建控制类

        • 类上加入注解@Controller,创建对象,放到springmvc容器中

        • 在类中的方法上面加入RequestMapping注解:请求地址与方法的映射。类上:指定类中所有方法的模块:/test/*.do

        package com.example.controller;

        import org.springframework.stereotype.Controller;
        import org.springframework.web.bind.annotation.RequestMapping;
        import org.springframework.web.servlet.ModelAndView;

        /*
        创建控制器对象
        后端控制器(处理器)
        */

        @Controller
        public class controller_1 {
        /*
        通过方法处理用户提交的请求,springmvc中使用的是方法来处理
        方法是自定义的,可以有多种返回值,多种参数,方法名自定义
        */

        /*

        @RequestionMapping:请求映射,将一个请求于一个方法绑定在一起
        一个请求指定一个方法处理
        属性:1. value:请求得url地址,必须唯一,使用时,推荐地址以“/”开头
        说明:使用@RequestionMapping修饰得方法叫做处理器方法或者控制器方法,可以处理请求,类似于Servlet得doGet,doPost
        */

        /*
        返回值ModelAndView
        Model:数据,请求处理完后显示给用户的数据
        View:视图:比如jsp等等
        */
        @RequestMapping(value = "/service.do") //处理页面的请求地址
        // @ResponseBody
        public ModelAndView doService(){
        System.out.println("进入控制器");
        // 先简单返回数据
        ModelAndView modelAndView = new ModelAndView();

        //添加数据,框架在请求的最后把数据放入request作用域
        //request.setAttribute("msg","返回的图片为:")
        modelAndView.addObject("msg","返回的图片为:");
        modelAndView.addObject("func","执行的方法:");

        //指定视图,视图的完整路径
        //框架对视图执行dorward操作,request.getRequestDispatcher("/show.jsp").forward(...)
        modelAndView.setViewName("show.jsp");

        System.out.println("退出控制器");
        return modelAndView;
        //后期做setAttribute何forward处理
        }

        }
      7. 创建结果页面

      8. 创建springmvc配置文件(spring配置文件)

        • 声明组件扫描器,用于指定**@Controller注解**所在的包名

        • 声明视图解析器:处理视图:

          • 将结果页面放在保护路径中,不可直接访问。用视图解析器:
          <?xml version="1.0" encoding="UTF-8"?>
          <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:context="http://www.springframework.org/schema/context"
          xmlns:mvc="http://www.springframework.org/schema/mvc"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/context
          https://www.springframework.org/schema/context/spring-context.xsd
          http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

          <!--声明组件扫描器-->
          <context:component-scan base-package="com.example.controller"/>
          <!--视图解析器:指定视图的文件的路径,prefix:前缀路径,前后都有“/”,suffix:后缀名。-->
          <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
          <property name="prefix" value="/WEB-INF/pages/"/>
          <property name="suffix" value=".jsp"/>
          </bean>


          </beans>
          //配置视图解析器后只需要文件名:逻辑名指定页面
          modelAndView.setViewName("show");
    • 请求处理过程:

      • 前端页面请求service.do
      • tomcat,通过web.xml的servlet-mapping给对应的中央调度器
      • 中央调度器根据配置的spring配置文件中的Controller对象中的RequestMapping指定的方法处理请求。
      • Contoller对象经得到的ModelAndView转发给前端进行展示
    • 注解开发

      • @RequestMapping

        @RequestMapping(value = "/service.do",method = RequestMethod.GET)
        /*
        属性:method,表示请求的方式。他的值是RequestMethod类枚举类型
        如:RequestMethod.GET,RequestMethodMeThod.POST
        get可用:<a href=""/>
        <br/>
        post:<form action=""/ method="post">
        <input type="submit" value="提交">
        </form>

        */
      • 接受参数:放在处理器方法中的形式参数,用于接受用户的参数

        HttpServletRequest
        HttpServletResponse
        HttpSession
      • 请求中的参数

        • 逐个接受

          • 请求jsp:

            <%--
            Created by IntelliJ IDEA.
            User: OMEN
            Date: 2021/7/20
            Time: 21:04
            To change this template use File | Settings | File Templates.
            --%>
            <%@ page contentType="text/html;charset=UTF-8" language="java" %>
            <html>
            <head>
            <title>Title</title>
            </head>
            <body>
            <p>提交参数</p>

            <form action="picture/first.do" method="post">
            姓名:<input type="text" name = "name">
            账号:<input type="text" name="account">
            密码:<input type="text" name="psw">
            <input type="submit" value="提交">
            </form>
            </body>
            </html>
          • 控制器接收:

            /*
            使用@RequestePara解决请求中参数和处理器方法中形式参数名不相同
            value属性值:为请求中的参数名
            位置放在形式参数定义前
            require属性:默认为true,请求中必须含有西参数,(url中get请求)无参数会报错
            为false,可以为空。

            */
            package com.example.controller;

            import org.springframework.http.HttpRequest;
            import org.springframework.stereotype.Controller;
            import org.springframework.web.bind.annotation.RequestMapping;
            import org.springframework.web.bind.annotation.RequestMethod;
            import org.springframework.web.servlet.ModelAndView;

            import javax.servlet.http.HttpServletRequest;
            import javax.servlet.http.HttpServletResponse;
            import javax.servlet.http.HttpSession;
            import java.net.http.HttpResponse;


            @Controller

            @RequestMapping(value = "/picture")
            public class controller_1 {

            /*
            接收参数过程
            1. 使用Request对象接收
            String name = request.getParaMeter("name");
            String age = request.getParaMeter("age");

            2.mvc框架通过中央调度器调用Controller对象的doSome方法
            此时按照请求的参数名与形参名对应进行传值,并进行类型转换。

            3.如果提交要转换为int数据时填空字符串,字母等,则会发生400错误:客户端异常Integer.valueof(String str)


            */
            @RequestMapping(value = "/service.do",method = RequestMethod.GET)

            public ModelAndView doService(){
            System.out.println("=====进入控制器=====");
            ModelAndView modelAndView = new ModelAndView();

            System.out.println("=====调用的service方法处理图片=====");
            modelAndView.addObject("msg","返回的图片为:");
            modelAndView.addObject("func","执行get请求的方法:");

            modelAndView.setViewName("show");

            System.out.println("=====退出控制器=====");
            return modelAndView;
            }

            @RequestMapping(value = "/first.do",method = RequestMethod.POST)

            public ModelAndView first(String name,int age,String account,String psw){
            System.out.println("=====进入控制器=====");
            ModelAndView modelAndView = new ModelAndView();

            System.out.println("=====调用的service方法处理图片=====");
            modelAndView.addObject("name",name);
            modelAndView.addObject("age",age);
            modelAndView.addObject("account",account);
            modelAndView.addObject("psw",psw);

            modelAndView.setViewName("show");

            System.out.println("=====退出控制器=====");
            return modelAndView;
            }

            }
            <!--4.post方式中文乱码:解决
            设置HtppServletRequest h参数并在控制器代码中指明编码方式
            h.setCharEncoding("utf-8")

            web.xml文件中设置过滤器:自定义或者自定义 -->


            <!--声明过滤器-->
            <filter>
            <filter-name>encodingFilter</filter-name>
            <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
            <!--设置属性参数-->

            <!--设置HttpServletRequest对象使用的编码值-->
            <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
            </init-param>

            <!--强制使HttpServletRequest对象使用上面编码-->
            <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
            </init-param>

            </filter>

            <filter-mapping>
            <filter-name>encodingFilter</filter-name>
            <!--/*表示所有的请求通过过滤器进行过滤-->
            <url-pattern>/*</url-pattern>

            <servlet-name>springmvc_controller</servlet-name>
            </filter-mapping>
        • 对象参数接受:接收多个参数

          • 优点一个对象参数接收多个参数,缺点,名字必须一致,且要有set,get方法。

            package com.example.controller;

            /*
            对象接收参数,属性名与请求参数名一致
            set方法与get方法
            */

            public class Picture {
            String name;
            String age;

            public Picture(){
            System.out.println("创建picture对象节进行参数接收");
            }
            public void setName(String name) {
            this.name = name;
            }

            public void setAge(String age) {
            this.age = age;
            }

            public String getName() {
            return name;
            }

            public String getAge() {
            return age;
            }
            }

            处理器方法:

            @RequestMapping(value = "/receiveObject.do",method = RequestMethod.POST)
            public ModelAndView first(Picture picture){
            System.out.println("=====进入控制器=====");
            ModelAndView modelAndView = new ModelAndView();

            if("".equals(picture.name) ||"".equals(picture.age) ){

            System.out.println("=====参数为空处理=====");
            modelAndView.setViewName("show_400");
            }
            else {

            System.out.println("=====调用的service方法处理图片=====");
            modelAndView.addObject("name", picture.name);
            modelAndView.addObject("age", picture.age);
            modelAndView.addObject("picture",picture);


            modelAndView.setViewName("show");

            }
            System.out.println("=====退出控制器=====");
            return modelAndView;
            }
          • 控制器方法返回值

            • ModelAndView:Model数据部分(最终在Request作用域里),View视图进行转发操作。同时用数据和视图

            • String:只进行页面跳转:逻辑名称或完全路径。

              • 可以手动添加数据到Request域:

                @RequestMapping(value = "/jump.do")
                public String jump(HttpServletRequest httpServletRequest,String name,String age){
                System.out.println("=====进入控制器=====");

                httpServletRequest.setAttribute("name",name);
                httpServletRequest.setAttribute("age",age);
                System.out.println("=====调用的service方法处理图片=====");


                System.out.println("=====退出控制器=====");
                return "show";
                }
            • void:不能表示数据,也不表示视图。处理ajax,可以使用void,通过HttpServletResponse输出数据,服务器只返回数据,和视图无关。

            • Object:响应Ajax,返回数据与视图无关。

              • 步骤

                • 加入处理json的工具库依赖

                • 对象转成json:

                  <mvc:annotation-driven>
                • 在处理器方法上加入@ResponseBody注解:进行输出

          • Tomcat可以处理静态资源:html,js,jsp等等,有一个默认Servlet,启动时创建

            • 还可以处理未映射的请求。

            • 自己的web.xml文件url-pattern为"/"时会替代tomcat的默认Servlet,中央处理器不会处理静态资源。

              • 需要在springmvc配置文件中添加标签,创建处理静态资源的控制器,最终是转发给tomcat进行处理。** **转发给默认控制器处理。

                <mvc:annotation-driven/>    
                <mvc:default-servlet-handler/>
              • 和RequestMapping有冲突,需要加入注解驱动解决

          • 第二种处理静态资源。同样有冲突,加注解驱动

            <mvc:annotation-driven/>    
            <mvc:default-servlet-handler/>