请求转发
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
@RequestMapping(value = "view")
public ModelAndView view(HttpServletRequest request) {
ModelAndView mv = new ModelAndView();
mv.setViewName("index"); //视图名
mv.addObject("name", "ljh");
return mv;
}
根据配置可以转到/WEB-INF/jsp/index.jsp文件,通过请求转发(forward)的方式跳转,所带的参数其实是通过
request.setAttribute("name","ljh")
的方式带给index.jsp的。
@RequestMapping("view2")
public String view2(){
return "index";
}
这也是通过forward方式转发到index.jsp页面。如果想转发到view.do这个url,可以这样写,
return "forward:view.do";
Springmvc维护了几个视图参数:(ModelAndView)视图+数据模型、(ModelMap、Model)数据模型,直接写成入参就可以使用,例如:
public String view3(Model model)
,实际上ModelMap和Model都是BindingAwareModelMap的实例,它们之间的关系图如下:
ModelAndView初始化后,model属性为空,当调用它增加数据模型的方法后,会自动创建一个ModelMap实例并给model属性赋值,用以保存数据模型。例如:
@RequestMapping("view6")
public ModelAndView view6(Model model){
ModelAndView mv = new ModelAndView();
mv.setViewName("index");
model.addAttribute("age",18);
return mv;
}
这种是
无法正常返回
数据模型的:
@RequestMapping("view4")
public String view4(){
ModelAndView mv = new ModelAndView();
mv.addObject("name", "ljh");
return "index";
}
可以正常转发到index.jsp页面,但是无法获取其中的name数据属性。但是可以通过
request.getAttribute("modelAndView")
获取返回的数据模型。
下面这种就可以
正常返回
视图数据:
@RequestMapping("view5")
public String view5(ModelMap mv) {
mv.addAttribute("email", "@163");
return "index";
}
如果返回的ModelAndView视图数据模型对象没有设置view属性,或者返回的String对象为null,则将对应请求url的值作为视图名。
@RequestMapping("view10")
public ModelAndView view10(){
ModelAndView mv = new ModelAndView();
mv.addObject("key", "value");
return mv;
}
或者
@RequestMapping("view10")
public String view10(){
return null;
}
最终都是转发到
/WEB-INF/jsp/view10.jsp
。
重定向
转发是通过服务器内部进行的,浏览器地址栏不会改变,并且可以访问WEB-INF目录下的文件,但是通过请求重定向却不可以。原因很简单,就是因为它是浏览器的访问。重定向是通过在响应头中添加Location字段,告诉浏览器去请求Location这个地址,浏览器会通过get去请求,浏览器地址栏会改变,并且不能往请求中放对象。
@RequestMapping("view6")
public String view6(ModelMap modelMap) {
modelMap.addAttribute("param", "value");
return "redirect:view5.do";
}
地址栏最后的数据
/view5.do?param=value
,view5中可以通过
request.getParameter("param")
方式获取get请求中值。
@RequestMapping("view7")
public ModelAndView view7(ModelMap modelMap) {
ModelAndView mv = new ModelAndView();
mv.setViewName("redirect:view5.do");
modelMap.addAttribute("score", 98);
return mv;
}
地址栏最后的数据
/view5.do?score=98
那么重定向时怎么才能传递对象呢?SpringMVC提供了RedirectAttributes接口,它继承Model接口,唯一的实现类RedirectAttributesModelMap继承ModelMap。
主要用到两个方法:
RedirectAttributes addAttribute(String var1, Object var2);
会自动添加参数到url上,同样不能是对象,var2需要可以转换成String类型。
RedirectAttributes addFlashAttribute(String var1, Object var2);
可以添加对象并保存,给重定向的请求获取。
例如:
@RequestMapping("view8")
public ModelAndView view8(RedirectAttributes ra) {
ra.addAttribute("param", "value");
ra.addFlashAttribute("object", new Integer(3));
ModelAndView mv = new ModelAndView();
mv.setViewName("redirect:view5.do");
return mv;
}
ra.addFlashAttribute("object", new Integer(3));
实际存储的属性在flashmap,那么flashmap又是什么呢?
Flash 属性 和 RedirectAttributes:通过FlashMap存储一个请求的输出,当进入另一个请求时作为该请求的输入,典型场景如重定向(POST-REDIRECT-GET模式,1、POST时将下一次需要的数据放在FlashMap;2、重定向;3、通过GET访问重定向的地址,此时FlashMap会把1放到FlashMap的数据取出放到请求中,并从FlashMap中删除;从而支持在两次请求之间保存数据并防止了重复表单提交)。 SpringMVC提供FlashMapManager用于管理FlashMap,默认使用SessionFlashMapManager,即数据默认存储在session中,但是键值并不是我们add的,而是系统指定的。
在HandlerAdapter执行完getModelAndView(ModelAndViewContainer mavContainer,ModelFactory modelFactory, NativeWebRequest webRequest)方法后,会将RedirectAttributes的属性值放入request中,在之后的视图渲染时将这个数据从request中取出加入session中,在重定向的下一次请求中DispatcherServlet的doService方法往request中添加。
下面提供两个方法把addFlashAttribute中的数据提取出来。
public String test1(HttpServletRequest request) {
Map<String,?> map = RequestContextUtils.getInputFlashMap(request);
Object o = map.get("object");
return "";
}
public String test2(@ModelAttribute("object") Object o) {
return "";
}
**注意:**要想使用RedirectAttributes,必须在servlet配置文件中配置:
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"
<mvc:annotation-driven/>
重定向的中文参数乱码问题:
重定向时如果需要在url之后传递参数,那么需要考虑编码的问题。默认情况下是按照”ISO-8859-1″的编码格式,也可以通过给请求设置编码格式设置,如
request.setCharacterEncoding("UTF-8")
。
发送重定向数据时编码:
URLEncoder.encode("中文",encode)
;
接受数据时解码:
URLDecoder.decode(param, encode)
。
视图和视图解析器
视图对象需要实现View接口:
public interface View {
//响应状态属性
String RESPONSE_STATUS_ATTRIBUTE = View.class.getName() + ".responseStatus";
//定义数据模型下取出变量路径
String PATH_VARIABLES = View.class.getName() + ".pathVariables";
//选择响应内容类型
String SELECTED_CONTENT_TYPE = View.class.getName() + ".selectedContentType";
//响应客户端的类型
String getContentType();
//渲染方法,model是数据模型
void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
}
当控制器返回ModelAndView的时候,视图解析器将数据模型传递给render方法并解析,以得到渲染视图。
SpringMVC的常用视图类:
如果只想返回Json数据,可以使用Json视图,设置view属性。
@RequestMapping("view9")
public ModelAndView view9(){
ModelAndView mv = new ModelAndView();
mv.setView(new MappingJackson2JsonView());
mv.addObject("key", "value");
return mv;
}
视图解析器配置完成后,会加载到SpringMVC的视图解析器列表中,当返回ModelAndView的时候,就会去列表中查找对应的解析器解析视图。为什么返回一个字符串或者setViewName(“…”)的时候可以返回一个视图呢?因为配置了视图解析器InternalResourceViewResolver,通过分析字符串,forward:或者redirect:开头,确定返回的视图,然后结合数据模型渲染出页面。