算法刷题笔记

Java - SSM 框架笔记

2024-06-06  本文已影响0人  Du1in9

👉 在线笔记:https://du1in9.github.io/ssm.github.io/

第1章 - Spring

1.1 Spring 入门

1.1.1 课程介绍

  1. 为什么要学?

    • Spring 技术是 JavaEE 开发必备技能,企业开发技术选型命中率 > 90%

    • 专业角度

      • 简化开发,降低企业级开发的复杂性
      • 框架整合,高效整合其他技术,提高企业级应用开发与运行效率
  1. 学什么?

    • 简化开发

      IOC、AOP(事务处理)

  1. 怎么学?

    • 学习 Spring 框架设计思想

    • 学习基础操作,思考操作与思想间的联系

    • 学习案例,熟练应用操作的同时,体会思想

1.1.2 相关概念

① 初识 Spring

② spring 系统架构

介绍完 Spring 的体系结构后,从中我们可以得出对于 Spring 的学习主要包含四部分内容,分别是:

  1. 核心容器(Core Container):Spring 的 IOC / DI
  2. 数据集成(Data Integration):IOC / DI 的具体应用,整合 Mybatis
  3. 面向切面编程(AOP),Aspects:Spring 的 AOP
  4. 事务(Transactions):AOP 的具体应用,事务管理

③ Spring 核心概念

1.1.3 入门案例

① IOC 入门案例

  1. 添加 Spring 的依赖 jar 包

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.10.RELEASE</version>
    </dependency>
    
  2. 添加案例中需要的类

    public interface BookDao {
        public void save();
    }
    public class BookDaoImpl implements BookDao {
        public void save() {
            System.out.println("book dao save ...");
        }
    }
    public interface BookService {
        public void save();
    }
    public class BookServiceImpl implements BookService {
        private BookDao bookDao = new BookDaoImpl();
        public void save() {
            System.out.println("book service save ...");
            bookDao.save();
        }
    }
    
  3. 添加 spring 配置文件 applicationContext.xml,在文件中完成 bean 的配置

    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"/>
    
  4. 获取 IOC 容器,并从容器中获取对象进行方法调用

    public class App {
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            BookService bookService = (BookService) ctx.getBean("bookService");
            bookService.save();
        }
    }
    

② DI 入门案例

  1. 去除代码中的 new,并为属性提供 setter 方法

    public class BookServiceImpl implements BookService {
        private BookDao bookdao;
        
        public void save() {
            System.out.println("book service save ...");
            bookDao.save();
        }
        public void setBookDao(BookDao bookdao) {
            this.bookdao = bookdao;
        }
    }
    
  2. 修改配置完成注入

    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <property name="bookdao" ref="bookDao"/>
    </bean>
    

1.2 IOC & DI

1.2.1 IOC 相关内容

① bean 基础配置

  1. bean 基础配置

    • id:使用容器可以通过 id 值获取对应的 bean,在一个容器中 id 值唯一

    • class:bean 的类型,即配置的 bean 的全路径类名

    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"/>
    
  2. bean 别名配置

    定义 bean 的别名,可定义多个,使用逗号(,)分号(;)空格( )分隔

    <bean id="bookService service" class="com.itheima.service.impl.BookServiceImpl"/>
    <bean id="bookDao,dao" name="dao" class="com.itheima.dao.impl.BookDaoImpl"/>
    

    注意:获取 bean 无论是通过 id 还是 name,如果无法获取到,将抛出异常 NoSuchBeanDefinitionException

  3. bean 作用范围配置

    • singleton:单例(默认)
    • prototype:非单例
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl scope="prototype"/>
    

    哪些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.itheima.dao.impl.BookDaoImpl"/>
    

    注意:无参构造方法如果不存在,将抛出异常 BeancreationException

  2. 静态工厂(了解)

    public class OrderDaoFactory {
        public static OrderDao getOrderDao(){
            return new OrderDaoImpl();
        }
    }
    
    <bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>
    
  3. 实例工厂(了解)

    public class UserDaoFactory {
        public UserDao getUserDao(){
            return new UserDaoImpl();
        }
    }
    
    <bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>
    <bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
    
    • FactoryBean(实用)
    public class UserDaoFactoryBean implements FactoryBean<UserDao> {
        // 代替实例工厂中创建对象的方法
        public UserDao getObject() throws Exception {
            return new UserDaoImpl();
        }
        public Class<?> getObjectType() {
            return UserDao.class;
        }
    }
    
    <bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>
    

③ bean 的生命周期

  1. bean 生命周期控制

    • 配置:init-method、destroy-method
    public class BookDaoImpl implements BookDao {
        public void save() {
            System.out.println("book dao save ...");
        }
        public void init(){
            System.out.println("init...");
        }
        public void destory(){
            System.out.println("destory...");
        }
    }
    
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
    
    • 接口:InitializingBean、DisposableBean(了解)
    public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
        public void save() {
            System.out.println("book service save ...");
        }
        public void destroy() throws Exception {
            System.out.println("service destroy");
        }
        public void afterPropertiesSet() throws Exception {
            System.out.println("service init");
        }
    }
    
    • 关闭容器:close、registerShutdownHook
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    ctx.registerShutdownHook();      // 1. 注册钩子关闭容器
    ctx.close();                 // 2. 手工关闭容器
    
  2. bean 生命周期

    • 初始化容器
      • 创建对象 (内存分配)
      • 执行构造方法
      • 执行属性注入 (set 操作)
      • 执行 bean 初始化方法
    • 使用 bean
      • 执行业务操作
    • 关闭 / 销毁容器
      • 执行 bean 销毁方法

