SpringInAction笔记(六)—— 渲染Web视图(下) - Go语言中文社区

SpringInAction笔记(六)—— 渲染Web视图(下)


3、使用Apache Tiles视图定义布局
       使用布局引擎,如Apache Tiles,定义适用于所有页面的通用页面布局。Spring MVC以视图解析器的形式为Apache Tiles提供了支持,这个视图解析器能够将逻辑视图名解析为Tile定义。
       需导入Tiles相关的jar包:
  tiles-api-3.0.8.jar
  tiles-core-3.0.8.jar
  tiles-jsp-3.0.8.jar
  tiles-servlet-3.0.8.jar
  tiles-template-3.0.8.jar
       slf4j-api-1.7.25  (java.lang.ClassNotFoundException: org.slf4j.LoggerFactory)
       commons-digester-2.1 (java.lang.ClassNotFoundException: org.apache.commons.digester.Rule)
       commons-beanutils-1.9.3 (ClassNotFoundException: org.apache.commons.beanutils.MethodUtils)
       tiles-request-api-1.0.7.(java.lang.NoClassDefFoundError: org/apache/tiles/request/render/Renderer)
       tiles-request-servlet-1.0.7.(ClassNotFoundException: org.apache.tiles.request.servlet.ServletApplicationContext)
       tiles-request-jsp-1.0.7 (ClassNotFoundException: org.apache.tiles.request.jsp.autotag.JspAutotagRuntime)
       tiles-autotag-core-runtime-1.2 (ClassNotFoundException: org.apache.tiles.autotag.core.runtime.AutotagRuntime)

3.1 配置Tiles视图解析器
       为了在Spring中使用Tiles,需要配置几个bean。我们需要一个TilesConfigurer bean,它会负责定位和加载Tile定义并协调生成Tiles。除此之外,还需要TilesViewResolver bean将逻辑视图名称解析为Tile定义。
       这两个组件又有两种形式:针对Apache Tiles 2和Apache Tiles 3分别都有这么两个组件。这两组Tiles组件之间最为明显的区别在于包名。针对Apache Tiles 2的TilesConfigurer/TilesViewResolver位于org.springframework.web.servlet.view.tiles2包中,而针对Tiles 3的组件位于org.springframework.web.servlet.view.tiles3包中。对于该例子来讲,我们使用的是Tiles 3。

 

WebConfig.java:

 

package spittr.config;

import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.tiles3.TilesConfigurer;
import org.springframework.web.servlet.view.tiles3.TilesViewResolver;

@Configuration
@EnableWebMvc  //启用Spring Mvc
@ComponentScan("spittr.web")
public class WebConfig extends WebMvcConfigurerAdapter {

	/**
	 * 配置Tiles视图解析器
	 * @return
	 */
	@Bean
	public ViewResolver viewResolver() {	
		return new TilesViewResolver();
	}
	  
	// Tiles 
	@Bean	  
	public TilesConfigurer tilesConfigurer() {
	    TilesConfigurer tiles = new TilesConfigurer();
	    tiles.setDefinitions(new String[] {
	        "/WEB-INF/layout/tiles.xml",
	    });
	    //启用刷新功能
	    tiles.setCheckRefresh(true);
	    return tiles;	  
	}

	/**
	 * 配置静态资源的处理
	 * 此配置要求DispatcherServlet将对静态资源的请求转发到Servlet容器中默认的Servlet上,
	 * 而非使用DispatcherServlet本身来处理此类请求
	 */
	@Override
	public void configureDefaultServletHandling(
			DefaultServletHandlerConfigurer configurer) {
		// TODO Auto-generated method stub
		//super.configureDefaultServletHandling(configurer);
		configurer.enable();
	}	
	  
	@Bean	  
	public MessageSource messageSource() {
	    ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
	    messageSource.setBasename("/resources/messages");
	    messageSource.setCacheSeconds(10);
	    return messageSource;	  
	}
	
}

当配置TilesConfigurer的时候,所要设置的最重要的属性就是definitions。这个属性接受一个String类型的数组,其中每个条目都指定一个Tile定义的XML文件。对于Spittr应用来讲,我们让它在“/WEB-INF/layout/”目录下查找tiles.xml。

       还可以指定多个Tile定义文件,甚至能够在路径位置上使用通配符,当然在上例中我们没有使用该功能。例如,我们要求TilesConfigurer加载“/WEB-INF/”目录下的所有名字为tiles.xml的文件,那么可以按照如下的方式设置definitions属性:

	    tiles.setDefinitions(new String[] {
	        "/WEB-INF/**/tiles.xml",
	    });

       接下来配置TilesViewResolver,可以看到,这是一个很基本的bean定义,没有什么要设置的属性:

	@Bean
	public ViewResolver viewResolver() {	
		return new TilesViewResolver();
	}


