实验内容

  1. 搭建Spring Boot后台,使用MapperServiceController三层架构。
  2. 使用Mybatis-Plus访问数据库。
  3. 必须用到Mybatis-Plus自带的增删改查功能,还有分页查询功能。

一、创建Spring Boot项目

正常来说是直接新建项目的,不过这里新建模块也是差不太多的,效果是一样的。右键项目并点击新建模块,选择Spring Boot生成器快速创建模块,构建类型选择Maven,如图1.1所示。
在这里插入图片描述

图1.1 设置Spring Boot生成器

然后选择Spring Boot依赖项,因为是Web后端,所以要选择Web下的Spring Web依赖。本来一般来说是要安装SQL下的MyBatis框架,但是我们要用到的是它的扩展版MyBatis-Plus,所以这里就不加入到依赖项,在下一点进行手动添加依赖。然后就是添加我们要操作的数据库的驱动依赖,我用的数据库为MySQL,所以我还添加了SQL下的MySQL Driver,如图1.2所示,点击创建后就成功创建了一个Spring Boot项目了。
在这里插入图片描述

图1.2 添加初始依赖

创建好项目后,就会自动开始下载所需要的依赖到本地仓库,只需要等待它下载完即可。

二、安装MyBatis-Plus依赖

在图1.2的最上面,还有一个选择Spring Boot版本,我选择的是3.4.4也就是Spring Boot3,根据官方文档及构建方式,应该添加如下依赖。

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
    <version>3.5.11</version>
</dependency>

因为MyBatis-Plus自带的分页功能的jsqlparser 5.0+ 版本不再支持 jdk8了,MyBatis-Plus针对这个问题解耦了 jsqlparser 依赖。又因为我们需要用到这个分页查询的功能,所以还需要添加这个分页插件。另外,为了使主体和插件版本不冲突,使用了官方文档提供的方法,添加maven bom 来管理依赖,需要添加如下内容,作用就是同步版本,也就是说上面那行的<version>可以省略了。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-bom</artifactId>
            <version>3.5.11</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<version>中的版本选择确定的版本,如我写的3.5.11。然后是添加 jsqlparser 依赖来支持分页查询如下二选一。

<!-- jdk 11+ 引入可选模块 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-jsqlparser</artifactId>
</dependency>

<!-- jdk 8+ 引入可选模块 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-jsqlparser-4.9</artifactId>
</dependency>

而以上这些东西需要放在项目中pom.xml内,如图2.1所示,设置完后点击右上角同步Maven更改的按钮,就会开始下载新依赖到本地仓库了。
在这里插入图片描述

图2.1 添加依赖并同步Maven
如果这里遇到提示没有找到依赖,请移步到 可能会遇到的问题解决。

三、配置连接MySQL数据库

需要修改application.properties文件来确定项目连接数据库的配置,不过我们更喜欢使用层级分明的.yml.yaml文件,所以需要修改它的后缀,再对其内容进行修改。这个配置文件在项目的src/main/resources下,同路径下的其他两个文件夹对这个项目没有作用,可以删除。先修改配置文件名为application.yml后,再将内容修改后如下所示,具体配置根据自己的数据库进行修改。

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver # 连接操作MySQL数据库的类
    url: jdbc:mysql://localhost:3306/exp1 # 最后为数据库的名字
    username: root # 数据库用户名
    password: 123456 # 数据库密码

另外,还需要在MySQL中创建对应的数据库,以及接下来要用到的表,这里可以用Navicat进行连接配置,不过我选择在IDEA里对数据库进行操作,先在IDEA右侧找到数据库的窗口进入,然后点击加号添加数据源,填写信息如图3.1所示,然后点击下载驱动进行连接测试。
在这里插入图片描述

图3.1 配置并连接

回到数据库窗口,先点击刷新,然后右键刚刚添加的数据源运行SQL脚本,对数据库进行创建、初始化表并插入一些初始数据,如图3.2所示。
在这里插入图片描述

图3.2 运行SQL脚本

我运行的SQL脚本如下。

DROP DATABASE IF EXISTS exp1;
CREATE DATABASE exp1 CHARACTER SET utf8;

USE exp1;

CREATE TABLE person (
    id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100),
    age TINYINT UNSIGNED
) CHARSET=utf8;

INSERT INTO person (id, name, age) VALUES 
(null, '白眉鹰王', 55),
(null, '金毛狮王', 45),
(null, '青翼蝠王', 38),
(null, '紫衫龙王', 42),
(null, '光明左使', 37),
(null, '光明右使', 48);

在数据源添加架构为刚刚新建的exp1数据库,然后双击其中的person表打开是否创建/插入成功,如图3.3所示。
在这里插入图片描述

图3.3 数据库表插入初始数据成功

四、创建Mapper、Service和Controller三层架构

POJO

在创建这三个架构前,还需要创建一个跟数据库中person表对应的实体类,有着一样的属性,其中还有GetterSetter方法,其中设置了主键类型为自增长,跟数据库配置一致。另外,为了输出的数据能够符合JSON数据格式,我重写了toString方法。(觉得GetterSetter方法有点多的,可以去了解一下Lombok这个依赖,这里不做介绍)

package org.peanut.exp1.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;

public class Person {

    @TableId(type = IdType.AUTO)
    Integer id;
    String name;
    Integer age;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "{" +
                "\"id\":" + id +
                ",\"name\":\"" + name + "\"" +
                ",\"age\":" + age +
                "}";
    }
}

Mapper

创建实体类对应的Mapper,一般来说是继承MyBatis-Plus的Mapper<T>接口的,不过后面需要在Service中对里面的方法进行实现,但是其提供的方法已经够用了,所以这里继承的是BaseMapper<T>,里面的泛型为我们的实体类,如下所示。这里可以添加@Mapper注解来标识这个类为Mapper,但是也可以通过@MapperScan注解来确定Mapper所在的包,这样在这个包下都识别成Mapper了,一般是在项目的Application中添加这个注解,并填入mapper包。
不过,之后还要编写一个配置类,可以写在里面,就不需要写在Application里了。

package org.peanut.exp1.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
//import org.apache.ibatis.annotations.Mapper;
import org.peanut.exp1.pojo.Person;

//@Mapper
public interface PersonMapper extends BaseMapper<Person> {
}

Service

为了避免Controller直接对Mapper进行操作,这里需要先创建Service架构中对应能操作的接口如下所示,直接继承MyBatis-Plus的IService<T>接口。

package org.peanut.exp1.service;

import com.baomidou.mybatisplus.extension.service.IService;
import org.peanut.exp1.pojo.Person;

public interface IPersonService extends IService<Person> {
}

然后就是实现刚刚创建的IPersonService接口,对于原来的MyBatis来说,还需要一个@AutowriePersonMapper属性,调用里面的方法操作数据库,最后添加一个@Service注解就好了。而 MyBatis-Plus 就更简单了,只需要在实现接口的前提下再继承ServiceImpl<M, T>类就不用手动添加字段自动注入的Mapper了,不过也需要填加@Service注解,如下所示,这是为了能让IPersonService能在Controller中能够字段自动注入。

package org.peanut.exp1.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.peanut.exp1.mapper.PersonMapper;
import org.peanut.exp1.pojo.Person;
import org.peanut.exp1.service.IPersonService;
import org.springframework.stereotype.Service;

@Service
public class PersonServiceImpl extends ServiceImpl<PersonMapper, Person> implements IPersonService {
}

Controller

创建能够映射对应的路径到对应的方法的Controller类了,首先得有一个操作数据库的Service接口,如图4.6所示,对于Controller类,还需要一个@RestController注解来让Spring Boot识别到,而Service接口的字段注入是接口的实现类。

package org.peanut.exp1.controller;

import org.peanut.exp1.service.IPersonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
public class PersonController {

    @Autowired
    IPersonService personService;
}

接下来就是创建CRUD对应HTTP请求的方法。

1、新建Person的API方法

MyBatis-PlusService实现的对应方法为save,所以我们只需要创建一个方法来接收POST请求来的Person,又因为这个Person数据是通过请求体以JSON格式传参,所以还需要在方法参数前添加@RequestBody注解,最后将其传入接口的save方法,返回是否成功插入到数据库,方法如下所示,在方法上是对应的请求方法的@PostMapping注解和路径,这也是让Spring Boot能够识别并处理相应请求的。返回的内容改成了Json格式的,便于解析。

	@PostMapping("/person/save")
    public String save(@RequestBody Person person) {
        return "{" +
                "\"msg\":" + (personService.save(person) ? "\"保存成功\"" : "\"保存失败\"") +
                "}";
    }

