Spring @ExceptionHandler не работает с @ResponseBody - PullRequest
26 голосов
/ 24 февраля 2011

Я пытаюсь настроить обработчик исключений Spring для контроллера покоя, который может отображать карту в xml и json на основе входящего заголовка accept. Прямо сейчас генерируется исключение 500 сервлетов.

Это работает, он забирает home.jsp:

@ExceptionHandler(IllegalArgumentException.class)
public String handleException(final Exception e, final HttpServletRequest request, Writer writer)
{
    return "home";
}

Это не работает:

@ExceptionHandler(IllegalArgumentException.class)
public @ResponseBody Map<String, Object> handleException(final Exception e, final HttpServletRequest request, Writer writer)
{
    final Map<String, Object> map = new HashMap<String, Object>();
    map.put("errorCode", 1234);
    map.put("errorMessage", "Some error message");
    return map;
}

В том же контроллере работает отображение ответа на xml или json через соответствующий конвертер:

@RequestMapping(method = RequestMethod.GET, value = "/book/{id}", headers = "Accept=application/json,application/xml")
public @ResponseBody
Book getBook(@PathVariable final String id)
{
    logger.warn("id=" + id);
    return new Book("12345", new Date(), "Sven Haiges");
}

Любой

Ответы [ 7 ]

21 голосов
/ 24 февраля 2011

Ваш метод

@ExceptionHandler(IllegalArgumentException.class)
public @ResponseBody Map<String, Object> handleException(final Exception e, final HttpServletRequest request, Writer writer)

не работает, так как имеет неправильный тип возврата.Методы @ExceptionHandler имеют только два допустимых типа возврата:

  • String
  • ModelAndView.

См. http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html для получения дополнительной информации.Вот конкретный текст из ссылки:

Тип возвращаемого значения может быть String, который интерпретируется как имя представления или объект ModelAndView.

В ответ накомментарий

Спасибо, кажется, я перечитал это.Это плохо ... есть идеи, как автоматически создавать исключения в формате xml / json?- Свен Хейгес 7 часов назад

Вот что я сделал (на самом деле я сделал это в Scala, поэтому я не уверен, что синтаксис в точности правильный, но вы должны понять суть).

@ExceptionHandler(Throwable.class)
@ResponseBody
public void handleException(final Exception e, final HttpServletRequest request,
        Writer writer)
{
    writer.write(String.format(
            "{\"error\":{\"java.class\":\"%s\", \"message\":\"%s\"}}",
            e.getClass(), e.getMessage()));
}
13 голосов
/ 08 ноября 2011

Спасибо, кажется, я переоценил это. Это плохо ... любые идеи, как обеспечить исключения автоматически в формате xml / json?

Новое в Spring 3.0 MappingJacksonJsonView может быть использовано для достижения этой цели:

private MappingJacksonJsonView  jsonView = new MappingJacksonJsonView();

@ExceptionHandler(Exception.class)
public ModelAndView handleAnyException( Exception ex )
{
    return new ModelAndView( jsonView, "error", new ErrorMessage( ex ) );
}
10 голосов
/ 06 мая 2011

Это похоже на подтвержденную ошибку (SPR-6902 @ResponseBody не работает с @ExceptionHandler)

https://jira.springsource.org/browse/SPR-6902

Исправлено в версии 3.1 M1, хотя ...

6 голосов
/ 17 июня 2016

Я использую Spring 3.2.4. Мое решение проблемы состояло в том, чтобы убедиться, что объект, который я возвращал из обработчика исключений, имел геттеры.

Без геттеров Джексон не смог сериализовать объект в JSON.

В моем коде, для следующего ExceptionHandler:

@ExceptionHandler(RuntimeException.class)
@ResponseBody
public List<ErrorInfo> exceptionHandler(Exception exception){
    return ((ConversionException) exception).getErrorInfos();
}

Мне нужно было убедиться, что у моего объекта ErrorInfo есть геттеры:

package com.pelletier.valuelist.exception;

public class ErrorInfo {
private int code;
private String field;
private RuntimeException exception;

public ErrorInfo(){}

public ErrorInfo(int code, String field, RuntimeException exception){
    this.code = code;
    this.field = field;
    this.exception = exception;
}

public int getCode() {
    return code;
}

public String getField() {
    return field;
}

public String getException() {
    return exception.getMessage();
}
}
6 голосов
/ 15 августа 2011

Это может быть обходной путь, если вы используете конвертеры сообщений для объектов ошибок маршала в качестве содержимого ответа

@ExceptionHandler(IllegalArgumentException.class)
public String handleException(final Exception e, final HttpServletRequest request)
{
    final Map<String, Object> map = new HashMap<String, Object>();
    map.put("errorCode", 1234);
    map.put("errorMessage", "Some error message");
    request.setAttribute("error", map);
    return "forward:/book/errors"; //forward to url for generic errors
}

//set the response status and return the error object to be marshalled
@SuppressWarnings("unchecked")
@RequestMapping(value = {"/book/errors"}, method = {RequestMethod.POST, RequestMethod.GET})
public @ResponseBody Map<String, Object> showError(HttpServletRequest request, HttpServletResponse response){

    Map<String, Object> map = new HashMap<String, Object>();
    if(request.getAttribute("error") != null)
        map = (Map<String, Object>) request.getAttribute("error");

    response.setStatus(Integer.parseInt(map.get("errorCode").toString()));

    return map;
}
3 голосов
/ 21 марта 2013

АннотацияМетодHandlerExceptionResolver также требуется MappingJacksonHttpMessageConverter

<bean
    class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver">
    <property name="messageConverters">
        <list>
            <bean
                class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
                <property name="objectMapper" ref="jacksonObjectMapper" />
            </bean>
        </list>
    </property>
</bean>

<bean id="jacksonObjectMapper"
    class="iacm.cemetery.framework.web.servlet.rest.JacksonObjectMapper" />
1 голос
/ 01 декабря 2016

Я сталкивался с подобной проблемой, эта проблема возникает, когда ваш тип возвращаемого значения метода Controller и тип возвращаемого значения ExceptionHandler не совпадают . Убедитесь, что у вас точно такие же типы возврата.

Метод контроллера:

@RequestMapping(value = "/{id}", produces = "application/json", method = RequestMethod.POST)
public ResponseEntity<?> getUserById(@PathVariable String id) throws NotFoundException {
    String response = userService.getUser(id);
    return new ResponseEntity(response, HttpStatus.OK);
}

Метод совета:

@ExceptionHandler(NotFoundException.class)
public ResponseEntity<?> notFoundException(HttpServletRequest request, NotFoundException e) {
    ExceptionResponse response = new ExceptionResponse();
    response.setSuccess(false);
    response.setMessage(e.getMessage());
    return new ResponseEntity(response, HttpStatus.NOT_FOUND);
}

Как видите, типы возвращаемых значений в обоих классах одинаковы ResponseEntity<?>.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...