【Springboot3+vue3】从零到一搭建Springboot3+vue3前后端分离项目,整合knef4j和mybaits实现基础用户信息管理
- 后端环境搭建
跟着黑马敲了黑马点评和苍穹外卖,但是感觉黑马教程封装的太好了。于是想自己从零到一搭建一个前后端分离的简单项目。
主要参考的博客为:
从零搭建SpringBoot3+Vue3前后端分离项目基座,中小项目可用_springboot+vue3-CSDN博客
记录一下自己的实现过程。
最终实现效果如下:

后端环境搭建
1.1 环境准备
-spring-boot3 最低支持jdk17,所以需要准备jdk17的环境
-Idea版本 2024.1.4
-Mysql8
1.2 数据库表准备
可以随便使用一个数据库可视化软件,然后创建数据库data_demo,并运行以下查询,创建用户表
我用的是Navicat Premium


建好后,选中数据库,右键选择新建查询
运行如下命令,创建数据库表
CREATE TABLE user(
id INT NOT NULL AUTO_INCREMENT COMMENT '主键',
login_name VARCHAR(255) NOT NULL COMMENT '登录名(账号)',
password VARCHAR(255) NOT NULL COMMENT '密码',
name varchar(50) NOT NULL COMMENT '姓名',
sex char(1) NOT NULL COMMENT '性别',
phone VARCHAR(20) COMMENT '联系电话',
PRIMARY KEY(id)
)COMMENT '用户信息表';
1.3 SpringBoot3项目创建



之后等待项目构建完成。构建完成的pom.xml文件如下,注意我在这里修改了spring的version,修改为3.3.3 ,因为在后面集成knef4j的时候发现3.4.0版本的spring无法显示接口。
参考博客如下:
尚硅谷新SSM教程中关于Knife4j 接口文档无法显示接口的问题_knife4j 识别不到controller-CSDN博客
即,正确的启动控制台没问题,但是不显示接口信息,后面将spring的版本降为3.3.3,成功解决
4.0.0
org.springframework.boot
spring-boot-starter-parent
3.3.3
com.myProject
demo
0.0.1-SNAPSHOT
demo
demo
17
org.springframework.boot
spring-boot-starter-web
com.mysql
mysql-connector-j
runtime
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin
1.4 MySql环境整合,使用druid连接池
在pom.xml中添加jdbc依赖,防止项目启动时找不到Bean报错
org.springframework.boot
spring-boot-starter-jdbc
添加druid依赖
com.alibaba
druid-spring-boot-3-starter
1.2.20
项目使用yml格式配置文件,修改resources下的application.properties为application.yml,删除文件原本内容,并将application.yml文件内容加上如下
配置项目端口号
server:
port: 9999
在application.yml中配置数据源和druid连接池 ,注意将database的name修改为自己数据库的名称,以及mysql的username和password
# ???????
database:
name: data_demo
spring:
datasource: #????
url: jdbc:mysql://localhost:3306/${database.name}?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: root
启动项目, 查看日志,端口和druid 初始化, 整合成功

1.5 整合mybatis-plus
1.5.1 引入mybaties-plus
官网地址: https://baomidou.com/
pom.xml中添加如下依赖
com.baomidou mybatis-plus-spring-boot3-starter 3.5.5application.yml中加入如下配置
mybatis ???
mybatis-plus:
configuration:
#???
map-underscore-to-camel-case: truemapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.demo
启动项目,出现mybatis-plus日志

1.5.2 配置代码生成器
pom.xml中添加如下依赖
com.baomidou mybatis-plus-generator 3.5.5 org.springframework.boot spring-boot-starter-freemarker
2.新建utils包,并在下边创建MybatisPlusGenerator.java代码生成器配置类

