概述
SpringBoot提供了一种快速使用Spring的方式,基于约定优于配置的思想
Spring缺点
- 配置繁琐
- 依赖繁琐
SpringBoot功能
- 自动配置
- Spring配置应该用那个,不该用那个,该过程是SpringBoot自动完成的
- 起步依赖
- 辅助功能
- 提供了一些大型项目中常见的非功能特性,如嵌入式服务器、安全、指标、健康检测、外部配置等
SpringBoot并不是对Spring功能上的增强,而是提供了一种快速使用Spinrg的方式
快速入门
- 创建Maven项目
- 导入SpringBoot起步依赖
<!--SpringBoot工程需要继承的父工程-->
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.2.6.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
- 定义Controller
package com.ht.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello(){
return "hello Spring boot!";
}
}
- 编写引导类
package com.ht;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 引导类。SpringBoot项目的入口
*/
@SpringBootApplication
public class HelloApplication {
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class);
}
}
- 启动测试
小结
- SpringBoot在创建项目时,使用jar的打包方式
- SpringBoot的引导类,是项目入口,运行main方法就可以启动项目
- 使用SpringBoot和Spring构建的项目,业务代码编写方式完全一样
快速构建SpringBoot工程
通过Idea快速构建
起步依赖原理分析
spring-boot-starter-parent
定义了各种技术的版本信息,组全了一套最优搭配的技术版本
spring-boot-starter-web
在各种starter中,定义了完成该功能需要的坐标合计,其中大部分版本信息来自父工程。
我们的工程继承parent,引入starter后,通过依赖传递,就可以简单方便获得需要的jar包,并且不会存在版本冲突等问题
配置
分类
SpringBoot是基于约定的,所以很多配置都有默认值,但如果想使用自己的配置替换默认配置的话,就可以使用application.properties或者application.yml(application.yaml)进行配置
- SpringBoot提供了两种配置文件类型:properties和yml/yaml
- 默认配置文件名称:application
- 在同一级目录下优先级为:properties>yml>yaml
Yaml
介绍
Yaml是一种直观的能够被电脑识别的数据序列化格式,并且容易被人类阅读,容易和脚本预言交互的,可以被支持yaml库的不同的编程语言程序导入,yml文件是以数据为核心的,比传统的xml方式更加简洁
yaml文件的扩展名可以使用.yml或.yaml
语法
- 大小写敏感
- 数据值前边必须有空格,作为分隔符
- 使用缩进表示层级关系
- 缩进时不允许使用Tab键,只允许使用空格(各个系统tab对应的空格数目可能不同,导致层次混乱)
- 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
- #表示注释,从这个字符一直到行尾,都会被解析器忽略。
数据格式
- 对象(map):键值对的集合
person:
name:zhangsan
#行内写法
person:{name,zhangsan}
- 数组:一组按次序排列的值
address:
-beijing
-shanghai
#行内写法
address:[beijing,shanghai]
- 纯量:单个的,不可再分的值。
msg1:'hello \n world' #单引忽略转义字符
msg2:"hello \n world" #双引识别转义字符
参数引用:${key}
读取配置文件
- @Value
@Value("${name}")
private String name;
name:1234
- Environment
@Autowired
private Enviroment env;
@RequstMapping("/hello")
public String hello2(){
System.out.println(env.getProperty("name"))
return "hello";
}
name:1234
- @ConfigurationProperties
@Component
@ConfigurationProperties(prefix = "person")
public class person{
private String name;
private int age;
。。。(get/set/toString)
}
person:
name:1234
age:123
@Autowired
private Person person;
@RequestMapping("/hello")
public String hello(){
System.out.println(person);
return "hello";
}
profile动态配置文件
简介
我们在开发SpringBoot应用时,通常同一套程序会被安装到不同环境,比如:开发、测试、生产等其中数据库地址、服务器端口等等配置不同,如果每次打包时,都要修改配置文件,那么非常麻烦,profile功能就是来进行动态配置切换的。
配置方式
- 多profile文件方式
多profile文件方式–properties
spring.profiles.active=pro
spring.profiles.active=dev
server:8000
server:8001
多profile文件方式—yml
spring:
profiles:
#active: pro
active: dev
激活方式
- 配置文件
项目内部配置文件加载顺序
Springboot程序启动时,会从以下位置加载配置文件:
- file:./config/:当前项目下的/config目录下
- file:./ :当前项目的根目录
- classpath:/config/:classpath的/config目录
- classpath:/ :classpath的根目录(常用即resources)
加载顺序为上文的排列顺序,高优先级配置的属性会生效
整合
整合Junit
- 搭建SpringBoot工程
- 引入starter-test起步依赖
- 编写测试类
- 添加测试相关注解
- @RunWith(SpringRunner.class)
- @SpringbootTest(classes = 启动类.class)
- 编写测试方法
整合redis
- 搭建SpringBoot工程
- 引入redis起步依赖
- 配置redis相关属性
- 注入RedisTemplate模板
@Autowired
private RedisTemplate redisTemplate;
@Test
public void testSet(){
//存入数据
redisTemplate.boundValueOps("name").set("zhangsan");
}
@Test
public void testGet(){
//获取对象
Object name = redisTemplate.boundValueOps("name").get();
System.out.println(name);
}
- 编写测试方法,测试
整合mybatis
- 核心配置:数据库连接相关信息(连什么?连谁?什么权限)
- 映射配置:SQL映射(XML/注解)
步骤:
1、创建一个新的springboot工程
2、选择当前模块需要使用的技术集(MyBatis、MySQL)
3、设置数据源参数
4、定义数据层借口和映射配置
5、测试
整合mybatis时的常见问题
时区设置问题
1、给mysql设置时区(url后面加serverTimezone=UTC)
整合MyBatis-Plus
- MyBatis-Plus与MyBatis区别
- 导入坐标不同
- 数据层实现简化
快速
使用阿里云的方式创建spring-boot
正式(官方)
1、手动添加SpringBoot整合MyBatis-Plus的坐标,可以通过mvnrepository获取
2、定义数据层接口与映射,继承BaseMapper
整合Druid
1、导入坐标
2、添加配置信息
spring:
datasource:
druid:
url:
username:
password:
整合第三方技术
- 导入对应的starter
- 配置对应的设置或采用默认配置
整合案例
模块搭建
1、勾选SpringMVC与MySQL坐标
2、修改配置文件为yml格式
3、设置端口号
实体类开发
- Lombok:一个java类库,提供了一组注解,简化POJO实体类开发
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
-
lombok版本由SpringBoot提供,无需指定版本
-
常用注解:@Data
@Data
public class Book {
private Integer id;
private String type;
private String name;
private String description;
}
- 为当前实体类在编译期设置对应的get/set方法,toString方法,hashCode方法,equals方法等
数据层标准开发
-
技术实现方案
- MyBatisPlus
- Druid
-
导入MyBatis与Druid对应的starter
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
- 配置数据源与MyBatisPlus对应的基础配置(id生成策略使用数据库自增策略)
spring:
datasource:
druid:
driver-class-name: com.mysql.jdbc.Driver
url:jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTC
username:root
password:root
mybatis-plus:
global-config:
db-config:
table-prefix: tb1_
id-type: auto
- 继承BaseMapper并指定泛型
@Mapper
public interface BookDao extends BaseMapper<Book> {
}
MP开始日志
- 为了方便调试可以开启MyBatisPlus的日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
数据层-分页功能
- 分页操作需要设定分页对象IPage
@Test
void testGetPage(){
Ipage page = new Page(1,5);
bookDao.selectPage(page,null);
}
-
Ipage对象中封装了分页操作中的所有数据
- 数据
- 当前页码值
- 每页数据总量
- 最大页码值
- 数据总量
-
分页操作是在MyBatisPlus的常规操作基础上增强得到,内部是动态的拼写SQL语句,因此需要增强对应的功能,使用MyBatisPlus拦截器实现
@Configuration
public class MPConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
数据层-按条件查询
- 使用QueryWrapper对象封装查询条件,推荐使用LambdaQueryWrapper对象,所有查询操作封装成方法调用
@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);
}
- 支持动态拼写查询条件
@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);
}
业务层开发
-
Service层接口定义与数据层接口定义具有较大区别,不要滥用
- selectByUserNameAndPassword(String username,String password);
- login(String username,String password);
-
接口定义
public interface BookService {
Boolean save(Book book);
Boolean update(Book book);
Boolean delete(Integer id);
Book getById(Integer id);
List<Book> getAll();
}
- 实现类定义
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookDao bookDao;
@Override
public Boolean save(Book book) {
return bookDao.insert(book)>0;
}
@Override
public Boolean update(Book book) {
return bookDao.updateById(book)>0;
}
@Override
public Boolean delete(Integer id) {
return bookDao.deleteById(id)>0;
}
@Override
public Book getById(Integer id) {
return bookDao.selectById(id);
}
@Override
public List<Book> getAll() {
return bookDao.selectList(null);
}
}
业务层–快速开发
-
快速开发方案
- 使用MyBatisPlus提供有业务层通用接口(ISerivce)与业务层通用实现类(ServiceImpl<M,T>)(M数据层接口,T实体类)
- 在通用类基础上做功能重载或追加
- 注意重载时不要覆盖原始操作,避免原始提供的功能丢失
-
接口定义
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);
}
- 实现类定义
@Service
public class BookServiceImpl2 extends ServiceImpl<BookDao,Book> implements IBookService{
}
表现层
- 基于Restful制作表现层接口
- 新增:POST
- 删除:DELETE
- 修改:PUT
- 查询:GET
- 接收参数:
- 实体数据:@RequestBody
- 路径变量:@PathVariable
表现层消息一致性处理
- 设计表现层返回结果的模型类,用于后端与前端进行数据格式统一,也称为前后端数据协议
@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;
@GetMapping
public R getAll(){
return new R(true,bookService.list());
}
@PostMapping
public R save(@RequestBody Book book){
// R r = new R();
// boolean flag = bookService.save(book);
// r.setFlag(flag);
return new R(bookService.save(book));
}
@PutMapping
public R update(@RequestBody Book book){
return new R(bookService.saveOrUpdate(book));
}
@DeleteMapping("{id}")
public R delete(@PathVariable Integer id){
return new R(bookService.removeById(id));
}
@GetMapping("{id}")
public R getById(@PathVariable Integer id){
return new R(true,bookService.getById(id));
}
@GetMapping("{currentPage}/{pageSize}")
public R getPage(int currentPage,int pageSize){
return new R(true,bookService.getPage(currentPage,pageSize));
}
}
- 设计统一的返回值结果类型便于前端开发读取数据
- 返回值结果类型可以根据需求自行设定,没有固定格式
- 返回值结果模型类用于后端与前端进行数据格式统一,也称为前后端数据协议
前后端协议联调
- 前后端分离结构设计中页面归属前端服务器
- 单体工程中页面放置在resources目录下的static目录中(建议执行clean)
异常处理
- 对异常进行统一处理,出现异常后,返回指定信息
//作为springmvc的异常处理器
@RestControllerAdvice
public class ProjectExceptionAdvice {
//拦截所有的异常信息
@ExceptionHandler(Exception.class)
public R doException(Exception ex){
//记录日志
//发送消息给运维
//发送邮件给开发人员,ex对象发送给开发人员
ex.printStackTrace();
return new R("服务器故障,请稍后");
}
}
@Data
public class R {
private Boolean flag;
private Object data;
private String msg;
public R(){
}
public R(Boolean flag){
this.flag=flag;
}
public R(Boolean flag,Object data){
this.flag=flag;
this.data=data;
}
public R(String msg){
this.flag=false;
this.msg=msg;
}
}