热门框架学习笔记

1-Spring框架

1. Spring框架

  1. Spring框架优势:简化开发、框架整合;
  2. Spring架构图
    热门框架学习笔记_第1张图片
  3. Spring的学习内容:Spring的IOC/DI、Spring的AOP、AOP的具体应用与事务管理、IOC/DI的具体应用与整合Mybatis。
  4. IOC:控制反转;IOC容器;Bean;DI依赖注入。

2. IOC相关内容

  1. bean的基础配置
<bean
	id="bean的唯一标识"
	class="bean的全类名"
	scope="bean的作用范围,有singleton(默认)和prototype"
	name="为bean取的别名"
	/>
  1. bean的实例化:
    • bean的创建:构造方法
    • Spring的IOC实例化对象的三种方式
      • 构造方法(常用)
      • 静态工厂(了解)
      • 实例工厂(了解)
        • FactoryBean(实用)
  2. bean的生命周期

3. DI相关内容

3.1 setter注入:

  1. 对于引用数据类型:
<bean ...>
	<property name="" ref=""/>
bean>
  1. 对于简单数据类型:
<bean ...>
	<property name="" value=""/>
bean>

3.2 构造器注入

  1. 引用数据类型
<bean ...>
	<constructor-arg name="" index="" type="" ref=""/>
bean>
  1. 简单数据类型
<bean ...>
	<constructor-arg name="" index="" type="" value=""/>
bean>

3.3 自动配置

  1. 标签删除;
  2. 标签中添加 autowire 属性。
  3. 分类:按照类型注入、按照名称注入

3.4 集合注入

标签内部写 arraylistsetmapprops 标签。

4. IOC/DI配置管理第三方bean

4.1 数据源对象管理

管理第三方bean步骤:

  1. 添加依赖;
  2. 配置第三方 bean,通过 setter 注入为第三方 bean 注入必要的参数;
  3. 从 IOC 容器获取对应的 bean 对象使用。

4.2 加载 properties 文件

  1. 开启 context 命名空间:
    热门框架学习笔记_第2张图片
  2. 加载 properties 配置文件
<context:property-placeholder location="" system-properties-mode="NEVER"/>
  1. 在applicationContext.xml引入properties配置文件中的值
${key}

5. 核心容器

  1. 容器创建的两种方式
    • ClassPathXmlApplicationContext[掌握]
    • FileSystemXmlApplicationContext[知道即可]
  2. 获取 Bean 的三种方式
    • getBean(“名称”):需要类型转换
    • getBean(“名称”,类型.class):多了一个参数
    • getBean(类型.class):容器中不能有多个该类的bean对象
  3. 容器类层次结构:最顶层的父接口 BeanFactory
  4. BeanFactory:
    • 使用BeanFactory创建的容器是延迟加载
    • 使用ApplicationContext创建的容器是立即加载
    • 具体BeanFactory如何创建只需要了解即可。
  5. bean 相关:
    热门框架学习笔记_第3张图片
  6. 依赖注入相关
    热门框架学习笔记_第4张图片

6. IOC/DI 注解开发

6.1 纯注解开发模式

  1. 创建配置类 SpringConfig;
  2. 在配置类上添加@Configuration注解,将其标识为一个配置类,替换applicationContext.xml
  3. 在配置类上添加包扫描注解@ComponentScan替换
@Configuration
@ComponentScan("com.itheima")
public class SpringConfig {
}

热门框架学习笔记_第5张图片

6.2 注解开发bean作用范围与生命周期管理

  1. @Scope :设置该类创建对象的作用范围,可用于设置创建出的bean是否为单例对象
  2. @PostConstruct :设置该方法为初始化方法
  3. @PreDestroy :设置该方法为销毁方法

6.3 注解开发依赖注入

注解开发只提供了自动装配的注解实现。

  1. @Autowired :为引用类型属性设置值,自动装配;
  2. @Qualifier :为引用类型属性指定注入的beanId,即可以在多个实现类中指定注入Bean的 Id;
  3. @Value :为 基本数据类型 或 字符串类型 属性设置值;
  4. @PropertySource :加载properties文件中的属性值,属性值可以使用 @Value("${key}") 注入。

7. IOC/DI注解开发管理第三方bean

7.1 注解开发管理第三方bean步骤

  1. 定义外部配置类管理第三方bean
  2. 定义获取第三方bean的方法,并通过 @Bean 注解将方法的返回值制作为Spring管理的一个bean对象
  3. @Bean :设置该方法的返回值作为spring管理的bean
  4. 在Spring配置类中使用 @Import({JdbcConfig.class}) 引入第三方bean
  5. @Import :导入配置类

7.2 注解开发实现为第三方bean注入资源

  1. 简单数据类型:在类中提供属性,用 @Value 注解引入值,在第三方bean的方法中传递参数进去即可;
  2. 引用数据类型:让 Spring 扫描管理到需要的bean,为第三方bean定义方法设置形参即可,容器会根据类型自动装配对象。

7.3 注解开发与配置文件开发对比

热门框架学习笔记_第6张图片

8. Spring整合

8.1 Spring整合Mybatis

要整合的内容:
第一件事是:Spring要管理MyBatis中的SqlSessionFactory
第二件事是:Spring要管理Mapper接口的扫描

整合步骤:

  1. 项目中导入整合需要的jar包:spring-jdbc、mybatis-spring
  2. 创建Spring的主配置类
  3. 创建数据源的配置类 JdbcConfig ,配置 DruidDataSource
  4. 主配置类中读properties并引入数据源配置类
  5. 创建Mybatis配置类并配置SqlSessionFactory,类里面定义两个Bean,一个用于产生SqlSessionFactory对象;一个返回MapperScannerConfigurer对象,用来处理原始配置文件中的mappers相关配置,加载数据层的Mapper接口类
    • SqlSessionFactoryBean封装SqlSessionFactory需要的环境信息
      热门框架学习笔记_第7张图片
    • MapperScannerConfigurer加载Dao接口,创建代理对象保存到IOC容器中
      热门框架学习笔记_第8张图片
  6. 主配置类中引入Mybatis配置类
  7. 编写运行类运行

8.2 Spring整合Junit

  1. 引入依赖:junit、spring-test
  2. 在test\java下创建一个测试类,添加两个注解:
    • 设置类运行器:@RunWith(SpringJUnit4ClassRunner.class)
    • 设置Spring环境对应的配置类:@ContextConfiguration(classes = {SpringConfig.class}) //加载配置类
      类里面自动装配注入 service bean,正常写 @Test 运行测试即可。

9. AOP

9.1 AOP 实现步骤

  1. 添加依赖:spring-contextaspectjweaver
  2. 定义接口与实现类、Spring的配置类、App运行类
  3. 定义通知类和通知
  4. 定义切入点
@Pointcut("execution(void com.itheima.dao.BookDao.update())")
private void pt(){}
  1. 制作切面:通知方法上添加注解 @Before("pt()")
  2. 将通知类配给容器并标识其为切面类 @Component@Aspect
  3. 开启注解格式AOP功能:在Spring配置类上添加注解 @EnableAspectJAutoProxy
  4. 运行程序

9.2 AOP 的核心概念

  1. 概念:AOP(Aspect Oriented Programming)面向切面编程,一种编程范式
  2. 作用:在不惊动原始设计的基础上为方法进行功能增强
  3. 核心概念:
    • 代理(Proxy):SpringAOP的核心本质是采用代理模式实现的
    • 连接点(JoinPoint):在SpringAOP中,理解为任意方法的执行
    • 切入点(Pointcut):匹配连接点的式子,也是具有共性功能的方法描述
    • 通知(Advice):若干个方法的共性功能,在切入点处执行,最终体现为一个方法
    • 切面(Aspect):描述通知与切入点的对应关系
    • 目标对象(Target):被代理的原始对象称为目标对象

9.3 切入点表达式

  1. 切入点表达式标准格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数)异常名)
execution(* com.itheima.service.*Service.*(..))
  1. 切入点表达式描述通配符:
    • 作用:用于快速描述,范围描述
    • *:匹配任意符号(常用)
    • … :匹配多个连续的任意符号(常用)
    • +:匹配子类类型

9.4 五种通知类型

- 前置通知
- 后置通知
- 环绕通知(重点)
- 返回后通知
- 抛出异常后通知

