apache dubbo 自定义全局统一的异常处理器

2022-06-22 12:29:47

项目使用过的是apache dubbo 2.7.1, 封装了自定义全局统一的异常处理器。

统一异常处理器

需要实现javax.ws.rs.ext.ExceptionMapper接口。

import org.apache.dubbo.rpc.RpcException;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;import org.jboss.resteasy.spi.DefaultOptionsMethodException;import org.springframework.util.StringUtils;import javax.exceptions.ServiceException;import javax.ws.rs.NotFoundException;import javax.ws.rs.core.Response;import javax.ws.rs.ext.ExceptionMapper;import java.io.ByteArrayOutputStream;import java.io.PrintStream;import java.util.ArrayList;import java.util.List;/**
 * 全局统一的异常处理器。
 */publicclassCustomExceptionMapperimplementsExceptionMapper<Exception>{privatefinalstatic Logger logger= LogManager.getLogger(CustomExceptionMapper.class);privatestaticfinal String TEXT_PLAIN_UTF_8="text/plain; charset=UTF-8";privatestaticfinal String JSON_UTF_8="application/json;charset=UTF-8";privatestaticfinalint FILTER_SIZE=60;privatestaticfinal String DEV="dev";privatestaticfinal String TEST="test";privatestaticfinalint UNAUTHORIZED=401;publicstatic String active;publicstaticvoidsetActive(String at){
        active= at;}@Overridepublic ResponsetoResponse(Exception e){if(einstanceofDefaultOptionsMethodException||(StringUtils.hasText(e.getMessage())&& e.getMessage().contains("org.jboss.resteasy.spi.DefaultOptionsMethodException"))){// 忽略此异常: Option跨域请求探测return Response.status(Response.Status.OK).type(TEXT_PLAIN_UTF_8).build();}
        Response.Status httpStatus= Response.Status.INTERNAL_SERVER_ERROR;
        Result<String> errorResult= null;
        List<String> messages=newArrayList<>();if(e.getStackTrace().length>0){
            StackTraceElement ste= e.getStackTrace()[0];
            messages.add("异常内容:"+ e.getMessage());
            messages.add("异常名:"+ e.getClass());
            messages.add("异常类名:"+ ste.getClassName());
            messages.add("异常文件名:"+ ste.getFileName());
            messages.add("异常行号:"+ ste.getLineNumber());
            messages.add("异常方法:"+ ste.getMethodName());}//1.处理404异常if(einstanceofNotFoundException){
            logger.error("发生404异常: ", e);
            errorResult=fail(404,"404 not found!");
            httpStatus= Response.Status.NOT_FOUND;}//2.dubbo远程调用异常if(einstanceofRpcException){
            errorResult=fail(ErrorCodeEnums.InternalServerError.getCode(),"服务重新连线中,请稍后", messages);
            httpStatus= Response.Status.UNAUTHORIZED;}//3.非法参数异常if(einstanceofIllegalArgumentException){if(!StringUtils.isEmpty(e.getMessage())){
                errorResult=fail(ErrorCodeEnums.InternalServerError.getCode(),filterChinese(e.getMessage()), messages);}else{
                errorResult=fail(ErrorCodeEnums.InternalServerError.getCode(),filterChinese("内部错误:A04"), messages);}}//4.对象解析异常if(einstanceofIllegalStateException){if(StringUtils.isEmpty(e.getMessage())){
                errorResult=fail(ErrorCodeEnums.InternalServerError.getCode(),filterChinese("内部错误:A03"), messages);}else{
                errorResult=fail(ErrorCodeEnums.InternalServerError.getCode(),filterChinese(e.getMessage()), messages);}}//5.强制转换异常if(einstanceofClassCastException){
            errorResult=fail(ErrorCodeEnums.InternalServerError.getCode(),"内部错误:A01", messages);}//6.空指针if(einstanceofNullPointerException){
            errorResult=fail(ErrorCodeEnums.InternalServerError.getCode(),"内部错误:A02", messages);}//7.处理自定义异常if(einstanceofAlertException){
            errorResult=fail(((AlertException) e).getErrorCode(), e.getMessage(), messages);
            logger.error("提示信息:{}", e.getMessage());}elseif(einstanceofAlertAndReloadException){
            errorResult=fail(((AlertAndReloadException) e).getErrorCode(), e.getMessage(), messages);
            logger.error("提示信息:{}", e.getMessage());}elseif(einstanceofServiceException){
            ServiceException serviceException=(ServiceException) e;//统一异常码
            Integer errorCode= serviceException.getErrorCode();
            String errorInfo= serviceException.getErrorInfo();if((!StringUtils.isEmpty(errorCode))&& errorCode== UNAUTHORIZED){
                httpStatus= Response.Status.UNAUTHORIZED;}if(StringUtils.isEmpty(errorCode)){
                errorCode= Response.Status.INTERNAL_SERVER_ERROR.getStatusCode();}if(httpStatus== Response.Status.UNAUTHORIZED){
                logger.debug("发生自定义异常,异常码:{}, 异常说明:{}", errorCode, errorInfo);}else{
                logger.error("发生自定义异常,异常码:{}, 异常说明:{}", errorCode, errorInfo, e);}//错误提示信息
            String reason= StringUtils.hasText(errorInfo)? errorInfo: ErrorCodeEnums.getByCode(errorCode);
            errorResult=fail(errorCode, StringUtils.hasText(reason)? reason: errorInfo, messages);}//8.其他异常if(errorResult== null){
            logger.error("发生异常: ", e);
            String msg= e.getMessage();if(StringUtils.isEmpty(msg)|| msg.length()> FILTER_SIZE){
                msg="服务器开小差了,请重试";}if(!StringUtils.isEmpty(active)&&(active.equals(DEV)|| active.equals(TEST))){
                errorResult=fail(ErrorCodeEnums.InternalServerError.getCode(), msg,getExceptionDetail(e), messages);}else{
                errorResult=fail(ErrorCodeEnums.InternalServerError.getCode(), msg, messages);}}return Response.status(httpStatus).entity(errorResult.toString()).type(JSON_UTF_8).build();}private Result<String>fail(int code, String msg){returnnewResult<>(code, msg);}private Result<String>fail(int code, String msg, List<String> messages){returnnewResult<>(code, msg, null, messages);}private Result<String>fail(int code, String msg, String errMessage){returnnewResult<>(code, msg, errMessage);}private Result<String>fail(int code, String msg, String errMessage, List<String> messages){returnnewResult<>(code, msg, errMessage, messages);}/**
     * 过滤掉 非中文字符。
     */privatestatic StringfilterChinese(final String str){if(!StringUtils.hasText(str)){return str;}if(str.length()<= FILTER_SIZE){return str;}//只保留前60个中文字符
        String filterStr= str.replaceAll("[^(\\u4e00-\\u9fa5)]","").replaceAll("\\(","").replaceAll("\\)","").replaceAll("\\.","").replaceAll("\\_","");if(StringUtils.isEmpty(filterStr)){//过滤后为空,则原样显示前60个字符return str.substring(0, FILTER_SIZE);}elseif(filterStr.length()> FILTER_SIZE){return filterStr.substring(0, FILTER_SIZE);}elseif(filterStr.length()<15){return str;}else{return filterStr;}}/**
     * 获取异常详细信息
     */publicstatic StringgetExceptionDetail(Exception ex){
        String ret= null;try{
            ByteArrayOutputStream out=newByteArrayOutputStream();
            PrintStream pout=newPrintStream(out);
            ex.printStackTrace(pout);
            ret=newString(out.toByteArray());
            pout.close();
            out.close();}catch(Exception e){}return ret;}}

统一异常码枚举类 ErrorCodeEnums.java:

/**
 * 全局统一的异常码。
 */publicenum ErrorCodeEnums{// ----------------- http标准状态码---------------------------------Unauthorized(401,"请先登录"),Forbidden(403,"您无权限访问此页面,请联系管理员或重新登录"),NotFound(404,"抱歉,您访问的页面不存在"),InternalServerError(500,"服务器内部错误"),//----------------- 自定义异常码 -----------------------------------ServerErrorRetry(666,"服务器内部错误,前端页面尝试再次调用接口直到返回666"),ParamsError(1001,"参数校验失败"),TokenExpired(1002,"登录token已过期"),AlertMsg(1003,"页面提示信息"),AlertMsgAndReload(1004,"提示信息,并自动刷新页面"),;/**
     * 异常码。
     */public Integer code;/**
     * 异常描述。
     */public String reason;ErrorCodeEnums(Integer code, String reason){this.code= code;this.reason= reason;}publicstatic StringgetByCode(Integer code){for(ErrorCodeEnums item: ErrorCodeEnums.values()){if(code.equals(item.getCode())){return item.reason;}}return"";}public IntegergetCode(){return code;}public StringgetReason(){return reason;}}

application.yml文件配置

在application.yml文件中配置启用

dubbo:application:name: xxx-service# 优雅停机超时时间shutwait:15000provider:#负载均衡loadbalance: roundrobintimeout:10000filter: xxxFilterconsumer:#关闭启动时检查依赖服务check:falsefilter: xxxFilterprotocols:dubbo:name: dubboport:-1server: nettyextension: xxx.CustomExceptionMapperrest:name: restport:80server: tomcatcontextpath: xxx-serviceextension: xxx.CustomExceptionMapper
  • 作者:machunlin~
  • 原文链接:https://blog.csdn.net/machunlin2010/article/details/117132275
    更新时间:2022-06-22 12:29:47