文章目录

  • 请求异常处理
    • 1 异常信息格式
    • 2 异常处理流程
    • 3 自定义业务异常类
    • 4 自定义业务异常处理器
    • 5 抛出自定义异常

请求异常处理

1 异常信息格式

系统在交互中难免会有异常发生,前端为了解析异常信息向用户提示特定义了异常信息的返回格式,如下:

1、返回response状态说明

状态码 说明
200 成功
401 没有权限
500 程序错误(需要自定义错误体)

2、自定义错误体

{"errCode": "你定义的错误码", "errMessage": "错误说明"
}

例如下面根据不同的业务自定义的错误码:

2 异常处理流程

截至目前系统并没有按照前端要求返回异常信息,测试如下:

注册商户时输入一个错误的验证码,返回信息如下

{ "timestamp": "2021‐12‐10T10:06:19.936+0000", "status": 500, "error": "Internal Server Error", "message": "验证码错误", "path": "/merchant/merchants/register"
}

从上边的返回信息得知,状态码为500符合要求,按前端的规范定义的错误信息要写在“errMessage” 中,显然不符合要求。

系统规范了异常处理流程,如下:

1、在服务层抛出自定义异常类型及不可预知异常类型。

上图中BusinessException为系统的自定义异常类型,程序中在代码显示抛出该异常,此类异常是程序员可预知的。

另一部分是系统无法预知的异常,如:数据库无法连接,服务器宕机等场景下所抛出的异常,此类异常是程序员无法预知的异常。

2、应用层接收到服务层抛出异常继续向上抛出,应用层自己也可以抛出自定义异常类型及不可预知异常类型。

3、统一异常处理器捕获到异常进行解析。

判断如果为自定义异常则直接取出错误代码及错误信息,因为程序员在抛出自定义异常时已将错误代码和异常信息指定。

如果为不可预知的异常则统一定义为99999异常代码。

4、统一异常处理器将异常信息格式为前端要求的格式响应给前端。

服务端统一将异常信息封装在下边的Json格式中返回:

{"errCode": "000000", "errMessage": "错误说明"
}

3 自定义业务异常类

1、在shanjupay-common工程的com.shanjupay.common.domain包下添加业务异常类BusinessException:

package com.shanjupay.common.domain;/*** 自定义的异常类型* @author Administrator* @version 1.0**/
public class BusinessException extends RuntimeException {private ErrorCode errorCode;public BusinessException(ErrorCode errorCode) {super();this.errorCode = errorCode;}public BusinessException() {super();}public void setErrorCode(ErrorCode errorCode) {this.errorCode = errorCode;}public ErrorCode getErrorCode() {return errorCode;}
}

2、定义错误代码

在common工程专门定义了ErrorCode接口及CommonErrorCode通用代码。

编写 ErrorCode 接口

package com.shanjupay.common.domain;public interface ErrorCode {int getCode();String getDesc();}

编写 CommonErrorCode通用代码

