SpringBoot+Vue项目实战

本文最后更新于:2 小时前

1 Spingboot+Vue 前后端分离实战项目

1.1 项目简介

采用 SpringBoot 3 + Vue 3 实现的前后端分离模版项目,集成多种技术栈,并且基于 JWT 校验方案。

1.2 项目地址

项目已上传至 Github 仓库,如有需要可自行下载使用。

1
2
3
4
5
6
url: https://github.com/Alleyf/SpingBoot-Vue/tree/master
title: "GitHub - Alleyf/SpingBoot-Vue: A Demo for SpringBoot with Vue."
description: "A Demo for SpringBoot with Vue. Contribute to Alleyf/SpingBoot-Vue development by creating an account on GitHub."
host: github.com
favicon: https://github.githubassets.com/favicons/favicon.svg
image: https://opengraph.githubassets.com/a9e35993db96532eecc54692cabfb8c305216983dce49278cab1b52a560daef6/Alleyf/SpingBoot-Vue

GitHub - Alleyf/SpingBoot-Vue: A Demo for SpringBoot with Vue.

1.3 后端功能

用户注册、用户登录、重置密码等基础功能以及对应接口

1.4 技术栈

  1. 前端
  • Vue 前端框架
  • ElementUI 前端 UI 组件库
  • Vue-Router 路由管理
  • Axios 异步请求框架
  • VueUse 适配黑暗模式
  • unplugin-auto-import 按需引入,减少打包后体积
  1. 后端
  • SpringBoot 后端框架
  • Mybatis 数据持久层框架
  • Redis 验证码存储、限流 IP、请求次数存储
  • Knife 4 j 接口文档生成
  • SpringSecurity 权限认证校验
  • JWT 生成 token 鉴权
  • RabbitMQ 积压邮件发送,由监听器统一处理
  • FastJson 后端统一用 Json 格式返回信息
  • Slf 4 j 日志打印实现

1.5 核心要点

1.5.1 限流

添加如下 filter,此处实现根据 ip 限流 3 秒内请求超过 10 次则限制访问 30 秒:

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
@Component  
@Order(Const.ORDER_LIMIT)
public class FlowLimitFilter extends HttpFilter {
@Resource
StringRedisTemplate stringRedisTemplate;
@Override
public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
String ip = request.getRemoteAddr();
if (this.limitFlowByIp(ip))
chain.doFilter(request, response);
else {
this.writeBlockMessage(response);
}
}
private void writeBlockMessage(HttpServletResponse response) throws IOException {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(Result.forbidden("操作频繁,请稍后再试").toJson());
}
/**
* 根据IP进行限流,同一IP三秒内超出10次拉入限流名单30秒 * * @param ip 限流IP
* @return 是否限流布尔值,为真则通过,为假则限制访问
*/ private boolean limitFlowByIp(String ip) {
synchronized (ip.intern()) {
String countKey = Const.FLOW_LIMIT_COUNT + ip;
String blockKey = Const.FLOW_LIMIT_BLOCK + ip;
if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(blockKey))) {
return false;
} else {
// ip限流检查
if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(countKey))) {
long increment = Optional.ofNullable(stringRedisTemplate.opsForValue().increment(countKey)).orElse(0L);
if (increment > 10) {
stringRedisTemplate.opsForValue().set(blockKey, "", 30, TimeUnit.SECONDS);
return false;
}
} else {
// 3s内连续请求将计数请求次数进行限流
stringRedisTemplate.opsForValue().set(countKey, "1", 3, TimeUnit.SECONDS);
}
return true;
}
}
}
}

1.5.2 接口文档

1.5.2.1 Swagger

springboot 3 使用 swagger 版本接口文档配置:

  1. pom. xml 引入依赖:
1
2
3
4
5
6
<!--    Swagger文档生成框架    -->
<dependency>
<groupId>org. springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.1.0</version>
</dependency>
  1. application. yml 配置静态资源:
