Reputation: 2369
I am using Spring Boot for my REST service. Now I want to implement a general logging at a central place. Here is my structure:
REST
@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();
}
}
My goal is to have a central class that intercepts all exceptions (also BeanValidation exceptions) and get the following information:
Is there a possibility to do that, maybe without annotating every method with @ExceptionHandler
?
Upvotes: 0
Views: 786
Reputation: 950
Well, you can use @ControllerAdvice to achieve this goal.
Here is a sample code:
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());
}
}
Upvotes: 2
Reputation: 300
You can use @ControllerAdvice
. Example code from https://mkyong.com/spring-boot/spring-rest-error-handling-example/
@ControllerAdvice
public class CustomGlobalExceptionHandler extends ResponseEntityExceptionHandler
{
//...
// @Validate For Validating Path Variables and Request Parameters
@ExceptionHandler(ConstraintViolationException.class)
public void constraintViolationException(HttpServletResponse response) throws IOException {
response.sendError(HttpStatus.BAD_REQUEST.value());
}
// error handle for @Valid
@Override
protected ResponseEntity<Object>
handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
HttpHeaders headers,
HttpStatus status, WebRequest request) {
Map<String, Object> body = new LinkedHashMap<>();
body.put("timestamp", new Date());
body.put("status", status.value());
//Get all fields errors
List<String> errors = ex.getBindingResult()
.getFieldErrors()
.stream()
.map(x -> x.getDefaultMessage())
.collect(Collectors.toList());
body.put("errors", errors);
return new ResponseEntity<>(body, headers, status);
}}
Upvotes: 1