0
点赞
收藏
分享

微信扫一扫

Springboot全局异常处理

彩虹_bd07 2022-03-11 阅读 72

Springboot全局异常处理

一、Spring Boot默认的异常处理机制

默认情况下,springboot提供了两种相应方式:① 浏览器请求头为Accept: text/html,springboot会默认相应一个html文档内容,为“Whitelabel Error Page”;② 会返回Json格式字符串信息。
原理:

/** 
 * springboot 默认提供了程序出错的结果映射路径/error,
 * 这个/error请求会在BasicErrorController中处理。
 * 其内部是通过判断请求头中的Accept的内容是否为text/html来区分请求是来自
 * 客户端浏览器(浏览器通常默认自动发送请求头内容Accept:text/html)
 * 还是客户端接口的调用,以此来决定返回页面视图还是 JSON 消息内容。
 *  public static final String TEXT_HTML_VALUE = "text/html";
 */
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {

	@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
	public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
		HttpStatus status = getStatus(request);
		Map<String, Object> model = Collections
				.unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML)));
		response.setStatus(status.value());
		ModelAndView modelAndView = resolveErrorView(request, response, status, model);
		return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
	}

	@RequestMapping
	public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
		HttpStatus status = getStatus(request);
		if (status == HttpStatus.NO_CONTENT) {
			return new ResponseEntity<>(status);
		}
		Map<String, Object> body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL));
		return new ResponseEntity<>(body, status);
	}

二、如何自定义错误页面

三、通过@ControllerAdvice注解来处理异常

两种情况:
局部异常处理 @Controller + @ExceptionHandler
全局异常处理 @ControllerAdvice + @ExceptionHandler

1. 局部异常处理 @Controller + @ExceptionHandler

局部异常主要用到的是@ExceptionHandler注解,此注解注解到类的方法上,当此注解里定义的异常抛出时,此方法会被执行。如果@ExceptionHandler所在的类是@Controller,则此方法只作用在此类。如果@ExceptionHandler所在的类带有@ControllerAdvice注解,则此方法会作用在全局。

@Controller
public class BaseErrorController extends  AbstractController{ 
    private Logger logger = LoggerFactory.getLogger(this.getClass()); 

    @RequestMapping(value="/ex") 
    @ResponseBody 
    public String error(){ 
        int i=5/0; 
        return "ex"; 
  } 

    //局部异常处理 
    @ExceptionHandler(Exception.class) 
    @ResponseBody 
    public String exHandler(Exception e){ 
      // 判断发生异常的类型是除0异常则做出响应 
      if(e instanceof ArithmeticException){ 
          return "发生了除0异常"; 
      } 
      // 未知的异常做出响应 
      return "发生了未知异常"; 
    }
} 

该注解用于标注处理方法处理那些特定的异常。被该注解标注的方法可以有以下任意顺序的参数类型:

  • Throwable、Exception 等异常对象;

  • ServletRequest、HttpServletRequest、ServletResponse、HttpServletResponse;

  • HttpSession 等会话对象;

  • org.springframework.web.context.request.WebRequest;

  • java.util.Locale;

  • java.io.InputStream、java.io.Reader;

  • java.io.OutputStream、java.io.Writer;

  • org.springframework.ui.Model;

并且被该注解标注的方法可以有以下的返回值类型可选:

  • ModelAndView;

  • org.springframework.ui.Model;

  • java.util.Map;

  • org.springframework.web.servlet.View;

  • @ResponseBody 注解标注的任意对象;

  • HttpEntity<?> or ResponseEntity<?>;

  • void;

以上罗列的不完全,更加详细的信息可参考:Spring ExceptionHandler。

2. 全局异常处理 @ControllerAdvice + @ExceptionHandler

在spring 3.2中,新增了@ControllerAdvice 注解,可以用于定义@ExceptionHandler、@InitBinder、@ModelAttribute,并应用到所有@RequestMapping中。

简单的说,进入Controller层的错误才会由@ControllerAdvice处理,拦截器抛出的错误以及访问错误地址的情况@ControllerAdvice处理不了,由SpringBoot默认的异常处理机制处理。

四、自定义

1. 自定义返回结果

package com.kuen.language.common.to;

