SSM框架知识点总结(黑马)

1.初识Spring

2.Spring Dramework

2.1学习路线

  1. Aop:面向切面编程

  2. Aspects:AOP思想实现

  3. Core Container:核心容器

  4. Data Access:数据访问

  5. Date Integration:数据集成

  6. Web:web开发

  7. Text:单元测试和集成测试

2.2核心概念

  • IoC(Inversion of Control)控制反转

    • 使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转

  • Spring技术对IoC思想进行了实现

    • Spring提供了一个容器,称为IoC容器,用来充当IoC思想中的外部

    • IoC容器负责对象的创建,初始化等一系列工作,被创建或被管理的对象在IoC容器中统称为 Bean

  • DI(Dependence Injection)依赖注入

    • 在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入

  • 目标:充分解耦

    • 使用IoC容器管理bean (IoC)

    • 在IoC容器内将有依赖关系的bean进行关系绑定 (DI)

  • 最终效果

    • 使用对象时不仅可以直接从IoC容器中获取,并且获取到的bean已经绑定了所有的依赖关系

2.3IoC入门案例思路分析

  1. 管理什么? (Service 和Dao)

  2. 如何将被管理的对象告知IoC容器?(配置)

  3. 被管理的对象交给IoC容器,如何获取到IoC容器? (接口)

  4. IoC容器得到后,如何从容器中获取bean?(接口方法)

  5. 使用Spring导入那些坐标? (pom.xml)

IOC入门案例

1.导入spring坐标
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>
2.定义Spring管理的类(接口)
public interface BookDao {
    public void save();
}
​
​
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
}
3.创建Spring配置文件,配置对应类作为Spring管理的bean
<?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">
​
<!--    1.导入spring的坐标spring-context,对应版本是5.2.10.RELEASE-->
​
<!--    2.配置bean
        bean标签表示配置bean
        id属性表示bean起名字
       class属性表示给bean定义类型
-->
    <bean id="bookDao" class="com.wen.dao.impl.BookDaoImpl"></bean>
    <bean id="bookService" class="com.wen.service.impl.BookServiceImpl"></bean>
</beans>
4.初始化IOC容器(Spring核心容器/Spring容器),通过容器获取bean
    public static void main(String[] args) {
        //3.获取IoC容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //4.获取bean(根据bean配置id获取)
//        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
//        bookDao.save();
​
        BookService bookService = (BookService) ctx.getBean("bookService");
        bookService.save();
​
    }

2.4 DI入门案例思路分析

  1. 基于IoC管理bean

  2. Service中使用new形式创建的Dao对象是否保留?(否)

  3. Service中需要的Dao对象如何进入到Service中?(提供方法)

  4. Service与Dao间的关系如何描述?(配置)

DI入门案例(XML版)

1.删除使用的new的形式创建的对象
public class BookServiceImpl implements BookService{
    private BookDao bookDao = new BookDaoImpl();
    public void save(){
        bookDao.save();
    }
}
2.提供依赖对象对应的setter方法
public class BookServiceImpl implements BookService {
    //5.删除业务层中使用new的方式创建的dao对象
    private BookDao bookDao;
​
    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
    //6.提供对应的set方法
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }
}
3.配置service与dao之间的关系
<bean id="bookDao" class="com.wen.dao.impl.BookDaoImpl"/>
    <bean id="bookService" class="com.wen.service.impl.BookServiceImpl">
<!--        7.配置service与dao的关系
            property标签表示配置当前的bean
            name的属性表示配置哪一个具体的属性(方法)
            ref表示这个属性(方法)参考哪一个bean
-->
        <property name="bookDao" ref="bookDao"/>
    </bean>

3.1bean作用范围说明

  • 为什么bean默认为单例?

  • 适合给容器进行管理的bean

    • 表现层对象

    • 业务层对象

    • 数据层对象

    • 工具对象

  • 不适合交给容器的进行管理的bean

    • 封装实体的域对象

3.2bean实例化

  • bean本质上就是对象,创建bean使用构造方法完成

实例化bean的三种构造方法
1.提供可访问 的构造方法
public class BookDaoImpl implements BookDao {
​
//    public BookDaoImpl() {
//        System.out.println("book dao constructor is running ....");
//    }
​
    public void save() {
        System.out.println("book dao save ...");
    }
​
}
​
  • 配置

        <bean id="bookDao"  class="com.wen.dao.impl.BookDaoImpl"/>
  • 无参构造方法如果不存在,,将抛出异常BeanCreationException

2.静态工厂
public class OrderDaoFactory{
    public static OrderDao getOrderDao(){
        return new OrderDaoImpl();
    }
}
  • 配置

    <bean
          id = "orderDao"
          factory-method = "getOrderDao"
          class="com.wen.factory.OrderDaoFactory"
          />

3.实例工厂
  • FactoryBean

public class UserDaoFactoryBean implement FactoryBean<UserDao>{
    public UserDao getObject() throws Exception{
        return new UserDaoImpl();
    }
    public Class<?> getObjectType(){
        return UserDao.class;
    }
}
  • 配置

<!--    方式四:使用FactoryBean实例化bean-->
    <bean id="userDao" class="com.wen.factory.UserDaoFactoryBean"/>

3.3bean生命周期

  • 生命周期:从创建到消亡的完整过程

  • bean生命周期:bean从创建到消亡的整体过程

  • bean生命周期控制:在bean创建后到销毁前做一些事情

  1. 初始化容器

    1. 创建对象(内存分配)

    2. 执行构造方法

    3. 执行属性注入(set操作)

    4. 执行bean初始化方法

  2. 使用bean

    1. 执行业务操作

  3. 关闭销毁bean

    1. 执行bean销毁方法

3.4bean生命周期控制

  • 提供生命周期控制方法

    public class BookDaoImpl implements BookDao {
        public void save() {
            System.out.println("book dao save ...");
        }
        //表示bean初始化对应的操作
        public void init(){
            System.out.println("init...");
        }
        //表示bean销毁前对应的操作
        public void destroy(){
            System.out.println("destory...");
        }
    
    }
  • 配置生命周期控制方法

        <bean id="bookDao" class="com.wen.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy"/>
    
  • 接口控制InitializingBean, DisposableBean接口

    public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
        private BookDao bookDao;
    
        public void setBookDao(BookDao bookDao) {
            System.out.println(&quot;set .....&quot;);
            this.bookDao = bookDao;
        }
    
        public void save() {
            System.out.println(&quot;book service save ...&quot;);
            bookDao.save();
        }
    
        public void destroy() throws Exception {
            System.out.println(&quot;service destroy&quot;);
        }
    
        public void afterPropertiesSet() throws Exception {
            System.out.println(&quot;service init&quot;);
        }
    }g

    关闭容器

    • close()

    • registerShutdownHook()

4.1依赖注入

  • 思考:向一个类中传递数据的方式有几种?

    • 普通方法(set方法)

    • 构造方法

  • 思考:依赖注入描述了在容器中建立bean与bean之间依赖关系的过程,如果bean运行需要的是数字或是字符串呢?

    • 引用类型

    • 简单类型(基本数据类型与String)

  • 依赖注入方式

    • setter注入

      • 简单类型

      • 引用类型

    • 构造器注入

      • 简单类型

      • 引用类型

