ItFreak:
Estoy usando la primavera de arranque para mi servicio REST. Ahora quiero poner en práctica un registro público en un lugar central. Aquí está mi estructura:
DESCANSO
@GetMapping(value="/rest/test/{userId}")
public User getUserById(@PathVariable String userId) {
return userService.findById(userId);
}
UserService
public User findById(@NotNull String userId) {
if(noUserFound) {
throw new InvalidArgumentException();
}
}
Mi objetivo es tener una clase central que intercepta todas las excepciones (también excepciones Bean Validation) y obtener la siguiente información:
- El punto final de la API que se llamaba
- Todos los parámetros que se han pasado
- La excepción y su mensaje
- El nombre de usuario / ID que envió la solicitud (estoy usando Keycloak con OpenAuth)
¿Existe la posibilidad de hacer eso, tal vez sin anotar todos los métodos con @ExceptionHandler
?
Boris Chistov:
Bueno, se puede utilizar @ControllerAdvice para lograr este objetivo.
Aquí es un ejemplo de código:
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
@ControllerAdvice
public class ErrorHandler extends ResponseEntityExceptionHandler {
// Build-in exceptions, this one is for Validation errors
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request
) {
// info about endpoint
var path = request.getDescription(false);
// request params map
var params = request.getParameterMap();
// authenticated principal
var user = request.getUserPrincipal();
log.debug("path: {}, params: {}, user: {}", path, params.keySet(), user.getName());
return super.handleMethodArgumentNotValid(ex, headers, status, request);
}
// Custom exception
@ExceptionHandler(NoAccessException.class)
public ResponseEntity<Error> noAccessException(NoAccessException ex, WebRequest request) {
return ResponseEntity
.status(HttpStatus.FORBIDDEN)
.body(Error.builder().message(ex.getMessage()).build());
}
}