aoe1231

看得完吗

SpringBoot入门

1、SpringBoot简介

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

1.1、原生开发SpringMVC程序过程

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
/**
 * 定义一个servlet容器启动的配置类,在里面加载spring的配置(需继承AbstractDispatcherServletInitializer,这样tomcat可以探测到这个类)
 */
public class ServletConfig extends AbstractDispatcherServletInitializer {
    /*
    * 注:Web容器(Tomcat)启动时,会加载SpringMvcConfig和SpringConfig配置类。
    *   这两个配置类产生的容器对象不是同一个对象。
    *   SpringMVC容器能访问Spring容器,而Spring容器不能访问SpringMVC容器。
    * */

    // 加载SpringMVC容器配置
    @Override
    protected WebApplicationContext createServletApplicationContext() {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(SpringMvcConfig.class);
        return ctx;
    }

    // 拦截请求:设置哪些请求归属SpringMVC处理
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"}; // 所有请求归SpringMVC进行处理
    }

    // 加载Spring容器的配置
    @Override
    protected WebApplicationContext createRootApplicationContext() {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(SpringConfig.class);
        return ctx;
    }

    // 设置过滤器,处理中文乱码问题
    @Override
    protected Filter[] getServletFilters() {
        // Post请求中文乱码处理:配置字符过滤器,为web容器添加过滤器并指定字符集,spring-web包中提供了专用的字符过滤器
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        return new Filter[]{filter};
    }
}
@Configuration
@ComponentScan({"com.clp.service"})
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class, MyBatisConfig.class})
@EnableTransactionManagement // 开启事务管理器
public class SpringConfig {
}
@Configuration
@ComponentScan({"com.clp.controller"})
@EnableWebMvc // 开启由json数据转换成对象的功能
public class SpringMvcConfig implements WebMvcConfigurer {
    @Autowired
    private ProjectInterceptor projectInterceptor;
    @Autowired
    private ProjectInterceptor2 projectInterceptor2;

    /**
     * 配置拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // addPathPatterns()方法的参数表示拦截的url字符串匹配则进行拦截
        // 拦截器链的执行顺序与添加顺序有关
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books", "/books/*");
        registry.addInterceptor(projectInterceptor2).addPathPatterns("/books", "/books/*");
    }
}
/*
 * @RestController:设置当前控制器类为RESTful风格,等同于@Controller与@ResponseBody两个注解组合功能。
 * @GetMapping & @PostMapping & @PutMapping & @DeleteMapping:
 *   设置当前控制器方法请求访问路径与请求动作,每种对应一个请求动作,例如@GetMapping对应GET请求。
 * */
//@Controller
//@ResponseBody
@RestController // @RestController = @Controller + @ResponseBody
@RequestMapping("/books")
public class BookController {
    @Autowired
    private BookService bookService;

    //    @RequestMapping(method = RequestMethod.POST)
    @PostMapping // @PostMapping = @RequestMapping(method = RequestMethod.POST)
    public Result post(@RequestBody Book book) {
        boolean flag = bookService.save(book);
        int i = 1 / 0;
        return new Result(flag ? Code.SAVE_OK : Code.SAVE_ERR, flag);
    }

    //    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    @DeleteMapping("/{id}") // @DeleteMapping("/{id}") = @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    public Result delete(@PathVariable Integer id) {
        boolean flag = bookService.delete(id);
        return new Result(flag ? Code.DELETE_OK : Code.DELETE_ERR, flag);
    }

    //    @RequestMapping(method = RequestMethod.PUT)
    @PutMapping // @PutMapping = @RequestMapping(method = RequestMethod.PUT)
    public Result put(@RequestBody Book book) {
        boolean flag = bookService.update(book);
        return new Result(flag ? Code.UPDATE_OK : Code.UPDATE_ERR, flag);
    }

    //    @RequestMapping(value = "/{id}}", method = RequestMethod.GET)
    @GetMapping("/{id}") // @GetMapping("/{id}") = @RequestMapping(value = "/{id}}", method = RequestMethod.GET)
    public Result get(@PathVariable Integer id) {
        Book book = bookService.getById(id);
        return new Result(
                book != null ? Code.GET_OK : Code.GET_ERR,
                book,
                book != null ? "查询成功" : "查询失败"
        );
    }

    //    @RequestMapping(method = RequestMethod.GET)
    @GetMapping // @GetMapping = @RequestMapping(method = RequestMethod.GET)
    public Result getAll() {
        List<Book> bookList = bookService.getAll();
        return new Result(
                bookList != null ? Code.GET_OK : Code.GET_ERR,
                bookList,
                bookList != null ? "查询成功" : "查询失败"
        );
    }
}

1.2、SpringBoot快速入门

1.2.1、创建SpringBoot项目

创建新模块,选择Spring初始化,并配置模块相关基础信息。然后选择当前模块需要使用的技术集。

1.2.2、开发控制器类

@RestController
@RequestMapping("/books")
public class BookController {
    @GetMapping("/{id}")
    public String getById(@PathVariable Integer id) {
        System.out.println("id: " + id);
        return "hello, springboot!";
    }
}

