1、本文目的
目前多数系统都采用前后端分离的方式,后端只负责提供restfull接口,返回json格式的数据就可以了,前端负责渲染。
本文带大家主要解决2个问题,在springmvc提供json格式的接口的时候,需要解决2个问题
- 问题1:所有接口的返回值采用统一的格式
- 问题2:系统中异常处理设计的问题,采用一种非常好的方式来解决这个问题
下面咱们一起来解决这2个问题。
2、解决问题1:实现统一的返回值
所有的接口均返回ResultDto类型的数据,ResultDto类的代码如下,主要有4个字段
- success:表示接口是成功还是失败
- code:错误码,当有异常的时候,可以返回具体的错误码
- msg:提示信息,比如:操作成功、用户名有误、密码有误等等
- data:类型是一个泛型,表示任意类型,这个用来存放接口中具体返回的数据,可以是任意类型的对象
- 还提供了几个静态方法,方便创建ResultDto对象
/*** rest接口通用返回值数据结构** @param <T>*/public class ResultDto<T> {//接口状态(成功还是失败)private Boolean success;//错误码private String code;//提示信息private String msg;//数据private T data;public Boolean getSuccess() {return success;}public void setSuccess(Boolean success) {this.success = success;}public String getCode() {return code;}public void setCode(String code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public T getData() {return data;}public void setData(T data) {this.data = data;}public static <T> ResultDto<T> success(T data) {return success(data, "操作成功!");}public static <T> ResultDto<T> success(T data, String msg) {ResultDto<T> result = new ResultDto<>();result.setSuccess(Boolean.TRUE);result.setMsg(msg);result.setData(data);return result;}public static <T> ResultDto<T> error(String msg) {return error(null,msg);}public static <T> ResultDto<T> error(String code,String msg) {return error(code,msg,null);}public static <T> ResultDto<T> error(String code, String msg, T data) {ResultDto<T> result = new ResultDto<>();result.setSuccess(Boolean.FALSE);result.setCode(code);result.setMsg(msg);result.setData(data);return result;}}
3、解决问题2:统一处理异常
3.1、如何做?
异常处理这块,我们的设计主要有2点,通过这2点来解决异常处理的问题
- 第一点:定义一个基础的业务异常类(BusException),业务代码中手动抛出异常的时候,统一抛出这种类型的异常,异常类型中可以携带更详细的错误信息,比如错误码、提示信息、扩展数据等等
- 第2点:采用springmvc全局来处理异常,控制器中不要捕获异常,将一次交给springmvc框架来统一处理。
3.2、具体代码
下面我们来看具体的代码片段,主要有2个类
业务异常类:BusException
代码比较简单,主要有2个属性和几个静态方法
- code:异常错误码,最终会丢给ResultDto的code属性输出到客户端
- data:异常的时候,可以传递一些扩展信息,此时可以丢到data中,最终会丢给ResultDto的data属性输出到客户端
- 提供了几个静态方法,便于抛出BusException异常
- 当我们的业务代码中需要抛出异常的时候,要求均抛出BusException类型的异常
/*** 业务异常*/public class BusException extends RuntimeException {//异常错误码private String code;//错误扩展信息private Object data;public BusException(String msg) {this(null, msg);}public BusException(String code, String msg) {this(code, msg, null);}public BusException(String code, String msg, Object data) {super(msg);this.code = code;this.data = data;}public String getCode() {return code;}public void setCode(String code) {this.code = code;}public Object getData() {return data;}public void setData(Object data) {this.data = data;}public static void throwBusException(String msg) {throwBusException(null, msg);}public static void throwBusException(String code, String msg) {throwBusException(code, msg, null);}public static void throwBusException(String code, String msg, Object data) {throw new BusException(code, msg, data);}}
全局异常统一处理类:GlobalExceptionHandle
如下代码,大家对springmvc统一异常处理不了解,建议先看一下上一篇文章。
注意下面代码中的
@1,这里使用到了@RestControllerAdvice,这个注解之前没有介绍过,他和@ControllerAdvice功能类似,只是这个注解内部定义的时候上面多了一个@ResponseBody注解,表示下面这个类中处理异常的方法返回值最终都会以json格式输出到客户端
/*** 全局异常处理*/@RestControllerAdvice // @1public class GlobalExceptionHandle {/*** 统一处理业务异常** @param e* @param <T>* @return*/@ExceptionHandler(BusException.class)public <T> ResultDto<T> doBusException(BusException e) {//1、记录错误日志//2、返回结果return ResultDto.error(e.getCode(), e.getMessage(), (T) e.getData());}/*** 处理其他异常** @param e* @param <T>* @return*/@ExceptionHandlerpublic <T> ResultDto<T> doException(Exception e) {//1、记录错误日志//2、返回结果return ResultDto.error("系统异常,请联系管理员,错误详情:" + e.getMessage());}}
2个问题解决了,下面我们来看看controller中如何使用。
4、Controller中代码如何写?
来个案例
如下代码,注意两点信息
- 内部提供了2个接口,接口的返回值都是ResultDto类型的
- 代码中,没有了try catch,而是将异常类型封装为BusException类型抛出,比如验证码有误,会抛出了BusException,顺便携带了错误码和错误提示信息,这些都会通过全局异常的处理,输出到客户端
@RestController@RequestMapping("/user")public class UserController {/*** 获取用户id** @param code* @return*/@RequestMapping("/getUserName")public ResultDto<String> getUserName(@RequestParam("code") Integer code) {if (!Integer.valueOf(6666).equals(code)) {//验证码有误的时候,返回4001错误码BusException.throwBusException("4001", "验证码有误!");}return ResultDto.success("路人");}/*** 获取用户id** @param code* @return*/@RequestMapping("/getUserId")public ResultDto<String> getUserId(@RequestParam("code") Integer code) {if (!Integer.valueOf(6666).equals(code)) {BusException.throwBusException("4001", "验证码有误!");}return ResultDto.success("8888");}}
验证效果
下面我们通过idea提供的HTTP client工具搞三个测试用例,测试下接口的效果,如下图,大家可以分别运行一下3个案例。

用例1输出结果:
{"success": true,"code": null,"msg": "操作成功!","data": "路人"}
用例2输出结果:
{"success": false,"code": "4001","msg": "验证码有误!","data": null}
用例3输出的结果:
{"success": false,"code": null,"msg": "系统异常,请联系管理员,错误详情:Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; nested exception is java.lang.NumberFormatException: For input string: \"abc\"","data": null}
5、总结
本文内容主要有2点:统一返回值、统一异常的处理,这2点大家要好好掌握,目前业界很少使用springmvc直接开发接口了,更多的是采用springboot来开发接口,本文的内容直接可以用到springboot中,来优化咱们的系统。
6、案例代码
git地址:https://gitee.com/javacode2018/springmvc-series

最新资料
更多内容请访问:IT源点
注意:本文归作者所有,未经作者允许,不得转载