一、简介
SpringBoot用来简化Spring应用的初始搭建和开发过程,
SpringBoot四大核心:
自动配置
起步依赖
Actuator
命令行界面
二、入门案例
1. 基于IDEA创建步骤
① 创建新模块,选择Spring Initializr,并配置模块相关基础信息
② 选择当前模块需要使用的技术集
③ 开发控制器类
④ 运行自动生成的Application类
2. 最简SpringBoot所包含的基础文件:
pom.xml 文件
Application 类
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
3. Spring 程序和 SpringBoot 对比
类/配置文件 | Spring | SpringBoot |
---|---|---|
pom文件中的坐标 | 手工添加 | 勾选添加 |
web.3.0配置类 | 手工制作 | 无 |
Spring/SpringMVC配置类 | 手工制作 | 无 |
控制器 | 手工制作 | 手工制作 |
4. 基于官网创建项目
① IDEA联网有问题时,可在官网创建项目
https://start.spring.io/
② 点击生成一个压缩文件
③ 解压并导入IDEA即可
5. 基于阿里云创建
https://start.aliyun.com/
6. 手工创建项目
① 创建普通Maven工程
② 手工导入坐标
<?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
http://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.5.4</version>
</parent>
<groupId>com.itheima</groupId>
<artifactId>springboot_01_03_quickstart</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
③ 手工制作引导类
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
7. 隐藏指定文件夹
8. 解析
(1) parent
(仅定义未使用)
所有SpringBoot项目要继承的项目,定义了
若干个坐标版本号(依赖管理,而非依赖),
以达到减少依赖冲突的目的
spring-boot-starter-parent各版本间存在着诸
多坐标版本不同
① 定义一系列的常用坐标版本
project-parent:pom.xml
< properties >< druid.version >1.1.16</ druid.version >< mybatis.version >3.5.6</ mybatis.version >< mysql.version >5.1.47</ mysql.version >< db2.version >1.2.3</ db2.version >< oracle.version >2.3.4</ oracle.version >< sybase.version >3.4.5</ sybase.version >< dbase.version >4.5.6</ dbase.version >< foxpro.version >5.6.7</ foxpro.version >< …….version >6.7.8</ …….version ></ properties >
② 定义一系列的常用坐标组合
project-dependencies:pom.xml
< dependency >< groupId >com.alibaba</ groupId >< artifactId >druid</ artifactId >< version >${druid.version}</ version ></ dependency >< dependency >< groupId >org.mybatis</ groupId >< artifactId >mybatis</ artifactId >< version >${mybatis.version}</ version ></ dependency >< dependency >< groupId >mysql</ groupId >< artifactId >mysql-connector-java</ artifactId >< version >${mysql.version}</ version ></ dependency >
③ 直接使用组合
project-a:pom.xml
< dependency >< groupId >example</ groupId >< artifactId >project-dependencies</ artifactId >< version >1.1.10</ version ></ dependency >
① 开发SpringBoot程序要继承spring-boot-starter-parent
② spring-boot-starter-parent中定义了若干个依赖管理
③ 继承parent模块可以避免多个依赖使用相同技术时出
现依赖版本冲突
④ 继承parent的形式也可以采用引入依赖的形式实现效果
<?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.5.4</version>
</parent>
<groupId>com.example</groupId>
<artifactId>springboot-01-quickstart</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
(2) starter
定义了当前项目使用的所有依赖坐标,以达到
减少依赖配置的目的
实际开发:
使用任意坐标时,仅书写GAV中的G和A,V由
SpringBoot提供,除非SpringBoot未提供对应
版本V
如发生坐标错误,再指定Version(小心版本冲突)
spring-boot-starter-web.pom
① 开发SpringBoot程序需要导入坐标时通常导入
对应的starter
② 每个不同的 starter 根据功能不同,通常包含多个依赖坐标③ 使用 starter 可以实现快速配置的效果,达到 简化配置的 目的
(3) 引导类
启动方式:
@SpringBootApplication
public class Springboot01QuickstartApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot01QuickstartApplication.class, args);
}
}
① SpringBoot 的引导类是 Boot 工程的 执行入口 ,运行 main 方法就可以启动项目② SpringBoot 工程运行后 初始化 Spring 容器, 扫描引导类所在包加载 bean
(4) 内嵌 tomcat
辅助功能:
使用maven依赖管理变更起步依赖项:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!--web起步依赖环境中,排除Tomcat起步依赖-->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--添加Jetty起步依赖,版本由SpringBoot的starter控制-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
</dependencies>
Jetty 比 Tomcat 更轻量级,可扩展性更强(相较于 Tomcat) ,谷歌应用引擎( GAE) 已经全面切换为 Jetty
tomcat(
默认
)
|
apache
出品,粉丝多,
应用面广
,
负载了若干较重的组件
|
jetty
|
更轻量级
,负载性能远不及
tomcat
|
undertow
|
undertow
,负载性能
勉强
跑赢
tomcat
|
① 内嵌 Tomcat 服务器是 SpringBoot 辅助功能之一② 内嵌 Tomcat 工作原理是将 Tomcat 服务器作为对象运行,并将该对象交给Spring容器管理③ 变更内嵌服务器思想是去除现有服务器,添加全新的服务器
9. REST 风格
① 设定 http 请求动作
@RequestMapping(value = "/users",method = RequestMethod.POST)
@ResponseBody
public String save(@RequestBody User user){
System.out.println("user save..." + user);
return "{'module':'user save'}";
}
@RequestMapping(value = "/users",method = RequestMethod.PUT)
@ResponseBody
public String update(@RequestBody User user){
System.out.println("user update..." + user);
return "{'module':'user update'}";
}
@RequestMapping 为方法注解,位于
SpringMVC 控制器方法定义上方,用于
设置当前控制器方法请求访问路径
属性:
value (默认):请求访问路径
method:http 请求动作,标准动作 (GET/
POST/PUUT/DELETE)
② 设定请求参数 (路径变量)
@RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE
)
@ResponseBody
public String delete(@PathVariable Integer id){
System.out.println("user delete..." + id);
return "{'module':'user delete'}";
}
@PathVariable 为形参注解,位于
SpringMVC 控制器方法形参定义上方,
用于绑定路径参数与处理器方法形参间
的关系,要求路径参数名与形参名一一
对应
其中 @RequestBody、@RequestParam、
@PathVariable 三者区别:
@RequestParam 用于接收 url 地址传参
或表单传参
@RequestBody 用于接收 json 数据
@PathVariable 用于接收路径参数,使用
(参数名称)描述路径参数
应用:
① 后期开发中,发送请求参数超过1个时,
以 json 格式为主,@RequestBody 应用
较广
② 如果发送非 json 格式数据,选用
@RequestParam 接收请求参数
③ 采用 RESTful 进行开发,当参数数量
较少时,例如1个,可以采用
@PathVariable 接收请求路径变量,通常
用于传递 id 值
RESTful 快速开发:
@RestController 类注解,基于 SpringMVC
的 RESTful 开发控制器类定义上方,用于设
置当前控制器类为 RESTful 风格,等同于
@Controller 与 @ResponseBody 两个注解
组合功能
@RestController
public class BookController{
}
@GetMapping、@PostMapping、
@PutMapping、@DeleteMapping 方法
注解,基于SpringMVC 的 RESTful 开发
控制器方法定义上方,用于设置当前控
制器方法请求访问路径与请求动作,每种
对应一个请求动作,例如 @GetMapping
对应 GET 请求
@GETMapping("/{id}")
public String getById(@PathVariable Integer id){
System.out.println("user getById..." + id);
return "{'module':'book getById'}";
}
属性:
value (默认):请求访问路径
二、基础配置
1. 复制工程
① 在工作空间中复制对应工程,并修改
工程名称
② 删除与 IDEA 相关配置文件,仅保留
src 目录与 pom.xml 文件
③ 修改 pom.xml 文件中的 artfactId 与新
工程/模块名相同
④ 删除 name 标签 (可选)
⑤ 保留备份工程供后期使用
2. 属性配置
(1) 修改服务器端口:
② SpringBoot 默认配置文件 application.properties,
通过键值对配置对应属性
关闭运行日志图标(banner),设置日志相关
SpringBoot 内置属性查询:
Common Application Properties
① SpringBoot 中导入对应 starter 后,提供
对应配置属性
② 书写 SpringBoot 配置采用关键字 + 提示
形式书写
(2) SpringBoot 提供了多种属性配置方式
① application.properties (传统格式/默认格式)
server.port=80
② application.yml (主流格式)
server:
port: 81
③ application.yaml
server:
port: 82
三者共存时加载顺序:
application.properties > application.yml > application.yaml
注:不同配置文件中相同配置按照加载
优先级相互覆盖,不同配置文件中不同
配置全部保留
(3) 属性自动提示消失解决方法
(4) yaml 数据格式
YAML 是一种数据序列化格式,优点是容
易阅读,容易与脚本语言交互,以数据为
核心, 重数据轻格式
YAML 文件扩展名:
.yml (主流)
.yaml
(5) yaml 语法规则
① 大小写敏感
② 属性层级关系使用多行描述,每行结尾
使用冒号结束
③ 使用缩进表示层级关系,同层级左侧对
齐,只允许使用空格 (不允许使用 Tab
键)
④ 属性值前面添加空格 (属性名与属性值之
间使用冒号+空格作为分隔)
⑤ # 表示注释
核心规则:数据前面要加空格与冒号隔开
① 字面值表示方式:
boolean
: TRUE
| TRUE,true,True,FALSE,false,False 均可 |
float: 3.14 | 6.8523015e+5 #支持科学计数法 |
int: 123 | 0b1010_0111_0100_1010_1110 #支持二进制、八进制、十六进制 |
null: ~ | 使用 ~ 表示 null |
string: HelloWorld | 字符串可以直接书写 |
string2: "Hello World" | 可以使用双引号包裹特殊字符 |
date: 2018-02-17 | 日期必须使用 yyyy-MM-dd 格式 |
datetime: 2018-02-17T15:02:31+08:00 | 时间和日期之间使用 T 连接, 最后使用 + 代表时区 |
② 数组表示方式:
在属性名书写位置的下方使用减号作为
数据开始符号,每行书写一个数据,减
号与数据间空格分隔
(6) yaml 数据读取
1) 读取单一属性数据
使用 @Value 读取单个数据,属性名引用
方式:${一级属性名.二级属性名......}
center :dataDir : /usr/local/fire/datatmpDir : /usr/local/fire/tmplogDir : /usr/local/fire/logmsgDir : /usr/local/fire/msgDir
① 在配置文件中可以使用属性名引用方式
引用属性
baseDir : /usr/local/firecenter :dataDir : ${ baseDir }/datatmpDir : ${ baseDir }/tmplogDir : ${ baseDir }/logmsgDir : ${ baseDir }/msgDir
② 属性中如果出现转义字符,需要使用
双括号包裹
lesson : "Spring\tboot\nlesson"
2) 读取全部属性数据
封装全部数据到 Environment 对象
① 使用 Environment 对象封装全部配置
信息
② 使用 @Autowired 自动装配数据到
Environment 对象中
自定义对象封装指定数据:
自定义对象封装指定数据的作用
① 使用 @ConfigurationProperties 注解
绑定配置信息到封装类中
② 封装类需要定义为 Spring 管理的 bean,
否则无法进行属性注入
三、整合第三方技术
1. 整合 JUnit
@SpringBootTest
class Springboot07JunitApplicationTests {
@Autowired
private BookService bookService;
@Test
public void testSave(){
bookService.save();
}
}
@SpringBootTest 测试类注解,位于测
试类定义上方,设置 JUnit 加载的
SpringBoot 启动类
class:设置 SpringBoot 启动类
① 导入测试对应的 starter
② 测试类使用 @SpringBootTest 修饰
③ 使用自动装配的形式添加要测试的对象
注:如果测试类在SpringBoot启动类的包或子
包中,可以省略启动类的设置,也就是省
略 classes 的设定
2. 整合 MyBatis
核心配置:数据库连接相关信息
映射配置:SQL 映射(XML /注解)
① 创建新模块,选择Spring初始化,并配置模
块相关基础信息
② 选择当前模块需要使用的技术集 (MyBatis、MySQL)
③ 设置数据源参数
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/ssm_db
username: root
password: root
SpringBoot 版本低于 2.4.3 ( 不含 ) , Mysql 驱动版本大于 8.0 时,需要在 url 连接串中配置时区
jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTC
或在 MySQL 数据库端配置时区解决此问题
④ 定义数据层接口与映射配置
@Mapper
public interface UserDao {
@Select("select * from user")
public List<User> getAll();
}
⑤ 测试类中注入dao接口,测试功能
@SpringBootTest
class Springboot08MybatisApplicationTests {
@Autowired
private BookDao bookDao;
@Test
public void testGetById() {
Book book = bookDao.getById(1);
System.out.println(book);
}
}
① 勾选 MyBatis 技术,也就是导入 MyBatis
对应的 starter
② 数据库连接相关信息转换成配置
③ 数据库 SQL 映射需要添加 @Mapper 被容
器识别到
3. 整合 MyBatis-Plus
MyBatis-Plus 与 MyBatis 区别:
① 导入坐标不同
② 数据层实现简化
整合:
① 手动添加SpringBoot整合 MyBatis-Plus 的
坐标,可以通过 mvnrepository 获取
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
② 定义数据层接口与映射配置,继承 BaseMapper
@Mapper
public interface UserDao extends BaseMapper<User> {
}
③ 其余同 SpringBoot 整合 MyBatis
① 手工添加 MyBatis-Plus 对应的 starter
② 数据层接口使用 BaseMapper 简化开发
③ 需要使用的第三方技术无法通过勾选确
定时,需要手工添加坐标
4. 整合 Druid
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTC
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
② 导入 Druid 对应的 starter
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</dependency>
③ 变更 Druid 的配置方式
spring:
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTC
username: root
password: root
5. 整合任意第三方技术
① 导入对应的 starter
② 配置对应的设置或采用默认配置
四、基于SpringBoot的 SSMP 整合案例
实体类开发 | 使用 Lombok 快速制作实体类 |
Dao开发 | 整合 MyBatisPlus,制作数据层测试类 |
Service开发 | 基于 MyBatisPlus 进行增量开发,制作业务层 测试类 |
Controller开发 | 基于 Restful 开发,使用 PostMan 测试接口功能 |
Controller开发 | 前后端开发协议制作 |
页面开发 |
基于
VUE+ElementUI
制作,前后端联调,页
面数据处理,页面消息处理
列表、新增、修改、删除、分页、查询
|
项目异常处理 | |
按条件查询 | 页面功能调整、Controller 修正功能、Service 修正功能 |
1. 制作流程:
① 先开发基础 CRUD 功能,做一层
测一层
② 调通页面,确认异步提交成功后,
制作所有功能
③ 添加分页功能与查询功能
2. 模块创建
① 勾选 SpringMVC 与 MySQL 坐标
② 修改配置文件为 yml 格式
③ 设置端口为 80 方便访问
3. 实体类开发
(1) 使用 lombok 简化开发
Lombok,一个 Java 类库,提供了一
组注解,简化 POJO 实体类开发
Lombok 版本由 SpringBoot 提供,无
需指定版本
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
(2) 常用注解:@Data
@Data
public class Book {
private Integer id;
private String type;
private String name;
private String description;
}
为当前实体类在编译期设置对应的get/set 方法, toString 方法,hashCode 方法, equals 方法等
4. 数据层开发
(1) 技术实现方案:
① MyBatisPlus
② Druid
(2) 导入 MyBatisPlus 与 Druid 对应的
starter
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</dependency>
(3) 配置数据源与 MyBatisPlus 对应的
基础配置 (id 生成策略使用数据库自
增策略)
spring:
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/ssm_db?servierTimezone=UTC
username: root
password: root
mybatis-plus:
global-config:
db-config:
table-prefix: tbl_
id-type: auto
(4) 继承 BaseMapper 并指定泛型
@Mapper
public interface BookDao extends BaseMapper<Book> {
}
(5) 制作测试类测试结果
@SpringBootTest
public class BookDaoTest {
@Autowired
private BookDao bookDao;
@Test
void testSave() {
Book book = new Book();
book.setName("测试数据");
book.setType("测试类型");
book.setDescription("测试描述数据");
bookDao.insert(book);
}
@Test
void testGetById() {
System.out.println(bookDao.selectById(13));
}
...
}
① 手工导入 starter 坐标 (2个)
② 配置数据源与 MyBatisPlus 对应的配置③ 开发 Dao 接口 (继承 BaseMapper)④ 制作测试类测试 Dao 功能是否有效
(6) 为方便调试可以开启 MyBatisPlus 的
日志,设置日志输出方式为标准输出
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
5. 数据层开发--分页功能
@Test
void testGetPage(){
IPage page = new Page(1,5);
bookDao.selectPage(page,null);
}
(2) IPage 对象中封装了分页操作中的
所有数据
① 数据② 当前 页码值③ 每页数据总量④ 最大 页码值⑤ 数据总量
(3) 分页操作是在 MP 的常规操作基础
上增强得到,内部是动态的拼写
SQL 语句,因此需要增强对应的功
能, 使用 MP 拦截器实现
@Configuration
public class MpConfig {
@Bean
public MybatisPlusInterceptor mpInterceptor() {
//1.定义Mp拦截器
MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
//2.添加具体的拦截器
mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mpInterceptor;
}
}
@Test
void testGetByCondition(){
IPage page = new Page(1,10);
LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>();
lqw.like(Book::getName,"Spring");
bookDao.selectPage(page,lqw);
}
@Test
void testGetByCondition(){
QueryWrapper<Book> qw = new QueryWrapper<Book>();
qw.like("name","Spring");
bookDao.selectList(qw);
}
(2) 支持动态拼写查询条件
@Test
void testGetByCondition(){
String name = "Spring";
IPage page = new Page(1,10);
LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>();
lqw.like(Strings.isNotEmpty(name),Book::getName,"Spring");
bookDao.selectPage(page,lqw);
}
7. 业务层开发
(1) Service 层接口定义与数据层接口
定义具有较大区别,不要混用
① selectByUserNameAndPassword (String username,String password);② login (String username,Stringpassword);
(2) 接口定义
public interface BookService {
boolean save(Book book);
boolean delete(Integer id);
boolean update(Book book);
Book getById(Integer id);
List<Book> getAll();
IPage<Book> getByPage(int currentPage,int pageSize);
}
(3) 实现类定义
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookDao bookDao;
public Boolean save(Book book) {
return bookDao.insert(book) > 0;
}
public Boolean delete(Integer id) {
return bookDao.deleteById(id) > 0;
}
public Boolean update(Book book) {
return bookDao.updateById(book) > 0;
}
}
(4) 测试类定义
@SpringBootTest
public class BookServiceTest {
@Autowired
private BookService bookService;
@Test
void testGetById(){
bookService.getById(9);
}
@Test
void testGetAll(){
bookService.getAll();
}
@Test
void testGetByPage(){
bookService.getByPage(1,5);
}
… …
}
① Service 接口名称定义成 业务名称 ,并与 Dao 接口名称进行 区分② 制作测试类测试 Service 功能是否有效
8. 业务层开发--快速开发
① 使用 MP 提供有业务层通用接口( ISerivce<T> ) 与业务层通用实现类 ( ServiceImpl<M,T> )② 在通用类基础上做 功能重载 或 功能追加③ 注意 重载时不要覆盖原始操作 ,避免原始提供的功能丢失
(1) 接口定义
public interface IBookService extends IService<Book> {
}
public interface IBookService extends IService<Book> {
//追加的操作与原始操作通过名称区分,功能类似
Boolean delete(Integer id);
Boolean insert(Book book);
Boolean modify(Book book);
Book get(Integer id);
}
(2) 实现类定义
@Service
public class BookServiceImpl2 extends ServiceImpl<BookDao,Book> implements IBookService {
}
@Service
public class BookServiceImpl2 extends ServiceImpl<BookDao,Book> implements IBookService {
@Autowired
private BookDao bookDao;
public Boolean insert(Book book) {
return bookDao.insert(book) > 0;
}
public Boolean modify(Book book) {
return bookDao.updateById(book) > 0;
}
public Boolean delete(Integer id) {
return bookDao.deleteById(id) > 0;
}
public Book get(Integer id) {
return bookDao.selectById(id);
}
}
9. 表现层开发
① 基于 Restful 进行 表现层 接口开发② 使用 Postman 测试表现层接口功能
(1) 功能测试
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private IBookService bookService;
@GetMapping
public List<Book> getAll(){
return bookService.list();
}
}
(2) 表现层接口开发
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private IBookService bookService;
@PostMapping
public Boolean save(@RequestBody Book book){
return bookService.insert(book);
}
@PutMapping
public Boolean update(@RequestBody Book book){
return bookService.modify(book);
}
@DeleteMapping("/{id}")
public Boolean delete(@PathVariable Integer id){
return bookService.delete(id);
}
}
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private IBookService bookService;
@GetMapping("/{id}")
public Book getById(@PathVariable Integer id){
return bookService.getById(id);
}
@GetMapping
public List<Book> getAll(){
return bookService.list();
}
@GetMapping("/{currentPage}/{pageSize}")
public List<Book> getAll(@PathVariable Integer currentPage,@PathVariable Integer pageSize){
return bookService.getPage(currentPage,pageSize).getRecords();
}
}
基于 Restful 制作表现层接口:
① 新增:POST
② 删除:DELETE
③ 修改:PUT
④ 查询:GET
接收参数:
① 实体数据:@RequestBody
② 路径变量:@PathVariable
10. 表现层消息一致性处理
设计表现层返回结果的模型类,用于
后端与前端进行数据格式统一,也称
为前后端数据协议
@Data
public class R{
private Boolean flag;
private Object data;
public R(){
}
public R(Boolean flag){
this.flag = flag;
}
public R(Boolean flag,Object data){
this.flag = flag;
this.data = data;
}
}
表现层接口统一返回值类型结果
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private IBookService bookService;
@PostMapping
public R save(@RequestBody Book book){
Boolean flag = bookService.insert(book);
return new R(flag);
}
@PutMapping
public R update(@RequestBody Book book){
Boolean flag = bookService.modify(book);
return new R(flag);
}
}
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private IBookService bookService;
@DeleteMapping("/{id}")
public R delete(@PathVariable Integer id){
Boolean flag = bookService.delete(id);
return new R(flag);
}
@GetMapping("/{id}")
public R getById(@PathVariable Integer id){
Book book = bookService.getById(id);
return new R(true,book);
}
}
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private IBookService bookService;
@GetMapping
public R getAll(){
List<Book> bookList = bookService.list();
return new R(true ,bookList);
}
@GetMapping("/{currentPage}/{pageSize}")
public R getAll(@PathVariable Integer currentPage,@PathVariable Integer pageSize){
IPage<Book> page = bookService.getPage(currentPage, pageSize);
return new R(true,page);
}
}
① 设计 统一的返回值结果类型 便于前端开发读取数据② 返回值结果类型可以根据需求自行设定, 没有固定格式③ 返回值结果模型类用于后端与前端进行数据格式统一,也称为前后端数据协议
11. 前后端协议联调
① 前后端分离结构设计中页面归属前端服务器② 单体工程中页面放置在 resources 目录下的 static 目录中(建议执行 clean )
(1) 前端发送异步请求,调用后端接口
//列表
getAll() {
axios.get("/books").then((res)=>{
console.log(res.data);
});
},
① 单体项目中页面放置在 resources/static目录下② created 钩子函数 用于初始化页面时发起调用③ 页面使用 axios 发送异步请求获取数据后确认前后端是否联通
(2) 列表页
将查询数据返回到页面,利用前端数据双向
绑定进行数据展示
//列表
getAll() {
axios.get("/books").then((res)=>{
this.dataList = res.data.data;
});
},
(3) 弹出添加窗口
//弹出添加窗口
handleCreate() {
this.dialogFormVisible = true;
},
(4) 清除数据
//重置表单
resetForm() {
this.formData = {};
},
//弹出添加窗口
handleCreate() {
this.dialogFormVisible = true;
this.resetForm();
},
(5) 添加
//添加
handleAdd () {
//发送异步请求
axios.post("/books",this.formData).then((res)=>{
//如果操作成功,关闭弹层,显示数据
if(res.data.flag){
this.dialogFormVisible = false;
this.$message.success("添加成功");
}else {
this.$message.error("添加失败");
}
}).finally(()=>{
this.getAll();
});
},
(6) 取消添加
//取消
cancel(){
this.dialogFormVisible = false;
this.$message.info("操作取消");
},
① 请求方式使用 POST 调用后台对应操作② 添加操作结束后 动态刷新页面 加载数据③ 根据操作结果不同,显示对应的提示信息④ 弹出添加 Div 时 清除表单数据
(7) 删除
// 删除
handleDelete(row) {
axios.delete("/books/"+row.id).then((res)=>{
if(res.data.flag){
this.$message.success("删除成功");
}else{
this.$message.error("删除失败");
}
}).finally(()=>{
this.getAll();
});
}
// 删除
handleDelete(row) {
//1.弹出提示框
this.$confirm("此操作永久删除当前数据,是否继续?","提示",{
type:'info'
}).then(()=>{
//2.做删除业务
axios.delete("/books/"+row.id).then((res)=>{
……
}).finally(()=>{
this.getAll();
});
}).catch(()=>{
//3.取消删除
this.$message.info("取消删除操作");
});
}
① 请求方式使用 Delete 调用后台对应操作② 删除操作需要传递当前行数据对应的 id 值到后台③ 删除操作结束后动态刷新页面加载数据④ 根据操作结果不同,显示对应的提示信息⑤ 删除操作前弹出提示框避免误操作
(8) 弹出修改窗口
//弹出编辑窗口
handleUpdate(row) {
axios.get("/books/"+row.id).then((res)=>{
if(res.data.flag){
//展示弹层,加载数据
this.formData = res.data.data;
this.dialogFormVisible4Edit = true;
}else{
this.$message.error("数据同步失败,自动刷新");
}
});
},
(9) 删除消息维护
//删除
handleDelete(row) {
axios.delete("/books/"+row.id).then((res)=>{
if(res.data.flag){
this.$message.success("删除成功");
}else{
this.$message.error("数据同步失败,自动刷新");
}
}).finally(()=>{
this.getAll();
});
}
① 加载要修改数据通过传递当前行数据对应的 id 值到后台查询数据② 利用前端数据双向绑定将查询到的数据进行 回显
(10) 修改
//修改
handleEdit() {
axios.put("/books",this.formData).then((res)=>{
//如果操作成功,关闭弹层并刷新页面
if(res.data.flag){
this.dialogFormVisible4Edit = false;
this.$message.success("修改成功");
}else {
this.$message.error("修改失败,请重试");
}
}).finally(()=>{
this.getAll();
});
},
(11) 取消添加和修改
cancel(){
this.dialogFormVisible = false;
this.dialogFormVisible4Edit = false;
this.$message.info("操作取消");
},
① 请求方式使用 PUT 调用后台对应操作② 修改操作结束后动态刷新页面加载数据 (同新增)③ 根据操作结果不同,显示对应的提示信息 (同新增)
12. 业务消息一致性处理
(1) 对异常进行统一处理,出现异常后,
返回指定信息
@RestControllerAdvice
public class ProjectExceptionAdvice {
@ExceptionHandler(Exception.class)
public R doOtherException(Exception ex){
//记录日志
//发送消息给运维
//发送邮件给开发人员,ex对象发送给开发人员
ex.printStackTrace();
return new R(false,null,"系统错误,请稍后再试!");
}
}
(2) 修改表现层返回结果的模型类,封
装出现异常后对应的信息
flag:falseData: null消息( msg ): 要显示信息
@Data
public class R{
private Boolean flag;
private Object data;
private String msg;
public R(Boolean flag,Object data,String msg){
this.flag = flag;
this.data = data;
this.msg = msg;
}
}
(3) 页面消息处理,没有传递消息加载默
认消息,传递消息后加载指定消息
//添加
handleAdd () {
//发送ajax请求
axios.post("/books",this.formData).then((res)=>{
//如果操作成功,关闭弹层,显示数据
if(res.data.flag){
this.dialogFormVisible = false;
this.$message.success("添加成功");
}else {
this.$message.error(res.data.msg);
}
}).finally(()=>{
this.getAll();
});
},
(4) 可以在表现层 Controller 中进行消息
统一处理
目的:国际化
@PostMapping
public R save(@RequestBody Book book) throws IOException {
Boolean flag = bookService.insert(book);
return new R(flag , flag ? "添加成功^_^" : "添加失败-_-!");
}
(5) 页面消息处理
//添加
handleAdd () {
//发送ajax请求
axios.post("/books",this.formData).then((res)=>{
if(res.data.flag){
this.dialogFormVisible = false;
this.$message.success(res.data.msg);
}else {
this.$message.error(res.data.msg);
}
}).finally(()=>{
this.getAll();
});
},
① 使用注解 @RestControllerAdvice定义 SpringMVC 异常处理器用来处理异常的② 异常处理器 必须被扫描加载 ,否则无法生效③ 表现层返回结果的模型类中 添加消息属性 用来传递消息到页面
13. 分页功能
(1) 页面使用 el 分页主键添加分页功能
<!--分页组件-->
<div class="pagination-container">
<el-pagination
class="pagiantion"
@current-change="handleCurrentChange"
:current-page="pagination.currentPage"
:page-size="pagination.pageSize"
layout="total, prev, pager, next, jumper"
:total="pagination.total">
</el-pagination>
</div>
(2) 定义分页组件需要使用的数据并将
数据绑定到分页组件
data:{
pagination: { //分页相关模型数据
currentPage: 1, //当前页码
pageSize:10, //每页显示的记录数
total:0, //总记录数
}
},
(3) 替换查询全部功能为分页功能
getAll() {
axios.get("/books/"+this.pagination.currentPage+"/"
+this.pagination.pageSi ze).then((res) => {
});
},
(4) 分页查询
使用路径参数传递分页数据或封装对
象传递数据
@GetMapping("/{currentPage}/{pageSize}")
public R getAll(@PathVariable Integer currentPage,@PathVariable Integer pageSize){
IPage<Book> pageBook = bookService.getPage(currentPage, pageSize);
return new R(null != pageBook ,pageBook);
}
(5) 加载分页数据
getAll() { axios.get("/books/"+this.pagination.currentPage+"/"+this.pagination.pageSize).then((res) => {
this.pagination.total = res.data.data.total;
this.pagination.currentPage = res.data.data.current;
this.pagination.pagesize = res.data.data.size;
this.dataList = res.data.data.records;
});
},
(6) 分页页码值切换
//切换页码
handleCurrentChange(currentPage) {
this.pagination.currentPage = currentPage;
this.getAll();
},
① 使用 el 分页组件② 定义 分页组件绑定的数据模型③ 异步调用 获取分页数据④ 分页数据 页面回显
14. 删除功能维护
@GetMapping("{currentPage}/{pageSize}")
public R getPage(@PathVariable int currentPage,@PathVariable int pageSize){
IPage<Book> page = bookService.getPage(currentPage, pageSize);
//如果当前页码值大于了总页码值,那么重新执行查询操作,使用最大页码值作为当前页码值
if( currentPage > page.getPages()){
page = bookService.getPage((int)page.getPages(), pageSize);
}
return new R(true, page);
}
15. 条件查询功能
(1) 查询条件数据封装
① 单独封装
② 与分页操作混合封装
pagination: { //分页相关模型数据
currentPage: 1, //当前页码
pageSize:10, //每页显示的记录数
total:0, //总记录数
name: "",
type: "",
description: ""
}
(2) 页面数据模型绑定
<div class="filter-container">
<el-input placeholder="图书类别" v-model="pagination.type"
class="filter-item"/>
<el-input placeholder="图书名称" v-model="pagination.name"
class="filter-item"/>
<el-input placeholder="图书描述" v-model="pagination.description"
class="filter-item"/>
<el-button @click="getAll()" class="dalfBut">查询</el-button>
<el-button type="primary" class="butT" @click="handleCreate()">新建
</el-button>
</div>
(3) 组织数据成为 get 请求发送的数据
getAll() {
//1.获取查询条件,拼接查询条件
param = "?name="+this.pagination.name;
param += "&type="+this.pagination.type;
param += "&description="+this.pagination.description;
console.log("-----------------"+ param);
axios.get("/books/"+this.pagination.currentPage+"/"
+this.pagination.pageSize+param)
.then((res) => {
this.dataList = res.data.data.records;
});
},
条件参数组织可以通过条件判定书
写的更简洁
(4) Controller 接收参数
@GetMapping("{currentPage}/{pageSize}")
public R getAll(@PathVariable int currentPage,@PathVariable int pageSize,Book book) {
System.out.println("参数=====>"+book);
IPage<Book> pageBook = bookService.getPage(currentPage,pageSize);
return new R(null != pageBook ,pageBook);
}
(5) 业务层接口功能开发
public interface IBookService extends IService<Book> {
IPage<Book> getPage(Integer currentPage,Integer pageSize,Book queryBook);
}
@Service
public class BookServiceImpl2 extends ServiceImpl<BookDao,Book> implements IBookService {
public IPage<Book> getPage(Integer currentPage,Integer pageSize,Book queryBook){
IPage page = new Page(currentPage,pageSize);
LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>();
lqw.like(Strings.isNotEmpty(queryBook.getName()),
Book::getName,queryBook.getName());
lqw.like(Strings.isNotEmpty(queryBook.getType()),
Book::getType,queryBook.getType());
lqw.like(Strings.isNotEmpty(queryBook.getDescription()),
Book::getDescription,queryBook.getDescription());
return bookDao.selectPage(page,lqw);
}
}
(6) Controller 调用业务层分页条件
查询接口
@GetMapping("{currentPage}/{pageSize}")
public R getAll(@PathVariable int currentPage,@PathVariable int pageSize,Book book) {
IPage<Book> pageBook = bookService.getPage(currentPage,pageSize,book);
return new R(null != pageBook ,pageBook);
}
(7) 页面回显数据
getAll() {
//1.获取查询条件,拼接查询条件
param = "?name="+this.pagination.name;
param += "&type="+this.pagination.type;
param += "&description="+this.pagination.description;
console.log("-----------------"+ param);
axios.get("/books/"+this.pagination.currentPage+"/"
+this.pagination.pageSize+param)
.then((res) => {
this.pagination.total = res.data.data.total;
this.pagination.currentPage = res.data.data.current;
this.pagination.pagesize = res.data.data.size;
this.dataList = res.data.data.records;
});
},
① 定义查询条件数据模型 (当前封装到分页数据模型中)② 异步调用分页功能并通过请求参数传递数据到后台
① pom.xml | 配置起步依赖 |
② application.yml |
设置数据源、端口、框架技术相关
配置等
|
③ dao |
继承BaseMapper、设置@Mapper
|
④ dao 测试类 | |
⑤ service |
调用数据层接口或MyBatis-Plus提供
的接口快速开发
|
⑥ service 测试类 | |
⑦ controller |
基于Restful开发,使用Postman测试
跑通功能
|
⑧ 页面 |
放置在resources目录下的static目录中
|