9.5 通知中获取参数

  1. 获取切入点方法的参数,所有的通知类型都可以获取参数
    • JoinPoint:适用于前置、后置、返回后、抛出异常后通知
    • ProceedingJoinPoint:适用于环绕通知
  2. 获取切入点方法返回值,前置和抛出异常后通知是没有返回值,后置通知可有可无,所以不做研究
    • 返回后通知
    • 环绕通知
  3. 获取切入点方法运行异常信息,前置和返回后通知是不会有,后置通知可有可无,所以不做研究
    • 抛出异常后通知
    • 环绕通知

9.6 知识点

  1. AOP 配置
    • @EnableAspectJAutoProxy :配置类定义上方,开启注解格式AOP功能
    • @Aspect :切面类定义上方,设置当前类为AOP切面类
    • @Pointcut :切入点方法定义上方,设置切入点方法
    • @Before :通知方法定义上方,设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法前运行
  2. 通知类型总结
    • @Before
    • @After :通知方法定义上方,设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法后运行
    • @AfterReturning :通知方法定义上方,设置当前通知方法与切入点之间绑定关系,当前通知方法在原始切入点方法正常执行完毕后执行
    • @AfterThrowing :通知方法定义上方,设置当前通知方法与切入点之间绑定关系,当前通知方法在原始切入点方法运行抛出异常后执行
    • @Around :通知方法定义上方,设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法前后运行,对原始方法的调用通过 pjp.proceed();实现

10. AOP 事务管理

10.1 事务管理步骤

  1. 在需要被事务管理的方法上添加注解 @Transactional,可以写在接口类上、接口方法上、实现类上和实现类方法上,建议写在实现类或实现类的方法上
  2. 在JdbcConfig类中配置事务管理器,配置第三方 bean :DataSourceTransactionManager
  3. 开启事务注解:在SpringConfig的配置类中开启 @EnableTransactionManagement
  4. 运行测试
  5. 知识点:
    • @EnableTransactionManagement :配置类定义上方,设置当前Spring环境中开启注解式事务支持;
    • @Transactional :业务层接口上方、业务层实现类上方、业务方法上方,为当前业务层方法添加事务(如果设置在类或接口上方则类或接口中所有方法均添加事务)

10.2 Spring事务角色

热门框架学习笔记_第9张图片

  • 事务管理员:发起事务方,在Spring中通常指代业务层开启事务的方法
  • 事务协调员:加入事务方,在Spring中通常指代数据层方法,也可以是业务层方法

10.3 Spring事务属性

  1. 事务配置,作为属性在 @Transactional 注解的参数上进行设置
    热门框架学习笔记_第10张图片
  2. 事务传播行为:转账业务追加日志案例
    • 创建日志表
    • 添加LogDao接口
    • 添加LogService接口与实现类,实现类方法配置 @Transactional
    • 在转账的业务中添加记录日志
    • 结果运行:正常运行时,日志表中日志记录成功;出现异常时,日志表未添加数据——日志的记录与转账操作隶属同一个事务,同成功同失败
      热门框架学习笔记_第11张图片
    • 需要效果:无论转账操作是否成功,日志必须保留
    • 事务传播行为:事务协调员对事务管理员所携带事务的处理态度。
    • 解决:修改logService改变事务的传播行为,在记录日志的业务方法上设置事务属性:传播行为设置为当前操作需要新事务
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void log(String out,String in,Double money ) {
	logDao.log("转账操作由"+out+"到"+in+",金额:"+money);
}

2-SpringMVC

1. SpringMVC概述与入门案例

1.1 SpringMVC

  1. SpringMVC是一种基于Java实现MVC模型的轻量级Web框架
  2. 优点
    • 使用简单、开发便捷(相比于Servlet)
    • 灵活性强
  3. 负责功能
    • controller如何接收请求和数据
    • 如何将请求和数据转发给业务层
    • 如何将响应数据转换成json发回到前端

1.2 入门案例流程

  1. 创建 Maven 项目,不使用骨架,设置打包方式为 war 包——定义为 web 项目
  2. 补全目录结构
  3. 导入jar包:javax.servlet-api、spring-webmvc、tomcat7-maven-plugin插件
  4. 创建配置类 SpringMvcConfig ,添加注解:
@Configuration
@ComponentScan("com.itheima.controller")
  1. 创建Controller类,添加 @Controller 注解,定义方法添加 @RequestMapping("/save") 注解设置当前控制器方法请求访问路径,添加注解 @ResponseBody 设置返回数据为json
  2. 使用配置类替换web.xml:将web.xml删除,换成ServletContainersInitConfig
public class ServletContainerInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer{

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMvcConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}
  1. 配置Tomcat环境
  2. 启动运行项目

1.3 bean加载控制 – 如何让Spring和SpringMVC分开加载各自的内容

  1. Spring加载的bean设定扫描范围为精准范围,例如service包、dao包等
  2. Spring加载的bean设定扫描范围为com.itheima,排除掉controller包中的bean
@Configuration
@ComponentScan(value="com.itheima",
excludeFilters=@ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = Controller.class
)
) p
ublic class SpringConfig {
}
  1. 方式三:不区分Spring与SpringMVC的环境,加载到同一个环境中[了解即可]

1.4 知识点

  1. @Controller :SpringMVC控制器类定义上方,设定SpringMVC的核心控制器bean;
  2. @RequestMapping :SpringMVC控制器类或方法定义上方,设置当前控制器方法请求访问路径;
  3. @ResponseBody :SpringMVC控制器类或方法定义上方,设置当前控制器方法响应内容为当前返回值,无需解析
  4. @ComponentScan :类定义上方,设置spring配置类扫描路径,用于加载使用注解格式定义的bean;excludeFilters:排除扫描路径中加载的bean,需要指定类别(type)和具体项(classes)、includeFilters:加载指定的bean,需要指定类别(type)和具体项(classes)

1.5 PostMan 工具的使用

2. 请求与响应

2.1 请求参数

  1. 设置请求映射路径:当有多个 Controller 时,可能具有相同的方法名,此时可以通过在 Controller 类上面添加 @@RequestMapping("/book")@RequestMapping("/user") 进行区分
  2. GET请求中文乱码:修改pom.xml中 tomcat 插件配置来解决GET请求中文乱码问题
  3. POST请求中文乱码:在 ServletContainersInitConfig 中配置过滤器
@Override
protected Filter[] getServletFilters() {
	CharacterEncodingFilter filter = new CharacterEncodingFilter();
	filter.setEncoding("UTF-8");
	return new Filter[]{filter};
}

2.2 五种类型参数传递

  1. 普通参数:
    • 地址参数名与形参变量名相同:定义形参即可接收参数
    • 形参与地址参数名不一致:写上 @RequestParam 注解
  2. POJO数据类型:请求参数与形参对象中的属性对应即可完成参数传递
  3. 嵌套POJO类型参数:请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性参数
  4. 数组类型参数:同名请求参数可以直接映射到对应名称的形参数组对象中
  5. 集合类型参数:同名请求参数可以使用@RequestParam注解映射到对应名称的集合对象中作为数据
  6. 知识点 @RequestParam :SpringMVC控制器方法形参定义前面,绑定请求参数与处理器方法形参间的关系

2.3 JSON数据传输参数

  1. SpringMVC接收JSON数据的实现步骤为:
    • 导入jackson包,SpringMVC默认使用的是jackson来处理json的转换
    • 使用PostMan发送JSON数据:JSON普通数组、JSON对象数据、JSON对象数组
    • 开启SpringMVC注解驱动,在配置类上添加 @EnableWebMvc 注解
    • Controller方法的参数前添加 @RequestBody 注解
  2. 知识点:
    • @EnableWebMvc :SpringMVC配置类定义上方,开启SpringMVC多项辅助功能
    • @RequestBody :SpringMVC控制器方法形参定义前面,将请求中请求体所包含的数据传递给请求参数——用于接收 json 数据
    • @RequestParam :用于接收url地址传参,表单传参

2.4 日期类型参数传递

  1. @DateTimeFormat :SpringMVC控制器方法形参前面,设定日期时间型数据格式
  2. 参数传递内部原理:SpringMVC 做了类型转换,SpringMVC中提供了很多类型转换接口和实现类。

2.5 响应

  1. 响应页面(了解):将页面名称返回回去,方法返回类型为 String,此处不能添加@ResponseBody,如果加了该注解,会直接将页面名称 page.jsp 当字符串返回前端
  2. 返回文本数据(了解):添加 @ResponseBody 注解,文本数据return回去即可
  3. 响应 json 数据:依赖 @ResponseBody 注解和 @EnableWebMvc 注解,将实体类对象或集合对象 return 即可
  4. @ResponseBody :SpringMVC控制器方法定义上方和控制类上,设置当前控制器返回值作为响应体,写在类上,该类的所有方法都有该注解功能。方法上有 @ReponseBody 注解后
    • 方法的返回值为字符串,会将其作为文本内容直接响应给前端
    • 方法的返回值为对象,会将对象转换成JSON响应给前端

