For our project, we decided to use the GlobalExceptionController for our basic error handling.

GlobalExceptionControllerpackage com.sparta.newsfeed.exception;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.server.ResponseStatusException;
import javax.xml.crypto.Data;
import java.time.format.DateTimeParseException;
import java.util.Objects;
@RestControllerAdvice
public class GlobalExceptionController {
// Password Not Found
@ExceptionHandler(PasswordMismatchException.class)
public ResponseEntity<String> passwordMismatchException(PasswordMismatchException ex) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(HttpStatus.BAD_REQUEST + " : " + ex.getMessage());
}
// Data Not Found
@ExceptionHandler(DataNotFoundException.class)
public ResponseEntity<String> dataNotFoundException(DataNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(HttpStatus.NOT_FOUND + " : " + ex.getMessage());
}
// Duplicated Data
@ExceptionHandler(DataDuplicationException.class)
public ResponseEntity<String> dataDuplicationException(DataDuplicationException ex) {
return ResponseEntity.status(HttpStatus.CONFLICT).body(HttpStatus.CONFLICT + " : " + ex.getMessage());
}
// When method arguments with @Valid fails
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<String> validationExceptions(MethodArgumentNotValidException ex) {
StringBuilder errorMessage = new StringBuilder();
ex.getBindingResult().getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String message = error.getDefaultMessage();
errorMessage.append(fieldName).append(": ").append(message).append(". ");
});
return new ResponseEntity<>(errorMessage.toString(), HttpStatus.BAD_REQUEST);
}
//입력으로 다른 타입 입력했을 때 에러 (ex . @PathVariable 이 Long 타입인데 String 타입 입력했을때)
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public String idTypeMismatch(MethodArgumentTypeMismatchException ex) {
return ex.getName() + " 의 입력된 값은 잘못된 입력 입니다. " + Objects.requireNonNull(ex.getRequiredType()).getSimpleName() + " 타입으로 " + " 정확히 입력해주세요."
+ " 당신이 넣은 값은 " + ex.getValue() + " 입니다.";
}
// When a user tries to access methods beyond its authority
@ExceptionHandler(ResponseStatusException.class)
@ResponseStatus(HttpStatus.FORBIDDEN)
@ResponseBody
public String accessRights(ResponseStatusException ex) {
return ex.getStatusCode() + ": " + ex.getReason() ;
}
}
The very last one is what I made for cases where users attempt to modify or delete other people's posts or view inaccessible posts (posts by other uses whom are not their friend).
@GetMapping("/posts")
public Page<PageResponseDto> getPosts(@Auth AuthUser authUser,
@RequestParam("feedUserEmail") String feedUserEmail,
@RequestParam(value = "page", defaultValue = "1") int page,
@RequestParam(value = "size", defaultValue = "10") int size) {
// Check if the posts belongs to you or your friends
boolean isOwner = Objects.equals(authUser.getEmail(), feedUserEmail);
boolean isFriend = relationshipService.checkFriend(authUser.getEmail(), feedUserEmail);
if (isOwner || isFriend) {
return postService.getPosts(feedUserEmail, page-1, size);
} else {
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "This is a private account. Try sending a friend request!");
}
}