1.2.2 DI 相关内容

① setter 注入(推荐)

  1. 简单类型

    public class BookDaoImpl implements BookDao {
        private int connectionNum;
        public void setConnectionNum(int connectionNum) {
            this.connectionNum = connectionNum;
        }
    }
    
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <property name="connectionNum" value="100"/>
    </bean>
    
  2. 引用类型

    public class BookServiceImpl implements BookService{
        private BookDao bookDao2;
        public void setBookDao(BookDao bookDao) {
            this.bookDao2 = bookDao;
        }
    }
    
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <property name="bookDao2" ref="bookDao"/>
    </bean>
    

② 构造器注入(了解)

  1. 简单类型

    public class BookDaoImpl implements BookDao {
        private int connectionNum;
        public BookDaoImpl(int connectionNum) {
            this.connectionNum = connectionNum;
        }
    }
    
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <constructor-arg name="connectionNum" value="100"/>
    </bean>
    
  2. 引用类型

    public class BookServiceImpl implements BookService{
        private BookDao bookDao;
        public BookServiceImpl(BookDao bookDao2) {
            this.bookDao = bookDao2;
        }
    }
    
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <constructor-arg name="bookDao2" ref="bookDao"/>
    </bean>
    

③ 自动配置

④ 集合注入

public class BookDaoImpl implements BookDao {
    private int[] array;
    public void setArray(int[] array) {
        this.array = array;
    }
}
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
    <property name="array">
        <array>
            <value>100</value>
            <value>200</value>
            <value>300</value>
        </array>
    </property>
</bean>

1.2.3 管理第三方 bean

① 案例

② 加载 properties 文件

1.3 核心容器

1.3.1 容器

  1. 创建容器

    // 1. 类路径加载 XML 配置文件 (常用)
    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    // 2. 文件系统加载 XML 配置文件
    ApplicationContext ctx = new FileSystemXmlApplicationContext("applicationContext.xml");
    // 加载多个 XML 配置文件
    ApplicationContext ctx = new ClassPathXmlApplicationContext("bean1.xml", "bean2.xml");
    
  2. 获取 bean

    // 1. 使用 bean 名称获取
    BookDao bookDao = (BookDao) ctx.getBean("bookDao");
    // 2. 使用 bean 名称获取并指定类型
    BookDao bookDao = ctx.getBean("bookDao",BookDao.class);
    // 3. 使用 bean 类型获取
    BookDao bookDao = ctx.getBean(BookDao.class);
    
  3. 容器类层次结构

    从图中可以看出,容器类也是从无到有根据需要一层层叠加上来的,重点理解下这种设计思想

  1. BeanFactory

    Resource resources = new ClassPathResource("applicationContext.xml");
    BeanFactory bf = new XmlBeanFactory(resources);
    BookDao bookDao = bf.getBean(BookDao.class);
    

1.3.2 总结

  1. bean 相关

  1. 依赖注入相关
  1. 容器相关

    • BeanFactory 是 IoC 容器的顶层接口,初始化 BeanFactory 对象时,加载的 bean 延迟加载
    • ApplicationContext 接口是 Spring 容器的核心接口,初始化时 bean 立即加载
    • ApplicationContext 接口提供基础的 bean 操作相关方法,通过其他接口扩展其功能
    • ApplicationContext 接口常用初始化类
      • ClassPathXmlApplicationContext (常用)
      • FileSystemXmlApplicationContext

1.4 注解开发

1.4.1 定义 bean

1.4.2 注解开发

  1. 纯注解开发模式

    • Spring 3.0 开启了纯注解开发模式,使用 Java 类替代配置文件,开启了 Spring 快速开发赛道

    • Java 类替换 Spring 核心配置文件:

    @Configuration                   // 用于设定当前类为配置类
    @ComponentScan("com.itheima")    // 用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式
    public class SpringConfig {
    }
    
    // 读取 Spring 核心配置文件初始化容器对象,切换为读取 Java 配置类初始化容器对象
    ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
    
  2. bean 作用范围

    @Scope("prototype")              // 用于设置 bean 的作用范围
    public class BookDaoImpl implements BookDao {
    }
    
  3. bean 生命周期

    @Repository
    public class BookDaoImpl implements BookDao {
        public void save() {
            System.out.println("book dao save ...");
        }
        @PostConstruct               // 在构造方法之后执行
        public void init() {
            System.out.println("init ...");
        }
        @PreDestroy              // 在销毁方法之前执行
        public void destroy() {
            System.out.println("destroy ...");
        }
    }
    

1.4.3 依赖注入

1.4.4 管理第三方 bean

1.5 Spring 整合

1.5.1 整合 mybatis

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.10.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.0</version>
</dependency>
@Configuration
@ComponentScan("com.itheima")
@PropertySource("jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class})
public class SpringConfig {
}
public class JdbcConfig {...}
public class MybatisConfig {
    @Bean
    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
        SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
        ssfb.setTypeAliasesPackage("com.itheima.domain");   // 1. 初始化类型别名
        ssfb.setDataSource(dataSource);                     // 2. 初始化 dataSource
        return ssfb;
    }
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer(){
        MapperScannerConfigurer msc = new MapperScannerConfigurer();
        msc.setBasePackage("com.itheima.dao");              // 3. 初始化映射配置
        return msc;
    }
}

1.5.2 整合 junit

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

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.2.10.RELEASE</version>
</dependency>
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceTest {
    @Autowired
    private AccountService accountService;
}

1.6 AOP