1.2.3、运行自动生成的Application类(引导类)

@SpringBootApplication
public class Springboot0101QuickstartApplication {

    public static void main(String[] args) {
        //生成可配置的容器对象
        ConfigurableApplicationContext ctx = SpringApplication.run(Springboot0101QuickstartApplication.class, args);
    }
}

1.3、最简SpringBoot程序所包含的基础文件

1、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.6.11</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.clp</groupId>
    <artifactId>module_01_quickstart</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>module_01_quickstart</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

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

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

实际开发:

  • 使用任意坐标时,仅书写GAV中的G和A,V由SpringBoot提供,除非SpringBoot未提供对应版本的V;
  • 如发生坐标错误,再指定Version(要小心版本冲突)。

2、Application类(引导类)

@SpringBootApplication
public class Module01QuickstartApplication {

    public static void main(String[] args) {
        SpringApplication.run(Module01QuickstartApplication.class, args);
    }
}

SpringBoot的引导类是Boot工程的执行入口,运行main()方法就可以启动项目;SpringBoot工程运行后初始化Spring容器,扫描引导类所在包加载bean。

1.4、Spring程序与SpringBoot程序对比

Spring程序与SpringBoot程序对比
类/配置文件 Spring SpringBoot
pom文件中的坐标 手工添加 勾选添加
web 3.0 配置类 手工制作
Spring/Spring MVC 配置类 手工制作
控制器 手工制作 手工制作

注意事项:基于idea开发SpringBoot程序需要确保联网且能够加载到程序框架结构。

1.5、SpringBoot项目打包运行

步骤:

  1. 对SpringBoot项目打包(执行Maven构建指令package);
  2. 执行启动指令:java -jar springboot.jar;

注意:jar支持命令行启动需要依赖maven插件支持,请确认打包时是否具有SpringBoot对应的maven插件:

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

1.6、SpringBoot内嵌tomcat

内嵌Tomcat服务器是SpringBoot辅助功能之一;内嵌Tomcat工作原理是将Tomcat服务器作为对象运行,并将该对象交给Spring容器管理;变更内嵌服务器思想是去除现有服务器,添加全新的服务器。

SpringBoot内嵌有三款服务器:

  • tomcat(默认):apache出品,粉丝多,应用面广,负载了若干较重的组件。
  • jetty:更轻量级,负载性能远不及tomcat。
  • undertow:undertow,负载性能勉强跑赢tomcat。

1.7、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 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.7.4</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
</project>

1、spring-boot-starter-parent

  • 开发SpringBoot程序要继承spring-boot-starter-parent,所有SpringBoot项目要继承的项目,定义了若干个坐标版本号(依赖管理,而非依赖),以达到减少依赖冲突的目的;
  • spring-boot-starter-parent中定义了若干依赖管理,各版本间存在着诸多坐标版本不同;
  • 继承parent模块可以避免多个依赖使用相同技术时出现依赖版本冲突;
  • 继承parent的形式也可以采用引入依赖的形式实现效果。

2、SpringBoot程序启动方式

@SpringBootApplication
public class Module01QuickstartApplication {

    public static void main(String[] args) {
        SpringApplication.run(Module01QuickstartApplication.class, args);
    }
}

 SpringBoot在创建项目时,采用jar的打包方式。SpringBoot的引导类是项目的入口,运行main()方法就可以启动项目。

3、可以使用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。

2、基础配置

2.1、属性配置

2.1.1、修改配置

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

  • application.properties;
    在./resource/application.properties中:
    用(什么技术就开什么配置)
    
    # 服务器的端口配置
    server.port=80
    
    # 修改banner(运行日志图标)
    #spring.main.banner-mode=off # 关闭运行日志图标
    #spring.banner.image.location=logo.png
    
    # 设置日志相关(设置启动日志)
    logging.level.root=debug
    logging.level.com.clp=warn
  • application.yml(常用);
    server:
      port: 80
  • application.yaml;
    server:
      port:80

不同配置文件中相同配置按照加载优先级相互覆盖,不同配置文件中不同配置全部保留。加载优先级:application.properties -> application.yml -> application.yaml

2.2、YMAL配置