定义Tiles
        Apache Tiles提供了一个文档类型定义(document type definition,DTD),用来在XML文件中指定Tile的定义。每个定义中需要包含一个<definition>元素,这个元素会有一个或多个<putattribute>元素。例如,如下的XML文档为Spittr应用定义了几个Tile。

 

        程序清单6.2 WEB-INF/layout/tiles.xml:

 

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>

  <!-- 定义base Tile -->
  <definition name="base" template="/WEB-INF/layout/page.jsp">
    <put-attribute name="header" value="/WEB-INF/layout/header.jsp" />
    <put-attribute name="footer" value="/WEB-INF/layout/footer.jsp" />
  </definition>

  <!-- 扩展base -->
  <definition name="home" extends="base">
    <put-attribute name="body" value="/WEB-INF/views/home.jsp" />
  </definition>

  <definition name="registerForm" extends="base">
    <put-attribute name="body" value="/WEB-INF/views/registerForm.jsp" />
  </definition>

  <definition name="profile" extends="base">
    <put-attribute name="body" value="/WEB-INF/views/profile.jsp" />
  </definition>

  <definition name="spittles" extends="base">
    <put-attribute name="body" value="/WEB-INF/views/spittles.jsp" />
  </definition>

  <definition name="spittle" extends="base">
    <put-attribute name="body" value="/WEB-INF/views/spittle.jsp" />
  </definition>

</tiles-definitions>

       每个<definition>元素都定义了一个Tile,它最终引用的是一个JSP模板。在名为base的Tile中,模板引用的是“/WEBINF/
layout/page.jsp”。某个Tile可能还会引用其他的JSP模板,使这些JSP模板嵌入到主模板中。对于base Tile来讲,它引用的是一个头部JSP模板和一个底部JSP模板。

       程序清单6.3 主布局模板page.jsp:引用其他模板来创建视图

<%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="t" %>
<%@ page session="false" %>
<html>
  <head>
    <title>Spittr</title>
    <link rel="stylesheet" 
          type="text/css" 
          href="<s:url value="/resources/style.css" />" >
  </head>
  <body>
    <!-- 插入头部 -->
    <div id="header">
      <t:insertAttribute name="header" />
    </div>
    <!-- 插入主题内容 -->
    <div id="content">
      <t:insertAttribute name="body" />
    </div>
    <!-- 插入底部 -->
    <div id="footer">
      <t:insertAttribute name="footer" />
    </div>
  </body>
</html>

使用Tile标签库中的<t:insert Attribute> JSP标签来插入其他的模板,在这里,用它来插入名为header、body和footer的模板.

        在base Tile定义中,header和footer属性分别被设置为引用“/WEBINF/layout/ header. jsp”和“/WEB-INF/layout/footer.jsp”。但是body属性呢?它是在哪里设置的呢?
       base Tile不会期望单独使用,它会作为基础定义,供其他的Tile定义扩展。在程序清单6.2的其余内容中,可以看到其他的Tile定义都是扩展自base Tile。它意味着它们会继承其header和footer属性的设置(当然,Tile定义中也可以覆盖掉这些性),但是每一个都设置了body属性,用来指定每个Tile特有的JSP模板。

       关注home Tile,它扩展了base。因为它扩展了base,因此它会继承base中的模板和所有的属性。尽管home Tile定义相对来说很简单,但是它实际上包含了如下的定义:

  <definition name="home" extends="base">
    <put-attribute name="header" value="/WEB-INF/layout/header.jsp" />
    <put-attribute name="footer" value="/WEB-INF/layout/footer.jsp" />
    <put-attribute name="body" value="/WEB-INF/views/home.jsp" />
  </definition>

 

属性所引用的每个模板是很简单的,如下是header.jsp模板:

 

<%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>
<a href="<s:url value="/" />"><img 
    src="<s:url value="/resources" />/images/spitter_logo_50.png" 
    border="0"/></a>

 

footer.jsp模板更为简单:

 

Copyright &copy; Craig Walls

 

每个扩展自base的Tile都定义了自己的主体区模板,所以每个都会与其他的有所区别。

 

home.jsp:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<h1>Welcome to Spitter</h1>

<a href="<c:url value="/spittles" />">Spittles</a> | 
<a href="<c:url value="/spitter/register" />">Register</a>


这里的关键点在于通用的元素放到了page.jsp、header.jsp以及footer.jsp中,其他的Tile模板中不再包含这部分内容。这使得它们能够跨页面重用,这些元素的维护也得以简化。

