问题
I'm trying to implement a Spring Web MVC @ExceptionHandler with a @ResponseBody to return an object containing validation errors. (Strategy E documented here).
In Spring 3.0.x, there was a confirmed bug , since resolved, that prohibited this from working properly. I'm using Spring 3.1.2, and shouldn't be running into that one.
I am, however, running into an exception"Could not find acceptable representation".
Here's the exception:
[10/21/12 12:56:53:296 CDT] 00000045 ExceptionHand E redacted.loggi
ng.jdk14.LogWrapper error Failed to invoke @ExceptionHandler method: public
redacted.model.view.ValidationErrorResponse redacted.controller.Re
stController.handleValidationException(redacted.util.ValidationExceptio
n,javax.servlet.http.HttpServletResponse)
Originating Class/Method:redacted.web.ui.filter.AccessControlFilter.pr
ocessFilter()
org.springframework.web.HttpMediaTypeNotAccepta
bleException: Could not find acceptable representation
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessage
ConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMeth
odProcessor.java:115)
And here's the code:
@ExceptionHandler(ValidationException.class)
@ResponseStatus(value = HttpStatus.PRECONDITION_FAILED)
@ResponseBody
public ValidationErrorResponse handleValidationException(ValidationException ex, HttpServletResponse response) {
List<ValidationError> errs = new LinkedList<ValidationError>();
for (ObjectError er : ex.getErrors()) {
errs.add(new ValidationError(er.getObjectName(), er.getDefaultMessage()));
}
return new ValidationErrorResponse(errs);
}
@RequestMapping(value = "/search")
@ResponseBody
public SearchResult search(@Valid @ModelAttribute SearchRequest searchRequest, BindingResult bResult) {
if (bResult.hasErrors()) {
throw new ValidationException(bResult.getAllErrors());
}
return searchService.search(searchRequest);
}
Any ideas?
回答1:
If you're reading this you probably have some question about how I got this to work. The short answer is that I don't know. I reverted off my code and re-implemented (actually copy and pasted the controller bits) from here, and it suddenly started working.
If you're using Spring 3.1.2, @ExceptionHandler and @ResponseBody does work.
My tentative explanation as to why this didn't work initially was that it was probably a user error or an error in the (very complicated, this application is massive) deployment scripts I was uing.
回答2:
I've had this issue when I needed to return a JSON error response for a request that ends with some known extension like "/blah/blah.xml". In this case Spring favors the extension-based representation matching, and ignores the Accept header (also is the case with the latest Spring 4.1.5).
I used the following to "lock" to the JSON response no matter what the request is.
@Configuration
@EnableWebMvc
public class ApplicationConfiguration extends WebMvcConfigurerAdapter {
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false);
configurer.ignoreAcceptHeader(true);
configurer.defaultContentType(MediaType.APPLICATION_JSON);
}
}
回答3:
The problem seems to be that Spring Does not how waht to convert the ValidationErrorResponse to, for example should it convert it to JSON, or XML or something else? try returning a ResponseEntity because you can control the content type directly.
protected ResponseEntity<ValidationErrorResponse> createResponseEntity(ValidationErrorResponse restApiError)
{
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// assuming your ValidationErrorResponse object has an http code stored in it
HttpStatus responseStatus = HttpStatus.valueOf(restApiError.getHttpStatus());
ResponseEntity<RestApiError> result = new ResponseEntity<>(restApiError, headers, responseStatus);
return result;
}
I use something like in my application, also I have a bunch of RuntimeExceptions that I can throw which contain wihtin them enough information be able to generate proper error responses.
来源:https://stackoverflow.com/questions/13000754/spring-3-1-2-mvc-exceptionhandler-with-responsebody