yaml:YAML(YAML,Ain't Markup Language):一种数据序列化格式。优点:① 容易阅读;② 容易与脚本语言交互;③ 以数据为核心,重数据轻格式。

2.2.1、yaml语法规则

(核心规则:数据前面要加空格与冒号隔开):

  • 大小写敏感;
  • 属性层级关系使用多行描述,每行结尾使用冒号结束;
  • 使用缩进表示层级关系,同层级左侧对齐,只允许使用空格(不允许使用tab键);
  • 属性值前面添加空格(属性名与属性值之间用冒号+空格作为分隔);
  • # 表示注释。
    # 设置端口
    server:
      port: 80
    
    user:
      name: zhangsan
      age: 18
      
    users1:
      - name: zhangsan
        age: 18
      - name: lisi
        age: 17
      -
        name: wangwu
        age: 20
    
    users2: [{name: zhangsan, age: 17}, {name: lisi, age: 18}]
    
    a:
      d:
        name: zhangsan
        hobbies:
          - game
          - music
          - sleep 
        hobbies2: [game, music, sleep]

2.2.2、数据读取

使用@Value读取单个数据,属性名引用方式:${一级属性名.二级属性名...}

package com.clp.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/books")
public class BookController {
    /**
     * country: beijing
     */
    //读取yml数据中的单一数据
    @Value("${country}")
    private String country;

    /**
     * user0:
     *   name: zhangsan
     *   age: 18
     */
    @Value("${user0.name}")
    private String name;

    /**
     * users:
     *   - name: zhangsan
     *     age: 18
     *   - name: lisi
     *     age: 20
     * @return
     */
    @Value("${users[0].age}")
    private int age;

    @GetMapping
    public String getById() {
        System.out.println("springboot is running..");
        System.out.println("country: " + country);
        System.out.println("user.name: " + name);
        System.out.println("users[0].age: " + age);
        return "springboot is running...";
    }

}

封装全部数据到Environment对象:

package com.clp.controller;

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/books")
public class BookController {
    @Autowired //使用自动装配将application.yml中所有的数据封装到一个对象Environment中
    private Environment env;

    @GetMapping
    public String getById() {
        System.out.println("springboot is running..");
        System.out.println(env.getProperty("server.port"));
        return "springboot is running...";
    }
}

封装部分数据:(注意:封装类需要定义为Spring管理的bean,否则无法进行属性注入)

package com.clp;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * application.yml:
 * # 创建类,用于封装下面的数据
 * # 由spring帮我们去加载数据到对象中,一定要告诉spring加载这些信息
 * # 使用的时候从spring中直接获取信息使用
 * datasource:
 *   driver: com.mysql.jdbc.Driver
 *   url: jdbc:mysql://localhost/springboot_db
 *   username: root
 *   pasword: 123456
 *
 * 步骤:
 * 1、定义数据模型封装yaml文件中对应的数据(变量名要和键的名称一致)
 * 2、定义为spring管控的bean(使用@Component)
 * 3、指定加载的数据(使用@ConfigurationProperties)
 */
@Component
@ConfigurationProperties(prefix = "datasource") //指定加载的数据
public class MyDataSource {
    private String driver;
    private String url;
    private String username;
    private String password;

    public String getDriver() {
        return driver;
    }

    public void setDriver(String driver) {
        this.driver = driver;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "MyDataSource{" +
                "driver='" + driver + '\'' +
                ", url='" + url + '\'' +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}


package com.clp.controller;

import com.clp.MyDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/books")
public class BookController {
    @Autowired
    private MyDataSource myDataSource;

    @GetMapping
    public String getById() {
        System.out.println("springboot is running..");
        System.out.println("myDataSource: " +myDataSource);
        return "springboot is running...";
    }
}

2.2.3、yml文件中的变量引用

application.yml:

baseDir: C:\windows
# 使用${属性名}的方式引用数据
tempDir1: ${baseDir}\temp # \t不解析为制表符
# 使用双引号包裹的字符串,其中的转义字符可以生效
tempDir2: "${baseDir}\temp" # \t解析为制表符

2.3、多环境开发配置

多环境启动:application.yaml

spring:
    profiles:
        active: pro
---
spring: # 设置生产环境
    profiles: pro
server: # 生产环境具体参数设定
    port: 80
---
spring: # 设置开发环境
    profiles: dev
server: # 开发环境具体参数设定
    port: 81
---
spring: # 设置测试环境
    profiles: test
server: # 测试环境具体参数设定
    port:82

 带参数启动SpringBoot:java -jar spring.jar --spring.profiles.active=test

2.3.1、Maven与SpringBoot多环境兼容

1、Maven中设置多环境属性:

    <profiles>
        <profile>
            <id>dev_env</id>
            <properties>
                <profile.active>dev</profile.active>
            </properties>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
        </profile>
        <profile>
            <id>pro_env</id>
            <properties>
                <profile.active>pro</profile.active>
            </properties>
        </profile>
        <profile>
            <id>test_env</id>
            <properties>
                <profile.active>test</profile.active>
            </properties>
        </profile>
    </profiles>

2、SpringBoot中引用Maven环境:

spring:
    profiles:
        active: ${profile.active}
---
spring: # 设置生产环境
    profiles: pro
server: # 生产环境具体参数设定
    port: 80
---
spring: # 设置开发环境
    profiles: dev
server: # 开发环境具体参数设定
    port: 81
---
spring: # 设置测试环境
    profiles: test
server: # 测试环境具体参数设定
    port:82

3、执行Maven打包指令

Maven指令执行完毕后,生成了对应的包,其中类参与编译,但是配置文件并没有编译,而是复制到包中。

- 复制前:
spring:
    profiles:
        active: ${profile.active}
        
- 复制后
spring:
    profiles:
        active: ${profile.active}

解决思路:对于源码中非Java类的操作要求加载Maven对应的属性,解析${}占位符。如下:

                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                    <configuration>
                        <encoding>utf-8</encoding>
                        <useDefaultDelimiters>true</useDefaultDelimiters>
                    </configuration>
                </plugin>

2.3.2、配置文件分类

SpringBoot中4级配置文件:

  • 1级:file : config/application.yml  【最高】
  • 2级:file : application.yml
  • 3级:classpath: config/application.yml
  • 4级:classpath: application.yml  【最低】

作用:

  • 1级与2级留作系统打包后设置通用属性;
  • 3级与4级用于系统开发阶段设置通用属性。

3、整合第三方技术

3.1、整合JUnit

步骤:

  1. 导入对应的starter(创建工程时会自动导入);
            <!--默认导入测试相关模块-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            </dependencies>
  2. 测试类使用@SpringBootTest修饰;
  3. 使用自动装配的形式添加要测试的对象。

名称:@SpringBootTest

类型:测试类注解

位置:测试类定义上方

作用:设置JUnit加载的SpringBoot启动类

相关属性:classes:设置SpringBoot启动类。注意:如果测试类在SpringBoot启动类或子包中,可以省略启动类的设置,也就是省略classes的设定;测试类如果不存在于引导类所在的包或子包中需要通过classes属性指定引导类。

范例:

package com.clp;

import com.clp.dao.BookDao;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest(classes = Springboot03JunitApplication.class) //显式地写上引导类
class Springboot03JunitApplicationTests {
    /**
     * 测试步骤:
     * 1、注入你要测试的对象;
     * 2、执行要测试的对象对应的方法
     */
    @Autowired
    private BookDao bookDao;

    @Test
    void contextLoads() {
        bookDao.save();
    }
}

3.2、整合MyBatis

核心配置:数据库连接相关信息(连什么?连谁?什么权限?)

映射配置:SQL映射(XML/注解)

步骤:

  1. 创建新模块,选择Spring初始化,并配置模块相关基础信息;选择当前模块需要使用的技术集Dependencies(MyBatis Framework、MySQL Driver);
            <!-- SpringBoot 整合 MyBatis -->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
            <!-- 配置druid数据源 -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.16</version>
            </dependency>
  2. 数据库连接相关信息转换成配置。设置数据源参数(在application.yml中):
    spring:
      datasource: # 配置数据源
        type: com.alibaba.druid.pool.DruidDataSource # 配置数据源类型:druid数据源
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://${api-server.host}:3306/mydb?serverTimezone=UTC
        username: root
        password: 123456
  3. 数据库SQL映射需要添加@Mapper被容器识别到。定义数据层接口与映射配置:
    package com.clp.dao;
    
    import com.clp.domain.Book;
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Select;
    
    @Mapper
    public interface BookDao {
        @Select("select * from tbl_book where id = #{id}")
        public Book getById(Integer id);
    }

3.3、整合MyBatis-Plus

3.4、整合Druid

步骤:

  1. 导入Druid对应的starter;
            <!--导入druid相关依赖-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>1.2.6</version>
            </dependency>
  2. 配置对应的设置或采用默认配置。变更Druid的配置方式如下:
    # 方式1(推荐)
    spring:
      datasource:
        druid:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc.mysql://localhost:3306/mydb?serverTimezone=UTC
          username: root
          password: 123456
    
    # 方式2
    #spring:
    #  datasource:
    #    driver-class-name: com.mysql.jdbc.Driver
    #    url: jdbc:mysql://localhost:3306/mydb?serverTimezone=UTC
    #    username: root
    #    password: 123456
    #    type: com.alibaba.druid.pool.DruidDataSource

整合第三方技术的通用方式:① 导入对应的starter;② 根据提供的配置格式,配置非默认值对应的配置项。

4、基于SpringBoot的SSM整合案例

1、pom.xml:配置起步依赖,必要的资源坐标(druid);

2、application.yaml:设置数据源、端口等;

3、配置类:全部删除;

4、dao:设置@Mapper;

5、测试类

4、基于SpringBoot的SSMP整合案例

案例实现方案分析:

  1. 实体类开发——使用Lombok快速制作实体类;
  2. Dao开发——整合MyBatisPlus,制作数据层测试类;
  3. Service开发——基于MyBatisPlus进行增量开发,制作业务层测试类;
  4. Controller开发——基于Restful开发,使用PostMan测试接口功能;
  5. Controller开发——前后端开发协议制作;
  6. 页面开发——基于VUE+ElementUI制作,前后端联调,页面数据处理,页面消息处理(列表、新增、修改、删除、分页、查询);
  7. 项目异常处理;
  8. 按条件查询——页面功能调整、Controller修正功能、Service修正功能。

起步依赖:

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <artifactId>3.4.1</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

设置Jdbc参数(application.yml):

spring:
  datasource: # 配置数据源
    type: com.alibaba.druid.pool.DruidDataSource # 配置数据源类型:druid数据源
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://${api-server.host}:3306/mydb?serverTimezone=UTC
    username: root
    password: 123456

注意:如果使用Druid数据源,需要导入对应坐标:

        <!-- 配置druid数据源 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>

4.1、实体类快速开发

Lombok是一个Java类库,提供了一组注解,简化POJO实体类开发。

常用注解:

  • @Data:为当前实体类在编译期设置对应的get() / set()方法,toString()方法, hashCode()方法,equals()方法等。
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <scope>provided</scope>
        </dependency>

4.2、数据层开发

技术实现方案:MyBatisPlus、Druid。

步骤:

  1. 导入MyBatisPlus与Druid对应的starter:
            <!--因为在parent中没有维护下面这2个版本,所以需要手动加-->
            <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>
  2. 配置数据源与MyBatisPlus对应的配置。(application.yml):
    # 配置端口号
    server:
      port: 80
    # 配置druid数据源
    spring:
      datasource:
        druid:
          driver-class-name: com.mysql.jdbc.Driver
          url: jdbc:mysql://localhost:3306/db
          username: root
          password: 123456
    # 配置表前缀
    mybatis-plus:
      global-config:
        db-config:
          table-prefix: tbl_
          id-type: auto #设置自增策略,即执行insert语句时,id增加的方式
  3. 开发Dao接口,并继承BaseMapper并指定泛型:
    package com.clp.dao;
    
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.clp.domain.Book;
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Select;
    
    @Mapper
    public interface BookDao extends BaseMapper<Book> {
    //    /**
    //     * MyBatis的使用方式
    //     * @param id
    //     * @return
    //     */
    //    @Select("select * from tbl_book where id = #{id}")
    //    Book getById(Integer id);
    }

为了方便调试可以开启MyBatisPlus的日志:

# 配置表前缀
mybatis-plus:
  configuration:
    # 配置日志方式,设置日志输出方式为标准输出
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

4.2.1、分页

分页操作需要设定分页对象IPage。

    /**
     * 分页功能需要添加一个拦截器(使用配置类进行配置)
     */
    @Test
    void testGetPage() {
        IPage page = new Page(2, 5);
        // 使用IPage封装分页数据,分页操作依赖MyBatis分页拦截器实现功能
        IPage iPage = bookDao.selectPage(page, null); //ipage就是page

        System.out.println(iPage.getCurrent()); // 2 当前页码值
        System.out.println(iPage.getSize()); // 5
        System.out.println(iPage.getTotal()); // 16
        System.out.println(iPage.getPages()); // 4 页数
        System.out.println(iPage.getRecords()); //记录
    }

IPage对象中封装了分页操作中的所有数据:

  • 数据;
  • 当前页码值;
  • 每页数据总量;
  • 最大页码值;
  • 数据总量。

分页操作是在MyBatisPlus的常规操作基础上增强得到,内部是动态的拼写SQL语句,因此需要增强对应的功能,使用MyBatis拦截器实现。

/**
 * (配置类)
 */
@Configuration
public class MPConfig {
    /**
     * 配置MyBatisPlus拦截器,交给SpringBoot管理
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        //创建mybatis拦截器(壳)
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        //添加拦截器1(分页拦截器)
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}

4.2.2、条件查询

使用QueryWrapper对象封装查询条件,推荐使用LambdaQueryWrapper对象,所有查询操作封装成方法调用。查询条件支持动态条件封装。

MyBatisPlus将书写复杂的SQL查询条件进行了封装,使用编程的形式完成查询条件的组合。

/**
     * 条件查询
     */
    @Test
    void testGetBy() {
        // 方式1
        QueryWrapper<Book> qw = new QueryWrapper<>();
        //select * from tbl_book where name like 'a';
        qw.like("name", "a");
        List<Book> books = bookDao.selectList(qw);
        System.out.println(books);

        //方式2 使用Lambda表达式
        String name = "a";
        LambdaQueryWrapper<Book> lqw  = new LambdaQueryWrapper<Book>();
        //lqw.like(Book::getName, name);
        // 如果name不为null,则进行查询
        lqw.like(name != null, Book::getName, name);
        bookDao.selectList(lqw);
    }

    @Test
    void test() {
        // 查询结果包含模型中部分属性
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        lqw.select(User::getId, User::getName, User::getAge);
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);
        
        // 查询结果包含模型类中未定义的属性
        QueryWrapper<User> qw = new QueryWrapper<User>();
        qw.select("count(*) as nums, gender");
        qw.groupBy("gender");
        List<Map<String, Object>> maps = userDao.selectMaps(qw);
        System.out.println(maps);
    }

    @Test
    void test2() {
        // 用户登录(eq匹配)
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        lqw.eq(User::getName, userQuery.getName()).eq(User::getPassword, userQuery.getPassword());
        User loginUser = userDao.selectOne(lqw);
        System.out.println(loginUser);
        
        // 购物设定价格区间、户籍设定年龄区间(le ge匹配 或 between 匹配)
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        // 方案1:设定上限下限
        lqw.le(User::getAge, userQuery.getAge()).ge(User::getAge, userQuery.getAge2());
        // 方案2:设定范围
        lqw.between(User::getAge, userQuery.getAge(), userQuery.getAge2());
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);
        
        // 查信息、搜索新闻(非全文检索版:like匹配)
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        lqw.likeLeft(User::getTel, userQuery.getTel());
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);
        
        // 统计报表
        QueryWapper<User> qw = new QueryWrapper<User>();
        qw.select("gender", "count(*) as nums");
        qw.groupBy("gender");
        List<Map<String, Object>> maps = userDao.selectMaps(qw);
        System.out.println(maps);
    }
