SpringBoot 全局异常处理
1、编写一个异常显示视图
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" content="text/html; charset=UTF-8" http-equiv="Content-Type">
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="/css/bootstrap-theme.min.css">
<link rel="stylesheet" href="/css/coummity.css">
<script src="/js/jquery-3.4.1.min.js"></script>
<script src="/js/bootstrap.js"></script>
</head>
<body>
<div class="jumbotron">
<h1>出错啦!!!!</h1>
<p th:text="${message}"></p>
<p><a class="btn btn-primary btn-lg" href="#" role="button">回到主页</a></p>
</div>
</body>
</html>
- 页面名称为error.html,放在templates文件夹下
- 使用了Bootstrap的组件
- 使用了thymeleaf模板引擎
- ${message}是后端传过来的值
2、编写一个全局异常处理器
@ControllerAdvice
public class CustomizeExceptionHandler {
@ExceptionHandler(Exception.class)
ModelAndView handle(Throwable e, Model model) {
if (e instanceof CustomizeException){
model.addAttribute("message",e.getMessage());
}else {
model.addAttribute("message","服务器冒烟了,要不你访问别的吧!");
}
return new ModelAndView("error");
}
}
- @ControllerAdvice注解
- @ExceptionHandler注解
- 将错误信息message发送到前端页面
- CustomizeException是自定义的异常类
- e instanceof CustomizeException 是判断当前的异常是不是 CustomizeException 异常
- 返回error视图
3、自定义异常类
public class CustomizeException extends RuntimeException{
private String message;
public CustomizeException(ICustomizeErrorCode errorCode) {
this.message = errorCode.getMessage();
}
@Override
public String getMessage() {
return message;
}
}
- 它要继承RuntimeException
- 重写getMessage方法
- 添加一个构造方法,方法的参数是一个接口 (后面讲为什么要这么做)
4、编写一个错误消息接口
public interface ICustomizeErrorCode {
String getMessage();
}
5、编写实现错误消息接口的枚举类
public enum CustomizeErrorCode implements ICustomizeErrorCode{
/**
* 问题不存在
*/
QUESTION_NOT_FOUND("你找的问题不存在了,要不换个试试?");
@Override
public String getMessage() {
return message;
}
private String message;
CustomizeErrorCode(String message) {
this.message = message;
}
}
6、业务代码
public QuestionDTO getById(Integer id) {
//通过id查询问题信息
Question question = questionMapper.selectByPrimaryKey(id);
//抛出自定义异常
if (question == null) {
throw new CustomizeException(CustomizeErrorCode.QUESTION_NOT_FOUND);
}
//获取用户信息
User user = userMapper.selectByPrimaryKey(question.getCreator());
QuestionDTO questionDTO = new QuestionDTO();
BeanUtils.copyProperties(question, questionDTO);
questionDTO.setUser(user);
return questionDTO;
}
- 这里抛出了一个自定义的异常,并且异常信息为之前定义的枚举类中的属性。写枚举类的作用就在于,在业务代码去填写异常信息的时候不用一直手写,如
throw new CustomizeException("你找的问题不存在了,要不换个试试?");
- 那为什么要定义一个错误消息接口呢?
当只有一种枚举类的时候或许还不用定义这个接口,但是实际应用中,我们不可能把所有的异常信息都写在一个类里。多个枚举类去实现这个接口,我们去给自定义异常类传参数是只要是实现这个自定义接口的类就可以了,这样代码会变得整洁。
7、扩展
- 以上的配置,只有当我们在地址栏访问 localhost:8080/question/222时,数据库不存在id为222的数据时返回给前端页面的一个错误,那当我们访问一个项目里完全不存在的页面时,怎么将错误信息返回到前端呢?
- 我们可以做一个控制层来解决这个问题
package com.gyy.community.controller;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
/**
* @author GYY
* @date 2020/1/8 21:32
*/
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class CustomizeErrorController implements ErrorController {
@Override
public String getErrorPath() {
return "error";
}
@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView errorHtml(HttpServletRequest request, Model model) {
HttpStatus status = getStatus(request);
if (status.is4xxClientError()){
model.addAttribute("message","你这个请求错了吧,要不然换个姿势?");
}
if (status.is5xxServerError()){
model.addAttribute("message","服务器冒烟了,要不然稍后再试?");
}
return new ModelAndView("error");
}
private HttpStatus getStatus(HttpServletRequest request) {
Integer statusCode = (Integer)request.getAttribute("javax.servlet.error.status_code");
if (statusCode == null) {
return HttpStatus.INTERNAL_SERVER_ERROR;
} else {
try {
return HttpStatus.valueOf(statusCode);
} catch (Exception var4) {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
}
}
}
在我们访问一个项目根本不存在的地址时,springboot会为我们返回/error请求,通过这个/error请求,我们可以写一个controller将他处理一下,把错误信息放到model中,返回到前端页面。