2、通过ID获取Person的API方法

不一样的是这个是GET请求,以及用到的传参方式是查询传参,就是在路径后添加?后给对应变量赋值,需要添加@RequestParam注解确定查询的参数映射到方法参数中,如下所示,而@RequestMapping注解可以换成@GetMapping注解,这样更好区分请求类型。

	@RequestMapping("/person/getById")
    public String getById(@RequestParam("id") Integer id) {
        return "{" +
                "\"person\":" + personService.getById(id) +
                "}";
    }

3、通过ID更新Person的API方法

跟新建Person一样是请求体传参,不过请求方式是PUT请求,如下所示。

	@PutMapping("/person/updateById")
    public String update(@RequestBody Person person) {
        return "{" +
                "\"msg\":" + (personService.updateById(person) ? "\"更新成功\"" : "\"更新失败\"") +
                "}";
    }

4、通过ID删除Person的API方法

请求方式为DELETE请求,跟通过ID获取Person差不太多,不过用的是路径参数,需要@PathVariable注解说明是在路径中获取参数,以及需要在路径中的用花括号扩住这个参数变量名,如下所示。

    @DeleteMapping("/person/deleteById/{id}")
    public String deleteById(@PathVariable("id") Integer id) {
        return "{" +
                "\"msg\":" + (personService.removeById(id) ? "\"删除成功\"" : "\"删除失败\"") +
                "}";
    }

5、分页查询所有Person的API方法

请求属于GET请求,用的也是查询传参,另外参数和方法参数名一样,所以@RequestParam可以省略,又因为用了Mybatis-Plus的分页插件,所以调用也很简单,如图下所示,其中加入了页的相关信息方便调试。

    @GetMapping("/person/all/selectPage")
    public String selectPage(Integer pageNo, Integer pageSize) {
        Page<Person> page = new Page<>(pageNo, pageSize);
        personService.page(page, null);

        String msg = "数据总条数: " + page.getTotal() +
                ",当前页数为: " + page.getCurrent() +
                ",每页数据条数: " + page.getSize() +
                ",总页数为: " + page.getPages();

        return "{" +
                "\"msg\":\"" + msg + "\"" +
                ",\"persons\": " + page.getRecords() +
                "}";
    }
添加分页插件

如果到这里就开始测试API,除了分页查询,其他功能都是正常的,而分页查询只会将所有记录显示出来,并不会有分页的效果。所以在测试API前,只添加依赖是不够的,还需要编写配置类添加分页插件(具体见MyBatis-Plus官方文档),表示添加并使用这个插件,如图下所示,以及添加之前说的@MapperScan注解。

package org.peanut.exp1.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("org.peanut.exp1.mapper") // 记得改成自己Mapper所在的路径
public class MyBatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

整体

Controller类最后如下所示。

package org.peanut.exp1.controller;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.peanut.exp1.pojo.Person;
import org.peanut.exp1.service.IPersonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
public class PersonController {

    @Autowired
    IPersonService personService;

    @PostMapping("/person/save")
    public String save(@RequestBody Person person) {
        return "{" +
                "\"msg\":" + (personService.save(person) ? "\"保存成功\"" : "\"保存失败\"") +
                "}";
    }

    @RequestMapping("/person/getById")
    public String getById(@RequestParam("id") Integer id) {
        return "{" +
                "\"person\":" + personService.getById(id) +
                "}";
    }

    @PutMapping("/person/updateById")
    public String update(@RequestBody Person person) {
        return "{" +
                "\"msg\":" + (personService.updateById(person) ? "\"更新成功\"" : "\"更新失败\"") +
                "}";
    }

    @DeleteMapping("/person/deleteById/{id}")
    public String deleteById(@PathVariable("id") Integer id) {
        return "{" +
                "\"msg\":" + (personService.removeById(id) ? "\"删除成功\"" : "\"删除失败\"") +
                "}";
    }

