写在前面

本文介绍如何通过SpringBoot+Mybatis来搭建一个电商系统的基本骨架,并以商品品牌管理为例来实现基本的CRUD操作,以及通过PageHelper实现分页查询。

使用的框架简介

SpringBoot

一个基于Spring的快速搭建Java企业级应用的开发框架。

Mybatis generator

Mybatis代码生成器,可根据数据库生成对应的model、mapper.xml、mapper接口以及Example,这样一般的单表查询不用再手写mapper。

PagerHelper

MyBatis分页插件,只需几行简单事务代码就能实现分页功能。如果你使用的是SpringBoot,那么只要整合了PagerHelper就自动整合了MyBatis:

1
2
3
4
5
PageHelper.startPage(pageNum, pageSize);
//之后进行查询操作将自动进行分页
List<PmsBrand> brandList = brandMapper.selectByExample(new PmsBrandExample());
//通过构造PageInfo对象获取分页信息,如当前页码,总页数,总条数
PageInfo<PmsBrand> pageInfo = new PageInfo<PmsBrand>(list);

Druid

阿里巴巴开源的数据库连接池,性能极佳,提供了多种特性和功能。

项目初始化

第一步,使用Maven新建一个名为myshop-all的项目:

第二步,删除其中的src目录,并修改其中的pom文件为如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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>

<groupId>com.kenbings.shop</groupId>
<artifactId>myshop-all</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>

<modules>
<module>shop-basic</module>
</modules>

</project>

第三步,在myshop-all目录下,使用spring Initializr构建工具构建一个SpringBoot的Web应用,名称为shop-basic的Module:

第四步,修改shop-basic这一web项目的pom文件内容为如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<?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.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.kenbings.shop</groupId>
<artifactId>shop-basic</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>shop-basic</name>
<description>项目骨架搭建</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--SpringBoot通用依赖模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--MyBatis分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.10</version>
</dependency>
<!--集成druid连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!-- MyBatis 生成器 -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.3</version>
</dependency>
<!--Mysql数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
</dependencies>

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

第五步,修改shop-basic这一web项目的application.yml配置文件为如下所示:

1
2
3
4
5
6
7
8
9
10
11
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: envy123
mybatis:
mapper-locations:
- classpath:mapper/*.xml
- classpath*:com/**/mapper/*.xml

第六步,新建com.kenbings.shop.shopbasic.common.api这两级目录,然后在api目录中新建IErrorCode接口:

1
2
3
4
5
6
7
8
/**
* 封装API的错误码
*/
public interface IErrorCode {
long getCode();

String getMessage();
}

新建ResultCode枚举类,需要实现之前的IErrorCode接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* 一些常用API操作码枚举类
*/
public enum ResultCode implements IErrorCode{
SUCCESS(200, "操作成功"),
FAILED(500, "操作失败"),
VALIDATE_FAILED(404, "参数检验失败"),
UNAUTHORIZED(401, "暂未登录或token已经过期"),
FORBIDDEN(403, "没有相关权限");

private long code;
private String message;

private ResultCode(long code, String message){
this.code = code;
this.message = message;
}

@Override
public long getCode() {
return code;
}

@Override
public String getMessage() {
return message;
}
}

新建CommonResult类,用于构建一个通用的返回对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/**
* 通用返回对象
*/
public class CommonResult<T> {
private long code;
private String message;
private T data;

public CommonResult(){}

public CommonResult(long code,String message,T data){
this.code = code;
this.message = message;
this.data = data;
}

/**
* 成功返回数据
* @param data 返回的数据
*/
public static <T> CommonResult<T> success(T data){
return new CommonResult<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(),data);
}

/**
* 成功返回数据
* @param data 返回的数据
*/
public static <T> CommonResult<T> success(T data,String message){
return new CommonResult<>(ResultCode.SUCCESS.getCode(), message,data);
}

/**
* 失败返回数据
* @param errorCode 返回的错误码
*/
public static <T> CommonResult<T> failed(IErrorCode errorCode){
return new CommonResult<>(errorCode.getCode(),errorCode.getMessage(),null);
}

/**
* 失败返回数据
* @param message 返回的提示信息
*/
public static <T> CommonResult<T> failed(String message){
return new CommonResult<>(ResultCode.FAILED.getCode(), message,null);
}

/**
* 失败返回结果
*/
public static <T> CommonResult<T> failed() {
return failed(ResultCode.FAILED);
}

/**
* 参数验证失败返回结果
*/
public static <T> CommonResult<T> validateFailed() {
return failed(ResultCode.VALIDATE_FAILED);
}