setter注入---简单类型
  1. 在bean中定义引用类型属性并提供可访问的set方法

        private String databaseName;
        
            public void setDatabaseName(String databaseName) {
            this.databaseName = databaseName;
        }
    ​

  2. 配置中使用property标签value属性注入简单类型数据

        <bean id="bookDao" class="com.wen.dao.impl.BookDaoImpl">
            <property name="databaseName" value="mysql"/>
        </bean>

构造器注入---引用类型(了解)

  1. 在bean中定义引用类型属性并提供可访问的构造方法

    public class BookServiceImpl implements BookService{
        private BookDao bookDao;
        private UserDao userDao;
    
        public BookServiceImpl(BookDao bookDao, UserDao userDao) {
            this.bookDao = bookDao;
            this.userDao = userDao;
        }
    }
  2. 配置中使用constructor-arg标签ref属性注入引用类型对象

        <bean id="userDao" class="com.wen.dao.impl.UserDaoImpl"/>
        <bean id="bookService" class="com.wen.service.impl.BookServiceImpl">
            <constructor-arg name="bookDao" ref="bookDao"/>
            <constructor-arg name="userDao" ref="userDao"/>

构造器注入--简单类型(了解)

  1. 在bean中定义引用类型属性并提供可访问的set方法

    public class BookDaoImpl implements BookDao {
        private String databaseName;
        private int connectionNum;
    
        public BookDaoImpl(String databaseName, int connectionNum) {
            this.databaseName = databaseName;
            this.connectionNum = connectionNum;
        }
    
        public void save() {
            System.out.println("book dao save ..."+databaseName+","+connectionNum);
        }
    }
    
  2. 配置中使用constructor-arg标签value属性注入简单类型数据

    <!--    <bean id="bookDao" class="com.wen.dao.impl.BookDaoImpl">-->
    <!--        <constructor-arg name="connectionNum" value="100"/>-->
    <!--        <constructor-arg name="databaseName" value="mysql"/>-->
    
    <!--    </bean>-->

4.2依赖自动装配

  • Ioc容器根据bean所依赖的资源在容器中自动查找并注入到bean的过程叫自动装配

  • 自动装配方式

    • 按类型

    • 按名称

    • 按构造方法

配置中使用bean标签autowire属性设置自动装配的类型

 <bean id="userDao" class="com.wen.dao.impl.BookDaoImpl"/>

    <bean id="bookService" class="com.wen.service.impl.BookServiceImpl" autowire="byType"/>

4.3集合注入

        <property name="array">
            <array>
                <value>100</value>
                <value>200</value>
                <value>300</value>
            </array>
        </property>
        <property name="list">
            <list>
                <value>pp</value>
                <value>kk</value>
                <value>jj</value>
            </list>
        </property>
        <property name="set">
            <set>
                <value>100</value>
                <value>200</value>
                <value>300</value>
                <value>300</value>
            </set>
        </property>
        <property name="map">
            <map>
                <entry key="country" value="china"/>
                <entry key="province" value="shanxi"/>
                <entry key="city" value="xin"/>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="country">china</prop>
                <prop key="province">shanxi</prop>
                <prop key="city">xin</prop>
            </props>
        </property>

5.1第三方资源配置管理

导入druid坐标

    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.16</version>
    </dependency>

配置数据源对象作为spring管理的bean

    <bean id="dataSource"  class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc//:mysql://localhost:3306/spring_db"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>

5.2加载properties配置信息

开启context命名空间

<?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

使用context命名空间,加载指定properties文件

        2.使用context空间加载properties文件
-->
    <context:property-placeholder location="jdbc.properties"/>
<!--    3.使用属性站位符${}读取properties中的属性-->
    <bean  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>

    <bean id="bookDao" class="com.wen.dao.impl.BookDaoImpl">
            <property name="name" value="${}"/>
    </bean>

6.1容器

创建

  • ClassPathXmlApplicationContext

  • FileSystemXmlApplicationContext

BeanFactory是Ioc容器的顶层接口,初始化BeanFactory对象时,加载的bean延迟加载 (lazy-init="true")

ApplicationContext接口是Spring容器的核心接口,初始化bean立即加载

ApplicationContext接口提供基础的bean操作相关方法,通过其他接口扩展其功能

3.注解

1.1注解开发定义bean

  • 使用@Component定义bean

@Component("bookDao")
public class BookDaoImpl implements BookDao{}

@Component
public class BookServiceImpl implements BookService{}
  • 核心配置文件中通过组件扫描加载bean

<context:component-scan base-package="com.wen"/>

1.2纯注解开发

  • java类代替Spring核心配置文件

    //声明当前类为Spring配置类
    @Configuration
    //设置bean扫描路径,多个路径书写为字符串数组格式
    @ComponentScan({"com.wen.service", "com.wen.dao"})
    public class SpringConfig {
    }
  • @Configuration注解用于设定当前类为配置

  • @Configuration注解用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式

    @ComponentScan({"com.wen.service", "com.wen.dao"})
  • 读取Spring核心配置文件初始化容器对象切换为读取Java配置类初始化容器对象

            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    
      //AnnotationConfigApplicationContext加载Spring配置类初始化Spring容器
            ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

1.3bean作用范围

  • 使用@Scope定义bean作用范围

    @Repository
    //@Scope设置bean的作用范围
    @Scope("singleton")
    public class BookDaoImpl implements BookDao {
    }
  • 使用@PostConstruct.@PreDestory定义bean生命周期

    @Repository
    //@Scope设置bean的作用范围
    @Scope("singleton")
    public class BookDaoImpl implements BookDao {
    
        public void save() {
            System.out.println("book dao save ...");
        }
        //@PostConstruct设置bean的初始化方法
        @PostConstruct
        public void init() {
            System.out.println("init ...");
        }
        //@PreDestroy设置bean的销毁方法
        @PreDestroy
        public void destroy() {
            System.out.println("destroy ...");
        }
    
    }
    

2.1依赖注入

  • 使用@Qualifier注解开启指定名称装配bean

@Service
public class BookServiceImpl implements BookService {
    //@Autowired:注入引用类型,自动装配模式,默认按类型装配
    @Autowired
    //@Qualifier:自动装配bean时按bean名称装配
    @Qualifier("bookDao")
    private BookDao bookDao;
​
    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

注意: @Qualifiler注解无法单独使用,必须配合@Autowired注解使用

  • 使用@Value实现简单类型注入

        //@Value:注入简单类型(无需提供set方法)
        @Value("${name}")
        private String name;
    ​
  • 加载properties文件

    • 使用@PropertySource注解加载properties文件

      @Configuration
      @ComponentScan("com.wen")
      //@PropertySource加载properties配置文件
      @PropertySource({"jdbc.properties"})
      public class SpringConfig {
      }   
    • 注意:路径仅仅支持单一文件配置,多文件请使用数组格式配置,不允许使用通配符*

2.2第三方bean管理,第三方依赖注入

  • 使用@Bean配置第三方bean

  • 使用Import注解手动加入配置类到核心配置,此注解只能添加一次,多个请使用数组格式

