作用:将捕获到的异常类型和具体页面对应起来。在捕获到对应类型的异常后,跳转到对应页面。
配置:XML方式(只能返回页面,很难兼容Ajax请求)
配置:Annotation方式(兼容两种请求)
1、后端:异常处理器
@ControllerAdvice
public class CrowdFundingExceptionResolever {
@ExceptionHandler(value=Exception.class)
public ModelAndView catchException(Exception exception) {
ModelAndView mav = new ModelAndView();
//存错误信息
mav.addObject("exception", exception);
//出错去往的页面 system-error.jsp
mav.setViewName("system-error");
return mav;
}
}
mav.addObject(“exception”, exception):存的是错误信息。
mav.setViewName(“system-error”):存的是错误以后去往的页面
如果存储的错误信息不重写的话,错误页面显示的就是具体的错误信息,客户感官不好,
2、前端:错误信息页面
<script type="text/javascript" src="jquery/jquery-2.1.1.min.js"></script>
<script type="text/javascript">
$(function(){
$("#bakcBtn").click(function(){
//返回到前一个页面
window.history.back();
});
});
</script>
<!-- 取错误信息 -->
<h1>${requestScope.exception.message }</h1>
<button id="bakcBtn" class="btn btn-lg btn-success btn-block">后退</button>
3、错误测试
故意新增一个存在的信息,我们可以指定报错的具体信息,可以自定义一个提示。
//新增
@RequestMapping("/admin/save")
public String saveAdmin(Admin admin) {
try {
adminService.saveAdmin(admin);
} catch (Exception e) {
e.printStackTrace();
//针对DuplicateKeyException这个异常,提示用户已存在,
if(e instanceof DuplicateKeyException) {
throw new RuntimeException("用户已存在!");
}
}
return "redirect:/admin/query/for/search.html";
}
4、异常映射兼容异步请求
目前这个异常处理机制,只能处理页面,对ajax的错误是无效的,ajax错误的话,只会在控制台报错,而不会在页面显示。所以ajax如果报错了,导致页面不能正常显示,不友好,怎么解决呢?
4.1 分辨异步请求和同步请求
4.1.1 pom依赖
在异常处理中判断它是同步请求还是异步请求,需要用到HttpServletRequest
,导入依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>
4.1.2 判断是否异步请求工具类
/**
* 判断请求是否为异步请求
*
* @param request
* @return
*/
public boolean checkAsyncRequest(HttpServletRequest request) {
//获取相应请消息头
String accept = request.getHeader("Accept");
String xRequested = request.getHeader("X-Requested-With");
//判断请求消息头是否包含json的特征
if (stringEffective(accept) && accept.contains("application/json")
|| stringEffective(xRequested) && xRequested.contains("XMLHttpRequest")) {
return true;
}
return false;
}
/**
* 判断字符串是否有效
*
* @param source 待验证字符串
* @return true表示有效,false表示无效
*/
public boolean stringEffective(String source) {
return source != null && source.length() > 0;
}
4.2 修改异常处理器
4.2.1 pom依赖
这里需要转换JSON,导入JSON包,这里用的是google的
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
4.2.2 JSON响应格式的实体类
这里用了lombok,注释是lombok帮助生成了get和set方法,以及全参和无参构造函数,没有lombok就自己写get和set方法,以及全参和无参构造函数
/**
* ajax请求的响应格式
*
* @author Administrator
*
*/
@AllArgsConstructor
@NoArgsConstructor
@Data
public class ResultEntity<T> {
public static final String SUCCESS = "SUCCESS";
public static final String FAILED = "FAILED";
public static final String NO_MESSAGE = "NO_MESSAGE";
public static final String NO_DATA = "NO_DATA";
// 方便返回成功结果(不携带查询结果情况)
public static ResultEntity<String> successWithoutData() {
return new ResultEntity<String>(SUCCESS, NO_MESSAGE, NO_DATA);
}
// 方便返回成功结果(携带查询结果情况)
public static <E> ResultEntity<E> successWithData(E data) {
return new ResultEntity<E>(SUCCESS, NO_MESSAGE, data);
}
// 方便返回失败结果
public static <E> ResultEntity<E> failed(E data, String message) {
return new ResultEntity<E>(FAILED, message, data);
}
private String result;
private String message;
private T data;
}
4.2.3 改进后的异常处理器
@ExceptionHandler(value = Exception.class)
public ModelAndView catchException(Exception exception,HttpServletRequest request,HttpServletResponse response) throws IOException {
//判断请求是否为异步
boolean checkAsyncRequestResult = CrowdFundingUtils.checkAsyncRequest(request);
//如果是异步请求
if(checkAsyncRequestResult) {
//创建ResultEntity对象,exception.getMessage()就是报错的异常信息,你也可以自己写,
//ResultEntity<String> resultEntity =ResultEntity.failed(ResultEntity.NO_DATA, "发生错误了");
ResultEntity<String> resultEntity =ResultEntity.failed(ResultEntity.NO_DATA, exception.getMessage());
//ResultEntity对象转为JSON对象
Gson gson = new Gson();
String json = gson.toJson(resultEntity);
//将JSON作为相应数据返回给浏览器
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(json);
return null;
}
ModelAndView mav=new ModelAndView();
mav.addObject("exception",exception);
mav.setViewName("system-error");
return mav;
}
这是用layer写的,就是这个样式,没有layer的话,可以直接alert查看报错信息