Поймать исключение при разборе параметров в Spring 3.0 WebMVC - PullRequest
8 голосов
/ 07 февраля 2011

Я использую Spring WebMVC для предоставления REST API. Я использую методы, такие как

@RequestMapping("/path({id}") void getById(@PathVariable("id") int id) {} методы.

Когда клиент неправильно вводит в запрос строку вместо целочисленного идентификатора, я получаю исключение NumberFormatException, например:

java.lang.NumberFormatException: For input string: "dojo"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
    at java.lang.Long.parseLong(Long.java:410)
    at java.lang.Long.valueOf(Long.java:525)
    at org.springframework.util.NumberUtils.parseNumber(NumberUtils.java:158)
    at org.springframework.core.convert.support.StringToNumberConverterFactory$StringToNumber.convert(StringToNumberConverterFactory.java:59)
    at org.springframework.core.convert.support.StringToNumberConverterFactory$StringToNumber.convert(StringToNumberConverterFactory.java:1)
    at org.springframework.core.convert.support.GenericConversionService$ConverterFactoryAdapter.convert(GenericConversionService.java:420)
    at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:37)
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:135)
    at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:199)
    at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:104)
    at org.springframework.beans.SimpleTypeConverter.convertIfNecessary(SimpleTypeConverter.java:47)
    at org.springframework.validation.DataBinder.convertIfNecessary(DataBinder.java:526)
    at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolvePathVariable(HandlerMethodInvoker.java:602)
    at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:289)
    at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:163)
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:414)
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:402)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:771)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:716)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:647)

Мой вопрос сейчас, как я могу элегантно его уловить? Я знаю, что Spring предоставляет аннотации @ExeptionHandler, но я не хочу, чтобы поймать NFE в целом. Я хочу иметь возможность перехватывать все исключения при разборе, чтобы представить клиенту приятное сообщение об ошибке.

Есть идеи?

Приветствия

Jan

Ответы [ 5 ]

2 голосов
/ 07 февраля 2011

Это фактическое исключение?(он не соответствует вашему примеру кода) Обычно можно ожидать, что он будет заключен в org.springframework.beans.TypeMismatchException, что, вероятно, достаточно конкретно, чтобы вы могли написать для него @ExceptionHandler метод.

Если это недостаточно конкретновам нужно отказаться от Spring-Magic и просто изменить тип параметра на String + разобрать его самостоятельно.Тогда вы можете справиться с этим так, как вам нравится.

1 голос
/ 06 ноября 2014

Я нашел решение вашей проблемы здесь http://www.coderanch.com/t/625951/Spring/REST-request-mapping-parameter-type

Просто попробуйте

@RequestMapping("/path({id:[\\d]+}") void getById(@PathVariable("id") int id) {} methods.

И тогда недопустимое использование приведет к 404. Я не уверен, что версия 3.0 поддерживает это.

0 голосов
/ 10 февраля 2011

сложив ваши комментарии, я попробовал следующее:

public class ValidatingAnnotationMethodHandlerAdapter extends AnnotationMethodHandlerAdapter {

@Override
protected ServletRequestDataBinder createBinder(HttpServletRequest request, Object target, String objectName) throws Exception {
    return new ServletRequestDataBinder(target, objectName) {

        @Override
        public <T> T convertIfNecessary(Object value, Class<T> requiredType) throws TypeMismatchException {
            try {
                return super.convertIfNecessary(value, requiredType);
            } catch (RuntimeException e) {
                throw new ControllerException("Could not parse parameter: " + e.getMessage());
            }
        }

        @Override
        public <T> T convertIfNecessary(Object value, Class<T> requiredType, MethodParameter methodParam) throws TypeMismatchException {
            try {
                return super.convertIfNecessary(value, requiredType, methodParam);
            } catch (RuntimeException e) {
                throw new ControllerException("Could not parse parameter: " + e.getMessage());
            }
        }

    };
}

ControllerException - это пользовательское исключение, которое перехватывается аннотированным методом @ExceptionController (я использую это исключение во всех классах валидаторов).

Надеюсь, вам понравится,

Jan

0 голосов
/ 07 февраля 2011

Возможно, я делаю это, потому что я старый программист Tyme, но я использую String в качестве типа для всех параметров @PathVariable и @RequestParameter, а затем выполняю анализ внутри метода-обработчика. Это позволяет мне легко перехватить все NumberFormatException исключения.

Хотя это не «весенний» способ сделать это, я рекомендую его, потому что это легко для меня и легко для моих будущих программистов по обслуживанию на шельфе.

0 голосов
/ 07 февраля 2011

Я не уверен на 100%, работает ли это для @PathVaribale или нет, но, как правило, для привязки модели можно использовать объект BindingResult рядом с переменной пути, и к * 1003 будет добавлена ​​модель и ошибка анализа* объект.

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