    @Configuration
    @ComponentScan("com.wen")
    //@Import:导入配置信息
    @Import({JdbcConfig.class})
    public class SpringConfig {
    }
    
    
    public class JdbcConfig {
        //1.定义一个方法获得要管理的对象
        @Value("com.mysql.jdbc.Driver")
        private String driver;
        @Value("jdbc:mysql://localhost:3306/spring_db")
        private String url;
        @Value("root")
        private String userName;
        @Value("root")
        private String password;
        //2.添加@Bean,表示当前方法的返回值是一个bean
        //@Bean修饰的方法,形参根据类型自动装配
        @Bean
        public DataSource dataSource(){
            DruidDataSource ds = new DruidDataSource();
            ds.setDriverClassName(driver);
            ds.setUrl(url);
            ds.setUsername(userName);
            ds.setPassword(password);
            return ds;
        }
    } 
  • 引用类型依赖注入

        @Bean
        public DataSource dataSource(BookDao bookDao){
            System.out.println(bookDao);
            DruidDataSource ds = new DruidDataSource();
            ds.setDriverClassName(driver);
            ds.setUrl(url);
            ds.setUsername(userName);
            ds.setPassword(password);
            return ds;
        }
  • 引用类型注入只需要为bean定义方法设置形参即可,容器会根据类型自动装配

3.1Xml配置与注解配置比较

4.Spring整合Mybits

1.mybits

public static void main(String[] args) throws IOException {
        // 1. 创建SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        // 2. 加载SqlMapConfig.xml配置文件
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml.bak");
        // 3. 创建SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        // 4. 获取SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 5. 执行SqlSession对象执行查询,获取结果User
        AccountDao accountDao = sqlSession.getMapper(AccountDao.class);

        Account ac = accountDao.findById(2);
        System.out.println(ac);

        // 6. 释放资源
        sqlSession.close();
    }
2.Spring整合Mybatis
public class MybatisConfig {
    //定义bean,SqlSessionFactoryBean,用于产生SqlSessionFactory对象
    @Bean
    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
        SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
        ssfb.setTypeAliasesPackage("com.itheima.domain");
        ssfb.setDataSource(dataSource);
        return ssfb;
    }
    //定义bean,返回MapperScannerConfigurer对象
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer(){
        MapperScannerConfigurer msc = new MapperScannerConfigurer();
        msc.setBasePackage("com.itheima.dao");
        return msc;
    }
}
3.Spring整合JUnit
//设置类运行器
@RunWith(SpringJUnit4ClassRunner.class)
//设置Spring环境对应的配置类
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceTest {
    //支持自动装配注入bean
    @Autowired
    private AccountService accountService;

    @Test
    public void testFindById(){
        System.out.println(accountService.findById(1));

    }

    @Test
    public void testFindAll(){
        System.out.println(accountService.findAll());
    }


}

5.Aop

1.1Aop简介

  • AOP面向切面编程,一种编程范式,指导开发着如何组织程序结构

    • OOP面向对象编程

  • 作用:在不动原始设计的基础上为其进行功能增强

    • spring理念:无侵入式

1.2AOP核心概念

  • 连接点:程序执行过程中的任意位置,粒度为执行方法.抛出异常.设置变量

    • 在SpringAOP中.理解为方法的执行

  • 切入点:匹配连接点的式子

  • 在spring中,一个切入点可以只描述一个具体方法,也可以匹配多个方法

    • 一个具体方法com.itheima.dao包下的BookDao接口中的无参无返回值的save方法

    • 匹配多个方法:所有的save方法,所有的get开头的方法,有所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法

  • 通知:在切入点处执行的操作,也就是共性功能

    • 在SpringAOP中,功能最终以方法的形式呈现

  • 通知类:定义通知的类

  • 切面:描述通知与切入点的对应关系

2.1AOP的入门案例

  1. 导包

  2. 制作连接点方法(原始操作,Dao接口与实现类)

  3. 制作公共功能(通知类与通知)

  4. 第一切入点

  5. 绑定切入点和通知关系(切面)

2.2AOP入门案例(注解版)

  1. 导包

  2. 定义Dao接口和实现类

    @Repository
    public class BookDaoImpl implements BookDao {
    ​
        public void save() {
            System.out.println(System.currentTimeMillis());
            System.out.println("book dao save ...");
        }
    ​
        public void update(){
            System.out.println("book dao update ...");
        }
    }
    ​
  3. 定义通知类,制作通知

    public class MyAdvice{
        public void before(){
            System.out.println(System.currentTimeMillis());
        }
    }
  4. 定义切入点

    //通知类必须配置成Spring管理的bean
    @Component
    //设置当前类为切面类类
    @Aspect
    public class MyAdvice {
        //设置切入点,要求配置在方法上方
        @Pointcut("execution(void com.itheima.dao.BookDao.update())")
        private void pt(){}
    }
  5. 绑定切入点与通知关系,并指定通知添加到原始连接点的具体执行位置

     //设置切入点,要求配置在方法上方
        @Pointcut("execution(void com.itheima.dao.BookDao.update())")
        private void pt(){}
    
        //设置在切入点pt()的前面运行当前操作(前置通知)
        // @Before("pt()")
        public void method(){
            System.out.println(System.currentTimeMillis());
        }
  6. 开启Spring对Aop注解驱动支持

    @Configuration
    @ComponentScan("com.itheima")
    //开启注解开发AOP功能
    @EnableAspectJAutoProxy
    public class SpringConfig {
    }

3.1AOP工作流程

  1. Spring容器启动

  2. 读取所有切面配置中的切入点

  3. 初始化bean,判定bean对应的类中的方法是否匹配到任意切点

    • 匹配失败,创建对象

    • 匹配成功,创建原始对象(目标对象)的代理对象

  4. 获取bean执行方法

    • 获取bean,调用方法并执行,完成操作

    • 获取bean是代理时,根据代理对象的运行模式运行原始方法与增强的内容,完成操作3

3.2核心概念

  • 目标对象:原始功能去掉共性功能对应的类产生的对象,这种对象是无法直接完成最终工作的

  • 代理(Proxy):目标对象无法直接完成工作,需要对其进行功能回填,通过原始对象的代理对象实现

3.3SpringAOP本质

本质:代理模式

4.1AOP切入点表达式

  • 切入点:要进行增强的方法

  • 切入点表达式:要进行增强的方法的描述方式

  • 切入点表达式标准格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数) 异常名

    execution(public void com.itheima.dao.BookDao.update(int))
  • 可以使用通配符描述切入点,快速描述

    • *:

      execution(public * com.itheima.*.BookDao.find*(int))
    • ..

      execution(public .. com.itheima.dao.BookDao.update(..))
  • 书写技巧

4.2AOP通知类型

  • AOP通知描述了抽取的公共功能,根据共性功能抽取的位置不同,最终运行的代码时要将其加入到合理的位置

  • AOP通知共分为5中类型

    • 前置通知

      •     //@Before:前置通知,在原始方法运行之前执行
              @Before("pt()")
            public void before() {
                System.out.println("before advice ...");

    • 后置通知

      • //@After:后置通知,在原始方法运行之后执行
         @After("pt2()")
         public void after() {
             System.out.println("after advice ...");
         }
           

    • 环绕通知 ProceedingJoinPoint
      • //@Around:环绕通知,在原始方法运行的前后执行
        //    @Around("pt()")
            public Object around(ProceedingJoinPoint pjp) throws Throwable {
                System.out.println("around before advice ...");
                //表示对原始操作的调用
                Object ret = pjp.proceed();
                System.out.println("around after advice ...");
                return ret;
            }

    • 返回后通知(了解)

    • 抛出异常后通知(了解)

4.3案例:测量业务层接口万次执行效率

@Component
@Aspect
public class ProjectAdvice {
    //匹配业务层的所有方法
    @Pointcut("execution(* com.itheima.service.*Service.*(..))")
    private void servicePt(){}

    //设置环绕通知,在原始操作的运行前后记录执行时间
    @Around("ProjectAdvice.servicePt()")
    public void runSpeed(ProceedingJoinPoint pjp) throws Throwable {
        //获取执行的签名对象
        Signature signature = pjp.getSignature();
        String className = signature.getDeclaringTypeName();
        String methodName = signature.getName();

        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
           pjp.proceed();
        }
        long end = System.currentTimeMillis();
        System.out.println("万次执行:"+ className+"."+methodName+"---->" +(end-start) + "ms");
    }

}

4.4 AOP通知获取数据

获取参数
  • 获取切入点方法的参数

    • JoinPoint:适用于前置,后置,返回后,抛出异常后通知

    • ProceedJointPoint:适用于环绕通知

   //JoinPoint:用于描述切入点的对象,必须配置成通知方法中的第一个参数,可用于获取原始方法调用的参数
//    @Before("pt()")
    public void before(JoinPoint jp) {
        Object[] args = jp.getArgs();
        System.out.println(Arrays.toString(args));
        System.out.println("before advice ..." );
    }

//    @After("pt()")
    public void after(JoinPoint jp) {
        Object[] args = jp.getArgs();
        System.out.println(Arrays.toString(args));
        System.out.println("after advice ...");
    }

获取返回值
  • 获取切入点方法返回值

    • 返回后通知

    • 环绕通知

@Around("pt()")  
public Object around(ProceedingJoinPoint pjp) {
        Object[] args = pjp.getArgs();
      return ret;
  }

获取异常
  • 获取切入点方法运行异常信息

    • 抛出异常后通知

    • 环绕通知

4.5案例:百度网盘密码数据兼容处理

@Component
@Aspect
public class DataAdvice {
    @Pointcut("execution(boolean com.itheima.service.*Service.*(*,*))")
    private void servicePt(){}

    @Around("DataAdvice.servicePt()")
    public Object trimStr(ProceedingJoinPoint pjp) throws Throwable {
        Object[] args = pjp.getArgs();
        for (int i = 0; i < args.length; i++) {
            //判断参数是不是字符串
            if(args[i].getClass().equals(String.class)){
                args[i] = args[i].toString().trim();
            }
        }
        Object ret = pjp.proceed(args);
        return ret;
    }
 

4.6 AOP总结

6. Spring事务简介

1. Spring事务简介

事务作用:在数据层保障一系列的数据库操作同成功同失败

Spring事务作用:在数据层或 业务层保障一系列的数据库操作同成功同失败

1.业务层接口上添加Spring事务管理

public interface AccountService {
    @Transactional
    public void transfer (String out,String in,Double money);
}

注意事项: Spring注解式事务通常添加在业务接口中而不会添加到业务层实现类中,降低耦合 注解式事务可以添加到业务方法上表示当前方法开启事务,也可以添加到接口上表示当前接口所有方法开启事务

2.设置事务管理器

@Bean
public PlatfromTransactionManager transactionManager(DataSource dataSource){
    DataSourceTransactionManager ptm = new DataSourceTransactionManager();
    ptm.setDataSource(dataSource);
    return ptm;
}

注意事项:

事务管理器要根据实现技术进行选则

Mybatis框架使用的是JDBC事务

3.开启注解式事务驱动

@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class})
@EnableTransactionManagement
public class SpringConfig{
}

2 Spring事务角色

事务角色

  • 事务管理员:发起事务方,在Spring中通常指代业务层开启事物的方法

  • 事务协调员:假如事务方,在Spring中通常指代数据层方法,也可以是业务层方法

3 事务相关配置

1.事务相关配置

2.事务传播行为

public interface LogService {
    //propagation设置事务属性:传播行为设置为当前操作需要新事务
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    void log(String out, String in, Double money);
}
​
​
​
@Service
public class LogServiceImpl implements LogService {
​
    @Autowired
    private LogDao logDao;
        public void log(String out,String in,Double money ) {
        logDao.log("转账操作由"+out+"到"+in+",金额:"+money);
    }
}

7.SpringMVC简介

1.1 SpringMVC概述

  • SpringMVC技术与Servlet技术功能等同,均属于web层技术开发

  • SpringMVC是一种基于Java实现MVC模型的轻量级Web框架

  • 优点

    • 使用简单,开发便捷(相比于Servlet)

    • 灵活性强

1.2 SpringMVC入门案例

  1. 导包

  2. 创建SpringMVC控制器类(等同于Servlet功能)

    //定义表现层控制器bean
    @Controller
    public class UserController {
    
        //设置映射路径为/save,即外部访问路径
        @RequestMapping("/save")
        //设置当前操作返回结果为指定json数据(本质上是一个字符串信息)
        @ResponseBody
        public String save(){
            System.out.println("user save ...");
            return "{'info':'springmvc'}";
        }
  3. 初始化SpringMVC环境(同Spring环境),设定SPringMVC加载对应的bean

    //springmvc配置类,本质上还是一个spring配置类
    @Configuration
    @ComponentScan("com.itheima.controller")
    public class SpringMvcConfig {
    }
  4. 初始化Servlet容器,加载SpringMVC环境,并设置SpringMVC技术处理的请求

    //web容器配置类
    public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
        //加载springmvc配置类,产生springmvc容器(本质还是spring容器)
        protected WebApplicationContext createServletApplicationContext() {
            //初始化WebApplicationContext对象
            AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
            //加载指定配置类
            ctx.register(SpringMvcConfig.class);
            return ctx;
        }
    ​
        //设置由springmvc控制器处理的请求映射路径
        protected String[] getServletMappings() {
            return new String[]{"/"};
        }
    ​
        //加载spring配置类
        protected WebApplicationContext createRootApplicationContext() {
            return null;
        }
    }
    ​

1.3入门案例工作流程分析

  • 启动服务器初始化过程

    1. 服务器启动,执行ServletContainersInitConfig类,初始化web容器

    2. 执行createServletApplicationContext方法,创建了WebApplicationContext对象

    3. 加载SpringMvcConfig

    4. 执行@ComponentScan加载对应的bean

    5. 加载UserController,每个@RequestMapping的名称对应一个具体的方法

    6. 执行getServletMappings方法,定义所有的请求都通过SpringMVC

  • 单词请求过程

    1. 发送请求localhost/save

    2. web容器发现所有请求都经过SpringMVC,将请求交给SpringMVC处理

    3. 解析请求路径/save

    4. 由/save匹配执行对应的方法save()

    5. 执行save()

    6. 检测到有@ResponseBody直接将save()方法的返回值作为响应求体返回给请求方

1.4 Controller加载控制

@Configuration
//@ComponentScan({"com.itheima.service","com.itheima.dao"})
//设置spring配置类加载bean时的过滤规则,当前要求排除掉表现层对应的bean
//excludeFilters属性:设置扫描加载bean时,排除的过滤规则
//type属性:设置排除规则,当前使用按照bean定义时的注解类型进行排除
//classes属性:设置排除的具体注解类,当前设置排除@Controller定义的bean
@ComponentScan(value="com.itheima",
    excludeFilters = @ComponentScan.Filter(
        type = FilterType.ANNOTATION,
        classes = Controller.class
    )
)
public class SpringConfig {
}
  • 属性

    • excludeFilters:排除扫描路径中加载的bean,需要指定类别(type)与具体项(classse)

    • includeFilters:加载指定的bean,需要指定类别(type)与具体项(classes)

bean加载格式

//web配置类简化开发,仅设置配置类类名即可
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
​
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SpringConfig.class};
    }
​
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMvcConfig.class};
    }
​
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

2.1请求映射路径

@RequestMapping

  • 作用:访问当前控制器方法请求访问路径,如果设置在类上统一设置当前控制器方法请求访问路径前缀

  • 属性

    • value(默认):请求访问路径,或访问路径前缀

@Controller
public class BookController {
    //请求路径映射
    @RequestMapping("/book/save")
    @ResponseBody
    public String save(){
        System.out.println("book save ...");
        return "{'module':'book save'}";
    }
}
​

2.2请求方式

  • Get请求

  • Post请求

  • 为web容器添加过滤器并指定字符集,Spring——web包中提供了专用的字符过滤器

       //乱码处理
        @Override
        protected Filter[] getServletFilters() {
            CharacterEncodingFilter filter = new CharacterEncodingFilter();
            filter.setEncoding("UTF-8");
            return new Filter[]{filter};
        } 

2.3请求参数

  • @RequestParam

       //普通参数:请求参数名与形参名不同时,使用@RequestParam注解关联请求参数名称与形参名称之间的关系
        @RequestMapping("/commonParamDifferentName")
        @ResponseBody
        public String commonParamDifferentName(@RequestParam("name") String userName , int age){
            System.out.println("普通参数传递 userName ==> "+userName);
            System.out.println("普通参数传递 age ==> "+age);
            return "{'module':'common param different name'}";
        }
  • POJO参数:请求参数名与形参对象属性名相同,定义POJO类型形参即可接收参数

        //POJO参数:请求参数与形参对象中的属性对应即可完成参数传递
        @RequestMapping("/pojoParam")
        @ResponseBody
        public String pojoParam(User user){
            System.out.println("pojo参数传递 user ==> "+user);
            return "{'module':'pojo param'}";
        }
  • 嵌套POJO参数:请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性参数

  • 数组参数:请求参数名与形参对象属性名相同且请求参数为多个,定义数组类型形参即可接收参数

        //数组参数:同名请求参数可以直接映射到对应名称的形参数组对象中
        @RequestMapping("/arrayParam")
        @ResponseBody
        public String arrayParam(String[] likes){
            System.out.println("数组参数传递 likes ==> "+ Arrays.toString(likes));
            return "{'module':'array param'}";
        }
  • 集合保存普通参数:请求参数参数名形参集合对象名相同请求参数为多个,@RequestParam绑定参数关系

        //集合参数:同名请求参数可以使用@RequestParam注解映射到对应名称的集合对象中作为数据
        @RequestMapping("/listParam")
        @ResponseBody
        public String listParam(@RequestParam List<String> likes){
            System.out.println("集合参数传递 likes ==> "+ likes);
            return "{'module':'list param'}";
        }

2.4请求参数(传递json数据)

  • @EnableWebMvc

    @Configuration
    @ComponentScan("com.itheima.controller")
    //开启json数据类型自动转换
    @EnableWebMvc
    public class SpringMvcConfig {
    }
    ​
  • @RequestBody

     @RequestMapping("/listParam")
        @ResponseBody
        public String listParam(@RequestBody List<String> likes){
            System.out.println("集合参数传递 likes ==> "+ likes);
            return "{'module':'list param'}";
        }

2.5日期类型参数传递

  • @DataTimeFormat

    • 属性:pattern:日期时间格式字符串

        //日期参数
        //使用@DateTimeFormat注解设置日期类型数据格式,默认格式yyyy/MM/dd
        @RequestMapping("/dataParam")
        @ResponseBody
    public String dataParam(Date date,
          @DateTimeFormat(pattern="yyyy-MM-dd") Date date1,
          @DateTimeFormat(pattern="yyyy/MM/dd HH:mm:ss") Date date2){
        System.out.println("参数传递 date ==> "+date);
        System.out.println("参数传递 date1(yyyy-MM-dd) ==> "+date1);
        System.out.println("参数传递 date2(yyyy/MM/dd HH:mm:ss) ==> "+date2);
            return "{'module':'data param'}";
        }
  • Converter接口

  • @EnableWebMvc功能之一:根据类型匹配对应的类型转换器

    public interface Converter<S,T>{
        @Nullable
        T converter(S var1);
    }
    • 请求参数年龄数据(String-->Integer)

    • 日期格式转换(String--->Date)

3.1响应

  • 响应文本数据(了解)

  • 响应json数据

3.2REST风格

REST:风格简介

3.3RESTful入门案例

  1. 设定http请求动作(动词)

        //设置当前请求方法为POST,表示REST风格中的添加操作
        @RequestMapping(value = "/users",method = RequestMethod.POST)
        @ResponseBody
        public String save(){
            System.out.println("user save...");
            return "{'module':'user save'}";
        }
    ​
    ​
        //设置当前请求方法为PUT,表示REST风格中的修改操作
        @RequestMapping(value = "/users",method = RequestMethod.PUT)
        @ResponseBody
        public String update(@RequestBody User user){
            System.out.println("user update..."+user);
            return "{'module':'user update'}";
        }
    ​
  2. 设定请求参数(路径变量)

        //设置当前请求方法为DELETE,表示REST风格中的删除操作
        //@PathVariable注解用于设置路径变量(路径参数),要求路径上设置对应的占位符,并且占位符名称与方法形参名称相同
        @RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)
        @ResponseBody
        public String delete(@PathVariable Integer id){
            System.out.println("user delete..." + id);
            return "{'module':'user delete'}";
        }
  3. @RequestMapping

    • 作用:设置当前控制器方法请求访问路径

    • 属性:

      • value:请求访问路径

      • method:http请求动作,标准动作(GET/POST/PUT/DELETE)

  4. @PathVarIable

    • 类型:形参注解

    • 位置:SpringMVC控制器方法形参定义前面

    • 作用:绑定路径参数与处理器方法形参间的关系,要求路径参数名与形参名一一对应

      •     //设置当前请求方法为DELETE,表示REST风格中的删除操作
            //@PathVariable注解用于设置路径变量(路径参数),要求路径上设置对应的占位符,并且占位符名称与方法形参名称相同
            @RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)
            @ResponseBody
            public String delete(@PathVariable Integer id){
                System.out.println("user delete..." + id);
                return "{'module':'user delete'}";
            }

