- 定义错误页面
- 使用HTTP状态码
- 在Controller中处理异常
- 全局统一异常处理
在用户访问页面时,常常会出现页面无法访问、访问路径错误等一系列问题,我们需要根据错误异常类型给用户相应的提示。
第一种最简单的方法:定义错误页面
在出现错误时,springboot会跳转到自己的错误页面。
?我们可以自己定义错误页面,在templates目录下新建error目录——》在error下新建404.HTML、403.HTML与500.HTML。springboot会自动在项目中寻找404,403等以错误编号命名的页面,并在发生错误时跳转。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>login</title>
<link rel="stylesheet" href="../static/css/bootstrap.css" type="text/css" >
</head>
<body>
`<div class="container" style="max-width: 600px;margin-top: 100px;">
<div class="jumbotron">
<h2>404</h2>
<p>对不起,你访问的页面不存在</p>
</div>
</div>
<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<script type="text/javascript" src="https://fastly.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js" ></script>
<script type="text/javascript" src="../static/js/bootstrap.js" ></script>
</body>
</html>
这个时候如果再发生404错误,会跳转到如图页面。
第二种,使用HTTP状态码。
新建Java类BookNotFoundException,使他继承RuntimeException。
@ResponseStatus()这个注释规定了这个类将会处理哪一类异常,如果书写为@ResponseStatus(HttpStatus.NOT_FOUND),那么它会处理404错误。
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(HttpStatus.NOT_FOUND)
public class BookNotFoundException extends RuntimeException{
public BookNotFoundException() {
}
public BookNotFoundException(String message) {
super(message);
}
public BookNotFoundException(String message, Throwable cause) {
super(message, cause);
}
}
使用方法:在Service内书写一个异常抛出。
@Service
public class bookServiceImpl{
@Autowired
private BookRepository bookRepository;
//查询一条信息
public book find(long id){
book book=bookRepository.findById(id).orElse(null);
if(book==null){
throw new BookNotFoundException("书单信息不存在");
}
return book;
}
}
第三种,在Controller内处理异常。
@Controller
@RequestMapping("/books")
public class bookController {
private final Logger logger= LoggerFactory.getLogger(bookController.class);
@Autowired
private bookServiceImpl bookService;
/*异常处理,只能处理bookController内里的异常*/
@ExceptionHandler({Exception.class})
public ModelAndView handlerException(HttpServletRequest request,Exception e) throws Exception {
logger.error("Request URL : {} ,Exception : {}",request.getRequestURL(),e.getMessage());
if(AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class)!=null){//如果指定异常/指定状态码,就把异常抛出,让springboot框架来处理
throw e;
}
ModelAndView mav=new ModelAndView();
mav.addObject("url",request.getRequestURL());
mav.addObject("exception",e);
mav.setViewName("error/error");//跳转到error页面
return mav;
}
}
新建error页面,同样放在error目录下。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>error</title>
<link rel="stylesheet" href="../static/css/bootstrap.css" type="text/css" >
</head>
<body>
`<div class="container" style="max-width: 600px;margin-top: 100px;">
<div class="jumbotron">
<h2>Error</h2>
<p>对不起,服务异常,请联系管理员</p>
<p>请求路径: <code th:text="${url}"></code></p>
<p>错误信息: <code th:text="${exception.message}"></code></p>
</div>
<!--堆栈信息让工作人员通过查看源码查看,不显示在页面上-->
<div th:utext="'<!--'" th:remove="tag"></div>
<div th:utext="'Failed Request URL: '+${url}" th:remove="tag"></div>
<div th:utext="'Exception message: '+${exception.message}" th:remove="tag"></div>
<ul th:remove="tag">
<li th:each="st: ${exception.stackTrace}" th:remove="tag">
<span th:utext="${st}" th:remove="tag"></span>
</li>
</ul>
<div th:utext="'-->'" th:remove="tag"></div>
</div>
<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<script type="text/javascript" src="https://fastly.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js" ></script>
<script type="text/javascript" src="../static/js/bootstrap.js" ></script>
</body>
</html>
这个时候如果bookController内发生错误,就会自动跳转到error页面。
查看源码,可以看到详细的错误异常。
?
?但是在Controller内书写的Exception只能处理Controller内的异常,如果每个Controller类里都要写一遍,就会造成代码冗余。
我们用全局统一异常处理来解决。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
@ControllerAdvice //所有的Controller内发生异常都会经过这里
public class ControllerExceptionHandler {
private final Logger logger= LoggerFactory.getLogger(ControllerExceptionHandler.class);
@ExceptionHandler({Exception.class})
public ModelAndView handlerException(HttpServletRequest request, Exception e) throws Exception {
logger.error("Request URL : {} ,Exception : {}",request.getRequestURL(),e.getMessage());
if(AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class)!=null){//如果指定异常/指定状态码,就把异常抛出,让springboot框架来处理
throw e;
}
ModelAndView mav=new ModelAndView();
mav.addObject("url",request.getRequestURL());
mav.addObject("exception",e);
mav.setViewName("error/error");//跳转到error页面
return mav;
}
}
|