Estoy usando Spring MVC para una API JSON simple, con un @ResponseBody
enfoque basado como el siguiente. (Ya tengo una capa de servicio que produce JSON directamente).
@RequestMapping(value = "/matches/{matchId}", produces = "application/json")
@ResponseBody
public String match(@PathVariable String matchId) {
String json = matchService.getMatchJson(matchId);
if (json == null) {
// TODO: how to respond with e.g. 400 "bad request"?
}
return json;
}
La pregunta es, en el escenario dado, ¿cuál es la forma más simple y limpia de responder con un error HTTP 400 ?
Encontré enfoques como:
return new ResponseEntity(HttpStatus.BAD_REQUEST);
... pero no puedo usarlo aquí ya que el tipo de retorno de mi método es String, no ResponseEntity.
java
spring
spring-mvc
http-error
Jonik
fuente
fuente
ResponseEntity
así. Esto funciona bien y es solo un simple cambio al código original, ¡gracias!Algo como esto debería funcionar, no estoy seguro de si hay una forma más simple o no:
fuente
body
yrequest
params.)No es necesariamente la forma más compacta de hacer esto, pero es bastante limpio.
Editar puede usar @ResponseBody en el método del controlador de excepciones si usa Spring 3.1+, de lo contrario use ao
ModelAndView
algo.https://jira.springsource.org/browse/SPR-6902
fuente
ERROR org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver - Failed to invoke @ExceptionHandler method: public controller.TestController$MyError controller.TestController.handleException(controller.TestController$BadThingException) org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
¿falta algo en la respuesta?javax.validation.ValidationException
en su lugar. (Primavera 3.1.4)Cambiaría la implementación ligeramente:
Primero, creo un
UnknownMatchException
:Tenga en cuenta el uso de @ResponseStatus , que será reconocido por Spring's
ResponseStatusExceptionResolver
. Si se lanza la excepción, creará una respuesta con el estado de respuesta correspondiente. (También me tomé la libertad de cambiar el código de estado al404 - Not Found
que me parece más apropiado para este caso de uso, pero puede seguirloHttpStatus.BAD_REQUEST
si lo desea).A continuación, cambiaría el
MatchService
para tener la siguiente firma:Finalmente, actualizaría el controlador y delegaría en Spring's
MappingJackson2HttpMessageConverter
para manejar la serialización JSON automáticamente (se agrega de forma predeterminada si agrega Jackson al classpath y agrega@EnableWebMvc
o<mvc:annotation-driven />
a su configuración, vea los documentos de referencia ):Tenga en cuenta que es muy común separar los objetos de dominio de los objetos de vista u objetos DTO. Esto se puede lograr fácilmente agregando una pequeña fábrica de DTO que devuelve el objeto JSON serializable:
fuente
Match
algún otro objeto.Aquí hay un enfoque diferente. Cree una
Exception
anotación personalizada con@ResponseStatus
, como la siguiente.Y tíralo cuando sea necesario.
Consulte la documentación de Spring aquí: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-ann-annotated-exceptions .
fuente
Como se menciona en algunas respuestas, existe la posibilidad de crear una clase de excepción para cada estado HTTP que desee devolver. No me gusta la idea de tener que crear una clase por estado para cada proyecto. Esto es lo que se me ocurrió en su lugar.
Vayamos al código
Luego creo una clase de consejo de controlador
Para usarlo
http://javaninja.net/2016/06/throwing-exceptions-messages-spring-mvc-controller/
fuente
Estoy usando esto en mi aplicación de arranque de primavera
fuente
La forma más fácil es lanzar un
ResponseStatusException
fuente
Con Spring Boot, no estoy completamente seguro de por qué esto era necesario (obtuve el
/error
respaldo aunque@ResponseBody
se definió en un@ExceptionHandler
), pero lo siguiente en sí mismo no funcionó:Todavía arrojó una excepción, aparentemente porque no se definieron tipos de medios producibles como un atributo de solicitud:
Entonces los agregué.
Y esto me ayudó a tener un "tipo de medio compatible compatible", pero aún así no funcionó, porque
ErrorMessage
estaba defectuoso:JacksonMapper no lo manejó como "convertible", así que tuve que agregar getters / setters, y también agregué
@JsonProperty
anotacionesEntonces recibí mi mensaje como estaba previsto
fuente
También podría
throw new HttpMessageNotReadableException("error description")
beneficiarse del manejo de errores predeterminado de Spring .Sin embargo, tal como es el caso con esos errores predeterminados, no se establecerá ningún cuerpo de respuesta.
Encuentro esto útil al rechazar solicitudes que razonablemente solo podrían haber sido hechas a mano, lo que potencialmente indica una intención malévola, ya que ocultan el hecho de que la solicitud fue rechazada en base a una validación personalizada más profunda y sus criterios.
Hth, dtk
fuente
HttpMessageNotReadableException("error description")
es obsoleto.Otro enfoque es utilizar
@ExceptionHandler
la@ControllerAdvice
de centralizar todas sus manipuladores en la misma clase, si no hay que poner los métodos de controlador en cada controlador que desea gestionar una excepción.Tu clase de manejador:
Tu excepción personalizada:
Ahora puede lanzar excepciones desde cualquiera de sus controladores, y puede definir otros controladores dentro de su clase de consejos.
fuente
Creo que este hilo realmente tiene la solución más fácil y limpia, que no sacrifica las herramientas de marcialización JSON que proporciona Spring:
https://stackoverflow.com/a/16986372/1278921
fuente