版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lupengfei1009/article/details/88065593
导读
本文基于以下文章开发:
SpringBoot学习之旅(二)—整合MyBatis(MyBatis Generator)
源码地址
前言
所谓了系统,就是将一系列的请求响应的交互,按一定的流程及规则,将其串联起来,每一次的请求交互做其中的某一项小的工作;然后一步一步的将其串联成一个完整的业务线;正因为每次做的事情及交互的数据不一致,因此我们就需要规范化每一次的请求及响应;这样公共部分的请求及响应的数据即可统一去处理,业务中只需要去处理本次操作个性化的数据及相关的校验,从而降低不必要的校验及冗余的代码。
响应规范
响应示例
- 响应示例
- 成功响应
状态为0时标识{ "status": 1, "data": { "key1": "va1", "key2": 2, "key3": true } }
- 错误响应
{ "status": -1, "data": { "errCode": 10001, "errMsg": "参数错误!" } }
- 成功响应
代码实现
-
定义公共错误信息接口
/** * 公共异常的接口 */ public interface ComErrorInf { /** * 获取错误码 * * @return */ Integer getErrCode(); /** * 获取错误描述 * * @return */ String getErrMsg(); /** * 修改错误描述信息 * * @param errMsg * @return */ ComErrorInf setErrMsg(String errMsg); }
-
定义错误码枚举(BusiErrCodeEm)
该枚举实现平台公共的错误接口ComErrorInf
具体的错误码信息,根据个人业务定义,这里只说一个大致的规范public enum BusiErrCodeEm implements ComErrorInf { //>10000的错误码约束为参数才错误码 REQ_PARAM_10001(10001, "参数信息有误"), REQ_PARAM_10002(10002, "参数校验失败"), //>20000 约束为用户的错误码 USER_20001(20001, "未找到用户"), //>30000 约束为订单的错误码 BUSI_ORDER_30001(30001, "订单信息未找到"), UNKNOWN(999999, "未知错误"); /** * 错误码 */ private Integer errCode; /** * 错误描述 */ private String errMsg; BusiErrCodeEm(Integer errCode, String errMsg) { this.errCode = errCode; this.errMsg = errMsg; } @Override public Integer getErrCode() { return this.errCode; } @Override public String getErrMsg() { return this.errMsg; } @Override public ComErrorInf setErrMsg(String errMsg) { this.errMsg = errMsg; return this; } }
-
定义业务异常类(BusiException)
业务异常实现平台公共的错误接口ComErrorInf
由于错误码枚举和异常实现了同一个接口,因此就可以将枚举中的错误码信息转化为异常信息并返回public class BusiException extends Exception implements ComErrorInf { private ComErrorInf comErrorInf; /** * 接受BusiErrCodeEm传参,构造业务异常 * * @param comErrorInf */ public BusiException(ComErrorInf comErrorInf) { super(); this.comErrorInf = comErrorInf; } public BusiException(ComErrorInf comErrorInf, String errMsg) { super(); this.comErrorInf = comErrorInf; this.comErrorInf.setErrMsg(errMsg); } @Override public Integer getErrCode() { return this.comErrorInf.getErrCode(); } @Override public String getErrMsg() { return this.comErrorInf.getErrMsg(); } @Override public ComErrorInf setErrMsg(String errMsg) { this.comErrorInf.setErrMsg(errMsg); return this; } }
-
使用示例
业务中如果出现异常,比如用户信息不存在,那么就可以使用以下方式向上抛异常throw new BusiException(BusiErrCodeEm.USER_20001);
如何优雅处理异常
- 异常处理场景
- 场景一
对于系统来说,异常是很常见的,比如前端传参不对,参数校验不对,数据库数据未找到,空指针等等的错误;如果说我们没有一个公共的处理异常的地方,就会出现到处都是异常处理机制,这样对于开发人员来说,是一个很没有营养、很恶心、很耗时的体力活,同时还不利于系统的维护及健壮;我们需要的正确做法是,在各自的业务流程中抛出对应的异常,由一个统一的地方去接受到异常,并友好的返回给前端; - 场景二
使用传统的MVC涉及模式,Controller为整个系统处理完之后,响应给用户的最后一道关口,MV层出现了异常且异常没有捕获并处理的话,如果Controller不加以处理,那么Spring就会以HttpStatus为500等错误状态返回给前端,这样用户端就会出现一个很不友好的错误信息;对于系统来说,只要接收到用户的请求,那么就应该回一个HttpStatus.OK的状态回去,如果业务出现异常,那么我们只需要根据响应报文去友好的去做处理;
- 场景一
- 使用ExceptionHandler
- 定义BaseController
将ExceptionHandler的捕获代码写在BaseController,系统级的所有Controller都继承自BaseControllerpackage com.lupf.springboottest.controller; import com.lupf.springboottest.error.BusiErrCodeEm; import com.lupf.springboottest.error.BusiException; import com.lupf.springboottest.response.BaseRespObj; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import java.util.HashMap; import java.util.Map; public class BaseController { /** * 通过ExceptionHandler 捕获controller未捕获到的异常,给用户一个友好的返回 * * @param ex 异常信息 * @return */ //捕获为Exception的异常 @ExceptionHandler(Exception.class) //指明响应的状态为200 @ResponseStatus(HttpStatus.OK) //返回业务对象 @ResponseBody public Object exceptionHandler(Exception ex) { BaseRespObj baseRespObj = new BaseRespObj(); baseRespObj.setStatus(-1); Map<String, Object> errObjs = new HashMap<>(); if (ex instanceof BusiException) { BusiException busiException = (BusiException) ex; errObjs.put("errCode", busiException.getErrCode()); errObjs.put("errMsg", busiException.getErrMsg()); } else { errObjs.put("errCode", BusiErrCodeEm.UNKNOWN.getErrCode()); errObjs.put("errMsg", BusiErrCodeEm.UNKNOWN.getErrMsg()); } baseRespObj.setData(errObjs); return baseRespObj; } }
- 用户Controller
package com.lupf.springboottest.controller; import com.lupf.springboottest.dao.UserDOMapper; import com.lupf.springboottest.dataobject.UserDO; import com.lupf.springboottest.error.BusiErrCodeEm; import com.lupf.springboottest.error.BusiException; import com.lupf.springboottest.response.BaseRespObj; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/user") public class UserController extends BaseController { @Autowired UserDOMapper userDOMapper; @RequestMapping("/hello") public BaseRespObj getUserById(@RequestParam(name = "id") Integer id) throws BusiException { UserDO userDO = userDOMapper.selectByPrimaryKey(id); if (null == userDO) { throw new BusiException(BusiErrCodeEm.USER_20001); } BaseRespObj baseRespObj = BaseRespObj.create(userDO); return baseRespObj; } }
-
正常的请求
-
未找到用户
扫描二维码关注公众号,回复: 5443665 查看本文章 -
模拟空指针,测试未捕获到的异常
-
- 定义BaseController