前言:
最近使用springmvc写了不少rest api, 觉得真是一个好框架. 之前描述的几篇关于rest api的文章, 其实还是不够完善. 比如当遇到参数缺失, 类型不匹配的情况时, 直接抛出异常, 返回的内容是400+的错误页面, 而不是json内容, 这让移动端的调用方很难处理.
本文主要讲述对于rest api, springmvc对异常的解决处理方案.
系列整理:
springmvc学习笔记系列的文章目录:
• idea创建springmvc项目
• 面向移动端的REST API
• Jackson的使用和定制
REST API的设计原则博文
• 移动互联网实战—Web Restful API设计和基础架构
场景构造:
大背景, 我们已借助使用Jackson框架和注解@ResonseBody来实现pojo对象以json形式返回.
先来构造几个案例, 来描述我们所要解决的问题.
共同的测试代码:
@Controller
@RequestMapping("/math")
public class TestController { @RequestMapping(value="/div", method= RequestMethod.GET)
@ResponseBody
public int div(@RequestParam("a") int a,
@RequestParam("b") int b) {
// *) div zero error
return a / b;
} }
1). 场景一(参数缺失, 类型不匹配)
case 1:
http://localhost:8080/math/div?a=10
参数b缺失, 返回400错误页
case 2:
http://localhost:8080/math/div?a=10&b=hehe
参数b类型不对, 类型转换失败
我们的希望是, 将这些参数缺少/类型不匹配的异常, 以JSON串的形式返回, 而不是以400的错误页面返回.
2). 场景二(业务代码抛出异常)
case 1:
http://localhost:8080/math/div/a=10&b=0
发生除零异常
内部抛出业务异常非常常见, 防不胜防, 返回是500+的错误页面.
解决方案:
基于上文的场景, 遇到异常时, 返回的都是400+/500+的错误页面, 一方面客户端sdk解析和处理麻烦, 另一方面泄露了内部的错误细节. 那是否一种办法拦截异常, 并返回自己定义的错误数据格式呢?
答案是肯定的, springmvc引入了织入@ControlAdvice.
其对异常的处理, 非常的方便, 可简单参考如下sample.
@ControllerAdvice
public class RestApiControlAdvice { @ExceptionHandler(value=RuntimeException.class)
@ResponseBody
public String handle(RuntimeException e) {
// *记入异常日志
return e.getMessage();
} @ExceptionHandler(value=Exception.class)
@ResponseBody
public String handle(Exception e) {
// *记入异常日志
return e.getMessage(); } }
通过结合注解@ExceptionHanlder, 来定义具体的异常处理, 以及返回的结果.
这边需要注意的是, @ExceptionHandler可定义多个, 当多个匹配时, 按编写最早的处理函数优先处理. 这边就像try/catch那种常见的情况了, 既顺序敏感. 最佳实践, 需要把处于顶层的异常类搁置到代码最尾端.
当然对于参数缺失/类型不匹配的处理, 可以如下定义.
@ExceptionHandler(value=MissingServletRequestParameterException.class)
@ResponseBody
public TResult<Void> handle(MissingServletRequestParameterException e) {
return "Miss parameter " + e.getParameterName() + ":" + e.getParameterType();
} @ExceptionHandler(value= TypeMismatchException.class)
@ResponseBody
public String handle(TypeMismatchException e) {
return e.getErrorCode() + ", required type: " + e.getRequiredType() + ", but value: " + e.getValue();
}
业务上的异常代码, 往往可以抽象出一个异常基类.
总结:
springmvc的入门和上手确实非常快, 但要真正的理解. 确实还是需要花功夫, 这边只是简单介绍一下, 并没有深入源码. 希望将来有一天有机会讲讲背后的技术原理.
公众号&游戏站点:
个人微信公众号: 木目的H5游戏世界
个人游戏作品集站点, www.mmxfgame.com, 请点击访问: http://120.26.221.54/.