健康管理系统前后端交互设计与 API 规范
1. 整体架构设计
1.1 前后端分离架构
健康管理系统采用前后端分离的架构设计:
1.2 数据流设计
用户操作 → Vue 组件 → Service 层 → Axios 请求 → 后端 Controller
↓
用户界面 ← 状态更新 ← 响应处理 ← 数据返回 ← Service 层
2. API 设计规范
2.1 RESTful API 设计原则
系统遵循 RESTful API 设计规范:
| HTTP 方法 | 用途 | 示例 |
|---|---|---|
| GET | 获取资源 | GET /api/v1/users/info |
| POST | 创建资源 | POST /api/v1/food-records |
| PUT | 更新资源 | PUT /api/v1/users/update |
| DELETE | 删除资源 | DELETE /api/v1/food-records/123 |
2.2 统一响应格式
所有 API 返回统一的响应结构:
{
"success": true,
"message": "操作成功",
"data": { }
}
响应字段说明:
success: 操作是否成功(boolean)message: 提示信息(string)data: 返回数据(object/array,可选)
2.3 API 版本控制
API 路径包含版本号,便于后续升级:
/api/v1/users/login # 当前版本
/api/v2/users/login # 未来新版本
3. 认证与授权机制
3.1 JWT Token 认证
系统使用 JWT(JSON Web Token)进行身份认证:
认证流程:
1. 用户登录
POST /api/v1/users/login
{ username: "xxx", password: "xxx", captcha: "xxx" }
2. 后端验证成功,返回 Token
{ success: true, data: { token: "eyJhbG..." } }
3. 前端存储 Token(localStorage)
4. 后续请求携带 Token
Authorization: Bearer eyJhbG...
5. 后端验证 Token 有效性
后端 JWT 工具类(JwtUtil.java):
@Component
public class JwtUtil {
// 使用 HS256 算法生成密钥
private final Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
/**
* 生成 JWT Token
* @param username 用户名
* @return JWT 令牌字符串
*/
public String generateToken(String username) {
Map<String, Object> claims = new HashMap<>();
claims.put("username", username);
return Jwts.builder()
.setClaims(claims) // 设置自定义声明
.setSubject(username) // 设置主题(用户名)
.setIssuedAt(new Date()) // 设置签发时间
.setExpiration(new Date(System.currentTimeMillis() + expirationTime)) // 设置过期时间
.signWith(key) // 使用密钥签名
.compact(); // 生成令牌
}
/**
* 从 Token 中提取用户名
* @param token JWT 令牌
* @return 用户名
*/
public String extractUsername(String token) {
Claims claims = Jwts.parserBuilder()
.setSigningKey(key) // 设置验证密钥
.build()
.parseClaimsJws(token) // 解析令牌
.getBody(); // 获取声明体
return claims.getSubject();
}
/**
* 验证 Token 是否有效
* @param token JWT 令牌
* @return 是否有效
*/
public boolean validateToken(String token) {
try {
Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);
return true; // 解析成功,令牌有效
} catch (Exception e) {
return false; // 解析失败,令牌无效或过期
}
}
}
3.2 前端请求拦截器
前端通过 Axios 拦截器自动添加认证头:
// api.js - 请求拦截器:在请求发送前自动添加 JWT Token
api.interceptors.request.use(
config => {
// 从 localStorage 获取登录时保存的 token
const token = localStorage.getItem('token')
if (token) {
// 在请求头中添加 Authorization 字段
config.headers.Authorization = `Bearer ${token}`
} else {
// 对于AI小助手相关接口,允许无token访问
const aiAssistantPaths = ['/api/v1/ai-assistant/status', '/api/v1/ai-assistant/chat']
const isAiAssistantPath = aiAssistantPaths.some(path => config.url.includes(path))
// 如果不是AI助手接口且没有token,清空数据并跳转登录页
if (!isAiAssistantPath) {
clearUserLocalStorage()
window.location.href = '/'
}
}
return config
},
error => Promise.reject(error)
)
3.3 权限控制
- 大部分接口需要认证才能访问
- AI 小助手部分接口(如状态检查)允许匿名访问
- 401/403 错误自动跳转登录页
4. 核心 API 模块
4.1 用户认证模块
基础路径: /api/v1/users
| 接口 | 方法 | 功能 | 认证 |
|---|---|---|---|
/login |
POST | 用户登录 | 否 |
/register |
POST | 用户注册 | 否 |
/info |
GET | 获取用户信息 | 是 |
/update |
PUT | 更新用户信息 | 是 |
/update-avatar |
POST | 更新头像 | 是 |
/change-password |
POST | 修改密码 | 是 |
/delete |
DELETE | 注销账户 | 是 |
/security-question |
GET | 获取密保问题 | 否 |
/reset-password |
POST | 重置密码 | 否 |
/ai-assistant-settings |
GET/POST | AI助手设置 | 是 |
/ai-assistant-avatar |
POST | AI助手头像 | 是 |
后端 Controller 代码片段:
/**
* 用户控制器 - 处理用户相关的所有请求
* 路径前缀: /api/v1/users
*/
@RestController
@RequestMapping("/api/v1/users")
public class UserController {
// 注入用户服务层
@Autowired
private UserService userService;
// 注入 JWT 工具类
@Autowired
private JwtUtil jwtUtil;
/**
* 用户登录接口
* @param request 包含用户名、密码、验证码的登录请求
* @return 包含 JWT Token 的用户响应
*/
@PostMapping("/login")
public UserResponse login(@Valid @RequestBody UserLoginRequest request) {
// 调用服务层验证用户身份
User user = userService.login(request.getUsername(), request.getPassword());
// 生成 JWT Token
String token = jwtUtil.generateToken(user.getUsername());
// 构建响应对象
UserResponse response = new UserResponse();
response.setToken(token);
response.setUsername(user.getUsername());
return response;
}
}
前端 Service 代码片段:
// userService.js - 用户相关 API 封装
const userService = {
// 用户登录:传入用户名密码,返回包含 token 的用户信息
login: async (credentials) => api.post(apiPaths.user.login, credentials),
// 用户注册:传入用户名、密码、邮箱等信息
register: async (userData) => api.post(apiPaths.user.register, userData),
// 获取用户信息:根据用户名查询用户详细信息
getUserInfo: async (username) => api.get(`${apiPaths.user.info}?username=${username}`),
// 更新用户信息:传入用户资料进行更新
updateUserInfo: async (userData) => api.put(apiPaths.user.update, userData)
}
export default userService
4.2 AI 小助手模块
基础路径: /api/v1/ai-assistant
| 接口 | 方法 | 功能 | 认证 |
|---|---|---|---|
/chat |
POST | AI 对话 | 是 |
/status |
GET | 获取AI状态 | 否 |
/history |
POST | 保存对话历史 | 是 |
/history/{username} |
GET | 获取历史列表 | 是 |
/history/{username}/{sessionId} |
DELETE | 删除对话 | 是 |
/history/{username}/{sessionId}/title |
PUT | 更新对话标题 | 是 |
前端 Service 代码片段:
// healthService.js - AI小助手相关 API
aiAssistant: {
/**
* 发送聊天消息
* @param message 用户输入的消息内容
* @param username 当前用户名
* @param context 上下文信息(如AI性格、名称等)
* @returns 返回AI的回复内容
*/
chat: async (message, username, context) => {
return api.post(apiPaths.aiAssistant.chat, { message, username, context }, { timeout: 30000 })
},
// 获取用户的对话历史列表
getHistoryList: async (username) => {
return api.get(`${apiPaths.aiAssistant.history}/${encodeURIComponent(username)}`)
},
// 删除指定的对话历史
deleteHistory: async (username, sessionId) => {
return api.delete(`${apiPaths.aiAssistant.history}/${encodeURIComponent(username)}/${encodeURIComponent(sessionId)}`)
}
}
4.3 AI 健康分析模块
基础路径: /api/v1/ai-analysis
| 接口 | 方法 | 功能 | 认证 |
|---|---|---|---|
/generate |
POST | 生成分析报告 | 是 |
/save |
POST | 保存分析记录 | 是 |
/ |
GET | 获取分析记录列表 | 是 |
/favorited |
GET | 获取收藏记录 | 是 |
/{id}/favorite |
POST | 切换收藏状态 | 是 |
/{id} |
DELETE | 删除记录 | 是 |
/batch-delete |
DELETE | 批量删除 | 是 |
前端 Service 代码片段:
// healthService.js - AI健康分析相关 API
aiAnalysis: {
/**
* 生成健康分析报告
* @param username 用户名
* @param startDate 分析开始日期
* @param endDate 分析结束日期
* @returns 返回AI生成的分析报告
*/
generateAnalysis: async (username, startDate, endDate) => {
return api.post(apiPaths.aiAnalysis.generate, null, {
params: { username, startDate, endDate },
timeout: 120000 // AI生成耗时较长,设置120秒超时
})
},
// 切换分析记录的收藏状态
toggleFavorite: async (recordId, favorited) => {
return api.post(apiPaths.aiAnalysis.favorite(recordId), { favorited })
}
}
4.4 健康记录模块
所有健康记录模块(饮食、运动、睡眠、情绪、体重)采用统一的 API 设计模式:
饮食记录 (/api/v1/food-records):
| 接口 | 方法 | 功能 |
|---|---|---|
/ |
GET | 获取记录列表 |
/ |
POST | 添加记录 |
/{id} |
DELETE | 删除记录 |
/ |
PUT | 更新记录 |
/{id}/favorite |
POST | 切换收藏 |
/batch-delete |
DELETE | 批量删除 |
前端 Service 代码片段(以饮食记录为例):
// healthService.js - 饮食记录相关 API
food: {
// 获取用户的饮食记录列表,支持分页和筛选参数
getRecords: async (username, params) => api.get(`${apiPaths.food.records}?username=${username}`, { params }),
// 创建新的饮食记录
createRecord: async (record) => api.post(apiPaths.food.records, record),
// 更新已有的饮食记录
updateRecord: async (recordId, record) => api.put(`${apiPaths.food.records}/${recordId}`, record),
// 删除指定的饮食记录
deleteRecord: async (recordId) => api.delete(`${apiPaths.food.records}/${recordId}`),
// 切换记录的收藏状态
toggleFavorite: async (recordId, favorited) => api.post(apiPaths.food.favorite(recordId), { favorited })
}
运动记录 (/api/v1/workouts)、睡眠记录 (/api/v1/sleep-records)、情绪记录 (/api/v1/mood-records)、体重记录 (/api/v1/weight-records) 均采用相同的 API 设计模式。
5. 前端 API 封装
5.1 API 路径管理
所有 API 路径集中管理在 apiPaths.js:
// API 基础路径
const API_BASE = '/api/v1';
// API 路径配置对象
const apiPaths = {
// 用户相关接口
user: {
login: `${API_BASE}/users/login`, // 登录
register: `${API_BASE}/users/register`, // 注册
info: `${API_BASE}/users/info`, // 获取用户信息
update: `${API_BASE}/users/update` // 更新用户信息
},
// 饮食记录接口
food: {
records: `${API_BASE}/food-records`, // 记录增删改查
favorite: (id) => `${API_BASE}/food-records/${id}/favorite` // 动态路径:切换收藏
},
// AI小助手接口
aiAssistant: {
chat: `${API_BASE}/ai-assistant/chat`, // AI对话
history: `${API_BASE}/ai-assistant/history` // 对话历史
},
// AI健康分析接口
aiAnalysis: {
generate: `${API_BASE}/ai-analysis/generate`, // 生成分析
favorite: (id) => `${API_BASE}/ai-analysis/${id}/favorite` // 动态路径:切换收藏
}
};
export default apiPaths;
优点:
- 路径统一管理,便于维护
- 支持动态路径参数
- 避免硬编码 URL
5.2 Axios 实例配置
// api.js - Axios 配置和拦截器
import axios from 'axios'
// 创建 axios 实例,配置基础参数
const api = axios.create({
baseURL: 'http://localhost:8080', // 后端服务地址
timeout: 10000, // 请求超时时间(10秒)
headers: { 'Content-Type': 'application/json' } // 默认请求头
})
// 请求拦截器:在请求发送前处理(如添加 Token)
api.interceptors.request.use(
config => {
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
},
error => Promise.reject(error)
)
// 响应拦截器:在收到响应后处理(如统一错误处理)
api.interceptors.response.use(
response => response.data, // 直接返回响应数据
error => {
// 401/403 未授权,清空数据并跳转登录页
if (error.response?.status === 401 || error.response?.status === 403) {
clearUserLocalStorage()
window.location.href = '/'
}
return Promise.reject(error)
}
)
export default api
6. 错误处理机制
6.1 后端错误处理
全局异常处理器(GlobalExceptionHandler.java):
/**
* 全局异常处理器 - 统一处理所有 Controller 抛出的异常
* @ControllerAdvice 注解标识这是一个全局异常处理类
*/
@ControllerAdvice
public class GlobalExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* 处理自定义业务异常
* @param ex 自定义异常对象
* @return 包含错误信息的响应实体
*/
@ExceptionHandler(BaseException.class)
public ResponseEntity<Map<String, Object>> handleBaseException(BaseException ex) {
logger.error("Base exception: {}", ex.getMessage());
return createErrorResponse(HttpStatus.valueOf(ex.getStatusCode()), ex.getMessage(), ex.getClass().getSimpleName());
}
/**
* 处理运行时异常
* @param ex 运行时异常对象
* @return 400 错误响应
*/
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<Map<String, Object>> handleRuntimeException(RuntimeException ex) {
logger.error("Runtime exception: ", ex);
return createErrorResponse(HttpStatus.BAD_REQUEST, ex.getMessage(), ex.getClass().getSimpleName());
}
/**
* 处理所有其他未捕获的异常
* @param ex 异常对象
* @return 500 错误响应
*/
@ExceptionHandler(Exception.class)
public ResponseEntity<Map<String, Object>> handleException(Exception ex) {
logger.error("Unexpected exception: ", ex);
return createErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, "服务器内部错误", ex.getMessage());
}
/**
* 创建统一的错误响应结构
* @param status HTTP 状态码
* @param message 错误消息
* @param error 异常类型
* @return ResponseEntity 对象
*/
private ResponseEntity<Map<String, Object>> createErrorResponse(HttpStatus status, String message, String error) {
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("status", status.value()); // HTTP 状态码
errorResponse.put("message", message); // 错误消息
errorResponse.put("error", error); // 异常类型
return ResponseEntity.status(status).body(errorResponse);
}
}
自定义异常基类:
/**
* 自定义异常基类 - 所有业务异常都继承此类
* 包含状态码字段,用于返回对应的 HTTP 状态码
*/
public class BaseException extends RuntimeException {
private int statusCode; // HTTP 状态码
/**
* 构造方法
* @param message 错误消息
* @param statusCode HTTP 状态码
*/
public BaseException(String message, int statusCode) {
super(message);
this.statusCode = statusCode;
}
public int getStatusCode() { return statusCode; }
}
错误响应格式:
{
"status": 400,
"message": "请求参数错误",
"error": "RuntimeException"
}
6.2 前端错误处理
项目采用两层错误处理机制:
第一层:Axios 响应拦截器(api.js)
拦截器处理全局错误,如 401/403 跳转登录页:
// 响应拦截器:统一处理响应错误
api.interceptors.response.use(
response => response.data, // 成功响应直接返回数据
error => {
// 401: 未授权,403: 禁止访问,都跳转到登录页
if (error.response?.status === 401 || error.response?.status === 403) {
clearUserLocalStorage() // 清除本地存储的用户数据
window.location.href = '/' // 跳转到登录页
}
return Promise.reject(error)
}
)
第二层:错误处理工具函数(errorHandler.js)
组件层使用 handleApiError 处理具体错误并提示用户:
/**
* 统一处理 API 错误
* @param error 错误对象(Axios 抛出的错误)
* @param setErrorMessage 设置错误消息的回调函数(用于UI显示)
* @param defaultMessage 默认错误消息
* @returns 处理后的错误消息
*/
export const handleApiError = (error, setErrorMessage, defaultMessage = '操作失败') => {
let errorMessage = defaultMessage;
if (error.response) {
// 服务器返回了错误状态码
switch (error.response.status) {
case 400: errorMessage = '请求参数错误'; break;
case 401: errorMessage = '未授权,请重新登录'; break;
case 403: errorMessage = '禁止访问'; break;
case 404: errorMessage = '请求的资源不存在'; break;
case 409: errorMessage = '资源冲突,可能已存在'; break;
case 500: errorMessage = '服务器内部错误'; break;
default: errorMessage = error.response.data?.message || defaultMessage;
}
} else if (error.request) {
// 请求已发出但没有收到响应(网络错误)
errorMessage = '网络错误,无法连接到服务器';
} else {
// 请求配置出错
errorMessage = error.message || defaultMessage;
}
// 如果提供了回调函数,设置错误消息到UI
if (setErrorMessage) setErrorMessage(errorMessage);
return errorMessage;
};
6.3 错误码说明
| 状态码 | 含义 | 处理方式 |
|---|---|---|
| 200 | 请求成功 | 正常处理 |
| 400 | 请求参数错误 | 提示用户检查输入 |
| 401 | 未授权 | 跳转登录页 |
| 403 | 禁止访问 | 提示无权限 |
| 404 | 资源不存在 | 提示资源不存在 |
| 409 | 资源冲突 | 提示资源已存在 |
| 500 | 服务器错误 | 提示服务器错误 |
7. 数据持久化策略
7.1 前端数据缓存
| 存储位置 | 用途 | 示例 |
|---|---|---|
| localStorage | 长期缓存 | token、用户设置、主题 |
| sessionStorage | 会话缓存 | 临时表单数据 |
| Pinia Store | 应用状态 | 当前用户信息、健康数据 |
| 内存 | 临时状态 | 组件内部状态 |
7.2 数据同步机制
用户操作 → 更新前端状态 → 调用 API → 后端处理 → 数据库
↑ ↓
└────── 响应成功,更新状态 ←────┘
7.3 离线处理
- 关键操作(如添加记录)失败后提示用户
- 支持重试机制
- 后端断开时清空本地缓存并跳转登录页
8. 安全设计
8.1 传输安全
- 使用 HTTPS 加密传输(生产环境)
- 敏感信息(密码)加密传输
8.2 认证安全
- JWT Token 设置过期时间
- Token 失效自动跳转登录
- 登出时清空所有缓存数据
8.3 数据安全
- 用户只能访问自己的数据
- 后端进行权限校验
- 敏感操作需要重新认证
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)