/**
* 参数验证失败返回结果
* @param message 提示信息
*/
public static <T> CommonResult<T> validateFailed(String message) {
return new CommonResult<T>(ResultCode.VALIDATE_FAILED.getCode(), message, null);
}

/**
* 未登录返回结果
*/
public static <T> CommonResult<T> unauthorized(T data) {
return new CommonResult<T>(ResultCode.UNAUTHORIZED.getCode(), ResultCode.UNAUTHORIZED.getMessage(), data);
}

/**
* 未授权返回结果
*/
public static <T> CommonResult<T> forbidden(T data) {
return new CommonResult<T>(ResultCode.FORBIDDEN.getCode(), ResultCode.FORBIDDEN.getMessage(), data);
}

public long getCode() {
return code;
}

public void setCode(long code) {
this.code = code;
}

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

public T getData() {
return data;
}

public void setData(T data) {
this.data = data;
}
}

新建CommonPage类,这是一个用于封装分页数据的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/**
* 分页数据封装类
*/
public class CommonPage<T> {
private Integer pageNum;
private Integer pageSize;
private Integer totalPage;
private Long total;
private List<T> list;

/**
* 将 PageHelper 分页后的list转换为分页信息
*/
public static <T> CommonPage<T> restPage(List<T> list){
CommonPage<T> commonPage = new CommonPage<>();
PageInfo<T> pageInfo = new PageInfo<>(list);
commonPage.setPageNum(pageInfo.getPageNum());
commonPage.setPageSize(pageInfo.getPageSize());
commonPage.setTotalPage(pageInfo.getPages());
commonPage.setTotal(pageInfo.getTotal());
commonPage.setList(pageInfo.getList());
return commonPage;
}

public Integer getPageNum() {
return pageNum;
}

public void setPageNum(Integer pageNum) {
this.pageNum = pageNum;
}

public Integer getPageSize() {
return pageSize;
}

public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}

public Integer getTotalPage() {
return totalPage;
}

public void setTotalPage(Integer totalPage) {
this.totalPage = totalPage;
}

public List<T> getList() {
return list;
}

public void setList(List<T> list) {
this.list = list;
}

public Long getTotal() {
return total;
}

public void setTotal(Long total) {
this.total = total;
}
}

第七步,新建com.kenbings.shop.shopbasic.config目录,在里面定义一个名为MyBatisConfig的类,用于设置动态生成的mapper接口的路径信息:

1
2
3
4
5
6
7
/**
* MyBatis配置类
*/
@Configuration
@MapperScan("com.kenbings.shop.shopbasic.mbg.mapper")
public class MyBatisConfig {
}

第八步,新建com.kenbings.shop.shopbasic.mbg目录,在里面定义一个名为CommentGenerator的类,它需要继承DefaultCommentGenerator类,用于自定义注释生成器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* 自定义注释生成器
*/
public class CommentGenerator extends DefaultCommentGenerator {
private boolean addRemarkComments = false;

/**
*设置用户配置的参数
*/
@Override
public void addConfigurationProperties(Properties properties) {
super.addConfigurationProperties(properties);
this.addRemarkComments = StringUtility.isTrue(properties.getProperty("addRemarkComments"));
}

/**
* 给字段添加注释
*/
@Override
public void addFieldComment(Field field, IntrospectedTable introspectedTable,
IntrospectedColumn introspectedColumn) {
String remarks = introspectedColumn.getRemarks();
//根据参数和备注信息来判断是否添加备注信息
if (addRemarkComments && StringUtility.stringHasValue(remarks)) {
addFieldJavaDoc(field, remarks);
}
}

/**
* 给model的字段添加注释
*/
private void addFieldJavaDoc(Field field, String remarks) {
//文档注释开始
field.addJavaDocLine("/**");
//获取数据库字段的备注信息
String[] remarkLines = remarks.split(System.getProperty("line.separator"));
for (String remarkLine : remarkLines) {
field.addJavaDocLine(" * " + remarkLine);
}
addJavadocTag(field, false);
//文档注释结束
field.addJavaDocLine(" */");
}
}

第九步,在mbg目录下新建一个名为Generator的类,用于执行MBG的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* 用于执行MBG的代码
*/
public class Generator {
public static void main(String[] args) throws Exception {
// MBG 执行过程中的警告信息
List<String> warnings = new ArrayList<String>();
//当生成的代码重复时,覆盖原代码
boolean overwrite = true;
//读取我们的 MBG 配置文件
InputStream inputStream = Generator.class.getResourceAsStream("/generatorConfig.xml");
ConfigurationParser configurationParser = new ConfigurationParser(warnings);
Configuration config = configurationParser.parseConfiguration(inputStream);
inputStream.close();

DefaultShellCallback callback = new DefaultShellCallback(overwrite);
//创建 MBG
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
//执行生成代码
myBatisGenerator.generate(null);
//输出警告信息
for (String warning : warnings) {
System.out.println(warning);
}
}
}

