springboot 2.x處理404、500等異常


404錯誤

404錯誤是不經過Controller的,所以使用@ControllerAdvice或@RestControllerAdvice無法獲取到404錯誤

springboot2處理404錯誤的兩種方式

第一種:直接配置

#出現錯誤時, 直接拋出異常
spring.mvc.throw-exception-if-no-handler-found=true

這種方式不太適用實際開發,比如和swagger集成時,訪問/swagger-ui.html會出現404異常

第二種:繼承ErrorController來處理錯誤

import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Controller
public class MyErrorController implements ErrorController {

    @RequestMapping("/error")
    public String handleError(HttpServletRequest request){
        //獲取statusCode:401,404,500
        Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
        if(statusCode == 500){
            return "/error/500";
        }else if(statusCode == 404){
            //對應的是/error/404.html、/error/404.jsp等,文件位於/templates下面
            return "/error/404";
        }else if(statusCode == 403){
            return "/403";
        }else{
            return "/500";
        }

    }


    @Override
    public String getErrorPath() {
        return "/error";
    }
}

import com.bettn.common.util.Result;
import com.bettn.common.util.WebUtils;
import org.apache.shiro.ShiroException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 全局異常捕獲處理
 */
@RestControllerAdvice
public class ExceptionControllerAdvice {
    private static final Logger logger= LoggerFactory.getLogger(ExceptionControllerAdvice.class);



    // 捕捉shiro的異常
    @ExceptionHandler(ShiroException.class)
    public Result handle401() {
        return new Result(401,"您沒有權限訪問!",null);
    }


    // 捕捉其他所有異常
    @ExceptionHandler(Exception.class)
    public Object globalException(HttpServletRequest request, HandlerMethod handlerMethod, Throwable ex) {
        if(WebUtils.isAjax(handlerMethod)){
            return new Result(getStatus(request).value(), "訪問出錯,無法訪問: " + ex.getMessage(), null);
        }else {
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.setViewName("/error/500"); //這里需要在templates文件夾下新建一個/error/500.html文件用作錯誤頁面
            modelAndView.addObject("errorMsg",ex.getMessage());
            return modelAndView;
        }

    }

    /**
     * 判斷是否是Ajax請求
     *
     * @param request
     * @return
     */
    public boolean isAjax(HttpServletRequest request) {
        return (request.getHeader("X-Requested-With") != null &&
                "XMLHttpRequest".equals(request.getHeader("X-Requested-With").toString()));
    }
//    @ExceptionHandler(Exception.class)
//    public Result globalException(HttpServletRequest request, Throwable ex) {
//        return new Result(getStatus(request).value(),"訪問出錯,無法訪問: " + ex.getMessage(),null);
//    }


    /**
     * 獲取響應狀態碼
     * @param request
     * @return
     */
    private HttpStatus getStatus(HttpServletRequest request) {
        Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
        if (statusCode == null) {
            return HttpStatus.INTERNAL_SERVER_ERROR;
        }
        return HttpStatus.valueOf(statusCode);
    }

    /**
     * 捕捉404異常,這個方法只在配置
     * spring.mvc.throw-exception-if-no-handler-found=true來后起作用
     * 
     */
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(NoHandlerFoundException.class)
    public Result handle(HttpServletRequest request,NoHandlerFoundException e) {
        System.out.println(12);
        return new Result(404,"沒有【"+request.getMethod()+"】"+request.getRequestURI()+"方法可以訪問",null);
    }
}

這個異常類與ExceptionControllerAdvice連用,ExceptionControllerAdvice類除了不能處理404異常以外,其他異常都可以處理,其中
globalException異常這個方法會捕獲500錯誤,導致MyErrorController無法捕獲到500錯誤,從而跳轉到500頁面,也就是說MyErrorController在這個項目中
只能捕獲404異常

500異常捕獲

500異常分為ajax和直接跳轉500頁面

具體的異常捕獲,代碼如何下:


// 捕捉其他所有異常
@ExceptionHandler(Exception.class)
public Object globalException(HttpServletRequest request, HandlerMethod handlerMethod, Throwable ex) {
    if(WebUtils.isAjax(handlerMethod)){
        return new Result(getStatus(request).value(), "訪問出錯,無法訪問: " + ex.getMessage(), null);
    }else {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("/error/500"); //這里需要在templates文件夾下新建一個/error/500.html文件用作錯誤頁面
        modelAndView.addObject("errorMsg",ex.getMessage());
        return modelAndView;
    }

}
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
public class WebUtils extends org.springframework.web.util.WebUtils {
	/**
	 * 判斷是否ajax請求
	 * spring ajax 返回含有 ResponseBody 或者 RestController注解
	 * @param handlerMethod HandlerMethod
	 * @return 是否ajax請求
	 */
	public static boolean isAjax(HandlerMethod handlerMethod) {
		ResponseBody responseBody = handlerMethod.getMethodAnnotation(ResponseBody.class);
		if (null != responseBody) {
			return true;
		}
		// 獲取類上面的Annotation,可能包含組合注解,故采用spring的工具類
		Class<?> beanType = handlerMethod.getBeanType();
		responseBody = AnnotationUtils.getAnnotation(beanType, ResponseBody.class);
		if (null != responseBody) {
			return true;
		}
		return false;
	}

	public static String getCookieValue(HttpServletRequest request, String cookieName) {
		Cookie cookie=getCookie(request, cookieName);
		return cookie==null?null:cookie.getValue();
	}

	public static void removeCookie(HttpServletResponse response, String cookieName) {
		setCookie(response, cookieName, null, 0);
		
	}

	public static void setCookie(HttpServletResponse response, String cookieName, String cookieValue,
			int defaultMaxAge) {
		Cookie cookie=new Cookie(cookieName,cookieValue);
		cookie.setHttpOnly(true);
		cookie.setPath("/");
		cookie.setMaxAge(defaultMaxAge);
		response.addCookie(cookie);
	}

}

TIP

404、500頁面需要放在/templates下,且確認配置了視圖,如jsp、thymeleaf等,否則也會出現找不到頁面,例如集成thymeleaf

依賴

<!-- thymeleaf模板引擎和shiro框架的整合,這個是與shiro集成的,一般不整合shiro就不需要這個依賴 -->
<dependency>
    <groupId>com.github.theborakompanioni</groupId>
    <artifactId>thymeleaf-extras-shiro</artifactId>
    <version>${thymeleaf.extras.shiro.version}</version>
</dependency>
<!-- SpringBoot集成thymeleaf模板 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

配置

spring:
  # 模板引擎
  thymeleaf:
    mode: HTML5
    encoding: utf-8
    # 禁用緩存
    cache: false

404、500頁面地址(目錄結構)

src/main/resources/templates/error/404.html
src/main/resources/templates/error/500.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>500</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>

<!--
直接使用${el}無法解析出el的值
${errorMsg}
-->

<h3>糟糕! 服務器出錯啦~~(>_<)~~</h3>
<div>
    異常信息如下:<br/>
    <p th:text="${errorMsg}"></p>
</div>
</body>
</html>

參考:https://www.jianshu.com/p/8d41243e7fba


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM