Spring 3.0 WebMVC中的Catch参数解析异常

时间:2011-02-07 17:22:23

标签: java rest spring-mvc

我使用Spring WebMVC提供REST API。我使用像

这样的方法

@RequestMapping("/path({id}") void getById(@PathVariable("id") int id) {}方法。

当客户端错误地将字符串而不是整数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。我希望能够捕获所有解析异常,以便向客户端提供一个很好的错误消息。

有什么想法吗?

干杯,

5 个答案:

答案 0 :(得分:2)

这是实际的例外吗? (它与您的代码示例不匹配)通常人们会希望将其包含在org.springframework.beans.TypeMismatchException中,这可能足以让您为其编写@ExceptionHandler方法。

如果这还不够具体,你需要放弃Spring-Magic,只需将参数类型改为String +自己解析。然后你可以按照自己喜欢的方式处理它。

答案 1 :(得分:1)

我在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版是否支持此功能。

答案 2 :(得分:0)

我不是100%确定这是否适用于@PathVaribale,但通常对于模型绑定,您可以在路径变量旁边使用BindingResult对象,并且将添加模型和解析错误到BindingResult/Errors对象。

答案 3 :(得分:0)

也许我这样做是因为我是一个老式的程序员,但我使用String作为所有@PathVariable@RequestParameter参数的类型,然后我在处理程序方法中进行解析。这使我可以轻松捕获所有NumberFormatException例外。

虽然这不是“春天”的做法,但我推荐它,因为它对我来说很容易,对我未来的离岸维护程序员来说也很容易理解。

答案 4 :(得分:0)

将您的评论放在一起,我尝试了以下内容:

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注释方法捕获(我在所有验证器类中都使用此异常)。

希望你喜欢它,