package com.example.demo.utils;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.io.File;
import java.sql.Types;
import java.util.Collections;
public class MybatisPlusGenerator {
static final String url = "jdbc:mysql://127.0.0.1:3306/data_demo?serverTimezone=UTC"; // 数据库地址
static final String username = "root"; // 数据库用户名
static final String password = "123456"; // 数据库密码
static final String authorName = "HuaXiang"; // 作者名
static final String parentPackageNameResource = "com/example/demo"; // mapper.xml路径
static final String parentPackageNameJava = "com.example.demo"; // java 文件父包名
// 要生成代码对应的数据表名
static final String tableName = "user";
public static void main(String[] args) {
FastAutoGenerator.create(url, username, password)
// 1.全局配置
.globalConfig(builder -> {
builder.author(authorName) // 设置作者
.enableSpringdoc() // 开启 swagger 模式
// 获取当前工程路径并定位到项目java目录下
.outputDir(System.getProperty("user.dir") + "/src/main/java"); // 指定输出目录
})
// 2.数据源配置
.dataSourceConfig(builder -> builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
int typeCode = metaInfo.getJdbcType().TYPE_CODE;
if (typeCode == Types.SMALLINT) {
// 自定义类型转换
return DbColumnType.INTEGER;
}
return typeRegistry.getColumnType(metaInfo);
}))
// 3.包名策略配置
.packageConfig(builder -> {
builder.parent(parentPackageNameJava) // 设置父包名
.entity("entity")
.mapper("mapper")
.service("service")
.serviceImpl("service.impl")
.controller("controller")
//.moduleName("system") // 设置父包模块名
.pathInfo(Collections.singletonMap(OutputFile.xml, System.getProperty("user.dir") + "/src/main/resources/" + "/mapper")); // 设置mapperXml生成路径
})
// 策略配置
.strategyConfig(builder -> {
builder.addInclude(tableName) // 设置需要生成的表名
// 覆盖已生成文件
.entityBuilder().enableFileOverride()
.mapperBuilder().enableFileOverride()
.serviceBuilder().enableFileOverride().formatServiceFileName("%sService");
//.addTablePrefix("t_", "c_"); // 设置过滤表前缀
})
// 配置模板
.templateConfig(builder -> {
//builder.controller(""); // 不生成controller
})
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
.execute();
}
}
- 修改数据库相关信息
- 修改authorName
- 修改parentPackageNameResource, parentPackageNameJava
- 修改tableName, 要生成代码的数据表名称,多个表使用,分割
- .enableSpringdoc() 可以选择,生成swagger3文档注释
修改完成后运行main函数,生成相应代码,mapper.xml在resource下与java同路径下
运行后目录如下:

1.5.3 配置分页插件
新建config包,并在下边配置类MybatiesPlusConfig.java

package com.example.demo.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
public class MybatisPlusConfig {
/**
* 添加分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//如果配置多个插件,切记分页最后添加
//interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType
return interceptor;
}
}
在启动类配置扫描mapper路径@MapperScan(“com.example.demo.mapper”)

1.6 整合swagger3(knife4j)
1.6.1 整合
pom.xml引入knife4j的依赖
com.github.xiaoymin knife4j-openapi3-jakarta-spring-boot-starter 4.5.0 application.yml中添加配置
springdoc-openapi 配置
springdoc:
swagger-ui:
path: /swagger-ui.html
tags-sorter: alpha
operations-sorter: alpha
api-docs:
path: /v3/api-docs
group-configs:
- group: ‘default’
paths-to-match: ‘/**’
packages-to-scan: com.example.demo.controllerknife4j 配置
knife4j:
是否启用增强
enable: true
开启生产环境屏蔽
production: false
是否认证登录
basic:
# basic是否开启,默认为false
enable: true
username: root
password: 123456
setting:
language: zh_cn
enable-version: true
enable-swagger-models: true测试。配置完成后,访问路径:http://localhost:9999/doc.html ,用户名密码为配置文件中的用户名和密码,如图

1.6.2 使用
实体类使用@Schema注解,在mybatis-plus选择的话会自动生成

Controller层使用
/**
*
* 用户信息表 前端控制器
*
* @since 2024-12-06
*/
@Tag(name = "用户接口")
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
/**
* 用户列表分页
* @param pageSize 每页显示的条数
* @param currentPage 要查询的页
* @param name 用户姓名
* @return Result>>
*/
@GetMapping("/pageList")
@Operation(summary = "用户列表分页查询")
@Parameters({
@Parameter(name = "Authorization", in = ParameterIn.HEADER, required = true, description = "token"),
@Parameter(name = "pageSize", required = true, description = "每页显示的条数"),
@Parameter(name = "currentPage", required = true, description = "要查询的页"),
@Parameter(name = "name", description = "用户姓名", required = false)
})
public Result> pageList(@RequestParam int pageSize, @RequestParam int currentPage, @Nullable @RequestParam String name) {
IPage page = userService.pageList(pageSize, currentPage, name);
if (page == null) {
return Result.error("查询失败");
}
//PageResultBean pageResultBean = new PageResultBean(page.getTotal(), page.getRecords());
return Result.success(PageResultBean.getInstance(page.getTotal(), page.getRecords()));
}
}

