(一)请求转发和重定向
(二)项目准备
1、复制一份ch02的代码,重命名为ch08 forward-redirect,删掉target文件夹和.iml文件后,更改pom.xml文件中的项目名信息。
然后点击Project Structure,点击+,import Modules,选择Maven项目,点击ok,将刚刚这个ch08的项目引入。
2、修改index.jsp的内容
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String basePath = request.getScheme() + "://" +
request.getServerName() + ":" +request.getServerPort() +
request.getContextPath() + "/";
%>
<html>
<head>
<title>Title</title>
<base href="<%=basePath%>"/>
</head>
<body>
<p>当处理器方法返回ModelAndView实现forward</p>
<form action="doFoward.do" method="post">
姓名:<input type="text" name="name"/><br/>
年龄:<input type="text" name="age"/><br/>
<input type="submit" value="提交请求"/>
</form>
</body>
</html>
(三)请求转发forward
1、视图解析器代码在springmvc.xml中:
<!--声明 springmvc框架中的视图解析器,帮助开发人员设置视图文件的路径-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--前缀:视图文件位置-->
<property name="prefix" value="/WEB-INF/view/"/>
<!--后缀:视图文件的扩展名-->
<property name="suffix" value=".jsp"/>
</bean>
在MyController文件中,可以省略文件名的前缀和后缀,但是这里指的当然只是前缀为/WEB-INF/view/目录的文件。一旦我们要访问webapp下的文件hello.jsp,是没有办法访问的。
2、修改MyController.java文件(注意method要改为POST的提交方式):
@Controller
public class MyController {
//指定sme.do用GET请求获取
@RequestMapping(value="/doForward.do",method= RequestMethod.POST)
public ModelAndView doSome(){
ModelAndView mv = new ModelAndView();
mv.addObject("msg","欢迎使用springmvc做web开发");
mv.addObject("fun","执行的是doSome方法");
//mv.setViewName("show");
//显示转发
mv.setViewName("forward:/WEB-INF/view/show.jsp");
return mv;
}
}
3、成功运行:
4、复制一份show.jsp页面到webapp文件夹下改名为hello.jsp,这个时候使用视图解析器就无法访问到这个文件了(因为已经制定了文件路径的前缀是WEB/INF)。这时只要将MyController文件路径改成这个:
mv.setViewName("forward:/hello.jsp");
(四)重定向redirect
1、在index.jsp中增加一个表单:
<p>当处理器方法返回ModelAndView实现redirect</p>
<form action="doRedirect.do" method="post">
姓名:<input type="text" name="name"><br/>
年龄:<input type="text" name="age"><br/>
<input type="submit" value="提交请求">
</form>
2、在MyController类中增加doSome2方法:
@RequestMapping(value="/doRedirect.do",method= RequestMethod.POST)
public ModelAndView doSome2(String name,Integer age){
ModelAndView mv = new ModelAndView();
//数据放入到request作用域
mv.addObject("myname",name);
mv.addObject("myage",age);
//重定向
mv.setViewName("redirect:/hello.jsp");
//http://localhost:8080/ch08_forward_redirect/hello.jsp?myname=lisi&myage=22
return mv;
}
因为在@RequestMapping处发起了一次request请求,并传参给下面的name和age;但在重定向时又发起了一次request请求。所以在hello.jsp即展示界面中不能直接访问到“myname”和"myage"的值,因为是两次不同的request请求。
3、因此,还要修改hello.jsp界面,用${param.myname}获取请求信息。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>hello.jsp从request作用域获取数据</h3><br/>
<h3>myname数据:${param.myname}</h3><br/>
<h3>myage数据:${param.myage}</h3>
<h3>取参数数据:<%=request.getParameter("myname")%></h3>
</body>
</html>
4、运行成功:
(五)总结
(六)集中统一处理异常
6.1 springmvc框架的异常处理机制
springmvc框架采用的是统一的、全局的异常处理。
把controller中的所有异常处理都集中到一个地方,即采用的是aop思想,把业务逻辑和异常处理代码分开,也叫解耦合。
使用两个注解:
1)@ExceptionHandler
2)@ControllerAdvice
6.2 异常处理的步骤
6.3 项目代码
1、项目准备及代码编写
(1)复制一份ch08的代码,重命名为ch09 exception-handler。
(2)删除webapp文件夹下的hello.jsp,只留下index.jsp。删除部分表单,修改index.jsp代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String basePath = request.getScheme() + "://" +
request.getServerName() + ":" +request.getServerPort() +
request.getContextPath() + "/";
%>
<html>
<head>
<title>Title</title>
<base href="<%=basePath%>" />
</head>
<body>
<p>处理异常的,全局异常处理</p>
<form action="some.do" method="post">
姓名:<input type="text" name="name"><br/>
年龄:<input type="text" name="age"><br/>
<input type="submit" value="提交请求">
</form>
</body>
</html>
(3)接下来准备异常类:
在com.bjpowernode文件夹下新建exception文件夹,新建MyUserException类作为异常类,在该文件extends后面增加Exception,表示继承这个类Exception。然后按ctrl+O键重新方法,选择Exception0、Exception(message:String)两个方法进行重写(一般放在第一个和第二个)。
同样的方法准备AgeException类和NameException类,但它们的父类是MyUserException类(即extends MyUserException)。
(4)在MyController类中加异常代码(如果是加了try和catch,就是自己在处理异常;如果不加,就是交给框架处理),出现红色波浪线,选择Add Ex…抛出异常,但是NameException、AgeException两个异常都要抛出,所以将抛出的异常交给父类MyUserException。
@Controller
public class MyController {
@RequestMapping(value="/some.do")
public ModelAndView doSome(String name,Integer age) throws MyUserException {
ModelAndView mv = new ModelAndView();
//try{
if(!"zs".equals(name)){
throw new NameException("姓名不正确!!!");
}
if(age==null || age>80){
throw new AgeException("年龄比较大!!!");
}
//}catch(Exception e){
// e.printStackTrace();
//}
mv.addObject("myname",name);
mv.addObject("myage",age);
mv.setViewName("show");
return mv;
}
}
(5)创建一个普通类,作用全局异常处理类。
在com.bjpowernode包下新建package名为handler,在下面新建类GlobalExceptionHandler。
/**
* @ControllerAdvice:控制器增强(也就是说给控制器类增加功能--异常处理功能)
* 位置:在类的上面
* 特点:必须让框架知道这个注解所在的包名,即需要在springmvcl配置文件中声明组件扫描器指定@ControllerAdvice所在的包名。
*/
@ControllerAdvice
public class GlobalExceptionHandler {
//定义方法,处理发生的异常
/*
形参:Exception,表示Controller中抛出的异常对象。通过形参可以获取发生的异常信息。
@ExceptionHandler(异常的class):表示异常的类型,当发生此类型异常时,由当前方法处理。
*/
//处理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","你的年龄不能大于80");
mv.addObject("ex",exception);
mv.setViewName("ageError");
return mv;
}
//处理其他异常,相当于else
@ExceptionHandler
public ModelAndView doOtherException(Exception exception){
ModelAndView mv = new ModelAndView();
mv.addObject("msg","出现其他异常");
mv.addObject("ex",exception);
mv.setViewName("defaultError");
return mv;
}
}
(6)检查springmvc.xml文件中是否声明了组件扫描器。
(7)删掉WEB-INF/view文件夹下的other.jsp,修改show.jsp:
<body>
<h3>show.jsp从request作用域获取数据</h3><br/>
<h3>myname数据:${myname}</h3>
<h3>myage数据:${myage}</h3>
</body>
(8)然后在view文件夹下新建ageError.jsp。提示信息${msg}是来自于GlobalExceptionHandler类中"msg"的相关提示;
${“ex.message”}则对应于:在AgeException类中的构造方法中有super(message),这个message来自于MyController类中抛出异常时提示的信息throw new AgeException(“年龄比较大!!!”)。
<body>
ageError.jsp<br/>
提示信息:${msg}<br/>
系统异常消息:${ex.message}
</body>
同理,在view文件夹下创建nameError.jsp、defaultError.jsp。
(8)修改springmvc的配置文件
增加两个注解(注意:增加注解驱动<mvc:annotation-driven时一定要选到后面是/mvc的才能按enter键)。
<!--处理异常需要的两步-->
<context:component-scan base-package="com.bjpowernode.handler" />
<mvc:annotation-driven/>
2、项目运行结果
(1)正常执行
(2)异常执行
(3)其他异常
3、小结
(1)当用户输入完信息后,将形参提交请求到MyController类。如果中间出现异常,则根据异常跳转到GlobalExceptionHandler类,根据异常类型找到对应的@ExceptionHandler的value值,接下来走这个值下对应的方法。
方法中的msg就是最后显示在XXError.jsp界面的提示信息;XXError.jsp界面的系统异常信息则是MyController类文件中throw new NameException的值。
(2)controller是业务逻辑代码,发现了异常后统一交给handler文件夹下的GlobalExceptionHandler类文件出来,即handler是非业务逻辑代码,整体组成了AOP的思想。