4.SpringMVC核心技术
Posted 小马Mark
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了4.SpringMVC核心技术相关的知识,希望对你有一定的参考价值。
请求重定向和转发
当处理器对请求处理完毕后,向其它资源进行跳转时,有两种跳转方式:请求转发与重定向。
根据所要跳转的资源类型,又可分为两类:跳转到页面与跳转到其它处理器。
**注意:**对于请求转发的页面,可以是WEB-INF中页面;而重定向的页面,是不能为WEB-INF中页的。因为重定向相当于用户再次发出一次请求,而用户是不能直接访问 WEB-INF 中资源的。
SpringMVC 框架把原来 Servlet 中的请求转发和重定向操作进行了封装。现在可以使用简单的方式实现转发和重定向。
forward:
表示转发,实现request.getRequestDispatcher("xx.jsp").forward()
redirect:
表示重定向,实现response.sendRedirect("xxx.jsp")
请求转发
处理器方法返回 ModelAndView 时,需在 setViewName()指定的视图前添加 forward:视图完整路径
,
@RequestMapping(value = "/some.do")
public ModelAndView doSome(String name, Integer age) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("myName",name);
modelAndView.addObject("myAge",age);
modelAndView.setViewName("forward:/WEB-INF/view/show.jsp"); // forward:完整uri
return modelAndView;
}
此时的视图不再与视图解析器一同工作,这样可以在配置了解析器时指定不同位置的视图。
-
视图页面必须写出相对于项目根的路径。
-
forward 操作不需要视图解析器。
处理器方法返回 String,在视图路径前面加入 forward: 视图完整路径
。
@RequestMapping(value = "/some.do")
public String doSome(String name, Integer age, HttpServletRequest request) {
System.out.println("name = " + name + ", age = " + age);
request.setAttribute("myName", name);
request.setAttribute("myAge", age);
// 框架对视图执行的是forward转发操作
return "forward:/test.jsp";
}
请求重定向
在处理器方法返回的视图字符串的前面添加 redirect:
,则可实现重定向跳转。(与请求转发语法相似)
重定向是不能访问/WEB-INF/目录下的资源的,因为两次请求都是从客户端发送的,是不能直接访问的。
@RequestMapping(value = "/other.do")
public ModelAndView doOther(String name, Integer age) {
System.out.println("name = " + name + ", age = " + age);
// name = zxx, age = 123
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("myName",name); // 将你设置的名称作为参数名,放入到了url中
modelAndView.addObject("myAge",age);
modelAndView.setViewName("redirect:/test.jsp");
return modelAndView;
}
**注意:**重定向与转发有点不一样,重定向是两次请求,所以是两个不同的request域,所以框架就让在重定向时将你想要设置到Request域中的参数和值,重新放到了第二次请求的get请求的url中,传递给了另一个页面。
http://localhost:8080/springmvc06/test.jsp?myName=zxx&myAge=123
异常处理
两个注解:
-
@ExceptionHandler
:统一处理某一类异常,从而能够减少代码重复率和复杂度- 属性:value = 异常类的class类型
-
@ControllerAdvice
:异常集中处理,更好的使业务逻辑与异常处理剥离开;其实对Controller层进行拦截
补充:@ResponseStatus
:可以将某种异常映射为HTTP状态码
框架将异常处理方法专门定义在一个类中,作为全局的异常处理类,需要使用注解@ControllerAdvice
,字面理解就是“控制器增强”,是给控制器对象增强功能的。
使用@ControllerAdvice
修饰的类中可以使用@ExceptionHandler
。当使用@RequestMapping
注解修饰的方法抛出异常时,会执行@ControllerAdvice
修饰的类中的异常处理方法。
@ControllerAdvice
是使用@Component 注解修饰的,可以<context:component-scan>
扫描到@ControllerAdvice
所在的类路径(包名),创建对象。
@ControllerAdvice // 写在类上
public class GlobalExceptionHandler {
@ExceptionHandler(value = UserException.class) // 指定value的值就只处理相应的异常
public ModelAndView doUserException(Exception e){
ModelAndView mv = new ModelAndView();
mv.addObject("tips",e);
mv.setViewName("userError");
return mv;
}
@ExceptionHandler //不指定value,就处理其他没有被处理的所有异常,所以不指定value的方法只能有一个
public ModelAndView defaultException(Exception e){
ModelAndView mv = new ModelAndView();
mv.addObject("tips",e);
mv.setViewName("userError");
return mv;
}
}
<context:component-scan base-package="com.maj.handler" /> <!--扫描创建异常处理类的包-->
<!--声明注解驱动-->
<mvc:annotation-driven />
拦截器
Interceptor 拦截器是springMVC中的一种
**主要作用:**拦截指定的用户请求,并进行相应的预处理与后处理。
拦截的时间点:
- 在请求处理之前,也就是Controller类中的方法执行之前先被拦截
- 在控制器方法执行之后也会执行拦截器
- 在请求处理完成后也会执行拦截器
在处理器映射器映射出所要执行的处理器类时,已经将拦截器与处理器组合为了一个处理器执行链,并返回给了中央调度器。
拦截器与过滤器类似,但是功能方向侧重不同:(区别)
-
过滤器是Servlet中的对象,拦截器是框架中的对象
-
过滤器是实现 Filter接口,拦截器是实现HandlerInterceptor接口
-
过滤器是用来过滤请求参数,设置编码字符集等工作,拦截器是拦截用户的请求,做请求判断处理的
-
过滤器是在拦截器之前先执行的
-
过滤器是Tomcat服务器创建的对象,拦截器是springmvc容器中创建对象
-
过滤器可以处理jsp,js,html等等;拦截器是侧重拦截Controller对象,(如果请求不能被 DispatcherServlet接收,这个请求不会执行拦截器内容)
特点:
- 拦截器也是全局的,可以给多个Controller做拦截
- 拦截器可以有>=0个,他们一起拦截用户的请求
拦截器常用在:用户登录处理,权限检查,记录日志
一个拦截器
自定义拦截器,需要实现 HandlerInterceptor接口。而该接口中含有三个方法:
preHandle(request,response, Object handler)
:- 该方法在处理器方法执行之前执行。
- 参数:Object handler 被拦截的控制器对象
- 返回值为 boolean
- true,表示通过放行,执行后续的处理器方法
- false,表示没有通过拦截器的验证,在拦截器
preHandle
方法就截止了
postHandle(request,response, Object handler,ModelAndView mv)
:- 该方法在处理器方法执行之后执行。
- 处理器方法若最终未被执行,则该方法不会执行。
- 由于该方法是在处理器方法执行完后执行,且该方法参数中包含 ModelAndView,所以该方法可以修改处理器方法的处理结果数据,且可以修改跳转方向。
afterCompletion(request,response, Object handler, Exception ex)
:- 该方法是最后执行的方法,清除资源
- 该方法是请求处理完成后(已经给用户发送数据了)再执行的,此时对 ModelAndView 再操作也对响应无济于事。
- 当
preHandle()
方法返回 true 时,会将该方法放到专门的方法栈中,等到对请求进行响应的所有工作完成之后才执行该方法。
自定义拦截器
package com.maj.handler;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor 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方法执行了");
}
}
注册拦截器
<!--注册拦截器(0或多个)-->
<mvc:interceptors>
<mvc:interceptor>
<!--
指定拦截的请求uri地址
path:uri地址,可以使用通配符 **
** :表示任意的字符,文件或者多级目录和目录中的文件
/user/**:表示user路径里面的全部都拦截
例如:http://localhost:8080/springmvc06/user/allUsers.do
/** :表示项目下所有路径都拦截
-->
<mvc:mapping path="/user/**"/>
<!--指定自定义的拦截器-->
<bean class="com.maj.handler.MyInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
多个拦截器
<mvc:interceptors>
<!--第一个拦截器-->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.maj.handler.MyInterceptor01" />
</mvc:interceptor>
<!--第二个拦截器-->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.maj.handler.MyInterceptor02" />
</mvc:interceptor>
</mvc:interceptors>
声明拦截器是按照先后顺序放入到ArrayList中,所以先声明的拦截器,会先拦截。
所以执行顺序是:
-
拦截器01的preHandle返回true,拦截器02的preHandle返回true
拦截器01的`preHandle`----》拦截器02的`preHandle`----》Controller处理----》拦截器02的`postHandle`----》拦截器01的`postHandle`----》拦截器02的`afterCompletion`----》拦截器01的`afterCompletion`
-
拦截器01的preHandle返回true,拦截器02的preHandle返回false
拦截器01的`preHandle`----》拦截器02的`preHandle`----》拦截器01的`afterCompletion`
-
拦截器01的preHandle返回false,拦截器02的preHandle返回true/false
----》拦截器01的`preHandle`
如图:
以上是关于4.SpringMVC核心技术的主要内容,如果未能解决你的问题,请参考以下文章