SSM学习总结

前言

        经过二十天的学习,终于算是看完了黑马的SSM整合,还是边学边玩,真的又浪费了时间,往后努力吧!!!
        终于到了框架阶段,现在也算是基本了解了使用,总结一下,以免后面忘记,也方便以后回顾,现在已经感觉到前面的忘完了,借此机会也巩固一下总体的知识点,黑马课程的资料https://pan.baidu.com/s/1LxIxcHDO7SYB96SE-GZfuQ 提取码:dor4

知识点梳理

  按自己的Maven项目梳理

Spring IOC

包含内容:Bean标签的基础配置,Bean的生命周期,各种数据类型的各种方式的依赖注入,Spring相关API

<?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:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
xml再学
    在引用schema约束文件(xsd),步骤如下
        1.填写xml根元素
        2.引入xsi前缀. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance",有很多取值,我们一般用这个
        3.引入命名空间xsi:xsi:schemaLocation="约束1名称(随便起但要遵循url格式) 约束1地址(本地,网络都可以)
                                    约束2名称(随便起但要遵循url格式) 约束2地址(本地,网络都可以)"
        4.为每一个xsd约束声明一个前缀(可以有一个不声明,便是默认的命名空间)
            xmlns:前缀="约束1名称"
            !!!为什么P命名空间xmlns:p="约束名"我这里没有定义
        5.使用约束1的标签
            <前缀:标签></前缀:标签>
-->
<!--
    配置dao层实现类,解耦service与dao层,
        java反射是通过找全类名然后通过无参构造,所以一定要有无参改造方法
        1.Bean标签范围配置
            1.scope:指对象的作用范围
                singleton   默认值,单例的
                prototype   多例的 (原型)
                request     web项目中,Spring创建一个Bean对象,将对象存放到request域中
                session     同上,存到session域中
                global session  web项目中,应用在Portlet环境,如果没有Portlet环境那么globalSession相当于session
                    <bean id="userDao" class="com.muyu.dao.impl.UserDaoImpl" ></bean>
            2.去看Bean中scope在不同取值时的对象创建时机(因为是通过无参创建,所以复写无参构造便可看到什么时候创建)
                测试说明scope为singleton的Bean,在加载时被创建,且每加载一次,便会创建一个对象.
                scope为prototype,为在调用getBean获取Bean是被创建.
-->
<!--
        2.Bean生命周期配置
            init-method="init" 初始化方法
            destroy-method="destroy" 销毁方法
                如果用ApplicationContext类型,容器会自动关闭,没有手动关闭,所以在没有调用destroy方法就关闭了,
                如果想看到调用到destroy方法,可以强制转成ClassPathXmlApplicationContext类型(或者直接用这个类型),调用close方法
      <bean id="" class="" init-method="init" destroy-method="destroy"></bean>
-->
<!--
        3.Bean实例化的三种方式
            无参构造方法实例化
            工厂(静态)方法实例化 (创建一个工厂对象,然后添加相应静态方法)
                <bean id="" class="静态工厂的全类名" factory-method="静态工厂的方法"></bean>
            工厂(实例)方法实例化 (创建一个工厂对象,添加一个不是静态的方法)[所以需要先有工厂对象实例,才能调用]
                <bean id="DF" class="工厂对象"></bean>
                <bean id="" factory-bean="DF" factory-method="方法"></bean>
-->
<!--
        4.Bean的依赖注入
            ref代表数据引用注入,value代表普通数据
            什么时候注入,与Bean标签范围配置什么时候创建对象相同
            概念
                依赖注入(DependencyInjection):它是Spring框架核心IOC(反转控制)的具体变现.
                在编写程序时,通过控制反转,把对象的创建交给Spring,代码中不可能出现没有依赖的情况,
                IOC解耦只是降低了他们的依赖关系,但不会消除,例如【业务层仍然会调用持久层方法】
                那这种业务层与持久层的依赖关系,在使用spring之后,就让spring来维护.(即:坐等框架把持久层传入业务层)
            实例: 在实际项目中Service层还需要调用Dao层的数据,如果不使用依赖注入,实现如下
                [controller层:]{getBean("UserService").方法()} [service层:]{getBean("UserDao").方法()},整体耦合性还是太高
            使用:(如果不从容器中获取,则Service中不会给Dao赋值)
                1.使用构造方法注入:
                    传统注入:
                        在service层中创建UserDao对象及构造方法(一定要有无参构造)
                        <bean id="userServiceConstructor" class="com.muyu.service.impl.UserServiceImpl">
                            <constructor-arg name="dao" ref="userDao"/>
                        </bean>
                    C命名空间注入:
                        c命名空间之前也需要通过xmlns:c="http://www.springframework.org/schema/c"
                        <bean id="uS" class="ServiceImpl" c:dao-ref="userDao"/>
                2.使用set方法注入:
                    传统注入:
                        在service层中创建UserDao对象及setUserDao()方法
                        在applicationContext.xml配置
                        <bean id="userDao" class="Dao全类名"></bean>
                        <bean id="uS" class="Service全类名">
                            <property name="service类中dao属性(我这里是dao)" ref="userDao"></property>
                        </bean>
                    P命名空间注入:
                        在<beans>中添加命名空间  xmlns:p="http://www.springframework.org/schema/p"
                        <bean id="uS" class="Service全类名" p:dao-ref="userDao"/>
                3.依赖注入数据类型
                        上面操作都是注入的引用Bean,除了对象引用可以注入,普通数据类型,集合等都可以在容器中注入
                    注入普通数据类型(将引用数据类型的ref换成value) : set方式注入 , constructor方式注入
                    注入引用数据类型(Bean)
                    注入集合数据类型(基本同理)
                        <property name="strList">list
                            <list>
                                <value>aaa</value>
                                <value>'bbb'</value>
                                <value>ccc"</value>
                            </list>
                        </property>
                        <property name="userMap">//map
	                        <map>
	                            <entry key="u1" value-ref="user1"></entry>
	                            <entry key="u2" value-ref="user2"></entry>
	                        </map>
                        </property>
                        <property name="properties">//properties类型,继承了Hashtable<Object,Object>
                            <props>
                                <prop key="p1">ppp1</prop>
                                <prop key="p1">ppp2</prop>
                                <prop key="p2">ppp3</prop>
                                <prop key="p3">ppp4</prop>
                            </props>
                        </property>

-->
<!--
        5.引入其他配置文件(分模块开发)
            在实际开发中Spring的配置非常多,这导致Spring配置很繁琐且体积庞大,
            所以可以将部分配置拆解到其他配置文件中,而在spring主配置文件中通过import标签进行加载
                <import resource="applicationContext-xxx.xml"/>
-->
<!--
    Spring的重点配置
        <bean>标签
            id属性:在容器中bean实例的唯一标识
            class属性:要实例化的Bean全限定名
            scope属性:Bean的作用范围
            <property>标签: set属性注入
                name属性:属性名称
                value属性:注入的普通属性值
                ref属性:注入的对象引用
                <list>标签
                <map>标签
                <props>标签
            <constructor-arg>标签:构造方法注入
        <import>标签导入其他Spring分文件
-->
<!--
Spring相关API
    1.ApplicationContext的实现类
        1.ClassPathXmlApplicationContext
            从类的根路径下加载配置文件(在Maven项目中就是resources)
        2.FilSystemXmlApplicationContext
            从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置
                new FileSystemXmlApplicationContext("E://java//applicationContext.xml");
        3.AnnotationConfigApplicationContext
            是有注解配置容器对象,需要使用此类创建spring容器,他用来读取注解
    2.getBean()方法使用
        Object getBean(String name);
        T getBean(Class<T> requiredType);//如果容器中存在多个类型的Bean则会报错
-->
<!--
Spring配置数据源(连接池)(详细见spring_ioc_anno中test)
    数据源的作用
        数据源是提高程序性能出现的,实现实例化数据源,初始部分链接资源
        使用链接资源时从数据源中获取,使用完毕后将链接资源归还数据源
    常见数据源:DBCP,C3P0,BoneCP,Druid等

-->
</beans>

Spring-IOC-anno

包含内容:再温数据源,Spring注解开发,Spring集成Junit

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--
Spring配置数据源(连接池)(详细见spring_ioc_anno)
    1.数据源的作用
        数据源是提高程序性能出现的,实现实例化数据源,初始部分链接资源
        使用链接资源时从数据源中获取,使用完毕后将链接资源归还数据源
        常见数据源:DBCP,C3P0,BoneCP,Druid等
    2.C3P0配置
        ComboPooledDataSource ds = new ComboPooledDataSource();
        ds.setDriverClass(driver);ds.setJdbcUrl(url);ds.setUser(name);ds.setPassword(password);
        Connection conn = ds.getConnection();conn.close();
    3.Druid配置
         DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driver);ds.setUrl(url);ds.setUsername(name);ds.setPassword();
        Connection conn = ds.getConnection();conn.close();
    4.使用spring容器配置(druid)解释使用set方式注入 ,注意set方法属性
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value=""></property>
            <property name="url" value=""></property>
            <property name="username" value=""></property>
            <property name="password" value=""></property>
        </bean>
    5.抽离配置文件,虽然在spring容器中配置已经解耦合了,但是不符合要求,要求jdbc单独配置
        1.加载properties配置文件(applicationContext.xml加载jdbc.properties配置文件获取连接信息)
            1.需要引入context命名空间和约束路径:
                命名空间:xmlns:context="http://www.springframework.org/schema/context"
                约束路径:http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
            2.通过context命名空间加载配置文件 <context:property-placeholder location="classpath:jdbc.properties"/>
                位置:classpath:代表resources位置
            3.通过SEL表达式类似于jsp中EL表达式${key}"
