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>