# 快速上手 SpringBoot

# SpringBoot 简介

SpringBoot 是由 Pivotal 团队提供的全新框架,其设计目的用来简化 Spring 应用的初始搭建以及开发过程

# SpringBoot 入门程序

@RestController
@RequestMapping("/books")
public class BootController {
    @GetMapping
    public String geiById(){
        System.out.println("springboot is running...");
        return "springboot is running...";
    }
}

# SpringBoot 官网

  1. 国外:https://start.spring.io/
  2. 国内:https://start.aliyun.com/

# Spring 和 SpringBoot 区别

# Spring 程序缺点

  1. 依赖设置繁琐
  2. 配置繁琐

# SpringBoot 优点

  1. 起步依赖(简化依赖配置)
  2. 自动配置(简化常用工程相关配置)
  3. 辅助功能(内置服务器)

# SpringBoot 小结

  1. 开发 SpringBoot 程序要继承 spring-boot-starter-parent
  2. spring-boot-starter-parent 中定义了若干个依赖管理
  3. 继承 parent 模块可以避免多个依赖使用相同技术时候出现依赖版本冲突
  4. 继承 parent 的形式也可以采用引入依赖的形式实现效果

# starter

SpringBoot 中常见项目名称,定义了当前项目使用的所有依赖坐标,以达到减少依赖配置的目的

# SpringBoot(starter)小结

  1. 开发 SpringBoot 程序需要导入坐标时通常导入对应的 starter
  2. 每个不同的 starter 根据功能不同,通常包含多个依赖坐标
  3. 使用 starter 可以实现快速配置的效果,达到简化配置的目的

# SpringBoot 工程引导类

  1. 启动方式
  2. SpringBoot 的引导类是 Boot 工程的执行入口,运行 main 方法就可以启动项目
  3. SpringBoot 工程运行后初始化 Spring 容器,扫描引导类所在包加载 Bean
@SpringBootApplication
public class Springboot01quickstartApplication {
    public static void main(String[] args){
        SpringApplication.run(Springboot01quickstartApplication.class,args);
    }
}

# 辅助功能(内嵌 tomcat)

# 内置服务器分类

# tomcat 默认

apache 出品,粉丝多,应用面广,负载了若干较重组件

# jetty

更轻量级,负载性能远不及 tomcat

# undertow

负载性能勉强跑赢 tomcat

# REST 开发

# REST 简介

REST,表现形式状态转换

# 传统风格资源描述

http://localhost/user/getById?id=1

http://localhost/user/saveUser

# REST 风格描述形式

http://localhost/user/1

http://localhost/usre

# 优点

  1. 隐藏资源的访问行为,无法通过地址得知对资源做的何种操作
  2. 书写简化

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

http://localhost/users 查询全部用户信息用 GET(查询)

http://localhost/users/1 查询指定用户信息 GET(查询)

http://localhost/users 添加用户信息 POST(新增 / 保存)

http://localhost/users 修改用户信息 PUT(修改 / 更新)

http://localhost/users/1 删除用户信息 DELETE(删除)

# 入门案例

# @RequestMapping

  1. 类型:方法注解
  2. 位置:SpringMVC 控制器方法定义
  3. 作用:设置当前控制器方法请求路径
  4. 属性:
    1. value:请求访问路径
    2. method:http 请求动作,标准动作(GET/POST/PUT/DELETE)
@RequestMapping(value = "/users",methods = RequestMethod.POST)
@ResponseBody
public String save(@RequestBody User user){
    return "{'moudle':'user save'}";
}

# @PathVariable

  1. 类型:形参注解
  2. 位置:SpringMVC 控制器方法形参前
  3. 作用:绑定路径参数与处理器方式行参间关系,要求路径参数名一一对应
@RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)
@ResponseBody
public String delete(@PathVariable Integer id){
    return "{'module':'user delete'}";
}

# @RequestBody @RequestParam @PathVariable

# 区别

  1. @RequestParam 用于接收 url 地址传参或表单传递
  2. @RequestBody 用于接收 json 数据
  3. @PathVariable 用于接收路径参数,使用(参数名称)描述路径参数

