我使用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。我希望能够捕获所有解析异常,以便向客户端提供一个很好的错误消息。
有什么想法吗?
干杯,
扬
答案 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注释方法捕获(我在所有验证器类中都使用此异常)。
希望你喜欢它,
扬