当处理器对请求处理完毕后,向其他资源跳转时,有两种跳转方式:请求转发 与 重定向 。而根据所要跳转的资源类型,又分为两类:跳转到页面与跳转到其他处理器。
注意,对于请求转发的页面,可以是 WEB-INF 中的页面;而重定向的页面,是不能为 WEB-INF中的页面。因为重定向相当于用户再次发出一次请求,而用户是不能直接访问 WEB-INF 中资源的。
springmvc框架把原来的servlet中的请求转发和重定向进行了封装,现在可以使用简单方式实现了。
forward:表示转发,实现request.getRequestDispatcher("xx.jsp").forward()
redirect:表示重定向,实现response.sendRedirect("xxx.jsp")
处理器方法返回 ModelAndView,实现转发 forward操作
语法:setViewName("forward:视图文件完整路径")
forward特点:不和视图解析器一同使用,就当项目中没有视图解析器
对应控制器
@Controller
public class MyController {
@RequestMapping(value = "/doForward.do")
public ModelAndView doSome(){
ModelAndView mv = new ModelAndView();
mv.addObject("msg","-----欢迎使用spring mvc做web开发------" );
mv.addObject("fun","执行的是doSome方法");
//=====================重点===========================
//使用视图解析器
//mv.setViewName("show");
//显式转发
mv.setViewName("forward:WEB-INF/view/show.jsp");
//=====================重点===========================
return mv;
}
}
处理器方法返回ModelAndView,实现转发redirect操作
语法:setViewName("redirect:视图文件完整路径")
redirect特点:不和视图解析器一同使用,就当作项目中没有视图解析器
<br/>
框架对重定向的操作:
1、框架会把model中的简单类型的数据,转为String使用,作为hello.jsp的get请求参数使用
目的是在 doRedirect.do 和 hello.jsp 两次请求之间传递参数
2、在目标hello.jsp可以使用参数集合对象 $(param) 获取请求参数值,格式为:$(param.name)
3、重定向不能访问WEB-INF资源
对应控制器
@RequestMapping(value = "/doRedirect.do")
public ModelAndView doWithRedirect(String name,Integer age){
ModelAndView mv = new ModelAndView();
//数据放入到 request 作用域
mv.addObject("name",name);
mv.addObject("age",age);
//=====================重点===========================
//重定向
mv.setViewName("redirect:hello.jsp");
//http://localhost:8080/08_forward/hello.jsp?name=zhangsan&age=11
//=====================重点===========================
return mv;
}
hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Titletitle>
head>
<body>
<h3>show.jsph3><br/>
<h3>name数据:${name}h3>
<h3>age数据:${age}h3>
body>
html>
输入参数如下图
虽然网址上传递了参数,但name和age取不到参数,因为重定向是两次请求,参数在第一次请求的作用域里面,无法直接传递到第二个作用域。此时修改hello.jsp,直接访问第一次请求作用域里面的参数。
hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Titletitle>
head>
<body>
<h3>show.jsph3><br/>
<h3>name数据:${param.name}h3>
<h3>age数据:${param.age}h3>
<h3>取参数数据:<%=request.getParameter("name")%>h3>
body>
html>
springmvc框架采用的是统一,全局的异常处理。把controller中的所有异常处理都集中到一个地方,采用的是aop思想,把业务逻辑和异常处理代码分开。也叫解耦(ou)合。
使用两个注解:1、ExceptionHandler 2、ControllerAdvice
异常处理主要步骤:
1 新建一个自定义异常类 MyUserException,再定义它的子类 NameException,AgeException
2 在 controller 抛出 NameException,AgeException
3 创建一个普通类,作为 全局异常处理类
1> 类上面加上 @ControllerAdvice
2> 类中方法上面加上 @ExceptionHandler
4 创建对应视图。创建组件扫描器扫描,扫描全局变量处理程序。创建注解驱动。
项目结构如下
springmvc.xml,加入组件扫描器和注解驱动
<context:component-scan base-package="com.zh.handler"/>
<mvc:annotation-driven/>
MyController.java,控制器方法,向 MyUserException 抛出异常
@Controller
public class MyController {
@RequestMapping(value = "/some.do")
public ModelAndView doSome(String name,Integer age) throws MyUserException {
ModelAndView mv = new ModelAndView();
//根据请求抛出异常
if (!"zs".equals(name)){
throw new NameException("姓名不正确");
}
if (age <= 0 || age >= 99){
throw new AgeException("年龄输入有误");
}
mv.addObject("name",name);
mv.addObject("age",age);
mv.setViewName("show");
return mv;
}
}
自定义异常类 MyUserException.java,继承 Exception
public class MyUserException extends Exception{
public MyUserException() {
super();
}
public MyUserException(String message) {
super(message);
}
}
子类 NameException.java
//表示当前用户姓名有异常,抛出NameException
public class NameException extends MyUserException {
public NameException() {
super();
}
public NameException(String message) {
super(message);
}
}
下面创建一个GlobalExceptionHandler.java,作为 全局异常处理类
控制器增强 (可以理解为:增加控制器功能),放在类上面
特点:必须让框架知道这个注解所在的包名,需要在springmvc配置文件声明 组件扫描器
指定 @ControllerAdvice 所在的全局异常处理类包名
@ExceptionHandler(异常的class):表示异常的类型,当发生此类型的异常时,由当前方法处理。放在方法上面
处理异常的方法和控制器方法的定义一样,可以有多个参数,可以有ModelAndView,String,void,对象类型的返回值
形参:Exception,表示Controller中抛出的异常对象,通过形参可以获取发送的异常信息
GlobalExceptionHandler.java
//@ControllerAdvice 增强控制器
@ControllerAdvice
public class GlobalExceptionHandler {
//处理NameException异常
@ExceptionHandler(value = NameException.class)
public ModelAndView doNameException(Exception exception){
ModelAndView mv = new ModelAndView();
mv.addObject("msg","用户名必须是zs,其他用户不能访问");
mv.addObject("ex",exception);
//指定视图
mv.setViewName("nameError");
return mv;
}
//处理AgeException异常
@ExceptionHandler(value = AgeException.class)
public ModelAndView doAgeException(Exception exception){
ModelAndView mv = new ModelAndView();
mv.addObject("msg","年龄输入范围有误");
mv.addObject("ex",exception);
mv.setViewName("ageError");
return mv;
}
//处理NameException,AgeException以外的,不知类型的异常
@ExceptionHandler
public ModelAndView doOtherException(Exception exception){
ModelAndView mv = new ModelAndView();
mv.addObject("msg","其他不知类型的异常");
//指定视图
mv.setViewName("defaultError");
return mv;
}
}
拦截器说明:
1 拦截器是springmvc中的一种,需要实现HandlerInterceptor接口
2 拦截器和过滤器类似,功能方向侧重点不同。过滤器是用来过滤请求参数,设置编码字符集等。
拦截器是拦截用户的请求,可以对多个Controller做拦截。
3 拦截器是全局的,可以对多个Controller做拦截。
一个项目中可以有0个或多个拦截器,他们在一起拦截用户的请求。
拦截器常用在:用户登录处理,权限检查,记录日志。
拦截器的使用步骤:
1 定义普通类实现HandlerInterceptor接口,实现接口的三个方法
2 在springmvc文件中,声明拦截器,指定拦截请求的uri地址
拦截器的执行时间:
1 在请求处理之前,也就是controller类中方法执行之前先被拦截
2 在控制器方法执行之后也会执行拦截器
3 在请求处理完成后也会执行拦截器
在主配置文件sprinmvc.xml中,声明拦截器
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.zh.handler.MyInterceptor"/>
mvc:interceptor>
mvc:interceptors>
创建一个MyInterceptor.java,作为拦截器类,继承自HandlerInterceptor,实现三个方法:preHandle,postHandle,afterCompletion
预处理方法:preHandle
重要:是整个项目的入口,门户
当preHandle返回true,请求可以被处理
当preHandle返回false,请求到此方法就截止
参数:Object handler:被拦截的控制器对象
返回值:boolean
true:请求通过拦截器验证,可以处理拦截器方法
控制台显示结果:
MyInterceptor拦截器的preHandle()方法执行了!
MyController控制器的doSome()方法执行!
MyInterceptor拦截器的postHandle()方法执行了!
MyInterceptor拦截器的afterCompletion()方法执行了!
false:请求没有通过拦截器的验证,请求到达拦截器就截止了。请求没有被处理
控制台显示结果:
MyInterceptor拦截器的preHandle()方法执行了!
特点:
1、该方法在控制器方法(MyController的doSome)之前执行,用户请求首先到达该方法
2、在该方法中可以获取请求的信息,验证请求是否符合要求。可以验证用户是否登录,验证用户是否有权访问某个连接地址(url),
如果验证失败,可以截断请求;如果验证成功,可以放行请求,此时控制器方法才能执行
MyInterceptor.java
//拦截器类:看作是多个控制器中公用的功能,集中到拦截器统一处理,使用的是aop思想(面向切面编程)。
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor拦截器的preHandle()方法执行了!");
return true;
}
/*
* 后处理方法:postHandle
* 参数:
* Object handler:被拦截的处理器对象MyController
* ModelAndView mv:处理器方法的返回值
*
* 特点:
* 1、在处理器方法(MyController.doSome)之后执行
* 2、能够获取到处理器方法的返回值ModelAndView,可以修改ModelAndView中的数据和视图,会影响到最后的输出结果
* 3、主要是对原来的执行结果做第二次修正
* */
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mv) throws Exception {
System.out.println("MyInterceptor拦截器的postHandle()方法执行了!");
}
/*
* 最后执行方法:afterCompletion
* 参数:
* Object handler:被拦截的处理器对象
* Exception ex:程序中发生的异常
* 特点:
* 1、在请求处理完成后执行。框架中规定是你的视图处理完成后,对视图执行了forward。就认为请求处理完成。
* 2、一般做资源回收,程序请求中创建的一些对象,在这里删除,回收占用的内存
*
* */
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor拦截器的afterCompletion()方法执行了!");
}
}
多个拦截器时
在框架中保存多个拦截器是ArrayList,
按照声明的先后顺序放入ArrayList
第一个拦截器类
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("11111--MyInterceptor拦截器的preHandle()方法执行了!");
return true;
}
@Override
public void postHandle(......){
System.out.println("11111--MyInterceptor拦截器的postHandle()方法执行了!");
}
.....
第二个拦截器类
public class MyInterceptor2 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("22222--MyInterceptor拦截器的preHandle()方法执行了!");
return true;
}
@Override
public void postHandle(......){
System.out.println("22222--MyInterceptor拦截器的postHandle()方法执行了!");
}
.....
配置文件中也要同时声明两个拦截器
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.zh.handler.MyInterceptor"/>
mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.zh.handler.MyInterceptor2"/>
mvc:interceptor>
mvc:interceptors>
运行结果如下
11111--MyInterceptor拦截器的preHandle()方法执行了!
22222--MyInterceptor拦截器的preHandle()方法执行了!
MyController控制器的doSome()方法执行!
22222--MyInterceptor拦截器的postHandle()方法执行了!
11111--MyInterceptor拦截器的postHandle()方法执行了!
22222--MyInterceptor拦截器的afterCompletion()方法执行了!
11111--MyInterceptor拦截器的afterCompletion()方法执行了!
执行结果为
11111--MyInterceptor拦截器的preHandle()方法执行了!
22222--MyInterceptor拦截器的preHandle()方法执行了!
11111--MyInterceptor拦截器的afterCompletion()方法执行了!
11111--MyInterceptor拦截器的preHandle()方法执行了!
1 过滤器是servlet中的对象,拦截器是框架中的对象
2 过滤器实现Filter接口,拦截器实现HandlerInterceptor
3 过滤器是用来设置request,response的参数,属性,侧重对数据过滤的
拦截器用来验证请求,能截断请求
4 过滤器是在拦截器之前先执行
5 过滤器是tomcat服务器创建的对象
拦截器是springmvc容器中创建的对象
6 过滤器是一个执行时间点
拦截器是三个执行时间点
7 过滤器可以处理jsp,js,html等
拦截器是侧重拦截对Controller的对象。如果你的请求不能被DispatcherServlet接收,这个请求 不会执行拦截器内容
8 拦截器拦截普通类方法执行,过滤器过滤servlet请求响应
https://blog.csdn.net/weixin_40350981/article/details/109645897