feat: add base docs
This commit is contained in:
48
pom.xml
48
pom.xml
@@ -33,7 +33,7 @@
|
||||
<lombok.version>1.18.30</lombok.version>
|
||||
<mybatis-plus.version>3.5.5</mybatis-plus.version>
|
||||
<dynamic-datasource.version>4.3.1</dynamic-datasource.version>
|
||||
<mysql.version>8.0.33</mysql.version>
|
||||
<mysql.version>8.0.33</mysql.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<!-- 核心依赖 -->
|
||||
@@ -43,14 +43,14 @@
|
||||
</dependency>
|
||||
|
||||
<!-- 数据库相关 -->
|
||||
<dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
</dependency>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<version>${mysql.version}</version>
|
||||
<version>${mysql.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
@@ -70,26 +70,26 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
<version>0.11.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-impl</artifactId>
|
||||
<version>0.11.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-jackson</artifactId>
|
||||
<version>0.11.5</version>
|
||||
</dependency>
|
||||
<!-- 添加验证依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
<version>0.11.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-impl</artifactId>
|
||||
<version>0.11.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-jackson</artifactId>
|
||||
<version>0.11.5</version>
|
||||
</dependency>
|
||||
<!-- 添加验证依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<!-- API文档 -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package icu.sunway.ai_spring_example.Controller.AuthController;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/auth")
|
||||
public class AuthController {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,422 @@
|
||||
# Auth模块接口文档
|
||||
|
||||
## 文档说明
|
||||
|
||||
本文档为Auth(认证授权)模块的接口详情,遵循《接口开发通用规范文档》的所有约定,基础路径为`/api/v1/auth`,数据交互格式为JSON,字符编码UTF-8,时间戳单位为毫秒。
|
||||
|
||||
## 1. 登录接口
|
||||
|
||||
### 接口基本信息
|
||||
|
||||
- 接口名称:用户登录
|
||||
- 接口路径:`/api/v1/auth/login`
|
||||
- 请求方法:POST
|
||||
- 接口描述:用户通过账号(手机号/用户名)+密码/验证码完成登录,返回登录令牌(token)
|
||||
|
||||
### 请求头
|
||||
|
||||
| 字段名 | 类型 | 必填性 | 示例值 |
|
||||
| --------------- | ------ | ------ | ---------------- |
|
||||
| Content-Type | String | 是 | application/json |
|
||||
| Accept-Language | String | 否 | zh-CN |
|
||||
|
||||
### 请求参数(Body)
|
||||
|
||||
| 字段名 | 类型 | 必填性 | 描述 | 示例值 |
|
||||
| ---------- | ------- | ------ | ------------------------------------------------ | ------------- |
|
||||
| account | String | 是 | 登录账号(手机号/用户名) | "13800138000" |
|
||||
| password | String | 否 | 登录密码(与verifyCode二选一) | "Abc123456" |
|
||||
| verifyCode | String | 否 | 验证码(与password二选一) | "8888" |
|
||||
| isRemember | Boolean | 否 | 是否记住登录(默认false,记住则token有效期延长) | true |
|
||||
|
||||
### 响应示例(成功)
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "登录成功",
|
||||
"timestamp": 1744238900000,
|
||||
"data": {
|
||||
"token": "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjEsInVzZXJuYW1lIjoiYWRtaW4iLCJleHAiOjE3NDQ4NDM3MDB9.QP8kXjZ8e7R5t5s7k9L2m1n8b7v6c5x4s3a2d1f0g9h8j7k6l5p4o3i2u1y0t9s8r7e6w5q4a3s2d1f0g",
|
||||
"expireTime": 1744843700000,
|
||||
"userInfo": {
|
||||
"userId": 1,
|
||||
"userName": "admin",
|
||||
"phoneNumber": "138****8000",
|
||||
"role": "ADMIN",
|
||||
"isEnabled": true,
|
||||
"createTime": 1743238900000
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 响应示例(失败)
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 400,
|
||||
"message": "验证码错误或已过期",
|
||||
"timestamp": 1744238900000,
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
### 状态码说明
|
||||
|
||||
| 状态码 | 说明 |
|
||||
| ------ | -------------------------------- |
|
||||
| 200 | 登录成功 |
|
||||
| 400 | 参数错误/验证码错误/账号密码错误 |
|
||||
| 403 | 账号被封禁 |
|
||||
| 429 | 登录失败次数过多,账号临时锁定 |
|
||||
| 500 | 服务器内部错误 |
|
||||
|
||||
## 2. 退出登录接口
|
||||
|
||||
### 接口基本信息
|
||||
|
||||
- 接口名称:用户退出登录
|
||||
- 接口路径:`/api/v1/auth/logout`
|
||||
- 请求方法:DELETE
|
||||
- 接口描述:销毁当前用户的登录令牌,退出登录状态
|
||||
|
||||
### 请求头
|
||||
|
||||
| 字段名 | 类型 | 必填性 | 示例值 |
|
||||
| --------------- | ------ | ------ | ------------------------------ |
|
||||
| Authorization | String | 是 | Bearer eyJhbGciOiJIUzI1NiJ9... |
|
||||
| Content-Type | String | 是 | application/json |
|
||||
| Accept-Language | String | 否 | zh-CN |
|
||||
|
||||
### 请求参数
|
||||
|
||||
无业务请求参数(仅需请求头携带token)
|
||||
|
||||
### 响应示例(成功)
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "退出登录成功",
|
||||
"timestamp": 1744238900000,
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
### 响应示例(失败)
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 401,
|
||||
"message": "Token已过期,请重新登录",
|
||||
"timestamp": 1744238900000,
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
### 状态码说明
|
||||
|
||||
| 状态码 | 说明 |
|
||||
| ------ | ---------------- |
|
||||
| 200 | 退出登录成功 |
|
||||
| 401 | Token失效/未登录 |
|
||||
| 500 | 服务器内部错误 |
|
||||
|
||||
## 3. 刷新Token接口
|
||||
|
||||
### 接口基本信息
|
||||
|
||||
- 接口名称:刷新登录令牌
|
||||
- 接口路径:`/api/v1/auth/refresh-token`
|
||||
- 请求方法:POST
|
||||
- 接口描述:通过旧Token刷新获取新的登录令牌,延长登录有效期
|
||||
|
||||
### 请求头
|
||||
|
||||
| 字段名 | 类型 | 必填性 | 示例值 |
|
||||
| --------------- | ------ | ------ | ------------------------------ |
|
||||
| Authorization | String | 是 | Bearer eyJhbGciOiJIUzI1NiJ9... |
|
||||
| Content-Type | String | 是 | application/json |
|
||||
| Accept-Language | String | 否 | zh-CN |
|
||||
|
||||
### 请求参数(Body)
|
||||
|
||||
| 字段名 | 类型 | 必填性 | 描述 | 示例值 |
|
||||
| ------ | ------ | ------ | ------------ | ------------------------- |
|
||||
| token | String | 是 | 旧的登录令牌 | "eyJhbGciOiJIUzI1NiJ9..." |
|
||||
|
||||
### 响应示例(成功)
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "Token刷新成功",
|
||||
"timestamp": 1744238900000,
|
||||
"data": {
|
||||
"newToken": "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjEsInVzZXJuYW1lIjoiYWRtaW4iLCJleHAiOjE3NDU0NDg1MDB9.Z7x6y5w4v3u2t1s0r9e8w7q6a5z4s3d2f1g0h9j8k7l6p5o4i3u2y1t0s9r8e7w6q5a4s3d2f1g0h9j8k7l6p5o4i",
|
||||
"expireTime": 1745448500000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 响应示例(失败)
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 401,
|
||||
"message": "Token已失效,无法刷新,请重新登录",
|
||||
"timestamp": 1744238900000,
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
### 状态码说明
|
||||
|
||||
| 状态码 | 说明 |
|
||||
| ------ | ------------------ |
|
||||
| 200 | Token刷新成功 |
|
||||
| 400 | 旧Token格式错误 |
|
||||
| 401 | 旧Token已过期/无效 |
|
||||
| 500 | 服务器内部错误 |
|
||||
|
||||
## 4. 获取当前用户信息接口
|
||||
|
||||
### 接口基本信息
|
||||
|
||||
- 接口名称:获取当前登录用户信息
|
||||
- 接口路径:`/api/v1/auth/user/info`
|
||||
- 请求方法:GET
|
||||
- 接口描述:根据登录令牌获取当前用户的基础信息(脱敏展示敏感字段)
|
||||
|
||||
### 请求头
|
||||
|
||||
| 字段名 | 类型 | 必填性 | 示例值 |
|
||||
| --------------- | ------ | ------ | ------------------------------ |
|
||||
| Authorization | String | 是 | Bearer eyJhbGciOiJIUzI1NiJ9... |
|
||||
| Content-Type | String | 是 | application/json |
|
||||
| Accept-Language | String | 否 | zh-CN |
|
||||
|
||||
### 请求参数
|
||||
|
||||
无业务请求参数(仅需请求头携带token)
|
||||
|
||||
### 响应示例(成功)
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "查询用户信息成功",
|
||||
"timestamp": 1744238900000,
|
||||
"data": {
|
||||
"userId": 1,
|
||||
"userName": "admin",
|
||||
"phoneNumber": "138****8000",
|
||||
"idCard": "310**********1234",
|
||||
"roleList": ["ADMIN"],
|
||||
"isEnabled": true,
|
||||
"createTime": 1743238900000,
|
||||
"createTimeStr": "2025-01-01 10:00:00",
|
||||
"lastLoginTime": 1744152500000,
|
||||
"lastLoginTimeStr": "2025-04-10 08:00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 响应示例(失败)
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 401,
|
||||
"message": "未登录,请先登录",
|
||||
"timestamp": 1744238900000,
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
### 状态码说明
|
||||
|
||||
| 状态码 | 说明 |
|
||||
| ------ | ---------------- |
|
||||
| 200 | 查询用户信息成功 |
|
||||
| 401 | Token失效/未登录 |
|
||||
| 404 | 用户信息不存在 |
|
||||
| 500 | 服务器内部错误 |
|
||||
|
||||
## 5. 发送登录验证码接口
|
||||
|
||||
### 接口基本信息
|
||||
|
||||
- 接口名称:发送登录验证码
|
||||
- 接口路径:`/api/v1/auth/send-login-code`
|
||||
- 请求方法:POST
|
||||
- 接口描述:向指定手机号发送登录验证码,限制发送频率
|
||||
|
||||
### 请求头
|
||||
|
||||
| 字段名 | 类型 | 必填性 | 示例值 |
|
||||
| --------------- | ------ | ------ | ---------------- |
|
||||
| Content-Type | String | 是 | application/json |
|
||||
| Accept-Language | String | 否 | zh-CN |
|
||||
|
||||
### 请求参数(Body)
|
||||
|
||||
| 字段名 | 类型 | 必填性 | 描述 | 示例值 |
|
||||
| ----------- | ------ | ------ | ------------------ | ------------- |
|
||||
| phoneNumber | String | 是 | 接收验证码的手机号 | "13800138000" |
|
||||
|
||||
### 响应示例(成功)
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "验证码发送成功,请注意查收",
|
||||
"timestamp": 1744238900000,
|
||||
"data": {
|
||||
"expireTime": 1744239200000 // 验证码过期时间戳(5分钟有效期)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 响应示例(失败)
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 429,
|
||||
"message": "验证码发送过于频繁,请1分钟后重试",
|
||||
"timestamp": 1744238900000,
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
### 状态码说明
|
||||
|
||||
| 状态码 | 说明 |
|
||||
| ------ | ------------------------------ |
|
||||
| 200 | 验证码发送成功 |
|
||||
| 400 | 手机号格式错误 |
|
||||
| 429 | 发送频率超限 |
|
||||
| 404 | 手机号未注册 |
|
||||
| 500 | 验证码发送失败(短信服务异常) |
|
||||
|
||||
## 6. 重置密码接口
|
||||
|
||||
### 接口基本信息
|
||||
|
||||
- 接口名称:重置登录密码
|
||||
- 接口路径:`/api/v1/auth/reset-password`
|
||||
- 请求方法:PUT
|
||||
- 接口描述:用户通过手机号+验证码重置登录密码(全量更新密码)
|
||||
|
||||
### 请求头
|
||||
|
||||
| 字段名 | 类型 | 必填性 | 示例值 |
|
||||
| --------------- | ------ | ------ | ---------------- |
|
||||
| Content-Type | String | 是 | application/json |
|
||||
| Accept-Language | String | 否 | zh-CN |
|
||||
|
||||
### 请求参数(Body)
|
||||
|
||||
| 字段名 | 类型 | 必填性 | 描述 | 示例值 |
|
||||
| ----------- | ------ | ------ | ----------------------------------------------- | ------------- |
|
||||
| phoneNumber | String | 是 | 绑定的手机号 | "13800138000" |
|
||||
| verifyCode | String | 是 | 验证码 | "8888" |
|
||||
| newPassword | String | 是 | 新密码(需符合密码规则:8-20位,含大小写+数字) | "Abc123456" |
|
||||
|
||||
### 响应示例(成功)
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "密码重置成功,请重新登录",
|
||||
"timestamp": 1744238900000,
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
### 响应示例(失败)
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 400,
|
||||
"message": "新密码格式不符合要求,需包含大小写字母和数字,长度8-20位",
|
||||
"timestamp": 1744238900000,
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
### 状态码说明
|
||||
|
||||
| 状态码 | 说明 |
|
||||
| ------ | -------------------------------- |
|
||||
| 200 | 密码重置成功 |
|
||||
| 400 | 参数错误/验证码错误/密码格式错误 |
|
||||
| 429 | 验证码发送频率超限/验证次数过多 |
|
||||
| 404 | 手机号未注册 |
|
||||
| 500 | 服务器内部错误 |
|
||||
|
||||
## 7. 校验Token有效性接口
|
||||
|
||||
### 接口基本信息
|
||||
|
||||
- 接口名称:校验Token有效性
|
||||
- 接口路径:`/api/v1/auth/verify-token`
|
||||
- 请求方法:GET
|
||||
- 接口描述:校验当前登录令牌是否有效,返回令牌基础信息
|
||||
|
||||
### 请求头
|
||||
|
||||
| 字段名 | 类型 | 必填性 | 示例值 |
|
||||
| --------------- | ------ | ------ | ------------------------------ |
|
||||
| Authorization | String | 是 | Bearer eyJhbGciOiJIUzI1NiJ9... |
|
||||
| Content-Type | String | 是 | application/json |
|
||||
| Accept-Language | String | 否 | zh-CN |
|
||||
|
||||
### 请求参数
|
||||
|
||||
无业务请求参数(仅需请求头携带token)
|
||||
|
||||
### 响应示例(成功)
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "Token有效",
|
||||
"timestamp": 1744238900000,
|
||||
"data": {
|
||||
"userId": 1,
|
||||
"token": "eyJhbGciOiJIUzI1NiJ9...",
|
||||
"isValid": true,
|
||||
"expireTime": 1744843700000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 响应示例(失败)
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 401,
|
||||
"message": "Token无效或已过期",
|
||||
"timestamp": 1744238900000,
|
||||
"data": {
|
||||
"isValid": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 状态码说明
|
||||
|
||||
| 状态码 | 说明 |
|
||||
| ------ | ---------------- |
|
||||
| 200 | Token有效 |
|
||||
| 401 | Token无效/已过期 |
|
||||
| 500 | 服务器内部错误 |
|
||||
|
||||
## 通用说明
|
||||
|
||||
1. 所有接口响应均遵循通用响应格式,包含`code`、`message`、`timestamp`字段,`data`字段按需返回;
|
||||
2. 敏感信息(手机号、身份证号)均做脱敏处理,符合安全规范;
|
||||
3. 接口频率限制遵循通用规范:验证码接口1分钟/次、1小时/5次,登录接口5分钟连续失败5次锁定15分钟,通用接口QPS≤10;
|
||||
4. 所有入参均做合法性校验,参数错误返回400状态码并提示具体错误信息;
|
||||
5. Token格式为`Bearer + 空格 + token`,需登录的接口未传/传错Token均返回401状态码。
|
||||
@@ -10,7 +10,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/permission")
|
||||
@RequestMapping("/api/v1/permission")
|
||||
public class PermissionController {
|
||||
|
||||
@Resource
|
||||
|
||||
@@ -10,7 +10,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/role")
|
||||
@RequestMapping("/api/v1/role")
|
||||
public class RoleController {
|
||||
|
||||
@Resource
|
||||
|
||||
@@ -11,7 +11,7 @@ import jakarta.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/role-permission")
|
||||
@RequestMapping("/api/v1/role-permission")
|
||||
public class RolePermissionController {
|
||||
|
||||
@Resource
|
||||
|
||||
@@ -10,7 +10,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/user")
|
||||
@RequestMapping("/api/v1/user")
|
||||
public class UserController {
|
||||
|
||||
@Resource
|
||||
|
||||
@@ -13,7 +13,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/user-role")
|
||||
@RequestMapping("/api/v1/user-role")
|
||||
public class UserRoleController {
|
||||
|
||||
@Resource
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
# 接口开发通用规范文档
|
||||
|
||||
## 文档说明
|
||||
|
||||
本规范为项目所有接口的通用开发准则,适用于前后端接口对接、后端接口开发、接口文档编写等场景,所有业务接口均需遵循本规范。
|
||||
|
||||
### 基础约定
|
||||
|
||||
- 接口基础路径:`/api/v1`(各业务模块在基础路径后追加,如Auth模块:`/api/v1/auth`)
|
||||
- 数据交互格式:JSON
|
||||
- 字符编码:UTF-8
|
||||
- 时间戳单位:毫秒(整数类型)
|
||||
- 接口版本管理:通过URL路径版本号(如v1)区分,不使用请求参数/请求头区分
|
||||
|
||||
## 一、通用请求规范
|
||||
|
||||
### 1. 请求方式(RESTful规范)
|
||||
|
||||
| 操作类型 | 请求方法 | 典型场景 | 示例 |
|
||||
| ------------- | -------- | -------------------------------- | ----------------------------- |
|
||||
| 新增/提交数据 | POST | 登录、发送验证码、创建资源 | `/api/v1/auth/login` |
|
||||
| 查询数据 | GET | 获取详情、校验状态、列表查询 | `/api/v1/auth/user/info` |
|
||||
| 修改数据 | PUT | 全量更新(如重置密码、修改信息) | `/api/v1/auth/reset-password` |
|
||||
| 部分更新 | PATCH | 局部更新(如修改用户昵称) | `/api/v1/user/nickname` |
|
||||
| 删除数据 | DELETE | 退出登录、删除资源 | `/api/v1/auth/logout` |
|
||||
|
||||
### 2. 请求头规范
|
||||
|
||||
| 字段名 | 类型 | 必填性 | 描述 | 示例 |
|
||||
| --------------- | ------ | ------ | --------------------------------------------------------- | -------------------------------- |
|
||||
| Authorization | String | 非必选 | 登录令牌,格式为`Bearer + 空格 + token`(需登录接口必传) | "Bearer eyJhbGciOiJIUzI1NiJ9..." |
|
||||
| Content-Type | String | 必选 | 请求体格式,仅支持`application/json` | "application/json" |
|
||||
| Accept-Language | String | 非必选 | 语言类型,默认zh-CN | "zh-CN" |
|
||||
|
||||
### 3. 分页请求参数(列表接口必传)
|
||||
|
||||
所有列表查询接口均需支持分页,分页参数统一通过`GET`请求参数传递(POST请求可放在Body中),参数规范如下:
|
||||
|
||||
| 字段名 | 类型 | 必填性 | 默认值 | 描述 | 示例 |
|
||||
| ------ | ------- | ------ | ------ | ----------------------------- | ---- |
|
||||
| page | Integer | 否 | 1 | 当前页码(从1开始) | 1 |
|
||||
| limit | Integer | 否 | 10 | 每页显示条数(最大不超过100) | 10 |
|
||||
|
||||
#### 示例
|
||||
|
||||
```plain
|
||||
GET /api/v1/user/list?current=1&size=10
|
||||
```
|
||||
|
||||
### 4. 请求参数命名规范
|
||||
|
||||
- 字段名使用**小驼峰命名**(如`userName`、`phoneNumber`),禁止使用下划线/连字符;
|
||||
- 布尔类型字段命名:使用`isXXX`格式(如`isRemember`、`isEnabled`);
|
||||
- 时间类字段:统一使用`createTime`、`updateTime`等,禁止使用`create_at`;
|
||||
- 参数值:手机号、身份证号等字符串类型参数,值为纯数字时仍以字符串传递。
|
||||
|
||||
## 二、通用响应规范
|
||||
|
||||
### 1. 基础响应格式(所有接口统一)
|
||||
|
||||
所有接口响应必须包含`code`、`message`、`timestamp`字段,`data`字段为可选(无业务数据时返回`null`)。
|
||||
|
||||
#### 格式定义
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200, // 整数,业务状态码
|
||||
"message": "操作成功", // 字符串,提示信息(前端可直接展示)
|
||||
"timestamp": 1744238900000, // 整数,服务器响应时间戳(毫秒)
|
||||
"data": {} // 任意类型,业务数据(无数据时为null)
|
||||
}
|
||||
```
|
||||
|
||||
#### 字段说明
|
||||
|
||||
| 字段名 | 类型 | 必填性 | 描述 |
|
||||
| --------- | ------- | ------ | --------------------------------------------------------------------------- |
|
||||
| code | Integer | 是 | 业务状态码(200表示成功,非200表示异常) |
|
||||
| message | String | 是 | 响应提示信息(成功/失败描述,需友好、简洁) |
|
||||
| timestamp | Integer | 是 | 服务器处理请求的时间戳(毫秒),前端可用于时间展示/校验 |
|
||||
| data | Any | 否 | 业务数据体:1. 无数据时为null;2. 单条数据为Object;3. 列表数据遵循分页规范 |
|
||||
|
||||
### 2. 分页响应格式(列表接口专用)
|
||||
|
||||
列表接口的`data`字段必须遵循以下结构,禁止自定义分页字段名/格式。
|
||||
|
||||
#### 格式定义
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "查询成功",
|
||||
"timestamp": 1744238900000,
|
||||
"data": {
|
||||
"records": [], // 数组,当前页数据列表
|
||||
"total": 0, // 整数,符合条件的总记录数
|
||||
"size": 10, // 整数,每页显示条数(实际返回条数)
|
||||
"current": 1, // 整数,当前页码
|
||||
"pages": 0 // 整数,总页数(total/size向上取整)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 字段说明
|
||||
|
||||
| 字段名 | 类型 | 必填性 | 描述 |
|
||||
| ------- | ------- | ------ | ----------------------------------------- |
|
||||
| records | Array | 是 | 当前页数据列表(无数据时为空数组) |
|
||||
| total | Integer | 是 | 总记录数(用于计算总页数/分页展示) |
|
||||
| size | Integer | 是 | 每页请求条数(与请求参数size一致) |
|
||||
| current | Integer | 是 | 当前页码(与请求参数current一致) |
|
||||
| pages | Integer | 是 | 总页数(计算公式:Math.ceil(total/size)) |
|
||||
|
||||
#### 分页响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "用户列表查询成功",
|
||||
"timestamp": 1744238900000,
|
||||
"data": {
|
||||
"records": [
|
||||
{"id": 1, "username": "admin", "role": "ADMIN"},
|
||||
{"id": 2, "username": "user1", "role": "USER"}
|
||||
],
|
||||
"total": 20,
|
||||
"size": 10,
|
||||
"current": 1,
|
||||
"pages": 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 通用状态码规范
|
||||
|
||||
| 状态码 | 含义 | 核心场景 |
|
||||
| ------ | -------------- | -------------------------------------- |
|
||||
| 200 | 操作成功 | 所有接口正常响应 |
|
||||
| 400 | 参数错误 | 请求参数缺失/格式错误/校验不通过 |
|
||||
| 401 | 未授权 | token失效/未登录/令牌格式错误 |
|
||||
| 403 | 禁止访问 | 账号被封禁/权限不足/IP受限 |
|
||||
| 404 | 资源不存在 | 用户不存在/接口路径错误/数据记录不存在 |
|
||||
| 409 | 资源冲突 | 用户名重复/手机号已绑定/操作重复提交 |
|
||||
| 429 | 请求过于频繁 | 验证码发送频率超限/接口调用频率超限 |
|
||||
| 500 | 服务器内部错误 | 服务端逻辑异常/第三方接口调用失败 |
|
||||
|
||||
## 三、接口命名规范
|
||||
|
||||
### 1. URL路径命名
|
||||
|
||||
- 路径全部使用**小写字母**,多个单词用连字符(-)分隔(如`/api/v1/auth/refresh-token`);
|
||||
- 路径使用名词而非动词(RESTful规范),如`/api/v1/user`(用户资源)而非`/api/v1/getUser`;
|
||||
- 资源ID放在路径末尾,如`/api/v1/user/123`(查询ID为123的用户)。
|
||||
|
||||
### 2. 响应字段命名
|
||||
|
||||
- 与请求参数一致,使用**小驼峰命名**;
|
||||
- 时间字段:优先返回时间戳(Integer,毫秒),如需返回格式化时间,字段名加`Str`后缀(如`createTimeStr`);
|
||||
- 金额字段:以分为单位返回整数(避免浮点精度问题),字段名加`Cent`后缀(如`amountCent`)。
|
||||
|
||||
## 四、安全规范(必遵循)
|
||||
|
||||
### 1. 密码/敏感信息处理
|
||||
|
||||
- 敏感信息返回:手机号、身份证号等脱敏展示(如`138****8000`);
|
||||
- Token处理:JWT Token不存储敏感信息(如密码),Redis存储的Token设置合理过期时间。
|
||||
|
||||
### 2. 接口频率限制
|
||||
|
||||
- 验证码接口:同一手机号1分钟内最多1次,1小时内最多5次;
|
||||
- 登录接口:同一账号5分钟内连续失败5次,临时锁定15分钟;
|
||||
- 通用接口:单IP/单用户接口调用频率不超过QPS 10。
|
||||
|
||||
### 3. 数据校验
|
||||
|
||||
- 所有入参必须做合法性校验(格式、长度、范围);
|
||||
|
||||
## 五、异常响应示例
|
||||
|
||||
### 1. 参数错误(400)
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 400,
|
||||
"message": "手机号格式错误",
|
||||
"timestamp": 1744238900000,
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 未授权(401)
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 401,
|
||||
"message": "Token已过期,请重新登录",
|
||||
"timestamp": 1744238900000,
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 服务器错误(500)
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 500,
|
||||
"message": "服务器内部错误,请稍后重试",
|
||||
"timestamp": 1744238900000,
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
1. 所有接口必须遵循**统一响应格式**(包含code/message/timestamp),列表接口强制分页并使用指定分页结构;
|
||||
2. 接口命名、参数/字段命名需符合RESTful规范和小驼峰/小写连字符约定,保证可读性;
|
||||
3. 安全规范是核心底线,密码、Token、频率限制等规则必须严格执行,避免安全漏洞;
|
||||
4. 本规范为基础准则,各业务模块可在本规范基础上补充模块专属规则,但不得与本规范冲突。
|
||||
@@ -0,0 +1,256 @@
|
||||
# 接口开发规范
|
||||
|
||||
## 0. 与API文档规范对照说明
|
||||
|
||||
本开发规范与`Controller/api-doc-standard.md`互为补充:
|
||||
|
||||
- **api-dev-standard.md**:指导**代码实现**(如何编写符合规范的代码)
|
||||
- **api-doc-standard.md**:定义**接口契约**(请求/响应格式标准)
|
||||
|
||||
### 关键一致性说明
|
||||
|
||||
| 规范维度 | 代码实现规范 (本文件) | 接口文档规范 (api-doc-standard) | 对齐状态 |
|
||||
| ------------ | -------------------------------- | ----------------------------------- | -------------------------------------- |
|
||||
| **响应格式** | 必须使用ResponseUtils生成响应 | 强制要求code/message/timestamp/data | ✅ 对齐 |
|
||||
| **分页参数** | 代码中参数名: `page`/`limit` | 文档中参数名: `page`/`limit` | ✅ 语义对齐(page=current, limit=size) |
|
||||
| **状态码** | ResponseUtils需支持400/401等状态 | 明确200/400/401等状态码语义 | ⚠️ 需增强 |
|
||||
| **时间字段** | Entity用LocalDateTime | 响应用时间戳(Integer) | ⚠️ 需转换 |
|
||||
|
||||
> **特别说明**:当前代码中`ResponseUtils`实现需扩展以完全符合api-doc-standard,但开发规范以**实际代码结构**为准。
|
||||
|
||||
---
|
||||
|
||||
## 1. 整体架构规范
|
||||
|
||||
### 1.1 分层结构
|
||||
|
||||
遵循CLAUDE.md定义的分层架构,特别注意:
|
||||
|
||||
- **Controller层**:业务逻辑的主要编写位置
|
||||
- **Service层**:仅包含接口定义和MyBatis Plus继承实现
|
||||
- 接口:`I{Name}Service` 继承 `IService<Entity>`
|
||||
- 实现:`{Name}ServiceImpl` 继承 `ServiceImpl<Mapper, Entity>`
|
||||
- **业务逻辑不应下沉到Service层**,Controller直接调用Service提供的CRUD方法
|
||||
|
||||
### 1.2 目录规范
|
||||
|
||||
- Controller按实体划分目录:`Controller/{EntityName}Controller/`
|
||||
- **Entity目录**:`Entity/` 下直接存放实体类(**无需子目录**)
|
||||
- **Mapper目录**:`Mapper/` 下直接存放Mapper接口(**无需子目录**)
|
||||
- **Service目录**:
|
||||
- 接口:`Service/`
|
||||
- 实现:`Service/Implements/`
|
||||
- 示例:
|
||||
- `User.java` → `Entity/User.java`
|
||||
- `UserMapper.java` → `Mapper/UserMapper.java`
|
||||
|
||||
## 2. Controller编写规范
|
||||
|
||||
### 2.1 服务注入
|
||||
|
||||
```java
|
||||
@Resource
|
||||
private IUserService userService;
|
||||
```
|
||||
|
||||
- **必须**使用`@Resource`而非`@Autowired`
|
||||
- **不得**在Service层编写业务逻辑
|
||||
|
||||
### 2.2 响应处理(必须遵守)
|
||||
|
||||
**所有接口必须使用ResponseUtils统一响应格式**:
|
||||
|
||||
对于 Controller 中的函数返回类型,统一使用 Object 类型,而不是具体的实体类。
|
||||
|
||||
如果需要编写具体 VO 实体类,在对应的 Controller 目录下创建 vo 文件夹并在其中定义。
|
||||
|
||||
```java
|
||||
// 成功响应
|
||||
return ResponseUtils.success(data);
|
||||
|
||||
// 失败响应(需指定状态码)
|
||||
return ResponseUtils.fail(400, "用户名格式错误");
|
||||
```
|
||||
|
||||
- **必须包含**:
|
||||
- `code`:按[api-doc-standard#状态码规范](Controller/api-doc-standard.md#三、通用状态码规范)设置
|
||||
- `timestamp`:当前时间戳(`System.currentTimeMillis()`)
|
||||
- `data`:业务数据(列表接口需返回标准分页结构)
|
||||
- **禁止**直接返回原始对象
|
||||
|
||||
### 2.3 分页处理
|
||||
|
||||
**必须使用MyBatis Plus原生Page对象**:
|
||||
|
||||
```java
|
||||
@GetMapping
|
||||
public Object getAllUsers(
|
||||
@RequestParam(defaultValue = "1") Integer page,
|
||||
@RequestParam(defaultValue = "10") Integer limit) {
|
||||
|
||||
Page<User> pageObj = new Page<>(page, limit);
|
||||
return ResponseUtils.success(userService.page(pageObj));
|
||||
}
|
||||
```
|
||||
|
||||
- **关键点**:
|
||||
- Page对象字段与API响应结构完全匹配(records/total/size/current/pages)
|
||||
- **禁止**手动构建分页响应
|
||||
- 分页参数**代码中命名为`page`/`limit`**
|
||||
|
||||
### 2.4 查询操作
|
||||
|
||||
**简单查询**直接使用Service方法:
|
||||
|
||||
```java
|
||||
@GetMapping("/{id}")
|
||||
public Object getUserById(@PathVariable Long id) {
|
||||
return ResponseUtils.success(userService.getById(id));
|
||||
}
|
||||
```
|
||||
|
||||
**复杂查询**使用QueryWrapper:
|
||||
|
||||
```java
|
||||
@GetMapping("/username/{username}")
|
||||
public Object getUserByUsername(@PathVariable String username) {
|
||||
QueryWrapper<User> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq("username", username);
|
||||
return ResponseUtils.success(userService.getOne(wrapper));
|
||||
}
|
||||
```
|
||||
|
||||
- **注意**:查询条件构建应在Controller层完成
|
||||
|
||||
## 3. Entity层规范
|
||||
|
||||
### 3.1 基础结构
|
||||
|
||||
```java
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("user")
|
||||
public class User {
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
private String username;
|
||||
private String password;
|
||||
// ...其他字段
|
||||
}
|
||||
```
|
||||
|
||||
- **必须使用**:
|
||||
- Lombok注解:`@Data` + `@NoArgsConstructor` + `@AllArgsConstructor`
|
||||
- MyBatis Plus注解:`@TableName` + `@TableId`
|
||||
- **字段命名**:小驼峰命名(`createTime`而非`create_time`)
|
||||
|
||||
### 3.2 时间字段处理
|
||||
|
||||
- **Entity层**:使用`LocalDateTime`类型(如`createTime`)
|
||||
|
||||
## 4. Mapper层规范
|
||||
|
||||
### 4.1 基础结构
|
||||
|
||||
```java
|
||||
@Mapper
|
||||
public interface UserMapper extends BaseMapper<User> {
|
||||
// 仅允许MyBatis Plus内置方法,自定义SQL需走Service层
|
||||
}
|
||||
```
|
||||
|
||||
- **必须**继承`BaseMapper<Entity>`
|
||||
- **禁止**在Mapper接口中添加方法(自定义SQL需通过Service层)
|
||||
|
||||
## 5. Service层规范
|
||||
|
||||
### 5.1 接口定义
|
||||
|
||||
```java
|
||||
public interface IUserService extends IService<User> {
|
||||
// 仅允许扩展MyBatis Plus未提供的方法
|
||||
}
|
||||
```
|
||||
|
||||
- **必须**继承`IService<Entity>`
|
||||
- **仅当需要**扩展MyBatis Plus未提供的方法时才添加方法
|
||||
|
||||
### 5.2 实现类
|
||||
|
||||
```java
|
||||
@Service
|
||||
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
|
||||
@Resource
|
||||
private UserMapper userMapper;
|
||||
}
|
||||
```
|
||||
|
||||
- **必须**继承`ServiceImpl<Mapper, Entity>`
|
||||
- **禁止**在实现类中编写业务逻辑(仅用于注入Mapper)
|
||||
|
||||
## 6. 禁止行为清单
|
||||
|
||||
| 类型 | 错误示例 | 正确做法 |
|
||||
| ------------ | ----------------------------------- | ------------------------------------ |
|
||||
| 业务逻辑位置 | 在ServiceImpl中编写业务 | 所有业务逻辑放在Controller |
|
||||
| 响应格式 | 直接返回`new ResponseEntity<>(...)` | 用ResponseUtils生成带timestamp的响应 |
|
||||
| 分页参数 | 使用`offset`/`pageSize` | 统一用`page`/`limit`参数 |
|
||||
| 状态码 | 所有错误返回500 | 按[api-doc-standard]返回400/401等 |
|
||||
| 时间字段 | 直接返回LocalDateTime | 转换为时间戳或格式化字符串 |
|
||||
|
||||
## 7. 必须使用的工具类
|
||||
|
||||
| 工具类 | 用途 | 示例 |
|
||||
| --------------- | -------------- | ------------------------------------- |
|
||||
| `ResponseUtils` | 生成标准化响应 | `ResponseUtils.fail(400, "参数错误")` |
|
||||
|
||||
## 8. 接口设计原则
|
||||
|
||||
1. **RESTful规范**:
|
||||
- 路径使用**复数名词**:`/users`而非`/user`
|
||||
- **参数命名**:代码用`page`/`limit`,文档用`current`/`size`
|
||||
|
||||
2. **字段转换**:
|
||||
- Entity的`LocalDateTime` → 接口响应需转为时间戳
|
||||
- 敏感字段(如密码)需在Controller层过滤:`user.setPassword(null)`
|
||||
|
||||
3. **错误处理**:
|
||||
- 按[api-doc-standard#通用状态码规范](Controller/api-doc-standard.md#三、通用状态码规范)返回精确错误
|
||||
- 示例:`return ResponseUtils.fail(409, "用户名已存在");`
|
||||
|
||||
## 9. 完整示例
|
||||
|
||||
```java
|
||||
@RestController
|
||||
@RequestMapping("/users")
|
||||
public class UserController {
|
||||
|
||||
@Resource
|
||||
private IUserService userService;
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public Object getUser(@PathVariable Long id) {
|
||||
User user = userService.getById(id);
|
||||
// 过滤敏感字段
|
||||
user.setPassword(null);
|
||||
// 转换时间格式
|
||||
return ResponseUtils.success(user);
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public Object listUsers(
|
||||
@RequestParam(defaultValue = "1") Integer page,
|
||||
@RequestParam(defaultValue = "10") Integer limit) {
|
||||
|
||||
// 参数校验
|
||||
if (limit > 100) {
|
||||
return ResponseUtils.fail(400, "每页数量不能超过100");
|
||||
}
|
||||
|
||||
Page<User> pageObj = new Page<>(page, limit);
|
||||
Page<User> resultPage = userService.page(pageObj);
|
||||
return ResponseUtils.success(resultPage);
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -145,19 +145,6 @@ public class JsonUtils {
|
||||
return toObject(json, Map.class, keyClazz, valueClazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将对象转换为Map
|
||||
*
|
||||
* @param obj 对象
|
||||
* @return Map
|
||||
*/
|
||||
public static Map<String, Object> toMap(Object obj) {
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
return objectMapper.convertValue(obj, Map.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证JSON字符串是否有效
|
||||
*
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
package icu.sunway.ai_spring_example.Utils;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 分页工具类
|
||||
*/
|
||||
public class PageUtils {
|
||||
|
||||
/**
|
||||
* 默认页码
|
||||
*/
|
||||
public static final Integer DEFAULT_PAGE = 1;
|
||||
|
||||
/**
|
||||
* 默认每页数量
|
||||
*/
|
||||
public static final Integer DEFAULT_LIMIT = 10;
|
||||
|
||||
/**
|
||||
* 最大每页数量
|
||||
*/
|
||||
public static final Integer MAX_LIMIT = 100;
|
||||
|
||||
/**
|
||||
* 分页结果类
|
||||
*
|
||||
* @param <T> 数据类型
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public static class PaginationResult<T> {
|
||||
private Integer currentPage;
|
||||
private Integer pageSize;
|
||||
private Long totalItems;
|
||||
private Integer totalPages;
|
||||
private List<T> list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证和调整分页参数
|
||||
*
|
||||
* @param page 页码
|
||||
* @param limit 每页数量
|
||||
* @return 调整后的分页参数数组 [page, limit]
|
||||
*/
|
||||
public static Integer[] validatePageParams(Integer page, Integer limit) {
|
||||
// 验证页码
|
||||
if (page == null || page < 1) {
|
||||
page = DEFAULT_PAGE;
|
||||
}
|
||||
|
||||
// 验证每页数量
|
||||
if (limit == null || limit < 1 || limit > MAX_LIMIT) {
|
||||
limit = DEFAULT_LIMIT;
|
||||
}
|
||||
|
||||
return new Integer[] { page, limit };
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建Page对象
|
||||
*
|
||||
* @param page 页码
|
||||
* @param limit 每页数量
|
||||
* @return Page对象
|
||||
*/
|
||||
public static <T> Page<T> createPage(Integer page, Integer limit) {
|
||||
Integer[] params = validatePageParams(page, limit);
|
||||
return new Page<>(params[0], params[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将MyBatis Plus的Page结果转换为分页结果
|
||||
*
|
||||
* @param pageResult MyBatis Plus的Page结果
|
||||
* @return 分页结果
|
||||
*/
|
||||
public static <T> PaginationResult<T> createPaginationResult(IPage<T> pageResult) {
|
||||
return new PaginationResult<>(
|
||||
(int) pageResult.getCurrent(),
|
||||
(int) pageResult.getSize(),
|
||||
pageResult.getTotal(),
|
||||
(int) pageResult.getPages(),
|
||||
pageResult.getRecords());
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建空的分页结果
|
||||
*
|
||||
* @param page 页码
|
||||
* @param limit 每页数量
|
||||
* @return 空的分页结果
|
||||
*/
|
||||
public static <T> PaginationResult<T> createEmptyPaginationResult(Integer page, Integer limit) {
|
||||
Integer[] params = validatePageParams(page, limit);
|
||||
return new PaginationResult<>(
|
||||
params[0],
|
||||
params[1],
|
||||
0L,
|
||||
0,
|
||||
List.of());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user