1.5.1 AOP 简介

  1. AOP 概念与作用

    AOP (Aspect Oriented Programming) 面向切面编程,一种编程范式,指导开发者如何组织程序结构

    • OOP (Object Oriented Programming) 面向对象编程

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

  2. AOP 核心概念

    • 连接点 (JoinPoint):程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等
      • 在 SpringAOP 中,理解为方法的执行
    • 切入点 (Pointcut):匹配连接点的式子
      • 在 SpringAOP 中,一个切入点可以描述一个具体方法,也可也匹配多个方法
    • 通知 (Advice):在切入点处执行的操作,也就是共性功能
      • 在 SpringAOP 中,功能最终以方法的形式呈现
    • 通知类:定义通知的类
    • 切面 (Aspect):描述通知与切入点的对应关系

1.5.2 AOP 入门案例

  1. 添加依赖(pom.xml)

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.4</version>
    </dependency>
    
  2. 定义接口与实现类(dao 包)

    public interface BookDao {
        public void save();
        public void update();
    }
    
    @Repository
    public class BookDaoImpl implements BookDao {
        public void save() {
            System.out.println(System.currentTimeMillis());
        }
        public void update(){
            System.out.println("book dao update ...");
        }
    }
    
  3. 定义通知类、通知、切入点和切面,将通知类配给容器并标识其为切面类(aop 包)

    @Component
    @Aspect
    public class MyAdvice {
        // 1. 切入点定义依托一个不具有实际意义的方法进行,即无参数、无返回值、方法体无实际逻辑
        @Pointcut("execution(void com.itheima.dao.BookDao.update())")
        private void pt(){}
        // 2. 绑定切入点与通知关系,并指定通知添加到原始连接点的具体执行位置
        @Before("pt()")
        public void method(){    
            System.out.println(System.currentTimeMillis());
        }
    }
    
  4. 开启注解格式 AOP 功能(config 包)

    @Configuration
    @ComponentScan("com.itheima")
    @EnableAspectJAutoProxy
    public class SpringConfig {
    }
    

1.5.3 AOP 工作流程

  1. Spring 容器启动,读取所有切面配置中的切入点

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

    • 匹配失败,创建对象
    • 匹配成功,创建原始对象(目标对象)的代理对象
  3. 获取 bean 执行方法

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

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

1.5.4 AOP 配置管理

① AOP 切入点表达式

  1. 语法格式

    // 方式一: 执行 com.itheima.dao 包下的 BookDao 接口中的无参数 update 方法
    execution(void com.itheima.dao.BookDao.update())
    // 方式二: 执行 com.itheima.dao.impl 包下的 BookDaoImpl 类中的无参数 update 方法
    execution(void com.itheima.dao.impl.BookDaoImpl.update())
    

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

    • execution:动作关键字,描述切入点的行为动作,例如 execution 表示执行到指定切入点
    • public:访问修饰符,还可以是 public,private 等,可以省略
    • 异常名:方法定义中抛出指定异常,可以省略
  2. 通配符

    • * :单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现
    • .. :多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写
    • + :专用于匹配子类类型(了解)
    // 匹配 com.itheima 包下的任意包中的 UserService 类或接口中所有 find 开头的带有一个参数的方法
    execution(public * com.itheima.*.UserService.find*(*))
    // 匹配 com 包下的任意包中的 UserService 类或接口中所有名称为 findById 的方法
    execution(public User com..UserService.findById(..))
    // 这个使用率较低,描述子类的,咱们做 JavaEE 开发,继承机会就一次
    execution(* *..*Service+.*(..))
    
  3. 书写技巧

    • 所有代码按照标准规范开发,否则以下技巧全部失效
    • 描述切入点通常描述接口,而不描述实现类,如果描述到实现类,就出现紧耦合了
    • 返回值类型对于增删改类使用精准类型加速匹配,对于查询类使用 * 通配快速描述
    • 包名书写尽量不使用 .. 匹配,效率过低,常用*做单个包描述匹配,或精准匹配
    • 接口名/类名书写名称与模块相关的采用 * 匹配,例如 UserService 书写成 *Service,绑定业务层接口名
    • 方法名书写以动词进行精准匹配,名词采用 * 匹配,例如 getById 书写成 getBy*,selectAll 书写成 selectAll

② AOP 通知类型

  1. AOP 通知类型

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

    • AOP 通知共分为 5 种类型:前置通知、后置通知、环绕通知、返回后通知、抛出异常后通知

    @Before("pt()")              // 1. 前置通知
    public void before() {
        System.out.println("around before advice ...");
    }
    
    @After("pt()")               // 2. 后置通知
    public void after() {
        System.out.println("around after advice ...");
    }
    
    @Around("pt()")              // 3. 环绕通知 (重点)
    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;
    }
    
    @AfterReturning("pt()")      // 4. 返回后通知
    public void afterReturning() {
        System.out.println("afterReturning advice ...");
    }
    
    @AfterThrowing("pt()")       // 5. 抛出异常后通知
    public void afterThrowing() {
        System.out.println("afterThrowing advice ...");
    }
    
  2. @Around 注意事项

    • 环绕通知必须依赖形参 ProceedingJoinPoint 才能实现对原始方法的调用,进而实现原始方法调用前后同时添加通知
    • 通知中如果未使用 ProceedingJoinPoint 对原始方法进行调用将跳过原始方法的执行
    • 对原始方法的调用可以不接收返回值,通知方法设置成 void 即可,如果接收返回值,最好设定为 Object 类型
    • 原始方法的返回值如果是 void 类型,通知方法的返回值类型可以设置成 void,也可以设置成 Object 类型
    • 由于无法预知原始方法运行后是否会抛出异常,因此环绕通知方法必须要处理 Throwable 异常
  3. 案例:测量业务层接口执行效率

    需求:任意业务层接口执行均可显示其万次执行效率(执行时长)

    @Component
    @Aspect
    public class ProjectAdvice {
        @Pointcut("execution(* com.itheima.service.*Service.*(..))")
        private void servicePt(){}
    
        @Around("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");
        }
    }
    