-->
<!--
Spring注解开发
    1.Spring原始注解
        spring是轻代码重配置的框架,配置比较繁重,影响程序开发效率,所以注解开发是一种趋势,注解替代xml配置文件可以简化配置提升开发效率
            (原始注解:出现比较早的(主要替换<Bean>的配置),,新注解:出现比较晚)
        内容
            注解                  说明
            @Component      使用在类上用于实例化Bean
                可在相应的层级上加相应的衍生注解来替换,增加可读性
            [衍生注解]@Controller     使用在web层类上用于实例化Bean
            [衍生注解]@Service        使用在service层类上用于实例化Bean
            [衍生注解]@Repository     使用在dao层类上用于实例化Bean
            @Autowired      使用在字段上用于根据类型依赖注入
                如果只有这一个注解,则会按着数据类型,从Spring容器中进行匹配
                类似于T getBean(Class<T> requiredType);//如果容器中存在多个类型的Bean则会报错
            @Qualifier      结合@Autowired一起使用,用于根据名称进行依赖注入
            @Resource       相当于@Autowired+@Qualifier,按照名称进行注入
                @Resource(name="userDao")//相当于上面两个,但注解没有value,所有用需要加上相对的名称
            @Value          注入普通属性
                @Value("aaa")String driver如果直接用普通这种方式,那还不如直接初始化变量
                所以可以结合SEL表达式让它变得有意义
            @Scope          标注Bean的作用范围
            @PostConstruct  使用在方法上标注该方法是Bean的初始化方法
            @PreDestroy     使用在方法上标注该方法是Bean的销毁方法
        使用步骤:
            1.应该要先配置组件扫描,让程序能够在知道需要扫描哪里的包(前提是要有context命名空间)
                第一种
                    <context:component-scan base-package="com.muyu"/>
                第二种
                    <context:component-scan base-package="com.muyu">
                        /*一个<component-scan>只能有一种(可多个)<exclude-filter>或<include-filter>标签
                            <exclude>代表扫描不是这样的,<include>表示扫描这样的,
                                type属性:annotation注解 regex正则表达式 assignable可转让的 custom惯例 aspectj方面
                            例<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>*/
                        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
                        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
                    </context:component-scan>
            2.在需要搭地方添加注释(不过好像没办法一个类为多个id了,因为@Component只有一个String类型的,且还不是数组)
        使用问题
            1.利用上述内容实现注解开发,不过好像和applicationContext.xml中id不冲突
                如果xml与注解中都有则按着xml配置走,不重名则各走各的,且可互相调用
            2.注解竟然可以直接添加到属性上,这就既不用constructor配置,也不用使用set方法,直接可以注入
                @Autowired/*自动注入*/
                @Qualifier("userDao")/*要被注入的id*/
                private UserDao dao;
    2.Spring新注解(可能到Springboot后会经常看到)
            因为原始注解要找到源码进行注解添加,所以对于外部的类便没有办法
        解决问题(上面注解不能全部替代xml配置文件,还需使用新注解配置如下)
            非定义的Bean配置:<bean>
            加载properties文件的配置:<context:property-placeholder>
            组价扫描配置:<context:component-scan>
            引入其他文件<import>
        内容
            注解                  说明
            @Configuration      用于指定当前类是一个Spring配置类,当创建容器时会从该类上加载注解
            @ComponentScan      用于指定Spring在初始化容器时要扫描的包.
                                作用与xml配置中<context:component-Scan base-package=""/>一样
            @Bean               使用在方法上,标注该方法返回值储存到Spring容器中
            @PropertySource     用于接在.properties文件的配置
            @import             由于导入其他配置类
        步骤
            1.创建Spring核心配置类(@Configuration,只有一个便可{可以多个,但是不能嵌套,即:A导入了B,B又导入了A},其他使用import导入)及其他配置类
            2.根据以上注释完全替代xml配置
            3.更改ApplicationContext的获取方法(三个获取该类的API)
                更改为new AnnotationConfigApplicationContext(SpringConfiguration.class);
                //如果xml配置了组件扫描也可以使用该ClassPathXmlApplicationContext
    3.Spring集成Junit
        问题:在测试类中,每个测试方法都有以下两行代码,这两行代码获取容器,如果不写,直接提示空指针,所以不能轻易删掉
                ApplicationContext app=new ClassPathXmlApplicationContext("bean.xml);
                IAccountService as = app.getBean("accountService",IAccountService.class);
        解决: 让SpringJunit负责创建Spring容器,但需要降配置文件名称告诉它
              将需要进行测试Bean直接在测试类中注入
        步骤:
            1.导入spring集成Junit的坐标(spring-test并不在spring-context中)
                需要单独导入springframework中spring-test
            2.使用@Runwith注解替换原来的运行期,谁去跑测试
                @RunWith(SpringJUnit4ClassRunner.class)
            3.使用@Contextconfiguration指定配置文件或配置类
                @ContextConfiguration("classpath:applicationContext.xml")//配置文件
                @ContextConfiguration(classes=SpringConfiguration.class)//配置类
                从日志文件中看出这两个执行步骤可能不同
            4.使用@Autowired注入需要测试的对象
                @Autowired @Qualifier("userService") private UserService userService;
                要测试谁就注入谁,就是原始注解
            5.创建测试方法进行测试
                测试时,报错java.lang.ExceptionInInitializerError(初始化异常)
                  错误信息里有java.lang.IllegalStateException: SpringJUnit4ClassRunner requires JUnit 4.12 or higher.
                我用的是spring 5.0.5.RELEASE和junit4 4.11测试时抛出该异常,将junit4换为4.12后问题解决。
-->
</beans>

Spring MVC

包含内容:
  Spring集成Web环境, Spring简介及配置(后面会稍微详细的整理一下整体的配置),
  SpringMVC各组件, MVC请求响应, MVC获取请求数据(各数据类型)
    手动配置视图解析器,配置处理器映射器(用作返回对象数据类型,配置注解驱动即可自动加载),自定义类型转换器
  文件上传案例,各乱码处理办法,静态资源不能加载

	<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--
Spring集成web环境
    1.1ApplicationContext应用上下文获取方式
        问题描述
            应用上下文配置是通过new ClasspathApplicationContext(spring配置文件)方式获取的,但是每次从容器中获取bean时都要编写这句话,
            这样的弊端是配置文件多次加载,应用上下文对象多次创建
        解决(可以使用静态代码块之类的,最好的是如下方式)
            在web项目中,可以使用ServletContextListener监听web应用的启动,我们可以在web启动时,就加载Spring的配置文件,创建上上下文对象ApplicationContext,
            再将其存储到最大的域ServletContext域中,这样就可以在任意位置从狱中获取应用上下文对象了.
        优化:
            这样是解决了多次加载的问题,但是好多东西都是耦合死的,必须将解耦贯彻到底
            1.配置文件名称   配置web.xml全局初始化参数
            2.存在servletContext域中的名称 编辑工具类,隐藏读取servletContext中ApplicationContext的读取细节
    1.2 Spring提供获取应用上下文工具(和自己写的差不多)
        描述:Spring提供了一个监听器ContextLoaderListener就是对上述的封装,该监听器内部加载Spring配置文件,创建应用上下文对象,并储存到servletContext域中
            提供了一个客户端工具WebApplicationContextUtils供使用者获取应用上下文对象
            所以我们需要做两件事1.在web.xml中配置监听器 2.使用Utils工具获取对象
        步骤:
            1.导spring-web包(坐标)(spring是把监听器封装到了这个包中)
            2.配置ContextLoaderListener
                <listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>
            3.配置全局参数
                <context-param>
                    <param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value>
                </context-param>
            4.使用WebApplicationContextUtils获取应用上下文
                WebApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(servletContext);
-->

<!--
SpringMVC简介
    概述
        springMVC是一种基于Java实现的mvc设计模式的驱动类型的轻量级web框架,属于SpringFrameWord的后续产品,已经融合到了Spring webFlow中.
        他通过一套注解,让一个简单的java类变成处理请求的控制器,而无需实现任何接口,同时它还支持RESTful编程风格的请求
    请求过程:1.客户端请求tomcat服务器,
            2.tomcat引擎接收客户请求,封装request与response
            3.调用请求资源
        请求资源中存在共有行为与特有行为,springmvc就是通过(前端控制器)实现的servlet来接管共有行为,然后调用POJO(普通java文件)的特有行为
    使用步骤:
        1.导入SpringMVC
            <groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.0.5.RELEASE</version>
        2.配置SpringMVC核心控制器DispatcherServlet,并配置spring-mvc.xml
            //配置SpringMVC的前端控制器
            <servlet>//配置servlet
                <servlet-name>DispatcherServlet</servlet-name>
                <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
                //这个要在load-on-startup前面
                <init-param>//这个在第五步
                    <param-name>contextConfigLocation</param-name>
                    <param-value>classpath:spring-mvc.xml</param-value>
                </init-param>
                //代表服务器启动时就加载该servlet
                //不配则为第一次访问时加载
                <load-on-startup>1</load-on-startup>
            </servlet>
            <servlet-mapping>
                <servlet-name>DispatcherServlet</servlet-name>
                <url-pattern>/</url-pattern>[/]代表缺省的servlet,每次任何请求都要走这个servlet
            </servlet-mapping>
        3.编写POJO(在springMVC一般称作Controller(控制器))
        4.将Controller使用注解配置到Spring容器中(@Component @Controller[用这个])
            //4.放入Spring容器
            @Controller
            //3.编写controller视图
            public class UserController {
                @RequestMapping("/quick")
                //配置请求映射,即在访问/quick是,会调用该方法,并跳转到你返回的那个资源
                public String save(){
                    System.out.println("Controller save running...");
                    return "success.jsp";//return返回的视图
                    /*
                    这个return地址省略的是forward:或redirect:
                    根据源码可知
                        在spring-webmvc-5.0.5.RELEASE.jar!/org/springframework/web/servlet/DispatcherServlet.properties配置文件中找到视图解析器ViewResolver
                        然后到相应的类中得知它是将[:]为分隔符,分为前缀与后缀, (String prefix, String suffix) {this();this.setPrefix(prefix);this.setSuffix(suffix);}
                        前缀便是转发方式,后缀便是资源地址
                    */
                }
            }
        5.在spring-mvc.xml配置组件扫描
            <context:component-scan base-package="com.muyu.controller"/>
        6.执行测试
            http://localhost:8080/spring_mvc/user/quick
-->
<!--
SpringMVC组件解析
    SpringMVC的执行流程
        见webapp/img中图一图二(放在了下面)
SpringMVC注解解析
    @RequestMapping 请求映射
        作用:用于建立请求URL和处理请求方法的对应关系
        位置:
            类上,请求UR:的第一级目录.此处不写的话,就相当于根目录
            方法上: 请求URL的第二级访问目录,与类上的使用@RequestMapping标注的一级目录一起组成访问虚拟路径
        参数:
            value:由于指定请求URL.他和path属性作用一样的
            method:用于指定请求的方式RequestMethod.{GET POST...}
            params:用于指定限制请求参数条件.它支持简单表达式.要求请求参数的key与value必须配置的一模一样
                params = {"accountName"},表示请求参数必须有accountName
                params ={"money!100*"},表示请求参数中money不能是100
SpringMVC组件解析(视图解析器...)
    SpringMVC用默认组件的配置,默认组件配置都在DispatcherServlet.properties配置文件中配置的
    SpringMVC的xml配置解析(spring-mvc.xml)[相关组件]
        前端控制器 DispatcherServlet 手动配置web.xml,在SpringMVC第二步 调用其他功能组件
        处理器映射器 HandlerMapping 解析返回处理器执行链
        处理器适配器 HandlerAdapter 调用处理器(Controller,后端适配器),返回ModelAndView
        处理器:Handler 返回ModelAndView
        视图解析器 ViewResolver 解析返回的View
            默认配置:org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
            手动配置:(可以配置多个可以编辑优先级order,不配默认是按第一个配置的视图走)
                <bean id="viewResolverAA" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                    <property name="prefix" value="/"/>//前缀,不能配置转发方式/redirect:/不行
                    <property name="suffix" value=".jsp"/>//后缀
                    //只需要return success 就可以转发到/success.jsp
                    //配置了还是不影响重定向与转发的定义,只不过这个配置就没用了,你只要写上转发类型:资源路径,就不会用这个配置
                </bean>
        视图 View

组件扫描又有新知识(见spring_ioc_anno中app.xml原始注解)
-->

<!--
SpringMVC的数据响应
    SpringMVC的数据响应方式
        1.页面跳转(需要跳转页面的)
            直接返回字符串 会结合解析器前后缀拼接后跳转,重定向不能访问到WEB-INF里资源
            通过ModelAndView对象返回
                见UserController save1-5,相对简单不过多赘述
        2.回写数据(只需回写数据的)
            //需要添加@ResponseBody,告知SpringMVC框架此方法是回写数据的
            直接返回字符串
                //第一种方式: 不需要@ResponseBody注解,定义参数HttpServletResponse,然后调用response.getWriter().print() 返回值为void,不能定义String返回空,那样是根目录
                //第二种就是添加注解,简单返回
            返回对象或集合
                //第一种:导入JACKSON相应的包 jackson-core jackson-databind jackson-annotations SpringMVC版本5.0.5 Jackson版本2.9.5
                    //然后使用ObjectMapper序列化为json字符串
                //第二种配置处理器映射器 HandlerAdapter 不需要自己引入Jackson但是好像会有警告
                    HandlerAdapter不知道为什么DispatcherServlet.properties中的HandlerAdapter好像找不到类
                    这样返回对象或者集合时就可以直接用JACKSON进行解析,但是仍需要注解@ResponseBody
                    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
                        <property name="messageConverters">
                            <list>
                                <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
                            </list>
                        </property>
                    </bean>
                //第三种使用第二种配置相当复杂,因此我们使用mvc的注解驱动替代上述配置<mvc:annotation-driven/>
                    <mvc:annotation-driven/>作用
                        在SpringMVC的各个组件中,处理器映射器,处理器适配器,视图解析器称为SpringMVC的三大组件'
                        使用<mvc:annotation-driven>自动加载RequestMappingHandlerMapping(处理映射器)和
                        RequestMappingHandlerAdapter(处理适配器),可用在Spring-xml.xm配置文件中使用
                        <mvc:annotation-driven>替代注解处理器和适配器的配置,
                        同时使用<mvc:annotation-driven>默认底层就会集成jackson进行对象或集合的son格式字符串的转换.
                    所以添加这个配置就可以不用自己配置Jackson了
-->
<!--
SpringMVC获取请求数据
    1.获取请求参数
        客户端请求参数格式为name=value&name=value..客户端获取请求参数,优势还需要进行数据的封装,SpringMVC可以接受如下类型参数
            基本数据类型
             POJO类型
            数组类型
                上面三种都比较简单,不做赘述,案例见Controller中save9-10()
            集合类型
                方式一:将要获取集合对象封装成一个POJO(简单javabean,必须要get,set方法),并且提交表单时必须按着POJO的名称传递
                    @RequestMapping(value = "/quick11")@ResponseBody
                    public void save11(VO vo) {System.out.println(vo);}
                方式二:通过Ajax请求的参数,并设置contextType:"application/json;charset=utf-8"
                    @RequestMapping(value = "/quick12")@ResponseBody
                    public void save12(@RequestBody List<User> userList) {
                        System.out.println(userList);
                    }
    2.参数绑定注解@RequestParam
        当请求参数名称与Controller的业务方法参数名称不一致时,就需要通过该注解显示绑定
            save13(@RequestParam("请求的名称") String 形参),
        参数
            value:绑定的请求参数名称 required:指定此参数一定存在,不然报错,默认为true
            defaultValue:当没有请求参数时,则使用此值, 如果使用此参数,则required没有用了
    3.获取Restful风格的参数
        Restful是一种架构风格,设计风格,而不是标准,只是提供了一组设计原则和约束.主要用于客户端和服务器端交互类的软件,基于这个风格设计的软件公家简介,共有层次,更容易实现缓存机制等
        Restful风格的请求是使用"URL+请求方式"代表依次请求的目的,http协议里面四个表示操作的动词如下
            GET:用于获取资源  POST用于新增资源  PUT用于更新资源  DELETE:由于删除资源
            例如 /user/1 GET: 得到id为1的user /user/1 DELETE 删除id为1的user
                /user/1  PUT: 更新id为1的user /user  POST  新增user
           上述url地址/user/1中1就是要获取的请求参数,在SpringMVC中可以使用占位符进行参数绑定,@RequestMapping("/user/{id}")就意味着id可以获取1
           然后通过注解@PathVariable(value="id")对参数进行绑定,从而是参数可以获取URL中的参数
           例:@RequestMapping(value = "/quick13/{name}")@ResponseBody
             public void save13(@PathVariable(value ="name") String username) {System.out.println(username);
        但是我还是不知道请求方式有什么用(看来我的猜测没有错,见Restful.jsp)
            可以将RequestMapping配置四个相同的value,然后设置请求方式便可以做到,相同的地址相应的请求方式执行相应的代码
            但是HTML不支持put与delete这两种请求方式,只能通过Ajax实现
    4.自定义类型转换器  SpringMVC默认已经提供了一下类型转换器,但是不是所有数据类型都提供了转换器,
            没有提供的就需要自定义转换器,例如日期类型的数据
        步骤:1.定义转换器实现Converter接口
            2.在配置文件中声明转换器
            <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
                <property name="converters">
                    <list>
                        配置自定义日期转换器
                        <bean class="com.muyu.converter.DataConverter"></bean>
                        //<bean class="com.muyu.converter.IntConverter"></bean>
                        //写着玩,证明是按着<S,T>这两个类型来判断用哪个,替换了就用不了SpringMVC的了
                    </list>
                </property>
            </bean>
            3.在<mvc:annotation-driven conversion-service="conversionService">中引用转换器
        但是自定义完了就不能用原先的了,
            他应该是按着implements Converter<String, Date>这两个的类型判断的,
            自己写了个String->Integer的(写死,就返回66),结果所有要由String转int的值都为66,笑死
    5.获取Servlet相关API(还是依靠注入)
        SpringMVC支持使用原始servletAPI对象作为控制器形参进行诸如,常用对象HttpServletRequest HttpServletResponse HttpServletSession
    6.获取请求头@RequestHeader
        使用@RequestHeader可以获取请求头信息,相当于web阶段学习的request.getHeader(name)
            属性如下 value:请求头名称 required:是否携带此请求头 默认为true
        使用@CookieValue可以获取获取cookie的信息
            属性如下 value:请求头名称 required:是否携带此Cookie 默认为true
    7.文件上传
        文件上传三要素:
            1.文件上传项,
            2.文件上传项表单是post提交
            3.表单的enctype属性是多部分表单信息,即enctype="multipart/form-data"
            <form action="/user/quick" method="post" enctype="multipart/form-data">
                名称:<input name="name"/><input type="file" name="file"><input type="submit"></form>
        enctype="multipart/form-data"请求体数据:
            -WebKitFormBoundaryMWfi8WNeNmCPYB8B
            Content-Disposition: form-data; name="name"

            name
            -WebKitFormBoundaryMWfi8WNeNmCPYB8B
            Content-Disposition: form-data; name="file"; filename="abc.txt"
            Content-Type: text/plain

            这是文件
            -WebKitFormBoundaryMWfi8WNeNmCPYB8B-
        单文件上传步骤
            1.导入fileupload和io的坐标
                <groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId>
                <groupId>commons-io</groupId><artifactId>commons-io</artifactId>
            2.配置文件上传解析器
                <bean id="multipartResolver"
                          class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
                        上传文件总大小
                    <property name="maxUploadSize" value="5242800"/>
                    上传单个文件总大小
                    <property name="maxUploadSizePerFile" value="5242800"/>
                    上传文件编码方式
                    <property name="defaultEncoding" value="UTF-8"/>
                </bean>
            3.编写文件上传代码
                前端符合文件上传三要素
                后端MultipartFile参数与前端文件input的name相同
                	@RequestMapping(value = "/quick16")
				    @ResponseBody //文件上传
				    public void save16_1(MultipartFile uploadFile) throws IOException {
				        //获取文件名称
				        //uploadFile.getName();//这个是表单那个名称
				        String file_name = uploadFile==null?"为空":uploadFile.getOriginalFilename();//这个是文件名称
				        //拷贝到某地方
				//        uploadFile.transferTo(new File(file_name));//会拷贝到tomcat,bin目录下D:\Program Files\Apache Software Foundation\Tomcat 9.0.45\bin\abc.txt
				        System.out.println(file_name);
				    }
    在回写数据时出现乱码
        解决1:
            <mvc:annotation-driven conversion-service="conversionService">&lt;!&ndash;这个可以&ndash;&gt;
                <mvc:message-converters register-defaults="true">
                    <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                        <property name="defaultCharset" value="UTF-8"/>
                        <property name="writeAcceptCharset" value="false"/>
                    </bean>
                </mvc:message-converters>
            </mvc:annotation-driven>
            说明
                替换其中的StringHttpMessageConverter,它是用来将String写到response中;
                修改的两个属性说明:defaultCharset改为UTF-8(项目字符集)即可正确显示中文,因为默认是ISO-8859-1格式;
                writeAcceptCharset修改为false,即可看到响应头清爽很多,节省资源;
        解决2:@RequestMapping(value = "/quick14",produces = {"text/plain;charset=utf-8","text/html;charset=utf-8"})
            //乱码解决指定响应的字符集为utf-8,就不会再用StringHttpMessageConverter的字符集了;
        博客:https://www.cnblogs.com/lvbinbin2yujie/p/10611415.html
    在获取请求参数是遇到的问题(都是集合)
        1.使用方式一时,POJO没有设置get方法导致失败
        2.在发送json是遇到的
            4.post请求参数乱码问题 这个存在乱码问题,原先通过request.setCharacterEncoding("utf-8");现在可以使用配置过滤器,设置编码方式(web.xml)
                <filter>
                    <filter-name>CharacterEncoderFilter</filter-name>
                    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
                    <init-param>//配置编码方式
                        <param-name>encoding</param-name>//没有提示
                        <param-value>UTF-8</param-value>
                    </init-param>
                </filter>
                <filter-mapping>
                    <filter-name>CharacterEncoderFilter</filter-name>
                    <url-pattern>/*</url-pattern>
                </filter-mapping>
            3.ajax请求成功但是报415错误,因为我用的是dataType="application/json",而不是contextType="application/json;charset=utf-8",使用后可以了
            2.jQuery不能运行,因为<script>必须是成对的,不能自闭和,所以报错
            1.静态资源不能加载
                原因:因为在配置SpringMVC的前端控制器是时是缺省的,及所有资源都会走这个servlet,那经过这个资源的路径都或被解析成Controller(RequestMapping)中的资源路径,当然找不到
                解决:1.配置开放某些资源的访问
                        <mvc:resources mapping="/js/**" location="/js/"/>
                        //                      请求路径        目录
                        <mvc:resources mapping="/img/**" location="/img/"/>
                        //如果是这个请求路径,则去location中寻找
                    2.(建议使用)配置使用[默认的Servlet](tomcat)来响应找不到的文件
                        <mvc:default-servlet-handler/>
                    3.在web.xml配置Tomcat的defaultServlet来处理静态文件
                        <servlet-mapping>
                            <servlet-name>default</servlet-name>
                            <url-pattern>*.css</url-pattern>
                        </servlet-mapping>
                        要写在DispatcherServlet的前面,让 defaultServlet先拦截请求,这样请求就不会进入Spring了,我想性能是最好的吧。
                        Tomcat, Jetty, JBoss, and GlassFish 自带的默认Servlet的名字  "default"
                        Google App Engine 自带的 默认Servlet的名字  "_ah_default"
                        Resin 自带的 默认Servlet的名字  "resin-file"
                        WebLogic 自带的 默认Servlet的名字   "FileServlet"
                        WebSphere  自带的 默认Servlet的名字  "SimpleFileServlet"
                            博客:https://blog.csdn.net/hello5orld/article/details/9407905
                    4.在web.xml只对.do进行拦截(这样就只会拦截.do这样的url,css等静态资源就可以访问了)
                        <servlet-mapping>
                            <servlet-name>DispatcherServlet</servlet-name>
                            <url-pattern>/.do</url-pattern>
                        </servlet-mapping>
-->
</beans>

SpringMVC执行顺序

Spring MVC Interceptor

Spring JDBC与Spring Test(练习案例就不说了)
 包含内容:
  Spring MVC Interceptor作用
  SpringMVC中异常处理
    配置MVC提供的简单处理器,自定义异常处理器

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<!--
SpringMVC拦截器
    1.拦截器(interceptor)作用
        Spring MVC的拦截器类似于Servlet开发中的过滤器Filter,用于对处理进行预处理与后处理
        将连接器按一定顺序连成一条链,这条链称为连接器链(Interceptor Chain).在访问被拦截的方法或字段是,拦截器链中的拦截器就会按其执勤定义的顺序被调用,拦截器也是AOP思想的具体实现
    2.连接器与过滤器的区别()很多仅列出两条
        区别          过滤器(Filter)             拦截器
        使用范围  是servlet规范中的一部分,    是SpringMVC框架自己的,只用使用
                 任何JavaWeb都可使用,        SpringMVC的工程才可使用
        拦截范围  在url-pattern中配置/*后,    在<mvc:mapping path=""/>配置了/**后
                  可以拦截所用资源            也可拦截所有资源<mvc:exclude-mapping path=""/>标签排除
                                             不许要拦截的资源
    3.拦截器入门
        自定义拦截器步骤
            1.创建拦截器类实现HandlerInterceptor接口
            2.配置拦截器(spring-mvc.xml)
                <mvc:interceptors>
                    <mvc:interceptor>
                        //配置拦截资源(/**所有)
                        <mvc:mapping path="/**"/>
                        <bean class="com.muyu.interceptor.MyInterceptor"/>
                    </mvc:interceptor>
                </mvc:interceptors>
            3.测试拦截器
    4.方法执行说明 1.拦截器链(Interceptor Chain)的perHandle()->2.Controller.方法
                ->3.Interceptor_Chain.postHandle()->4.Interceptor_Chain.afterCompletion()
    案例:spring_test的登陆权限控制
    		配置拦截全部,可能会出现反复调用
        1.配置登陆权限拦截器时需要配置exclude-mapping
        2.在查询user时需要抛出异常(抓取异常也可以,但是我们习惯在业务层(service)进行)
-->
<!--
SpringMVC中异常处理
    1.在业务层抓异常弊端
        1.抓异常代码与业务代码耦合在了一起
        2.没有很好的利用抽取思想,让代码可能存在冗余(多次出抓取同样异常)
            可以利用spring相应组件处理相应异常
    2.异常处理思路
        系统中异常包括两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发,测试等手段检测运行时异常发生
        系统的各个层都有刻意出现异常,通过thorws Exception向上抛出,最后由springmvc前端控制器
            提交给异常异常处理器进行异常处理(HandleExceptionResolver)
    3.处理异常处理的两种方式
        1.使用SpringMVC提供的简单处理器SimpleMappingExceptionResolver
            (一种异常与页面的映射关系)
            <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
                //配置默认异常处理,value是跳转的资源名称,并与内部视图解析器用法一致
                <property name="defaultErrorView" value="error"/>
                //配置异常与资源映射关系
                <property name="exceptionMappings">
                    <map>
                        <entry key="java.lang.ClassCastException" value="error1"/>
                        <entry key="java.lang.ArithmeticException" value="error2"/>
                        <entry key="java.io.FileNotFoundException" value="error3"/>
                        <entry key="java.lang.NullPointerException" value="error4"/>
                        <entry key="com.muyu.exception.MyException" value="error5"/>
                    </map>
                </property>
            </bean>
        2.使用Spring的异常处理接口HandlerExceptionResolver自定义自己的异常处理器
            自定义异常处理器步骤
                1.创建异常处理类实现HandlerExceptionResolver
                public class MyExceptionResolver implements HandlerExceptionResolver {
                /**处理异常方法
                     *
                     * @param request
                     * @param response
                     * @param handler
                     * @param ex 参数Exception:异常对象
                     * @return ModelAndView跳转错误视图信息
                     */
                    @Override
                    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
                        ModelAndView modelAndView = new ModelAndView();
                        if (ex instanceof MyException) {
                            modelAndView.addObject("info", "自定义异常");
                        } else if (ex instanceof ClassCastException) {
                            modelAndView.addObject("info", "类转换异常");
                        }

                        modelAndView.setViewName("error");
                        return modelAndView;
                    }
                2.配置异常处理器
                    配置是不需要配置什么参数只需要将异常处理器放在Spring容器中即可
                    <bean class="com.muyu.resolver.MyExceptionResolver"/>
                    也可以配置实现彻底解耦
                3.编写异常页面
-->
</beans>

Spring Aop

 包含内容:
  Spring AOP简介及各术语解释
  基于xml配置与注解方式配置AOP增强

Spring MVC使用AOP拦截Controller

在2022年8月第一次听说父容器与子容器这一说,在学习spring Security时又了解了一下,在此补充一下,以防忘记

 其实并不是什么Spring的Controller层已经被AnnotationMethodHandlerAdapter给拦截了,真正的原因是:我在配置该Demo项目的时候采用了applicationContext.xml和spring-servlet.xml两个配置文件,其中值得一提的是:spring-servlet.xml配置文件可以直接丢在web文件夹下,而不用在web.xml中配置,我亲自试过有效。但是为了方便文件管理,还是和applicationContext.xml一起放在resource路径下哦。

    我们必须先明白这两个配置文件在SpringMVC中的作用,applicationContext.xml会在ContextLoaderListenerclass被初始化时加载,Spring会创建一个WebApplicationContext上下文,称为父上下文(父容器) ,保存在 ServletContext中,keyWebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE的值。而spring-servlet.xml可以配置多个,它代表每个 DispatcherServlet有一个自己的上下文对象(WebApplicationContext),称为子上下文(子容器),子上下文可以访问父上下文中的内容,但父上下文不能访问子上下文中的内容。 它也保存在 ServletContext中,key是"org.springframework.web.servlet.FrameworkServlet.CONTEXT"+Servlet名称。

    那么问题来了,当spring在加载父容器的时候就会去找切入点,但是这个时候切入的controller是在子容器中的,父容器是无法访问子容器,所以就拦截不到。所以只需将上文配置的丢到spring-servlet.xml子配置文件中去即可。注意这里了,这是SpringMVC web项目案例,如果是测Server服务,还是放在applicationContext.xml中哦。
<?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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<!--
Spring AOP
    切面:目标方法与增强方法称为切面(暂且称之)
    1.AOP简介
        AOP为Aspect Oriented Programming的缩写,意思是面向切面编程,是通过预编译方式和运行期**动态代理**
          实现程序功能的统一维护的一种技术
        AOP是OOP(面对对象编程)的延续,是软件开发的一个热点,也是Spring框架中繁荣一个重要内容,是函数式编程的一种衍生泛型,
          利用AOP可以对业务逻辑的各个部分进行隔离,从而是得业务逻辑各个部分耦合度降低,提高程序的可重用性,同时提高了开发效率.
    2.AOP的作用及其优势
        作用:在程序运行期间,在不修改源代码的情况下对方法进行增强, 优势:减少重复代码,提高开发效率,便于维护
    3.AOP的底层实现(动态代理)[看test包中ProxyTest]
        实际上,AOP的底层通过Spring提供的**动态代理**技术实现的,在运行期间,spring通过动态代理技术动态的生成代理对象,
          代理对象方法执行时进行增强功能的介入,再去调用目标对象的方法,从而完成功能的增强
    4.AOP的动态代理技术
        JDK代理:基于接口的动态代理技术,[看proxy中cglib.impl.Proxy.java]
            (目标对象与代理对象共同继承一个接口,要想增强方法时,在InvocationHandler中invoke方法增强,再调用代理对象方法即可,代理对象方法就是接口里的方法)
        cglib代理:基于父类的动态代理技术[看proxy中cglib.proxy.java]
            {需要导架包,但是现在spring已经将cglib集成到了springframework中spring-core中,不需要导了(5以后)}
            (目标对象是代理对象的父类{不是继承关系,这是代理对象依赖于目标对象自动生成},从而实现子类拥有更丰富的功能)
    5.AOP相关概念
            (Spring的AOP实现底层就是对上述两种方法的动态代理进行封装,封装后我们只需要对需要关注的部分进行代码编写,并通过配置的方式完成指定目标的方法增强)
        Target(目标对象):需要代理的目标对象
        Proxy(代理):一个类被AOP阻止增强后就产生了一个结果代理类
        Joinpoint(连接点):指那些被拦截的点,在spring中,是指方法,因为spring只支持方法类型的连接点
            (目标对象可以增强的方法)
        **Pointcut(切入点/切点)**:指我们要对那些哪些Joinpoint(连接点)进行拦截的定义
            (目标对象需要被增强的方法)
            (需要配置)
        *Advice(通知/增强):指拦截到Joinpoint之后要做的事情就是通知
            (放置增强逻辑的方法)
            (需要编写并配置)
        *Aspect(切面):是切入点与通知(引介)的结合
            (配置文件配置)
        *Weaving(织入):是指把增强应用到目标对象来创建新的对象的过程,spring采用动态代理织入,而Aspectj采用编译期织入和类装载期织入
            (动词,将你的切点和增强结合的过程称为织入过程)
            (配置过程可认为织入过程)
    6.AOP开发明确的事项
        1.需要编写的内容
            编写核心业务代码(目标类的目标方法)
                [谁是切点,切点表达式配置]
            编写切面类,切面类中有通知(增强功能方法)
                [谁是通知,切面类中的增强方法]
            在配置文件中,配置织入关系,即将哪些通知与哪些连接点进行结合
                [将切点与通知进行织入配置]
    7.基于xml的AOP开发
        开发步骤(快速入门)
            1.导入AOP相关坐标
                1).spring-aop   这个包在spring-context中有了,可以不用再导
                2).org.aspectj/aspectjweaver/1.8.4
                    这个是早期实现AOP思想的小框架aspectj,spring中AOP配置没这个轻
                    spring融入了aspectj,使用spring配置可以使用原生spring配置,也可以使用aspectj配置[主张]
            2.创建目标接口和目标类(内部有切点[方法])
            3.创建切面类(内部有增强方法)
            4.将目标类和切面类的对象创建权交给spring
                (配置bean或注解@Component)
            5.在applicationContext.xml中配置织入关系
                <aop:config>
                    //声明切面,告诉那个bean是切面类
                    <aop:aspect ref="myAspect">
                        切面=切点+通知(增强)
                        //   前置增强 告诉  [2.]进行哪些增强                 [1.]哪些切点(方法)&ndash;&gt;
                        <aop:before method="before" pointcut="execution(public void com.muyu.aop.Target.save())"/>
                    </aop:aspect>
                </aop:config>
            6.测试代码,见maven中test中相应程序
        xml配置AOP详解
            1.切点表达式写法
                表达式语法:
                    execution([修饰符] 返回值类型 包名.类名.方法名(参数))
                   * 访问修饰符可以省略
                   * 返回值类型,包名,赖明方法名可以用星号*代表任意
                   * 包名与类名之间有一个点.代表当前包下的类, 两个点..表示当前包及其子包下的类
                   * 参数勒边可以用两个点..表示任意个数,任意类型的参数列表
                例:
                    execution(public void com.muyu.aop.Target.save())
                        com.muyu.aop包下的Target类的返回值为void,参数为空参的方法
                    execution(void com.muyu.aop.Target.*(..))
                        com.muyu.aop包下的Target类的返回值为void,参数为任意的任意方法
                    execution(* com.muyu.aop.*.*(..))
                        com.muyu.aop包下的任意类的任意方法(返回值为任意,参数为任意)
                    execution(* com.muyu.aop..*.*(..))
                        com.muyu.aop包及其子包下的任意类的任意方法(返回值为任意,参数为任意)
                    execution(* *.*.*(..))
                        任意包下任意类的任意方法
        2.增强方法类型<aop:增强方法类型 method="相应方法" pointcut="表达式"/>
            <aop:before> 前置增强   用于配置前置通知,指定增强方法在切入点之前执行
            <aop:after-returning> 后置增强   用于配置后置通知,指定增强方法在切入点之后执行
                好像前置和后置调用带有参数的方法时,需要配置arg-names(还不会)
                但是调用ProceedingJoinPoint参数(即环绕增强带的参数)的好像不需要配但是,会报错(Bean创建异常)
            <aop:around> 环绕增强   执勤增强方法在切点方法执行之前和之后执行
                要实现环绕增强(执行前后),需要方法携带ProceedingJoinPoint参数
                然后调用proceed方法(用带参数的),并可将返回值返回
                如果调用的不带参数(ProceedingJoinPoint),则不会实现环绕增强,
                    只在切点前执行,且仍在前置增强后执行
            <aop:after-throwing> 异常抛出增强 指定增强方法在出现异常时执行
            <aop:after> 最终增强    无论增强方法执行是否有异常都会执行
        3.增强方法各类型执行顺序
            无异常
                前置增强..
                环绕前通知..
                Aop Target Save...
                最终增强...
                环绕后通知..
                后置增强..
            存在异常
                前置增强..
                环绕前通知..
                Aop Target Save...
                最终增强...
                异常抛出增强..
        4.切点表达式的抽取
            由于配置时可能出现多次相同的表达式配置,所以对pointcut就行抽取可以便于维护
                <aop:pointcut id="MyPointcut" expression="execution(public void com.muyu.aop.Target.save())"/>
                <aop:before method="before" pointcut-ref="MyPointcut"/>
    8.基于注解配置aop增强开发
        步骤
            1.创建目标接口和目标类(内部有切点)
            2.创建切面类(内部有增强方法)
            3.将目标类和切面类的对象创建权交给Spring
                @Component("Target")//3.将目标类创建权给spring
                public class Target implements TargetInterface {}
                @Component("MyAspect")//3.将切面类创建权给spring
                @Aspect //4.在切面类中使用注解配置注入关系  标注当前MyAspect是一个切面类
                public class MyAspect {}
            4.在切面类中使用注解配置注入关系
                @Aspect //4.1在切面类中使用注解配置注入关系  标注当前MyAspect是一个切面类(就是上一步)
                @Before("execution(* com.muyu.anno.*.*(..))")//4.2在切面类中使用注解配置注入关系,那些方法需要这个方法增强
                public void before(){}
            5.在配置文件中开启组件扫描和AOP自动代理
                <context:component-scan base-package="com.muyu.anno"/>//5.1组件扫描
                <aop:aspectj-autoproxy/>//5.2Aop自动代理
            6.测试
        通知(增强)类型
            1.@Before 通xml前置增强
            2.@AfterReturning 通xml后置增强
            3.@Around 通xml环绕增强
            4.@AfterThrowing 通xml异常抛出增强
            5.@After 通xml最终增强
        切点表达式配置抽取
            方式
                在切面内部定义方法,在该方法使用@Pointcut("切点表达式")注解定义包大师,然后在增强注解中引用即可
                    @Pointcut("execution(* com.muyu.anno.*.*(..))")
                    public void pointcut(){}
            引用(以最终增强为例)
                1).@After("pointcut()")
                2).@After("MyAspect.pointcut()")