第十步,在resources目录下新建一个名为generatorConfig.xml的配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
<properties resource="generator.properties"/>
<context id="MySqlContext" targetRuntime="MyBatis3" defaultModelType="flat">
<property name="beginningDelimiter" value="`"/>
<property name="endingDelimiter" value="`"/>
<property name="javaFileEncoding" value="UTF-8"/>
<!-- 为模型生成序列化方法-->
<plugin type="org.mybatis.generator.plugins.SerializablePlugin"/>
<!-- 为生成的Java模型创建一个toString方法 -->
<plugin type="org.mybatis.generator.plugins.ToStringPlugin"/>
<!--可以自定义生成model的代码注释-->
<commentGenerator type="com.kenbings.shop.shopbasic.mbg.CommentGenerator">
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true"/>
<property name="suppressDate" value="true"/>
<property name="addRemarkComments" value="true"/>
</commentGenerator>
<!--配置数据库连接-->
<jdbcConnection driverClass="${jdbc.driverClass}"
connectionURL="${jdbc.connectionURL}"
userId="${jdbc.userId}"
password="${jdbc.password}">
<!--解决mysql驱动升级到8.0后不生成指定数据库代码的问题-->
<property name="nullCatalogMeansCurrent" value="true" />
</jdbcConnection>
<!--指定生成model的路径-->
<javaModelGenerator targetPackage="com.kenbings.shop.shopbasic.mbg.model" targetProject="shop-basic\src\main\java"/>
<!--指定生成mapper.xml的路径-->
<sqlMapGenerator targetPackage="com.kenbings.shop.shopbasic.mbg.mapper" targetProject="shop-basic\src\main\resources"/>
<!--指定生成mapper接口的的路径-->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.kenbings.shop.shopbasic.mbg.mapper"
targetProject="shop-basic\src\main\java"/>
<!--生成全部表tableName设为%-->
<table tableName="pms_brand">
<generatedKey column="id" sqlStatement="MySql" identity="true"/>
</table>
</context>
</generatorConfiguration>

第十一步,在resources目录下新建一个名为generator.properties的数据配置文件:

1
2
3
4
jdbc.driverClass=com.mysql.cj.jdbc.Driver
jdbc.connectionURL=jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
jdbc.userId=root
jdbc.password=envy123

第十二步,打开数据库,执行如下SQL语句:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
DROP DATABASE IF EXISTS shop;
CREATE DATABASE shop;
USE shop;
DROP TABLE IF EXISTS pms_brand;
CREATE TABLE `pms_brand` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`first_letter` varchar(8) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '首字母',
`sort` int DEFAULT NULL,
`factory_status` int DEFAULT NULL COMMENT '是否为品牌制造商:0->不是;1->是',
`show_status` int DEFAULT NULL,
`product_count` int DEFAULT NULL COMMENT '产品数量',
`product_comment_count` int DEFAULT NULL COMMENT '产品评论数量',
`logo` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '品牌logo',
`big_pic` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '专区大图',
`brand_story` text CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT '品牌故事',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=59 DEFAULT CHARSET=utf8mb3 COMMENT='品牌表';

此时我们项目的基本骨架如下所示:

第十三步,执行Generator类中的main方法,可以看到此时生成后的目录结构如下所示:

第十四步,新建com.kenbings.shop.shopbasic.service目录,并在里面新建一个名为PmsBrandService的接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public interface PmsBrandService {
/**
* 查询所有的品牌信息
*/
List<PmsBrand> listAllBrand();

/**
* 创建一个新品牌
*/
int createBrand(PmsBrand pmsBrand);

/**
* 修改一个品牌信息
*/
int updateBrand(Long id,PmsBrand pmsBrand);

/**
* 删除一个品牌
*/
int deleteBrand(Long id);

/**
* 分页查询品牌信息
*/
List<PmsBrand> listBrand(int pageNum, int pageSize);

/**
* 获取某个品牌信息
*/
PmsBrand getBrand(Long id);
}