    @GetMapping("/person/all/selectPage")
    public String selectPage(Integer pageNo, Integer pageSize) {
        Page<Person> page = new Page<>(pageNo, pageSize);
        personService.page(page, null);

        String msg = "数据总条数: " + page.getTotal() +
                ",当前页数为: " + page.getCurrent() +
                ",每页数据条数: " + page.getSize() +
                ",总页数为: " + page.getPages();

        return "{" +
                "\"msg\":\"" + msg + "\"" +
                ",\"persons\": " + page.getRecords() +
                "}";
    }
}

以及文件组织结构如下图所示,采用单包分层进行组织。
在这里插入图片描述

五、测试API接口

为了更加简单的测试,我使用Apipost这款软件进行测试的。

1、测试添加Person

首先是对添加Person进行测试,填入对应的请求路径,以及Person对应的请求体,因为ID是自增的,所以ID是可以省略的,发送POST请求后会收到响应信息,如图5.1所示。
在这里插入图片描述

图5.1 测试新增Person的API

回到IDEA并连接数据库,打开对应的数据表可以看到,确实成功新增了一个Person,如图5.2所示。
在这里插入图片描述

图5.2 新增Person成功

2、测试通过ID获取Person

接着测试通过ID获取Person,请求为GET请求,另外还需要在路径上补充查询参数,如图5.3所示,对比图5.2可以看到成功获取到ID为1的Person数据信息。
在这里插入图片描述

图5.3 测试通过ID获取Person的API

3、测试通过ID更新Person

然后测试通过ID更新PersonHTTP请求类型为PUT请求,用的也是请求体传参,所以需要写一个JSON格式的数据,必须有ID字段,加需要更新的字段。比如,将ID为1的Person的名字改成花生,但不更新age,所以只传了IDname,如图5.4所示。
在这里插入图片描述

图5.4 测试通过ID更新Person的API

回到IDEA并刷新数据表,可以发现更新成功,如图5.5所示,并且只更新了名字。
在这里插入图片描述

图5.5 更新Person的名字成功

4、测试通过ID删除Person

接下来就是测试通过ID删除Person,请求类型为DELETE请求,而这个用的是路径传参,如图5.6所示,删除ID为7的Person,当然直接把{id}替换成对应id也是同样的效果。在这里插入图片描述

图5.6 测试通过ID删除Person的API

回到IDEA刷新数据表,对比图5.2可以发现确实成功删除了一开始加的那条数据,如图5.7所示。
在这里插入图片描述

图5.7 删除Person成功

5、测试分页查询Person

最后是分页查询,属于GET请求,填写路径并加上对应的查询参数,如图5.8所示,与图5.7的数据对比以及返回的数据进行分析,成功实现了分页功能。
在这里插入图片描述

图5.8 测试分页查询所有Person的API

可能会遇到的问题

因与Maven官方仓库连接不稳定导致依赖下载慢或下载失败的情况,然后缺少项目所需的依赖。
解决方法如下:使用镜像库进行下载依赖,避免与外网连接的不稳定,我修改的是阿里云公共仓库。具体是修改Mavensettings.xml文件,如下图所示,右键项目下的pom.xml文件,然后移动到Maven选项下,找到子菜单的创建/设置setting选项打开。
在这里插入图片描述
并且打开IDEA 的中Maven的设置,最后勾选settings.xml的重写并应用,如下图所示。
在这里插入图片描述
此时,Maven会自动重新解析所有Maven项目的依赖并开始下载,若没有重新下载,需要先刷新Maven项目,再手动依次运行Maven生存期中的cleaninstall进行下载依赖,如下图所示,需要跳过测试是因为还没配置MySQL连接信息或没有进行其他配置,会报错导致构建失败,虽然没影响,但是会误判。
在这里插入图片描述

参考

官方文档

安装 | MyBatis-Plus
分页插件 | MyBatis-Plus

用到的软件

IntelliJ IDEA
Apipost-API

结语

文章里用到的大部分图片是作业里直接复制过来的,所以有些图片看着很糊,不过也能看得出来要干什么(主要是懒得再截一遍了)。
不过还是很抱歉的啦!(。・_・。)ノI’m sorry~

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