3. Rest风格

3.1 REST简介

按照REST风格访问资源时使用行为动作区分对资源进行了何种操作

  • http://localhost/users 查询全部用户信息 GET(查询)
  • http://localhost/users/1 查询指定用户信息 GET(查询)
  • http://localhost/users 添加用户信息 POST(新增/保存)
  • http://localhost/users 修改用户信息 PUT(修改/更新)
  • http://localhost/users/1 删除用户信息 DELETE(删除)

按照不同的请求方式代表不同的操作类型:

  • 发送GET请求是用来做查询
  • 发送POST请求是用来做新增
  • 发送PUT请求是用来做修改
  • 发送DELETE请求是用来做删除

3.1 RESTful快速开发

  1. @RequestMapping 提到类上面,用来定义所有方法共同的访问路径 /books/user
  2. 使用 @GetMapping @PostMapping @PutMapping @DeleteMapping设置当前控制器方法请求访问路径与请求动作
  3. 使用 @RestController 注解替换 @Controller@ResponseBody 注解写在 Controller 类上方
  4. 使用 @PathVariable 解决方法形参的名称和路径{}中的值不一致问题与多个参数的区分问题
  5. 知识点:
    • @PathVariable :SpringMVC控制器方法形参定义前面,绑定路径参数与处理器方法形参间的关系,要求路径参数名与形参名一一对应
    • @RestController :基于SpringMVC的RESTful开发控制器类定义上方,设置当前控制器类为RESTful风格,等同于 @Controller@ResponseBody 两个注解组合功能
    • @GetMapping @PostMapping @PutMapping @DeleteMapping :基于SpringMVC的RESTful开发控制器方法定义上方,设置当前控制器方法请求访问路径与请求动作,每种对应一个请求动作,例如@GetMapping对应GET请求

3.2 案例-页面访问处理

  1. 问题:静态页面存放在项目的webapp目录下,访问pages目录下的books.html,SpringMVC拦截了静态资源,根据/pages/books.html去controller找对应的方法,找不到所以会报404的错误。
  2. 解决:在 config 包下定义 SpringMvcSupport 类将静态资源进行放行
@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/");
    }
}

同时注意让 SpringMvcConfig 配置类扫描到 config 包中的 SpringMvcSupport 类。

4. SSM 整合

流程:

  1. 创建Maven的web项目,设置打包方式,补全目录
  2. 添加 SSM 需要的依赖:
    • spring:spring-jdbcspring-test
    • 数据库:mybatismysql-connector-javadruidmybatis-spring
    • 单元测试:junit
    • servlet:spring-webmvcjavax.servlet-apijackson-databind
    • tomcat:tomcat7-maven-plugin
  3. 创建项目包结构
    热门框架学习笔记_第12张图片
  4. 创建SpringConfig配置类
@Configuration
@ComponentScan({"com.itheima.service"})
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class, MyBatisConfig.class})
@EnableTransactionManagement
public class SpringConfig {
}
  1. 创建JdbcConfig配置类,包含数据库连接池 bean 和 事务管理的 bean
public class JdbcConfig {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;

    @Bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(username);
        ds.setPassword(password);
        return ds;
    }

    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource){
        DataSourceTransactionManager dstm = new DataSourceTransactionManager();
        dstm.setDataSource(dataSource);
        return dstm;
    }
}
  1. 创建MybatisConfig配置类,包含 SqlSessionFactoryBean 和 mapper映射文件的bean
public class MyBatisConfig {
    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        sqlSessionFactoryBean.setTypeAliasesPackage("com.itheima.domain");
        return sqlSessionFactoryBean;
    }

    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer(){
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setBasePackage("com.itheima.dao");
        return mapperScannerConfigurer;
    }
}
  1. 创建jdbc.properties
  2. 创建SpringMVC配置类
@Configuration
@ComponentScan({"com.itheima.controller", "com.itheima.config"})
@EnableWebMvc
public class SpringMvcConfig {
}
  1. 创建Web项目入口配置类
// Web 项目入口配置类
public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    // 加载 Spring 配置类
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SpringConfig.class};
    }

    // 加载 SpringMvc 配置类
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMvcConfig.class};
    }

    // 配置 SpringMVC 请求地址拦截规则
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    // 设置 post 请求中文乱码过滤器
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("utf-8");
        return new Filter[]{filter};
    }
}
  1. 创建数据库及表并初始化数据
  2. 编写模型类:domain 包下 Book 类
  3. 编写Dao接口:用注解编写 sql 语句:增、删、改、按 id 查询、查询所有。查询会返回查询的对象或者null,而正常增删改是没有返回值的,此时不能判断到底有没有增删改成功:将增删改的返回值改为 int ,会返回操作影响的行数,当成功操作,返回值 >0 再在 service 层返回 true 表示操作成功;否则返回 false 表示操作失败。
  4. 编写Service接口和实现类
  5. 编写Contorller类,使用 REST 风格
@RestController
@RequestMapping("/books")
public class BookController {
    @Autowired
    private BookService bookService;

    @PostMapping
    public Result save(@RequestBody Book book){
        boolean flag = bookService.save(book);
        return new Result(flag ? Code.SAVE_OK : Code.SAVE_ERR, flag);
    }

    @PutMapping
    public Result update(@RequestBody Book book){
        boolean flag = bookService.update(book);
        return new Result(flag ? Code.UPDATE_OK : Code.UPDATE_ERR, flag);
    }

    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id){
        boolean flag = bookService.delete(id);
        return new Result(flag ? Code.DELETE_OK : Code.DELETE_ERR, flag);
    }

    @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);
    }

    @GetMapping
    public Result getAll(){
        List<Book> list = bookService.getAll();
        Integer code = list != null ? Code.GET_OK : Code.GET_ERR;
        String msg = list != null ? "" : "数据查询失败,请重试!";
        return new Result(code,list,msg);
    }
}
  1. 单元测试 Service 类
  2. PostMan测试各个功能

5. 统一结果封装

5.1 结果封装思路

  • 为了封装返回的结果数据:创建结果模型类,封装数据到data属性中
  • 为了封装返回的数据是何种操作及是否操作成功:封装操作结果到code属性中
  • 操作失败后为了封装返回的错误信息:封装特殊消息到message(msg)属性中
    热门框架学习笔记_第13张图片

5.2 实现

  1. 在 controller 包下创建 Result 类:三个属性、构造方法、setter、getter
  2. 在 controller 包下定义返回码 Code 类:各种操作成功、失败编码(自己定义)
  3. 修改Controller类的返回值,让所有方法的返回值类型都是 Result ,在 return 语句中将封装好的 Result 对象返回回去

6. 异常处理

目的:出现异常的时候,也会返回一个 Result 标准结果对象回去,在 msg 属性中添加异常信息。

6.1 异常分类

  1. 业务异常(BusinessException):规范的用户行为产生的异常如输入错数据类型、不规范的用户行为操作产生的异常如故意传递错误的请求数据
    • 解决:发送对应消息传递给用户,提醒规范操作
  2. 系统异常(SystemException):项目运行过程中可预计但无法避免的异常如系统宕机
    • 解决:发送固定消息传递给用户,安抚用户;发送特定消息给运维人员,提醒维护;记录日志
  3. 其他异常(Exception):编程人员未预期到的异常如用到的文件不存在
    • 解决:发送固定消息传递给用户,安抚用户;发送特定消息给编程人员,提醒维护(纳入预期范围内);记录日志

6.2 异常解决方案的实现

  1. 在 exception 包下定义自定义异常类,封装业务异常和系统异常
// 自定义业务异常类
public class BusinessException extends RuntimeException{
    private Integer code;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public BusinessException(Integer code, String message){
        super(message);
        this.code = code;
    }

    public BusinessException(Integer code, String message, Throwable cause){
        super(message,cause);
        this.code = code;
    }
}
// 自定义系统异常类
public class SystemException extends RuntimeException{
    private Integer code;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public SystemException(Integer code, String message){
        super(message);
        this.code = code;
    }

