用戶管理控制器,實現了用戶CRUD操作的RESTful API:
1. 類結構與核心注解
1.1 控制器聲明
@RestController
@RequestMapping("/api/users")
public class UserController
@RestController 深度解析:
- 組合注解:
@Controller
+@ResponseBody
- 自動序列化:返回的對象自動轉換為JSON
- Spring MVC集成:無需手動配置JSON轉換器
- RESTful設計:專為API接口設計
@RequestMapping(“/api/users”) 路徑設計:
- 統一前綴:所有用戶相關接口以
/api/users
開頭 - 版本控制:便于后續添加
/api/v2/users
- 語義清晰:一看就知道是用戶管理接口
1.2 依賴注入與日志
private static final Logger log = LoggerFactory.getLogger(UserController.class);@Autowired
private UserService userService;
日志配置:
- SLF4J框架:統一的日志接口
- 類級別Logger:每個類有獨立的日志記錄器
- 靜態final:性能優化,避免重復創建
依賴注入優勢:
- 松耦合:Controller不直接依賴具體實現
- 易測試:可以注入Mock對象進行單元測試
- 配置驅動:Spring容器管理對象生命周期
2. RESTful API設計解析
2.1 HTTP方法與URL映射
功能 | HTTP方法 | URL | 說明 |
---|---|---|---|
創建用戶 | POST | /api/users | 創建資源 |
刪除用戶 | DELETE | /api/users/{id} | 刪除指定資源 |
更新用戶 | PUT | /api/users/{id} | 完整更新資源 |
查詢單個用戶 | GET | /api/users/{id} | 獲取指定資源 |
查詢所有用戶 | GET | /api/users | 獲取資源列表 |
分頁查詢 | GET | /api/users/page | 分頁獲取資源 |
RESTful設計優點:
- 語義明確:HTTP方法表達操作意圖
- URL簡潔:資源導向的路徑設計
- 標準化:遵循HTTP協議規范
3. 核心接口詳細解析
3.1 創建用戶接口
@PostMapping
public Result<User> createUser(@RequestBody User user) {try {User createdUser = userService.createUser(user);return Result.success(createdUser);} catch (Exception e) {log.error("創建用戶失敗", e);return Result.<User>error(e.getMessage());}
}
@PostMapping 解析:
- HTTP POST:用于創建資源
- 無路徑參數:直接映射到類路徑
/api/users
@RequestBody 詳解:
- JSON反序列化:自動將請求體JSON轉換為User對象
- Content-Type要求:前端需設置
application/json
- 參數驗證:可結合Bean Validation進行參數校驗
前端請求示例:
// 前端請求
fetch('/api/users', {method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify({username: 'newuser',password: '123456',email: 'newuser@example.com'})
})
3.2 刪除用戶接口
@DeleteMapping("/{id}")
public Result<Void> deleteUser(@PathVariable Long id) {try {boolean success = userService.deleteUser(id);if (success) {return Result.success();} else {return Result.<Void>error("用戶不存在");}} catch (Exception e) {log.error("刪除用戶失敗", e);return Result.<Void>error(e.getMessage());}
}
@PathVariable 詳解:
- 路徑參數提取:從URL
/api/users/123
中提取id=123
- 類型轉換:自動將字符串轉換為Long類型
- 參數驗證:Spring自動處理類型轉換異常
業務邏輯處理:
- 存在性檢查:先檢查用戶是否存在
- 狀態反饋:根據刪除結果返回不同信息
- 冪等性:多次刪除同一資源結果一致
3.3 更新用戶接口
@PutMapping("/{id}")
public Result<User> updateUser(@PathVariable Long id, @RequestBody User user) {try {user.setId(id); // 關鍵:設置ID確保更新正確的用戶User updatedUser = userService.updateUser(user);return Result.success(updatedUser);} catch (Exception e) {log.error("更新用戶失敗", e);return Result.<User>error(e.getMessage());}
}
設計要點:
- PUT語義:完整替換資源
- ID一致性:URL中的ID覆蓋請求體中的ID
- 返回更新后數據:便于前端同步最新狀態
前端使用示例:
// 更新用戶信息
fetch('/api/users/123', {method: 'PUT',headers: { 'Content-Type': 'application/json' },body: JSON.stringify({username: 'updateduser',email: 'updated@example.com'})
})
3.4 查詢接口設計
單用戶查詢
@GetMapping("/{id}")
public Result<User> getUserById(@PathVariable Long id)
用戶名查詢
@GetMapping("/username/{username}")
public Result<User> getUserByUsername(@PathVariable String username)
郵箱查詢
@GetMapping("/email/{email}")
public Result<User> getUserByEmail(@PathVariable String email)
URL設計模式:
- RESTful風格:
/資源/查詢條件/值
- 語義明確:URL即文檔
- 易于理解:符合直覺的路徑結構
3.5 分頁查詢核心實現
@GetMapping("/page")
public Result<Map<String, Object>> getUsersByPage(@RequestParam(defaultValue = "1") Integer pageNum,@RequestParam(defaultValue = "10") Integer pageSize,@RequestParam(required = false) String username) {
@RequestParam 詳解:
- defaultValue:提供默認值,提升用戶體驗
- required = false:可選參數,支持條件查詢
- 類型轉換:自動將字符串轉換為Integer
分頁邏輯:
// 條件分支:搜索 vs 普通分頁
if (username != null && !username.trim().isEmpty()) {users = userService.searchUsersByUsername(username, pageNum, pageSize);total = userService.getSearchTotalCount(username);
} else {users = userService.getUsersByPage(pageNum, pageSize);total = userService.getTotalCount();
}
返回數據結構:
Map<String, Object> data = new HashMap<>();
data.put("list", users); // 當前頁數據
data.put("total", total); // 總記錄數
data.put("pageNum", pageNum); // 當前頁碼
data.put("pageSize", pageSize); // 每頁大小
data.put("pages", (total + pageSize - 1) / pageSize); // 總頁數
前端調用示例:
// 普通分頁
fetch('/api/users/page?pageNum=1&pageSize=10')// 搜索分頁
fetch('/api/users/page?pageNum=1&pageSize=10&username=zhang')
3.6 密碼修改接口
@PutMapping("/{id}/password")
public Result<Void> changePassword(@PathVariable Long id, @RequestBody Map<String, String> passwordData)
設計特點:
- 專用接口:密碼修改獨立于普通更新
- 安全考慮:需要提供原密碼驗證
- Map參數:靈活接收鍵值對數據
請求體格式:
{"oldPassword": "123456","newPassword": "newpass123"
}
安全驗證流程:
// 1. 參數驗證
if (oldPassword == null || newPassword == null) {return Result.<Void>error("密碼不能為空");
}// 2. 用戶存在性檢查
User user = userService.getUserById(id);
if (user == null) {return Result.<Void>error("用戶不存在");
}// 3. 原密碼驗證
if (!oldPassword.equals(user.getPassword())) {return Result.<Void>error("原密碼錯誤");
}
4. 異常處理機制
4.1 統一異常處理模式
try {// 業務邏輯
} catch (Exception e) {log.error("操作失敗", e);return Result.<Type>error(e.getMessage());
}
異常處理優勢:
- 用戶友好:返回可讀的錯誤信息
- 系統穩定:防止異常導致系統崩潰
- 便于調試:記錄詳細的錯誤日志
4.2 改進
// 更細粒度的異常處理
try {// 業務邏輯
} catch (BusinessException e) {// 業務異常log.warn("業務異常: {}", e.getMessage());return Result.error(e.getMessage());
} catch (DataAccessException e) {// 數據訪問異常log.error("數據庫操作失敗", e);return Result.error("系統繁忙,請稍后重試");
} catch (Exception e) {// 未知異常log.error("系統異常", e);return Result.error("系統錯誤");
}
5. 響應格式統一
5.1 成功響應
{"code": 200,"message": "操作成功","data": {"id": 1,"username": "admin","email": "admin@example.com"}
}
5.2 失敗響應
{"code": 500,"message": "用戶不存在","data": null
}
5.3 分頁響應
{"code": 200,"message": "操作成功","data": {"list": [...],"total": 50,"pageNum": 1,"pageSize": 10,"pages": 5}
}
-
RESTful標準:符合HTTP協議語義
-
統一響應格式:便于前端處理
-
完整CRUD操作:功能齊全
-
異常處理機制:提升系統穩定性
-
日志記錄:便于問題排查
-
參數驗證:基礎的輸入校驗
-
參數驗證增強:使用Bean Validation
-
權限控制:添加認證授權
-
接口文檔:使用Swagger注解
-
批量操作:支持批量刪除/更新
-
緩存策略:添加查詢緩存
-
限流控制:防止接口被惡意調用
7.1 參數驗證增強
@PostMapping
public Result<User> createUser(@RequestBody @Valid User user, BindingResult bindingResult) {if (bindingResult.hasErrors()) {return Result.error("參數驗證失敗:" + bindingResult.getFieldError().getDefaultMessage());}// 業務邏輯...
}
7.2 權限控制
@GetMapping("/{id}")
@PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
public Result<User> getUserById(@PathVariable Long id) {// 業務邏輯...
}
7.3 API文檔
@GetMapping("/{id}")
@ApiOperation(value = "根據ID查詢用戶", notes = "返回用戶詳細信息")
@ApiParam(name = "id", value = "用戶ID", required = true)
public Result<User> getUserById(@PathVariable Long id) {// 業務邏輯...
}