SpringBoot
需要达到的学习效果:
- 1.掌握基于SpringBoot框架的程序开发步骤
- 2.熟练使用SpringBoot配置信息修改服务器配置
- 3.基于SpringBoot完成SSM的整合项目开发
1.初始化
- 1.创建新模块,选择Spring初始化,并配置模块的基础信息
- 2.使用Spring Web进行SpringMvc的开发:
- 3.开发控制类,定义控制器:(REST风格)
@RestController
@RequestMapping("/books/")
public class BookController {
@PostMapping("{id}")
public String getById(@PathVariable Integer id) {
System.out.println("id === " + id);
return "success";
}
}
- 4.运行自动生成的Application类:
2.Spring与SpringBoot程序开发对比
- 基于idea开发SpringBoot框架需要联网
另外一种方式就是通过Spring的官网进行生成:(不用idea照样生成工程)
0.快速启动
- 脱离idea启动一个SpringBoot程序
1.SpringBoot概述
- 用于简化Spring应用的初始搭建和开发过程
- Spring程序的缺点:
- 配置繁琐
- 依赖设置繁琐
- SpringBoot解决的问题:
- 自动配置
- 起步依赖(简化依赖配置)
- 辅助功能(内置服务器)
- pom文件中已经帮我们提前做好了版本管理以及对应的依赖管理
1.起步依赖:
在pom文件中只有简单的几个起步依赖,就可以完成整个工程项目所需的基本配置:
而在<parent>spring-boot-start-parent</parent>
中,他对应继承了
<parent>spring-boot-dependencies</parent>
在<parent>spring-boot-dependencies</parent>
中,他配置了各种版本管理,以及依赖管理:
- GAV:
- groupId
- artifactId
- version
- 在企业应用中,需要根据使用的Spring版本去找对应的SpringBoot版本是多少
2.辅助功能
3.启动方式
4.使用maven依赖管理变更起步依赖项
在spring-boot-start-web
下将tomcat排除:<exclusions><exclusion>spring-boot-starter-tomcat</exclusion></exclusions>
5.配置格式
- 直接在
application.properties
- 配置
application.yml
- 配置
application.yaml
三个文件同时存在时,生效顺序:properties > yml > yaml
1)YAML文件
- yaml语法规则:
- 1.大小写敏感
- 2.属性层级关系使用多行描述,每行结尾使用冒号结束
- 3.使用缩进表示层级关系,同层级左侧对齐,只允许使用空格(不允许使用Tab键)
- 4.属性值前面添加空格(属性名与属性值之间使用冒号+空格作为分隔)
- #表示注释
2.yaml数据读取方式
1.使用
@Vaule
读取单个数据,属性名引用方式:${一级属性名.二级属性名}
2.封装全部数据到Enviment对象
- 3.自定义对象封装指定数据
2.多环境开发
yaml多环境开发配置:
properties文件多环境开发配置:
1.多环境启动命令格式
执行package打包之前,最好先clean一下
有其他干扰配置文件时,应该将它放到备份里面,防止对自己的设置冲突
1.
java -jar springboot.jar -- spring.server.active=dev
2.命令行修改参数配置:
java -jar springboot.jar --server.port=88
当设置的配置没有生效时,需要去检查一下参数的优先级,是否被其他优先级高的替换掉了
3.整合Junit
4.整合Mybatis
- 1.表现层实现:这里是使用测试类来实现
@SpringBootTest
class SpringbootMybatisDemoApplicationTests {
@Autowired
private BookDao bookDao;
@Test
void getById() {
Book book = bookDao.getBookById(1);
System.out.println(book);
}
}
- 2.数据层接口映射配置:
@Mapper
public interface BookDao {
@Select("select * from tb_book where id = #{id}")
public Book getBookById(Integer id);
}
- 3.数据库连接配置以及Druid数据源设置:
导入druid数据源坐标:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/ssm_db
username: root
password: 123456
type: com.alibaba.druid.pool.DruidDataSource
MybatisPlus
1.简介
- 基于Mybatis框架基础上开发的增强型工具,旨在简化开发,提高效率
- SpringBoot整合Mybatis开发过程:
- 创建SpringBoot工程
- 勾选配置使用技术
- 设置dataSource相关属性(JDBC参数)
- 定义数据层接口映射配置
2.特性
- 无侵入:只增强,不改变现有工程
- 强大的CRUD操作,内置通用Mapper,少量配置可以实现单表CRUD操作
- 支持Lambda:编写查询条件无需担心字段写错
- 支持主键自动生成
- 内置分页插件
3.标准CRUD开发
@SpringBootTest
class Mybatisplus01QuickstartApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetById(){
User user = userDao.selectById(1L);
System.out.println(user);
}
@Test
void testGetAll() {
List<User> userList = userDao.selectList(null);
System.out.println(userList);
}
@Test
void testInsert() {
User user = new User();
user.setName("wangwu");
user.setPassword("123456");
user.setAge(34);
user.setTel("123456566");
userDao.insert(user);
}
@Test
void testDelete() {
userDao.deleteById(1L);
}
@Test
void testUpdate() {
User user = new User();
user.setId(1L);
user.setName("lisi");
user.setPassword("123456");
user.setAge(34);
user.setTel("123456566");
userDao.updateById(user);
}
}
1)MybatisPlus提供的查询分页
提供了一个接口
Ipage
设置分页拦截器作为Spring管理的Bean:
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
//1,定义MybatisPlus的拦截器
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//2. 添加具体的拦截器
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
- 分页查询:可以在Ipage的对象中获取到当前页面是第几页,每页显示的数量,总页数,所有数据以及当前页面的具体数据
@SpringBootTest
class Mybatisplus01QuickstartApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testPage() {
IPage page = new Page<>(1, 1);
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());
}
}
2)按条件查询
- MybatisPlus将书写复杂的SQL查询条件进行了封装,使用编程的形式完成查询条件的组合
@SpringBootTest
class Mybatisplus01QuickstartApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testSelectByCondition() {
//方式一:
QueryWrapper<User> qw = new QueryWrapper<>();
qw.lt("age", 50);
List<User> userList = userDao.selectList(qw);
System.out.println(userList);
//方式二:lambda格式的条件查询
QueryWrapper<User> qw1 = new QueryWrapper<>();
qw1.lambda().lt(User::getAge, 20);
List<User> userList1 = userDao.selectList(qw1);
System.out.println(userList1);
//方式三:lambda的api格式
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
lqw.gt(User::getAge, 20);
List<User> userList2 = userDao.selectList(lqw);
System.out.println(userList2);
}
}
- 多条件:
查询age在20到30之间的数据:
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
lqw.gt(User::getAge, 20).lt(User::getAge, 30);
List<User> userList2 = userDao.selectList(lqw);
System.out.println(userList2);
查询age大于30或者小于20的数据:
LambdaQueryWrapper<User> lqw1 = new LambdaQueryWrapper<>();
lqw.gt(User::getAge, 30).or().lt(User::getAge, 20);
List<User> userList3 = userDao.selectList(lqw1);
System.out.println(userList3);
3)null值处理
- 在进行范围匹配查询时,我们通常是通过接收用户选定的两个范围值来确定范围
- 但是如果用户只选了一侧的范围值的话,另一侧就会以null的形式传递过来
- 我们通常是通过if判断该值是否为空,从而看是否追加该侧的条件:
- 这里MybatisPlus提供了更为简洁的方式:
在传递条件前,设立一个条件,如果满足条件为true,才连接当前查询条件,否则不连接该条件
@SpringBootTest
class Mybatisplus01QuickstartApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testSelectByCondition() {
UserQuery uq = new UserQuery();
//模拟页面传递过来的查询数据
uq.setAge(20); //条件1
// uq.setAge2(30); //条件2
LambdaQueryWrapper<User> lqw2 = new LambdaQueryWrapper<>();
lqw2.gt(null != uq.getAge2(), User::getAge, uq.getAge2());
lqw2.lt(null != uq.getAge(),User::getAge, uq.getAge());
List<User> userList4 = userDao.selectList(lqw2);
System.out.println(userList4);o.selectList(lqw);
System.out.println(userList2);
}
}
4)查询投影
- 查询结果包含模型类中部分属性:
@SpringBootTest
class Mybatisplus01QuickstartApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testSelectByWrapper() {
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
lqw.select(User::getId, User::getName, User::getAge);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
}
}
- 查询结果包含模型中未定义的属性:
@SpringBootTest
class Mybatisplus01QuickstartApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testSelectByWrapper2() {
QueryWrapper<User> qw = new QueryWrapper<>();
qw.select("count(*) as count, tel");
qw.groupBy("tel");
List<Map<String, Object>> mapList = userDao.selectMaps(qw);
System.out.println(mapList);
}
}
5)其他条件查询
- 等匹配:
eq()
- 以及其他:
lt() le() gt() between()
@SpringBootTest
class Mybatisplus01QuickstartApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testLogin() {
QueryWrapper<User> qw = new QueryWrapper<>();
qw.eq("name", "黑马程序员").eq("password", "itheima");
User user = userDao.selectOne(qw);
System.out.println(user);
}
}
6)字段映射与表名映射
- 数据库表字段与编码时的属性设计不同:
- 2.编码时添加了数据库中未定义的属性:
采用默认查询开放了更多字段的查看权限:
表名与实体类名不一致:
4.id生成策略控制
1)id生成
- 不同的表应用时需要不同的id生成策略:
- 注解:
@TableId
:
AUTO(0)
:使用数据库id自增策略控制id生成NONE(1)
:不设置id生成策略INPUT(2)
:用户手工输入id(不能为null)ASSIGN_ID(3)
:雪花算法生成id(可兼容数值型与字符串型)ASSIGN_UUID(4)
:以UUID生成算法作为id生成策略
2)全局设置
- 每个实体类上都需要配置
@TableId
- 数据库中表名一般有前缀:比如
tb_xxx
,每个表都需要加入@TableName("tb_xxx")
- 为了简化:直接在全局进行配置:
mybatis-plus:
global-config:
banner: false
db-config:
#全局配置表的id生成策略为:雪花算法生成策略
id-type: assign_id
#设置全表的前缀拼接“tb_"
table-prefix: tb_
- 原本需要在表的实体类
User
上加@TableName("tb_user")
,在全局配置中加上表的前缀之后,就可以去除注解,直接匹配
5.多记录操作
- 按多个id进行删除:
deleteBatchIds()
传入id数组 - 按多个id进行查询:
selectBatchIds()
6.逻辑删除
@TableLogic
:逻辑删除字段,标记当前记录是否被删除正常数据删除时,对应的关联数据也会进行删除
但是对应总的订单数等业务统计数据,删除数据会对业务造成损失,业务数据从数据库中丢弃
逻辑删除:为数据设置是否可用状态字段,删除时设置状态字段为不可用状态,数据保留在数据库中
比如:当员工张业绩离职时,需要删除他对应的信息,那么他关联的销售业绩也需要对应删除
- 但是当统计总的销售金额时,数据被删除就无法统计出真正的销售总额
逻辑删除配置流程
1.在对应表中新增字段
deleted
默认值为0
2.配置该字段为逻辑删除字段
- 方式一:
@TableLogic(value = "0", deval = "1")
,标记删除为1,没有删除则为0
- 方式一:
@Data
public class User {
//根据雪花算法生成Id
//当未传入id时,会自动根据雪花算法生成Id
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String name;
private String password;
private Integer age;
private String tel;
@TableLogic(value = "0", delval = "1")
private Integer deleted;
}
* 方式二:全局配置:
mybatis-plus:
global-config:
banner: false
db-config:
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
- 3.编写测试代码:
@SpringBootTest
class Mybatisplus01QuickstartApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testDeleted() {
userDao.deleteById(1963561718751342594L);
}
}
- mybatisplus中执行的其实是update语句:
7. mybatis乐观锁设置
- 1.添加锁标记字段:默认为1
- 2.实体类添加对应字段,并设定当前字段为版本更新字段
@Version
:
@Data
public class User {
//根据雪花算法生成Id
//当未传入id时,会自动根据雪花算法生成Id
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String name;
private String password;
private Integer age;
private String tel;
private Integer deleted;
@Version
private Integer version;
}
- 3.配置乐观锁拦截器,实现锁机制对应的动态SQL拼装:也就是在执行更新SQL之前拼接version字段的条件:
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
//1,定义Mybatis的拦截器
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//2. 添加分页查询的拦截器
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
//3. 添加乐观锁拦截器
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
- 4.使用乐观锁机制在修改前必须先获取到对应数据的version方可正常进行:
@SpringBootTest
class Mybatisplus01QuickstartApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testOptimisticLock() {
//先查询数据,获取到version数据
User user = userDao.selectById(1963562661970673666L);
//执行数据修改操作
user.setName("Tom999");
userDao.updateById(user);
}
}
- 执行时会根据获取的version去查对应的数据,然后操作完之后将version+ 1
乐观锁实现机制
- 首先模拟了a和b并发去获取同一条数据的情况:
@SpringBootTest
class Mybatisplus01QuickstartApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testOptimisticLock() {
//a 和 b同时修改同一条数据
User user_a = userDao.selectById(1963577811377319938L); //version == 2
User user_b = userDao.selectById(1963577811377319938L); //version == 2
//a先执行数据修改操作
user_a.setName("lisi"); //version == 2
userDao.updateById(user_a); //version => 3
//b再修改
user_b.setName("zhaoliu"); //此时已经找不到version为2的数据了
userDao.updateById(user_b);
}
}
- 当a和b获取到同一条数据后,他们此时的version都是为2,而当a先提交之后,通过拦截器会先根据version = 2查询到当前记录并动态拼接SQL将当前记录的version修改为3
- 而当b再提交时,拦截器通过version = 2已经查不到对应的数据了,就无法进行修改
- 这样就避免了并发下,两个操作同时修改同一条记录的问题
8.代码生成器
1.添加依赖:
mybatis-plus-generator
MybatisPlus关于代码生成器的依赖以及velocity-engine-core
生成代码的核心引擎:
2.创建生成器:
1)数据源的指定:
package com.itheima;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
public class Generator {
public static void main(String[] args) {
AutoGenerator autoGenerator = new AutoGenerator();
DataSourceConfig dataSource = new DataSourceConfig();
dataSource.setDriverName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC");
dataSource.setUsername("root");
dataSource.setPassword("root");
autoGenerator.setDataSource(dataSource);
autoGenerator.execute();
}
}
- 2)全局配置的指定:指定生成的文件路径,包名,是否覆盖等
- 3)包相关配置指定:每个包对应的名称
- 4)策略相关配置指定:指定需要生成的表,设置逻辑删除字段,乐观锁字段等
*注:上述内容来自B站黑马程序员视频的学习截图,仅作为学习交流,不用作商业用途,如有侵权,联系删除。