写点什么

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

用户头像
try catch
关注
发布于: 2021 年 05 月 21 日

项目使用过的是 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;
/** * 全局统一的异常处理器。 */public class CustomExceptionMapper implements ExceptionMapper<Exception> { private final static Logger logger = LogManager.getLogger(CustomExceptionMapper.class);
private static final String TEXT_PLAIN_UTF_8 = "text/plain; charset=UTF-8"; private static final String JSON_UTF_8 = "application/json;charset=UTF-8"; private static final int FILTER_SIZE = 60; private static final String DEV = "dev"; private static final String TEST = "test";
private static final int UNAUTHORIZED = 401;
public static String active;
public static void setActive(String at) { active = at; }
@Override public Response toResponse(Exception e) { if (e instanceof DefaultOptionsMethodException || (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 = new ArrayList<>(); 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 (e instanceof NotFoundException) { logger.error("发生404异常: ", e); errorResult = fail(404, "404 not found!"); httpStatus = Response.Status.NOT_FOUND; }
//2.dubbo远程调用异常 if (e instanceof RpcException) { errorResult = fail(ErrorCodeEnums.InternalServerError.getCode(), "服务重新连线中,请稍后", messages); httpStatus = Response.Status.UNAUTHORIZED; }
//3.非法参数异常 if (e instanceof IllegalArgumentException) { 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 (e instanceof IllegalStateException) { 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 (e instanceof ClassCastException) { errorResult = fail(ErrorCodeEnums.InternalServerError.getCode(), "内部错误:A01", messages); }
//6.空指针 if (e instanceof NullPointerException) { errorResult = fail(ErrorCodeEnums.InternalServerError.getCode(), "内部错误:A02", messages); }
//7.处理自定义异常 if (e instanceof AlertException) { errorResult = fail(((AlertException) e).getErrorCode(), e.getMessage(), messages); logger.error("提示信息:{}", e.getMessage()); } else if (e instanceof AlertAndReloadException) { errorResult = fail(((AlertAndReloadException) e).getErrorCode(), e.getMessage(), messages); logger.error("提示信息:{}", e.getMessage());
} else if (e instanceof ServiceException) { 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) { return new Result<>(code, msg); }
private Result<String> fail(int code, String msg, List<String> messages) { return new Result<>(code, msg, null, messages); }
private Result<String> fail(int code, String msg, String errMessage) { return new Result<>(code, msg, errMessage); }
private Result<String> fail(int code, String msg, String errMessage, List<String> messages) { return new Result<>(code, msg, errMessage, messages); }
/** * 过滤掉 非中文字符。 */ private static String filterChinese(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); } else if (filterStr.length() > FILTER_SIZE) { return filterStr.substring(0, FILTER_SIZE); } else if (filterStr.length() < 15) { return str; } else { return filterStr; } }
/** * 获取异常详细信息 */ public static String getExceptionDetail(Exception ex) { String ret = null; try { ByteArrayOutputStream out = new ByteArrayOutputStream(); PrintStream pout = new PrintStream(out); ex.printStackTrace(pout); ret = new String(out.toByteArray()); pout.close(); out.close(); } catch (Exception e) { } return ret; }
}
复制代码

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

/** * 全局统一的异常码。 */public enum 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; }
public static String getByCode(Integer code) { for (ErrorCodeEnums item : ErrorCodeEnums.values()) { if (code.equals(item.getCode())) { return item.reason; } } return ""; }
public Integer getCode() { return code; }
public String getReason() { return reason; }}
复制代码

application.yml 文件配置

在 application.yml 文件中配置启用


dubbo:  application:    name: xxx-service    # 优雅停机超时时间    shutwait: 15000  provider:    #负载均衡    loadbalance: roundrobin    timeout: 10000    filter: xxxFilter  consumer: #关闭启动时检查依赖服务    check: false    filter: xxxFilter  protocols:    dubbo:      name: dubbo      port: -1      server: netty      extension: xxx.CustomExceptionMapper    rest:      name: rest      port: 80      server: tomcat      contextpath: xxx-service      extension: xxx.CustomExceptionMapper
复制代码


发布于: 2021 年 05 月 21 日阅读数: 20
用户头像

try catch

关注

还未添加个人签名 2012.07.23 加入

还未添加个人简介

评论

发布
暂无评论
apache dubbo 自定义全局统一的异常处理器