package com.clp.dao;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.clp.domain.Book;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
public class BookDaoTest1Case {
    @Autowired
    private BookDao bookDao;

    @Test
    void testGetById() {
        System.out.println(bookDao.selectById(1));
    }

    @Test
    void save() {
        Book book = new Book();
        book.setType("测试数据123");
        book.setName("测试数据123");
        book.setDescription("测试数据123");

        bookDao.insert(book);
    }

    @Test
    void testUpdate() {
        Book book = new Book();
        book.setId(17);
        book.setType("abcdefg");
        book.setName("测试数据123");
        book.setDescription("测试数据123");

        bookDao.updateById(book);
    }

    @Test
    void testDelete() {
        bookDao.deleteById(16);
    }

    @Test
    void testGetAll() {
        List<Book> books = bookDao.selectList(null);
        System.out.println(books);
    }

    /**
     * 分页功能需要添加一个拦截器(使用配置类进行配置)
     */
    @Test
    void testGetPage() {
        IPage page = new Page(2, 5);
        IPage iPage = bookDao.selectPage(page, null); //ipage就是page

        System.out.println(iPage.getCurrent()); // 2 当前页码值
        System.out.println(iPage.getSize()); // 5
        System.out.println(iPage.getTotal()); // 16
        System.out.println(iPage.getPages()); // 4 页数
        System.out.println(iPage.getRecords()); //记录
    }

    /**
     * 条件查询
     */
    @Test
    void testGetBy() {
        // 方式1
        QueryWrapper<Book> qw = new QueryWrapper<>();
        //select * from tbl_book where name like 'a';
        qw.like("name", "a");
        List<Book> books = bookDao.selectList(qw);
        System.out.println(books);

        //方式2 使用Lambda表达式
        String name = "a";
        LambdaQueryWrapper<Book> lqw  = new LambdaQueryWrapper<Book>();
        //lqw.like(Book::getName, name);
        // 如果name不为null,则进行查询
        lqw.like(name != null, Book::getName, name);
        bookDao.selectList(lqw);
    }
}

4.2.3、字段映射与表名映射

- 问题1:表字段与编码属性设计不同步。解决方案:
    名称:@TableField
    类型:属性注解
    位置:模型类属性定义上方
    作用:设置当前属性对应的数据库表中的字段关系
    范例:
        public class User {
            @TableField(value="pwd") // 对应的数据库字段名为 pwd
            private String password;
        }
    相关属性:
        value(默认):设置数据库表字段名称
        exist:设置属性在数据库表字段中是否存在,默认为true。此属性无法与value合并使用
        select:设置属性是否参与查询,此属性与select()映射配置不冲突
        
- 问题2:编码中添加了数据库中未定义的属性。解决方案:
    public class User {
        private Long id;
        private String name;
        @TableField(value="pwd");
        private String password;
        private Intager age;
        @TableField(exist=false)
        private Intager online;
    }
    