# 应用

  1. 后期开发中,发送请求超过一个时,以 json 格式为主,@RequestBody 应用较广
  2. 如果发送非 json 格式数据,选用 @RequestParam 接收请求参数
  3. 采用 RESTful 进行开发,当参数较少时,例如一个,可以使用 @PathVariable 接收路径请求变量,通常用于传递 id 值

# RESTful 快速开发

# @RestController

  1. 类型:类注解
  2. 基于 SpringMVC 的 RESTful 开发控制器类定义在上方
  3. 设置当前控制器类为 RESTful 风格,等同于 @Controller 和 @ResponseBody 两个注解组合功能
@RestController
public class BookController {
}

# @GetMapping @PostMapping @PutMapping @DeleteMapping

  1. 类型:方法注解
  2. 位置:基于 SpringMVC 的 RESTful 开发控制器方法定义上方
  3. 作用:设置当前控制器方法请求访问路径与请求动作,每种对应一个请求动作,例如 @GetMapping 对用 GET 请求
  4. 属性:
    1. value:请求访问路径
@GetMapping("/{id}")
public String getById(@PathVariable Integer id){
    return "{'moudle':book getById}";
}

# 基础配置

# 复制工程

# 原则

  1. 保留工作基础结构
  2. 抹掉原始工程痕迹

# 属性配置

# 修改服务器端口

SpringBoot 默认配置文件 application.properties,通过键值对配置对应属性

server.port = 80

# 关闭运行日志图标(banner)

spring.main.banner-mode=off

# 设置日志相关

logging.level.root=debug

# SpringBoot 提供了多种属性配置方式

# application.properties

server.port=80

# application.yml

server:
	port: 81

# SpringBoot 配置文件加载顺序

application.properties > application.yml > application.yaml

常用 application.yml 不同配置文件中相同配置按照加载优先级相互覆盖,不同配置文件中不同配置全部保留

# yaml

# 简介

yaml 是一种数据序列化格式

# 优点

  1. 容易阅读
  2. 容易与脚本语言交互
  3. 以数据为核心,重数据轻格式

# yaml 文件扩展名

.yml

.yaml

# yaml 语法

  1. 大小写敏感
  2. 属性层次关系使用多行描述,每行结尾使用冒号结束
  3. 使用缩进表示层级关系,同层级左侧对齐,只允许使用空格
  4. 属性值前面添加空格(属性名和属性值之间使用冒号 + 空格作为分隔)
  5. #表示注释

# yaml 数据读取

使用 @Value 读取单个数据,属性名引用方式:$

# yaml 配置文件

lesson: SpringBoot
server:
	port: 80
enterprise:
	name: baozi
	age: 18
	tel: 1588888888
	subject: 
		- Java
		- 前端
		- 大数据

# 数据读取

@RestController
@RequestMapping("/books")
public class BookController {
    @Value("${lesson}")
    private String lessonName;
    @Value("${server.port}")
    private int port;
    @Value("${enterprise.subject}")
    private String[] subject;
}

# 在配置文件中可以使用属性名引用方式引用属性

baseDir: /use/local/fire
center:
	dataDir: ${baseDir}/data

# 属性值中如果出现转义字符,需要双引号包裹

lesson: "Spring\tboot\nlesson"

# 封装全部数据到 Eneviroment 对象

lesson: SpringBoot
server:
	port: 80
enterprise:
	name: baozi
	age: 18
	tel: 1588888888
	subject: 
		- Java
		- 前端
		- 大数据
@RestController
@RequestMapping("/books")
public class BookController{
    @Autowired
    private Enviroment 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";
    }
}

# 自定义对象封装指定参数

datasource:
	dirver: com.mysql.jdbc.Driver
	url: jdbc:mysql://localhost:3306/springdatabase
	username: root
	password: root
@Component
@ConfigurationProperties(prefix = "datasource")
public class DataSource {
    private String dirver;
    private String url;
    private String username;
    private String password;
}

# 整合第三方技术

