在 JAX-RS (如 Jersey、RESTEasy) 中,資源方法可直接返回 Response 對象,通過 Response.status(int).entity(Object).build() 靈活控制 HTTP 狀態碼、響應體、Headers。DAO 層只需返回業務狀態 (枚舉、布爾值、自定義結果對象),資源層映射為對應 HTTP 狀態。
public class Result<T> {
private boolean success;
private T data;
private String errorCode;
private String errorMsg;
// getter/setter + 靜態工廠方法 ok()/fail()
}
@Repository
public class UserDao {
public Result<User> save(User user) {
try {
// 持久化邏輯
return Result.ok(user);
} catch (DataIntegrityViolationException e) {
return Result.fail("DUP_KEY", "用戶已存在");
} catch (Exception e) {
return Result.fail("DB_ERR", "數據庫異常");
}
}
}
@Path("/users")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class UserResource {
@Inject UserDao userDao;
@POST
public Response createUser(User user) {
Result<User> result = userDao.save(user);
if (result.isSuccess()) {
// 201 Created,並返回 Location 頭
return Response.status(Response.Status.CREATED)
.entity(result.getData())
.header("Location", "/users/" + result.getData().getId())
.build();
}
// 根據錯誤碼映射具體狀態
switch (result.getErrorCode()) {
case "DUP_KEY": return Response.status(Response.Status.CONFLICT).entity(result).build(); // 409
case "VALID_ERR": return Response.status(Response.Status.BAD_REQUEST).entity(result).build(); // 400
default: return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(result).build(); // 500
}
}
}
| 業務場景 | HTTP 狀態 | Response.Status 常量 |
|---|---|---|
| 創建成功 | 201 | CREATED |
| 查詢/更新成功 | 200 | OK |
| 刪除成功無內容 | 204 | NO_CONTENT |
| 參數校驗失敗 | 400 | BAD_REQUEST |
| 未授權/Token 失效 | 401 | UNAUTHORIZED |
| 無權限訪問 | 403 | FORBIDDEN |
| 資源不存在 | 404 | NOT_FOUND |
| 資源衝突 (如唯一鍵重複) | 409 | CONFLICT |
| 服務器內部錯誤 | 500 | INTERNAL_SERVER_ERROR |
若不想在每個資源方法寫 if-else,可拋出自定義異常,配合 ExceptionMapper 統一轉換:
@Provider
public class BusinessExceptionMapper implements ExceptionMapper<BusinessException> {
@Override
public Response toResponse(BusinessException e) {
return Response.status(e.getStatus())
.entity(Result.fail(e.getCode(), e.getMessage()))
.build();
}
}
// 資源方法簡化為
@POST
public User createUser(User user) {
Result<User> r = userDao.save(user);
if (!r.isSuccess()) throw new BusinessException(r.getErrorCode(), r.getErrorMsg(), mapToHttpStatus(r.getErrorCode()));
return r.getData(); // 直接返回實體,JAX-RS 自動轉 200/201
}
Response.status(...).build()。ExceptionMapper 實現關注點分離,代碼更乾淨。