-->
    <!--目标对象-->
    <bean id="Target" class="com.muyu.aop.Target"></bean>
    <!--切面对象-->
    <bean id="myAspect" class="com.muyu.aop.MyAspect"></bean>
    <!--配置织入:告诉spring框架 [1.]那些方法(切点)需要进行[2.]哪些增强(前置,后置..)-->
    <aop:config>
        <!--声明切面,告诉那个bean是切面类-->
        <aop:aspect ref="myAspect">
            <!--对pointcut进行抽取-->
            <aop:pointcut id="MyPointcut" expression="execution(public void com.muyu.aop.Target.save())"/>
            <!--切面=切点+通知(增强)-->
            <!--前置增强 告诉  [2.]进行哪些增强  [1.]哪些切点(方法)-->
            <aop:before method="before" pointcut-ref="MyPointcut"/>
            <aop:after-returning method="afterReturning" pointcut-ref="MyPointcut"/>
            <aop:around method="around" pointcut-ref="MyPointcut"/>
            <aop:after-throwing method="afterThrowing" pointcut="execution(* com.muyu.aop.*.*(..))"/>
            <aop:after method="after" pointcut="execution(* com.muyu.aop.*.*(..))"/>
        </aop:aspect>
    </aop:config>
</beans>

Spring TX

 包含内容:
  编程式事务控制三大对象简介
  基于xml配置与注解方式配置AOP增强

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
">
<!--
编程式事务控制相关对象(了解)
    1.PlatformTransactionManager(声明式事务需要配置此对象)
        此对象是接口,是spring的事务管理器,它里面提供了我们常用的操作事务方法.
            getTransaction(TransactionDefinition),获取事务状态信息
            commit(TransactionStatus),提交事务
            rollback(TransactionStatus),回滚事务
        因为是接口类型所以在不同Dao层技术则有不同的实现类,
            例如Dao层技术是jdbc或者mybatis时:org.springframework.jdbc.datasource.DataSourceTransactionManager
            Dao层技术为hibernate时:org.springframework.orm.hibernate5.HibernateTransactionManager
    2.TransactionDefinition(声明式事务需要配置此对象)
        是事务的定义信息对象,里面有如下方法(封装信息:隔离级别,传播行为,超时时间,只读信息)
            getIsolationLevel() 获取事务的隔离级别
                设置隔离级别可解决,脏读,不可重复读,虚读(幻度)
            getPropagationBehavior()获取书屋的传播行为
                是解决业务方法调用业务方法他们事务统一性的问题
            getTimeout() 获取超时时间
                -1代表(默认),没有时间限制,如果有则按秒为单位设置
            isReadOnly() 是否只读
    3.TransactionStatus(不需要配置,因为他是实时变化的,是一个被动信息)
        此对象是接口,提供的是事务具体运行状态(存储的是在不同时间点的以下信息),方法如下
            hasSavepoint() 是否储存存储回滚点
            isCompleted() 事务是否完成
            isNewTransaction() 是否是新事务
            isRollbackOnly() 事务是否回滚
    4.编程式事务控制三大对象相互关系
        1.平台事务管理器:指定事务怎么控制的
            根据不同的dao层实现而定
        2.事务定义对象:维护事务一些属性信息
            封装事务参数
        3.事务状态对象:在运行过程中封装的一些过程信息的
            被动封装事务信息
        关系: 1平台事务管理器+事务定义对象==>事务状态对象