# SpringBoot 整合 Junit

@SpringBootTest
public class SpringBoot07JunitApplicationTests {
    @Autowired
    private BookService bookService;
    @Test
    public void testSave() {
        bookService.save();
    }
}
  1. 名称:@SpringBootTest
  2. 类型:测试类注解
  3. 位置:测试类定义上方
  4. 作用:设置 Junit 加载的 SpringBoot 启动类
  5. 相关属性:classes:设置 SpringBoot 启动类
@SpringBootTest
class SpringBootJunitApplicationTests{}
@SpringBootTest(classes = SpringBoot05JunitApplication.class)
class Springboot07JunitApplicationTests{}

# SpringBoot 整合 MyBatis

# 创建新模块,选择 Spring 初始化,并配置相关基础信息

image-20230118155915915

# 选择当前模块使用的技术集(Mybatis,MySQL)

image-20230118160006471

# 设置数据源参数

spring:
    datasource:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/database
        username: root
        password: root

# 定义数据层接口与映射配置

@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();
        System.out.println(book);
    }
}

# 注意事项

# MySQL8.x 驱动强制要求设置时区

  1. 修改 url,添加 serverTimezone 设定
  2. 修改 MySQL 数据库配置
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/student?serverTimezone=UTC
    username: root
    password: root

# 驱动过时时,更换为 com.mysql.cj.jdbc.Driver

# SpringBoot 整合 MyBatis-Plus

# 手动添加 SpringBoot 整合 MyBatis-Plus 坐标

<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> {
    
}

# 整合 Durid

# 导入 Druid 对应 starter

<dependency>
    <groupId>com.alibaba</groupId>
    <artifacId>druid-spring-boot-starter<artifacId>
    <version>1.2.6</version>
</dependency>

# 变更 Druid 的配置方式

spring:
    datasource:
        druid:
            driver-class-name: com.mysql.cj.jdbc.Driver
            url: jdbc:mysql://localhost:3306/database?serverTimezone=UTC
            username: root
            password: root

# 整合 SSMP 案例

# Lombok

# Lombok 基本介绍

  1. Lombok 是一个 Java 类库,提供了一组注解,简化 pojo 的实体类开发
  2. lombok 版本由 Spring Boot 提供,无需指定版本
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifacId>lombok</artifacId>
<dependency>

# 常用注解

@Data
public class Book {
    private Integer id;
    private String type;
}

为当前实体类在编译期设置对应的 get/set 方法,toString 方法,hashCode 方法,equals 方法等

# 日志 log

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 对象封装的数据

  1. 数据
  2. 当前页码值
  3. 每页数据总量
  4. 最大页码值
  5. 数据总量

# 分页操作 MyBatisPlus 拦截器实现

@Configuration
public class MpConfig {
    @Bean
    public MyBatisPlusInterceptor mpInterceptor() {
        // 定义 Mp 拦截器
        MybatisPlusInterceptor mpInterceptor = new MyBatisPlusInterceptor();
        // 添加具体操作
        mpInterceptor.addInnerInterceptor(new PageationInnerInterceptor());
        return mpInterceptor;
    }
}

# 数据层开发 —— 条件查询

# 使用 QueryWrapper 对象封装查询条件

@Test
void testGetByCondition() {
    QueryWrapper<Book> qw = new QueryWrapper<Book>();
    qw.like("name","Spring");
    bookDao.selectList(qw);
}

# 使用 LambdaQueryWrapper 对象封装查询条件

@Test
void testGetCondition() {
    IPage page = new Page(1,10);
    LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>();
    lqw.like(Book::getName,"Spring");
    bookDao.selectPage(page,lqw);
}

# 支持动态拼写查询条件

@Test
void testGetCondition(){
    String name = "Spring";
    IPage page = new Page(1,10);
    LambdaQueryWrapper lqw = new LambdaQueryWrapper<Book>();
    lqw.like(String.isNotEmpty(name),Book::getName,"Spring");
    bookDao.selectPage(page,lqw);
}

# 业务层开发 —— 快速开发