    public SystemException(Integer code, String message, Throwable cause){
        super(message,cause);
        this.code = code;
    }
}
  1. 将其他异常包成自定义异常:即在代码处理中遇到可以预测到的异常情况时,抛出我们自定义的异常
    • try{}catch(){}在catch中重新throw我们自定义异常
    • 直接throw自定义异常即可
	@Override
    public Book getById(Integer id) {
        // 模拟业务异常,包装成自定义异常
        if(id == 1){
            throw new BusinessException(Code.BUSINESS_ERR,"请不要用你的技术挑战我的耐性");
        }

        // 模拟系统异常,将可能出现的异常包装转换成自定义异常
        try {
            int i = 1 / 0;
        } catch (Exception e){
            throw new SystemException(Code.SYSTEM_TIMEOUT_ERR,"服务器访问超时,请重试!",e);
        }

        return bookDao.getById(id);
    }

  1. 在 controller 包下定义异常处理器类 ProjectExceptionAdvice,在出现异常的时候依然正常返回标准的 Result 对象给前端,同时要确保SpringMvcConfig能够扫描到异常处理器类
@RestControllerAdvice
public class ProjectExceptionAdvice {
    // @ExceptionHandler 用于设置当前处理器类对应的异常类型
    @ExceptionHandler(SystemException.class)
    public Result doSystemException(SystemException ex){
        //其他处理:记录日志、发送消息给运维、发送邮件给开发人员
        // 接替 controller 返回结果
        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){
        //其他处理
        return new Result(Code.SYSTEM_UNKNOW_ERR, null, "系统繁忙,请稍后再试");
    }
}

6.3 知识点

  1. 异常处理器:集中的、统一的处理项目中出现的异常
  2. @RestControllerAdvice :Rest风格开发的控制器增强类定义上方,为Rest风格开发的控制器类做增强——此注解自带 @ResponseBody 注解与 @Component 注解,具备对应的功能
  3. @ExceptionHandler :专用于异常处理的控制器方法上方,设置指定异常的处理方案,功能等同于控制器方法,出现异常后终止原始控制器执行,并转入当前方法执行

7. 拦截器

7.1 拦截器概念

热门框架学习笔记_第14张图片

  1. 拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行
  2. 作用:
    • 在指定的方法调用前后执行预先设定的代码
    • 阻止原始方法的执行
    • 总结:拦截器就是用来做增强
  3. 拦截器和过滤器:
    • 归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术
    • 拦截内容不同:Filter对所有访问进行增强,Interceptor仅针对SpringMVC的访问进行增强
      热门框架学习笔记_第15张图片

7.2 拦截器开发

  1. 在 controller 包下添加 interceptor 包,创建拦截器类 ProjectInterceptor,让类实现 HandlerInterceptor 接口,重写接口中的三个方法;拦截器类要被SpringMVC容器扫描到
@Component
//定义拦截器类,实现HandlerInterceptor接口
//注意当前类必须受Spring容器控制
public class ProjectInterceptor implements HandlerInterceptor {
	@Override
	//原始方法调用前执行的内容
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		System.out.println("preHandle...");
		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...");
	}
}
  1. 配置拦截器类:在 config 包下的 SpringMvcSupport 类中,定义一个 ProjectInterceptor 对象并自动装配,覆盖 addInterceptors 方法配置拦截器
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
	@Autowired
	private ProjectInterceptor projectInterceptor;
	@Override
	protected void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
	} 
	@Override
	protected void addInterceptors(InterceptorRegistry registry) {
		//配置拦截器
		registry.addInterceptor(projectInterceptor).addPathPatterns("/books");
	}
}
  1. SpringMVC添加SpringMvcSupport包扫描
  2. 修改拦截器拦截规则,让 /books 下一级目录也被包含
@Override
protected void addInterceptors(InterceptorRegistry registry) {
	//配置拦截器
	registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*" );
}
  1. 简化SpringMvcSupport的编写
@Configuration
@ComponentScan({"com.itheima.controller"})
@EnableWebMvc
//实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性
public class SpringMvcConfig implements WebMvcConfigurer {
	@Autowired
	private ProjectInterceptor projectInterceptor;
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		//配置多拦截器
		registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
	}
}

热门框架学习笔记_第16张图片

7.3 拦截器参数

  1. 前置处理方法
  2. 后置处理方法
  3. 完成处理方法

7.4 拦截器链配置

热门框架学习笔记_第17张图片

3-SpringBoot

1. SpringBoot 简介

1.1 SpringBoot 入门案例

  1. 创建新模块
    • 选择 Spring Initializr ,用来创建 SpringBoot 工程,模块名、路径、包名自己更改
      热门框架学习笔记_第18张图片
    • 选中 Web ,然后勾选 Spring Web
      热门框架学习笔记_第19张图片
    • 经过以上步骤后就创建了如下结构的模块,它会帮我们自动生成一个 Application 类
      热门框架学习笔记_第20张图片
  2. 创建 Controller:在 com.itheima.controller 包下使用 Rest 风格创建 BookController
  3. 启动服务器:运行项目 com.itheima 包下的 Application 类即成功启动
  4. 使用 Postman 工具测试程序
  5. 对比
    热门框架学习笔记_第21张图片

1.2 官网构建工程

  • 进入SpringBoot 官网
    热门框架学习笔记_第22张图片
  • 选择依赖:ADD DEPENDENCES
    热门框架学习笔记_第23张图片
  • 生成工程:GENERATE
    热门框架学习笔记_第24张图片

1.3 SpringBoot工程快速启动

  1. 打包:使用 Maven 的 package 指令在 target 目录下生成对应的 Jar 包
  2. 进入 jar 包所在位置,在 命令提示符 中输入如下命令
java -jar springboot_01_quickstart-0.0.1-SNAPSHOT.jar

1.4 SpringBoot 概述

  1. 起步依赖
    • starter : SpringBoot 中常见项目名称,定义了当前项目使用的所有项目坐标,以达到减少依赖配置的目的
    • parent : 所有 SpringBoot 项目要继承的项目,定义了若干个坐标版本号(依赖管理,而非依赖),以达到减少依赖冲突的目的
    • 实际开发 : 使用任意坐标时,仅书写GAV中的 G(groupid) 和 A(artifactId) ,V(version) 由SpringBoot提供
  2. 程序启动
    创建的每一个 SpringBoot 程序时都包含一个引导类:
  • SpringBoot 在创建项目时,采用jar的打包方式
  • SpringBoot 的引导类是项目的入口,运行 main 方法就可以启动项目
  1. 切换web服务器:将启动工程的服务器由 tomcat 切换为 jetty
    • 排除 tomcat 服务器
<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-webartifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-tomcatartifactId>
        exclusion>
    exclusions>
dependency>
- 在 pom.xml 中引入 jetty 的起步依赖
<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-jettyartifactId>
dependency>

2. 配置文件

SpringBoot 程序的配置文件名必须是 application

2.1 yaml格式

  1. YAML(YAML Ain’t Markup Language),一种数据序列化格式
  2. 优点:
    • 容易阅读
    • 容易与脚本语言交互
    • 以数据为核心,重数据轻格式
  3. YAML 文件扩展名:
    • .yml (主流)
    • .yaml
  4. 语法规则
    • 核心规则:数据前面要加空格与冒号隔开
  5. 三种配置文件的优先级:application.properties > application.yml > application.yaml

2.2 yaml配置文件数据读取

  1. 环境准备:
    • 创建 SpringBoot 工程
    • controller 包下创建控制器
    • domain 包下创建实体类封装数据
    • resources 下创建一个名为 application.yml 的配置文件
lesson: SpringBoot

server: 
  port: 80

enterprise:
  name: itcast
  age: 16
  tel: 138****8888
  subject:
    - java
    - 前端
    - 大数据
  1. 读取配置数据
  • 使用 @Value 注解:
@RestController
@RequestMapping("/books")
public class BookController {
	@Value("${lesson}")
	private String lesson;
	@Value("${server.port}")
	private Integer port;
	@Value("${enterprise.subject[0]}")
	private String subject_00;
	@GetMapping("/{id}")
	public String getById(@PathVariable Integer id){
		System.out.println(lesson);
		System.out.println(port);
		System.out.println(subject_00);
		return "hello , spring boot!";
	}
}
  • Environment对象 :SpringBoot 还可以使用 @Autowired 注解注入 Environment 对象的方式读取数据, SpringBoot 会将配置文件中所有的数据封装到 Environment 对象中,如果需要使用哪个数据只需要通过调用 Environment 对象的 getProperty(String name) 方法获取
@RestController
@RequestMapping("/books")
public class BookController {
	@Autowired
	private Environment env;
	@GetMapping("/{id}")
	public String getById(@PathVariable Integer id){
		System.out.println(env.getProperty("lesson"));
		System.out.println(env.getProperty("enterprise.name"));
		System.out.println(env.getProperty("enterprise.subject[0]"));
		return "hello , spring boot!";
	}
}
  • 自定义对象:
    • 将实体类 bean 的创建交给 Spring 管理:在类上添加 @Component 注解
    • 使用 @ConfigurationProperties 注解表示加载配置文件:在该注解中也可以使用 prefix 属性指定只加载指定前缀的数据
    • BookController 中进行注入

