# 餐厅管理系统 - 前端API接口文档 ## 📋 接口概述 本系统使用JWT Token进行身份认证。除了登录注册接口外,所有API都需要在请求头中携带有效的JWT Token。 **服务器地址**: `http://localhost:8080` ## 🔐 认证机制 ### JWT Token使用方式 - **获取Token**: 通过登录接口获取 - **使用Token**: 在请求头中添加 `Authorization: Bearer {token}` - **Token有效期**: 24小时 - **无需Token**: 仅注册和登录接口 ## 📱 认证相关接口 ### 1. 用户注册 **接口地址**: `POST /api/auth/register` **是否需要Token**: ❌ 否 **请求参数**: ```json { "accountName": "用户名(3-20字符,字母数字下划线)", "accountPassword": "密码(8-20字符,至少包含字母和数字)", "confirmPassword": "确认密码(需与密码相同)", "accountPhone": "手机号(11位数字,可选)", "accountType": "账户类型(admin/manager/customer)", "accountGender": "性别(male/female,可选)" } ``` **请求示例**: ```javascript const registerData = { accountName: "zhangsan", accountPassword: "password123", confirmPassword: "password123", accountPhone: "13812345678", accountType: "customer", accountGender: "male" }; const response = await fetch('http://localhost:8080/api/auth/register', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(registerData) }); const result = await response.json(); ``` **响应示例**: ```json { "code": 200, "msg": "成功", "data": { "token": null, "accountInfo": { "accountId": 1, "accountName": "zhangsan", "accountType": "customer", "accountPhone": "13812345678", "accountGender": "male", "accountImg": null } } } ``` ### 2. 用户登录 **接口地址**: `POST /api/auth/login` **是否需要Token**: ❌ 否 **请求参数**: ```json { "accountName": "用户名", "accountPassword": "密码" } ``` **请求示例**: ```javascript const loginData = { accountName: "zhangsan", accountPassword: "password123" }; const response = await fetch('http://localhost:8080/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(loginData) }); const result = await response.json(); // 保存Token到本地存储 if (result.code === 200) { const jwtToken = result.data.token; localStorage.setItem('token', jwtToken); localStorage.setItem('userInfo', JSON.stringify(result.data.accountInfo)); } ``` **响应示例**: ```json { "code": 200, "msg": "成功", "data": { "token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ6aGFuZ3NhbiIsImlhdCI6MTcwNDczNzgxLCJleHAiOjE3NTA1NjAxODF9...", "accountInfo": { "accountId": 1, "accountName": "zhangsan", "accountType": "customer", "accountPhone": "13812345678", "accountGender": "male", "accountImg": null } } } ``` ### 3. 修改密码 **接口地址**: `PUT /api/auth/change-password` **是否需要Token**: ✅ 是 **请求参数**: ```json { "oldPassword": "当前密码", "newPassword": "新密码(8-20字符,至少包含字母和数字)", "confirmPassword": "确认新密码" } ``` **请求示例**: ```javascript // 获取存储的Token const storedToken = localStorage.getItem('token'); const passwordData = { oldPassword: "password123", newPassword: "newpassword456", confirmPassword: "newpassword456" }; // 构建请求头,确保完整Token传递 const headers = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${storedToken}` }; const response = await fetch('http://localhost:8080/api/auth/change-password', { method: 'PUT', headers: headers, body: JSON.stringify(passwordData) }); const result = await response.json(); ``` **响应示例**: ```json { "code": 200, "msg": "成功", "data": "密码修改成功" } ``` ### 4. 获取当前用户信息 **接口地址**: `GET /api/auth/current-user` **是否需要Token**: ✅ 是 **请求示例**: ```javascript // 获取存储的Token const authToken = localStorage.getItem('token'); // 构建请求头 const requestHeaders = { 'Authorization': `Bearer ${authToken}` }; const response = await fetch('http://localhost:8080/api/auth/current-user', { method: 'GET', headers: requestHeaders }); const result = await response.json(); ``` **响应示例**: ```json { "code": 200, "msg": "成功", "data": "当前登录用户: zhangsan" } ``` ## 🔧 前端Token管理 ### Token存储和使用 ```javascript class AuthManager { // 保存Token - 确保完整保存 static saveToken(tokenString, userInfo) { if (tokenString && tokenString.trim()) { localStorage.setItem('token', tokenString); localStorage.setItem('userInfo', JSON.stringify(userInfo)); } } // 获取完整Token static getToken() { const tokenValue = localStorage.getItem('token'); return tokenValue ? tokenValue.trim() : null; } // 获取用户信息 static getUserInfo() { const userInfo = localStorage.getItem('userInfo'); return userInfo ? JSON.parse(userInfo) : null; } // 清除Token(登出) static logout() { localStorage.removeItem('token'); localStorage.removeItem('userInfo'); } // 检查是否已登录 static isLoggedIn() { const token = this.getToken(); return token && token.length > 0; } // 创建认证头 - 确保完整Token传递 static getAuthHeaders() { const fullToken = this.getToken(); return fullToken ? { 'Authorization': `Bearer ${fullToken}` } : {}; } } ``` ### 统一请求封装 ```javascript class ApiClient { static baseURL = 'http://localhost:8080'; // 通用请求方法 - 使用变量方式确保Token完整传递 static async request(url, options = {}) { // 获取完整Token const currentToken = AuthManager.getToken(); // 构建基础headers const baseHeaders = { 'Content-Type': 'application/json' }; // 如果有Token,添加认证header const authHeaders = currentToken ? { 'Authorization': `Bearer ${currentToken}` } : {}; // 合并headers const finalHeaders = { ...baseHeaders, ...authHeaders, ...(options.headers || {}) }; const config = { ...options, headers: finalHeaders }; try { const response = await fetch(`${this.baseURL}${url}`, config); const result = await response.json(); // 处理认证失败 if (response.status === 403 || response.status === 401) { AuthManager.logout(); // 跳转到登录页面 window.location.href = '/login'; return null; } return result; } catch (error) { console.error('API请求失败:', error); throw error; } } // GET请求 static async get(url) { return this.request(url, { method: 'GET' }); } // POST请求 static async post(url, data) { return this.request(url, { method: 'POST', body: JSON.stringify(data) }); } // PUT请求 static async put(url, data) { return this.request(url, { method: 'PUT', body: JSON.stringify(data) }); } // DELETE请求 static async delete(url) { return this.request(url, { method: 'DELETE' }); } } ``` ### 认证相关操作 ```javascript class AuthAPI { // 用户注册 static async register(userData) { return ApiClient.post('/api/auth/register', userData); } // 用户登录 - 确保完整Token保存 static async login(credentials) { const result = await ApiClient.post('/api/auth/login', credentials); if (result && result.code === 200) { // 获取完整Token并保存 const completeToken = result.data.token; AuthManager.saveToken(completeToken, result.data.accountInfo); } return result; } // 修改密码 - 使用变量方式传递Token static async changePassword(passwordData) { // 获取完整Token const userToken = AuthManager.getToken(); // 构建请求头 const requestHeaders = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${userToken}` }; // 直接使用fetch确保Token完整传递 const response = await fetch(`${ApiClient.baseURL}/api/auth/change-password`, { method: 'PUT', headers: requestHeaders, body: JSON.stringify(passwordData) }); return await response.json(); } // 获取当前用户 - 使用变量方式传递Token static async getCurrentUser() { const accessToken = AuthManager.getToken(); const headers = { 'Authorization': `Bearer ${accessToken}` }; const response = await fetch(`${ApiClient.baseURL}/api/auth/current-user`, { method: 'GET', headers: headers }); return await response.json(); } // 登出 static logout() { AuthManager.logout(); window.location.href = '/login'; } } ``` ## 🎯 使用示例 ### 登录页面 ```javascript // 登录表单提交 async function handleLogin(event) { event.preventDefault(); const formData = new FormData(event.target); const loginCredentials = { accountName: formData.get('username'), accountPassword: formData.get('password') }; try { const loginResult = await AuthAPI.login(loginCredentials); if (loginResult.code === 200) { alert('登录成功!'); // 验证Token是否正确保存 const savedToken = AuthManager.getToken(); console.log('Token已保存:', savedToken ? '是' : '否'); window.location.href = '/dashboard'; } else { alert(`登录失败:${loginResult.msg}`); } } catch (error) { alert('登录请求失败,请检查网络连接'); } } ``` ### 注册页面 ```javascript // 注册表单提交 async function handleRegister(event) { event.preventDefault(); const formData = new FormData(event.target); const registrationData = { accountName: formData.get('username'), accountPassword: formData.get('password'), confirmPassword: formData.get('confirmPassword'), accountPhone: formData.get('phone'), accountType: formData.get('userType'), accountGender: formData.get('gender') }; try { const registerResult = await AuthAPI.register(registrationData); if (registerResult.code === 200) { alert('注册成功!请登录'); window.location.href = '/login'; } else { alert(`注册失败:${registerResult.msg}`); } } catch (error) { alert('注册请求失败,请检查网络连接'); } } ``` ### 修改密码页面 ```javascript // 修改密码表单提交 async function handleChangePassword(event) { event.preventDefault(); const formData = new FormData(event.target); const changePasswordInfo = { oldPassword: formData.get('oldPassword'), newPassword: formData.get('newPassword'), confirmPassword: formData.get('confirmPassword') }; try { // 使用专门的方法确保Token完整传递 const changeResult = await AuthAPI.changePassword(changePasswordInfo); if (changeResult.code === 200) { alert('密码修改成功!'); } else { alert(`密码修改失败:${changeResult.msg}`); } } catch (error) { alert('请求失败,请检查网络连接'); } } ``` ### 业务API调用示例 ```javascript // 获取数据列表 - 使用变量方式确保Token传递 async function fetchDataWithAuth(apiEndpoint) { try { // 获取完整Token const authenticationToken = AuthManager.getToken(); if (!authenticationToken) { alert('请先登录'); window.location.href = '/login'; return; } // 构建请求头 const apiHeaders = { 'Authorization': `Bearer ${authenticationToken}` }; const response = await fetch(`http://localhost:8080${apiEndpoint}`, { method: 'GET', headers: apiHeaders }); const result = await response.json(); if (result && result.code === 200) { return result.data; } else { alert(`请求失败:${result.msg}`); return null; } } catch (error) { alert('请求失败,请检查网络连接'); return null; } } // 发送数据 - 使用变量方式确保Token传递 async function postDataWithAuth(apiEndpoint, postData) { try { // 获取完整Token const userAuthToken = AuthManager.getToken(); if (!userAuthToken) { alert('请先登录'); window.location.href = '/login'; return; } // 构建请求头 const requestHeaders = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${userAuthToken}` }; const response = await fetch(`http://localhost:8080${apiEndpoint}`, { method: 'POST', headers: requestHeaders, body: JSON.stringify(postData) }); const result = await response.json(); if (result && result.code === 200) { return result.data; } else { alert(`操作失败:${result.msg}`); return null; } } catch (error) { alert('请求失败,请检查网络连接'); return null; } } ``` ## 🚨 错误处理 ### 常见错误码 | 错误码 | 说明 | 处理方式 | |--------|------|----------| | 200 | 成功 | 正常处理数据 | | 401 | 未认证 | 跳转到登录页面 | | 403 | 已禁止/Token无效 | 清除Token,跳转到登录页面 | | 500 | 服务器错误 | 显示错误信息,建议重试 | ### Token验证和错误处理 ```javascript // 页面加载时验证Token有效性 async function validateTokenOnPageLoad() { const currentToken = AuthManager.getToken(); if (!currentToken) { // 没有Token,跳转到登录页 window.location.href = '/login'; return; } try { // 测试Token是否有效 const testHeaders = { 'Authorization': `Bearer ${currentToken}` }; const testResponse = await fetch('http://localhost:8080/api/auth/test', { method: 'GET', headers: testHeaders }); if (testResponse.status === 403 || testResponse.status === 401) { // Token无效,清除并跳转 AuthManager.logout(); window.location.href = '/login'; } } catch (error) { console.error('Token验证失败:', error); } } // 页面加载时执行Token验证 window.addEventListener('DOMContentLoaded', validateTokenOnPageLoad); ``` ## 📝 重要注意事项 1. **Token完整性**: - 始终使用变量方式传递Token,避免字符串截断 - 在存储和读取Token时检查完整性 2. **Token安全**: - Token存储在localStorage中,注意防止XSS攻击 - 生产环境建议考虑更安全的存储方式 3. **请求头构建**: - 使用变量方式构建Authorization头 - 确保Token前缀"Bearer "正确添加 4. **错误处理**: - 统一处理401/403错误,自动跳转登录页 - 为用户提供友好的错误提示 5. **调试建议**: - 在控制台检查Token是否完整 - 验证请求头是否正确设置 这份文档强调了使用变量方式来确保Token完整传递,避免了直接字符串拼接可能导致的截断问题!