采用SpringBoot3 + Vue3编写的前后端分离模版项目,集成多种技术栈,使用JWT校验方案。
用户注册、用户登录、重置密码等基础功能以及对应接口
- 采用Mybatis-Plus作为持久层框架,使用更便捷
- 采用Redis存储注册/重置操作验证码,带过期时间控制
- 采用RabbitMQ积压邮件发送任务,再由监听器统一处理
- 采用SpringSecurity作为权限校验框架,手动整合Jwt校验方案
- 采用Redis进行IP地址限流处理,防刷接口
- 视图层对象和数据层对象分离,编写工具方法利用反射快速互相转换
- 错误和异常页面统一采用JSON格式返回,前端处理响应更统一
- 手动处理跨域,采用过滤器实现
- 使用Swagger作为接口文档自动生成,已自动配置登录相关接口
- 采用过滤器实现对所有请求自动生成雪花ID方便线上定位问题
- 针对于多环境进行处理,开发环境和生产环境采用不同的配置
- 日志中包含单次请求完整信息以及对应的雪花ID,支持文件记录
- 项目整体结构清晰,职责明确,注释全面,开箱即用
用户注册、用户登录、重置密码等界面,以及一个简易的主页
- 采用Vue-Router作为路由
- 采用Axios作为异步请求框架
- 采用Element-Plus作为UI组件库
- 使用VueUse适配深色模式切换
- 使用unplugin-auto-import按需引入,减少打包后体积
.
├── database.sql # 数据库初始化脚本
├── my-project-backend # Spring Boot 后端
│ ├── pom.xml # 依赖、Maven 环境与资源过滤配置
│ └── src/main
│ ├── java/com/example
│ │ ├── config # Security、Swagger、消息队列等配置
│ │ ├── controller # 接口入口,exception 包处理异常响应
│ │ ├── entity
│ │ │ ├── dto # 数据库实体
│ │ │ └── vo # request 请求对象、response 响应对象
│ │ ├── filter # JWT 校验、跨域、限流与请求日志
│ │ ├── listener # 邮件队列消费者
│ │ ├── mapper # MyBatis-Plus 数据访问接口
│ │ ├── service # 业务接口及 impl 实现
│ │ └── utils # JWT、限流、常量等公共工具
│ └── resources # 多环境配置与日志配置
└── my-project-frontend # Vue 前端
├── vite.config.js # 构建、路径别名与 Element Plus 按需引入
└── src
├── main.js # 应用入口与后端请求地址
├── net/index.js # 请求封装、登录与令牌管理
├── router/index.js # 页面路由与登录守卫
└── views # 页面,welcome 目录存放登录、注册等页面
| 依赖 | 说明 |
|---|---|
| JDK | 17,与后端 pom.xml 中的 Java 版本保持一致 |
| Maven | 3.6.3 或更高版本 |
| Node.js / npm | 建议使用 Node.js 22 LTS,通过 npm 安装前端依赖 |
| MySQL | 8.x,初始化脚本使用 utf8mb4_0900_ai_ci 排序规则 |
| Redis | 用于验证码、JWT 黑名单和请求限流 |
| RabbitMQ | 用于异步发送验证码邮件 |
| SMTP 邮箱 | 开启 SMTP 服务,准备发件地址和授权码 |
先创建二开项目使用的 MySQL 数据库,再向该库导入根目录的 database.sql。默认配置连接名为 test 的数据库。脚本会删除并重建 db_account 表,适合在新建的开发库中导入;初始化后没有预设账号,可通过注册页面创建用户。
启动 MySQL、Redis 和 RabbitMQ,按本地环境修改 application-dev.yml:
| 配置项 | 修改内容 |
|---|---|
spring.datasource |
数据库地址、库名、用户名和密码 |
spring.data.redis |
当前文件未显式配置,默认连接 localhost:6379、数据库 0;使用其他实例或密码时补充此配置 |
spring.rabbitmq |
RabbitMQ 地址、账号、密码和 virtual host,账号需要有对应 virtual host 的权限 |
spring.mail |
SMTP 地址、发件邮箱和授权码,端口、认证及 SSL/TLS 参数按邮箱服务商要求配置 |
spring.security.jwt |
项目自己的签名密钥、令牌有效期与登录频率限制,其中 expire 单位为小时 |
spring.web.cors |
允许访问后端的前端来源、请求方法及是否携带凭证 |
spring.web.verify / spring.web.flow |
验证邮件发送间隔和请求限流参数,时间单位为秒 |
后端默认使用 dev Maven profile,在项目根目录执行:
cd my-project-backend
mvn spring-boot:run -Pdev后端开发环境默认监听 8080 端口,接口文档地址为 http://localhost:8080/swagger-ui/index.html,OpenAPI JSON 地址为 http://localhost:8080/v3/api-docs。
前端请求地址在 src/main.js 的 axios.defaults.baseURL 中配置,当前为 http://localhost:8080,后端地址变化时同步修改。在另一个终端从项目根目录执行:
cd my-project-frontend
npm install
npm run dev打开 Vite 输出的本地地址,默认是 http://localhost:5173。当前前端直接请求后端地址,vite.config.js 未配置接口代理。
新增模块可以参考 Account、AccountMapper、AccountService 和 AccountServiceImpl 的组织方式:
- 在数据库中建立业务表,在
entity/dto中添加对应实体,通过@TableName、@TableId声明表名与主键。 - 在
mapper中添加带@Mapper的接口并继承BaseMapper<实体>,在service和service/impl中实现业务逻辑,复用 MyBatis-Plus 的查询、保存和更新能力。 - 在
entity/vo/request中定义请求对象,使用 Jakarta Validation 注解并在 Controller 参数上添加@Valid;数据库实体与对外响应对象分别定义。 - 在
controller中添加/api/业务名接口,统一使用RestBean.success(...)或RestBean.failure(...)返回结果,通过@Tag、@Operation补充接口文档。
RestBean<T> 包含 id(请求追踪 ID)、code、data 和 message。前端请求封装根据响应体中的 code 判断业务结果,成功为 200,登录失效为 401,无权限为 403。HTTP 状态码与响应体中的业务状态码需要分别查看。
以“获取当前用户信息”为例,可以复用现有账户服务。先新增 my-project-backend/src/main/java/com/example/entity/vo/response/AccountInfoVO.java,声明需要返回的字段:
package com.example.entity.vo.response;
import lombok.Data;
@Data
public class AccountInfoVO {
Integer id;
String username;
String email;
}再新增 my-project-backend/src/main/java/com/example/controller/AccountController.java:
package com.example.controller;
import com.example.entity.RestBean;
import com.example.entity.vo.response.AccountInfoVO;
import com.example.service.AccountService;
import com.example.utils.Const;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/account")
public class AccountController {
@Resource
AccountService accountService;
@GetMapping("/me")
public RestBean<AccountInfoVO> me(@RequestAttribute(Const.ATTR_USER_ID) Integer id) {
return RestBean.success(accountService.getById(id).asViewObject(AccountInfoVO.class));
}
}JwtAuthenticationFilter 会在令牌校验成功后,将用户 ID 写入 Const.ATTR_USER_ID 对应的请求属性。需要识别当前用户的接口可以按上面的方式读取。Account 已实现 BaseData,asViewObject(...) 会复制同名字段到具有公共无参构造方法的 VO;新增实体需要此能力时也可实现 BaseData。响应 VO 只声明对外需要的字段,例如上面的示例不会返回账户密码。
在 src/views 中新增页面,例如 ProfileView.vue,通过 src/net/index.js 提供的 get、post 请求后端。封装会自动携带 JWT、处理业务失败提示和登录失效,成功回调收到的是 RestBean.data:
<script setup>
import { onMounted, ref } from 'vue'
import { get } from '@/net'
const account = ref({})
onMounted(() => {
get('/api/account/me', data => {
account.value = data
})
})
</script>
<template>
<div>
<div>用户名:{{ account.username }}</div>
<div>邮箱:{{ account.email }}</div>
</div>
</template>在 src/router/index.js 的 routes 数组中注册页面,并为路由设置 name:
{
path: '/index/profile',
name: 'profile',
component: () => import('@/views/ProfileView.vue')
}当前路由守卫会将已登录用户从名称以 welcome 开头的路由跳转到 /index,并拦截未登录用户访问以 /index 开头的路径。新增 /settings 等其他需要登录的路径时,应同步调整守卫规则。页面访问规则与后端接口权限分别配置。
页面使用 Vue 单文件组件和 <script setup> 编写;@ 指向 src。Element Plus 组件已配置按需引入,Vue 的 ref、reactive 等 API 按现有页面风格显式导入。
- 登录由
SecurityConfiguration中的 Spring Security 表单登录处理,地址为POST /api/auth/login,参数为username、password,请求类型为application/x-www-form-urlencoded。前端直接复用login(...)方法。 - 登录成功后,前端保存令牌及过期时间;勾选“记住我”时使用
localStorage,否则使用sessionStorage。后续请求携带Authorization: Bearer <token>,退出登录复用logout(...),后端会将令牌加入 Redis 黑名单。 SecurityConfiguration当前放行/api/auth/**、/error和 Swagger 相关路径,其他请求要求拥有Const.ROLE_DEFAULT,默认值为user。公开接口通过requestMatchers(...).permitAll()明确配置,需要登录的业务接口使用独立的业务路径。- 扩展角色时,同步修改角色常量、账户角色及
SecurityConfiguration的匹配规则。数据库角色值使用user、admin这样的名称,Spring Security 的roles(...)会添加ROLE_前缀。角色权限写入 JWT,修改角色后需要重新登录以生成包含新权限的令牌。 - 密码处理复用注入的
PasswordEncoder,其实现为 BCrypt;JWT 操作复用JwtUtils,限流操作复用FlowUtils,Redis key 前缀、队列名等常量集中放在Const中。 - 注册和重置密码验证码通过
mail队列发送,邮件标题与正文在MailQueueListener中修改,队列声明位于RabbitConfiguration。当前验证码有效期在AccountServiceImpl中设置为 3 分钟,调整时同步更新邮件中的说明。 - 请求日志由
RequestLogFilter记录,可用响应中的id对照日志中的reqId定位请求;日志文件位于后端进程工作目录下的log/,滚动策略在logback-spring.xml中配置。
后端通过 Maven profile 选择环境:application.yml 中的 @environment@ 会在 Maven 处理资源时替换,构建产物只包含公共配置和所选环境的配置文件。开发环境使用 -Pdev,生产环境使用 -Pprod;切换环境时使用 clean 清理旧资源。
先按部署环境修改 application-prod.yml 中的数据库、Redis、RabbitMQ、SMTP 和 JWT 配置,再从项目根目录打包后端:
cd my-project-backend
mvn clean package -Pprod -DskipTests
java -jar target/my-project-backend-0.0.1-SNAPSHOT.jar当前生产配置监听 80 端口并关闭 OpenAPI 文档。仅在启动命令中切换 Spring profile 不会补入构建时未包含的环境配置文件,部署时应使用对应 Maven profile 生成的产物。
前端打包前,将 src/main.js 中的 axios.defaults.baseURL 改为实际后端地址;如果通过同域反向代理转发 /api,可改为 /。在已安装前端依赖的基础上,从项目根目录执行:
cd my-project-frontend
npm run build将生成的 my-project-frontend/dist/ 部署到静态资源服务器。路由使用 History 模式,需要为前端页面配置回退到 index.html,例如 Nginx 的 try_files $uri $uri/ /index.html;,并为 /api 单独配置后端转发。