2.3 多环境配置

  1. yaml文件:在 application.yml 中使用 --- 来分割不同的配置;
  2. 设置启用的环境
#设置启用的环境
spring:
  profiles:
    active: pro	#表示使用的是生产环境的设置

---
#开发
spring:
  config:
    activate:
      on-profile: dev
server:
  port: 80
---
#生产
spring:
  config:
    activate:
      on-profile: pro
server:
  port: 81
---
#测试
spring:
  config:
    activate:
      on-profile: test
server:
  port: 82
  1. 命令行启动参数设置
    • 在运行 jar 时设置开启指定的环境的方式
java –jar xxx.jar –-spring.profiles.active=test
- 临时修改端口号
java –jar xxx.jar –-server.port=88

2.4 配置文件分类

  • 1级:classpath:application.yml
  • 2级:classpath:config/application.yml
  • 3级:file :application.yml
  • 4级:file :config/application.yml
    说明:级别越高优先级越高

3. SpringBoot 整合 junit

  1. 环境准备:SpringBoot 工程,待测试的 service 接口、实现类,@Service 注解
  2. 编写测试类:在 test/java 下创建 com.itheima 包,在该包下创建测试类 SpringbootQuickstartApplicationTests (默认创建工程时生成有),将 BookService 注入到该测试类中
@SpringBootTest
class SpringbootQuickstartApplicationTests {
    @Autowired
    private BookService bookService;

    @Test
    void testSave() {
        bookService.save();
    }

}

4. SpringBoot 整合 Mybatis

  1. 创建模块:选择 Spring Initializer ,配置模块相关基础信息;选择当前模块需要使用的技术集(MyBatis、MySQL)
    热门框架学习笔记_第25张图片
  2. 定义实体类:在 domain 包下定义实体类 Book
  3. 在 dao 包下定义 BookDao 接口,注解编写 getById sql语句
  4. 在 test/java 包 com.example 下修改测试类 SpringbootMybatisApplicationTests
@SpringBootTest
class SpringbootMybatisApplicationTests {
    @Autowired
    private BookDao bookDao;

    @Test
    void testGetById() {
        Book book = bookDao.getById(1);
        System.out.println(book);
    }
}
  1. 编写配置,指定要连接的数据库和连接需要的信息,在 resources 目录下 application.yml 配置文件中配置如下内容:\
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/ssm_db
    username: root
    password: 1234
  1. 运行测试方法 testGetById 测试报错:在 Spring 容器中没有 BookDao 类型的 bean ,原因 ⇒ Mybatis 会扫描接口并创建接口的代码对象交给 Spring 管理,但是现在并没有告诉 Mybatis 哪个是 dao 接口,即没有最开始的指定 Mapper ⇒ 在 BookDao 接口上使用 @Mapper
@Mapper
public interface BookDao {
    @Select("select * from tbl_book where id = #{id}")
    public Book getById(Integer id);
}
  1. 再次运行,测试得到 id 为1的书籍结果
  2. 指定 Druid 数据源: 导入 Druid 依赖
<dependency>
    <groupId>com.alibabagroupId>
    <artifactId>druidartifactId>
    <version>1.1.16version>
dependency>
  1. application.yml 配置文件中通过 spring.datasource.type 来配置使用什么数据源配置
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/ssm_db
    username: root
    password: 1234
    type: com.alibaba.druid.pool.DruidDataSource

4-Maven高级

1. 分模块开发

1.1 分模块开发设计

  1. 按照功能拆分
  2. 按照模块拆分

1.2 项目拆分步骤

  1. 创建Maven模块
  2. 书写模块代码
  3. 通过maven指令安装模块到本地仓库(install 指令)
  4. 在需要该模块的地方导入依赖坐标

2. 依赖管理

2.1 依赖传递

  1. 依赖传递
    热门框架学习笔记_第26张图片
  2. 依赖冲突:项目依赖的某一个jar包,有多个不同的版本,因而造成类包版本冲突
  3. 依赖冲突时版本优先级:
    • 特殊优先:当同级配置了相同资源的不同版本,后配置的覆盖先配置的
    • 路径优先:当依赖中出现相同的资源时,层级越深,优先级越低,层级越浅,优先级越高
    • 声明优先:当资源在相同层级被依赖时,配置顺序靠前的覆盖配置顺序靠后的
  4. 各个坐标的依赖关系:点击Maven面板中的show Dependencies
    热门框架学习笔记_第27张图片

2.2 可选依赖

  1. 可选依赖指对外隐藏当前所依赖的资源 —— 不透明
  2. 格式:
<dependency>
    <groupId>com.itheimagroupId>
    <artifactId>maven_03_pojoartifactId>
    <version>1.0-SNAPSHOTversion>
    
    <optional>trueoptional>
dependency>

2.3 排除依赖

  1. 排除依赖指主动断开依赖的资源,被排除的资源无需指定版本—不需要
  2. 格式:
<dependency>
    <groupId>com.itheimagroupId>
    <artifactId>maven_04_daoartifactId>
    <version>1.0-SNAPSHOTversion>
    
    <exclusions>
        <exclusion>
            <groupId>com.itheimagroupId>
            <artifactId>maven_03_pojoartifactId>
        exclusion>
    exclusions>
dependency>
  1. 可选依赖与排除依赖对比:A依赖B,B依赖C,C通过依赖传递会被A使用到,现在要想办法让A不去依赖C
    • 可选依赖是在B上设置 ,A不知道有C的存在
    • 排除依赖是在A上设置 ,A知道有C的存在,主动将其排除掉

3. 聚合和继承

3.1 聚合

  1. 聚合概念:
    • 聚合:将多个模块组织成一个整体,同时进行项目构建的过程称为聚合
    • 聚合工程:通常是一个不具有业务功能的"空"工程(有且仅有一个pom文件)
    • 作用:使用聚合工程可以将多个工程编组,通过对聚合工程进行构建,实现对所包含的模块进行同步构建
  2. 聚合实现步骤
  • 步骤1:创建一个空的maven项目
  • 步骤2:将项目的打包方式改为pom
	<packaging>pompackaging>
  • 步骤3:pom.xml添加所要管理的项目
    
    <modules>
        <module>../maven_02_ssmmodule>
        <module>../maven_03_pojomodule>
        <module>../maven_04_daomodule>
    modules>
  • 步骤4:使用聚合统一管理项目:执行聚合工程的 compile 指令,所有被其管理的项目都会被执行编译操作

3.2 继承

  1. 继承概念:
    • 继承:描述的是两个工程间的关系,与java中的继承相似,子工程可以继承父工程中的配置信息,常见于依赖关系的继承。
    • 作用:
      • 简化配置
      • 减少版本冲突
  2. 继承实现步骤
  • 步骤1:创建一个空的Maven项目并将其打包方式设置为pom,可以直接和聚合公用一个工程、
  • 步骤2:在子项目中设置其父工程
    
    <parent>
        <groupId>com.itheimagroupId>
        <artifactId>maven_01_parentartifactId>
        <version>1.0-SNAPSHOTversion>
        
        <relativePath>../maven_01_parentrelativePath>
    parent>
  • 步骤3:优化子项目共有依赖导入问题:将子项目共同使用的jar包都抽取出来,维护在父项目的pom.xml中;删除子项目中已经被抽取到父项目的pom.xml中的jar包;父项目中有依赖对应的jar包,子项目虽然已经将重复的依赖删除掉了,但是刷新的时候,子项目中所需要的jar包依然存在
  • 步骤4:优化子项目依赖版本问题:在父工程mavne_01_parent的pom.xml来定义依赖管理
	
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>junitgroupId>
                <artifactId>junitartifactId>
                <version>4.12version>
                <scope>testscope>
            dependency>
        dependencies>
    dependencyManagement>
  • 标签不真正引入jar包,而是配置可供子项目选择的jar包依赖;子项目要想使用它所提供的这些jar包,需要自己添加依赖,并且不需要指定
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <scope>testscope>
        dependency>