1.7 数据交互处理
1.7.1响应数据封装(公共返回数据类)
封装返回数据封装类,放到common包下:

package com.example.demo.common;
import io.swagger.v3.oas.annotations.media.Schema;
public class Result {
@Schema(description = "业务状态码 1:成功 0: 失败")
private int code; // 业务状态码 0:成功 1: 失败
@Schema(description = "提示信息")
private String message; // 提示信息
@Schema(description = "返回数据")
private T data; // 响应数据
public Result(int code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
// 操作成功返回响应结果(带响应数据)
public static Result success(E data) {
return new Result<>(1, "操作成功", data);
}
public static Result success() {
return new Result<>(1, "操作成功", null);
}
public static Result error(String message) {
return new Result<>(0, message, null);
}
public int getCode() {
return code;
}
public void setCode(int 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;
}
@Override
public String toString() {
return "Result{" +
"code=" + code +
", message='" + message + ''' +
", data=" + data +
'}';
}
}
1.7.2 分页查询返回数据封装
封装分页查询的数据,放到common包下

package com.example.demo.common;
import io.swagger.v3.oas.annotations.media.Schema;
public class Result {
@Schema(description = "业务状态码 0:成功 1: 失败")
private int code; // 业务状态码 0:成功 1: 失败
@Schema(description = "提示信息")
private String message; // 提示信息
@Schema(description = "返回数据")
private T data; // 响应数据
public Result(int code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
// 操作成功返回响应结果(带响应数据)
public static Result success(E data) {
return new Result<>(0, "操作成功", data);
}
public static Result success() {
return new Result<>(0, "操作成功", null);
}
public static Result error(String message) {
return new Result<>(1, message, null);
}
public int getCode() {
return code;
}
public void setCode(int 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;
}
@Override
public String toString() {
return "Result{" +
"code=" + code +
", message='" + message + ''' +
", data=" + data +
'}';
}
}
1.8 全局异常处理
创建exception包,在包下放全局异常处理类GlobalExceptionHandler.java,

使用springboot @RestControllerAdvice注解配置
package com.example.demo.exception;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import com.example.demo.common.Result;
// 全局异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {
private final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(Exception.class)
public Result handlerException(Exception e) {
logger.warn(e.getMessage());
return Result.error(StringUtils.hasLength(e.getMessage()) ? e.getMessage() : "操作失败");
}
}
1.9 整合JWT,生成token
pom.xml 中引入依赖
com.auth0 java-jwt 4.4.0封装工具类JwtUtil,放到utils包下
package com.example.demo.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;import java.util.Date;
import java.util.Map;public class JwtUtil {
private static final String KEY = “Demo”; // 密钥// 接收数据,生成token并返回 public static String getToken(Mapclaims) { return JWT.create() .withClaim("claims", claims) .withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60)) // 失效时间1小时 .sign(Algorithm.HMAC256(KEY)); } // 接收token,验证并返回数据 public static Map parseToken(String token) { return JWT.require(Algorithm.HMAC256(KEY)) .build() .verify(token) .getClaim("claims") .asMap(); } }
1.10 封装ThreadLocal工具类
因为前后端分离,使用ThreadLocal线程变量存储用户登录信息,替代session
package com.example.demo.utils;
public class ThreadLocalUtil {
// 提供ThreadLocal 对象
private static final ThreadLocal
浙公网安备 33010602011771号