- 问题3:采用默认查询开放了更多的字段查看权限:SELECT id, name, pwd, age, tel, speciality FROM user
    public class User {
        private Long id;
        private String name;
        @TableField(value="pwd", select=false); // 设置该字段不参与查询
        private String password;
        private Intager age;
        @TableField(exist=false)
        private Intager online;
    }
    
- 问题4:表名与编码开发设计不同步。如表名为tbl_user,实体类名为User
    @TableName("tbl_user") // 设置对应的数据库表名
    public class User {
        private Long id;
        private String name;
        @TableField(value="pwd", select=false); // 设置该字段不参与查询
        private String password;
        private Intager age;
        @TableField(exist=false)
        private Intager online;
    }

4.2.4、id生成策略控制

不同的表应用不同的id生成策略:

  • 日志:自增(1,2,3,4,...);
  • 购物订单:特殊规则(FQ12345A415);
  • 外卖单:关联地区日期等信息(10 04 20200314 34 91);
  • 关系表:可省略id;
  • ...
@TableId(type = IdType.类型),类型有如下几类:
    AUTO(0):使用数据库id自增策略控制id
    NONE(1):不设置id生成策略
    INPUT(2):用户手工输入id
    ASSIGN_ID(3):雪花算法生成id(可兼容数值型与字符串型)
    ASSIGN_UUID(4):以UUID生成算法作为id生成策略