package com.shanjupay.common.domain;/*** 异常编码*/
public enum CommonErrorCode implements ErrorCode {公用异常编码 //E_100101(100101,"传入参数与接口不匹配"),E_100102(100102,"验证码错误"),E_100103(100103,"验证码为空"),E_100104(100104,"查询结果为空"),E_100105(100105,"ID格式不正确或超出Long存储范围"),E_100106(100106,"上传错误"),E_100107(100107,"发送验证码错误"),E_100108(100108,"传入对象为空"),E_100109(100109,"手机号格式不正确"),E_100110(100110,"用户名为空"),E_100111(100111,"密码为空"),E_100112(100112,"手机号为空"),E_100113(100113,"手机号已存在"),E_100114(100114,"用户名已存在"),E_100115(100115,"密码不正确"),SAAS服务异常编码110 //E_110001(110001,"账号不存在"),E_110002(110002,"角色编码在同一租户中已存在,不可重复"),E_110003(110003,"角色为空"),E_110004(110004,"角色已绑定账号,被使用中不可删除"),E_110005(110005,"权限集合为空"),E_110006(110006,"参数为空"),E_110007(110007,"未查询到租户关联的角色"),E_110008(110008,"账号被其他租户使用,不可删除"),商户服务异常编码200//E_200001(200001,"企业名称不能为空"),E_200002(200002,"商户不存在"),E_200003(200003,"商户还未通过认证审核,不能创建应用"),E_200004(200004,"应用名称已经存在,请使用其他名称"),E_200005(200005,"应用不属于当前商户"),E_200006(200006,"门店不属于当前商户"),E_200007(200007,"二维码生成失败"),E_200008(200008,"授权码为空"),E_200009(200009,"订单标题为空"),E_200010(200010,"订单金额为空"),E_200011(200011,"授权码格式有误"),E_200012(200012,"租户不存在"),E_200013(200013,"员工不存在"),E_200014(200014,"商户下未设置根门店"),E_200015(200015,"未查询到该门店"),E_200016(200016,"资质申请已通过,无需重复申请"),E_200017(200017,"商户在当前租户下已经注册,不可重复注册"),E_200018(200018,"商户下的根门店,不可删除"),交易服务异常编码300//E_300001(300001,"支付金额为空"),E_300002(300002,"openId为空"),E_300003(300003,"appId为空"),E_300004(300004,"商户id为空"),E_300005(300005,"服务类型编码为空"),E_300006(300006,"订单金额转换异常"),E_300007(300007,"原始支付渠道为空"),E_300008(300008,"已存在相同的支付参数,不可重复配置"),E_300009(300009,"传入对象为空或者缺少必要的参数"),E_300010(300010,"应用没有绑定服务类型,不允许配置参数"),E_300110(300110,"交易单号不能为空"),支付渠道代理服务异常编码400//E_400001(400001,"微信确认支付失败"),E_400002(400002,"支付宝确认支付失败"),运营服务异常编码500//特殊异常编码/E_999991(999991,"调用微服务-授权服务 被熔断"),E_999992(999992,"调用微服务-用户服务 被熔断"),E_999993(999993,"调用微服务-资源服务 被熔断"),E_999994(999994,"调用微服务-同步服务 被熔断"),E_999910(999910,"调用微服务-没有传tenantId租户Id"),E_999911(999911,"调用微服务-没有json-token令牌"),E_999912(999912,"调用微服务-json-token令牌解析有误"),E_999913(999913,"调用微服务-json-token令牌有误-没有当前租户信息"),E_999914(999914,"调用微服务-json-token令牌有误-该租户下没有权限信息"),E_NO_AUTHORITY(999997,"没有访问权限"),CUSTOM(999998,"自定义异常"),/*** 未知错误*/UNKNOWN(999999,"未知错误");private int code;private String desc;public int getCode() {return code;}public String getDesc() {return desc;}private CommonErrorCode(int code, String desc) {this.code = code;this.desc = desc;}public static CommonErrorCode setErrorCode(int code) {for (CommonErrorCode errorCode : CommonErrorCode.values()) {if (errorCode.getCode()==code) {return errorCode;}}return null;}
}

目录结构如下:

4 自定义业务异常处理器

1、在shanjupay‐common工程的com.shanjupay.common.domain包下添加错误响应包装类RestErrorResponse:

package com.shanjupay.common.domain;import io.swagger.annotations.ApiModel;
import lombok.Data;/*** @author Administrator* @version 1.0**/
@ApiModel(value = "RestErrorResponse", description = "错误响应参数包装")
@Data
public class RestErrorResponse {private String errCode;private String errMessage;public RestErrorResponse(String errCode,String errMessage){this.errCode = errCode;this.errMessage= errMessage;}
}

2、定义全局异常处理器

全局异常处理器使用ControllerAdvice注解实现,ControllerAdvice是SpringMVC3.2提供的注解,用 ControllerAdvice可以方便实现对Controller面向切面编程,具体用法如下:

注解 说明
ControllerAdvice和ExceptionHandler注解 实现全局异常处理
ControllerAdvice和ModelAttribute注解 实现全局数据绑定
ControllerAdvice生InitBinder注解 实现全局数据预处理

这里用到的是第一种用法:ControllerAdvice和ExceptionHandler结合可以捕获Controller抛出的异常

ControllerAdvice和ExceptionHandler结合可以捕获Controller抛出的异常,根据异常处理流程,Service和持久层最终都会抛给Controller,所以此方案可以实现全局异常捕获,异常被捕获到即可格式为前端要的信息格式响应给前端。

