1.视图解析器
请求处理方法执行完成后,最终返回一个 ModelAndView 对象。对于那些返回 String,View 或 ModeMap 等类型的处理方法Spring MVC 也会在内部将它们装配成一个 ModelAndView 对象,它包含了逻辑名和模型对象的视图。
springMVC通过视图解析器ViewResolver得到最终的视图对象View,视图是无状态打所以不会有线程安全问题。
1)org.springframework.web.servlet.view.InternalResourceViewResolver视图解析器
<!-- 视图解析器: 如何把 handler 方法返回值解析为实际的物理视图 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
InternalResourceViewResolver解析器,默认支持JSP视图,JSP最常用的就是JSTL标签库,如果要用jstl标签库还需加上jstl的相关依赖。
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
2) org.springframework.web.servlet.view.BeanNameViewResolver解析器
当我们需要配置自定义视图解析器的时候就可以配置BeanNameViewResolver解析器;
当有多个视图解析器时,通过order属性定义视图解析器的优先级,order值越小优先级越高,InternalResourceViewResolver的order值为Integer的最大值。
<!-- 配置视图 BeanNameViewResolver 解析器: 使用视图的名字来解析视图 -->
<!-- 通过 order 属性来定义视图解析器的优先级, order 值越小优先级越高 -->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
<property name="order" value="100"></property>
</bean>
eg:
package com.atguigu.springmvc.views;
import java.util.Date;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.View;
/**
*
*注意自定义视图解析器需要添加@Component注解否则spring注册不了导致
*BeanNameViewResolver解析器解析不了
*/
@Component
public class HelloView implements View{
@Override
public String getContentType() {
return "text/html";
}
@Override
public void render(Map<String, ?> model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
response.getWriter().print("HelloView, 当前时间为time: " + new Date());
}
}
/**
*测试方法
*/
@RequestMapping("/testView")
public String testView(){
System.out.println("testView");
return "helloView";
}
结果图:
2.文件上传
1)org.springframework.web.multipart.commons.CommonsMultipartResolver文件上传解析器
<!-- 定义文件上传解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设定默认编码 -->
<property name="defaultEncoding" value="UTF-8"></property>
<!-- 设定文件上传的最大值5MB,5*1024*1024 -->
<property name="maxUploadSize" value="5242880"></property>
</bean>
eg:
// 演示:文件上传
@RequestMapping("/fileUpload")
// 通过参数:MultipartFile file来接收上传的文件,这个是SpringMVC中定义的类,会被自动注入
public ModelAndView show21(@RequestParam("file") MultipartFile file) throws Exception {
ModelAndView mv = new ModelAndView("SUCCESS");
if(file != null){
// 将上传得到的文件 转移到指定文件。
file.transferTo(new File("D:/test/" + file.getOriginalFilename()));
}
mv.addObject("msg", "上传成功!" + file.getOriginalFilename());
return mv;
}
3.重定向与转发
一般情况下,控制器方法返回字符串类型的值会被当成逻辑视图名处理,如果返回的字符串中带 forward: 或 redirect: 前缀
时,SpringMVC 会对他们进行特殊处理:将 forward: 和 redirect: 当成指示符,其后的字符串作为 URL 来处理
– redirect:success.jsp:会完成一个到 success.jsp 的重定向的操作
– forward:success.jsp:会完成一个到 success.jsp 的转发操作
DispatcherServlet.class render方法 1204行
第1264行
AbstractCachingViewResolver.class 146行
UrlBasedViewResolver.class
springMVC 中重定向和转发 方法源码
4.拦截器
Spring MVC也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义的拦截器必须实现HandlerInterceptor接口。
自定义拦截器配置
<mvc:interceptors>
<!-- 配置自定义的拦截器 -->
<bean class="com.cqxy.springmvc.interceptors.OneInterceptor"></bean>
<!-- 配置拦截器(不)作用的路径 -->
<mvc:interceptor>
<mvc:mapping path="/test"/>
<bean class="com.cqxy.springmvc.interceptors.TwoInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
package com.cqxy.springmvc.interceptors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class TwoInterceptor implements HandlerInterceptor{
/**
* 该方法在目标方法之前被调用.
* 若返回值为 true, 则继续调用后续的拦截器和目标方法.
* 若返回值为 false, 则不会再调用后续的拦截器和目标方法.
*
* 可以考虑做权限. 日志, 事务等.
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
System.out.println("[TwoInterceptor] preHandle");
return true;
}
/**
* 调用目标方法之后, 但渲染视图之前.
* 可以对请求域中的属性或视图做出修改.
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("[TwoInterceptor] postHandle");
}
/**
* 渲染视图之后被调用. 释放资源
*/
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("[TwoInterceptor] afterCompletion");
}
}
package com.cqxy.springmvc.interceptors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class TwoInterceptor implements HandlerInterceptor{
/**
* 该方法在目标方法之前被调用.
* 若返回值为 true, 则继续调用后续的拦截器和目标方法.
* 若返回值为 false, 则不会再调用后续的拦截器和目标方法.
*
* 可以考虑做权限. 日志, 事务等.
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
System.out.println("[TwoInterceptor] preHandle");
return true;
}
/**
* 调用目标方法之后, 但渲染视图之前.
* 可以对请求域中的属性或视图做出修改.
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("[TwoInterceptor] postHandle");
}
/**
* 渲染视图之后被调用. 释放资源
*/
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("[TwoInterceptor] afterCompletion");
}
}
单个拦截器方法的执行顺序为:preHandle ---->HandlerAdapter#handle--->postHandle------>HandlerAdapter#render-->afterCompletion
多个拦截器执行顺序为:OneInterceptor#preHandle--> TwoInterceptor#preHandle-->HandlerAdapter#handle-->TwoInterceptor#postHandle OneInterceptor#postHandle-->DispatcherServlet#render-->TwoInterceptor#afterCompletion-->OneInterceptor#afterCompletion
当多个拦截器中其中的preHandle方法返回为false时该拦截器的后续方法将不会执行,但是其他拦截器的afterCompletion 方法还是将会执行。
5.异常处理
Spring MVC 通过 HandlerExceptionResolver 处理程序的异常,包括 Handler 映射、数据绑定以及目标方法执行时发生的异常。
HandlerExceptionResolver的实现类:
用法:
主要在单个Controller中 @ExceptionHandler 注解定义的方法。
@ExceptionHandler({RuntimeException.class})
public ModelAndView handleArithmeticException2(Exception ex){
System.out.println("[出异常了]: " + ex);
ModelAndView mv = new ModelAndView("error");
mv.addObject("exception", ex);
return mv;
}
也可以自定义全局异常类 注意类要加上@ControllerAdvice注解
package com.atguigu.springmvc.test;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
@ControllerAdvice
public class SpringMVCTestExceptionHandler {
@ExceptionHandler({ArithmeticException.class})
public ModelAndView handleArithmeticException(Exception ex){
System.out.println("----> 出异常了: " + ex);
ModelAndView mv = new ModelAndView("error");
mv.addObject("exception", ex);
return mv;
}
}
附:
在spring与springmvc进行整合时不能同时配置包扫描,这会导致初始化的时候会创建两次bean
正确配置
<!--
SpringMVC 的 IOC 容器中的 bean 可以来引用 Spring IOC 容器中的 bean.
Spring IOC 容器中的 bean 却不能来引用 SpringMVC IOC 容器中的 bean!
-->
<springmvc.xml>
<context:component-scan base-package="com.cqxy.springmvc" use-default-filters="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation"
expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
<spring.xml>
<context:component-scan base-package="com.cqxy.springmvc">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation"
expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>