运行结果:

 


 

 

4、使用Thymeleaf
        多年来,在Java应用中,有多个项目试图挑战JSP在视图领域的统治 性地位。最新的挑战者是Thymeleaf,它展现了一些切实的承诺,是 一项很令人兴奋的可选方案。Thymeleaf模板是原生的,不依赖于标签库。它能在接受原始HTML的地方进行编辑和渲染。因为它没有与 Servlet规范耦合,因此Thymeleaf模板能够进入JSP所无法涉足的领域。
4.1 配置Thymeleaf视图解析器
        为了要在Spring中使用Thymeleaf,我们需要配置三个启用Thymeleaf与 Spring集成的bean:
        (1)ThymeleafViewResolver:将逻辑视图名称解析为Thymeleaf 模板视图;
        (2)SpringTemplateEngine:处理模板并渲染结果;
        (3)TemplateResolver:加载Thymeleaf模板。
需要引入以下jar包:
    thymeleaf-3.0.9
    thymeleaf-spring4-3.0.9
    attoparser-2.0.4
    unbescape-1.1.5

 

 

清单 WebConfig.java:

 

 

package spittr.config;

import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.thymeleaf.spring4.SpringTemplateEngine;
import org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring4.view.ThymeleafViewResolver;
import org.thymeleaf.templateresolver.ITemplateResolver;

@Configuration
@EnableWebMvc  //启用Spring Mvc
@ComponentScan("spittr.web")
public class WebConfig extends WebMvcConfigurerAdapter {

	/**
	 * 配置Thymeleaf视图解析器
	 * @return
	 */
	@Bean
	public ThymeleafViewResolver viewResolver(SpringTemplateEngine templateEngine) {	
	    ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
	    viewResolver.setTemplateEngine(templateEngine);
	    return viewResolver;
	}
	
	/**
	 * 模板引擎,处理模板并渲染结果
	 * @param templateResolver
	 * @return
	 */
	@Bean	  
	public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
	    SpringTemplateEngine templateEngine = new SpringTemplateEngine();
	    templateEngine.setTemplateResolver(templateResolver);
	    return templateEngine;  
	}
	
	/**
	 * 模板解析器
	 * @return
	 */
	@Bean  
	public ITemplateResolver templateResolver() {
		// SpringResourceTemplateResolver自动与Spring自己集成, 资源解决基础设施, 强烈推荐。
		SpringResourceTemplateResolver  templateResolver = new SpringResourceTemplateResolver ();
	    templateResolver.setPrefix("/WEB-INF/views/");
	    templateResolver.setSuffix(".html");
	    //要解析的模板会渲染成HTML5输出
	    templateResolver.setTemplateMode("HTML5");
	    // 默认情况下, 模板缓存为true。如果您想要设置为false。模板在修改时自动更新。
	    templateResolver.setCacheable(true);
	    return templateResolver;	  
	}

	/**
	 * 配置静态资源的处理
	 * 此配置要求DispatcherServlet将对静态资源的请求转发到Servlet容器中默认的Servlet上,
	 * 而非使用DispatcherServlet本身来处理此类请求
	 */
	@Override
	public void configureDefaultServletHandling(
			DefaultServletHandlerConfigurer configurer) {
		// TODO Auto-generated method stub
		//super.configureDefaultServletHandling(configurer);
		configurer.enable();
	}	
	  
	@Bean	  
	public MessageSource messageSource() {
	    ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
	    messageSource.setBasename("/resources/messages");
	    messageSource.setCacheSeconds(10);
	    return messageSource;	  
	}
	
}

ThymeleafViewResolver是Spring MVC中ViewResolver的一个实现类。像其他的视图解析器一样,它会接受一个逻辑视图名称,并 将其解析为视图。不过在该场景下,视图会是一个Thymeleaf模板。       

   需要注意的是ThymeleafViewResolver bean中注入了一个对 SpringTemplate Engine bean的引用。SpringTemplateEngine会在Spring中启用Thymeleaf引擎,用来解析模板,并基于这些模板渲染结果。可以看到,我们为其注入了一个TemplateResolver bean的引用。      

      TemplateResolver会最终定位和查找模板。与之前配 置InternalResource-ViewResolver类似,它使用了prefix和suffix属性。前缀和后缀将会与逻辑视图名组合使用,进而定位Thymeleaf引擎。它的templateMode属性被设置成了HTML 5,这表明我们预期要解析的模板会渲染成HTML 5输出。

 

4.2 定义Thymeleaf模板        

Thymeleaf在很大程度上就是HTML文件,与JSP不同,它没有什么特 殊的标签或标签库。Thymeleaf之所以能够发挥作用,是因为它通过 自定义的命名空间,为标准的HTML标签集合添加Thymeleaf属性。如下的程序清单展现了home.html,也就是使用Thymeleaf命名空间的首页模板。

清单 home.html:      

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Spitter</title>
    <link rel="stylesheet" 
          type="text/css" 
          th:href="{/resources/style.css}"></link>
  </head>
  <body>
    <div id="header" th:include="page :: header"></div>
  
    <div id="content">
      <h1>Welcome to Spitter</h1>
  
      <a th:href="@{/spittles}">Spittles</a> | 
      <a th:href="@{/spitter/register}">Register</a>
      
      <br/>
      
      View: <span th:text="${view}">unknown</span>
    </div>
    <div id="footer" th:include="page :: copy"></div>
  </body>
</html>

 

首页模板相对来讲很简单,只使用了th:href属性。这个属性与对 应的原生HTML属性很类似,也就是href属性,并且可以按照相同的方式来使用。th:href属性的特殊之处在于它的值中可以包含Thymeleaf表达式,用来计算动态的值。它会渲染成一个标准的href 属性,其中会包含在渲染时动态创建得到的值。

 

       “@{}”表达式用来计算相对于 URL的路径(就像在JSP页面中,我们可能会使用的JSTL <c:url>标 签或Spring<s:url>标签类似)。


借助Thymeleaf实现表单绑定
       表单绑定是Spring MVC的一项重要特性。它能够将表单提交的数据填充到命令对象中,并将其传递给控制器,而在展现表单的时候,表单 中也会填充命令对象中的值。如果没有表单绑定功能的话,我们需要确保HTML表单域要映射后端命令对象中的属性,并且在校验失败后 展现表单的时候,还要负责确保输入域中值要设置为命令对象的属 性。

 

       作为阐述的样例,请参考如下的Thymeleaf模板片段,它会渲染First Name输入域:

 

        <label th:class="${#fields.hasErrors('firstName')}? 'error'">First Name</label>: 
          <input type="text" th:field="*{firstName}"  
                 th:class="${#fields.hasErrors('firstName')}? 'error'" /><br/>

       在这里,我们不再使用Spring JSP标签中的cssClassName属性,而是在标准的HTML标签上使用th:class属性。th:class属性会渲染为一个class属性,它的值是根据给定的表达式计算得到的。在上面的这两个th:class属性中,它会直接检查firstName域有没有校验错误。如果有的话,class属性在渲染时的值为error。如果这 个域没有错误的话,将不会渲染class属性。
       <input>标签使用了th:field属性,用来引用后端对象的 firstName域。
 

清单  /spittr/WebRoot/WEB-INF/views/registerForm.html:

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Spitter</title>
    <link rel="stylesheet" type="text/css" 
          th:href="{/resources/style.css}"></link>
  </head>
  <body>
    <div id="header" th:include="page :: header"></div>

    <div id="content">
      <h1>Register</h1>
  
      <form method="POST" th:object="${spitter}">
        <div class="errors" th:if="${#fields.hasErrors('*')}">
          <ul>
            <li th:each="err : ${#fields.errors('*')}" 
                th:text="${err}">Input is incorrect</li>
          </ul>
        </div>
        <label th:class="${#fields.hasErrors('firstName')}? 'error'">First Name</label>: 
          <input type="text" th:field="*{firstName}"  
                 th:class="${#fields.hasErrors('firstName')}? 'error'" /><br/>
  
        <label th:class="${#fields.hasErrors('lastName')}? 'error'">Last Name</label>: 
          <input type="text" th:field="*{lastName}"
                 th:class="${#fields.hasErrors('lastName')}? 'error'" /><br/>
  
        <label th:class="${#fields.hasErrors('email')}? 'error'">Email</label>: 
          <input type="text" th:field="*{email}"
                 th:class="${#fields.hasErrors('email')}? 'error'" /><br/>
  
        <label th:class="${#fields.hasErrors('username')}? 'error'">Username</label>: 
          <input type="text" th:field="*{username}"
                 th:class="${#fields.hasErrors('username')}? 'error'" /><br/>
  
        <label th:class="${#fields.hasErrors('password')}? 'error'">Password</label>: 
          <input type="password" th:field="*{password}"  
                 th:class="${#fields.hasErrors('password')}? 'error'" /><br/>
        <input type="submit" value="Register" />
      
      
      </form>
    </div>
    <div id="footer" th:include="page :: copy"></div>
  </body>
</html>


运行结果:

 

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/ganmaotong/article/details/80377215
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-02-13 13:59:23
  • 阅读 ( 1045 )
  • 分类:Go Web框架

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