-->
<!--
基于XML声明式事务控制
    声明式事务控制作用
        事务管理不侵入开发的组件,具体来说业务对象不会意识到正在事务管理中,事务上也应该如此,因为事务层属于系统层面的服务,而不是逻辑代码一部分,如果想给变书屋管理策划的话,也只需要在定义文件中重新配置
            即事务管理与业务逻辑进行松耦合
        在不需要书屋管理时,只要在怎减重修改一下即可移除事务管理
        事务声明控制底层就是AOP
    声明式事务控制实现(按aop配置走)
        1.导包,spring-aop,spring-tx(封装了事务管理的API)
        2.创建目标接口与对象(内涵切点)
            经分析:accountService为目标对象,里面的transfer方法为切点
        3.创建切面类(内涵增强)
            经分析:通知(增强)为事务控制,而事务控制spring已经封装不需要手动配置
            所以这一步改为配置事务通知,
                <tx:advice id="txAdvice" transaction-manager="transactionManager">
                    //设置事物的属性信息,即配置第二个对象
                    <tx:attributes>
                        <tx:method name="*"/>
                    </tx:attributes>
                </tx:advice>
            在此之前需要配置平台事务管理器(因为还是使用Connection来执行事务,所以需要DataSource)
                <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                    <property name="dataSource" ref="dataSource"/>
                </bean>
            详解<tx:attributes><tx:method name=""/></tx:attributes>
                //分别为    匹配方法名           隔离级别             传播行为                超时时间     是否只读
                <tx:method name="transfer" isolation="DEFAULT" propagation="REQUIRED" timeout="-1" read-only="false"/>
                可以配置多个方法名,并为个方法设置不同属性信息,其中可以用"*"来做任意字符(0到多个),例如:tr*ns*fer,可以匹配transfer方法
                    也可以是没有的方法,不会报错只是不起作用
                    事务控制只会对配置在<tx:method name=""/>中的方法有效
        4.交给spring创建权
        5.在applicationContext.xml中配置织入关系
            <aop:config>
                //spring专门为事务配置添加了advisor标签,
                //这个advisor也是一个切面,一个通知的切面
                <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.muyu.service.impl.*.*(..))"/>
            </aop:config>
