三 后台环境搭建
10. 异常映射
支点: git checkout -b 3.10.0_exception_mapping
10.1 目标和思路
10.1.1 目标
- 使用异常映射机制将整个项目的异常和错误提示进行统一管理
10.1.2 思路
10.1.3 注意: SpringMVC 提供了 基于 XML 和 基于注解两种异常映射机制
10.2 基于 XML 的异常映射
10.2.1 XML 配置
<!-- 配置基于 XML 的异常映射 -->
<bean id="simpleMappingExceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 配置异常类型和具体视图页面的对应关系 -->
<property name="exceptionMappings">
<props>
<!-- key 属性指定异常类全名 -->
<!-- 标签体中写对应的视图 (这个值会拼前后缀得到具体路径) -->
<prop key="java.lang.Exception">system-error</prop>
</props>
</property>
</bean>
10.2.2 新建错误页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>错误</title>
</head>
<body>
<h1>出错了</h1>
<!-- 从请求域取出 Exception 对象, 再近一步访问 message 属性就能够显示错误信息 -->
${requestScope.exception.message}
</body>
</html>
10.2.3 测试
- TestHandler.java
@RequestMapping("/test/ssm.html")
public String testSsm(ModelMap modelMap) {
List<Admin> adminList = adminService.getAll();
System.out.println(adminList);
modelMap.addAttribute("adminList", adminList);
modelMap.addAttribute("adminList2", adminList);
modelMap.addAttribute("adminList4", adminList);
System.out.println(10 / 0);
return "/target";
}
- 显示错误信息
10.3 判断请求类型的工具方法
10.3.1 CrowdUtil.java
package com.atguigu.crowd.util;
import javax.servlet.http.HttpServletRequest;
public class CrowdUtil {
/**
* 判断当前请求是否为 Ajax 请求
*
* @param request 请求对象
* @return true: 当前请求是 Ajax 请求
* false: 当前请求不是 Ajax 请求
*/
public static boolean judgeRequestType(HttpServletRequest request) {
// 1. 获取请求消息头
String acceptHeader = request.getHeader("Accept");
String xRequestedWith = request.getHeader("X-Requested-With");
// 2. 判断
return (acceptHeader != null && acceptHeader.contains("application/json"))
||
("XMLHttpRequest".equals(xRequestedWith));
}
}
-
测试 判断请求类型的工具方法 - TestHandler.java
-
- judgeResult: true
@ResponseBody
@RequestMapping("/send/compose/object2.json")
public ResultEntity<Student> testReceiveComposeObject2(@RequestBody Student student, HttpServletRequest request) {
boolean judgeResult = CrowdUtil.judgeRequestType(request);
Logger logger = LoggerFactory.getLogger(TestHandler.class);
logger.info("judgeResult: " + judgeResult);
logger.info(student.toString());
// 将"查询"到的 Student 对象封装到 ResultEntity 中返回
return ResultEntity.successWithData(student);
}
-
- judgeResult: false
@RequestMapping("/test/ssm.html")
public String testSsm(ModelMap modelMap, HttpServletRequest request) {
boolean judgeResult = CrowdUtil.judgeRequestType(request);
Logger logger = LoggerFactory.getLogger(TestHandler.class);
logger.info("judgeResult: " + judgeResult);
List<Admin> adminList = adminService.getAll();
System.out.println(adminList);
modelMap.addAttribute("adminList", adminList);
modelMap.addAttribute("adminList2", adminList);
modelMap.addAttribute("adminList4", adminList);
// System.out.println(10 / 0);
return "/target";
}
10.3.2 pom.xml 需要的依赖
atcrowdfunding05-common-util
<dependencies>
<!-- 引入 Servlet 容器中相关依赖 -->
<!-- https://mvnrepository.com/artifact/javax.servlet/servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
</dependencies>
10.4 基于注解的异常映射
10.4.1 CrowdUtil.java
package com.atguigu.crowd.mvc.config;
import com.atguigu.crowd.util.CrowdUtil;
import com.atguigu.crowd.util.ResultEntity;
import com.google.gson.Gson;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @ControllerAdvice: 表示当前类是一个基于注解的异常处理器类
*/
@ControllerAdvice
public class CrowdExceptionResolver {
@ExceptionHandler(value = ArithmeticException.class)
public ModelAndView resolveNullPointerException(
ArithmeticException exception,
HttpServletRequest request,
HttpServletResponse response
) throws IOException {
String viewName = "system-error";
return commonExceptionResolver(viewName, exception, request, response);
}
/**
* @ExceptionHandler: 将一个具体的异常类型和一个方法关联起来
*
* @param exception
* @param request
* @param response
* @return
* @throws IOException
*/
@ExceptionHandler(value = NullPointerException.class)
public ModelAndView resolveNullPointerException(
NullPointerException exception,
HttpServletRequest request,
HttpServletResponse response
) throws IOException {
String viewName = "system-error";
return commonExceptionResolver(viewName, exception, request, response);
}
public static ModelAndView commonExceptionResolver(
// 跳转的视图
String viewName,
// 实例捕获到的异常类型
Exception exception,
// 当前请求对象
HttpServletRequest request,
HttpServletResponse response
) throws IOException {
// 1. 判断请求类型
boolean judgeRequestType = CrowdUtil.judgeRequestType(request);
// 2. 如果是 Ajax 请求
if (judgeRequestType) {
// 3. 创建 ResultEntity 对象
ResultEntity<Object> resultEntity = ResultEntity.failed(exception.getMessage());
// 4. 创建 Gson 对象
Gson gson = new Gson();
// 5. 将 ResultEntity 对象转换为 JSON 对象
String json = gson.toJson(resultEntity);
// 6. 将 JSON 字符串作为响应体返回
response.getWriter().write(json);
// 7. 由于上面已经通过原生的 response 对象返回了响应, 所以不提供 ModelAndView 对象
return null;
}
// 8. 如果不是 Ajax 请求则创建 ModelAndView 对象
ModelAndView modelAndView = new ModelAndView();
// 9. 将 Exception 对象存入模型
modelAndView.addObject("exception", exception);
// 10. 设置对应的视图名称
modelAndView.setViewName(viewName);
// 11. 返回 ModelAndView 对象
return modelAndView;
}
}
- 测试非Ajax请求 - TestHandler.java
@RequestMapping("/test/ssm.html")
public String testSsm(ModelMap modelMap, HttpServletRequest request) {
boolean judgeResult = CrowdUtil.judgeRequestType(request);
Logger logger = LoggerFactory.getLogger(TestHandler.class);
logger.info("judgeResult: " + judgeResult);
List<Admin> adminList = adminService.getAll();
System.out.println(adminList);
modelMap.addAttribute("adminList", adminList);
modelMap.addAttribute("adminList2", adminList);
modelMap.addAttribute("adminList4", adminList);
// System.out.println(10 / 0);
String a = null;
System.out.println(a.length());
return "/target";
}
- 测试Ajax请求 - TestHandler.java
@ResponseBody
@RequestMapping("/send/compose/object2.json")
public ResultEntity<Student> testReceiveComposeObject2(@RequestBody Student student, HttpServletRequest request) {
String a = null;
System.out.println(a.length());
boolean judgeResult = CrowdUtil.judgeRequestType(request);
Logger logger = LoggerFactory.getLogger(TestHandler.class);
logger.info("judgeResult: " + judgeResult);
logger.info(student.toString());
// 将"查询"到的 Student 对象封装到 ResultEntity 中返回
return ResultEntity.successWithData(student);
}