SpringBoot&MyBatisPlus
5. SpringBoot
- 学习目标:
- 掌握基于SpringBoot框架的程序开发步骤
- 熟练使用SpringBoot配置信息修改服务器配置
- 基于SpringBoot完成SSM整合项目开发
5.1 入门案例
SpringBoot是由Pivotal团队提供的全新框架,其设计目的是用来简化Spring应用的初始搭建以及开发过程
原生开发SpringSSM程序过程
- 创建工程,在pom中配对应的依赖
- 添加Spring、MyBatis、SpringMVC的相关配置类
- 添加Controller类、Service类、Dao
实现步骤:
创建工程
编写controller
运行Application
最简SpringBoot程序所包含的基础文件
pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version> 2.7.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent> <groupId>com.mark</groupId>
<artifactId>SpringBoot_01_QuickStart</artifactId>
<version>0.0.1-SNAPSHOT</version> <properties>
<java.version>11</java.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>Application类
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Spring程序与SpringBoot程序对比
基于idea开发SpringBoot程序需要确保联网且能够加载到程序框架
5.2 SpringBoot工程官网创建方式
5.3 SpringBoot项目快速启动
对SpringBoot项目打包(执行Maven构建指令package)
执行启动指令
java -jar springboot.jar
注意事项:
jar支持命令行启动需要依赖maven插件支持,需要确认在打包时是否具有SpringBoot对应的maven插件
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.3</version>
</plugin>
</plugins>
</build>
5.4 SpringBoot概述
SpringBoot是由Pivotal团队提供的全新框架,其设计目的是用来简化Spring应用的初始搭建以及开发过程
Spring程序缺点
- 配置繁琐
- 依赖设置繁琐
SpringBoot程序优点
- 自动配置
- 起步依赖(简化依赖配置)
- 辅助功能(内置服务器,...)
起步依赖帮助我们实现了快速配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.3</version>
</parent>
<groupId>com.mark</groupId>
<artifactId>SpringBoot_01_QuickStart</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<!--起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
- starter
- SpringBoot中常见项目名称,定义了当前项目使用的所有项目坐标,以达到减少依赖配置的目的
- partent
- 所有SpringBoot项目要继承的项目,定义了若干个坐标版本号(依赖管理,而非依赖),以达到减少冲突的目的
- spring-boot-starter-parent(2.5.0)与spring-boot-starter-parent(2.4.6)共计57处坐标版本不同
- starter
实际开发
- 使用任意坐标时,仅书写VGA中的G和A,V由SpringBoot提供
- 如发生坐标错误,再指定version(要小心版本冲突)
SpringBoot启动
启动方式
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Spring在创建项目时,采用jar的打包方式
SpringBoot的引导类是项目的入口,运行main方法就可以启动
5.5 Spring辅助功能:切换web服务器
使用jetty替换tomcat:使用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>
</dependency>
Jetty比Tomcat更轻量级,可扩展性更强(相较于Tomcat),谷歌搜索引擎(GAE)已经全面切换为Jetty
5.6 配置文件格式
修改服务器端口
http://localhost:8080/books/1
修改为80端口号:
http://localjost/books/1
SpringBoot提供了多种属性配置方式
application.properties中修改
在resources下的application.properties添加
server.port=80
application.yml中修改
在resources下新建application.yml文件,添加
server:port:80
application.ymal中修改
在resources下新建application.yaml文件,添加
server:port:80
注意:
- 在之后主要在application.yml中修改配置
- 如果三个文件都存在,properties为第一配置文件,yml为第二配置文件,yaml为第三配置文件。即如果三个文件有相同的配置,优先级为properties->yml->yaml
5.7 yaml格式
YAML(YAML Ain't Markup Language):一种数据序列化格式
优点:
- 容易阅读
- 容易与脚本语言交互
- 以数据为核心,重数据轻格式
YAML文件扩展名
- .yml(主流)
- .yaml
yaml语法规则
大小写敏感
属性层级关系使用多行描述,每行结尾使用冒号结束
使用缩进表示层级关系,同层级左侧对齐,只允许使用空格(不允许使用Tb键)
属性值前面添加空格(属性名与属性值之间使用冒号+空格作为分隔)
#表示注释
数组数据在书写位置的下方使用减号作为数据的开始,每行书写一个数据,减号与数据间空格分隔
yaml数据读取的方式
数据如下:
lesson: SpringBoot server:
port: 80 person:
name: mark
age: 21
tel: 123456789
likes:
- Java
- Game
- Music logging:
level:
root: info
方式一:使用@value注解读取单个数据。引用方式:${一级属性名.二级属性名}
@RestController
@RequestMapping("/books")
public class BookController {
@Value("${lesson}")
private String lesson;
@Value("${server.port}")
private Integer port;
@Value("${person.likes[0]}")
private String likes_00; @GetMapping("/{id}")
public String getById(@PathVariable Integer id) {
System.out.println(lesson);
System.out.println(port);
System.out.println(likes_00);
return "hello Spring Boot";
}
}
方式二:使用Environment对象加载所有环境信息并封装(一般在框架内部使用)
@RestController
@RequestMapping("/books")
public class BookController {
//加载所有的环境信息
@Autowired
private Environment environment; @GetMapping("/{id}")
public String getById(@PathVariable Integer id) {
System.out.println(environment.getProperty("lesson"));
System.out.println(environment.getProperty("server.port"));
System.out.println(environment.getProperty("person.likes[0]"));
return "hello Spring Boot";
}
}
方式三:自定义对象封装指定数据(常用)
定义实体类,添加注解
@Component
和@ConfigurationProperties
@Getter
@Setter
@ToString
//1.将其定义成一个bean使之能受Spring控制
@Component
//2.读取配置中的属性person
@ConfigurationProperties(prefix = "person")
public class Person {
private String name;
private Integer age;
private String tel;
private String[] likes;
}
使用时自动装配即可
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private Person person; @GetMapping("/{id}")
public String getById(@PathVariable Integer id) {
System.out.println(person);
return "hello Spring Boot";
}
}
自定义对象封装数据警告解决方案:添加以下依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
5.8 多环境开发配置
yaml、yml配置方式:
#设置启用的环境
spring:
profiles:
active: dev
---
#开发
spring:
profiles: dev
server:
port: 80
---
#生产
spring:
profiles: pro
server:
port: 81
---
#测试
spring:
profiles: test
server:
port: 82
上述是过时写法,以下为不过时写法
#设置启用的环境
spring:
profiles:
active: dev
---
spring:
config:
activate:
on-profile: dev
server:
port: 82
properties配置方式:(了解即可)
在主启动配置文件application.properties中添加
#设置启用的环境
spring.profiles.active=dev
新建分类配置文件application-dev.properties添加环境配置
server.port=80
同理新建application-pro.properties、application-test.properties添加环境配置
server.port=81
server.port=82
多环境启动命令格式
因为有中文,所以先设置编码
在打包前首先执行clean,然后package打包。避免影响结果
cmd执行:带参数启动SpringBoot
java -jar SpringBoot_04_profile-0.0.1-SNAPSHOT.jar --spring.profiles.active=test
即在测试环境下运行
使用临时参数启动SpringBoot
java -jar SpringBoot_04_profile-0.0.1-SNAPSHOT.jar --spring.profiles.active=test --server.port=88
参数加载优先级:
- 参考https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config
多环境开发兼容问题(Maven与Boot)
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>
Boot的yml中设置生产环境
#设置启用的环境
spring:
profiles:
active: ${profile.active} ---
#开发
spring:
profiles: dev
server:
port: 80 ---
#生产
spring:
profiles: pro
server:
port: 81 ---
#测试
spring:
profiles: test
server:
port: 82
打包运行发现端口号是8080
解决:
添加插件
<!--对资源文件进行解析-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<encoding>UTF-8</encoding>
<useDefaultDelimiters>true</useDefaultDelimiters>
</configuration>
</plugin>
5.9 配置文件分类
- SpringBoot中4级配置文件
- 1级:file: config/application.yml ----最高
- 2级:file: application.yml
- 3级:classpath: config./application.yml
- 4级:classpath: application.yml ----最低
- 作用:
- 1级与2级留做系统打包后设置通用属性(在资源管理器target目录下创建yml)
- 3级与4级用于系统开发阶段设置通用属性(在IDEA的resources包下创建)
5.10 SpringBoot整合junit
Spring整合Junit
//设置运行器
@RunWith(SpringJUnit4ClassRunner.class)
//加载环境
@ContextConfiguration(classes = SpringConfig.class)
public class BookServiceTest {
@Autowired
private BookService bookService;
@Test
public void testGetById() {
Book book = bookService.getById(2);
System.out.println(book);
}
}
书写一个Service接口和实现类,直接在TestApplication中测试即可
@SpringBootTest
class SpringBoot07TestApplicationTests {
@Autowired
private BookService bookService;
@Test
void contextLoads() {
bookService.save();
}
}
5.11 SpringBoot整合SSM
SpringBoot整合Spring(不存在)
SpringBoot整合SpringMVC(不存在)
SpringBoot整合MyBatis(主要、唯一)
创建工程,在创建模块时添加MyBatis和MySQL
书写实体类(pojo)和dao接口
在dao接口上添加注解@Mapper
修改配置文件,设置数据源参数
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql:///ssm_db
username: root
password: 123
如果使用的SpringBoot版本低于2.4.3(不含),MySQL驱动版本大于8.0时,需要在url连接串中配置时区,或在MySQL数据库端配置时区解决此问题
url: jdbc:mysql:///ssm_db?serverTimezone=UTC
现在就可以运行啦
如何使用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:///ssm_db
username: root
password: 123
type: com.alibaba.druid.pool.DruidDataSource
5.12 基于SpringBoot的整合SSM案例
pom.xml
配置起步依赖,必要的资源坐标(druid)
application.yml
设置数据源、端口等
#TODO 配置数据源相关信息
server:
port: 80 spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/ssm_db
username: root
password: 123
配置类
全部删除
dao
设置@Mapper
测试类
页面
将静态页面放在resources下的static目录下
可以在static下创建index.html主页,这样不用输入地址即可进入
<script>
document.location.href="pages/books.html"
</script>
6. MyBatisPlus
6.1 入门案例
MyBatisPlus(简称MP)是基于MyBatis框架基础上的增强型工具,旨在简化开发、提高效率
SpringBoot整合MyBatis开发过程
- 创建SpringBoot工程
- 勾选配置使用的技术
- 设置dataSource相关属性(JDBC参数)
- 定义数据层接口映射配置
基于SpringBoot使用MyBatisPlus
创建工程,勾选MySQL
手动添加MyBatisPlus、Druid依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency> <dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.11</version>
</dependency>
配置数据源
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/ssm_db
username: root
password: 123
创建domain下的实体类User
@Getter
@Setter
@ToString
public class User {
private Long id;
private String name;
private String password;
private Integer age;
private String tel;
}
创建dao下的接口UserDao继承BeanMapper,添加泛型为User
@Mapper
public interface UserDao extends BaseMapper<User> {
}
接下里就可以测试了
@SpringBootTest
class MyBatisPlus01QuickStartApplicationTests {
@Autowired
private UserDao userDao; @Test
void testGetAll() {
List<User> list = userDao.selectList(null);
System.out.println(list);
}
}
6.2 MyBatisPlus简介
MyBatisPlus(简称MP)是基于MyBatis框架基础上的增强型工具,旨在简化开发、提高效率
MyBatisPlus特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 强大的 CRUD 操作:内置通用 Mapper、少量配置即可实现单表大部分 CRUD 操作
- 支持 Lambda 形式调用:编写各类查询条件,无需再担心字段写错
- 支持主键自动生成
- 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
6.3 标准数据层CRUD功能
@SpringBootTest
class MyBatisPlus01QuickStartApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testSave(){
User user = new User();
user.setName("王昭君");
user.setPassword("123");
user.setAge(12);
user.setTel("123456888");
userDao.insert(user);
}
@Test
void testDelete(){
userDao.deleteById(1567537461138120705L);
}
@Test
void testUpdate(){
User user = new User();
user.setId(1L);
user.setName("Tom666");
//提供哪些字段,修改哪些字段
userDao.updateById(user);
}
@Test
void testById(){
User user = userDao.selectById(2L);
System.out.println(user);
}
@Test
void testGetAll() {
List<User> list = userDao.selectList(null);
System.out.println(list);
}
}
6.4 标准分页功能制作
@Test
void testGetByPage(){
//1:查第一页 2:一页有多少条数据
IPage page =new Page(1,2);
userDao.selectPage(page,null);
System.out.println("当前页码值:"+page.getCurrent());
System.out.println("当前页有:"+page.getSize()+"条");
System.out.println("一共有:"+page.getPages()+"页");
System.out.println("一共有:"+page.getTotal()+"条数据");
System.out.println("数据:"+page.getRecords());
//此时查数据发现查不出有多少页多少数据且数据为全部数据
//这就需要配置PM的分页拦截器
}
此时查数据发现查不出有多少页多少数据且数据为全部数据
这就需要配置PM的分页拦截器
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mPlusInterceptor(){
//1.定义MP的拦截器
MybatisPlusInterceptor mybatisPlusInterceptor =new MybatisPlusInterceptor();
//2.在MP的拦截器添加具体的拦截器
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
}
结果如下:
当前页码值:1
当前页有:2条
一共有:3页
一共有:5条数据
数据:[User(id=1, name=Tom666, password=tom, age=13, tel=18888888888), User(id=2, name=Jerry, password=jerry, age=12, tel=13999999999)]
可以在yml配置中开启日志
# 开启MP的日志(输出到控制台)
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
6.5 条件查询
MP将书写复杂的SQL查询条件进行了封装,使用编程的形式完成查询条件的组合
由于输出日志太多,因此可以配置一个logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
</configuration>
还可以清除MP和Spring的LOGO:在yml中配置banner
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatisplus_db
username: root
password: 123
main:
banner-mode: off
mybatis-plus:
global-config:
banner: false
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
这样输出结果就会很清爽
方式一:
@Test
void testGetAll() {
//按条件查询方式一:
QueryWrapper wrapper = new QueryWrapper();
//<:小于 >:大于
wrapper.lt("age",18);
List<User> userList = userDao.selectList(wrapper);
System.out.println(userList);
}
方式二:
//按条件查询方式二:
QueryWrapper<User> wrapper = new QueryWrapper<User>();
wrapper.lambda().lt(User::getAge,18);
List<User> userList = userDao.selectList(wrapper);
System.out.println(userList);
方式三(推荐):
//按条件查询方式三:
LambdaQueryWrapper<User> lambdaQueryWrapper =new LambdaQueryWrapper<User>();
lambdaQueryWrapper.lt(User::getAge,10);
List<User> userList = userDao.selectList(lambdaQueryWrapper);
System.out.println(userList);
//方式三添加多个条件
LambdaQueryWrapper<User> lambdaQueryWrapper =new LambdaQueryWrapper<User>();
//lambdaQueryWrapper.lt(User::getAge,18);
//lambdaQueryWrapper.gt(User::getAge,12);
//12到18之间
//lambdaQueryWrapper.lt(User::getAge,18).gt(User::getAge,12);
//小于12或大于18
lambdaQueryWrapper.lt(User::getAge,12).or().gt(User::getAge,18);
List<User> userList = userDao.selectList(lambdaQueryWrapper);
System.out.println(userList);
6.6 条件查询—null值处理
//模拟页面传递过来的查询数据
UserQuery userQuery = new UserQuery();
//userQuery.setAge(10);
userQuery.setAge2(30);
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<User>();
//先判定第一个参数是否为true,如果为true,如果为true连接当前条件
lambdaQueryWrapper.lt(null != userQuery.getAge2(),User::getAge,userQuery.getAge2());
lambdaQueryWrapper.gt(null != userQuery.getAge(),User::getAge,userQuery.getAge());
List<User> userList = userDao.selectList(lambdaQueryWrapper);
System.out.println(userList);
6.7 查询投影(查询的字段控制)
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<User>();
//该格式只适用于lambda表达式
lambdaQueryWrapper.select(User::getId, User::getName,User::getAge);
List<User> userList = userDao.selectList(lambdaQueryWrapper);
System.out.println(userList);
/*结果:
Preparing: SELECT id,name,age FROM user
==> Parameters:
<== Columns: id, name, age
<== Row: 1, Tom666, 13
<== Row: 2, Jerry, 12
<== Row: 3, Mark, 21
<== Row: 4, 诸葛亮, 15
<== Row: 1567537209630830593, 王昭君, 12
<== Total: 5
*/
非lambda表达式写法:
QueryWrapper<User> lambdaQuery = new QueryWrapper<User>();
lambdaQuery.select("id","name","age");
List<User> userList = userDao.selectList(lambdaQuery);
System.out.println(userList);
查询总数
QueryWrapper<User> lambdaQuery = new QueryWrapper<User>();
lambdaQuery.select("count(*) as count");
List<Map<String, Object>> userMaps = userDao.selectMaps(lambdaQuery);
System.out.println(userMaps);
/*结果:
==> Preparing: SELECT count(*) FROM user
==> Parameters:
<== Columns: count(*)
<== Row: 5
<== Total: 1
*/
分组统计
QueryWrapper<User> lambdaQuery = new QueryWrapper<User>();
//根据电话分组,查询个数
lambdaQuery.select("count(*) as count,tel");
lambdaQuery.groupBy("tel");
List<Map<String, Object>> userMaps = userDao.selectMaps(lambdaQuery);
System.out.println(userMaps);
6.8 查询条件
范围匹配(>、=、between)
模糊匹配(like)
空判定(null)
包含性匹配(in)
分组(group)
排序(order)
用户登录
LambdaQueryWrapper<User> lambdaQuery = new LambdaQueryWrapper<>();
//等同于"="(equal)
lambdaQuery.eq(User::getName, "Jerry").eq(User::getPassword, "jerry");
User user = userDao.selectOne(lambdaQuery);
System.out.println(user);
购物设定价格区间、户籍设定年龄区间
LambdaQueryWrapper<User> lambdaQuery = new LambdaQueryWrapper<>();
//范围查询 lt le gt ge between
//方式二
//lambdaQuery.le(User::getAge,30).ge(User::getAge,10);
//方式二
lambdaQuery.between(User::getAge,10,30);
List<User> list = userDao.selectList(lambdaQuery);
System.out.println(list);
查信息,搜索新闻(非全文检索版:like匹配)
LambdaQueryWrapper<User> lambdaQuery = new LambdaQueryWrapper<>();
//模糊匹配 Right和Left代表百分号的位置
lambdaQuery.likeRight(User::getName,"M");
List<User> list = userDao.selectList(lambdaQuery);
System.out.println(list);
统计报表(分组查询聚合函数)
QueryWrapper<User> lambdaQuery = new QueryWrapper<User>();
lambdaQuery.select("count(*) as count");
List<Map<String, Object>> userMaps = userDao.selectMaps(lambdaQuery);
System.out.println(userMaps);
更多条件查询查看http://mybatis.plus/guide/wrapper.html#abstractwrapper
6.9 映射匹配兼容性
问题一:表字段与编码属性设计不同步
@Data
public class User {
@TableField(value = "pwd");
private String password;
}
问题二:编码中添加了数据库中未定义的属性
@Data
public class User {
private Long id;
private String name;
private String password;
private Integer age;
private String tel;
@TableField(exist = false)
private boolean online;
}
问题三:采用默认查询开放了更多字段的查看权限
@Data
public class User {
@TableField(value = "pwd",select = false);
private String password;
}
问题四:表名与编码开发设计不同步
@TableName("tbl_user")
@Data
public class User {
private Long id;
private String name;
private String password;
private Integer age;
private String tel;
}
6.10 id生成策略
不同的表应用不同的id生成策略
- 日志:自增(1,2,3,4,…)
- 购物订单:特殊规则(F023948AK3843)
- 外卖单:关联地区日期等信息(1004202003143491)
- 关系表:可省略id
- ...
注解:@TableId
范例:
@TableName("tbl_user")
@Data
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
}
- 相关属性:
- value:设置数据库主键名称
- type:设置主键属性的生成策略,值参照IdType枚举值
- AUT0(0):使用数据库id自增策略控制id生成
- NONE(1):不设置id生成策略
- INPUT(2):用户手工输入id
- ASSIGN ID(3):雪花算法生成id(可兼容数值型与字符串型)
- ASSIGN UUID(4):以UUID生成算法作为id生成策略
- 相关属性:
6.11 多数据操作(删除与查询)
@Test
void testDelete(){
List<Long> list = new ArrayList<>();
list.add(1567537209630830593L);
list.add(1568108502637993985L);
userDao.deleteBatchIds(list);
}
@Test
void testSelectPro(){
List<Long> list = new ArrayList<>();
list.add(1L);
list.add(3L);
list.add(4L);
userDao.selectBatchIds(list);
}
6.12 逻辑删除
删除操作业务问题:业务数据从数据库张丢弃
逻辑删除:为数据设置是否可用状态字段,删除时设置状态字段为不可用状态,数据保留在数据库中
在数据库表中新增字段delete,类型为int,长度为1,默认值为0
@TableLogic(value="0",deval = "1")
在User类标注后,执行delete不会删除该条数据但是查询无法查到
还可以在通用配置添加逻辑删除字段
mybatis-plus:
global-config:
banner: false
db-config:
#逻辑删除字段
logic-delete-field: deleted
#删除
logic-delete-value: 1
#没有被删除
logic-not-delete-value: 0
6.13 乐观锁
业务并发现象带来的问题:秒杀
在数据库表中新增字段version,类型为int,长度为int最大长度11,默认值为1
在User对象中添加属性version,添加注解@Version
添加拦截器
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mPlusInterceptor(){
//添加乐观锁
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return mybatisPlusInterceptor;
}
}
6.14 代码生成器
模板:MP提供
数据库相关配置:读取数据库获取信息
开发者自定义配置:手工配置
使用步骤:
添加坐标
<!--代码生成器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency> <!--velocity模板引擎-->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
代码生成器类Generator
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:///mybatisplus_db?serverTimezone=UTC");
dataSource.setUsername("root");
dataSource.setPassword("123");
autoGenerator.setDataSource(dataSource);
autoGenerator.execute(); //设置全局配置
GlobalConfig globalConfig = new GlobalConfig();
//设置代码生成位置
globalConfig.setOutputDir(System.getProperty("user.dir") + "/MyBatisPlus_04_generator/src/main/java");
//设置生成完毕后是否打开生成代码所在的目录
globalConfig.setOpen(false);
//设置作者
globalConfig.setAuthor("Mark");
//设置是否覆盖原始生成的文件
globalConfig.setFileOverride(true);
//设置数据层接口名,%s为占位符,指代模块名称
globalConfig.setMapperName("%sDao");
//设置Id生成策略
globalConfig.setIdType(IdType.ASSIGN_ID);
autoGenerator.setGlobalConfig(globalConfig); //设置包名相关配置
PackageConfig packageInfo = new PackageConfig();
//设置生成的包名,与代码所在位置不冲突,二者叠加组成完整路径
packageInfo.setParent("com.aaa");
//设置实体类包名
packageInfo.setEntity("domain");
//设置数据层包名
packageInfo.setMapper("dao");
autoGenerator.setPackageInfo(packageInfo); //策略设置
StrategyConfig strategyConfig = new StrategyConfig();
//设置当前参与生成的表名,参数为可变参数
strategyConfig.setInclude("tbl_user");
//设置数据库表的前缀名称,模块名 = 数据库表名 - 前缀名 例如: User = tbl_user - tbl_
strategyConfig.setTablePrefix("tbl_");
//设置是否启用Rest风格
strategyConfig.setRestControllerStyle(true);
//设置乐观锁字段名
strategyConfig.setVersionFieldName("version");
//设置逻辑删除字段名
strategyConfig.setLogicDeleteFieldName("deleted");
//设置是否启用lombok
strategyConfig.setEntityLombokModel(true);
autoGenerator.setStrategy(strategyConfig);
//2.执行生成操作
autoGenerator.execute();
}
}
代码生成器模板
- 添加坐标
<dependencies>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<optional>false</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
- 添加数据库配置和生成代码的位置
dataSource.url=jdbc:mysql://123.456.789.000/tableName?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false
dataSource.driverName=com.mysql.cj.jdbc.Driver
dataSource.username=root
dataSource.password=9999
package.base=com.mark.mall.modules
- MyBatisPlusGenerator类
public class MyBatisPlusGenerator { public static void main(String[] args) {
String projectPath = System.getProperty("user.dir") + "/tuling-mpbg";
String moduleName = scanner("模块名");
String[] tableNames = scanner("表名,多个英文逗号分割").split(",");
// 代码生成器
AutoGenerator autoGenerator = new AutoGenerator();
autoGenerator.setGlobalConfig(initGlobalConfig(projectPath));
autoGenerator.setDataSource(initDataSourceConfig());
autoGenerator.setPackageInfo(initPackageConfig(moduleName));
autoGenerator.setCfg(initInjectionConfig(projectPath, moduleName));
autoGenerator.setTemplate(initTemplateConfig()); //
autoGenerator.setStrategy(initStrategyConfig(tableNames));
autoGenerator.setTemplateEngine(new VelocityTemplateEngine());
autoGenerator.execute();
} /**
* 读取控制台内容信息
*/
private static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
System.out.println(("请输入" + tip + ":"));
if (scanner.hasNext()) {
String next = scanner.next();
if (StrUtil.isNotEmpty(next)) {
return next;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "!");
} /**
* 初始化全局配置
*/
private static GlobalConfig initGlobalConfig(String projectPath) {
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setOutputDir(projectPath + "/src/main/java");
globalConfig.setAuthor("XuShu");
globalConfig.setOpen(false);
globalConfig.setSwagger2(true);
globalConfig.setBaseResultMap(true);
globalConfig.setFileOverride(true);
globalConfig.setDateType(DateType.ONLY_DATE);
globalConfig.setEntityName("%s");
globalConfig.setMapperName("%sMapper");
globalConfig.setXmlName("%sMapper");
globalConfig.setServiceName("%sService");
globalConfig.setServiceImplName("%sServiceImpl");
globalConfig.setControllerName("%sController");
return globalConfig;
} /**
* 初始化数据源配置
*/
private static DataSourceConfig initDataSourceConfig() {
Props props = new Props("generator.properties");
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setUrl(props.getStr("dataSource.url"));
dataSourceConfig.setDriverName(props.getStr("dataSource.driverName"));
dataSourceConfig.setUsername(props.getStr("dataSource.username"));
dataSourceConfig.setPassword(props.getStr("dataSource.password"));
return dataSourceConfig;
} /**
* 初始化包配置
*/
private static PackageConfig initPackageConfig(String moduleName) {
Props props = new Props("generator.properties");
PackageConfig packageConfig = new PackageConfig();
packageConfig.setModuleName(moduleName);
packageConfig.setParent(props.getStr("package.base"));
packageConfig.setEntity("model");
return packageConfig;
} /**
* 初始化模板配置
*/
private static TemplateConfig initTemplateConfig() {
TemplateConfig templateConfig = new TemplateConfig();
//可以对controller、service、entity模板进行配置
//mapper.xml模板需单独配置
templateConfig.setXml(null);
return templateConfig;
} /**
* 初始化策略配置
*/
private static StrategyConfig initStrategyConfig(String[] tableNames) {
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setNaming(NamingStrategy.underline_to_camel);
strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
strategyConfig.setEntityLombokModel(true);
strategyConfig.setRestControllerStyle(true);
//当表名中带*号时可以启用通配符模式
if (tableNames.length == 1 && tableNames[0].contains("*")) {
String[] likeStr = tableNames[0].split("_");
String likePrefix = likeStr[0] + "_";
strategyConfig.setLikeTable(new LikeTable(likePrefix));
} else {
strategyConfig.setInclude(tableNames);
}
return strategyConfig;
} /**
* 初始化自定义配置
*/
private static InjectionConfig initInjectionConfig(String projectPath, String moduleName) {
// 自定义配置
InjectionConfig injectionConfig = new InjectionConfig() {
@Override
public void initMap() {
// 可用于自定义属性
}
};
// 模板引擎是Velocity
String templatePath = "/templates/mapper.xml.vm";
// 自定义输出配置
List<FileOutConfig> focList = new ArrayList<>();
// 自定义配置会被优先输出
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
return projectPath + "/src/main/resources/mapper/" + moduleName
+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
injectionConfig.setFileOutConfigList(focList);
return injectionConfig;
}
}
SpringBoot&MyBatisPlus的更多相关文章
- spring-boot+mybatisPlus+shiro的集成demo 我用了5天
spring-boot + mybatis-plus + shiro 的集成demo我用了五天 关于shiro框架,我还是从飞机哪里听来的,就连小贱都知道,可我母鸡啊.简单百度了下,结论很好上手,比s ...
- IDEA上创建 Maven SpringBoot+mybatisplus+thymeleaf 项目
概述 在WEB领域,Java也是在不断的探索和改进,从开始的JSP--->Struts1--->Struts2+Spring--->Spring MVC--->SpringBo ...
- springboot+mybatisplus 测试代码生成
测试springboot + mybatisplus 实现代码生成 使用默认的模板引擎 pom.xml文件 <?xml version="1.0" encoding=&q ...
- 2、SpringBoot+MybatisPlus整合-------BaseCRUD
开发工具:STS 代码下载链接:GitHub管理代码 版本: Springboot:1.5.14.RELEASE 使用2.0以上的Springboot,会报出一些异常.欢迎知道异常原因的大牛解惑. M ...
- SpringBoot+MyBatisPlus整合时提示:Invalid bound statement(not found):**.dao.UserDao.queryById
场景 在使用SpringBoot+MyBatisPlus搭建后台启动项目时,使用EasyCode自动生成代码. 在访问后台接口时提示: Invilid bound statement (not fou ...
- springboot+mybatisplus+sharding-jdbc分库分表实例
项目实践 现在Java项目使用mybatis多一些,所以我也做了一个springboot+mybatisplus+sharding-jdbc分库分表项目例子分享给大家. 要是用的springboot+ ...
- springboot + mybatisPlus 入门实例 入门demo
springboot + mybatisPlus 入门实例 入门demo 使用mybatisPlus的优势 集成mybatisplus后,简单的CRUD就不用写了,如果没有特别的sql,就可以不用ma ...
- 关于写SpringBoot+Mybatisplus+Shiro项目的经验分享四:部署到阿里云
框架: SpringBoot+Mybatisplus+Shiro 简单介绍:关于写SpringBoot+Mybatisplus+Shiro项目的经验分享一:简单介绍 阿里云开放必要端口,mysql与t ...
- 关于写SpringBoot+Mybatisplus+Shiro项目的经验分享三:问题2
框架: SpringBoot+Mybatisplus+Shiro 简单介绍:关于写SpringBoot+Mybatisplus+Shiro项目的经验分享一:简单介绍 搜索框是该项目重要的一环,由于涉及 ...
- 关于写SpringBoot+Mybatisplus+Shiro项目的经验分享二:问题1
框架: SpringBoot+Mybatisplus+Shiro 简单介绍:关于写SpringBoot+Mybatisplus+Shiro项目的经验分享一:简单介绍 添加时,如果失败,不能正确跳转 c ...
随机推荐
- 【java】学习路径27-HashSet、TreeSet,HashMap
学习路径20-27的所有源代码都可以在此下载 https://www.aliyundrive.com/s/cg8jTRbg6vy HashSet.TreeSet中,Set表示集合,特性在于:无序的.不 ...
- ABAQUS和UG许可证冲突问题的解决方案
前段时间重新安装了ABAQUS,更新到了2020版本后,发现NX UG怎么突然打不开了,搜索一下,发现是两个许可证有冲突.找了很多解决方案,主要归纳为以下两种: 方法一:Lmtools修改法 先说结论 ...
- Html飞机大战(二):面向对象绘制背景
好家伙, 我们为了后续工作的顺利进行,我试着把每一个模块封装为对象 但冻手之前还是要构思一下 我们把天空封装成一个类: 1.来搞一手简单的对象分析: 属性方面的都好理解 来说明一下方法: (1) p ...
- KingbaseES V8R6集群同步模式synchronous参数配置详解
如下图所示: 集群数据同步原理说明: synchronous参数配置测试: 集群节点信息: ID | Name | Role | Status | Upstream | repmgrd | PID | ...
- 如何修改SAO用户密码
KingbaseES SAO 用户是专门用于审计管理的用户,用户配置审计策略需要使用该用户.在initdb 完成后,SAO 用户的默认密码保存在参数 sysaudit.audit_table_pas ...
- 解决element-ui中组件【el-upload】一次性上传多张图片的问题
element-ui 中的组件 el-upload默认的行为是一张图片请求一次,在项目需求中,通常是多张图片要求只向后台请求一次,下面的做法就是为了实现这样的需求 前端 <el-upload r ...
- 从代码到发包,一个程序全搞定!Gitea 推出软件包自托管功能 Package Registry
2022 年 7 月的最后一天,随着 Gitea 1.17.0 版本的正式发布,Gitea 开源社区推出了一项名为 Package Registry 的包管理功能,与 Gitea 代码仓库无缝集成,类 ...
- 放弃 Electron,拥抱 WebView2!JavaScript 快速开发独立 EXE 程序
Electron 不错,但也不是完美的. Electron 带来了很多优秀的桌面软件,但并不一定总是适合我们的需求. 多个选择总是好事! 我使用 Electron 遇到的一些麻烦 1.Electron ...
- 聊聊单点登录(SSO)中的CAS认证
SSO介绍 背景 随着企业的发展,一个大型系统里可能包含 n 多子系统, 用户在操作不同的系统时,需要多次登录,很麻烦,我们需要一种全新的登录方式来实现多系统应用群的登录,这就是单点登录. web 系 ...
- HCNP Routing&Switching之ARP安全
前文我们了解了IP安全相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/16652367.html:今天我们来聊一聊ARP安全相关话题: 什么是ARP? ...