SpringMVC——视图解析

一、SpringMVC解析视图概述

  • 不论控制器返回一个String,ModelAndView,View都会转换为ModelAndView对象,由视图解析器解析视图,然后,进行页面的跳转。
    在这里插入图片描述

视图解析源码分析:重要的两个接口View和ViewResolver

  • View视图:
    在这里插入图片描述
  • ViewResolver视图解析器:
    在这里插入图片描述

二、视图和视图解析器

  • 请求处理方法执行完成后,最终返回一个 ModelAndView 对象。对于那些返回 String,View 或 ModeMap 等类型的处理方法,Spring MVC 也会在内部将它们装配成一个 ModelAndView 对象,它包含了逻辑名和模型对象的视图
  • Spring MVC 借助视图解析器(ViewResolver)得到最终的视图对象(View),最终的视图可以是 JSP ,也可能是 Excel、JFreeChart等各种表现形式的视图
  • 对于最终究竟采取何种视图对象对模型数据进行渲染,处理器并不关心,处理器工作重点聚焦在生产模型数据的工作上,从而实现 MVC 的充分解耦

2.1 视图

  • 视图的作用是渲染模型数据,将模型里的数据以某种形式呈现给客户。

  • 为了实现视图模型和具体实现技术的解耦,Spring 在 org.springframework.web.servlet 包中定义了一个高度抽象的 View 接口:
    在这里插入图片描述

  • 视图对象由视图解析器负责实例化。由于视图是无状态的,所以他们不会有线程安全的问题

常用的视图实现类:

在这里插入图片描述

2.2 视图解析器

  • SpringMVC 为逻辑视图名的解析提供了不同的策略,可以在 Spring WEB 上下文中 配置一种或多种解析策略,并指定他们之间的先后顺序。每一种映射策略对应一个具体的视图解析器实现类。
  • 视图解析器的作用比较单一:将逻辑视图解析为一个具体的视图对象。
  • 所有的视图解析器都必须实现 ViewResolver 接口:
    在这里插入图片描述

常用的视图解析器实现类:
在这里插入图片描述

  • 程序员可以选择一种视图解析器或混用多种视图解析器
  • 每个视图解析器都实现了 Ordered 接口并开放出一个 order 属性,可以通过 order 属性指定解析器的优先顺序,order 越小优先级越高
  • SpringMVC 会按视图解析器顺序的优先顺序对逻辑视图名进行解析,直到解析成功并返回视图对象,否则将抛出 ServletException 异常
  • InternalResourceViewResolver
    • JSP 是最常见的视图技术,可以使用 InternalResourceViewResolve作为视图解析器:
      在这里插入图片描述

三、JstlView(国际化)

  • 若项目中使用了JSTL,则SpringMVC 会自动把视图由InternalResourceView转为 JstlView (断点调试,将JSTL的jar包增加到项目中,视图解析器会自动修改为JstlView)

  • 若使用 JSTL 的 fmt 标签则需要在 SpringMVC 的配置文件中配置国际化资源文件

3.1 JstlView使用流程

  1. 配置两个语言的配置文件:(命名规范:基础名_语言代码_国家代码.properties)
    在这里插入图片描述

  2. 增加jstl标签 jar包(断点调试,这时的View对象就是JstlView)
    在这里插入图片描述

  3. 设置国际化资源文件

    <!--让SpringMVC管理国际化资源文件;配置一个资源文件管理器;id是必须叫messageSource  -->
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
    	<!--  basename指定基础名-->
    	<property name="basename" value="i18n"></property>
    </bean>
    
  4. 控制器代码

    @Controller
    public class helloController {
          
          
    	@RequestMapping("toLogin")
    	public String login(){
          
          
    		System.out.println("login...");
    		return "login";
    	}
    }
    
  5. 登录页面(/WEB-INF/pages/login.jsp)使用fmt标签库

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
    	<form action="toLogin">
    		<fmt:message key="username"/><input /><br/>
    		<fmt:message key="password" /><input /><br/>
    		<input type="submit" value="<fmt:message key='loginBtn' />" />
    	</form>
    </body>
    </html>
    

注意点:

  1. 一定要过SpringMVC的视图解析流程,人家会创建一个jstlView帮你快速国际化;不能直接访问登录页面,也不能通过forward访问

    分析源码:
    在这里插入图片描述

3.2 view-controller将请求映射一个页面

  • 若希望直接响应通过 SpringMVC 渲染的页面,可以使用 mvc:view-controller 标签实现

    <!-- 发送一个请求("toLoginPage");直接来到web-inf下的login页面;mvc名称空间下有一个请求映射标签 -->
    <!-- 
    	path="":指定哪个请求
    	view-name:指定映射给哪个视图
    	走了SpringMVC的整个流程,视图解析....不需要再写控制器方法
     -->
    <mvc:view-controller path="/toLogin" view-name="login"/>
    
  • 配置<mvc:view-controller>会导致其他请求路径失效
    解决办法:配置mvc:annotation-driven标签

    <!-- 开启mvc注解驱动模式;开启了mvc的开挂模式 -->
    <mvc:annotation-driven></mvc:annotation-driven>
    

