Estou usando o Spring MVC para uma API JSON simples, com @ResponseBody
abordagem baseada na seguinte. (Eu já tenho uma camada de serviço produzindo JSON diretamente.)
@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;
}
A pergunta é, no cenário fornecido, qual é a maneira mais simples e limpa de responder com um erro do HTTP 400 ?
Me deparei com abordagens como:
return new ResponseEntity(HttpStatus.BAD_REQUEST);
... mas não posso usá-lo aqui, pois o tipo de retorno do meu método é String, não ResponseEntity.
java
spring
spring-mvc
http-error
Jonik
fonte
fonte
ResponseEntity
assim também. Isso funciona bem e é apenas uma simples alteração no código original - obrigado!Algo assim deve funcionar, não tenho certeza se existe ou não uma maneira mais simples:
fonte
body
erequest
parâmetros.)Não necessariamente a maneira mais compacta de fazer isso, mas IMO bastante limpo
Na edição, você pode usar @ResponseBody no método manipulador de exceções, se estiver usando o Spring 3.1+, caso contrário, use a
ModelAndView
ou algo assim.https://jira.springsource.org/browse/SPR-6902
fonte
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
Há algo faltando na resposta?javax.validation.ValidationException
vez disso. (Spring 3.1.4)Eu mudaria um pouco a implementação:
Primeiro, eu crio um
UnknownMatchException
:Observe o uso do @ResponseStatus , que será reconhecido pelo Spring
ResponseStatusExceptionResolver
. Se a exceção for lançada, ela criará uma resposta com o status de resposta correspondente. (Também tomei a liberdade de alterar o código de status ao404 - Not Found
qual acho mais apropriado para este caso de uso, mas você pode continuarHttpStatus.BAD_REQUEST
se quiser.)Em seguida, eu mudaria
MatchService
para ter a seguinte assinatura:Finalmente, eu atualizaria o controlador e o delegaria ao Spring
MappingJackson2HttpMessageConverter
para lidar com a serialização JSON automaticamente (ela será adicionada por padrão se você adicionar Jackson ao caminho de classe e adicionar uma@EnableWebMvc
ou<mvc:annotation-driven />
sua configuração, consulte os documentos de referência ):Observe que é muito comum separar os objetos de domínio dos objetos de exibição ou DTO. Isso pode ser facilmente alcançado adicionando uma pequena fábrica de DTO que retorna o objeto JSON serializável:
fonte
Match
e algum outro objeto.Aqui está uma abordagem diferente. Crie um personalizado
Exception
anotado com@ResponseStatus
, como o seguinte.E jogue-o quando necessário.
Confira a documentação do Spring aqui: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-ann-annotated-exceptions .
fonte
Conforme mencionado em algumas respostas, existe a capacidade de criar uma classe de exceção para cada status HTTP que você deseja retornar. Não gosto da ideia de ter que criar uma classe por status para cada projeto. Aqui está o que eu inventei.
Vamos ao código
Então eu crio uma classe de conselho de controlador
Para usá-lo
http://javaninja.net/2016/06/throwing-exceptions-messages-spring-mvc-controller/
fonte
Estou usando isso no meu aplicativo de inicialização da primavera
fonte
A maneira mais fácil é lançar um
ResponseStatusException
fonte
Com o Spring Boot, não sei ao certo por que isso foi necessário (recebi o
/error
fallback, embora tenha@ResponseBody
sido definido em um@ExceptionHandler
), mas o seguinte por si só não funcionou:Ainda gerou uma exceção, aparentemente porque nenhum tipo de mídia produtável foi definido como um atributo de solicitação:
Então eu os adicionei.
E isso me levou a ter um "tipo de mídia compatível compatível", mas ainda assim não funcionou, porque
ErrorMessage
estava com defeito:O JacksonMapper não o tratou como "conversível", então tive que adicionar getters / setters e também adicionei
@JsonProperty
anotaçãoEntão recebi minha mensagem como pretendido
fonte
Você também pode
throw new HttpMessageNotReadableException("error description")
se beneficiar do tratamento de erros padrão do Spring .No entanto, assim como ocorre com esses erros padrão, nenhum corpo de resposta será definido.
Acho isso útil ao rejeitar solicitações que poderiam razoavelmente ter sido criadas manualmente, indicando potencialmente uma intenção malévola, pois ocultam o fato de que a solicitação foi rejeitada com base em uma validação personalizada mais profunda e em seus critérios.
Hth, dtk
fonte
HttpMessageNotReadableException("error description")
está obsoleto.Outra abordagem é usar
@ExceptionHandler
com@ControllerAdvice
para centralizar todos os seus manipuladores na mesma classe; caso contrário, você deve colocar os métodos do manipulador em todos os controladores em que deseja gerenciar uma exceção.Sua classe de manipulador:
Sua exceção personalizada:
Agora você pode lançar exceções em qualquer um dos seus controladores e definir outros manipuladores dentro da classe de aconselhamento.
fonte
Eu acho que esse segmento realmente tem a solução mais fácil e limpa, que não sacrifica as ferramentas de marcial JSON fornecidas pelo Spring:
https://stackoverflow.com/a/16986372/1278921
fonte