3.4RESTful快速开发

  • @RestController

    • 作用:设置当前控制器类为RESTful风格,等同于@Controller与@ResponseBody两个注解的结合

    • @RequestMapping("/books")
      public class BookController2 {
      

3.5基于RESTful页面数据交互

  1. 制作SpringMVC控制器,并通过POSTMan测试接口功能

    @RestController
    @RequestMapping("/books")
    public class BookController {
    
        @PostMapping
        public String save(@RequestBody Book book){
            System.out.println("book save ==> "+ book);
            return "{'module':'book save success'}";
        }
    
        @GetMapping
        public List<Book> getAll(){
            System.out.println("book getAll is running ...");
            List<Book> bookList = new ArrayList<Book>();
    
            Book book1 = new Book();
            book1.setType("计算机");
            book1.setName("SpringMVC入门教程");
            book1.setDescription("小试牛刀");
            bookList.add(book1);
    
            return bookList;
        }
    
    }
  2. 设置对静态资源的访问放行

    @Configuration
    public class SpringMvcSupport extends WebMvcConfigurationSupport {
        //设置静态资源访问过滤,当前类需要设置为配置类,并被扫描加载
        @Override
        protected void addResourceHandlers(ResourceHandlerRegistry registry) {
            //当访问/pages/????时候,从/pages目录下查找内容
            registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
     registry.addResourceHandler("/js/**").addResourceLocations("/js/");
            registry.addResourceHandler("/css/**").addResourceLocations("/css/");
            registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
        }
    }
  3. 前端页面通过异步提交访问后台控制器

                        //添加
                        saveBook () {
                            axios.post("/books",this.formData).then((res)=>{
    ​
                            });
                        },
    ​
                        //主页列表查询
                        getAll() {
                            axios.get("/books").then((res)=>{
                                this.dataList = res.data;
                            });
                        },

8. SSM框架整合

8.1SSM整合流程

  1. 创建工程

  2. SSM整合

    • Spring

      • SpringConfig

    • Mybatis

      • MybatisConfig

      • JdbcConfig

      • jdbc.properties

    • SpringMVC

      • ServletConfig

      • SpringMvcConfig

  3. 功能模块

    • 标与实体类

    • dao(接口+自动代理)

    • service(接口+实现类)

      • 业务层接口测试(整合 JUnit)

    • controller

      • 表现层接口测试(PostMan)

  4. Spring整合Mybatis

    • 配置

      • SpringConfig

      • JDBCConfig,jdbc.properties

      • MyBatisConfig

    • 模型

      • Book

    • 数据层标准开发

      • BookDao

    • 业务层标准开发

      • BookService

      • BookServiceImpl

    • 测试接口

      • BookServiceTest

    • 事务处理

  5. Spring整合SpringMVC

    • web配置类

    • SpringMVC配置类

    • 基于Restful的Controller开发

8.2表现层数据封装

  • 前端接收数据格式-----创建结果模型类,封装数据到data属性中

  • 前端接收数据格式-----封装操作结果到code属性中

  • 前端接收数据格式-----封装特殊消息到message(msg)属性中

  • 设置统一数据返回结果类

    public class Result {
        //描述统一格式中的数据
        private Object data;
        //描述统一格式中的编码,用于区分操作,可以简化配置0或1表示成功失败
        private Integer code;
        //描述统一格式中的消息,可选属性
        private String msg;
    • 设置统一的数据返回结果编码

      //状态码
      public class Code {
          public static final Integer SAVE_OK = 20011;
          public static final Integer DELETE_OK = 20021;
          public static final Integer UPDATE_OK = 20031;
          public static final Integer GET_OK = 20041;
      ​
          public static final Integer SAVE_ERR = 20010;
          public static final Integer DELETE_ERR = 20020;
          public static final Integer UPDATE_ERR = 20030;
          public static final Integer GET_ERR = 20040;
      }
      ​
  • 根据情况设定合理的Result

    //统一每一个控制器方法返回值
    @RestController
    @RequestMapping("/books")
    public class BookController {
    
        @Autowired
        private BookService bookService;
        @GetMapping("/{id}")
        public Result getById(@PathVariable Integer id) {
            Book book = bookService.getById(id);
            Integer code = book != null ? Code.GET_OK : Code.GET_ERR;
            String msg = book != null ? "" : "数据查询失败,请重试!";
            return new Result(code,book,msg);
        }
    

8.3异常处理器

1.

  • 异常处理器

    • 集中的,统一的,处理项目中出现的异常

      //@RestControllerAdvice用于标识当前类为REST风格对应的异常处理器
      @RestControllerAdvice
      public class ProjectExceptionAdvice {
          //@ExceptionHandler用于设置当前处理器类对应的异常类型
          @ExceptionHandler(SystemException.class)
          public Result doSystemException(SystemException ex){
              return new Result(666,null);
          }
      }
  • ExceptionHandler

    • 作用:设置指定异常的处理方案,功能等同于控制器方法,出现异常后终止原始控制器执行,并转入当前方法执行

    • 此类方法可以根据处理的异常不同,制作多个方法分别处理对应的异常

2.

  • 项目异常分类

    • 业务异常

      • 规范用户行为产生的异常

      • 不规范的用户行为操作产生的异常

    • 系统异常

      • 项目运行过程中可预计且无法避免的异常

    • 其他异常

      • 编程人员位未预期刀的异常

  • 项目异常处理方案

    • 业务异常

      • 发送对应的消息传递给用户,体醒规范操作

    • 系统异常

      • 发送固定消息传递给用户,安抚用户

      • 提醒维护人员维护

      • 日志

    • 其他异常

      • 发送固定消息传递给用户,安抚用户

      • 提醒维护人员维护

      • 日志

  1. 自定义项目系统级异常

  2. 自定义项目业务级异常

  3. 自定义异常编码

  4. 出发自定义异常

  5. 拦截并处理

    //@RestControllerAdvice用于标识当前类为REST风格对应的异常处理器
    @RestControllerAdvice
    public class ProjectExceptionAdvice {
        //@ExceptionHandler用于设置当前处理器类对应的异常类型
        @ExceptionHandler(SystemException.class)
        public Result doSystemException(SystemException ex){
            //记录日志
            //发送消息给运维
            //发送邮件给开发人员,ex对象发送给开发人员
            return new Result(ex.getCode(),null,ex.getMessage());
        }
    ​
        @ExceptionHandler(BusinessException.class)
        public Result doBusinessException(BusinessException ex){
            return new Result(ex.getCode(),null,ex.getMessage());
        }
    ​
        //除了自定义的异常处理器,保留对Exception类型的异常处理,用于处理非预期的异常
        @ExceptionHandler(Exception.class)
        public Result doOtherException(Exception ex){
            //记录日志
            //发送消息给运维
            //发送邮件给开发人员,ex对象发送给开发人员
            return new Result(Code.SYSTEM_UNKNOW_ERR,null,"系统繁忙,请稍后再试!");
        }
    }
    ​
  6. 异常处理器效果对比

  7. 自定义项目系统级异常

    axios.get("/books").then((res)=>{});
    axios.post("/books",this.formData).then((res)=>{});
    axios.delete("/books/"+row.id).then((res)=>{});
    axios.put("/books",this.formData).then((res)=>{});
    axios.get("/books"+row.id).then((res)=>{});

8.4 拦截器

拦截器概念

  • 拦截器是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行

  • 作用:

    • 在指定的方法调用前后执行预先设定的代码

    • 组织原始方法的执行

拦截器和过滤器的区别

  • 归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术

  • 拦截内容不同:Filter对所有访问进行增强,Intercepor仅针对SpringMVC的访问进行增强

制作拦截器功能类
​
配置拦截器的执行位置
  1. 声明拦截器的bean,并实现HandlerInterceptor接口(注意:扫描加载bean)

    @Component
    //定义拦截器类,实现HandlerInterceptor接口
    //注意当前类必须受Spring容器控制
    public class ProjectInterceptor implements HandlerInterceptor { 
        @Override
        //原始方法调用前执行的内容
        //返回值类型可以拦截控制的执行,true放行,false终止
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            String contentType = request.getHeader("Content-Type");
            HandlerMethod hm = (HandlerMethod)handler;
            System.out.println("preHandle..."+contentType);
            return true;
        }
    ​
        @Override
        //原始方法调用后执行的内容
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("postHandle...");
        }
    ​
        @Override
        //原始方法调用完成后执行的内容
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("afterCompletion...");
        }
    }
    ​
  2. 定义配置类,继承WebMvcConfigurationSupport,实现addInterceptor方法(注意:扫描加载配置)

    @Configuration
    public class SpringMvcSupport extends WebMvcConfigurationSupport {
    
        @Override
        protected void addInterceptors(InterceptorRegistry registry) {
            ...
        }
    }
  3. 添加拦截器并设定拦截的访问路径,路径可以通过可变参数设置多个

    @Configuration
    public class SpringMvcSupport extends WebMvcConfigurationSupport {
        @Override
        protected void addInterceptors(InterceptorRegistry registry) {
            //配置拦截器
    registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
        }
    }
    
  4. 使用标准接口WebMvc'Configurer简化开发(注意:侵入式较强)

    @Configuration
    @ComponentScan("com.itheim.controller")
    @EnableWebMvc
    public class SpringMvcConfig implements WebMvcConfigurer{
    @Autowired
        private ProjectInterceptor projectInterceptor;
        
        public void addInterceptors(InterceptorRegistry){
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
        }
    }

多个拦截器执行顺序

  • 类似先进后出

9.Maven

9.1分模块开发与设计

  1. 分模块开发意义

    • 将原始模块按照功能拆成若干个子模块,方便模块间的相互调用,接口共享

  2. 新建新模块,放进去,在添加对应依赖,

  3. 依赖具有传递性

    • 直接依赖

    • 间接依赖

  4. 依赖冲突

    • 特殊优先:当同级配置了相同的资源的不同版本,后配置的覆盖先配置的

    • 声明优先:当资源在相同层级被依赖时,配置顺序考前

    • 路径优先:当依赖中出现相同的

9.2继承与聚合

聚合

  • 作用:使用聚合工程可以将多个工程编组,通过对聚合工程进行构建,实现对所包含的模块进行同步构建

    • 当工程中某个模块发生更新时,必须保障工程中与已更新模块关联的模块同步更新,此时可以使用聚合工程来解决批量模块同步构建的问题

  1. 创建Maven模块,设置打包类型

    <packaging>pom<packaging>
  2. 设置当前聚合工程所包含的子模块名称

      <modules>
        <module>../maven_02_ssm</module>
      </modules>

继承

  1. 创建Maven模块,设置打包类型为pom

  2. 在父工程的pom文件中配置依赖关系(子工程将沿用父工程中的依赖关系)

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.10.RELEASE</version>
            </dependency>
    </dependencies>  
  3. 配置子工程中可选的依赖关系

    <!--定义依赖管理-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
  4. 在子过程中配置当前工程所继承的父工程

    定义该工程的父工程
    <parent>
        <groupId>com.itheima</groupId>
        <artifactId>maven_parent</artifactId>
        <version>1.0-SNAPSHOT</version>
        填写父工程的文件
        <relativePath>../maven_parent/pom.xml</relativePath>
    </parent>
  5. 在子工程中配置使用父工程中可选依赖的坐标

    <dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            </dependency>
    </dependencies>  

属性

  1. 定义属性

    <!--定义属性-->
    <properties>
        <spring.version>5.2.10.RELEASE</spring.version>
        <junit.version>4.12</junit.version>
        <mybatis-spring.version>1.3.0</mybatis-spring.version>
        <!--<jdbc.url>jdbc:mysql://127.0.0.1:3306/ssm_db</jdbc.url>-->
    </properties>
  2. 引用属性

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
      撒旦 阿斯顿萨达会尽量快点撒发给发爱上覅偶尔ncy>

版本管理

9.3多环境配置与应用

9.4私服

10.SpringBoot

1.创建一个Spring
2.执行启动指令
java -jar springboot.jar
3.SpringBoot配置文件
4.整合JUnit

@SpringBootTest

@SpringBootTest(classes = Springboot07JunitApplication.class)
class Spirngboot07JunitApplicationTest{}
5.SpringBoot整合MyBatis(主要)
  • 设置数据源

    spring:
        datasource:
            type: com.alibaba.druid.pool.DruidDataSource
            driver-class-name: com.mysql.cj.jdbc.Driver
            url: jdbc:mysql://localhost:3306/ssm_db
            username: root
            pasword:  root
  • 定义数据层接口与映射配置

    @Mapper
    public interface UserDao{
        @Select("select * from user")
        public List<User> getAll();
    }
  • 测试类注入dao接口,测试功能

6.基于SpringBoot的SSM整合案例
  1. pom.xml

    配置起步依赖,必要的资源坐标(druid)

  2. application.yml

    设置数据源.端口等

  3. 配置类

    全部删除

  4. dao

    设置@Mapper

  5. 测试类

  6. 页面

    放置在resource目录下的static目录中

11.MybatisPlus完成标准Dao开发

1.1MybatisPlus简介

入门案例

  • 手动添加依赖

  • 设置Jdbc参数(application.yml)

  • 制作实体类与表结构(类名与表名对应,属性与字段名对应)

  • 定义数据接口,继承BaseMapper<User>

    @Mapper
    public interface UserDao extends BaseMapper<User>{
        
    }
  • 测试类中注入Dao接口,测试功能

    @SpringBootTest
    class Mybatispuls01QuickstartApplicationTest{
        @Autowired
        private UserDao userdao;
        @Test
        public void testGetAll(){
            List<User> userList = userDao.selectList(null);
            userList.forEach(System.out::println);
        }
    }

MybatisPlus特性

  • 无侵入:只做增强不做改变,不会对现有的工程产生影响

  • 强大的 CRUD 操作:内置通用 Mapper,少量配置即可实现单表CRUD操作

  • 支持 Lambda :编写查询条件无需担心字段写错

  • 支持主键自动生成

  • 内置分页插件

  • ...........

lombok依赖包 @Data

1.2MP分页查询功能

  1. 设置分页拦截器作为Spring管理的bean

    @Configuration
    public class MpConfig {
        @Bean
        public MybatisPlusInterceptor mpInterceptor(){
            //1.定义Mp拦截器
            MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
            //2.添加具体的拦截器
            mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
            return mpInterceptor;
        }
    }
    ​
  2. 执行分页查询

        void textGetByPage(){
            IPage page = new Page(1,2);
            userDao.selectPage(page,null);
            System.out.println("当前页码值:"+page.getCurrent());
            System.out.println("每页显示数:"+page.getSize());
            System.out.println("一共多少页:"+page.getPages());
            System.out.println("一共多少条数据:"+page.getTotal());
            System.out.println("数据:"+page.getRecords());
        }
  • 开启日志

  • mybatis-plus:
        configuration:
            log-impl:org.apache.ibatis.logging.stdout.StdOutImpl

1.3条件查询

//方式一:按条件查询
        QueryWrapper qw = new QueryWrapper();
        qw.lt("age",18);
        List<User> userList = userDao.selectList(qw);
        System.out.println(userList);
​
//方式二:lambda格式按条件查询
        QueryWrapper<User> qw = new QueryWrapper<User>();
        qw.lambda().lt(User::getAge, 10);
        List<User> userList = userDao.selectList(qw);
        System.out.println(userList);
​
//方式三:lambda格式按条件查询
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        lqw.lt(User::getAge, 10);
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);

1.4 条件查询-null值处理

//null判定
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        lqw.lt(User::getAge, uq.getAge2());
        if( null != uq.getAge()) {
            lqw.gt(User::getAge, uq.getAge());
        }
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);
​
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//先判定第一个参数是否为true,如果为true连接当前条件
//      lqw.lt(null != uq.getAge2(),User::getAge, uq.getAge2());
//      lqw.gt(null != uq.getAge(),User::getAge, uq.getAge());
        lqw.lt(null != uq.getAge2(),User::getAge, uq.getAge2())
           .gt(null != uq.getAge(),User::getAge, uq.getAge());
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);

1.4查询投影

 //查询投影
//        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//        lqw.select(User::getId,User::getName,User::getAge);
//        QueryWrapper<User> lqw = new QueryWrapper<User>();
//        lqw.select("id","name","age","tel");
//        List<User> userList = userDao.selectList(lqw);
//        System.out.println(userList);
​
//        QueryWrapper<User> lqw = new QueryWrapper<User>();
//        lqw.select("count(*) as count, tel");
//        lqw.groupBy("tel");
//        List<Map<String, Object>> userList = userDao.selectMaps(lqw);
//        System.out.println(userList);

查询条件

//条件查询
       LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        //等同于=
        lqw.eq(User::getName,"Jerry").eq(User::getPassword,"jerry");
        User loginUser = userDao.selectOne(lqw);
        System.out.println(loginUser);
​
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        //范围查询 lt le gt ge eq between
        lqw.between(User::getAge,10,30);
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);
​
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        //模糊匹配 like
        lqw.likeLeft(User::getName,"J");
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);
​

1.5字段映射与表名映射

@TableField

  • 作用: 设置当前属性对应的数据库表中的字段关系

    • value #select:设置属性是否参与查询,此属性与value()映射不冲突

    public class User{
        @TableField(value = "pwd",select = false)
        private String password;
    }
    • exist: 设置属性在数据库表字段中是否存在,默认为true.此属性无法发与value合并使用

      public class User{
          @TableField(exist=false)
          private Interage online;
      }

@TableName

  • 作用:设置当前类对应与数据库表关系

    @TableName("tbl_user")
    public class User{
        private Long id;
    }

1.6 id生产策略控制

@Table

  • 作用:设置当前类中主键属性的生成策略

    public class User{
        @Table(type = IdType.AUTO)
        private Long Id;
    }

1.7 多数据操作

  • 按照主键删除多条记录

List<Long> ids = Arrays.asList(new Long[]{2,3});
userDao.deleteBatchIds(ids);
  • 根据主键查询多条记录

List<Long> ids = Arrays.asList(new Long[]{2,3});
List<User> userList = userDao.selectBatchIds(ids);
  • 逻辑删除

  1. 实体类中添加对应字段,并设定当前字段为逻辑删除标记字段

    public class User{
        private Long id;
        @TableLogic
        private Interger deleted;
    }
  2. (通用的)配置逻辑删除字面值

    mybatis-plus:
        global-config:
            db-config:
                logic-delete-field:delete
                logic-not-delete-value:0
                logic-delete-value:1

1.8乐观锁

  1. 数据库里加入字段

  2. 在实体类中加入对应字段,并设定当前字段为逻辑删除字段

    public class User{
        private Long id;
        @Version
        private Integer version;
    }
  3. 配置乐观锁拦截器实现锁机制对应的动态SQL语句拼装

    @Congfiguration
        public class MpConfig{
        @Bean
        public MybatisPlusTnterceptor mpInterceptor(){
            MybatisPlusTnterceptor mpInterceptor = new MybatisPlusTnterceptor();
            mpIntercepor.addInnerInterceptor(new OptimisticLockerInterceptor());
            return mpInterceptor;
        }    
    ​
    }
  4. 使用乐观锁机制在修改前必须先获取到对应数据的Version方可正常进行

    @Test
    void testUpdate(){
        //先查询数据,获取到version数据
        User user = userDao.selectById(1L);
        //执行数据修改操作
        user.setName("Tom and Jerry");
        userDao.updateById(user);
    }

2.1快速开发

代码生成器

public class CodeGenerator {
    public static void main(String[] args) {
        AutoGenerator autoGenerator = new AutoGenerator();
        DataSourceConfig dataSource = new DataSourceConfig();
        dataSource.setDriverName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/jdbc?serverTimezone=UTC");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        autoGenerator.setDataSource(dataSource);
​
​
​
        //设置全局配置
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setOutputDir(System.getProperty("test.SSM")+"/mybatisplus_04/src/main/java");    //设置代码生成位置
        globalConfig.setOpen(false);    //设置生成完毕后是否打开生成代码所在的目录
        globalConfig.setAuthor("黑马程序员");    //设置作者
        globalConfig.setFileOverride(true);     //设置是否覆盖原始生成的文件
        globalConfig.setMapperName("%sDao");    //设置数据层接口名,%s为占位符,指代模块名称
        globalConfig.setIdType(IdType.ASSIGN_ID);   //设置Id生成策略
        autoGenerator.setGlobalConfig(globalConfig);
​
        //设置包名相关配置
        PackageConfig packageInfo = new PackageConfig();
        packageInfo.setParent("com.aaa");   //设置生成的包名,与代码所在位置不冲突,二者叠加组成完整路径
        packageInfo.setEntity("domain");    //设置实体类包名
        packageInfo.setMapper("dao");   //设置数据层包名
        autoGenerator.setPackageInfo(packageInfo);
​
        //策略设置
        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig.setInclude("tbl_user");  //设置当前参与生成的表名,参数为可变参数
        strategyConfig.setTablePrefix("tbl_");  //设置数据库表的前缀名称,模块名 = 数据库表名 - 前缀名  例如: User = tbl_user - tbl_
        strategyConfig.setRestControllerStyle(true);    //设置是否启用Rest风格
        strategyConfig.setVersionFieldName("version");  //设置乐观锁字段名
        strategyConfig.setLogicDeleteFieldName("deleted");  //设置逻辑删除字段名
        strategyConfig.setEntityLombokModel(true);  //设置是否启用lombok
        autoGenerator.setStrategy(strategyConfig);
        //2.执行生成操作
        autoGenerator.execute();
    }
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值