③ AOP 通知获取数据

  1. 获取参数

    • JoinPoint:适用于前置、后置、返回后、抛出异常后通知
    @Before("pt()")
    public void before(JoinPoint jp){
        Object[] args = jp.getArgs();
        System.out.println("before advice ..."+Arrays.toString(args));
    }
    
    • ProceedingJoinPoint:适用于环绕通知
    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        Object[] args = pjp.getArgs();
        System.out.println("around advice ..."+Arrays.toString(args));
        Object ret = pjp.proceed();
        return ret;
    }
    
  2. 获取返回值:返回后通知、环绕通知(了解)

    @AfterReturning(value = "pt()",returning = "ret")
    public void afterReturning(Object ret) {
        System.out.println("afterReturning advice ..."+ret);
    }
    
    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        Object[] args = pjp.getArgs();
        Object ret = pjp.proceed(args);
        System.out.println("around advice ..."+ret);
        return ret;
    }
    
  3. 获取异常:抛出异常后通知、环绕通知(了解)

  4. 案例:网盘密码数据兼容处理

    需求:对百度网盘分享链接输入密码时尾部多输入的空格做兼容处理

    @Component
    @Aspect
    public class DataAdvice {
        @Pointcut("execution(boolean com.itheima.service.*Service.*(*,*))")
        private void servicePt(){}
    
        @Around("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;
        }
    }
    

1.5.5 AOP 事务管理

① Spring 事务简介

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

    public interface AccountService {
        @Transactional
        public void transfer(String out,String in ,Double money) ;
    }
    
    // Spring 注解式事务通常添加在业务层接口中而不会添加到业务层实现类中,降低耦合
    // Spring 注解式事务也可以添加到接口上表示当前接口所有方法开启事务
    
  2. 设置事务管理器

    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource){
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
    // 事务管理器要根据实现技术进行选择; MyBatis 框架使用的是 JDBC 事务
    
  3. 开启注解式事务驱动

    @EnableTransactionManagement
    public class SpringConfig {
    }
    

② Spring 事务角色

③ Spring 事务属性

属性 作用
readOnly 设置是否为只读事务
timeout 设置事务超时时间
rollbackFor 设置事务回滚异常
propagation 设置事务传播行为
// 1. 添加 AccountService 接口与实现类, 设置记录日志

public interface AccountService {
    @Transactional(rollbackFor = IOException.class)
    public void transfer(String out,String in ,Double money);
}

public void transfer(String out,String in ,Double money) {
    try{
        accountDao.outMoney(out,money);
        if(true) {throw new IOException();}
        accountDao.inMoney(in,money);
    }finally {
        logService.log(out,in,money);
    }
}
// 注意: 并不是所有异常都会回滚, 可以使用 rollbackFor 属性来设置出现 IOException 回滚
// 2. 添加 LogService 接口与实现类, 设置事务的传播行为

public interface LogService {
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    void log(String out, String in, Double money);
}

public void log(String out,String in,Double money ) {
    logDao.log("转账操作由"+out+"到"+in+",金额:"+money);
}

第2章 - SpringMVC

2.1 SpringMVC 概述

2.2 SpringMVC 入门案例

2.2.1 入门案例

  1. 导入 SpringMVC 与 Servlet 坐标

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.10.RELEASE</version>
    </dependency>
    
  2. 创建 SpringMVC 控制器类

    @Controller
    public class UserController {
        @RequestMapping("/save") // 4.
        @ResponseBody
        public String save(){
            System.out.println("user save ...");
            return "{'info':'springmvc'}";
        }
    }
    
  3. 初始化 SpringMVC 环境,设定 SpringMVC 加载对应的 bean

    @Configuration       
    @ComponentScan("com.itheima.controller") // 3.
    public class SpringMvcConfig {
    }
    
  4. 初始化 Servlet 容器,加载 SpringMVC 环境,并设置 SpringMVC 技术处理的请求

    // AbstractDispatcherServletInitializer 类是 SpringMVC 提供的快速初始化 web3.0 容器的抽象类
    public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {      // 1.
        protected WebApplicationContext createServletApplicationContext() {      // 2.
            AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
            ctx.register(SpringMvcConfig.class);
            return ctx;
        }
        protected String[] getServletMappings() {    // 5.
            return new String[]{"/"};
        }
        // 如果需要加载非 SpringMVC 对应的 bean, 使用当前方法
        protected WebApplicationContext createRootApplicationContext() {
            return null;
        }
    }
    

2.2.2 工作流程解析

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

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

  3. 加载 SpringMvcConfig 配置类,执行 @ComponentScan 加载对应的 bean

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

  5. 执行 getServletMappings 方法,设定 SpringMVC 拦截请求的路径规则

2.2.3 bean 加载控制

  1. 方式一:设定扫描范围为 com.itheima,排除掉 controller 包内的 bean

    @Configuration
    @ComponentScan(
        value="com.itheima", 
        excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)
    )
    public class SpringConfig {}
    
    @Configuration
    public class SpringMvcConfig {}
    
  2. 方式二:设定扫描范围为精准范围,例如 service 包、dao 包等(常用)

    @Configuration
    @ComponentScan({"com.itheima.service","com.itheima.dao"})
    public class SpringConfig {}
    
    @Configuration
    @ComponentScan("com.itheima.controller")
    public class SpringMvcConfig {}
    
  3. 方式三:不区分 Spring 与 SpringMVC 的环境,加载到同一个环境中(了解)