第十五步,在之前的service目录中新建一个名为impl的目录,然后在impl目录中新建一个名为PmsBrandServiceImpl的类,注意这个类需要实现PmsBrandService接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@Service
public class PmsBrandServiceImpl implements PmsBrandService {
@Autowired
private PmsBrandMapper pmsBrandMapper;

@Override
public List<PmsBrand> listAllBrand() {
return pmsBrandMapper.selectByExample(new PmsBrandExample());
}

@Override
public int createBrand(PmsBrand pmsBrand) {
return pmsBrandMapper.insertSelective(pmsBrand);
}

@Override
public int updateBrand(Long id, PmsBrand pmsBrand) {
pmsBrand.setId(id);
return pmsBrandMapper.updateByPrimaryKeySelective(pmsBrand);
}

@Override
public int deleteBrand(Long id) {
return pmsBrandMapper.deleteByPrimaryKey(id);
}

@Override
public List<PmsBrand> listBrand(int pageNum, int pageSize) {
PageHelper.startPage(pageNum,pageSize);
return pmsBrandMapper.selectByExample(new PmsBrandExample());
}

@Override
public PmsBrand getBrand(Long id) {
return pmsBrandMapper.selectByPrimaryKey(id);
}
}

第十六步,新建com.kenbings.shop.shopbasic.controller目录,并在里面新建一个名为PmsBrandController的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/**
* 品牌管理Controller
*/
@RestController
@RequestMapping("/brand")
public class PmsBrandController {
@Autowired
private PmsBrandService pmsBrandService;

private static final Logger LOGGER = LoggerFactory.getLogger(PmsBrandController.class);

/**
* 查询所有的品牌信息
*/
@GetMapping("/listAll")
public CommonResult<List<PmsBrand>> getBrandList(){
return CommonResult.success(pmsBrandService.listAllBrand());
}

/**
* 创建一个新品牌
*/
@PostMapping("/create")
public CommonResult createBrand(@RequestBody PmsBrand pmsBrand){
CommonResult commonResult;
int count = pmsBrandService.createBrand(pmsBrand);
if(count==1){
commonResult = CommonResult.success(pmsBrand);
LOGGER.debug("品牌创建成功:{}",pmsBrand);
}else{
commonResult = CommonResult.failed("品牌创建失败");
LOGGER.debug("品牌创建失败:{}",pmsBrand);
}
return commonResult;
}

/**
* 修改一个品牌信息
*/
@PostMapping("/update/{id}")
public CommonResult updateBrand(@PathVariable("id") Long id, @RequestBody PmsBrand pmsBrandDTO, BindingResult result){
CommonResult commonResult;
if(result.hasErrors()){
commonResult = CommonResult.failed(result.getFieldError().getDefaultMessage());
return commonResult;
}
int count = pmsBrandService.updateBrand(id,pmsBrandDTO);
if(count==1){
commonResult = CommonResult.success(pmsBrandDTO);
LOGGER.debug("品牌修改成功:{}",pmsBrandDTO);
}else{
commonResult = CommonResult.failed("品牌修改失败");
LOGGER.debug("品牌修改失败:{}",pmsBrandDTO);
}
return commonResult;
}

/**
* 删除一个品牌
*/
@PostMapping("/delete/{id}")
public CommonResult deleteBrand(@PathVariable("id") Long id){
CommonResult commonResult;
int count = pmsBrandService.deleteBrand(id);
if(count==1){
commonResult = CommonResult.success(null);
LOGGER.debug("品牌删除成功:{}",id);
}else{
commonResult = CommonResult.failed("品牌修改失败");
LOGGER.debug("品牌删除失败:{}",id);
}
return commonResult;
}

/**
* 分页查询品牌信息
*/
@GetMapping("/list")
public CommonResult<CommonPage<PmsBrand>> listBrand(
@RequestParam(value = "pageNum",defaultValue = "1")Integer pageNum,
@RequestParam(value = "pageSize",defaultValue = "5")Integer pageSize
){
List<PmsBrand> pmsBrands = pmsBrandService.listBrand(pageNum, pageSize);
return CommonResult.success(CommonPage.restPage(pmsBrands));
}

/**
* 获取某个品牌信息
*/
@GetMapping("/{id}")
public CommonResult<PmsBrand> getBrand(@PathVariable("id")Long id){
return CommonResult.success(pmsBrandService.getBrand(id));
}

第十七步,启动项目入口类ShopBasicApplication,打开浏览器进行测试,这里以访问id为1的品牌为例进行说明。

在浏览器地址栏中输入http://localhost:8080/brand/1,可以看到浏览器显示如下信息:

这样关于项目的骨架搭建就完成了,后续学习如何接入Swagger-UI实现API文档的在线使用。本篇笔记源码,可以点击 这里 进行阅读。