springboot全局异常处理

使用@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注解时如下:

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值