此博客用于个人学习,来源于ssm框架的书籍,对知识点进行一个整理。
4.1 异常处理:
4.1.1 异常处理思路:
Controller调用service,service调用dao,异常都是向上抛出的,最终有DispatcherServlet找异常处理器进行异常的处理。
4.1.2 实现步骤:
- 编写异常类和错误页面。
/**
* 自定义异常
* @author 黑马程序员
* @Company http://www.ithiema.com
* @Version 1.0
*/
public class CustomException extends Exception {
private String message;
public CustomException(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
jsp页面:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>执行失败</title>
</head>
<body>
执行失败!
${message }
</body>
</html>
- 自定义异常处理器。
/**
* 自定义异常处理器
* @author 黑马程序员
* @Company http://www.ithiema.com
* @Version 1.0
*/
public class CustomExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request,HttpServletResponse response, Object handler, Exception ex) {
ex.printStackTrace();
CustomException customException = null;
//如果抛出的是系统自定义异常则直接转换
if(ex instanceof CustomException){
customException = (CustomException)ex; }else{
//如果抛出的不是系统自定义异常则重新构造一个系统错误异常。
customException = new CustomException("系统错误,请与系统管理 员联系!");
}
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("message", customException.getMessage());
modelAndView.setViewName("error");
return modelAndView;
}
}
- 配置异常处理器。
<!-- 配置自定义异常处理器 -->
<bean id="handlerExceptionResolver" class="com.itheima.exception.CustomExceptionResolver"/>
4.2 SpringMVC 中的拦截器:
4.2.1 拦截器的作用:
Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。它和过滤器是有几分相似,但是也有区别:
- 过滤器是 servlet 规范中的一部分,任何 java web 工程都可以使用;拦截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能用。
- 过滤器在 url-pattern 中配置了/*之后,可以对所有要访问的资源拦截;拦截器它是只会拦截访问的控制器方法,如果访问的是 jsp,html,css,image 或者 js 是不会进行拦截的。
它也是 AOP 思想的具体应用。我们要想自定义拦截器, 要求必须实现:HandlerInterceptor 接口。
4.2.2 自定义拦截器的步骤:
第一步:编写一个普通类实现 HandlerInterceptor 接口。
/**
* 自定义拦截器
* @author 黑马程序员
* @Company http://www.ithiema.com
* @Version 1.0
*/
public class HandlerInterceptorDemo1 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle 拦截器拦截了");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {
System.out.println("postHandle 方法执行了");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion 方法执行了");
}
}
第二步:配置拦截器。
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean id="handlerInterceptorDemo1" class="com.itheima.web.interceptor.HandlerInterceptorDemo1"></bean>
</mvc:interceptor>
</mvc:interceptors>
4.2.3 拦截器的细节:
首先,我们来看一个概念,放行——如果有下一个拦截器就执行下一个,如果该拦截器处于拦截器链的最后一个,则执行控制器中的方法。
拦截器中方法的说明:
- preHandle:
- 如何调用: 按拦截器定义顺序调用。
- 何时调用:只要配置了都会调用。
- 有什么用:如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回 true;如果程序员决定不需要再调用其他的组件去处理请求,则返回 false。
- postHandle:
- 如何调用:按拦截器定义逆序调用。
- 何时调用:在拦截器链内所有拦截器返成功调用。
- 有什么用:在业务处理器处理完请求后,但是 DispatcherServlet 向客户端返回响应前被调用,在该方法中对用户请求 request 进行处理。
- afterCompletion:
- 如何调用:按拦截器定义逆序调用。
- 何时调用:只有 preHandle 返回 true 才调用。
- 有什么用:在 DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。
4.2.4 拦截器的作用路径:
作用路径可以通过在配置文件中配置。
<!-- 配置拦截器的作用范围 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" /><!-- 用于指定对拦截的 url -->
<mvc:exclude-mapping path=""/><!-- 用于指定排除的 url-->
<bean id="handlerInterceptorDemo1" class="com.itheima.web.interceptor.HandlerInterceptorDemo1"></bean>
</mvc:interceptor>
</mvc:interceptors>
4.2.5 多个拦截器的执行顺序:
4.2.6 正常流程测试:
配置文件:
<!-- 配置拦截器的作用范围 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" /><!-- 用于指定对拦截的 url -->
<bean id="handlerInterceptorDemo1" class="com.itheima.web.interceptor.HandlerInterceptorDemo1"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**" />
<bean id="handlerInterceptorDemo2" class="com.itheima.web.interceptor.HandlerInterceptorDemo2"></bean>
</mvc:interceptor>
</mvc:interceptors>
拦截器 1 的代码:
/**
* 自定义拦截器
* @author 黑马程序员
* @Company http://www.ithiema.com
* @Version 1.0
*/
public class HandlerInterceptorDemo1 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截器 1:preHandle 拦截器拦截了");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {
System.out.println("拦截器 1:postHandle 方法执行了");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("拦截器 1:afterCompletion 方法执行了");
}
}
拦截器 2 的代码:
/**
* 自定义拦截器
* @author 黑马程序员
* @Company http://www.ithiema.com
* @Version 1.0
*/
public class HandlerInterceptorDemo2 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {
System.out.println("拦截器 2:preHandle 拦截器拦截了");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {
System.out.println("拦截器 2:postHandle 方法执行了");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {
System.out.println("拦截器 2:afterCompletion 方法执行了");
}
}
从结果可以看出符合上面的流程框图。
4.2.7 拦截器的简单案例(验证用户是否登录):
实现思路:
- 有一个登录页面,需要写一个 controller 访问页面 2、登录页面有一提交表单的动作。需要在 controller 中处理。
- 1、判断用户名密码是否正确。
2、如果正确 向 session 中写入用户信息。
3、返回登录成功。 - 拦截用户请求,判断用户是否登录。
1、如果用户已经登录。放行。
2、如果用户未登录,跳转到登录页面。
控制器代码:
//登录页面
@RequestMapping("/login")
public String login(Model model)throws Exception{
return "login";
}
//登录提交
//userid:用户账号,pwd:密码
@RequestMapping("/loginsubmit")
public String loginsubmit(HttpSession session,String userid,String pwd)throws Exception{
//向 session 记录用户身份信息
session.setAttribute("activeUser", userid);
return "redirect:/main.jsp";
}
//退出
@RequestMapping("/logout")
public String logout(HttpSession session)throws Exception{
//session 过期
session.invalidate();
return "redirect:index.jsp";
}
拦截器代码:
public class LoginInterceptor implements HandlerInterceptor{
@Override
Public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {
//如果是登录页面则放行
if(request.getRequestURI().indexOf("login.action")>=0){
return true;
}
HttpSession session = request.getSession();
//如果用户已登录也放行
if(session.getAttribute("user")!=null){
return true;
}
//用户没有登录挑战到登录页面
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return false;
}
}