持续学习&持续更新中…
守破离
【Java从零到架构师第③季】【33】SpringMVC-异常处理
以前是如何处理异常的?
使用try-catch
弊端:每个Controller下的每个方法(@RequestMapping)都需要写try-catch语句。
@RequestMapping("/demo1")
@ResponseBody
public String demo1(String birthday) {
try {
System.out.println("demo1");
Date birth = new SimpleDateFormat("yyyy年MM月dd日").parse(birthday);
System.out.println(birth);
} catch (Exception e) {
e.printStackTrace();
// 处理异常!
}
return "success!";
}
使用throws+配置500页面
用途:这种方法,适合那些服务器内部出现严重的错误,用于警告用户他的行为不当。
handle_500.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<div>出异常啦!</div>
<div>
<%
StringBuilder sb = new StringBuilder();
Throwable throwable = exception;
do {
sb.append(throwable.getClass())
.append("——")
.append(throwable.getMessage())
.append("<br>");
throwable = throwable.getCause();
} while (throwable != null);
%>
<text><%=sb.toString()%></text>
</div>
<div>
<%-- 根据异常做出相应的处理 --%>
<p><%=exception%></p>
</div>
</body>
</html>
web.xml:
<error-page>
<error-code>500</error-code>
<location>/WEB-INF/handle_500.jsp</location>
</error-page>
编写代码时不用管异常:
@RequestMapping("/demo2")
@ResponseBody // 检查型异常
public String demo2(String birthday) throws Exception {
System.out.println("demo2");
Date birth = new SimpleDateFormat("yyyy/MM/dd").parse(birthday);
System.out.println(birth);
// 运行时异常:
// System.out.println(1 / 0);
// throw new RuntimeException("demo1");
return "success!";
}
异常处理
异常处理—SimpleMappingExceptionResolver
缺点:为异常处理页面能够传递的东西(信息)有限(
<property name="exceptionAttribute" value="ex"/>
)
统一设置异常处理页面:
applicationContext.xml:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionAttribute" value="ex"/>
<property name="defaultErrorView" value="/WEB-INF/error/default.jsp"/>
</bean>
ExceptionController1:
@Controller
@RequestMapping("/exception1")
public class ExceptionController1 {
@RequestMapping("/demo1")
@ResponseBody
public String demo1() {
throw new DateTimeException("demo1");
}
@RequestMapping("/demo2")
@ResponseBody
public String demo2() throws Exception {
throw new IOException("demo2");
}
// ...
}
JSP页面使用异常:
<!-- 不用在page指令中加上 isErrorPage="true" -->
<body>
<p>异常:${ex}</p>
<p>异常信息:${ex.message}</p>
</body>
当想要特殊处理某个异常时:
applicationContext.xml:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.ArrayIndexOutOfBoundsException">/WEB-INF/error/runtime.jsp</prop>
<prop key="java.io.IOException">/WEB-INF/error/io.jsp</prop>
</props>
</property>
<property name="exceptionAttribute" value="ex"/>
<property name="defaultErrorView" value="/WEB-INF/error/default.jsp"/>
</bean>
异常处理—自定义异常解析器
@Component
public class MyExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
// 可以使用request、response对象
// 可以通过handler知道是哪个Controller的哪个方法出现了异常
// 拿到具体的Controller和具体的方法后,就可以做出相应的处理
HandlerMethod handlerMethod = (HandlerMethod) handler;
System.out.println(handlerMethod.getBean());
System.out.println(handlerMethod.getMethod());
ModelAndView mv = new ModelAndView();
// 自己可以根据异常的类型决定去哪个异常处理页面
// 对某种类型的异常做特殊处理
// if (ex instanceof ArrayIndexOutOfBoundsException) {
// mv.setViewName("xxx");
// } else if (ex instanceof IOException) {
// mv.setViewName("xxx");
// }else if(ex instanceof xxx) {
// // ...
// }else {
// mv.setViewName("default.jsp");
// }
mv.setViewName("/WEB-INF/error/default.jsp");
// 可以给异常处理页面传递任何信息
// mv.addObject(attributeName,attributeValue);
mv.addObject("ex", ex);
mv.addObject("userinfo", "name:lp, age:10,...");
return mv;
}
}
异常处理—@ExceptionHandler
缺点:需要为每一个Controller都写带有@ExceptionHandler的异常处理方法
@Controller
@RequestMapping("/ex2")
public class ExceptionController2 {
@RequestMapping("/demo1")
@ResponseBody
public String demo1() {
throw new DateTimeException("demo1");
}
@RequestMapping("/demo2")
@ResponseBody
public String demo2() throws Exception {
throw new IOException("demo2");
}
@RequestMapping("/demo3")
@ResponseBody
public String demo3() {
throw new ArithmeticException("demo3");
}
// 需要特殊处理的异常
// @ExceptionHandler(DateTimeException.class)
// public void exceptionHandlerSpecial1(Exception ex) {
// System.out.println(ex);
// }
//
// @ExceptionHandler(ArithmeticException.class)
// public ModelAndView exceptionHandlerSpecial2(Exception ex) {
// ModelAndView mv = new ModelAndView();
// mv.addObject("ex", ex);
// mv.setViewName("/WEB-INF/error/runtime.jsp");
// System.out.println(ex);
// return mv;
// }
// 需要特殊处理的异常
@ExceptionHandler({DateTimeException.class, ArithmeticException.class})
public void exceptionHandlerSpecial(Exception ex) {
System.out.println(ex);
}
// 其余所有的异常
@ExceptionHandler
public ModelAndView exceptionHandlerOther(Exception ex) {
ModelAndView mv = new ModelAndView();
mv.addObject("ex", ex);
mv.setViewName("/WEB-INF/error/default.jsp");
return mv;
}
}
异常处理—@ExceptionHandler+@ControllerAdvice
@ControllerAdvice
public class MyExceptionHandler {
// 默认处理所有的异常
@ExceptionHandler
public ModelAndView exceptionHandlerOther(Exception ex) {
ModelAndView mv = new ModelAndView();
mv.addObject("ex", ex);
mv.setViewName("/WEB-INF/error/default.jsp");
return mv;
}
// 需要特殊处理的异常
@ExceptionHandler({DateTimeException.class, ArithmeticException.class})
@ResponseBody
public String exceptionHandlerSpecial(Exception ex) {
System.out.println(ex);
return "出现了异常:" + ex;
}
}
参考
小码哥-李明杰: Java从0到架构师③进阶互联网架构师.
本文完,感谢您的关注支持!