基于注解声明式事务控制(注解原则:自己写的使用注解,别人的尽量使用xml配置[也只能])
    配置步骤
        1.配置平台管理事务
            <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                <property name="dataSource" ref="dataSource"/>
            </bean>
        2.通知 事务的增强使用注解@Transactional,
            @Transactional//相当于配置了<tx:advice><tx:attributes><tx:method name="此属性就是配置这个注解的方法"/></tx:attributes></tx:advice>
            public void transfer(String outMan, String inMan, double money) {}
         	//所以不需要配置这个了,但是要在xml还需配置事务注解驱动
            <tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes>
        上面注解配置相当于
             <aop:config>//配置织入
                 <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.muyu.service.impl.AccountServiceImpl.transfer())"/>
            </aop:config>
        3.还需配置事务注解驱动
            <tx:annotation-driven transaction-manager="transactionManager"/>
    注解配置声明式事务控制解析
        1.使用@Transaction在需要进行事务控制的类或是方法上修饰,注解可用的属性同xml配置方式,可配置隔离级别,传播行为等
        2.注解使用在类上,南无该类下的所有方法使用同一套注解参数配置
        3.使用在方法上,不同方法可用采用不同的参数配置
        4.Xml配置文件中要开启注解驱动<tx:annotation-driven/>
-->

    <bean id="accountService" class="com.muyu.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"/>
    </bean>
    <bean id="accountDao" class="com.muyu.dao.impl.AccountDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"/>
    </bean>

    <!--1.加载jdbc.properties-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <!--配置数据源对象-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    <!--配置jdbc模板-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>


    <!--经分析:accountService为目标对象,里面的transfer方法为切点-->
    <!--配置平台管理事务-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--通知 事务的增强-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--设置事物的属性信息,即配置第二个对象-->
        <tx:attributes>
            <!--transfer-->
            <tx:method name="tr*n*fer"/>
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut id="txPointcut" expression="execution(* com.muyu.service.impl.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    </aop:config>
</beans>

Mybatis Quick(快速入门)