1
2
3
4
springdoc:
paths-to-match: /api/**
swagger-ui:
operations-sorter: alpha
  1. SecurityConfiguration. java 设置接口文档相关静态资源放行:
1
2
3
4
5
6
return http
.authorizeHttpRequests (conf -> conf
.requestMatchers ("/api/auth/**", "/error"). permitAll ()
.requestMatchers ("/swagger-ui/**", "/v 3/api-docs/**"). permitAll ()
.anyRequest (). hasAnyRole (Const. ROLE_DEFAULT)
)
  1. 添加 SwaggerConfig. java swagger 相关配置文件:
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
/**
* Swagger 开发文档相关配置
*/
@Configuration
@SecurityScheme (type = SecuritySchemeType. HTTP, scheme = "Bearer",
name = "Authorization", in = SecuritySchemeIn. HEADER)
@OpenAPIDefinition (security = { @SecurityRequirement (name = "Authorization") })
public class SwaggerConfiguration {
/**
* 配置文档介绍以及详细信息
* @return OpenAPI
*/
@Bean
public OpenAPI springShopOpenAPI () {
return new OpenAPI ()
.info (new Info (). title ("示例项目 API 文档")
.description ("欢迎来到本示例项目 API 测试文档,在这里可以快速进行接口调试")
.version ("1.0")
.license (new License ()
.name ("项目开源地址")
.url (" https://github.com/Ketuer/SpringBoot-Vue-Template-Jwt" )
)
)
.externalDocs (new ExternalDocumentation ()
.description ("我们的官方网站")
.url (" https://itbaima.net" )
);
}
/**
* 配置自定义的 OpenApi 相关信息
* @return OpenApiCustomizer
*/
@Bean
public OpenApiCustomizer customerGlobalHeaderOpenApiCustomizer () {
return api -> this.authorizePathItems (). forEach (api.getPaths ()::addPathItem);
}
/**
* 登录接口和退出登录接口手动添加一下
* @return PathItems
*/
private Map<String, PathItem> authorizePathItems (){
Map<String, PathItem> map = new HashMap<>();
map.put ("/api/auth/login", new PathItem ()
.post (new Operation ()
.tags (List.of ("登录校验相关"))
.summary ("登录验证接口")
.addParametersItem (new QueryParameter ()
.name ("username")
.required (true)
)
.addParametersItem (new QueryParameter ()
.name ("password")
.required (true)
)
.responses (new ApiResponses ()
.addApiResponse ("200", new ApiResponse ()
.description ("OK")
.content (new Content (). addMediaType ("*/*", new MediaType ()
.example (RestBean.success (new AuthorizeVO ()). asJsonString ())
))
)
)
)
);
map.put ("/api/auth/logout", new PathItem ()
.get (new Operation ()
.tags (List.of ("登录校验相关"))
.summary ("退出登录接口")
.responses (new ApiResponses ()
.addApiResponse ("200", new ApiResponse ()
.description ("OK")
.content (new Content (). addMediaType ("*/*", new MediaType ()
.example (RestBean.success ())
))
)
)
)
);
return map;
}
}

1.5.2.2 knife4j

springboot 3 使用 knife 4.1.0 版本接口文档配置:

  1. pom. xml 引入依赖:
1
2
3
4
5
6
<!--        knife4j-->  
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>4.1.0</version>
</dependency>
  1. application. yml 配置静态资源:
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
--- #knife4j 接口文档配置  
springdoc:
swagger-ui:
# 访问路径
path: /swagger-ui.html
# 标签排序
tags-sorter: alpha
# 操作排序
operations-sorter: alpha
# api文档配置
api-docs:
# 访问路径
path: /v3/api-docs
# 组配置
group-configs:
# 组
- group: 'default'
# 匹配路径
paths-to-match: '/**'
# 扫描包
packages-to-scan: com.csdc.mshdcf
# knife4j的增强配置,不需要增强可以不配
knife4j:
# 是否开启
enable: true
# 设置
setting:
# 语言
language: zh_cn
  1. SecurityConfiguration. java 设置接口文档相关静态资源放行:

    1
    2
    3
    4
    5
    6
    7
    return http  
    .authorizeHttpRequests (conf -> {
    //配置请求路径,允许所有请求
    conf.requestMatchers ("/api/auth/**", "/error", "/doc. html", "/webjars/**", "/v 3/api-docs/**"). permitAll ()
    //其他请求需要认证
    .anyRequest (). authenticated ();
    })
  2. 添加 Knife 4 jConfig. java knife 4 j 相关配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration  
public class Knife4jConfig {
@Bean
public OpenAPI springShopOpenApi() {
return new OpenAPI()
.info(new Info().title("MSHDCF")
.description("多源异构数据汇聚融合接口文档")
.version("v 1")
.license(new License().name("Apache 2.0").url(" https://springdoc.org")))
.externalDocs(new ExternalDocumentation()
.description("外部文档")
.url(" https://springshop.wiki.github.org/docs"));
}
}

swagger访问地址为: http://localhost:8081/swagger-ui/index.html
knife4j访问地址为: http://localhost:8081/doc.html


1.5.3 踩坑

  1. redis 本地安装好需要修改配置文件设置 requirepass password 密码,才可以在 idea 里远程连接使用。

  2. vue 中的 form 表单一定要动态绑定 :model,如果添加了字段验证 :rules,还必须为每个 el-form-item 指定 propmodel 的键。

  3. RabbitMQ 必须为监听器添加@Component 注解才能自动注入的交换机和队列 bean 添加并绑定起来,否则 RabbitConfiguration 配置类不生效

  4. RabbitMQ 发送 Map等复杂消息时,需要添加(反)序列化消息转换器,否则刷屏消息转换报错,添加消息转换器步骤如下:

    • 添加 jackson 依赖:
    1
    2
    3
    4
    5
       <!--        jackson-->  
    <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    </dependency>
    • MailQueueListener 中注册 MessageConverter bean:
    1
    2
    3
    4
    5
         @Bean  
    public MessageConverter messageConverterer () {
    // 创建一个 Jackson 2 JsonMessageConverter 对象
    return new Jackson 2 JsonMessageConverter ();
    }
  5. Bean 不要被循环或重复导入。

  6. 使用 mybatis 时由于没有给 DTO 实体的属性添加与数据表对应的字段注释,因此属性名必须与字段名一致。

  7. @RequestParam 一般用于 Get 请求路径传参,@RequestBody 一般用于 Post 请求 Json 传递请求体数据(也可以用@RequestParam 传参但必须请求头注明 url 编码或者表单格式)。

  8. 内部结束 setInterval 定时器:

    1
    2
    const coldTimer = setInterval (() => {  
    coldTime. value > 0 ? coldTime. value-- : clearInterval (coldTimer) }, 1000)
  9. fastjson 2 在使用时,要注意返回 json 格式化的工具类 Result 必须加上 @Data、@AllArgsConstructor 注解才能使用,否则返回的 json 格式化数据一直为空(null)

  10. SpringBoot 从 2.5. x 版本后开始支持 java17,采用 java17 才能使用 Map/List.of 快速创建哈希表或列表,才能在服务处显示端口号并且开启 Actuator 后可以查看 Actuator 运行状态

  11. test 测试类一定要和 src>main>java 下的软件包同名的软件包下,否则会找不到配置类报错。

  12. springboot 最大并发数:SpringBoot 最大连接数及最大并发数是多少??? - 知乎

1
2
3
4
url: https://zhuanlan.zhihu.com/p/654602186
title: "SpringBoot 最大连接数及最大并发数是多少???"
description: "每个 Spring Boot 版本和内置容器不同,结果也不同,这里以 Spring Boot 2.7.10 版本 + 内置 Tomcat 容器举例。概序在 SpringBoot 2.7.10 版本中内置 Tomcat 版本是 9.0.73,SpringBoot 内置 Tomcat 的默认设置如下: Tomcat 的…"
host: zhuanlan. zhihu. com

1.6 效果

1.6.1 首页

image.png

1.6.2 注册

image.png

1.6.3 重置密码

image.png

1.6.4 黑暗模式

image.png

1.7 未来计划

  • 实现用户管理
  • 实现权限管理
  • 实现菜单管理
  • 实现日志管理
  • 发挥想象,完善为一个有创意的平台

1.8 Reference

1
2
3
4
url: https://itbaima.net/
title: "柏码 - 让每一行代码都闪耀智慧的光芒!"
host: itbaima.net
favicon: /favicon.ico

柏码 - 让每一行代码都闪耀智慧的光芒!


SpringBoot+Vue项目实战
https://alleyf.github.io/2026/03/0fe45fd783f7.html
作者
fcs
发布于
2026年3月8日
更新于
2026年3月8日
许可协议