import org.springframework.http.HttpStatus;

import java.util.HashMap;
import java.util.Map;

/**
 * @program: Language
 * @description: 返回结果对象
 * @author: Kuen.Hou
 * @create: 2022-03-05 09:59
 **/
public class ResultObject extends HashMap<String, Object> {
    private static final long serialVersionUID = -2227292363737068440L;

    public ResultObject() {
        put("code", 0);
    }


    @Override
    public ResultObject put(String key, Object value) {
        super.put(key, value);
        return this;
    }

    public ResultObject data(Object value) {
        super.put("data", value);
        return this;
    }

    public static ResultObject error() {
        return error(HttpStatus.INTERNAL_SERVER_ERROR.value(), "未知异常,请联系管理员");
    }

    public static ResultObject error(String msg) {
        return error(HttpStatus.INTERNAL_SERVER_ERROR.value(), msg);
    }

    public static ResultObject error(int code, String msg) {
        ResultObject r = new ResultObject();
        r.put("code", code);
        r.put("msg", msg);
        return r;
    }

    public static ResultObject ok() {
        return new ResultObject();
    }

    public static ResultObject ok(String msg) {
        ResultObject r = new ResultObject();
        r.put("msg", msg);
        return r;
    }

    public static ResultObject ok(Map<String, Object> map) {
        ResultObject r = new ResultObject();
        r.putAll(map);
        return r;
    }

}

2. 自定义异常

package com.kuen.language.multiLanguage.exception;

/**
 * @program: Language
 * @description: 自定义异常
 * @author: Kuen.Hou
 * @create: 2022-03-05 10:31
 **/
public class CustomException extends RuntimeException {
    private static final long serialVersionUID = -173110604484282583L;

    private final String message;
    private int code = 500;

    public CustomException(String message) {
        super(message);
        this.message = message;
    }

    public CustomException(String message, Throwable e) {
        super(message, e);
        this.message = message;
    }

    public CustomException(String message, int code) {
        super(message);
        this.message = message;
        this.code = code;
    }

    public CustomException(String message, int code, Throwable e) {
        super(message, e);
        this.message = message;
        this.code = code;
    }
}

3. 自定义全局异常处理器

package com.kuen.language.common.handler;

import com.kuen.language.common.to.ResultObject;
import com.kuen.language.multiLanguage.exception.CustomException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;

/**
 * @program: Language
 * @description: 自定义异常处理器
 * @author: Kuen.Hou
 * @create: 2022-03-05 10:56
 **/
@RestControllerAdvice
@Slf4j
public class CustomExceptionHandler {

    /**
     * 应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器
     * @param binder
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {
//        System.out.println("请求有参数才进来");
    }

    /**
     * 把值绑定到Model中,使全局@RequestMapping可以获取到该值
     * @param model
     */
    @ModelAttribute
    public void addAttributes(Model model) {
//        model.addAttribute("author", "Kuen.Hou");
    }

    @ExceptionHandler(Exception.class)
    public Object handleException(Exception e, HttpServletRequest req){
        ResultObject r = new ResultObject();
        //业务异常
        if(e instanceof CustomException){
            r.put("code", ((CustomException) e).getCode());
            r.put("msg", e.getMessage());
        }else{//系统异常
            r.put("code","500");
            r.put("msg","未知异常,请联系管理员");
        }

        //使用HttpServletRequest中的header检测请求是否为ajax, 如果是ajax则返回json, 如果为非ajax则返回view(即ModelAndView)
        String contentTypeHeader = req.getHeader("Content-Type");
        String acceptHeader = req.getHeader("Accept");
        String xRequestedWith = req.getHeader("X-Requested-With");
        if ((contentTypeHeader != null && contentTypeHeader.contains("application/json"))
                || (acceptHeader != null && acceptHeader.contains("application/json"))
                || "XMLHttpRequest".equalsIgnoreCase(xRequestedWith)) {
            return r;
        } else {
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.addObject("msg", e.getMessage());
            modelAndView.addObject("url", req.getRequestURL());
            modelAndView.addObject("stackTrace", e.getStackTrace());
            modelAndView.setViewName("error");
            return modelAndView;
        }
    }
}
举报

相关推荐

0 条评论