2.2.4 PostMan 工具

2.3 请求与响应

2.3.1 映射路径

@Controller
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/save")
    public void save(){
        System.out.println("user save ...");
    }
    @RequestMapping("/delete")
    public void delete(){
        System.out.println("user delete ...");
    }
}

2.3.2 请求参数

@RequestMapping("/commonParam")
public void commonParam(String name,int age){
    System.out.println("普通参数传递 name ==> "+name);
    System.out.println("普通参数传递 age ==> "+age);
}

解决 Post 请求中文乱码问题

public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Filter[] getServletFilters() {    // 配置过滤器
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        return new Filter[]{filter};
    }
}

2.3.3 参数类型

2.3.4 响应数据

2.4 REST 风格

2.4.1 REST 简介

2.4.2 RESTful 入门

@Controller
public class UserController {
    @RequestMapping(value = "/users", method = RequestMethod.GET)
    public void getAll(){}

    @RequestMapping(value = "/users", method = RequestMethod.POST)
    public void save(){}

    @RequestMapping(value = "/users", method = RequestMethod.PUT)
    public void update(@RequestBody User user){}

    @RequestMapping(value = "/users/{id}", method = RequestMethod.GET)
    public void getById(@PathVariable Integer id){}

    @RequestMapping(value = "/users/{id}", method = RequestMethod.DELETE)
    public void delete(@PathVariable Integer id){}
}

@RequestParam、@RequestBody、@PathVariable

2.4.3 RESTful 快速开发

@RestController:设置控制类为 RESTful 风格,等同于 @Controller 与 @ResponseBody 两个注解的组合功能

@RestController
@RequestMapping("/users")
public class UserController {
    @GetMapping
    public void getAll(){}

    @PostMapping
    public void save(@RequestBody Book book){}

    @PutMapping
    public void update(@RequestBody Book book){}

    @GetMapping("/{id}")
    public void getById(@PathVariable Integer id){}

    @DeleteMapping("/{id}")
    public void delete(@PathVariable Integer id){}
}

2.4.4 RESTful 案例

需求:基于 RESTful 页面数据交互

2.5 拦截器

2.5.1 拦截器概念

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

拦截器作用

拦截器与过滤器区别

2.5.2 入门案例

  1. 声明拦截器的 bean,并实现 HandlerInterceptor 接口

    @Component           // 记得扫描加载 bean: "com.itheima.controller"
    public class ProjectInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(...) throws Exception {
            System.out.println("preHandle..."+contentType);
            return true;
        }
        @Override
        public void postHandle(...) throws Exception {
            System.out.println("postHandle...");
        }
        @Override
        public void afterCompletion(...) throws Exception {
            System.out.println("afterCompletion...");
        }
    }
    
  1. 定义配置类,添加拦截器并设定拦截的访问路径,路径可以通过可变参数设置多个

    @Configuration       // 记得扫描加载配置: "com.itheima.config"
    public class SpringMvcSupport extends WebMvcConfigurationSupport {
        @Autowired
        private ProjectInterceptor projectInterceptor;
        @Override
        protected void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
        }
    }
    

2.5.3 拦截器参数

2.5.4 拦截器链配置

多拦截器执行顺序

第3章 - Maven 高级

3.1 分模块开发

  1. 创建 Maven 模块(maven_03_pojo、maven_04_dao)

    <!-- maven_02_ssm/pom.xml -->
    <dependency>
        <groupId>com.itheima</groupId>
        <artifactId>maven_03_pojo</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    
    <dependency>
        <groupId>com.itheima</groupId>
        <artifactId>maven_04_dao</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    
    <!-- maven_04_dao/pom.xml -->
    <dependency>
        <groupId>com.itheima</groupId>
        <artifactId>maven_03_pojo</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    
  2. 书写模块代码(Book.java、BookDao.java)

    现实中,需要先针对模块功能进行设计,再进行编码。不会先将工程开发完毕,然后进行拆分

  3. 通过 maven 指令安装模块到本地仓库(install 指令)

    现实中,团队内部开发,需要发布模块功能到团队内部可共享的仓库中(私服)

3.2 依赖管理

  1. 依赖传递

    • 依赖具有传递性

      • 直接依赖:在当前项目中通过依赖配置建立的依赖关系
      • 间接依赖:被资源的资源如果依赖其他资源,当前项目间接依赖其他资源
    • 依赖传递冲突问题

      • 路径优先:当依赖中出现相同的资源时,层级越深,优先级越低,层级越浅,优先级越高
      • 声明优先:当资源在相同层级被依赖时,配置顺序靠前的覆盖配置顺序靠后的
      • 特殊优先:当同级配置了相同资源的不同版本,后配置的覆盖先配置的
  1. 可选依赖、排除依赖

    • 可选依赖:指对外隐藏当前所依赖的资源(不透明)
    <dependency>
        <groupId>com.itheima</groupId>
        <artifactId>maven_03_pojo</artifactId>
        <version>1.0-SNAPSHOT</version>
        <optional>true</optional>
    </dependency>
    
    • 排除依赖:指主动断开依赖的资源,被排除的资源无需指定版本(不需要)
    <dependency>
        <groupId>com.itheima</groupId>
        <artifactId>maven_04_dao</artifactId>
        <version>1.0-SNAPSHOT</version>
        <exclusions>
            <exclusion>
                <groupId>com.itheima</groupId>
                <artifactId>maven_03_pojo</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    

3.3 聚合和继承

3.3.1 聚合

<!-- 1. 创建 Maven 模块,设置打包类型为 pom -->
<groupId>com.itheima</groupId>
<artifactId>maven_01_parent</artifactId>
<version>1.0-RELEASE</version>
<packaging>pom</packaging>
<!-- 注: 每个 maven 工程默认打包方式为 jar, web 工程打包方式为 war -->

<!-- 2. 设置当前聚合工程所包含的子模块名称 -->
<modules>
    <module>../maven_02_ssm</module>
    <module>../maven_03_pojo</module>
    <module>../maven_04_dao</module>
</modules>
<!-- 注: 聚合工程中所包含的模块在进行构建时会根据依赖关系设置顺序,与配置书写位置无关 -->

3.3.2 继承

<!-- ssm_parent/pom.xml -->

<!-- 1. 配置依赖关系(简化配置)-->
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.10.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.2.10.RELEASE</version>
    </dependency>
</dependencies>

<!-- 2. 配置子工程中可选的依赖关系(减少版本冲突)-->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
    </dependencies>
</dependencyManagement>
<!-- ssm_crm/pom.xml -->
<!-- ssm_goods/pom.xml -->

<!-- 1. 在子工程中配置当前工程所继承的父工程 -->
<parent>
    <groupId>com.itheima</groupId>
    <artifactId>ssm_parent</artifactId>
    <version>1.0-RELEASE</version>
    <relativePath>../ssm_parent/pom.xml</relativePath>
</parent>

<!-- 2. 在子工程中配置使用父工程中可选依赖的坐标 -->
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
    </dependency>
</dependencies>

3.3.3 区别

3.4 属性

  1. 引用属性
<!-- 1. 定义属性 -->
<properties>
    <spring.version>5.2.10.RELEASE</spring.version>
</properties>

<!-- 2. 引用属性 -->
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>${spring.version}</version>
    </dependency>
</dependencies>
  1. 加载属性
<!-- 1. 定义属性 -->
<properties>
    <jdbc.driver>com.mysql.jdbc.Driver</jdbc.driver>
    <jdbc.url>jdbc:mysql://127.0.0.1:3306/ssm_db</jdbc.url>
    <jdbc.username>root</jdbc.username>
    <jdbc.password>1234</jdbc.password>
</properties>
# 2. 加载属性
jdbc.driver=${jdbc.driver}
jdbc.url=${jdbc.url}
jdbc.username=${jdbc.username}
jdbc.password=${jdbc.password}
  1. 版本管理

    • SNAPSHOT(快照版本)

      • 项目开发过程中临时输出的版本

      • 快照版本会随着开发的进展不断更新

3.5 多环境开发

  1. 定义多环境

    <profiles>
        <profile>
            <id>env_pro</id>
            <properties>
                <jdbc.url>jdbc:mysql://61.41.134.129:3306/ssm_db</jdbc.url>
            </properties>
        </profile>
        <profile>
            <id>env_dep</id>
            <properties>
                <jdbc.url>jdbc:mysql://127.0.0.1:3306/ssm_db</jdbc.url>
            </properties>
        </profile>
        <profile>
            <id>env_test</id>
            <properties>
                <jdbc.url>jdbc:mysql://65.13.40.251:3306/ssm_db</jdbc.url>
            </properties>
        </profile>
    </profiles>
    
  2. 使用多环境

    mvn install -P env_dep
    

3.6 私服

3.6.1 简介与安装

3.6.2 私服仓库分类

仓库类别 英文名称 功能 关联操作
宿主仓库 hosted 保存自主研发+第三方资源 上传
代理仓库 proxy 代理连接中央仓库下载 下载
仓库组 group 为仓库编组简化下载操作 下载

3.6.3 私服上传下载

  1. 私服上配置仓库

    • 创建 itheima-snapshot 仓库

    • 创建 itheima-release 仓库

  2. 配置本地 Maven 对私服的访问权限(settings.xml)

    <server>
        <id>itheima-snapshot</id>
        <username>admin</username>
        <password>admin</password>
    </server>
    <server>
        <id>itheima-release</id>
        <username>admin</username>
        <password>admin</password>
    </server>
    

    配置私服的访问路径(settings.xml)

    <mirror>
        <!--仓库组 ID-->
        <id>maven-public</id>
        <!--所有内容都从私服获取-->
        <mirrorOf>*</mirrorOf>
        <!--仓库组的访问路径-->
        <url>http://localhost:8081/repository/maven-public/</url>
    </mirror>
    
  3. 配置当前工程保存在私服中的具体位置(pom.xml)

    <distributionManagement>
        <repository>
            <url>http://localhost:8081/repository/itheima-release/</url>
        </repository>
        <snapshotRepository>
            <url>http://localhost:8081/repository/itheima-snapshot/</url>
        </snapshotRepository>
    </distributionManagement>
    

    发布命令

    mvn deploy
    

第4章 - SpringBoot

4.1 SpringBoot 简介

4.1.1 SpringBoot 入门

  1. 入门案例

    • 快速开发

      • 第一步:创建 SpringBoot 新模块,配置基础信息,并选择 web 技术集
     @RestController
     @RequestMapping("/books")
     public class BookController {
         @GetMapping("/{id}")
         public String getById(@PathVariable Integer id){
             System.out.println("id ==> "+id);
             return "hello , spring boot!";
         }
     }
  1. Spring 与 SpringBoot 对比

    类 / 配置文件 Spring SpringBoot
    pom.xml 坐标 手工添加 勾选添加
    web3.0 配置类 手工制作
    Spring / SpringMVC 配置类 手工制作
    Controller 控制器类 手工制作 手工制作

    最简 SpringBoot 程序所包含的基础文件:

    • pom.xml
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.0</version>
    </parent>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    • Application 启动类
    @SpringBootApplication
    public class Application {
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    }
    
  2. 官网创建方式

4.1.2 SpringBoot 简介

  1. 起步依赖(pom.xml)

    • parent

      • 所有 SpringBoot 项目要继承的项目,定义了若干个坐标版本号(依赖管理,而非依赖),以达到减少依赖冲突的目的

      • spring-boot-starter-parent(2.5.0)与 spring-boot-starter-parent(2.4.6)共计 57 处坐标版本不同

    • starter

      • SpringBoot 中常见项目名称,定义了当前项目使用的所有项目坐标,以达到减少依赖配置的目的
      • 也可以使用 maven 依赖管理,变更起步依赖项:
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
          <exclusions>
              <exclusion>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-tomcat</artifactId>
              </exclusion>
          </exclusions>
      </dependency>
      
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-jetty</artifactId>
          <!-- 使用任意坐标时, 仅书写GAV中的G和A, V由SpringBoot提供 -->
      </dependency>
      
  2. 程序启动(Application 引导类)

    • SpringBoot 在创建项目时,采用 jar 的打包方式
    • SpringBoot 的引导类是项目的入口,运行 main 方法就可以启动项目

4.2 配置文件

4.2.1 配置文件格式

4.2.2 yaml 数据读取

4.2.3 多环境开发

  1. 多环境开发配置

    • yaml 版
    spring:
      profiles:
        active: dev
    ---
    spring:
      profiles: dev
        server:
          port: 80
    ---
    spring:
      profiles: pro
        server:
          port: 81
    ---
    spring:
      profiles: test
        server:
          port: 82
    
    • properties 版
    # application.properties
    spring.profiles.active=dev
    # application-dev.properties
    server.port=80
    # application-pro.properties
    server.port=81
    # application-test.properties
    server.port=82
    
  2. 命令行启动:参数设置

    java -jar springboot.jar --spring·profiles.active=test
    java -jar springboot.jar --server.port=88
    java -jar springboot.jar --server.port=88 --spring·profiles.active=test
    
  3. 多环境兼容问题(Maven 与 SpringBoot)

    • Maven 中设置多环境属性
    <profiles>
        <profile>
            <id>dev</id>
            <properties>
                <profile.active>dev</profile.active>
            </properties>
        </profile>
        <profile>
            <id>pro</id>
            <properties>
                <profile.active>pro</profile.active>
            </properties>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
        </profile>
        <profile>
            <id>test</id>
            <properties>
                <profile.active>test</profile.active>
            </properties>
        </profile>
    </profiles>
    
    • SpringBoot 中引用 Maven 属性
    spring:
      profiles:
        active: ${profile.active}
    ...
    
    # 此时 Maven 打包会失败,因为 package 生成了对应的包,其中类参与编译,但是配置文件并没有编译,而是复制到包中
    # 解决思路: 对于源码中非 java 类的操作要求加载 Maven 对应的属性,解析 ${} 占位符
    
    • 对资源文件开启对默认占位符的解析
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <configuration>
                    <encoding>UTF-8</encoding>
                    <useDefaultDelimiters>true</useDefaultDelimiters>
                </configuration>
            </plugin>
        </plugins>
    </build>
    

4.2.4 配置文件分类

4.3 SpringBoot 整合

4.3.1 整合 junit

  1. 测试类与启动类同包 / 子包下

    @SpringBootTest
    class ApplicationTests {
        @Autowired
        private BookService bookService;
        @Test
        public void save() {
            bookService.save();
        }
    }
    
  2. 测试类与启动类不同包下

    @SpringBootTest(classes = Application.class)
    

4.3.2 整合 mybatis

  1. 创建 SpringBoot 新模块,配置基础信息,并选择 MyBatis、MySQL 技术集

  2. 在 application.yml 设置数据源参数

    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/ssm_db
        username: root
        password: 1234
    
  3. 定义 dao 数据层接口与映射配置

    @Mapper
    public interface BookDao {
        @Select("select * from tbl_book where id = #{id}")
        public Book getById(Integer id);
    }
    

第5章 - MyBatisPlus

5.1 MyBatisPlus 入门

5.1.1 入门案例

  1. 创建 SpringBoot 新模块,选择 MySQL 起步依赖,手动添加 MyBatisPlus 依赖:

    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.4.1</version>
    </dependency>
    
  2. 在 application.yml 配置数据源、端口等

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

  4. 定义数据接口(继承 BaseMapper<User>)

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

5.1.2 简介

5.2 标准数据层开发

5.2.1 CRUD 制作

  1. 增加 (Create)

    User user = new User();
    user.setName("黑马程序员");
    user.setPassword("itheima");
    userDao.insert(user);
    
  2. 读取 (Read)

    User user = userDao.selectById(1L);
    System.out.println(user);
    List<User> userList = userDao.selectList(null);
    
  3. 更新 (Update)

    User user = new User();
    user.setId(2L);
    user.setPassword("tom");
    userDao.updateById(user);
    
  4. 删除 (Delete)

    userDao.deleteById(3L);
    