3.3 聚合与继承的对比

  1. 作用
    • 聚合用于快速构建项目,对项目进行管理
    • 继承用于快速配置和管理子项目中所使用jar包的版本
  2. 相同点
    • 聚合与继承的pom.xml文件打包方式均为pom,可以将两种关系制作到同一个pom文件中
    • 聚合与继承均属于设计型模块,并无实际的模块内容
  3. 不同点
    • 聚合是在当前模块中配置关系,聚合可以感知到参与聚合的模块有哪些
    • 继承是在子模块中配置关系,父模块无法感知哪些子模块继承了自己
  4. IDEA构建聚合与继承工程
    • 步骤1:创建一个空的Maven项目,可以将项目中的src目录删除掉,这个项目作为聚合工程和父工程
    • 步骤2:创建子项目,使该项目可以被聚合工程管理,同时会继承父工程
      热门框架学习笔记_第28张图片

4. 属性

4.1 属性

  1. 目的:解决如 Spring 多个依赖的版本的统一管理问题
    热门框架学习笔记_第29张图片
  2. 实现步骤:
  • 步骤1:父工程中定义属性
	<properties>
		<spring.version>5.2.10.RELEASEspring.version>
		<junit.version>4.12junit.version>
		<mybatis-spring.version>1.3.0mybatis-spring.version>
	properties>
  • 步骤2:修改依赖的version
	<dependency>
		<groupId>org.springframeworkgroupId>
		<artifactId>spring-coreartifactId>
		<version>${spring.version}version>
	dependency>
	<dependency>
		<groupId>org.springframeworkgroupId>
		<artifactId>spring-webmvcartifactId>
		<version>${spring.version}version>
	dependency>
	<dependency>
		<groupId>org.springframeworkgroupId>
		<artifactId>spring-jdbcartifactId>
		<version>${spring.version}version>
	dependency>
  • 效果:只需要更新父工程中properties标签中所维护的jar包版本,所有子项目中的版本也就跟着更新

4.2 配置文件加载属性

  1. 目的:管理项目中的配置文件如 jdbc.properties 的属性
  2. 实现步骤:
  • 步骤1:父工程定义属性
	<properties>
		<jdbc.url>jdbc:mysql://127.1.1.1:3306/ssm_dbjdbc.url>
	properties>
  • 步骤2:jdbc.properties文件中引用属性
	jdbc.driver=com.mysql.jdbc.Driver
	jdbc.url=${jdbc.url}
	jdbc.username=root
	jdbc.password=root
  • 步骤3:设置maven过滤文件范围:Maven在默认情况下是从当前项目的src\main\resources下读取文件进行打包。现在我们需要打包的资源文件是在maven_02_ssm下,需要我们通过配置来指定下具体的资源目录
	<build>
		<resources>
			
			<resource>
				<directory>../maven_02_ssm/src/main/resourcesdirectory>
				
				<filtering>truefiltering>
			resource>
		resources>
	build>
  • 多个项目需要属性配置:
	<build>
		<resources>
			
			<resource>
				<directory>${project.basedir}/src/main/resourcesdirectory>
				<filtering>truefiltering>
			resource>
		resources>
	build>
  • 解决有的项目是 web 项目,打包时 Maven 去找web项目的入口web.xml[配置文件配置的方式] 找不到而报错的问题:配置maven打包war时,忽略web.xml检查
	<build>
		<plugins>
		<plugin>
			<groupId>org.apache.maven.pluginsgroupId>
			<artifactId>maven-war-pluginartifactId>
			<version>3.2.3version>
			<configuration>
				<failOnMissingWebXml>falsefailOnMissingWebXml>
			configuration>
			plugin>
		plugins>
	build>
  1. Maven 的内置系统属性
    热门框架学习笔记_第30张图片

4.3 版本管理

  1. SNAPSHOT(快照版本):项目开发过程中临时输出的版本,称为快照版本
  2. RELEASE(发布版本):项目开发到一定阶段里程碑后,向团队外部发布较为稳定的版本,这种版本所对应的构件文件是稳定的
  3. alpha版:内测版,bug多不稳定内部版本不断添加新功能
  4. beta版:公测版,不稳定(比alpha稳定些),bug相对较多不断添加新功能
  5. 纯数字版

5. 多环境配置与应用

5.1 多环境开发

热门框架学习笔记_第31张图片
实现步骤:

  1. 父工程配置多个环境,并指定默认激活环境
<profiles>
	
	<profile>
		<id>env_depid>
		<properties>
			<jdbc.url>jdbc:mysql://127.1.1.1:3306/ssm_dbjdbc.url>
		properties>
		
		<activation>
			<activeByDefault>trueactiveByDefault>
		activation>
	profile>
	
	<profile>
		<id>env_proid>
		<properties>
			<jdbc.url>jdbc:mysql://127.2.2.2:3306/ssm_dbjdbc.url>
		properties>
	profile>
	
	<profile>
		<id>env_testid>
		<properties>
			<jdbc.url>jdbc:mysql://127.3.3.3:3306/ssm_dbjdbc.url>
		properties>
	profile>
profiles>
  1. 执行安装 install 查看env_dep环境是否生效:即安装项目,到压缩文件里找 jdbc.properties 里面的 url 配置的到底是哪个
  2. 切换默认环境为生产环境:在生产环境下配置 标签
  3. 执行安装并查看env_pro环境是否生效
  4. 命令行实现环境切换:
mvn install -P env_test
  1. 执行安装并查看env_test环境是否生效

5.2 跳过测试

  1. 方式一:IDEA工具实现跳过测试
    热门框架学习笔记_第32张图片
  2. 方式二:配置插件实现跳过测试:在父工程中的pom.xml中添加测试插件配置
<build>
	<plugins>
		<plugin>
			<artifactId>maven-surefire-pluginartifactId>
			<version>2.12.4version>
			<configuration>
				<skipTests>falseskipTests>
				
				<excludes>
					<exclude>**/BookServiceTest.javaexclude>
				excludes>
			configuration>
		plugin>
	plugins>
build>
  1. 方式三:命令行跳过测试
    热门框架学习笔记_第33张图片

6. 私服

6.1 私服

私服是一台独立的服务器,用于解决团队内部的资源共享与资源同步问题
热门框架学习笔记_第34张图片

6.2 私服安装

Sonatype公司的一款maven私服产品:Nexus
下载地址:https://help.sonatype.com/repomanager3/download

6.3 私服仓库分类

热门框架学习笔记_第35张图片

  1. 宿主仓库hosted:保存无法从中央仓库获取的资源 —— 自主研发、第三方非开源项目
  2. 代理仓库proxy:代理远程仓库,通过nexus访问其他公共仓库,例如中央仓库
  3. 仓库组group:将若干个仓库组成一个群组,简化配置;仓库组不能保存资源,属于设计型仓库
    热门框架学习笔记_第36张图片

6.4 本地仓库访问私服配置热门框架学习笔记_第37张图片

6.5 私服资源上传与下载

  1. 步骤1:配置工程上传私服的具体位置
  2. 步骤2:发布资源到私服

7-MyBatisPlus

1. 入门

1.1 入门案例

  1. 步骤1:创建数据库及表
  2. 步骤2:创建SpringBoot工程
    热门框架学习笔记_第38张图片
  3. 步骤3:勾选配置使用技术
    热门框架学习笔记_第39张图片
    MP并未被收录到idea的系统内置配置,无法直接选择加入,需要手动在pom.xml中配置添加。MyBatis整合Spring的jar包通过MP的依赖关系传入。
  4. 步骤4:pom.xml补全依赖

<dependency>
    <groupId>com.baomidougroupId>
    <artifactId>mybatis-plus-boot-starterartifactId>
    <version>3.4.1version>
dependency>

<dependency>
    <groupId>com.alibabagroupId>
    <artifactId>druidartifactId>
    <version>1.1.16version>
dependency>

热门框架学习笔记_第40张图片

  1. 步骤5:添加MP的相关配置信息:在 resources 目录下创建 application.yml 配置文件,并在文件中配置数据库连接的相关信息
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC
    username: root
    password: xxxx
  1. 步骤6:根据数据库表创建实体类
  2. 步骤7:创建Dao接口,继承 BaseMapper 接口
// @Mapper
public interface UserDao extends BaseMapper<User> {
}
  1. 步骤8:编写引导类 Mybatisplus01QuickstartApplication,通过 @MapperScan 注解扫描 Dao 包下面的所有接口,就不用在每个 Dao 接口上写 @Mapper 注解
@MapperScan("com.example.dao")
@SpringBootApplication
public class Mybatisplus01QuickstartApplication {

    public static void main(String[] args) {
        SpringApplication.run(Mybatisplus01QuickstartApplication.class, args);
    }

}
  1. 步骤9:编写测试类
@SpringBootTest
class Mybatisplus01QuickstartApplicationTests {

    @Autowired
    private UserDao userDao;

