统一异常处理
异常定义
自定义业务异常需继承 org.maculaframework.boot.core.exception.MaculaException 异常基类,定义如下
public abstract class MaculaException extends I18nException {
private static final long serialVersionUID = 1L;
public MaculaException(String message) {
super(message);
}
public MaculaException(String message, Throwable cause) {
super(message, cause);
}
public MaculaException(String message, Object[] args) {
super(message, args);
}
public MaculaException(String message, Object[] args, Throwable cause) {
super(message, args, cause);
}
public String getFullStackMessage() {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw, true);
this.printStackTrace(pw);
return sw.getBuffer().toString();
}
}
XxxBizException异常示例
public class XxxBizException extends MaculaException {
private static final long serialVersionUID = 1L;
public XxxBizException(String message, Throwable cause) {
super(message, cause);
}
public XxxBizException(String message, Object[] args) {
super(message, args);
}
public XxxBizException(String message, Object[] args, Throwable cause) {
super(message, args, cause);
}
}
重要!!!
如无必要,不需要自己try异常,交由框架统一拦截处理,除非是你主动抛出业务类异常,或者捕获异常后有相应处理逻辑。特别提醒,如果在事务中,Service方法中并不能捕获到数据库类型的异常,因为事务结束后才会提交数据库,这个时候抛出的异常Service方法是捕获不到的
异常处理方式
框架内部自动异常处理: service 层异常处理 controller 层异常处理 orderedExceptionNegotiateFilter 过滤器异常处理
Service层异常处理
框架内部基于Spring AOP 特性, 用 @Service 注解构建切入点 , 针对所有service层横切 统一拦截处理service层抛出的异常。 Macula提供了 ErrorMessage 注解, 在service层 用于自定义方法级别异常信息输出, service层异常处理时,将异常转换为MaculaException 向上抛出
@AfterThrowing(pointcut = "service()", throwing = "ex")
public void doAfterThrowing(JoinPoint joinPoint, Throwable ex) {
if (!(ex instanceof MaculaException)) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
try {
method = joinPoint.getTarget().getClass().getMethod(method.getName(), method.getParameterTypes());
} catch (Exception e) {}
ErrorMessage errorMessage = method.getAnnotation(ErrorMessage.class);
String message = errorMessage == null ? "org.macula.boot.core.exception.ServiceException" : errorMessage.value();
log.error(message, ex);
throw translate(message, ex);
}
}
Controller 层异常处理
框架内部基于spring mvc 的 @ControllerAdvice 和 @ExceptionHandler 注解组合实现全局 controller层异常拦截处理, 并统一用 Response 类封装异常信息返回
@ControllerAdvice
public class ControllerExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseBody
public Response handlerCoreException(Exception ex, HttpServletRequest req) {
if (ex instanceof MaculaException) {
return new Response((MaculaException)ex);
}
if (ex instanceof IllegalArgumentException) {
return new Response(new MaculaArgumentException((IllegalArgumentException)ex));
}
if (ex.getClass().equals("org.apache.dubbo.rpc.RpcException")) {
return new Response(new ServiceException(MaculaConstants.EXCEPTION_CODE_RPC, "org.apache.dubbo.rpc.RpcException", ex));
}
ServiceException sex = new ServiceException(MaculaConstants.EXCEPTION_CODE_UNKNOWN, "org.maculaframework.boot.core.exception.ServiceException", ex);
return new Response(sex);
}
}
Response****响应示例
{
"success":false,
"errCode":"500",
"errDesc":"获取数据失败",
"exceptionStack":null,
"redirection":null,
"validateErrors":null
}
ErrorMessage注解
在你的Service方法中添加@ErrorMessage注解可以定制该方法出现异常时返回的错误信息,否则会统一返回“服务层异常”的消息提示
使用示例
@ErrorMessage(value = "根据集群name查找失败 ")
public GatewayClusterEntity findByClusterName(String name) {
return gatewayClusterRepository.findByClusterName(name);
}
系统级异常处理
框架内部 基于Spring 框架的 OncePerRequestFilter 构建 OrderedExceptionNegotiateFilter 过滤器, 过滤每一个请求, 并根据请求特性,重新包装返回的异常信息,Controller层如果没有拦截到异常,会全部由 OrderedExceptionNegotiateFilter 接管处理 所有异常会统一用Response类封装,此时客户端收到的是HTTP 500的响应
Response****响应示例
{
"success":false,
"errCode":"500",
"errDesc":null,
"exceptionStack":null,
"redirection":null,
"validateErrors":null
}