在shanjupay‐merchant‐application工程 com.shanjupay.merchant.common.intercept添加

GlobalExceptionHandler:

package com.shanjupay.merchant.common.intercept;import com.shanjupay.common.domain.BusinessException;
import com.shanjupay.common.domain.CommonErrorCode;
import com.shanjupay.common.domain.ErrorCode;
import com.shanjupay.common.domain.RestErrorResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** 全局异常处理器* @author Administrator* @version 1.0**/
@ControllerAdvice//与@Exceptionhandler配合使用实现全局异常处理:可以捕获Controller抛出的异常
public class GlobalExceptionHandler {private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);//捕获Exception异常@ExceptionHandler(value = Exception.class)@ResponseBody@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)public RestErrorResponse processExcetion( HttpServletRequest request,HttpServletResponse response,Exception e){//解析异常信息//如果是系统自定义异常,直接取出errCode和errMessageif(e instanceof BusinessException){LOGGER.info(e.getMessage(),e);//解析系统自定义异常信息BusinessException businessException= (BusinessException) e;ErrorCode errorCode = businessException.getErrorCode();//错误代码int code = errorCode.getCode();//错误信息String desc = errorCode.getDesc();return new RestErrorResponse(String.valueOf(code),desc);}LOGGER.error("系统异常:",e);//统一定义为99999系统未知错误return new RestErrorResponse(String.valueOf(CommonErrorCode.UNKNOWN.getCode()),CommonErrorCode.UNKNOWN.getDesc());}
}

5 抛出自定义异常

按照异常处理流程,应用层抛出自定义异常由异常处理器进行解析。

1、校验验证码接口抛出 BusinessException

修改商户平台应用工程中SmsServicer的verifificationMessageCode接口

public void checkVerifyCode(String verifyKey, String verifyCode) throws BusinessException;

接口实现中抛出异常自定义异常类型

/*** 校验手机验证码** @param verifiyKey  验证码的key* @param verifiyCode 验证码*/
@Override
public void checkVerifiyCode(String verifiyKey, String verifiyCode) throws BusinessException {//校验验证码的urlString url = "http://localhost:56085/sailing/verify?name=sms&verificationCode="+verifiyCode+"&verificationKey="+verifiyKey;Map bodyMap = null;try {//使用restTemplate请求验证码服务ResponseEntity<Map> exchange = restTemplate.exchange(url, HttpMethod.POST, HttpEntity.EMPTY, Map.class);log.info("请求验证码服务,得到响应:{}", JSON.toJSONString(exchange));bodyMap = exchange.getBody();}catch (Exception e){e.printStackTrace();throw new BusinessException(CommonErrorCode.E_100102);//  throw new RuntimeException("校验验证码失败");}if(bodyMap == null || bodyMap.get("result") == null || !(Boolean) bodyMap.get("result")){throw new BusinessException(CommonErrorCode.E_100102);}
}

2、测试

请求商户注册,输出一个错误的验证码,返回信息如下:

{ "errCode": "100102", "errMessage": "验证码错误"
}

3、测试不可预知异常

故意在Controller中制造异常,测试是否抛出未知错误异常。

代码如下:

@PostMapping("/merchants/register")
public MerchantRegisterVO registerMerchant(@RequestBody MerchantRegisterVO merchantRegister){ int i=1/0;//故意制造异常 ....

请商户注册,返回信息如下:

{ "errMessage": "未知错误", "errCode": "999999"
}

SpringCloud请求异常处理封装BusinessException自定义异常类相关推荐

  1. Spring MVC如何接收浏览器传递来的请求参数--request--形参--实体类封装

    阅读目录 1. 通过HttpServletRequest获得请求参数和数据 2. 处理方法形参名==请求参数名 3. 如果形参名跟请求参数名不一样怎么办呢?用@RequestParam注解 4. 用实 ...

  2. java编写自定义异常类,统一异常处理

    /** * 自定义异常类 */ public class MyBaseException extends RuntimeException{private static final long seri ...

  3. java异常处理封装_Java统一异常处理(配置文件集中化定义)

    0.前言 无论任何项目,都避免不了在运行期间出现的一些异常,并伴随着因业务逻辑的需要而给出相应的提示,使得系统变得更加友好,这类提示处理,我们统称为异常处理(exceptiona handling). ...

  4. SpringBoot实现自定义异常类。

    本文分为两种方法,第一种适合于对于小程序这种简单的应用,只需要得到错误消息即可,第二章针对大型规范化的网页项目. 一.简易异常类封装: 1.创建自定义异常类 1.继承RuntimeException. ...

  5. 如何写一个自定义异常类

    1.自定义异常概述 当在某一些特殊情况下,JDK自带的异常无法准确描述异常情况时,采用自己定义异常类的方式封装异常信息. 2. 步骤: 申明一个异常处理类 异常处理类继承RuntimeExceptio ...

  6. Java封装OkHttp3工具类

    点击关注公众号,Java干货及时送达  作者:如漩涡 https://blog.csdn.net/m0_37701381 Java封装OkHttp3工具类,适用于Java后端开发者 说实在话,用过挺多 ...

  7. java+自定义异常类+输入若干成绩 为负数时输出抛出异常_java+自定义异常类+输入若干成绩 为...

    java+自定义异常类+输入若干成绩 为 [2021-02-10 19:00:54]  简介: java中定义类的关键字是:"class".在Java中定义一个类,需要使用&quo ...

  8. 如何编写和应用Java的自定义异常类

    11.7.1  编写自定义异常类的模式 编写自定义异常类实际上是继承一个API标准异常类,用新定义的异常处理信息覆盖原有信息的过程.常用的编写自定义异常类的模式如下: public class Cus ...

  9. java 处理异常的场景_Java高级----异常处理机制、自定义异常----含思维导图

    Java高级----异常处理机制.自定义异常----含思维导图 Java高级----异常处理机制.自定义异常----含思维导图 南一Java自学交流QQ群: 586012641 拒绝任何广告,共享Ja ...

最新文章

  1. 高并发编程-通过volatile重新认识CPU缓存 和 Java内存模型(JMM)
  2. NYOJ 16(矩形嵌套)
  3. 网络经济与企业管理(第 2 章:企业战略管理)
  4. 计算机组成原理mbps,2016年湖北师范学院计算机组成原理(同等学力加试)复试笔试仿真模拟题...
  5. STL源码剖析 关联式容器 红黑树
  6. 100篇论文串讲对话系统前世今生
  7. Android 开发者的 RxJava 详解(一)
  8. 【英语学习】【English L06】U01 Breakfast L3 I'm full from my brunch
  9. Linux学习:第一天,
  10. 倒计时 2 天!「2019 嵌入式智能国际大会」全日程大公开!
  11. 【IDEA】关于 IDEA 中新建 web 项目的 webapp 文件夹没有小蓝点 ,启动服务,访问不到解决方案
  12. 20190912每日一句
  13. 工控机在机器视觉系统中的应用
  14. lua深拷贝一个table
  15. 字长是指计算机什么之间,字长是指计算机()之间一次能够传递的数据位,位宽是CPU通过外据总线与()之 - 问答库...
  16. Java 后端开发常用的第三方服务 TOP10
  17. 【Python】5行代码采集3000+上市公司信息
  18. 2022电赛C题:小车跟踪(方案1+核心代码)
  19. word文档的只有横线的表格怎样做
  20. 链式二叉树的代码实现

热门文章

  1. 玻璃钢 硅胶 石膏模具制作 大理石 花岗岩 树脂 仿玉背景墙 人造砂岩技术视频教程
  2. 硅酸钙板是什么,和石膏板一样吗?
  3. 【华为机试真题 Python】能量消耗
  4. 键盘的箭头键不能上移和左移_做excel表格时,键盘上的上下左右键不能起到跳格作用,只会在一个格子里移动,为什么呢?...
  5. java word 转 PDF|HTML|PNG
  6. NKOI 1939 魔术球
  7. HQChart使用教程20-单股票截面数据(财务数据)计算器
  8. 导航栏以及二级菜单栏(下拉列表)的制作
  9. ttest求pvalue_T检验和其他假设检验的P值怎么理解
  10. NoMachine Server 自动开启