    //查询所有
    @Test
    void testGetAll() {
        List<User> userList = userDao.selectList(null);
        System.out.println(userList);
    }
}

1.2 MybatisPlus简介

  1. MyBatisPlus:基于MyBatis框架基础上开发的增强型工具,旨在简化开发、提高效率
  2. 官网:https://mp.baomidou.com/

2. 标准数据层开发

2.1 标准CRUD使用

热门框架学习笔记_第41张图片

2.2 新增

在测试类中进行新增操作:

 	//增
    @Test
    void testSave() {
        User user = new User();
        user.setName("黑马程序员");
        user.setPassword("itheima");
        user.setAge(12);
        user.setTel("13800001111");
        userDao.insert(user);
    }

2.3 删除

	//删
	@Test
	void testDelete(){
	    userDao.deleteById(1608813761737584642L);
	}

2.4 修改

//改
	@Test
	void testUpdate(){
	    User user = new User();
	    user.setId(1L);
	    user.setName("Tom666");
	    user.setPassword("tom666");
	    userDao.updateById(user);
	}

2.5 根据 ID 查询

    //根据Id查询
    @Test
    void testGetById() {
        User user = userDao.selectById(2L);
        System.out.println(user);
    }

2.6 查询所有

    //查询所有
    @Test
    void testGetAll() {
        List<User> userList = userDao.selectList(null);
        System.out.println(userList);
    }

2.7 Lombok

  1. Lombok 概念:一个Java类库,提供了一组注解,简化POJO实体类开发。
  2. 使用步骤
  • 步骤1:添加lombok依赖
	
	<dependency>
	    <groupId>org.projectlombokgroupId>
	    <artifactId>lombokartifactId>
	dependency>
  • 步骤2:安装Lombok的插件:新版本 IDEA 已内置
  • 步骤3:模型类上添加注解
    • @Setter:为模型类的属性提供setter方法
    • @Getter:为模型类的属性提供getter方法
    • @ToString:为模型类的属性提供toString方法
    • @EqualsAndHashCode:为模型类的属性提供equals和hashcode方法
    • @Data:是个组合注解,包含上面的注解的功能
    • @NoArgsConstructor:提供一个无参构造函数
    • @AllArgsConstructor:提供一个包含所有参数的构造函数

2.8 分页功能

  1. 分页查询方法:
	IPage<T> selectPage(IPage<T> page, Wrapper<T> queryWrapper)
- IPage:用来构建分页查询条件:IPage是一个接口,其有一个实现类为Page
- Wrapper:用来构建条件查询的条件,目前我们没有可直接传为Null
- IPage:返回值,你会发现构建分页条件和方法的返回值都是IPage
  1. 使用步骤
  • 步骤1:调用方法传入参数获取返回值
    //分页查询
    @Test
    void testSelectPage() {
        //1.创建 IPage 分页对象,设置分页参数
        IPage<User> page = new Page<>(1, 3);

        //2.执行分页查询
        userDao.selectPage(page,null);

        //3.获取分页结果
        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());
    }
  • 步骤2:设置分页拦截器:该拦截器MP已经为我们提供好了,我们只需要将其配置成Spring管理的bean对象即可:创建 config 包,新建 MyBatisPlusConfig 类
@Configuration
public class MybatisPlusConfig {

    //将分页拦截器插件配置成 Spring 管理的 bean 对象
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        //创建分页拦截器对象
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        //添加分页拦截器
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}
  • 步骤3:运行测试程序
    在这里插入图片描述
  • 想查看MP执行的SQL语句,可以修改application.yml配置文件
mybatis-plus:
  configuration:
    #打印 sql 日志到控制台
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

3. DQL编程控制

3.1 条件查询

  1. 条件查询的类:Wrapper 类
    热门框架学习笔记_第42张图片
  2. 环境构建
  • 创建一个SpringBoot项目:选择 sqlDriver
  • pom.xml中添加对应的依赖:mybatis-plus-boot-starterdruidlombok
  • 编写UserDao接口,添加 Mapper 注解
  • 编写模型类 User,添加 Data 注解
  • 编写引导类(系统生成)
  • 编写配置文件:dataSource、mp日志
  • 编写测试类
  • 取消初始化spring日志打印:在resources目录下添加logback.xml

<configuration>
configuration>
  • 取消MybatisPlus启动banner图标:application.yml添加如下内容:
# mybatis-plus日志控制台输出
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    banner: off # 关闭mybatisplus启动图标
  • 取消SpringBoot的log打印:application.yml添加如下内容:
spring:
  main:
    banner-mode: off # 关闭SpringBoot启动图标(banner)
  1. 构建条件查询
    热门框架学习笔记_第43张图片
  • QueryWrapper
	@Test
	void testGetAll(){
		QueryWrapper qw = new QueryWrapper();
		qw.lt("age",18);
		List<User> userList = userDao.selectList(qw);
		System.out.println(userList);
}
  • QueryWrapper的基础上使用lambda
   @Test
   void testGetAll(){
   	QueryWrapper<User> qw = new QueryWrapper<User>();
   	qw.lambda().lt(User::getAge, 10);//添加条件
   	List<User> userList = userDao.selectList(qw);
   	System.out.println(userList);
   }
  • LambdaQueryWrapper
	@Test
	void testGetAll(){
		LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
		lqw.lt(User::getAge, 10);
		List<User> userList = userDao.selectList(lqw);
		System.out.println(userList);
	}
  1. 多条件构建
	@Test
	void testGetAll(){
		LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
		lqw.lt(User::getAge, 30);
		lqw.gt(User::getAge, 10);
		List<User> userList = userDao.selectList(lqw);
		System.out.println(userList);
	}
  • 构建多条件的时候,可以支持链式编程
	LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
	lqw.lt(User::getAge, 30).gt(User::getAge, 10);
	List<User> userList = userDao.selectList(lqw);
	System.out.println(userList);
  • or() 查询
	@Test
	void testGetAll(){
		LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
		lqw.lt(User::getAge, 10).or().gt(User::getAge, 30);
		List<User> userList = userDao.selectList(lqw);
		System.out.println(userList);
	}
  1. null 判定
  • 前端传过来两个数据供范围查询判定是非为null,而实体类只有一个对应属性:新建一个模型类,让其继承User类,并在其中添加age2属性,UserQuery在拥有User属性后同时添加了age2属性
	@Data
	public class UserQuery extends User {
		private Integer age2;
	}
	@Test
		void testGetAll(){
		//模拟页面传递过来的查询数据
		UserQuery uq = new UserQuery();
		uq.setAge(10);
		uq.setAge2(30);
		LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
		//if(null != uq.getAge2()){
		//	lqw.lt(User::getAge, uq.getAge2());
		//} 
		//if( null != uq.getAge()) {
		//	lqw.gt(User::getAge, uq.getAge());
		//} 
		// 简化
		lqw.lt(null!=uq.getAge2(),User::getAge, uq.getAge2());
		lqw.gt(null!=uq.getAge(),User::getAge, uq.getAge());
		List<User> userList = userDao.selectList(lqw);
		System.out.println(userList);
	}

3.2 查询投影

  1. 查询指定字段
	@Test
	void testGetAll(){
		LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
		lqw.select(User::getId,User::getName,User::getAge);
		List<User> userList = userDao.selectList(lqw);
		System.out.println(userList);
	}
  1. 聚合查询
	@Test
	void testGetAll(){
		QueryWrapper<User> lqw = new QueryWrapper<User>();
		//lqw.select("count(*) as count");
		//SELECT count(*) as count FROM user
		//lqw.select("max(age) as maxAge");
		//SELECT max(age) as maxAge FROM user
		//lqw.select("min(age) as minAge");
		//SELECT min(age) as minAge FROM user
		//lqw.select("sum(age) as sumAge");
		//SELECT sum(age) as sumAge FROM user
		lqw.select("avg(age) as avgAge");
		//SELECT avg(age) as avgAge FROM user
		List<Map<String, Object>> userList = userDao.selectMaps(lqw);
		System.out.println(userList);
	}
  1. 分组查询
	@Test
	void testGetAll(){
		QueryWrapper<User> lqw = new QueryWrapper<User>();
		lqw.select("count(*) as count,tel");
		lqw.groupBy("tel");
		List<Map<String, Object>> list = userDao.selectMaps(lqw);
		System.out.println(list);
	}

