@ResponseStatus gán HTTP status code cho exception class hoặc controller method — khai báo tĩnh thay vì dùng ResponseEntity.
Trên exception class:
@ResponseStatus(HttpStatus.NOT_FOUND) // → 404
class UserNotFoundException extends RuntimeException {
public UserNotFoundException(Long id) {
super("User " + id + " not found");
}
}
@ResponseStatus(
value = HttpStatus.CONFLICT, // → 409
reason = "Email already registered"
)
class DuplicateEmailException extends RuntimeException {}Khi Spring bắt exception này → tự động trả status đã khai báo.
Trên controller method:
@PostMapping
@ResponseStatus(HttpStatus.CREATED) // → 201 cho mọi success
User create(@RequestBody @Valid CreateUserRequest req) {
return userService.create(req);
// không cần return ResponseEntity.created(...).build()
}
@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT) // → 204
void delete(@PathVariable Long id) {
userService.delete(id);
}Khi dùng @ResponseStatus vs ResponseEntity:
- @ResponseStatus — status cố định, đơn giản, self-documenting.
- ResponseEntity — status động (có thể thay đổi theo logic), cần thêm header, body có thể null.
Lưu ý: nếu đã có @ExceptionHandler trong @ControllerAdvice, @ResponseStatus trên exception class bị bỏ qua — handler lấy ưu tiên.
@ResponseStatus assigns an HTTP status code to an exception class or a controller method — a static declaration instead of using ResponseEntity.
On an exception class:
@ResponseStatus(HttpStatus.NOT_FOUND) // → 404
class UserNotFoundException extends RuntimeException {
public UserNotFoundException(Long id) {
super("User " + id + " not found");
}
}
@ResponseStatus(
value = HttpStatus.CONFLICT, // → 409
reason = "Email already registered"
)
class DuplicateEmailException extends RuntimeException {}When Spring catches this exception → automatically returns the declared status.
On a controller method:
@PostMapping
@ResponseStatus(HttpStatus.CREATED) // → 201 for every success
User create(@RequestBody @Valid CreateUserRequest req) {
return userService.create(req);
// no need for ResponseEntity.created(...).build()
}
@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT) // → 204
void delete(@PathVariable Long id) {
userService.delete(id);
}@ResponseStatus vs ResponseEntity:
- @ResponseStatus — fixed status, simple, self-documenting.
- ResponseEntity — dynamic status (can change based on logic), needs extra headers, body may be null.
Note: if a @ExceptionHandler exists in @ControllerAdvice, @ResponseStatus on the exception class is ignored — the handler takes precedence.