5.2.2 分页功能制作

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

    @Configuration
    public class MpConfig {
        @Bean
        public MybatisPlusInterceptor mpInterceptor(){
            MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
            mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
            return mpInterceptor;
        }
    }
    
  2. 执行分页查询

    IPage page  = new Page(2,3);
    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());
    

5.3 DQL 编程控制

5.3.1 条件查询

  1. 两种格式

    // 1. 常规格式: e.g. less equal 18 or greater equal 65
    QueryWrapper<User> qw = new QueryWrapper<User>();
    qw.le("age",18).or.ge("age",65);
    List<User>userList = userDao.selectList(qw);
    
    // 2. lambda 格式(推荐): e.g. less than 65 and greater than 18
    LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
    lqw.lt(User::getAge,65).gt(User::getAge,18);
    List<User>userList = userDao.selectList(lqw);
    
  2. null 判定

    @Data
    public class UserQuery extends User {
        private Integer age2;
    }
    
    UserQuery uq = new UserQuery();
    // 先判定第一个参数是否为 true,如果为 true 连接当前条件
    lqw.gt(null != uq.getAge(), User::getAge, uq.getAge());
    lqw.lt(null != uq.getAge2(), User::getAge, uq.getAge2());
    

5.3.2 查询投影

5.3.3 条件设置

5.3.4 映射兼容性

@Data
// 解决1: 表名与编码类名不同
@TableName("tbl_user")
public class User {
    private Long id;
    private String name;
    // 解决2: 表字段与编码属性不同
    // 解决3: 默认查询开放了过多的字段权限
    @TableField(value = "pwd", select = false)
    private String password;
    private Integer age;
    // 解决4: 编码属性在表内不存在
    @TableField(exist = false)
    private Integer online;
}

5.4 DML 编程控制

5.4.1 id 生成策略

@TableName("tbl_user")    // 1. 属性设置
public class User {       
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;
}
mybatis-plus:         ## 2. 全局策略
  global-config:      
    db-config:            
      id-type: assign_id
      table-prefix: tbl_

5.4.2 多数据操作

List<Long> list = new ArrayList<>();
list.add(1L);
list.add(2L);
list.add(3L);
userDao.selectBatchIds(list);   // 1. 根据 id 查询多条记录
userDao.deleteBatchIds(list);   // 2. 根据 id 删除多条记录

5.4.3 逻辑删除

5.4.4 乐观锁

5 代码生成器

  1. 创建 SpringBoot 新模块,导入相关的 jar 包(pom.xml)

    <!--1. mybatisplus-->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.4.1</version>
    </dependency>
    
    <!--2. 代码生成器-->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-generator</artifactId>
        <version>3.4.1</version>
    </dependency>
    
    <!--3. velocity模板引擎-->
    <dependency>
        <groupId>org.apache.velocity</groupId>
        <artifactId>velocity-engine-core</artifactId>
        <version>2.3</version>
    </dependency>
    
    <!-- others: spring webmvc, druid, mysql, test, lombok -->
    
  2. 创建代码生成器类(CodeGenerator.java)

    public class CodeGenerator {
        public static void main(String[] args) {
            AutoGenerator autoGenerator = new AutoGenerator();
    
            // 1. 设置数据库相关配置
            DataSourceConfig dataSource = new DataSourceConfig();
            dataSource.setDriverName("com.mysql.cj.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql://localhost:3306/mybatisplus_db");
            dataSource.setUsername("root");
            dataSource.setPassword("1234");
            autoGenerator.setDataSource(dataSource);
    
            // 2. 设置全局配置
            GlobalConfig globalConfig = new GlobalConfig();
            globalConfig.setOutputDir(System.getProperty("user.dir")+"/src/main/java");    // 设置代码生成位置
            globalConfig.setOpen(false);                 // 设置生成完毕后是否打开生成代码所在的目录
            globalConfig.setAuthor("黑马程序员");          // 设置作者
            globalConfig.setFileOverride(true);      // 设置是否覆盖原始生成的文件
            globalConfig.setMapperName("%sDao");         // 设置数据层接口名,%s为占位符,指代模块名称
            globalConfig.setIdType(IdType.ASSIGN_ID);    // 设置Id生成策略
            autoGenerator.setGlobalConfig(globalConfig);
    
            // 3. 设置包名相关配置
            PackageConfig packageInfo = new PackageConfig();
            packageInfo.setParent("com.aaa");            // 设置生成的包名
            packageInfo.setEntity("domain");             // 设置实体类包名
            packageInfo.setMapper("dao");                // 设置数据层包名
            autoGenerator.setPackageInfo(packageInfo);
    
            // 4. 策略设置
            StrategyConfig strategyConfig = new StrategyConfig();
            strategyConfig.setInclude("tbl_user");               // 设置当前参与生成的表名,参数为可变参数
            strategyConfig.setTablePrefix("tbl_");               // 设置数据库表的前缀名称
            strategyConfig.setRestControllerStyle(true);         // 设置是否启用Rest风格
            strategyConfig.setVersionFieldName("version");       // 设置乐观锁字段名
            strategyConfig.setLogicDeleteFieldName("deleted");   // 设置逻辑删除字段名
            strategyConfig.setEntityLombokModel(true);           // 设置是否启用lombok
            autoGenerator.setStrategy(strategyConfig);
            autoGenerator.execute();
        }
    }
    
  3. 运行成功后,会在当前项目中生成很多代码,包含 controller , service,mapper 和 entity

上一篇下一篇

猜你喜欢

热点阅读