简体   繁体   中英

How can I set up my application to ONLY return messages for ResponseStatusException?

By default, Spring Boot does not return messages for any exceptions, including ResponseStatusException , meaning that the message about bar below will not be returned to the client:

    @GetMapping("/foo")
    @ResponseBody
    public Foo getFoo(@RequestParam(name = "bar", defaultValue = "0") int bar) {
        if (bar <= 0) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "bar must always be positive");
        }
        return example.getFoo(bar);
    }

This can be changed by setting server.error.include-message=always in the application.properties , however this causes ALL exception messages to be returned to the client, including this one:

    @GetMapping("/baz")
    @ResponseBody
    public Baz getBaz() {
        if (!security.checkSecurity()) {
            throw new RuntimeException("Security breach! Hope no one finds out!");
        }
        return example.getBaz();
    }

I know this is a trivial example and the solution would be just "don't throw server exceptions from your controller", but the exception might actually come from some other code buried deep in the application, it could even be a NullPointerException or whatever.

How can I get the application to show messages only from ResponseStatusException and not other types of exception? (I guess other than adding try-catch clauses to every single controller method.)

You can add extra (@ExceptionHandler) methods to any controller to specifically handle exceptions thrown by request handling (@RequestMapping) methods in the same controller. Such methods can:

  • Handle exceptions without the @ResponseStatus annotation (typically predefined exceptions that you didn't write)
  • Redirect the user to a dedicated error view
  • Build a totally custom error response

Controller advice allows you to use exactly the same exception handling techniques but apply them across the whole application , not just to an individual controller. You can think of them as an annotation-driven interceptor.

Any class annotated with @ControllerAdvice becomes a controller-advice and three types of method are supported:

  • Exception handling methods annotated with @ExceptionHandler.
  • Model enhancement methods (for adding additional data to the model) annotated with @ModelAttribute. Note that these attributes are not available to the exception handling views.
  • Binder initialization methods (used for configuring form-handling) annotated with @InitBinder.

Solution:

@ControllerAdvice
public class RestControllerAdvice {

  @ExceptionHandler(ResponseStatusException.class)
  public ResponseEntity<String> handleStatusException(ResponseStatusException exception) {
    throw exception;
  }

  @ExceptionHandler(Exception.class)
  public ResponseEntity<String> handleException(Exception exception) {
    return new ResponseEntity<>("Exception", HttpStatus.INTERNAL_SERVER_ERROR);
  }
}

Catch all the exceptions and in the catch block throw ResponseStatusException like in:

@GetMapping("/actor/{id}")
public String getActorName(@PathVariable("id") int id) {
    try {
        return actorService.getActor(id);
    } catch (ActorNotFoundException ex) {
        throw new ResponseStatusException(
          HttpStatus.NOT_FOUND, "Actor Not Found", ex);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM