使用@ControllerAdvice注解和@ExceptionHandler注解来实现
我在基础上加了一些补充增加了自定义HandleException注解,自定义Api注解等
注意:不能自己trycatch异常,否则就不会被全局异常处理捕获到
当Exception子类被对应的子类异常处理捕获到后,会去相应的子类异常处理。找不到相应子类处理的异常就会到Exception异常处理。
具体做法:
1、自定义一个HandleException注解(注解在接口方法上,目的时当异常发生时,返回前端的错误信息)
import java.lang.annotation.*;
/**
* 统一处理异常
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HandleException {
/**
* 异常捕获后提示语
* @return
*/
String value() default "操作错误";
}
2、自定义一个Api注解(当前端api接口和服务端接口返回的json格式不同,有异常被捕获时通过有无此注解,判断返回的格式)
import java.lang.annotation.*;
/**
* 用于统一处理异常后,api则返回对应的格式(和后台不同)
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Api {
}
3、自定义一个MaxtechException异常(用于service层上抛异常,附带e.getMessage()错误信息时使用。)
package *;
public class MaxtechException extends RuntimeException {
private static final long serialVersionUID = 344013094194665717L;
private int level = 0;
public MaxtechException(String error) {
super(error);
}
public MaxtechException(int level, String error) {
super(error);
this.level = level;
}
public MaxtechException(String error, Throwable cause) {
super(error, cause);
}
public MaxtechException(int level, String error, Throwable cause) {
super(error, cause);
this.level = level;
}
public int getLevel() {
return this.level;
}
}
4、定义一个异常处理类
package *;
import *;
@RestControllerAdvice
public class MaxtechControllerAdvice {
protected final Logger log = LoggerFactory.getLogger(this.getClass());
/**
* 统一处理MaxtechException异常
* @param request
* @param response
* @param e
* @return
*/
@ExceptionHandler(MaxtechException.class)
@ResponseStatus(HttpStatus.OK)
public Object processMaxtechException(HttpServletRequest request,HttpServletResponse response, MaxtechException e) throws Exception {
HandlerMethod handler = getHandlerMethod(request);
//如果有Api注解,则是前端需返回jsonResponse
if(handler.getBean()!=null&&handler.getBean().getClass().getAnnotation(Api.class)!= null){
JsonResponse jsonResponse = new JsonResponse();
jsonResponse.getR().put(MindConst.CODE_STR, MindConst.FAILURE);
jsonResponse.getR().put(MindConst.DESC_STR, e.getMessage());
return jsonResponse;
}else{//后端则返回handleMsg串
return "{\"handleMsg\":{\"status\":0,\"message\":\"" + ParamUtil.toJsString(e.getMessage()) + "\"}}";
}
}
/**
* 统一处理Exception异常
* @param request
* @param response
* @param e
* @return
*/
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.OK)
public Object processException(HttpServletRequest request,HttpServletResponse response, Exception e) throws Exception {
HandlerMethod handler = getHandlerMethod(request);
String errorMessage="内部错误("+e.getMessage()+")!";
//判断是否有HandleException注解,有的话取注解中字段
if(handler.getMethod()!=null&&handler.getMethod().getAnnotation(HandleException.class)!=null){
errorMessage=handler.getMethod().getAnnotation(HandleException.class).value();
}
log.error(errorMessage,e);
//如果有Api注解,则是前端需返回jsonResponse
if(handler.getBean()!=null&&handler.getBean().getClass().getAnnotation(Api.class)!= null){
JsonResponse jsonResponse = new JsonResponse();
jsonResponse.getR().put(MindConst.CODE_STR, MindConst.FAILURE);
jsonResponse.getR().put(MindConst.DESC_STR, errorMessage);
return jsonResponse;
}else{//后端则返回handleMsg串
return "{\"handleMsg\":{\"status\":0,\"message\":\"" + ParamUtil.toJsString(errorMessage) + "\"}}";
}
}
/**
* 通过request对应的Controller处理类
* @param request
* @return
* @throws Exception
*/
private HandlerMethod getHandlerMethod(HttpServletRequest request) throws Exception {
//通过ApplicationContext上下文(spring)找到RequestMappingHandlerMapping这个bean
RequestMappingHandlerMapping handlerMapping = ApplicationContextUtil.getBean(RequestMappingHandlerMapping.class);
//RequestMappingHandlerMapping是对应url和处理类方法的一个类
HandlerExecutionChain handlerChain = handlerMapping.getHandler(request);
//通过处理链找到对应的HandlerMethod类
return (HandlerMethod) handlerChain.getHandler();
}
}
ApplicationContextUtil代码
package *;
import *;
@Component
public class ApplicationContextUtil implements ApplicationContextAware{
private static ApplicationContext applicationContext;
/**
* 实现ApplicationContextAware接口的回调方法,设置上下文环境
*
* @param applicationContext spring上下文对象
* @throws BeansException 抛出spring异常
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextUtil.applicationContext = applicationContext;
}
/**
* @return ApplicationContext
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* 获取对象
*
* @param name spring配置文件中配置的bean名或注解的名称
* @return 一个以所给名字注册的bean的实例
* @throws BeansException 抛出spring异常
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) throws BeansException {
return (T) applicationContext.getBean(name);
}
/**
* 获取类型为requiredType的对象
*
* @param clazz 需要获取的bean的类型
* @return 该类型的一个在ioc容器中的bean
* @throws BeansException 抛出spring异常
*/
public static <T> T getBean(Class<T> clazz) throws BeansException {
return applicationContext.getBean(clazz);
}
/**
* 如果ioc容器中包含一个与所给名称匹配的bean定义,则返回true否则返回false
*
* @param name ioc容器中注册的bean名称
* @return 存在返回true否则返回false
*/
public static boolean containsBean(String name) {
return applicationContext.containsBean(name);
}
}
测试结果:
我模拟了抛出了MaxtechException和IndexOutOfBoundsException异常情况
1、当抛出了MaxtechException,有Api注解时如下:
2、当抛出了MaxtechException,没有Api注解时如下:
3、当抛出了IndexOutOfBoundsException,有Api注解时如下:
4、当抛出了IndexOutOfBoundsException,没有Api注解时如下: