springcloud请求异常处理封装businessexception自定义异常类(代码片段)

流楚丶格念 流楚丶格念     2022-10-21     544

关键词:

文章目录

请求异常处理

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和errMessage
        if(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 
    //校验验证码的url
    String 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" 

axios请求封装,请求异常统一处理

参考技术A前端采用了axios来处理网络请求,为了避免在每次请求时都去判断各种各样的网络情况,比如连接超时、服务器内部错误、权限不足等等不一而足,我对axios进行了简单的封装,这里主要使用了axios中的拦截器功能。封... 查看详情

springcloud如何统一异常处理?写得太好了!

作者:BNDong链接:https://www.cnblogs.com/bndong/p/10135370.html前言在启动应用时会发现在控制台打印的日志中出现了两个路径为[/error]的访问地址,当系统中发送异常错误时,SpringBoot会根据请求方式分别跳转到以JS 查看详情

springcloud如何统一异常处理?写得太好了!

点击关注公众号,Java干货及时送达作者:BNDong链接:www.cnblogs.com/bndong/p/10135370.html前言在启动应用时会发现在控制台打印的日志中出现了两个路径为[/error]的访问地址,当系统中发送异常错误时,SpringBoot会根... 查看详情

springcloud如何统一异常处理?写得太好了!(代码片段)

作者:BNDong链接:https://www.cnblogs.com/bndong/p/10135370.html前言在启动应用时会发现在控制台打印的日志中出现了两个路径为[/error]的访问地址,当系统中发送异常错误时,SpringBoot会根据请求方式分别跳转到以JSON格式... 查看详情

springcloud学习系列之七-----zuul路由网关的过滤器和异常处理(代码片段)

前言在上篇中介绍了SpringCloudZuul路由网关的基本使用版本,本篇则介绍基于SpringCloud(基于SpringBoot2.x,.SpringCloudFinchley版)中的路由网关的过滤器Filter以及异常处理的教程。SpringCloudZuulFilter介绍过滤器概述Zuul的中心是一系列过滤器,... 查看详情

springcloud异常处理

  一开始我想着是在Feign的ErrorDecoder上做自定义的异常处理,来实现根据httpcode抛出各种异常。但是Feign与Hystrix结合之后,发现一个问题,只要服务调用抛出了Throwable类就会触发Hystrix的fallback(前提是配置了fallback)。想来想去... 查看详情

springcloud升级之路2020.0.x版-41.springcloudgateway基本流程讲解(代码片段)

...ceptionHandlingWebHandler之前有网友私信问过笔者,如何给SpringCloudGateway加全局异常处理器,其实和给基于Spring-Flux的异步Web服务加是一样的,都是通过实现并注册一个WebExceptionHandlerBean:WebExceptionHandler.javapublicinterfaceWe... 查看详情

统一异常处理(代码片段)

1统一请求返回的最外层对象日常处理请求时,异常返回结果与正常返回结果格式不一样,不利于前后端的数据交互,如果不处理也不利于编码。封装一个统一请求返回结果最外层对象是一种比较好的设计思想。packagecom.latiny.pojo;... 查看详情

reactnative——fetch封装新姿势

React和ReactNative的网络请求使用的是fetch关于基本的POST和GET请求以及异步变同步就不再描述,看看API的介绍。网络请求封装要完成的内容有:1、基本功能(网络请求)2、统一处理异常处理不同错误码处理3、可定制... 查看详情

springcloud---feignclient处理请求超时问题

1.feign的配置对应FeignClientConfig,会把配置文件的配置读入此类。2.连接超时和读超时(以properties文件形式为例):feign.client.config.springApplicationName.connectTimeout=1000.feign.client.config.springApplicationName.readTimeout=1000.sprin 查看详情

retrofit2.0+rxjava网络请求异常统一处理

...题下面列出具体添加的依赖。以下这些错误,都是在网络请求中经常见的。我们可以通过Toast弹出消息通知用户具体的异常以及加载对应的UI界面。除此之外,通过具体的异常信息,方便我们及时的排查项目中的BUG。那么问题就... 查看详情

springcloud微服务如何设计异常处理机制?

导读 今天和大家聊一下在采用Spring Cloud进行微服务架构设计时,微服务之间调用时异常处理机制应该如何设计的问题。我们知道在进行微服务架构设计时,一个微服务一般来说不可避免地会同时面向内部和外部提供相应... 查看详情

18.fastapi错误处理

...se,而不是return。HTTPException的参数包括:代码示例:执行请求:上面的请求是一个返回正确结果的请求。下面执行一个返回错误的请求:在FastAPI中,可以根据用户的需求进行自定义异常的封装和处理,对于自定义异常首先需要... 查看详情

springcloud-feign客户端统一处理下游服务自定义异常(1.5.x版本下可以)

参考技术A经过尝试和查阅资料,Springcloud处理下游服务的异常是是通过默认的ErrorDecoder实现处理的,最终上游业务获取抛出的异常处理都是FeignException处理,到时上游业务统一异常处理造成困扰,下面解决方式为:主要分析了返... 查看详情

wx小程序-request请求在项目实战中的封装

参考技术A在小程序项目开发中,对请求做封装是比较常见的操作,我们可以在封装过的请求里,做一些统一处理,比如统一配置、请求拦截、错误异常处理、授权处理等好了,我们直接看干货,上代码在项目根目录下新建一个re... 查看详情

解决:springcloud中feign支持get请求pojo传参

...OJO对象中,已提高程序的可读性和简化编写。但是在使用SpringCloud时,Feign对SpringMVC注解支持并不完善,其中一点就是,当发送的GET请求携带多个参数时,不能使用POJO来封装参数,这个就比较蛋疼了。一种使之支持GET请求POJO传递... 查看详情

springcloud源码分析(eureka-server-处理客户端删除状态请求)

文章目录​​1.处理客户端删除状态请求​​​​1.1InstanceResource.deleteStatusUpdate()​​​​1.2PeerAwareInstanceRegistryImpl.deleteStatusOverride()​​​​1.3AbstractInstanceRegistry.deleteStatusOverride()​​​​1.4PeerAwareInstance 查看详情

springcloud请求响应数据转换

上篇文章记录了从后端接口返回数据经过切面和消息转换器处理后返回给前端的过程。接下来,记录从请求发出后到后端接口调用过的过程。web请求处理流程源码分析 ApplicationFilterChain会调DispatcherServlet类的doService()(HttpServle... 查看详情