# 快速开发方案

  1. 使用 MyBatisPlus 提供有业务层通用接口(IService)与业务层通用实现类(ServiceImpl)
  2. 在通用类基础上做功能重载或功能追加
  3. 注意重载时不要覆盖原始操作,避免原始提供的的功能丢失

# 接口定义

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 BookServiceImol2 extends ServiceImpl<BookDao,Book> implments IBookService{
}

# 表现层开发

# 功能测试

@RestController
@ResquestMapping("/books")
public class BookController {
    @Autowired
    private IBookService bookService;
    @GetMapping
    public List<Book> getAll() {
        return bookService.list();
    }
}

# 表现层接口开发

@RestController
@RequestMapping("/books")
public class BookController {
    @Autowired
    private IBookService bookService;
    
    @PostMapping
    public Boolean save(@RequestBody Book book){
        return bookService.save(book);
    }
    @PutMapping
    public Boolean update(@RequestBody Book book){
        return bookService.modify(book);
    }
    @DeleteMapping("/{id}")
    public Boolean delete(@PathVariable Integer id){
        return bookService.delete(id);
    }
    @GetMapping("/{currentPage}/{pageSize}")
    public List<Book> getAll(@PathVariable Integer currentPage,@PathVariable Integer pageSize){
        return bookService.getPage(currentPage,pageSize).getRecords();
    }
}

# RESTful 制作表现层接口

# 查询:GET

@GetMapping
public List<Book> getAll() {
    return bookService.list();
}
@GetMapping("{id}")
public Book getById(@PathVariable Integer id){
    return bookService.getById(id);
}
@GetMapping("{currentPage}/{pageSize}")
public IPage<Book> getPage(@PathVariable Integer currentPage,@PathVariable Integer pageSize){
    IPage<Book> page = new Page<Book>(currentPage,pageSize);
    return bookService.page(page);
}

# POST:新增

@PostMapping
public Boolean save(@RequestBody Book book){
    return bookService.save(book);
}

# DELETE:删除

@DeleteMapping("{id}")
public Boolean delete(@PathVariable Integer id){
    return bookService.removeById(id);
}

# PUT:修改

@PutMapping
public Boolean update(@RequestBody Book book){
    return bookService.updateById(book);
}

# 接收参数

  1. 实体数据:@RequestBody
  2. 路径变量:@PathVariable

# 表现层消息一致性处理

# 数据格式

{
    "flag": true,
    "data": {
        "id": 1,
        "name": "baozi",
        "type": "正常"
    }
}

# 设计表现层模型类(前后端数据协议)

@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 bookServie;
    @PostMapping
    public R save(@RequestBody Book book){
        return new R(bookService.save(book));
    }
    @PutMapping
    public R update(@RequestBody Book book){
        return new R(bookService.updateById(book));
    }
}

# 前后端协议联调

# 前端发送异步请求,调用后端接口

# 列表功能

getAll () {
    axios.get("/books").then((res) => {
        this.dataList = res.data.data;
    })
}

# 新增功能

1 弹出添加窗口

handleCreate () {
    this.dialogFormVisible = true;
}

2 清除数据

// 重置表单
resetForm () {
    this.formData = {};
}
// 弹出添加窗口
handleCreate () {
    this.dialogFormVisible = true;
    this.resetForm();
}

3 添加

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

4 取消添加

cancel() {
    this.dialogFormVisible = false;
    this.$message.info("取消添加");
}

# 删除功能

handleDelete(row) {
    this.$confirm("是否确定要删除吗","提示",{type:"info"}).then(()=>{
        axios.delete("/books/" + row.id).then((res)=>{
            if(res.data.flag){
                this.$message.success("删除成功");
            } else {
                this.$message.error("删除失败");
            }
        }).finally(()=>{
           this.getAll();
        });
    }).catch(()=>{
       this.$message.info("取消删除");
    });
},

# 修改功能

1 弹出修改框

handleUpdate(row) {
    axios.get("/bboks/" + row.id).then((res)=>{
        if(res.data.flag){
            this.formData = res.data.data;
            this.dialogFormVisible4Edit = true;        
        } else {
            this.$message.error("数据同步失败,自动刷新");        
        }
    });
}

2 加载修改后的数据

// 修改
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();
    })
},

# 业务消息一致性处理(异常)

@RestControllerAdvice
public class ProjectExceptionAdvice {
    @ExceptionHandler(Exception ex){
        // 记录日志
        // 发送消息给运维
        // 发送邮件给开发人员,ex 对象发送给开发人员  
        ex.printStackTrace();
        return new (false,null,"系统错误,请稍后再试");  
    }
}

# 分页功能

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.pageSize).then((res)=>{
        this.pagination.currentPage = res.data.data.current;
        this.pagination.pageSize = res.data.data.size;
        this.pagination.total = res.data.data.total;
        // 数据
        this.dataList = res.data.data.records;
    })
},
// 切换页码
handleCurrentChange(currentPage) {
    this.pagination.currentPage = currentPage;
    this.getAll();
},

4 删除功能维护(当前页码值 > 最大页码值)

@GetMapping("{currentPage}/{pageSize}")
public R getPage(@PathVariable Integer currentPage,@PathVariable Integer pageSize){
    IPage<Book> page = new Page<Book>(currentPage,pageSize);
    if(currentPage > page.getPages()){
        return new R(true,bookService.page(page));
    }
    return new R(true,bookService.page(page));
}

# 条件查询

1 查询条件数据封装

pagination: {// 分页相关模型数据
    currentPage: 1,// 当前页码
    pageSize:5,// 每页显示的记录数
    total:0,// 总记录数
    type: "",
    name: "",
    description: ""
}

2 页面数据绑定

<div class="filter-container">
    <el-input placeholder="图书类别" v-model="pagination.type" style="width: 200px;" class="filter-item"></el-input>
    <el-input placeholder="图书名称" v-model="pagination.name" style="width: 200px;" class="filter-item"></el-input>
    <el-input placeholder="图书描述" v-model="pagination.description" style="width: 200px;" class="filter-item"></el-input>
    <el-button @click="getAll()" class="dalfBut">查询</el-button>
    <el-button type="primary" class="butT" @click="handleCreate()">新建</el-button>
</div>

3 阻止数据成为 get 请求发送的数据

getAll() {
    param = "?type="+this.pagination.type;
    param += "&name="+this.pagination.name;
    param += "&description="+this.pagination.description;
    axios.get("/books/" + this.pagination.currentPage + "/" + this.pagination.pageSize + param).then((res)=>{
        this.pagination.currentPage = res.data.data.current;
        this.pagination.pageSize = res.data.data.size;
        this.pagination.total = res.data.data.total;
        // 数据
        this.dataList = res.data.data.records;
    })
},

4 Controller 接收参数

@GetMapping("{currentPage}/{pageSize}")
public R getPage(@PathVariable Integer currentPage,@PathVariable Integer pageSize,Book book){
    System.out.println(book);
    IPage<Book> page = new Page<Book>(currentPage,pageSize);
    if(currentPage > page.getPages()){
        return new R(true,bookService.getPage(page,book));
    }
    return new R(true,bookService.getPage(page,book));
}

5 业务层接口功能开发

public interface IBookService extends IService<Book> {
    IPage<Book> getPage(IPage<Book> page, Book book);
}
@Service
public class BookService2Impl extends ServiceImpl<BookDao, Book> implements IBookService {
    @Autowired
    private BookDao bookDao;
    @Override
    public IPage<Book> getPage(IPage<Book> page, Book book) {
        LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>();
        lqw.like(Strings.isNotEmpty(book.getType()),Book::getType,book.getType());
        lqw.like(Strings.isNotEmpty(book.getName()),Book::getName,book.getName());
        lqw.like(Strings.isNotEmpty(book.getDescription()),Book::getDescription,book.getDescription());
        return bookDao.selectPage(page,lqw);
    }
}
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Baozi 微信支付

微信支付

Baozi 支付宝

支付宝

Baozi 微信

微信