Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

272
Views
Spring: controlador de excepciones diferente para RestController y Controller

En Spring, puede configurar el controlador de excepciones "global" a través de la anotación @ControllerAdvice y @ExceptionHandler. Estoy tratando de utilizar este mecanismo para tener dos controladores de excepciones globales:

  • RestControllerExceptionHandler , que debería devolver respuestas de error como json para cualquier controlador anotado con @RestController
  • ControllerExceptionHandler , que debería imprimir un mensaje de error en la pantalla para cualquier otro controlador (anotado con @Controller )

El problema es que cuando declaro estos dos manejadores de excepciones, Spring siempre usa ControllerExceptionHandler y nunca RestControllerExceptionHandler para manejar la excepción.

¿Cómo hacer que esto funcione? Por cierto: traté de usar la anotación @Order pero esto no parece funcionar.

Aquí están mis controladores de excepciones:

 // should handle all exception for classes annotated with @ControllerAdvice(annotations = RestController.class) public class RestControllerExceptionHandler { @ExceptionHandler(Exception.class) public ResponseEntity<ErrorResponse> handleUnexpectedException(Exception e) { // below object should be serialized to json ErrorResponse errorResponse = new ErrorResponse("asdasd"); return new ResponseEntity<ErrorResponse>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR); } // should handle exceptions for all the other controllers @ControllerAdvice(annotations = Controller.class) public class ControllerExceptionHandler { @ExceptionHandler(Exception.class) public ResponseEntity<String> handleUnexpectedException(Exception e) { return new ResponseEntity<String>("Unexpected exception, HttpStatus.INTERNAL_SERVER_ERROR); } } }

Cuando elimino ControllerExceptionHandler RestControllerExceptionHandler es llamado correctamente por Spring (solo para las clases anotadas con @RestController ).... pero cuando agrego ControllerExceptionHandler , todo pasa a través de ControllerExceptionHandler . ¿Por qué?

about 4 years ago · Santiago Trujillo
3 answers
Answer question

0

Después de una investigación más profunda, parece que el orden alfabético importa:/.

Cuando cambié el nombre de mi RestControllerExceptionHandler a ARestControllerExceptionHandler (que alfabéticamente precede a ControllerExceptionHandler ), ¡todo funciona como se esperaba! ARestControllerExceptionHandler maneja correctamente las excepciones de RestControllers y ControllerExceptionHandler maneja las excepciones de otros controladores.

Creé un error en primavera para esto: https://jira.spring.io/browse/SPR-15432

--- EDITAR:

Recibí la respuesta para SPR-15432 donde se sugiere que este caso se puede resolver con @Order ( org.springframework.core.annotation.Order ) o implementando la interfaz ordenada.

Esto no me funcionó antes, pero parece que he importado una anotación @Order incorrecta. (de log4j2 en lugar de primavera). Después de arreglar esto, funciona. La versión fija es la siguiente:

 // should handle all exception for classes annotated with @ControllerAdvice(annotations = RestController.class) @Order(1) // NOTE: order 1 here public class RestControllerExceptionHandler { @ExceptionHandler(Exception.class) public ResponseEntity<ErrorResponse> handleUnexpectedException(Exception e) { // below object should be serialized to json ErrorResponse errorResponse = new ErrorResponse("asdasd"); return new ResponseEntity<ErrorResponse>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR); } } // should handle exceptions for all the other controllers @ControllerAdvice(annotations = Controller.class) @Order(2) // NOTE: order 2 here public class ControllerExceptionHandler { @ExceptionHandler(Exception.class) public ResponseEntity<String> handleUnexpectedException(Exception e) { return new ResponseEntity<String>("Unexpected exception, HttpStatus.INTERNAL_SERVER_ERROR); } }
about 4 years ago · Santiago Trujillo Report

0

Eso sucede porque la anotación @RestController también es un @Controller, por lo que Spring está considerando el @ControllerAdvice con annotation = Controller.class para ambos.

Puede probar otro método para definir el subconjunto de controladores que @ControllerAdvice tendrá efecto, así que aquí hay algunas soluciones:


Solución 1

  1. Cree una nueva Anotación @NotRestController:

     @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface NotRestController { }
  2. Marque los controladores que no sean @RestController con @Controller y @NotRestController:

     @Controller @NotRestController @RequestMapping("/controller") public class SampleController { }
  3. Use NotRestController.class en ControllerExceptionHandler :

     @ControllerAdvice(annotations = NotRestController.class) public class ControllerExceptionHandler {

Creé un proyecto de muestra con la Solution 1 y lo compartí en Github:

https://github.com/brunocleite/springexceptionhandlertest


Solución 2

  1. Mueva sus clases @RestController a un paquete foo.bar y sus clases @Controller a otro paquete foo.nuk .

  2. Use la propiedad basePackages de @ControllerAdvice en lugar de annotations :

     @ControllerAdvice(basePackages={"foo.bar"}) public class RestControllerExceptionHandler { @ControllerAdvice(basePackages={"foo.nuk"}) public class ControllerExceptionHandler {

¡Saludos!

about 4 years ago · Santiago Trujillo Report

0

Esta fue mi solución. Elimina la necesidad de crear anotaciones adicionales.

  1. Crea 2 controladores base.
 @Controller public class BaseController @Controller public class BaseRestController
  1. Extienda cada controlador con el controlador base elegido.
 @Controller public class UserController extends BaseController @RestController public class UserRestController extends BaseRestController
  1. Cree 2 controladores globales e incluya solo la clase base extendida en cada uno.
 @ControllerAdvice(assignableTypes = BaseController.class) public class GlobalController @ControllerAdvice(assignableTypes = BaseRestController.class) public class GlobalRestController
about 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!