SpringMVC的@ControllerAdvice有三种使用场景:
- 全局异常处理
- 全局数据绑定
- 全局数据预处理
本文介绍在springboot中直接使用@ControllerAdvice定义全局异常
注:页面使用thymeleaf模板引擎
项目目录结构如下:
在exceptions中定义异常类文件
- 使用@ControllerAdvice注解,代表为全局异常类,项目中任意方法发生异常均会执行此方法
- @ExceptionHandler定义具体的异常类型,若定义为NullPointerException空指针异常,则发生ArrayIndexOutOfBoundsException数据越界异常时,不会执行此方法
- @Controller + @ResponseBody 组合,则方法既可返回model页面,也可返回json格式等数据
- GlobalExceptionHandler方法中定义判断是否为ajax请求时发生的异常,若是,则以json格式返回异常信息;若不是,则返回异常报错页面
package com.test.springboot.exceptions;
import com.test.springboot.constant.ViewConstant;
import com.test.springboot.utils.ResResultJson;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
/**
* 融合ajax请求和普通请求 返回异常的方式
* ajax请求 返回页面异常数据
* 普通请求,返回前端错误页面,错误页面上可展示异常数据
*/
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseBody
public Object errHandler(HttpServletRequest request, Exception e) throws Exception {
if (isAjax(request)) return ResResultJson.err(e.getMessage());
else {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("exception", e.getMessage()).addObject("url", request.getRequestURL()).setViewName(ViewConstant.ERROR_VIEW);
return modelAndView;
}
}
/**
* 判断是否为ajax请求
* @param request
* @return
*/
public static boolean isAjax(HttpServletRequest request) {
return (request.getHeader("X-Requested-With") != null && "XMLHttpRequest".equals(request.getHeader("X-Requested-With").toString()));
}
}
ResResultJson文件如下:
定义json返回的编码code,提示信息message,返回数据data
其中返回编码code可自主定义
package com.test.springboot.utils;
/**
*自定义返回数据结构
*/
public class ResResultJson {
private String code;
private String message;
private Object data;
public ResResultJson(String code,String message,Object data){
this.code = code;
this.message = message;
this.data = data;
}
public ResResultJson(String code,String message){
this.code = code;
this.message = message;
}
public static ResResultJson err(String code,String message){
return new ResResultJson(code,message);
}
public static ResResultJson err(String message){
return new ResResultJson("500",message);
}
public static ResResultJson reqOk(String code,String message,Object data){
return new ResResultJson(code,message,data);
}
public static ResResultJson reqOk(Object data){
return new ResResultJson("200","成功",data);
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
异常页面error.html定义:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>全局异常捕获测试</title>
</head>
<body>
<h1>系统出现异常:</h1>
<div th:text = "${url}">异常地址</div>
<div th:text = "${exception}">异常信息</div>
</body>
</html>
在java中 1/0 会出现java.lang.ArithmeticException: / by zero 异常,方法验证如下:
1. Web请求异常
启动项目,访问http://localhost:8081/springboot/err
方法中throw new异常,同样会走全局异常捕获,error.html中会展示抛出的异常信息
@RequestMapping("/err")
public void testException() throws BussinessException {
int num = 1 / 0;
// throw new BussinessException("发生异常了");
System.out.println(num);
}
error.html页面展示如下:
2. Ajax请求异常
第一步:get请求返回html页面
@RequestMapping(value = "/getJsonValue",method = RequestMethod.GET)
public Object getJsonValue(Model model,HttpServletRequest request){
JsonTest jsonTest = new JsonTest();
jsonTest.setName("Test99");
model.addAttribute(jsonTest);
return ViewConstant.REQ_VIEW;
}
第二步:html页面中定义ajax请求
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>发起请求</title>
<script th:src = "@{/js/jquery.min.js}"></script>
</head>
<body>
<input th:name = "personName" th:id="personName" th:value="${jsonTest.getName()}">
<button th:onclick="'javascript:reqAjax();'" th:type="button" th:text="提交"></button>
</body>
<script type="text/javascript" th:inline="javascript">
/*<![CDATA[*/
function reqAjax() {
// var name="00";
var name=$('#personName').val();
$.ajax({
//ajax请求不成功jquery.js报错,url要写为全量的url(包括yml配置文件中的servlet.context-path路径)
url:'/springboot/ajaxErr',
type:'POST',
async:false,
data:{name:name},
success:function (data) {
if(data.code == "200" && data.message == "成功"){
alert("请求成功,请求数据:"+data.data['sex']+","+data.data['name']);
}else {
alert("请求失败,失败信息:"+data.message);
}
}
});
}
/*]]>*/
</script>
</html>
第三步:ajax请求后台方法,方法中设置异常
@RequestMapping(value = "/ajaxErr",method = RequestMethod.POST)
@ResponseBody
public ResResultJson testAjaxException(HttpServletRequest request, HttpServletResponse response){
String name = request.getParameter("name");
System.out.println("name:"+name);
Map map = new HashMap();
if (name.isEmpty()) {
int num = 1 / 0;
}
map.put("name",name);
map.put("sex","男");
return ResResultJson.reqOk(map);
}
第四步:页面验证
personName有值,即前端传值时,点击【提交】,ajax请求成功,返回成功信息
personName无值,即ajax中name传值空,点击【提交】,程序有异常,则走全局异常捕获,返回异常信息