@TableName("tbl_user") // 设置对应的数据库表名
public class User {
    @TableId(type = IdType.AUTO) // 自动递增的id生成策略
    private Long id;
    private String name;
    @TableField(value="pwd", select = false); // 设置该字段不参与查询
    private String password;
    private Intager age;
    @TableField(exist=false)
    private Intager online;
}

4.2.5、多记录操作

- 按照主键删除多条记录
    List<Long> ids = Arrays.asList(new Long[]{2, 3});
    userDao.deleteBatchIds(ids);
- 根据主键查询多条记录
    List<Long> ids = Arrays.asList(new Long[]{2, 3});
    List<User> userList = userDao.selectBatchIds(ids);

4.2.6、逻辑删除

删除操作业务问题:业务数据从数据库中丢弃。

逻辑删除:为数据设置是否可用状态字段,删除时设置状态字段为不可用状态,数据保留在数据库中。

步骤:

  1. 数据库表中添加逻辑删除标记字段(如deleted字段);
  2. 实体类中添加对应字段,并设定当前字段为逻辑删除标记字段。
    @TableName("tbl_user") // 设置对应的数据库表名
    public class User {
        @TableId(type = IdType.AUTO) // 自动递增的id生成策略
        private Long id;
        private String name;
        @TableField(value="pwd", select = false); // 设置该字段不参与查询
        private String password;
        private Intager age;
        @TableField(exist=false)
        private Intager online;
        // @TableLogic(value = "0", delval = "1") // 不在配置文件中配置时的逻辑删除字段,标记挡墙记录是否被删除。标记为0为未删除,标记为1为逻辑删除
        @TableLogic() // 不指定value和delval的值,而是在配置文件中统一配置
        private Integer deleted;
    }
  3.  如果不想给每个value和delval定义值,可以在配置文件中统一配置逻辑删除字面值:
    mybatis-plus:
        global-config:
            db-config:
                logic-delete-field: deleted
                logic-not-deleted-value: 0
                logic-delete-value: 1

它实际会执行SQL语句:UPDATE tab_user SET deleted=1 WHERE id=? AND deleted=0

4.2.7、乐观锁

业务并发现象带来的问题:如秒杀业务。

步骤:

  1. 数据库表中添加锁标记字段;
  2. 实体类中添加对应字段,并设定当前字段为逻辑删除标记字段:
  3. @TableName("tbl_user") // 设置对应的数据库表名
    public class User {
        @TableId(type = IdType.AUTO) // 自动递增的id生成策略
        private Long id;
        private String name;
        @TableField(value="pwd", select = false); // 设置该字段不参与查询
        private String password;
        private Intager age;
        @TableField(exist=false)
        private Intager online;
        @TableLogic // 不指定value和delval的值,而是在配置文件中统一配置
        private Integer deleted;
        @Version
        private Integer version;
    }
  4. 需要配置乐观锁拦截器实现锁机制对应的动态SQL语句拼装:
    @Configuration
    public class MpConfig {
        @Bean
        public MybatisPlusInterceptor mpInterceptor() {
            // 1、定义Mp拦截器
            MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
            // 2、添加分页拦截器
            mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
            // 3、添加乐观锁拦截器
            mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
            return mpInterceptor;
        }
    }
  5. 使用乐观锁机制在修改前必须先获取到对应数据的version方可正常进行:
    @Test
    void testUpdate() {
        // 先查询数据,获取到version数据
        User user = userDao.selectById(1L);
        // 执行数据修改操作
        user.setName("Tom and Jerry");
        userDao.updateById(user);
    }

4.2.8、代码生成器

模板:MyBatisPlus提供。

数据库相关配置:读取数据库获取信息。

开发自定义配置:手工配置。

先导入所需坐标:

pom.xml:

    <!-- 代码生成器 -->
    <depedency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-generator</artifactId>
        <version>2.3</version>
    </depedency>
    <!-- velocity模板引擎 -->
    <dependency>
        <groupId>org.apache.velocity</groupId>
        <artifactId>velocity-engine-core</artifactId>
        <version>2.3</version>
    </dependency>
public class Generator {
    public static void main(String[] args) {
        // 1、获取代码生成器的对象
        AutoGenerator autoGenerator = new AutoGenerator();
        
        // 2、设置数据库相关配置
        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("123456");
        sutoGenerator.setDataSource(dataSource);
        
        // 3、设置全局配置
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setOutputDir(System.getProperty("user.dir") + "/project/src/main/java"); // 设置输出代码的位置
        globalConfig.setOpen(false); // 设置生成完毕后是否打开生成代码所在的目录
        globalConfig.setAuthor("xxx"); // 设置作者
        globalConfig.setFileOverride(true); // 设置是否覆盖原始生成的文件
        globalConfig.setMapperName("%sDao"); // 设置数据层接口名,%s为占位符,指代模块名称
        globalConfig.setIdType(IdType.ASSIGN_ID); // 设置Id生成策略
        autoGenerator.setGlobalConfig(globalConfig);
        
        // 4、设置包名相关配置
        PackageConfig packageInfo = new PackageConfig();
        packageInfo.setParent("com.itheima"); // 设置生成的包名,与代码所在位置不冲突,二者叠加组成完整路径
        packageInfo.setEntity("domain"); // 设置实体类包名
        packageInfo.setMapper("dao"); // 设置数据层包名
        autoGenerator.setPackageInfo(packageInfo);
        
        // 5、策略设置
        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig.setInclude("tbl_user"); // 设置当前参与生成的表名,参数为可变参数
        strategyConfig.setTablePrefix("tbl_"); // 设置数据库表的前缀名称,模块名 = 数据库名称 - 前缀名。例如:tbl_user => User
        strategyConfig.setRestControllerStyle(true); // 设置是否启用Rest风格
        strategyConfig.setVersionFieldName("version"); // 设置乐观锁字段名
        strategyConfig.setLogicDeleteFieldName("deleted"); // 设置逻辑删除字段名
        strategyConfig.setEntityLombokModel(true); // 设置是否启用lombok
        autoGenerator.setStrategy(strategyConfig);
        
        autoGenerator.execute();
        
    }
}

4.3、业务层开发

Service层接口定义和数据层接口定义具有较大区别,不要混用。Service接口名称定义成业务名称,并与Dao接口名称进行区分。

package com.clp.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.clp.domain.Book;

import java.util.List;

public interface BookService {
    Boolean save(Book book);
    Boolean update(Book book);
    Boolean delete(Integer id);
    Book getById(Integer id);
    List<Book> getAll();
    IPage<Book> getPage(int currentPage, int pageSize);
}
package com.clp.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.clp.dao.BookDao;
import com.clp.domain.Book;
import com.clp.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 该注解将该类定义成业务层对应的Bean
 */
@Service
public class BookServiceImpl implements BookService {
    @Autowired
    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.getById(id);
    }

    @Override
    public List<Book> getAll() {
        return bookDao.selectList(null);
    }

    @Override
    public IPage<Book> getPage(int currentPage, int pageSize) {
        IPage page = new Page(currentPage, pageSize);
        return bookDao.selectPage(page, null);
    }
}
package com.clp.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.clp.domain.Book;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
public class BookServiceTestCase {
    @Autowired
    private BookService bookService;

    @Test
    void testGetById() {
        Book book = bookService.getById(4);
        System.out.println(book);
    }

    @Test
    void save() {
        Book book = new Book();
        book.setType("测试数据123");
        book.setName("测试数据123");
        book.setDescription("测试数据123");

        bookService.save(book);
    }

    @Test
    void testUpdate() {
        Book book = new Book();
        book.setId(17);
        book.setType("abcdefg");
        book.setName("测试数据123");
        book.setDescription("测试数据123");

        bookService.update(book);
    }

    @Test
    void testDelete() {
        bookService.delete(16);
    }

    @Test
    void testGetAll() {
        List<Book> books = bookService.getAll();
        System.out.println(books);
    }

    /**
     * 分页功能需要添加一个拦截器(使用配置类进行配置)
     */
    @Test
    void testGetPage() {
        IPage iPage = bookService.getPage(2,5); //ipage就是page

        System.out.println(iPage.getCurrent()); // 2 当前页码值
        System.out.println(iPage.getSize()); // 5
        System.out.println(iPage.getTotal()); // 16
        System.out.println(iPage.getPages()); // 4 页数
        System.out.println(iPage.getRecords()); //记录
    }
}

4.3.1、业务层开发——快速开发

快速开发方案:

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

import com.baomidou.mybatisplus.extension.service.IService;
import com.clp.domain.Book;

public interface IBookService extends IService<Book> {

}
package com.clp.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.clp.dao.BookDao;
import com.clp.domain.Book;
import com.clp.service.IBookService;
import org.springframework.stereotype.Service;

@Service
public class IBookServiceImpl extends ServiceImpl<BookDao, Book> implements IBookService {
}

4.4、表现层开发

  1. 基于Resftul进行表现层接口开发;
  2. 使用Postman测试表现层接口功能。

实体数据:@RequestBody

路径变量:@PathVariable

package com.clp.controller;

import com.clp.domain.Book;
import com.clp.service.IBookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/books")
public class BookController {
    @Autowired
    private IBookService iBookService;

    @GetMapping
    public List<Book> getAll() {
        return iBookService.list();
    }
}
package com.clp.controller;

import com.clp.domain.Book;
import com.clp.service.IBookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/books")
public class BookController {
    @Autowired
    private IBookService iBookService;

    @GetMapping
    public List<Book> getAll() {
        return iBookService.list();
    }

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

    @PutMapping
    public Boolean update(@RequestBody Book book) {
        return iBookService.modify(book);
    }

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

    /**
     * http://localhost/books/2
     */
    @GetMapping("{id}")
    public Book getById(@PathVariable Integer id) {
        return iBookService.getById(id);
    }
}

4.4.1、表现层数据一致性处理

 

posted on 2022-09-18 15:47  啊噢1231  阅读(70)  评论(0编辑  收藏  举报

导航

回到顶部