实验:搭建Spring Boot+MyBatis-Plus后台
文章里用到的大部分图片是作业里直接复制过来的,所以有些图片看着很糊,不过也能看得出来要干什么(主要是懒得再截一遍了)。不过还是很抱歉的啦!・_・。
目录
实验内容
- 搭建Spring Boot后台,使用
Mapper
,Service
,Controller
三层架构。 - 使用
Mybatis-Plus
访问数据库。 - 必须用到
Mybatis-Plus
自带的增删改查功能,还有分页查询功能。
一、创建Spring Boot项目
正常来说是直接新建项目的,不过这里新建模块也是差不太多的,效果是一样的。右键项目并点击新建模块,选择Spring Boot
生成器快速创建模块,构建类型选择Maven
,如图1.1所示。
然后选择Spring Boot依赖项,因为是Web后端,所以要选择Web下的Spring Web依赖。本来一般来说是要安装SQL下的MyBatis
框架,但是我们要用到的是它的扩展版MyBatis-Plus
,所以这里就不加入到依赖项,在下一点进行手动添加依赖。然后就是添加我们要操作的数据库的驱动依赖,我用的数据库为MySQL,所以我还添加了SQL下的MySQL Driver
,如图1.2所示,点击创建后就成功创建了一个Spring Boot项目了。
创建好项目后,就会自动开始下载所需要的依赖到本地仓库,只需要等待它下载完即可。
二、安装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
更改的按钮,就会开始下载新依赖到本地仓库了。
三、配置连接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所示,然后点击下载驱动进行连接测试。
回到数据库窗口,先点击刷新,然后右键刚刚添加的数据源运行SQL脚本,对数据库进行创建、初始化表并插入一些初始数据,如图3.2所示。
我运行的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所示。
四、创建Mapper、Service和Controller三层架构
POJO
在创建这三个架构前,还需要创建一个跟数据库中person
表对应的实体类,有着一样的属性,其中还有Getter
和Setter
方法,其中设置了主键类型为自增长,跟数据库配置一致。另外,为了输出的数据能够符合JSON
数据格式,我重写了toString
方法。(觉得Getter
和Setter
方法有点多的,可以去了解一下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来说,还需要一个@Autowrie
的PersonMapper
属性,调用里面的方法操作数据库,最后添加一个@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-Plus
中Service
实现的对应方法为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所示。
回到IDEA并连接数据库,打开对应的数据表可以看到,确实成功新增了一个Person
,如图5.2所示。
2、测试通过ID获取Person
接着测试通过ID
获取Person
,请求为GET
请求,另外还需要在路径上补充查询参数,如图5.3所示,对比图5.2可以看到成功获取到ID
为1的Person
数据信息。
3、测试通过ID更新Person
然后测试通过ID
更新Person
,HTTP
请求类型为PUT
请求,用的也是请求体传参,所以需要写一个JSON
格式的数据,必须有ID
字段,加需要更新的字段。比如,将ID
为1的Person
的名字改成花生,但不更新age
,所以只传了ID
和name
,如图5.4所示。
回到IDEA并刷新数据表,可以发现更新成功,如图5.5所示,并且只更新了名字。
4、测试通过ID删除Person
接下来就是测试通过ID
删除Person
,请求类型为DELETE
请求,而这个用的是路径传参,如图5.6所示,删除ID
为7的Person
,当然直接把{id}
替换成对应id
也是同样的效果。
回到IDEA刷新数据表,对比图5.2可以发现确实成功删除了一开始加的那条数据,如图5.7所示。
5、测试分页查询Person
最后是分页查询,属于GET
请求,填写路径并加上对应的查询参数,如图5.8所示,与图5.7的数据对比以及返回的数据进行分析,成功实现了分页功能。
可能会遇到的问题
因与Maven
官方仓库连接不稳定导致依赖下载慢或下载失败的情况,然后缺少项目所需的依赖。
解决方法如下:使用镜像库进行下载依赖,避免与外网连接的不稳定,我修改的是阿里云公共仓库。具体是修改Maven
的settings.xml
文件,如下图所示,右键项目下的pom.xml
文件,然后移动到Maven
选项下,找到子菜单的创建/设置setting
选项打开。
并且打开IDEA 的中Maven
的设置,最后勾选settings.xml
的重写并应用,如下图所示。
此时,Maven
会自动重新解析所有Maven
项目的依赖并开始下载,若没有重新下载,需要先刷新Maven
项目,再手动依次运行Maven
生存期中的clean
和install
进行下载依赖,如下图所示,需要跳过测试是因为还没配置MySQL连接信息或没有进行其他配置,会报错导致构建失败,虽然没影响,但是会误判。
参考
官方文档
安装 | MyBatis-Plus
分页插件 | MyBatis-Plus
用到的软件
结语
文章里用到的大部分图片是作业里直接复制过来的,所以有些图片看着很糊,不过也能看得出来要干什么(主要是懒得再截一遍了)。
不过还是很抱歉的啦!(。・_・。)ノI’m sorry~
更多推荐
所有评论(0)