包含内容:
  Mybatis简介及开发步骤
  Mybatis实现DAO层
    传统方式实现
    代理方式实现
  深入映射配置文件
  深入核心配置文件
  动态SQL语句及其表达式替换

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
Mybatis简介
    1.原始JDBC操作分析
        问题:1.数据库连接不断创建,释放频繁影响性能
            2.SQL语句与程序硬耦合,不利于维护
            3.查询操作时,需手动封装实体对象
        解决:1.使用数据连接池
            2.将SQL语句抽取到xml中
            3.使用反射,内省等底层技术,自动将实体与表进行自动映射
    2.Mybatis简介
        1.mybatis是一个优秀的基于java的持久层(dao层)框架,它封装了jdbc,使用者只需要注重SQL语句即可
        2.mybatis通过xml或注解的方式将要执行的各种statement配置起来,
            并通过java对象和statement中SQL的动态参数就行映射生成最终执行的SQL语句
        3.mybatis框架执行SQL并将结果集映射为java对象并返回,
            采用ORM(对象关系映射)思想解决了实体和数据库映射的问题,对jdbc进行封装屏蔽了jdbc api细节
    3.mybatis开发步骤
        1.添加mybatis坐标(mysql必然)
        2.创建user数据表
        3.编写User实体类
        4.编写映射文件UserMapper.xml(命名(都可):表Mapping.xml)
                映射文件的包应该与dao层或domain层一级,即(com.muyu)
            配置内容
                SQL语句
            映射文件头
                <?xml version="1.0" encoding="UTF-8" ?>
                <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
            快速入门内容
                //         命名空间
                <mapper namespace="userMapper">
                    //   id调用此语句时需要     结果集类型mybatis封装成java对象
                    <select id="findAll" resultType="com.muyu.domain.User">
                        select * from user
                    </select>
                </mapper>
        5.编写核心文件SqlMapConfig.xml
            配置内容(配置核心配置)
                数据源在哪
                数据库在哪
            核心文件头
                <?xml version="1.0" encoding="utf-8"?>
                <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
            快速入门内容
                <configuration>
                    //配置数据源环境
                    //可以配置很多环境   default配置默认环境,值为环境id
                    <environments default="development">
                        <environment id="development">
                            // 事务管理器        使用原生JDBC类型
                            <transactionManager type="JDBC"></transactionManager>
                            //数据源       类型:使用数据池
                            <dataSource type="POOLED">
                                <property name="driver" value="com.mysql.jdbc.Driver"/>
                                <property name="url" value="jdbc:mysql://localhost:3306/test"/>
                                <property name="username" value="root"/>
                                <property name="password" value="1234"/>
                            </dataSource>
                        </environment>
                    </environments>
                    //配置加载映射文件
                    <mappers>
                        <mapper resource="com/muyu/mapper/UserMapper.xml"/>
                    </mappers>
        6.测试(导包导org.apache.ibatis里的包ibatis是mybatis前身)
            //获取核心配置文件
            InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
            //获取session工厂对象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            //获取session会话对象
            SqlSession sqlSession = sqlSessionFactory.openSession();
            //执行操作 参数:(UserMapper中)namespace.id
            List<User> userList = sqlSession.selectList("userMapper.findAll");
            //打印数据
            System.out.println(userList);
            //释放资源
            sqlSession.close();
    4.Mybatis增删改查操作
        插入操作注意问题
            1.插入语句使用insert标签,并且标签内就是SQL环境(都一样)
            2.在映射文件中使用ParameterType属性指定要插入的数据类型
            3.Sql语句中使用#{实体属性名}方式引用实体中的值
                标签里还用ParameterMap属性,应该是给自定义值用的,但是还不知道怎么用
                /***********
                多个参数就 字段=#{0},字段=#{1}//评论说的但是没有试
                方法1:顺序传参法
                public User selectUser(String name, int deptId);

                <select id="selectUser" resultMap="UserResultMap">
                    select * from user
                    where user_name = #{0} and dept_id = #{1}
                </select>
                ************/
            4.插入操作使用的API是sqlSession.insert("命名空间",实体对象)
            5.插入操作涉及数据库变化,所以要使用SQLSession对象显示提交事务,
                即sqlSession.commit()
                Mybatis数据库与原生jdbc不一样,原生jdbc是默认提交事务,但mybatis默认不提交事务
                所以如果不加commit怎不会变化表,但是自增的数值会遭到改变
        修改删除注意问题(注意事项和插入一样)
            1.当parameterType为一个简单数据类型是,占位符(#{})可以随便写,但是不能不写
                <delete id="delete" parameterType="java.lang.Integer">
                    delete from user where id=#{id}
                </delete>
-->
<!--
Mybatis核心配置文件概述(sqlMapConfig.xml)
    1.Mybatis核心配置文件层级
        configuration 配置
            properties 属性
                可以见数据源信息抽取成properties文件,该标签可以加载properties文件,怎用表达式(类似EL)使用
            settings 设置
            typeAliases 类型别名
                    该标签可以自定义类型的别名,让在映射文件(UserMapper.xml)中使用时就可以不用全类名
                Mybatis框架也设置了一些常用类型(java.lang)别名
                    String=>string, Long=>long, Integer=>int, Double=>double, Boolean=>boolean .....
                自定义类别名
                    <typeAliases>
                        // 可多个    需要重名的类                  定义的别名
                        <typeAlias type="com.muyu.domain.User" alias="user"/>
                    </typeAliases>
                使用注意
                    The content of element type "configuration" must match
                    "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)".
                    标签配置放置顺序应按照上说顺序配置,?代表可有可无
            typeHandlers 类型处理器
                [看深入Mybatis核心配置文件.1]
            (一般不用)ObjectFactory 对象工厂
            plugins 插件
                [看深入Mybatis核心配置文件.2]
            environments 环境
                environment 环境变量
                    transactionManager 事务管理器 类型有两种
                        1.JDBC:这个配置就是直接使用JDBC的提交和回滚设置,她依赖从数据源得到的连接来管理书屋作用域
                            [这个配置,事物的操作就是从数据源中拿的的connection操作,和之前控制事务一样]
                            {connection.setAutoCommit(false);//(开启事务)设置关闭自动提交
                             connection.commit()//提交事务  connection.rollback()//回滚事务}
                        2.MANAGED:这个配置几乎没做什么,它从来不提交或回滚一个连接,而是容器类管理事务的整个生命周期(比如JEE应用服务器的上下文).
                            默认情况下它会关闭连接(Connection),然而一些容器不希望这样,因此需要将closeConnection属性设置为false来组织它默认的关闭行为
                            [它管理事务并不是通过原始Connection,而是通过容器来管理,默认情况事务是关闭的]
                    DataSource 数据源 类型有三种
                        1.UNPOOLED:这个数据源的实现知识每次被请求时打开和关闭连接
                            [不使用连接池]
                        2.POOLED:这个数据源的实现利用了池的概念将JDBC连接对象组织起来.
                            [连接池思想]
                        3.JNDI:这个数据源的实现是为了能在EJB或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个JNDI上下文引用
                            []
            (一般不用)databaseIdProvider 数据库厂商标识
            mappers 映射器//加载映射文件
                1.使用相对于类路径的资源引用,例如:<mapper resource="com/muyu/mapper/UserMapper.xml"/>
                    核心配置文件在哪就相对于谁写
                2.使用完全限定资源定位符(URL),例:<mapper url="file:///var/mappers/AuthorMapper.xml"/>
                3.使用映射器接口实现类的完全限定类名,例:<mapper class="org.mybatis.builder.AuthorMapper"/>
                    学习注解后接触
                4.将包内的映射器接口实现全部注册为映射器,例:<package name="org.mybatis.builder"/>
-->
<!--
Mybatis相应API
    1.SqlSession工厂构造器SqlSessionFactoryBuilder
        常用API:SqlSessionFactory build(Stream inputStream)
        通过加载mybatis的核心配置文件的输入流的形式创建一个SQLSessionFactory对象
            //这个目录是相对于类路径的,在maven项目中是相对于resource
            String resource = "org/mybatis/builder/sqlMapConfig.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            SqlSession sqlSession = builder.build(inputStream);
        其中Resources工具类,这个类在org.apache.ibatis.io包中,Resources类帮助你从类路径下,文件系统或者一个web URL中加载资源文件.
    2.SqlSession工厂对象SqlSessionFactory
        有很多方法创建SqlSession实例,常用的有如下两个:
            openSession()  会默认开启一个事务,但事务不会自动提交,需要手动提交事务,SqlSession.commit()
            openSession(boolean autoCommit)参数为是否自动提交,设置为true,则会自动提交
    **3.SqlSession会话对象
        SqlSession实例在Mybatis中是非常强大的一个类,在这里你会看到所有执行语句,提交或回滚事务和获取映射器实例方法.
        执行语句主要有
            <T> T selectOne(String statement,Object parameter)
            <E> List<E> selectList(String statement,Object parameter)
            int insert(String statement,Object parameter)
            int update(String statement,Object parameter)
        操作事务方法主要有
            void commit()
            void rollback()
-->
<!--
Mybatis实现DAO层
    mybatis传统方式实现Dao[实例看userServiceImpl,UserMapper]
        和原先的一样,还是service调用自己实现的Dao,只是SQL语句配置到了UserMapper.xml中,简单实现了解耦
            @Override
            public List<User> findAll() throws IOException {
                InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
                SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
                SqlSessionFactory sqlSessionFactory = builder.build(resourceAsStream);
                SqlSession sqlSession = sqlSessionFactory.openSession();
                List<User> userList = sqlSession.selectList("userMapper.findAll");
                return userList;
            }
    Mybatis代理方式实现Dao层(不需要自己实现DAO)[实例看userServiceImpl,UserMapper2]
        采用Mybatis的代理开发方式实现DAO层的开发,这种方式是我们后面的主流
        Mapper接口开发方式只需要程序员编写Mapper接口()相当于Dao接口,由Mybatis框架根据接口定义创建接口动态代理对象,
        代理对象的方法体 同上边的Dao接口实现类方法.
        Mapper接口开发需要遵循以下规范
            1.Mapper.xml文件(映射文件)中的namespace与Mapper接口的全限名相同
                <mapper namespace="com.muyu.dao.UserMapper">
                public interface UserMapper {}
            2.Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
            3.Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
                如果接口方法参数是容器(list,set),parameterType也必须相同(list,set)
            4.Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
                如果接口方法返回值是容器(list,set),但只要容器里的内容类型与resultType相同即可
                 <select id="findAll" resultType="com.muyu.domain.User">
                 List<User> findAll() throws IOException;

                 <select id="findById" resultType="com.muyu.domain.User" parameterType="int">
                 User findById(int id) throws IOException;
        调用步骤
            //获取SqlSession步骤与传统一样,估计可以封装或者通过spring注入
            /***********
            多个参数就 字段=#{0},字段=#{1}//评论说的但是没有试
            方法1:顺序传参法
            public User selectUser(String name, int deptId);

            <select id="selectUser" resultMap="UserResultMap">
                select * from user
                where user_name = #{0} and dept_id = #{1}
            </select>
            ************/
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            List<User> all = mapper.findAll();
            System.out.println(all);
            User user = mapper.findById(1);
            System.out.println(user);
-->
<!--
动态SQL语句
	  利用<where>,<set><if><foreach>标签实现动态SQL语句
	案例
		动态查询
			/*添加where标签可以不加但是if中必须加and或其他逻辑关键字,他不会自动添加and但是会自动删除and猜测*/
		    <select id="findByCondition" parameterType="user" resultType="user">
		        select * from user
		        <where>
		            <if test="id>0">
		                and id=#{id}
		            </if>
		            <if test="username!=null">
		                and username=#{username}
		            </if>
		            <if test="password">
		                and password=#{password}
		            </if>
		        </where>
		    </select>
	    动态修改
	    	/*set和where标签类似,只是set标签会把逗号动态删除,所以在更改列后面添加逗号即可,但是在前面不会自动删除*/
		    <update id="updateById" parameterType="com.muyu.domain.User">
		        update user
		        <set>
		            <if test="username!=null">
		                username=#{username},
		            </if>
		            <if test="password!=null">
		                password=#{password},
		            </if>
		        </set>
		        where id=#{id}
		    </update>
深入Mybatis映射文件配置
        好像下面四个标签id是唯一的,所以使用重载好像会报错,
    <select>:查询
        有resultType属性(其他三个没有),设置返回值属性
    <insert>:插入
    <update>:修改
    <delete>:删除
        resultType
            如果接口方法返回值是容器(list,set),但只要容器里的内容类型与resultType相同即可
        parameterType详解:
            如果参数为list<类型>(foreach,collection收藏为list),则parameterType为list,也可以没有
            如果参数为数组:(foreach,collection收藏为array)
                int[],Integer[]:可以没有parameterType,可以为list,也可以为int[],Integer[]
                String[]:可以没有parameterType,可以为list,但是不可以String[],string[]
        <where>:where条件,
            /*添加where标签可以不加where 1=1,但是多个if添加中必须加and,他不会自动添加and但是会自动删除and
                猜测为什么,因为可能where标签里不只有and条件,可能还有or,like,可能还有分组,排序,分页等等*/
        <set>:修改时set条件 update 表 set 列=更改值,列=更改值 where 条件
            set和where标签类似,只是set标签会把逗号动态删除,所以在更改列后面添加逗号即可,但是在前面不会自动删除
        <if test="">:判断
            不支持 &&  用 and  or  || 来做逻辑与或的判断
            gt    对应       >
            gte   对应       >=
            lt    对应       <(会报错  相关联的 "test" 属性值不能包含 '<' 字符)
            lte   对应       <=(会报错  相关联的 "test" 属性值不能包含 '<' 字符)
            eq    对应       ==
            neq   对应       !=
            判断userList是否为空 userList != null and userList.isEmpty()
            判断是否包含某个特定字符
                <if test="username != null and username.indexOf('str')==0">
            是否以什么结尾
			    <if test="username != null and username.lastIndexOf('ji') == username.length() - 1"></if>
        <foreach>:用来遍历数组或集合参数的
            <foreach collection="list" open="id in(" separator="," close=")" item="id" >
                collection收藏,标注遍历类型,如果是list则为list,如果为数组(int[],String[]等)则为array,(类型不对则会报错),它的类型与parameterType有所区别,看parameterType详解
                open:继前面开始的语句,这里直接id in()[在where标签中,有条件则有where单词],如果前面有其他条件一定要加上and
                    已测试,加上and,如果前面没有where标签也会删除,所以好习惯应该是前面都加and
                separator分隔器:上一步与下一步相隔的东西
                close:整个foreach完后最后拼接的东西
                item:每步的临时参数
        <include>:插入抽取的SQL语句
            <include refid="selectSql"/>
    <sql>:sql片段抽取
        <sql id="selectSql">select * from user</sql>
-->
<!--
深入Mybatis核心配置文件
    1.typeHandlers标签(不常用)
        无论Mybatis在预处理语句(PreparedStatement)中设置一个参数是,还是从结果集中取出一个值是,都会用类型处理器将获取的值以合适的方式转换成Java类型,下面描述了一些默认的类型处理器(部分)
            类型处理器               Java类型                          JDBC类型
            BooleanTypeHandler      java.lang.Boolean, boolean       数据库兼容的BOOLEAN
            ByteTypeHandler      java.lang.Byte, byte       数据库兼容的NUMERIC(数字)或BYTE
            ShortTypeHandler      java.lang.Short, short       数据库兼容的NUMERIC或SHORT INTEGER(没找到)
            IntegerTypeHandler      java.lang.Integer, int       数据库兼容的NUMERIC或INTEGER(没找到)
            LongTypeHandler      java.lang.Long, long       数据库兼容的NUMERIC或LONG INTEGER(没找到)
        实例前置
            {修改了数据库表 添加了字段birthday,类型bigint,修改了实体类 添加了属性Data birthday}
        你可以重写类型处理器创建自己的类型处理器来处理不支持的或非标准的类型(可以覆盖有的也可以定义没有的).
            具体做法为:实现org.Apache.ibatis.type.TypeHandler接口,或继承一个便利的类org.apache.ibatis.type.BaseTypeHandler,
            然后可以选择性地将他映射到一个JDBC类型,例如需求:一个java中的Data数据类型,想将之存放的数据库的时候存成一个1970年至今的毫秒数(bigint/long),取出来的时候转换为date
        开发步骤:
            1.定义转换类继承类BaseTypeHandler<T>
                <T>泛型就是我要转化的java类型
                它不像SpringMVC自定义类型转换器,根据implements Converter<String, Date>这两个的类型判断的,
                它只有一个泛型所以只要你定义了一个类型不管这个类型要转成什么类型(可能因为java并不知道数据库这个字段是什么类型所以不能预知怎么转化,只能就依据你你写的处理)
                比如:你写个java.Date转数据库.long的程序,但是如果有个需要Java.Date转数据库Date的就会报错(因为preparedStatement.setLong(i,time);就是错的)
                知不道怎么解决这种,现在只能是一个项目的表java类转换数据库类一致(一个标准)
            2.覆盖4个未实现的方法,
                其中setNonNullParameter为java程序设置数据到数据库的回调方法
                getNullableResult为查询时,mysql的字段类型朱焕成java的Type类型的方法
            3.在Mybatis核心配置文件中进行注册
                <typeHandlers>
                    <typeHandler handler="com.muyu.handler.DateTypeHandler"/>
                </typeHandlers>
            4.测试是否转换正确
    2.plugins(插件)标签
          Mybatis可以使用第三方的插件对功能进行扩展,分页助手PageHelper是将分页的复杂操作进行封装,使用简单的方式即可获得分页的相关数据
        开发步骤:
            1.导入PageHelper的坐标
                //PageHelper插件
                <dependency>
                    <groupId>com.github.pagehelper</groupId>
                    <artifactId>pagehelper</artifactId>
                    <version>3.7.5</version>
                </dependency>
                //分页助手的解析器
                <dependency>
                    <groupId>com.github.jsqlparser</groupId>
                    <artifactId>jsqlparser</artifactId>
                    <version>0.9.1</version>
                </dependency>
            2.在mybatis核心配置文件中配置pageHelper插件
                <plugins>
                    <plugin interceptor="com.github.pagehelper.PageHelper">
                        //设置方言,其他数据库分页语句不一样
                        <property name="dialect" value="mysql"/>
                    </plugin>
                </plugins>
            3.测试分页数据请求
                3.1:首先得有查询多条语句的(为了展示效果,如果单条也没啥有)
                3.2以此方法使用
                        (原理也就是将语句添加相应dialect(方言)的分页语句[它会动态的变化语句,如果你设置当前页为小于等于零,则会让语句变为查询总条数,具体怎么看])
                        (获取信息原理,(略微看了波源码)可能它将返回的数据类型为Pages(继承了ArrayList,有分页助手实现),所以可以通过Pages类型获取相应的数据,并计算)
                    UserMapper2 mapper = sqlSession.getMapper(UserMapper2.class);
                    PageHelper.startPage(3, 3);
                    List<User> all = mapper.findAll();
                    for (User user : all) {
                        System.out.println(user);
                    }
                    //获取与分页相关参数
                    PageInfo<User> pageInfo = new PageInfo<User>(all);
                    System.out.println("当前页"+pageInfo.getPageNum());
                    System.out.println("每页显示条数:"+pageInfo.getPageSize());
                    System.out.println("总条数:"+pageInfo.getTotal());
                    System.out.println("总页数:"+pageInfo.getPages());
                    System.out.println("上一页:"+pageInfo.getPrePage());
                    System.out.println("下一页:"+pageInfo.getNextPage());
                    System.out.println("是否是首页:"+pageInfo.isIsFirstPage());
                    System.out.println("是否是尾页:"+pageInfo.isIsLastPage());
                    System.out.println("开始数据第几行:"+pageInfo.getStartRow());
                    System.out.println("末尾数据第几行:"+pageInfo.getEndRow());
    3.多表查询(看项目mybatis_multi)
    4.注解开发(看项目mybatis_multi)
-->
</beans>

Mybatis Multi(多表操作)

包含内容:
  Mybatis多表查询
    基于XML配置
      使用resultMap,association,collection,标签配置相应实体属性
    基于注解方式
      使用@One,@Many注解

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
Mybatis多表操作
    1.一对一关系(//一对一配置, 一个订单对应一个用户)
        {实例前置:
            添加orders(order by是mySQL排序关键字)实体类,并在实体类引用user}
        1.1 写出相应SQL语句
        1.2 编写select标签并编辑resultMap属性
        1.3 编写resultMap标签,并按以下标准编写
        //     id=>resultMap引用的标识  type=>要返回的类型(查询返回订单实体且每个订单包含相应用户)
        <resultMap id="orderMap" type="com.muyu.domain.Orders">
                /*手动指定字段与实体属性映射关系
                    column:数据库查询得结果集的字段名称
                    property:实体的属性名称
                    SELECT *,o.id oId FROM orders o,USER u WHERE u.id = o.uId
                    为了方便使用该SQL语句,使Orders表中id别名为oid
                    orders表中有uid字段所以不用重命名
                */
            //主键单独有标签<id>
            <id column="oid" property="id"/>
            <result column="ordertime" property="ordertime"/>
            <result column="total" property="total"/>
            /*
            //第一种方式
            <result column="uid" property="user.id"/>
            <result column="username" property="user.username"/>
            <result column="password" property="user.password"/>*/
            /*第二种方式:有层级更方便阅读*/
            //单词解释 association组合
            <association property="user" javaType="com.muyu.domain.User">
                <id column="uid" property="id"/>
                <result column="username" property="username"/>
                <result column="password" property="password"/>
            </association>
        </resultMap>
                /*一对一配置, 一个订单对应一个用户*/
        <select id="findOrdersAll" resultMap="orderMap">
        SELECT *,o.id oid FROM orders o,USER u WHERE u.id = o.uId
        </select>
    2.一对多关系(//一对多配置, 一个用户对应多个订单)
        {实例前置:
            在User实体类添加orders实体类的List容器}
        2.1 写出相应SQL语句
        2.2 编写select标签并编辑resultMap属性
        2.3 编写resultMap标签,并按以下标准编写
            <resultMap id="userMap" type="com.muyu.domain.User">
                <id column="uid" property="id"/>
                <result column="username" property="username"/>
                <result column="password" property="password"/>
                //封装集合标签 property=>在实体类的名称  ofType=>集合内的数据类型
                <collection property="ordersList" ofType="com.muyu.domain.Orders">
                    <id column="oid" property="id"/>
                    <result column="ordertime" property="ordertime"/>
                    <result column="total" property="total"/>
                </collection>
            </resultMap>
            //一对多配置, 一个用户对应多个订单
            <select id="findAll" resultMap="userMap">
                SELECT *,o.id iod FROM USER u LEFT OUTER JOIN orders o ON u.id=o.uid
            </select>
    3.多对多关系(//多对多配置, 一个用户对应多个角色,一个角色对应多个用户)
        {实例前置:
            添加role实体类,
            在User实体类添加role实体类的List容器}
        1.1 写出相应SQL语句
        1.2 编写select标签并编辑resultMap属性
        1.3 编写resultMap标签,并按以下标准编写
            <resultMap id="userRoleMap" type="user">
                <id column="userId" property="id"/>
                <result column="username" property="username"/>
                <result column="password" property="password"/>
                <collection property="roleList" ofType="com.muyu.domain.Role">
                    <id column="roleId" property="id"/>
                    <result column="roleName" property="roleName"/>
                    <result column="roleDesc" property="roleDesc"/>
                </collection>
            </resultMap>
            <select id="findUser_RoleAll" resultMap="userRoleMap">
                SELECT * FROM (USER u LEFT OUTER JOIN sys_user_role ur ON u.id=ur.userId)LEFT OUTER JOIN sys_role r ON r.id=ur.roleId
            </select>
Mybatis注解开发
    1.MyBatis常用注解
        @Insert:实现新增
        @Update:实现修改
        @Delete:实现删除
        @Select:实现查询
        @Result:实现结果集封装
        @One:实现一对一的结果集封装
        @Many:事项一对多结果集封装(多对多都差不多)
        //动态SQL语句
        @UpdateProvider(type=动态辅助类.class,method="方法{里面含判断逻辑}")
        @DeleteProvider
        @InsertProvider
        @SelectProvider
    2.简单开发步骤
        {实例前置:
            将userMapper.xml中配置相应方法id改名,使其xml配置不生效}
        2.1在Mapper接口上添加相应注解
            注解动态SQL,去网上看了很多文章,好像有不需要另外新建辅助类的(我只实践了新建辅助类方法)
                (感觉注解开发实现动态SQL都挺复杂的,xml配置稍微有点简化,但是貌似也不方便调试,幸好还有debug日志可以看)
                1.新建辅助类
                    public class DongTaiUpdate {}
                2.编写方法,实现逻辑
                    public String updateByNameAndPassword(User user) {
                        String sql = "update user ";
                        if(user.getUsername() != null) {
                            sql += " set username = #{username}";
                        }

                        if(user.getPassword() != null) {
                            if(user.getUsername() != null) {
                                sql += " , password = #{password}";
                            } else {
                                sql += " set password = #{password}";
                            }
                        }
                        sql += "where id = #{id}";
                        return sql;
                    }
                    上面我写了这么多,还没有判断全为空处理,(可能new Sql(){}方式会简单一点)
                    虽然xml配置也麻烦,但是有<set><where>标签简化了一些逻辑
                3.使用注解引用
                    @UpdateProvider(type=动态辅助类.class,method="方法{里面含判断逻辑}")
                    @DeleteProvider
                    @InsertProvider
                    @SelectProvider
                4.测试
        2.2在核心配置文件中sqlMapConfig.xml配置
            <mappers>
                <package name="com.muyu.mapper"/>
            </mappers>
            但是mappers如果有mapper标签,不知道为什么添加package会莫名报错,删了package也可正常运行
            评论:给大家提个醒,package方式文件名要和接口命一致,并且在同一包下
        2.3和xml注解一样测试
    3.复杂注解开发
        实现复杂关系映射之前我们可以在映射文件中通过配置<resultMap>类实现,使用注解开发后,我们可以使用@Results,@Result,@One,@Many各注解组合完成复杂的关系配置
            @Results, 代替的是标签<resultMap>该注解中可以使用单个@Result注解,也可以使用@Result集合,
                        使用格式:@Results({@Result,@Result...})
            @Result,  代替<id>[@Result(id = true)]和<result>标签,属性介绍,column(列),数据库列名,property:需配置的属性名(实体的属性)
                        one:需要使用@One注解,many:需要使用@Many注解
            @One,     代替了<association>,是多表查询的关键,在注解中用来指定子查询返回的单一对象,
                        属性介绍:select:指定用来多表查询的sqlMapper,
            @Many     代替了<collection>标签,是多表查询的关键,在注解中指定子查询返回对象集合,
                        属性介绍:select:指定用来多表查询的sqlMapper,
        3.1一对一查询
            /*//第一种方式,一次查询根据
            @Select("SELECT *,o.id oid FROM orders o,USER u WHERE u.id = o.uId")
            @Results({
                    @Result(column = "oid", property = "id"),
                    @Result(column = "ordertime", property = "ordertime"),
                    @Result(column = "total", property = "total"),
                    @Result(column = "uid", property = "user.id"),
                    @Result(column = "username", property = "user.username"),
                    @Result(column = "password", property = "user.password"),
            })*/
            //第二种方式,先查一张表,然后依据一个字段再调用其他查询
            //感觉这种方法很麻烦,而且很有可能会递归调用,至少在这个实例中有可能
            @Select("SELECT * FROM orders")
            @Results({
                    @Result(column = "oid", property = "id"),
                    @Result(column = "ordertime", property = "ordertime"),
                    @Result(column = "total", property = "total"),
                    @Result(
                            property = "user",//在实体中需要封装数据的属性名
                            column = "uid",//根据这个字段去调用其他程序查询
                            javaType = User.class,//要封装的实体类型
                            one = @One(select = "com.muyu.mapper.UserMapper.findById")
                                //select属性 代表查询那个接口的方法获得数据
                    )
            })
            public List<Orders> findAll();
        3.2一对多查询
            3.2.1 第一步,使用第二种方式在接口方法上加上相应注解
                //注解开发,第二种方式
                //这样到时直接左外连接了
                @Select("select * from user")
                @Results({
                        @Result(id = true,column = "id",property = "id"),
                        @Result(column = "username",property = "username"),
                        @Result(column = "password",property = "password"),
                        @Result(
                                property = "ordersList",
                                //根据id为参数,使用@Many中select的方法进行查询
                                column = "id",
                                //返回类型为List
                                javaType = List.class,
                                many = @Many(select = "com.muyu.mapper.OrdersMapper.findByUid")
                        )
                })
                public List<User> findOrdersAll();
            3.2.2 第二步,在订单Mapper(OrdersMapper)总共定义根据用户id查询订单数据
                @Select("select * from orders where uid=#{uid}")
                public List<Orders> findByUid(int uid);
        3.3多对多查询(与一对多查询几乎一样只是在第二步中是一次性查询两个表实现三表查询)
            3.3.1 第一步,使用第二种方式在接口方法上加上相应注解
                //多对多配置, 一个用户对应多个角色,一个角色对应多个用户
                //注解开发,第二种方式
                @Select("select * from user")
                @Results({
                        @Result(id = true,column = "id",property = "id"),
                        @Result(column = "username",property = "username"),
                        @Result(column = "password",property = "password"),
                        @Result(
                                property = "roleList",
                                column = "id",
                                javaType = List.class,
                                many = @Many(select = "com.muyu.mapper.RoleMapper.findByUid")
                        )
                })
                public List<User> findUser_RoleAll();
            3.3.2 第二步,在角色Mapper(RoleMapper)总共定义根据用户id查询假设数据(查两个表)
                @Select("SELECT * FROM sys_user_role ur,sys_role r WHERE ur.roleId=r.id AND ur.userId = #{uid}")
                public List<Role> findByUid(int uid);


-->
<!--
数据库知识:
    内连接的特性是只显示符合连接条件的记录,外连接必然会返回其中一张表的全部数据,哪怕不匹配。
    如果用内连接(inner join on),正常的写法是这样的:
    Select StudentInfo.*,ClassInfo.* from StudentInfo inner join ClassInfo on StudentInfo.ClassId=ClassInfo.ClassId
    用这种写法不会出现笛卡尔积,但是内连接是允许省略连接条件的,也就是可以省略掉on后面的内容,所以如果写成这样:
    Select StudentInfo.*,ClassInfo.* from StudentInfo,ClassInfo
    也是可以通过编译的,但是这样一来就产生了一个笛卡尔积。
    但是因为怕产生笛卡尔积而拒绝使用内链接是不正确的,只要不省略掉连接条件(用where代替),是不会产生全部的笛卡尔积,会产生过滤后的笛卡尔积。
    笛卡尔积:
    假设集合A={a,b},集合B={0,1,2},则两个集合的笛卡尔积为{(a,0),(a,1),(a,2),(b,0),(b,1),(b,2)}。可以扩展到多个集合的情况。
    外连接(OUTER JOIN):外连不但返回符合连接和查询条件的数据行,还返回不符合条件的一些行。
    在MySQL数据库中外连接分两类(不支持全外连接):左外连接(LEFT OUTER JOIN)、右外连接(RIGHT OUTER JOIN)
    博客:https://www.cnblogs.com/geaozhang/p/6753190.html
    外连接分三类:左外连接(LEFT OUTER JOIN)、右外连接(RIGHT OUTER JOIN)和全外连接(FULL OUTER JOIN)。Outer可省略
    三者的共同点是都返回符合连接条件和查询条件(即:内连接)的数据行。不同点如下:
    左外连接还返回左表中不符合连接条件单符合查询条件的数据行。
    右外连接还返回右表中不符合连接条件单符合查询条件的数据行。
    全外连接还返回左表中不符合连接条件单符合查询条件的数据行,并且还返回右表中不符合连接条件单符合查询条件的数据行。全外连接实际是上左外连接和右外连接的数学合集(去掉重复),即“全外 = 左外 UNION 右外”。
    说明:左表就是在(LEFT OUTER JOIN)关键字左边的表。右表当然就是右边的了。在三种类型的外连接中,OUTER 关键字是可省略的。
    使用左外连接
        SELECT *,o.id iod FROM USER u LEFT OUTER JOIN orders o ON u.id=o.uid
    使用外连接三表查询
        SELECT * FROM (USER u LEFT OUTER JOIN sys_user_role ur ON u.id=ur.userId)LEFT OUTER JOIN sys_role r ON r.id=ur.roleId
        错误的SQL:SELECT * FROM (USER u LEFT OUTER JOIN sys_user_role ur ON u.id=ur.userId), sys_role r where r.id=ur.roleId
        错误的SQL:SELECT * FROM USER u LEFT OUTER JOIN sys_user_role ur , sys_role r ON u.id=ur.userId and r.id=ur.roleId
-->
</beans>

itheima ssm

包含内容:
  spring整合MyBatis
    传统整合(即各用各的)
    根据mybatis-spring工具整合

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
">
<!--
SSM配置详解:
    Spring配置文件:applicationContext.xml
        [组件扫描:主要扫描service与mapper,所以配置不扫描controller]
        {配置SqlSessionFactory
        使用MapperScannerConfigurer,为mapper创建实体类
        配置事务}
    SpringMvc配置文件:spring-mvc.xml
        [组件扫描:只要扫描controller]
        [SpringMVC注解驱动:功能很强大,自动加载处理映射器处理适配器,集成jackson]
        [内部资源视图解析器:prefix:前缀,suffix:后缀]
        [静态资源资源访问权限:<mvc:default-servlet-handler>]
    MyBatis映射文件:AccountMapper.xml
        [SQL语句]
    MyBatis核心文件:sqlMapConfig.xml
        [数据类型别名:<typeAliases>]
        [环境:<environments>,(这个在spring整合mybatis是可以由Spring配置)
            事务管理器,数据源,所以需要加载jdbc配置信息<properties>]
        [加载映射:<mappers>,(这个在spring整合mybatis是可以由Spring配置)]
    数据库连接信息文件:jdbc.properties
    Web.xml文件:web.xml
        [spring与web结合->spring监听器:{在springframework.spring-web包}
            在服务器开启时自动加载ClassPathXmlApplicationContext,
            并封装到最大的域(ServletContext)中,所以也需要配置全局参数contextConfigLocation]
        [SpringMVC与web结合->SpringMVC前端控制器
            即一个servlet,并配置缺省与启动时创建]
        [请求获取数据乱码->编码过滤器,一个过滤器]
    日志文件:log4j.xml
原始方式整合Mybatis:
      即原先单个框架怎么用放一块就怎么用
    缺点:在业务层中(service)每次使用SqlSession和AccountMapper对象都要用相同的代码进行获取(即使可以抽取成工具类)
使用mybatis-spring工具整合Mybatis
    解决缺点:通过配置及其依赖注入的方式对SqlSession进行注入,方便使用
    整合思路:
        [SqlSession ss = MyBatisUtils.openSession();
        AccountMapper am=ss.getMapper(AccountMapper.class);
        以上将Session工厂给spring容器管理,从容器中获取操作的Mapper实例即可]
        am.save(account)
        [ss.commit();
        ss.close();
        以上将事务提交交给spring容器进行声明式事务控制]
-->
    <context:component-scan base-package="com.muyu">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!--配置数据源,准备替换在Mybatis核心配置文件中的环境配置-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--配置SqlSessionFactory,但是这是个接口,所以需要org.mybatis.spring这个包里的SqlSessionFactoryBean
        之后事务好像就自动提交了-->
    <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

        <!--<dataSource type="POOLED">-->
        <property name="dataSource" ref="dataSource"/>
        <!--还可以加载MyBatis核心配置文件-->
        <property name="configLocation" value="classpath:sqlMapConfig-spring.xml"/>
    </bean>
    <!--继上,扫描mapper所在包,为mapper创建实现类
        <mappers><package>,扫描完后,就会创建一个mapper的实现类,使用直接注入即可
    -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.muyu.mapper"/>
    </bean>

    <!--配置事务控制-->
    <!--配置平台管理事务-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--通知 事务的增强-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--设置事物的属性信息,即配置第二个对象-->
        <tx:attributes>
            <!--transfer-->
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut id="txPointcut" expression="execution(* com.muyu.service.impl.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
        <!--<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.muyu.service.impl.*.*(..))"/>-->
    </aop:config>
</beans>

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.muyu</groupId>
    <artifactId>itheima_ssm</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>


    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <dependency><!--spring集成Junit-->
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <dependency><!--spring-web封装了监听器-->
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>

        <!--spring-aop包在spring-context中有了-->
        <dependency><!--aop相关-->
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.4</version>
        </dependency>
        <dependency>
            <!--配置平台管理事务
             例如Dao层技术是jdbc或者mybatis时:org.springframework.jdbc.datasource.DataSourceTransactionManager-->
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <dependency><!--事务-->
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>


        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.32</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <dependency><!--mybatis整合spring-->
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.1</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.2.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.9.0</version>
        </dependency>
        
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.7</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>

</project>
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值