三、forward和redirect

  • 一般情况下,控制器方法返回字符串类型的值会被当成逻辑视图名处理
  • 如果返回的字符串中带forward:redirect:前缀时,SpringMVC 会对他们进行特殊处理:将 forward: 和 redirect: 当成指示符,其后的字符串作为 URL 来处理
  • redirect:success.jsp:会完成一个到 success.jsp 的重定向的操作
  • forward:success.jsp:会完成一个到 success.jsp 的转发操作
  1. forward前缀指定一个转发操作
    /**
     * forward:/hello.jsp
     * 		forward:转发到一个页面
     * 		/hello.jsp:转发到当前项目下的hello
     * 	
     * 	注意:一定加/,如果不加/就是相对路径,容易出问题
     */
    @RequestMapping("/handle01")
    public String handle01(){
          
          
    	System.out.println("handle01");
    	return "forward:/hello.jsp";
    }
    
  2. redirect前缀指定重定向到页面
    /**
     * 重定向到hello.jsp页面
     * 有前缀的转发和重定向操作,配置的视图解析器就不会进行拼串;
     * 
     * 转发	forward:转发的路径
     * 重定向	redirect:重定向的路径
     * 		/hello.jsp:代表就是从当前项目下开始;SpringMVC会为路径自动的拼接上项目名
     * 
     * 		原生的Servlet重定向/路径需要加上项目名才能成功
     * 		response.sendRedirect("/hello.jsp")
     * @return
     */
    @RequestMapping("handle03")
    public String handle03(){
          
          
    	System.out.println("handle03...");
    	return "redirect:/hello.jsp";//请求转发到hello.jsp页面
    }
    

四、自定义视图

  1. 编写自定义的视图解析器,和视图实现类

    控制器方法:

    /**
     * 自定义视图解析器和视图对象
     */
    @Controller
    public class MyViewResolverController {
          
          
    	@RequestMapping("/handleplus")
    	public String handleplus(Model model){
          
          
    		List<String> vname = new ArrayList<String>();
    		List<String> imgname = new ArrayList<String>();
    		vname.add("佟老师");
    		vname.add("康师傅");
    		imgname.add("萌萌");
    		model.addAttribute("video", vname);
    		model.addAttribute("imgs", imgname);
    		return "meinv:/login";
    	}
    }
    

    自定义视图:

    /**
     * 自定义视图
     * @author ZB
     *
     */
    public class MyView implements View {
          
          
    	@Override
    	public String getContentType() {
          
          
    		// TODO Auto-generated method stub
    		return "text/html";
    	}
    
    	@Override
    	public void render(Map<String, ?> model, HttpServletRequest request,
    			HttpServletResponse response) throws Exception {
          
          
    		// TODO Auto-generated method stub
    		
    		System.out.println("进入到自定义视图中:"+model.get("viedo"));
    		response.setContentType("text/html");//设置相应类型
    		response.getWriter().write("<h1>哈哈</h1>");
    	}
    }
    

    自定义视图解析器:

    /**
     * 自定义视图解析器
     * @author ZB
     *
     */
    public class MyMeiNvViewResolver implements ViewResolver {
          
          
    	
    	@Override
    	public View resolveViewName(String viewName, Locale locale)
    			throws Exception {
          
          
    		/**
    		 * 根据视图名返回视图对象
    		 */
    		//处理以meinv为前缀的
    		if(viewName.startsWith("meinv:")){
          
          
    			return new MyView();
    		}else{
          
          
    			//如果不能处理返回null即可
    			return null;
    		}
    	}
    }
    
  2. 视图解析器必须放在ioc容器中,让其工作,能创建出我们的自定义视图对象;

    <bean class="com.zb.view.MyMeiNvViewResolver">
    </bean>
    

输入网址/handleplus,会报404: /05_SpringMVC_viewResolver/WEB-INF/pages/meinv:/login.jsp

debug分析原因:

InternalResourceViewResolver视图解析器位于自定义视图解析器之前解析:导致meinv:/login被InternalResourceViewResolver进行拼串将请求路径拼成了WEB-INF/pages/meinv:/login.jsp,从而出现404
在这里插入图片描述

解决办法:指定视图解析器的优先级

自定义视图解析器实现Ordered的接口:

/**
 * 自定义视图解析器
 * @author ZB
 *
 */
public class MyMeiNvViewResolver implements ViewResolver,Ordered {
    
    
	
	private Integer order;
	
	@Override
	public View resolveViewName(String viewName, Locale locale)
			throws Exception {
    
    
		/**
		 * 根据视图名返回视图对象
		 */
		//处理以meinv为前缀的
		if(viewName.startsWith("meinv:")){
    
    
			return new MyView();
		}else{
    
    
			//如果不能处理返回null即可
			return null;
		}
	}

	@Override
	public int getOrder() {
    
    
		return order;
	}
	
	public void setOrder(Integer order){
    
    
		this.order = order;
	}

}

在spring配置中指定优先级,数字越小优先级越高

<bean class="com.zb.view.MyMeiNvViewResolver">
	<!-- 自定义的视图解析器,value="1"数字越小优先级越高 -->
	<property name="order" value="1"></property>
</bean>

此时:自定义视图解析器优先解析:(得到响应页面)
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_44630656/article/details/115188294