【问题标题】:Catch parameter parsing exception in Spring 3.0 WebMVC在 Spring 3.0 WebMVC 中捕获参数解析异常
【发布时间】:2011-02-07 17:22:23
【问题描述】:

我使用 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。我希望能够捕获所有解析异常,以便向客户端显示一个很好的错误消息。

有什么想法吗?

干杯,

一月

【问题讨论】:

    标签: java rest spring-mvc


    【解决方案1】:

    这是真正的例外吗? (它与您的代码示例不匹配)通常人们会期望将其包装在 org.springframework.beans.TypeMismatchException 中,这可能足够具体,您可以为其编写 @ExceptionHandler 方法。

    如果这还不够具体,您将需要放弃 Spring-Magic,只需将参数类型更改为 String + 自己解析即可。然后你可以随心所欲地处理它。

    【讨论】:

    • 是的,我也希望如此,但 NFE 是根本异常。很抱歉,我在示例中混合了 long 和 int。
    【解决方案2】:

    我在这里找到了解决您问题的方法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版本是否支持这个。

    【讨论】:

    • 不错的解决方案。在当前的 Spring 4 中,我们使用 @ControllerAdvice 来捕获异常,非常方便。
    • 很好的解决方案。顺便说一句,这会引发 HttpRequestMethodNotSupportedException。
    【解决方案3】:

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

    【讨论】:

    • 我做了一些研究,但找不到 PathVariable 和 BindingResult 之间的联系。还有其他人吗?
    【解决方案4】:

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

    虽然这不是“春天”的方式,但我推荐它,因为它对我来说很容易,也很容易让我未来的海上维护程序员理解。

    【讨论】:

    • 要知道这看起来像是首选解决方案,但我真的不喜欢它(因为它涉及很多更改)。希望有其他解决方案。
    • 另一种解决方案是重写/编写自己的 WebDataBinder 并抛出更具体的异常。
    【解决方案5】:

    将您的 cmets 放在一起,我尝试了以下方法:

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

    希望你喜欢,

    一月

    【讨论】:

      猜你喜欢
      • 2014-09-10
      • 2017-12-27
      • 1970-01-01
      • 2013-09-28
      • 1970-01-01
      • 2018-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多