3.3 查询条件

  1. 查询条件
    • 范围匹配(> 、 = 、between)
    • 模糊匹配(like)
    • 空判定(null)
    • 包含性匹配(in)
    • 分组(group)
    • 排序(order)
  2. 等值查询
	@Test
	void testGetAll(){
		LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
		lqw.eq(User::getName, "Jerry").eq(User::getPassword, "jerry");
		User loginUser = userDao.selectOne(lqw);
		System.out.println(loginUser);
	}
  1. 范围查询
	@Test
	void testGetAll(){
		LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
		lqw.between(User::getAge, 10, 30);
		//SELECT id,name,password,age,tel FROM user WHERE (age BETWEEN ? AND?)
		List<User> userList = userDao.selectList(lqw);
		System.out.println(userList);
	}
  • gt():大于(>)
  • ge():大于等于(>=)
  • lt():小于(<)
  • lte():小于等于(<=)
  • between():between ? and ?
  1. 模糊查询
	@Test
	void testGetAll(){
		LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
		lqw.likeLeft(User::getName, "J");
		//SELECT id,name,password,age,tel FROM user WHERE (name LIKE ?)
		List<User> userList = userDao.selectList(lqw);
		System.out.println(userList);
	}
  • like():前后加百分号,如 %J%
  • likeLeft():前面加百分号,如 %J
  • likeRight():后面加百分号,如 J%
  1. 排序查询
	@Test
	void testGetAll(){
		LambdaQueryWrapper<User> lwq = new LambdaQueryWrapper<>();
		/**
			* condition :条件,返回boolean,
				当condition为true,进行排序,如果为false,则不排序
			* isAsc:是否为升序,true为升序,false为降序
			* columns:需要操作的列
		*/
		lwq.orderBy(true,false, User::getId);
		userDao.selectList(lwq)
	}

热门框架学习笔记_第44张图片

3.4 映射匹配兼容性问题

  1. 问题1:表字段与编码属性设计不同步:
    热门框架学习笔记_第45张图片
  2. 问题2:编码中添加了数据库中未定义的属性
    热门框架学习笔记_第46张图片
  3. 问题3:采用默认查询开放了更多的字段查看权限(即查询不把敏感数据返回)
    热门框架学习笔记_第47张图片
  4. 问题4:表名与编码开发设计不同步
    热门框架学习笔记_第48张图片
  5. 知识点:
    • @TableField : 模型类属性定义上方,设置当前属性对应的数据库表中的字段关系
    • @TableName :模型类定义上方,设置当前类对应于数据库表关系

4. DML编程控制

4.1 id生成策略控制

  1. @TableId :模型类中用于表示主键的属性定义上方,设置当前类中主键属性的生成策略
  2. AUTO策略:
	@TableId(type = IdType.AUTO)
	private Long id;
  1. NONE: 不设置id生成策略,MP不自动生成,约等于INPUT
  2. INPUT:用户手工输入id
  3. ASSIGN_ID:雪花算法生成id(可兼容数值型与字符串型);可以在分布式的情况下使用,而且能够保证唯一,但是生成的主键是32位的字符串,长度过长占用空间而且还不能排序,查询性能也慢。
  4. ASSIGN_UUID:以UUID生成算法作为id生成策略;可以在分布式的情况下使用,生成的是Long类型的数字,可以排序性能也高,但是生成的策略和服务器时间有关,如果修改了系统时间就有可能导致出现重复主键。
  5. 简化配置:在一处进行配置,就能让所有的模型类都可以使用该主键ID策略:
mybatis-plus:
  global-config:
    db-config:
      id-type: assign_id
  1. 数据库表与模型类的映射关系的简化配置:所有模型类可以不写统一的数据库表前缀
mybatis-plus:
  global-config:
    db-config:
      table-prefix: tbl_

4.2 多记录操作

  1. 多条删除
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
  1. 批量查询
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

4.3 逻辑删除

  1. 删除操作:
    • 物理删除:业务数据从数据库中丢弃,执行的是delete操作
    • 逻辑删除:为数据设置是否可用状态字段,删除时设置状态字段为不可用状态,数据保留在数据库中,执行的是update操作
  2. 实现步骤:
  • 步骤1:修改数据库表添加deleted列:自定义内容如0代表正常,1代表删除,可以在添加列的同时设置其默认值为0正常
  • 步骤2:实体类添加属性:
    • 添加与数据库表的列对应的一个属性名,名称可以任意,如果和数据表列名对不上,可以使用 @TableField 进行关系映射,如果一致,则会自动对应
    • 标识新增的字段为逻辑删除字段,使用 @TableLogic
	@TableLogic(value="0",delval="1")
	//value为正常数据的值,delval为删除数据的值
	private Integer deleted;
  • 步骤3:运行删除方法,逻辑删除最后走的是update操作,会将指定的字段修改成删除状态对应的值。
    热门框架学习笔记_第49张图片
  • 执行查询操作:mp打印出来的sql语句中会多一个查询条件
    热门框架学习笔记_第50张图片
  • 想把已经删除的数据都查询出来:在 dao 接口中自己定义一个查询所有的方法
@Mapper
public interface UserDao extends BaseMapper<User> {
	//查询所有数据包含已经被删除的数据
	@Select("select * from tbl_user")
	public List<User> selectAll();
}
  • 简化配置:
mybatis-plus:
  global-config:
    db-config:
      # 逻辑删除字段名
      logic-delete-field: deleted
      # 逻辑删除字面值:未删除为0
      logic-not-delete-value: 0
      # 逻辑删除字面值:删除为1
      logic-delete-value: 1
  1. @TableLogic :模型类中用于表示删除字段的属性定义上方,标识该字段为进行逻辑删除的字段

4.4 乐观锁

  1. 实现思路(如秒杀应用场景):
  • 数据库表中添加version列,比如默认值给1
  • 第一个线程要修改数据之前,取出记录时,获取当前数据库中的version=1
  • 第二个线程要修改数据之前,取出记录时,获取当前数据库中的version=1
  • 第一个线程执行更新时,set version = newVersion where version = oldVersion
    • newVersion = version+1 [2]
    • oldVersion = version [1]
  • 第二个线程执行更新时,set version = newVersion where version = oldVersion
    • newVersion = version+1 [2]
    • oldVersion = version [1]
      假如这两个线程都来更新数据,第一个和第二个线程都可能先执行
    • 假如第一个线程先执行更新,会把version改为2,
    • 第二个线程再更新的时候,set version = 2 where version = 1,此时数据库表的数据version已经为2,所以第二个线程会修改失败
    • 假如第二个线程先执行更新,会把version改为2
    • 第一个线程再更新的时候,set version = 2 where version = 1,此时数据库表的数据version已经为2,所以第一个线程会修改失败
    • 不管谁先执行都会确保只能有一个线程更新数据,这就是MP提供的乐观锁的实现原理分析。
  1. 实现步骤:
  • 步骤1:数据库表添加列
    热门框架学习笔记_第51张图片
  • 步骤2:在模型类中添加对应的属性
	@Version
	private Integer version;
  • 步骤3:添加乐观锁的拦截器:可参考 mp 官方文档
@Configuration
public class MpConfig {
	@Bean
	public MybatisPlusInterceptor mpInterceptor() {
		//1.定义Mp拦截器
		MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
		//2.添加乐观锁拦截器
		mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
		return mpInterceptor;
	}
}
  • 步骤4:执行更新操作
	@Test
    void testUpdate() {
        User user = userDao.selectById(3L);
        User user2 = userDao.selectById(3L);

        user2.setName("Jock aaa");
        userDao.updateById(user2);
        user.setName("Jock bbb");
        userDao.updateById(user);

    }

5. 快速开发

  1. 代码生成器实现步骤
  • 步骤1:创建一个 SpringBoot Maven项目,勾选 mysqlDriver
  • 代码2:导入对应的jar包:mybatisplus、druid、lombok、代码生成器mybatis-plus-generator、velocity模板引擎velocity-engine-core
  • 步骤3:编写引导类
  • 步骤4:创建代码生成类,可参考 MybatisPlus 官网-核心功能-代码生成器
  • 步骤5:运行程序
    热门框架学习笔记_第52张图片
  1. MP中Service的CRUD:MP提供了一个Service接口和实现类,分别是:IService和ServiceImpl,后者是对前者的一个具体实现。修改以后的好处是,MP已经帮我们把业务层的一些基础的增删改查都已经实现了,可以直接进行使用。
@SpringBootTest
class Mybatisplus04GeneratorApplicationTests {

    private IUserService userService;

    @Test
    void testFindAll() {
        List<User> list = userService.list();
        System.out.println(list);
    }

}

未解决问题:报错 Failed to determine a suitable driver class,未找到原因

你可能感兴趣的:(java后端,学习,spring)