4.1 请求转发与重定向
当处理器对请求处理完毕后,向其它资源进行跳转时,有两种跳转方式:请求转发与重定向。而根据所要跳转的资源类型,又可分为两类:跳转到其它页面与跳转到其它处理器。
注意,对于请求转发的页面,可以是WEB-INF中的页面;而重定向的页面,不能是WEB-INF中的页面。因为重定向相当于用户再次发出一次请求,而用户是不能直接访问WEB-INF中的资源的。
4.1.1 返回ModelAndView时的请求转发
(1)、请求转发到页面
(2)、请求转发到Controller
4.1.2 返回ModelAndView时的重定向
(1)、重定向到页面
A、通过ModelAndView的Model携带参数
index.jsp
<form action="${pageContext.request.contextPath }/test/register.do" method="POST">
姓名:<input type="text" name="name" /><br />
年龄:<input type="text" name="age" /><br />
<input type="submit" value="注册" />
</form>
处理器
@org.springframework.stereotype.Controller
@RequestMapping("/test")
public class MyController {
@RequestMapping("/register.do")
public ModelAndView doSecond(String name, int age) {
ModelAndView mv = new ModelAndView();
mv.addObject("name", name);
mv.addObject("age", age);
mv.setViewName("redirect:/welcome.jsp");
return mv;
}
}
跳转到welcome.jsp页面获取接收参数
<!--
param.name底层执行的是request.getParameter("name")
requestScope.name底层执行的是request.getAttribute("name")
-->
name = ${param.name}
<br/>
age = ${param.age}
B、通过HttpSession携带参数
(2)、重定向到Controller
A、通过ModelAndView的Model携带参数
B、通过HttpSession携带参数
4.1.3 返回String时的请求转发
(1)、请求转发到页面
(2)、请求转发到Controller
4.1.4 返回String时的重定向
(1)、重定向到页面
(2)、重定向到Controller
index.jsp
<form action="${pageContext.request.contextPath }/test/register.do" method="POST">
姓名:<input type="text" name="name" /><br />
年龄:<input type="text" name="age" /><br />
<input type="submit" value="注册" />
</form>
处理器
@org.springframework.stereotype.Controller
@RequestMapping("/test")
public class MyController {
@RequestMapping("/register.do")
public String doRegister(String name, int age, Model model) {
model.addAttribute("name",name);
model.addAttribute("age",age);
return "redirect:other.do";
}
@RequestMapping("/other.do")
public String doOther(String name,int age) {
System.out.println("name = " + name);
System.out.println("age = " + age);
return "/welcome.jsp";
}
}
跳转到welcome.jsp页面获取接收参数
<!--
param.name底层执行的是request.getParameter("name")
requestScope.name底层执行的是request.getAttribute("name")
-->
name = ${param.name}
<br/>
age = ${param.age}
4.1.5 返回void时的请求转发
(1)、请求转发到页面
(2)、请求转发到Controller
4.1.6 返回void时的重定向
(1)、重定向到页面
(2)、重定向到Controller
4.2 异常处理
常用的springmvc异常处理方式主要有三种:
4.2.1 SimpleMappingExceptionResolver异常处理器
springmvc.xml
<context:component-scan base-package="com.bjpowernode.handlers"></context:component-scan>
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="defaultErrorView" value="/errors/error.jsp"></property>
<property name="exceptionAttribute" value="ex"></property>
<property name="exceptionMappings">
<props>
<prop key="com.bjpowernode.exceptions.NameException">/errors/nameError.jsp</prop>
<prop key="com.bjpowernode.exceptions.AgeException">/errors/ageError.jsp</prop>
</props>
</property>
</bean>
StudentException.class
public class StudentException extends Exception {
public StudentException() {
super();
}
public StudentException(String message) {
super(message);
}
}
NameException.class
public class NameException extends StudentException {
public NameException() {
super();
}
public NameException(String message) {
super(message);
}
}
AgeException.class
public class AgeException extends StudentException {
public AgeException() {
super();
}
public AgeException(String message) {
super(message);
}
}
处理器
@org.springframework.stereotype.Controller
@RequestMapping("/test")
public class MyController {
@RequestMapping("/register.do")
public ModelAndView doRegister(String name, int age) {
int i = 3/0;
ModelAndView mv = new ModelAndView();
mv.addObject("name", name);
mv.addObject("age", age);
mv.setViewName("welcom.jsp");
return mv;
}
}
error.jsp
<body>
error page.<br />
${ex.message}
</body>
nameError.jsp
name error page.
<br>
${ex.message}
ageError.jsp
age error page.
<br>
${ex.message}
4.2.2 自定义异常处理器
使用springmvc定义好的SimpleMappingExceptionResolver异常处理器,可以实现生指定异常后的跳转。但若要想实现在捕捉到异常时,进行一些操作,它是完成不了的。此时,就需要使用自定义异常。
自定义异常处理器,需要实现HandlerExceptionResolver接口,并且该类需要在springmvc配置文件中进行注册。
自定义异常处理器
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
ModelAndView mv = new ModelAndView();
mv.addObject("ex", ex);
mv.setViewName("/errors/error.jsp");
if(ex instanceof NameException) {
mv.setViewName("/errors/nameError.jsp");
}
if(ex instanceof AgeException) {
mv.setViewName("/errors/ageError.jsp");
}
return mv;
}
}
springmvc.xml 注册
<!-- 注册自定义异常处理器 -->
<bean class="com.bjpowernode.resolvers.MyHandlerExceptionResolver"></bean>
4.2.3 异常处理器注解@ExceptionHandler
定义异常处理器
@org.springframework.stereotype.Controller
public class BaseController {
@ExceptionHandler(NameException.class)
public ModelAndView handlerNameException(Exception ex) {
ModelAndView mv = new ModelAndView();
mv.addObject("ex", ex);
mv.setViewName("/errors/nameError.jsp");
return mv;
}
@ExceptionHandler(AgeException.class)
public ModelAndView handlerAgeException(Exception ex) {
ModelAndView mv = new ModelAndView();
mv.addObject("ex", ex);
mv.setViewName("/errors/ageError.jsp");
return mv;
}
@ExceptionHandler
public ModelAndView handlerException(Exception ex) {
ModelAndView mv = new ModelAndView();
mv.addObject("ex", ex);
mv.setViewName("/errors/error.jsp");
return mv;
}
}
处理器继承异常处理器
@org.springframework.stereotype.Controller
@RequestMapping("/test")
public class MyController extends BaseController {
@RequestMapping("/register.do")
public ModelAndView doRegister(String name, int age) throws StudentException {
if(!"beijing".equals(name)) {
throw new NameException("用户名不正确");
}
if(age > 60) {
throw new AgeException("年龄太大了");
}
ModelAndView mv = new ModelAndView();
mv.addObject("name", name);
mv.addObject("age", age);
mv.setViewName("/welcome.jsp");
return mv;
}
}
4.3 类型转换器和初始化参数绑定
可以解决提交的参数类型转换问题
4.4 数据验证
springmvc支持JSR(Java Specification Requests)303-bean validation数据验证规范。而该规范的实现者很多,其中较常用的是Hibernate Valicator。
需要注意的是,Hebernate Valicator是与Hibernate ORM并列的Hibernate的产品之一。
第一步:导入jar包
Hibernate Valicator的jar包:
hibernate-validator
jboss-logging
validation-api
第二步:注册验证器和驱动
springmvc.xml
<!-- 注册验证器 -->
<bean id="myValidator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="providerClass" value="org.hibernate.validator.HibernateValidator"></property>
</bean>
<!-- 注册mvc注解驱动 -->
<mvc:annotation-driven validator="myValidator"></mvc:annotation-driven>
第三步:实体类-验证规则
public class Student {
@NotNull(message="姓名不以为空")
@Size(min=3, max=6, message="姓名长度在{min}-{max}个字符之间")
private String name;
@Min(value=0, message="成绩不能小于{value}")
@Max(value=100, message="成绩不能大于{value}")
private double score;
@NotNull(message="电话不能为空")
@Pattern(regexp="^1[34578]\\d{9}$",message="手机号格式不正确")
private String mobile;
....
getter and setter
...
}
第四步:处理器
@org.springframework.stereotype.Controller
@RequestMapping("/test")
public class MyController {
@RequestMapping(value={"/register.do"}, method= RequestMethod.POST)
public ModelAndView doRegister(@Validated Student student, BindingResult br) {
ModelAndView mv = new ModelAndView();
mv.addObject("name", student);
mv.setViewName("/WEB-INF/jsp/welcome.jsp");
int errorCount = br.getErrorCount();
if(errorCount > 0) {
FieldError nameError = br.getFieldError("name");
FieldError scoreError = br.getFieldError("score");
FieldError mobieError = br.getFieldError("mobile");
if(nameError != null) {
String nameErrorMSG = nameError.getDefaultMessage();
mv.addObject("nameErrorMSG", nameErrorMSG);
}
if(scoreError != null) {
String scoreErrorMSG = scoreError.getDefaultMessage();
mv.addObject("scoreErrorMSG", scoreErrorMSG);
}
if(mobieError != null) {
String mobileErrorMSG = mobieError.getDefaultMessage();
mv.addObject("mobileErrorMSG", mobileErrorMSG);
}
mv.setViewName("/index.jsp");
}
return mv;
}
}
index.jsp
<form action="${pageContext.request.contextPath }/test/register.do" method="POST">
姓名:<input type="text" name="name" />${nameErrorMSG }<br />
成绩:<input type="text" name="score" />${scoreErrorMSG }<br />
电话:<input type="text" name="mobile" />${mobileErrorMSG }<br />
<input type="submit" value="注册" />
</form>
4.5 文件上传
4.5.1 上传单个文件
第一步:导入jar包
commons-fileupload
commons-io
第二步:注册
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8"></property>
<property name="maxUploadSize" value="1048576"></property>
</bean>
<mvc:annotation-driven></mvc:annotation-driven>
第三步:页面
<form action="${pageContext.request.contextPath }/test/upload.do" method="POST" enctype="multipart/form-data">
文件:<input type="file" name="img" /><br />
<input type="submit" value="提交" />
</form>
第四步:处理器
@org.springframework.stereotype.Controller
@RequestMapping("/test")
public class MyController {
@RequestMapping(value={"/upload.do"}, method= RequestMethod.POST)
public String doFileUpload(MultipartFile img, HttpSession session) throws Exception {
String path = session.getServletContext().getRealPath("/images");
if(img.getSize() > 0) {
String fileName = img.getOriginalFilename();
if(fileName.endsWith("jpg") || fileName.endsWith("png")) {
File file = new File(path, fileName);
img.transferTo(file);
return "/success.jsp";
}
}
return "/fail.jsp";
}
}
4.5.2 上传多个文件
处理器
@org.springframework.stereotype.Controller
@RequestMapping("/test")
public class MyController {
@RequestMapping(value={"/upload.do"}, method= RequestMethod.POST)
public String doFileUpload(@RequestParam MultipartFile[] imgs, HttpSession session) throws Exception {
String path = session.getServletContext().getRealPath("/images");
for(MultipartFile img:imgs) {
if(img.getSize() > 0) {
String fileName = img.getOriginalFilename();
if(fileName.endsWith("jpg") || fileName.endsWith("png")) {
File file = new File(path, fileName);
img.transferTo(file);
}
}
}
return "/success.jsp";
}
}
index.jsp
<form action="${pageContext.request.contextPath }/test/upload.do" method="POST" enctype="multipart/form-data">
文件1:<input type="file" name="imgs" /><br />
文件2:<input type="file" name="imgs" /><br />
文件3:<input type="file" name="imgs" /><br />
<input type="submit" value="提交" />
</form>
4.6 拦截器
springmvc中的拦截器是非常重要和相当有用的,它的主要作用是拦截指定的用户请求,并进行相应的预处理与后处理。其拦截的时间点在“处理器映射器根据用户提交的请求映射出了所要执行的处理器类,并且也找到了要执行该处理器类的处理器适配器,在处理器适配器执行处理器之前”。当然,在处理器映射器映射出所要执行的处理器类时,已经将拦截器与处理器组合为了一个处理器执行链,并返回给了中央调度器。
4.6.1 拦截器的实现
第一步:注册拦截器
<!-- 注册拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.bjpowernode.interceptors.OneInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
第二步:拦截器
public class OneInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
System.out.println("execute prehandler");
return true;
}
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception {
System.out.println("execute posthandler");
}
@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
System.out.println("execute aftercomplete");
}
}
处理器
@org.springframework.stereotype.Controller
@RequestMapping("/test")
public class MyController {
@RequestMapping("/some.do")
public String doSome() {
System.out.println("execute dosome");
return "/WEB-INF/jsp/welcome.jsp";
}
}
4.6.2 权限拦截器
处理器
@org.springframework.stereotype.Controller
@RequestMapping("/test")
public class MyController {
@RequestMapping("/some.do")
public String doSome() {
System.out.println("execute dosome");
return "/WEB-INF/jsp/welcome.jsp";
}
}
拦截器
public class PermissionInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String user = (String) request.getSession().getAttribute("user");
if("beijing".equals(user)) {
return true;
}
request.getRequestDispatcher("/fail.jsp").forward(request, response);
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
}
注册
<!-- 注册拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.bjpowernode.interceptors.PermissionInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
login.jsp
<%
session.setAttribute("user", "beijing");
%>>
login success.
logout.jsp
<%
session.removeAttribute("user");
%>
logout success.