Spring Boot视图技术

Posted shi_zi_183

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Boot视图技术相关的知识,希望对你有一定的参考价值。

Spring Boot视图技术

在一个Web应用中,通常会采用MVC设计模式实现对应的模型、视图和控制器,其中。视图是用户看到并与之交互的界面。对最初的Web应用来说,视图是由html元素组成的静态界面;而后期的Web应用更倾向于使用动态模板技术,从而实现前后端分离和页面的动态数据展示。Spring Boot框架为简化项目的整体开发,提供了一些视图技术支持,并主要推荐整合模板引擎技术实现前端页面的动态化内容。

Spring Boot支持的视图技术

前端模板引擎技术的出现,使前端开发人员无需关注后端业务的具体实现,只关注自己页面的呈现效果即可,从而解决了前端代码错综复杂的问题、实现了前后端分离开发。Spring Boot对很多模板引擎技术支持
1)FreeMarker:FreeMarker是一个基于模板生成输出文件文本(HTML页面、电子邮件,配置文件等)的模板引擎,它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入所开发产品的组件。
2)Groovy:Groovy是一种基于JVM的敏捷开发语言,它结合了Python、Ruby和Smalltalk的许多强大特性,能够与Java代码很好地结合,也能扩展现有代码。Groovy运行在JVM上,它可以使用Java语言编写的其他库。
3)Thymeleaf:它是一种用于Web和独立环境的现代服务器端的Java模板引擎,其主要目标是将优雅的Java模板带到开发工作流程中,将HTML在浏览器中正确显示,并且可以作为静态原型,让开发团队能够更容易地协作。Thymeleaf能够处理HTML,XML,javascript,CSS甚至纯文本。
4)Mustache:Mustache是轻逻辑地模板引擎(Logic-less templates),它是一个模板,用于对JS进行分离展示。Mustache地优势在于可以应用在JavaScript、php、Python、Perl等多种编程语言中。
Spring Boot不太支持常用地JSP模板,并且没有提供对应的整合配置,这是因为嵌入式Servlet容器的Spring Boot应用程序对于JSP模板存在一些限制

  • Spring Boot默认使用的嵌入式Servlet容器以JAR包的方式进行项目打包部署。JAR包方式不支持JSP模板。
  • 使用Undertow嵌入式容器部署Spring Boot项目时,不支持JSP模板。
  • Spring Boot默认提供了一个处理请求路径"/error"的统一错误处理器,返回具体异常信息。使用JSP模板时,无法使用Spring Boot自带的异常处理器,只能根据要求在Spring项目的指定位置定制错误页面。
    在使用Spring Boot框架进行Web应用开发时,可以选择使用传统的Spring MVC框架进行整合开发,也可以使用Spring 5之后出现的Spring WebFlux框架(异步交互)进行整合开发。针对于熟悉的MVC框架整合实现,Spring Boot实现了于FreeMarker、Groovy、Thymeleaf和Mustache前端模板技术的整合和自动化配置;针对于WebFlux框架的整合实现,Spring Boot则实现了与FreeMarker、Thymeleaf和Mustache前端模板引擎技术的整合支持和自动化配置。而这里Web开发都是添加Web模板下的Web依赖、使用传统的MVC框架进行整合讲解;

Thymeleaf基本语法

Thymeleaf是一种现代的基于服务器端的Java模板引擎技术,也是一个优秀的面向Java的XML、XHTML、HTML5页面模板,它具有丰富的标签语言、函数和表达式,在使用Spring Boot框架进行页面设计时,一般会选择Thymeleaf模板。

常用标签

在HTML页面上使用Thymeleaf标签,Thymeleaf标签能够动态地替换掉静态内容,动态显示页面内容。

<!DOCTYPE html>
<html lang="en" lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" type="text/css" media="all" th:href="@{/css/gtvg.css}"/>
    <title>Title</title>
</head>
<body>
    <p th:text="#{hello}">欢迎进入Thymeleaf的学习</p>
</body>
</html>

上述代码中,"xmlns:th="http://www.thymeleaf.org"用于引入Thymeleaf模板引擎,关键字"th"标签是Thymeleaf模板提供的标签,其中,"th:href"用于引入外联样式文件,"th:text"用于动态显示标签文本内容。除此之外,Thymeleaf模板提供了很多标签,接下来我们通过一张表罗列Thymeleaf的常用标签。

th:标签说明
th:insert页面片段包括(类似JSP的include标签)
th:replace页面片段包括(类似JSP中的include标签)
th:each元素遍历(类似JSP中的c:forEach标签)
th:if条件判断,条件成立时显示th标签的内容
th:unless条件判断,条件不成立时显示th标签的内容
th:swith条件判断,进行选择性匹配
th:caseth:swith分支的条件判断
th:object用于替换对象
th:with用于定义局部变量
th:attr通用属性修改
th:attrprepend通用属性修改,将计算结果追加前缀到现有属性值
th:attrappend通用属性修改,将计算结果追加后缀到现有属性值
th:value属性值修改,指定标签属性值
th:href用于设定链接地址
th:src用于设定链接地址
th:text用于指定标签显示的文本内容
th:utext用于指定标签显示的文本内容,对于特殊标签不转义
th:fragment声明片段
th:remove移除片段

需要说明的是,上述操作是以HTML为基础嵌入了Thymeleaf模板引擎,并使用th:*属性进行了页面需求开发。这种Thymeleaf模板页面虽然与纯HTML页面基本相似,但已经不是一个标准的HTML5页面了,这是因为在Thymeleaf页面中使用的th:*属性是HTML5规范所不允许的。如果我们想要使用Thymeleaf页面进行纯HTML5的页面开发,可以使用data-th-*属性替换th:*属性进行页面开发

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" type="text/css" media="all" data-th-href="@{/css/gtvg.css}"/>
    <title>Title</title>
</head>
<body>
    <p data-th-text="#{hello}">欢迎进入Thymeleaf的学习</p>
</body>
</html>

上述代码中,使用标准HTML5语法格式嵌入了Thymeleaf模板引擎进行页面动态数据展示。在使用data-th-*属性时,不需要引入Thymeleaf标签,并且属性名要使用data-th-*的形式。不过使用这种方式不会出现属性的快捷提示,对于开发来说比较麻烦,因此在实际开发中,相对推荐使用Thymeleaf标签的形式进行模板引擎页面的开发。
注:Thymeleaf支持处理6种模板视图,包括HTML、XML、TEXT、JAVASCRIPT、CSS和RAW。本章主要讲解Thymeleaf对HTML页面的嵌入处理,Thymeleaf对其他模板使徒的嵌入方法略有不同。

标准表达式

Thymeleaf模板引擎提供了多种标签表达式语法

说明表达式语法
变量表达式${…}
选择变量表达式*{…}
消息表达式#{…}
链接URL表达式@{…}
片段表达式~{…}

除此之外Thymeleaf还提供了更多语法支持,例如文本表达式、算数表达式、布尔表达式、比较表达式等。
变量表达式
变量表达式主要用于获取上下文中的变量值

<p th:text="${titile}">这是标题</p>

上述示例使用了Thymeleaf模板的变量表达式${...}用来动态获取p标签种的内容,如果当前程序没有启动或者当前上下文中不存在title变量,该片段会显示标签默认“这是标题”;如果当前上下文中存在title变量并且程序已经启动,当前p标签中的默认文本内容会被title变量的值所替换,从而达到模板引擎页面数据动态替换的效果。
同时,Thymeleaf为变量所在域提供了一些内置对象
1)#ctv:上下文对象
2)#vars:上下文变量
3)#locale:上下文区域设置
4)#request:(仅限 Web Context)HttpServletRequest对象
5)#response:(仅限 Web Context)HttpServletResponse对象
6)#session:(仅限 Web Context)HttpSession对象
7)#servletContext:(仅限Web Context)ServletContext对象

结合上述内置对象的说明,假设要在Thymeleaf模板引擎页面中动态获取当前国家信息,可以使用#locale内置对象

The locale country is: <span th:text="${#locale.country}">US</span>.

上述代码中,使用th:text="${#locale.country}"动态获取当前当前用户所在国家信息,其中<span>标签内默认内容为US,程序启动会通过浏览器查看当前页面时,Thymeleaf会通过浏览器语言设置来识别当前用户所在国家信息,从而实现动态替换。
选择变量表达式
选择变量表达式和变量表达式用法类似,一般用于从被选定对象而不是上下文中获取属性值,如果没有选定对象,则和变量表达式一样,示例代码如下。

<div th:object="${session.user}">
	<p>Name:<span th:text="${#object.firstName}">Sebastian</span>.</p>
	<p>Surname:<span th:text="${session.user.lastName}">Pepper</span>.</p>
	<p>Nationality:<span th:text="*{nationality}">Saturn</span>.</p>
</div>

上述代码中,${#object.firstName}变量表达式使用Thymeleaf模板提供的内置对象object获取当前上下文对象中的firstName属性值;${session.user.lastName}变量表达式获取当前user对象的lastName属性值;*{nationality}选择变量表达式获取当前指定对象user的nationality属性值。
消息表达式
消息表达式#{...}主要用于Thymeleaf模板页面国际化内容的动态替换和展示。使用消息表达式#{...}进行国际化设置时,还需要提供一些国际化配置文件。
链接表达式
链接表达式@{...}一般用于页面跳转或者资源的引入,在Web开发中占据着非常重要的地位,并且使用也非常频繁

<a href="details.html" th:href="@{http://localhost:8080/gtvg/order/details(orderId=${o.id}})}">view</a>
<a href="details.html" th:href="@{/order/details(orderId=${0.id})}">view</a>

上述代码中,连接表达式@{...}分别编写了绝对链接地址和相对链接地址。在有参表达式中需要按照@{路径(参数名称=参数值,参数名称=参数值...)}的形式编写,同时该参数的值可以使用变量表达式来传递动态参数值。
片段表达式
片段表达式~{...}是一种用来将标记片段移动到模板中的方法。其中,最常见的用法是使用th:insert或th:replace属性插入片段。

<div th:insert="~{thymeleafDemo::title}"></div>

上述代码中,使用th:insert属性将title片段模板引用到该div标签中。thymeleafDemo为模板名称,Thymeleaf会自动查找classpath:/resources/templates/目录下的thymeleafDemo模板,title为声明的片段名称。

Thymeleaf基本用法

Thymeleaf模板基本配置

在Spring Boot项目中使用Thymeleaf模板,首先必须保证引入Thymeleaf依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

其次,在全局配置文件中配置Thymeleaf模板的一些参数。一般Web项目都会使用下列配置。

server.port= 8080
server.servlet.context-path= /chapter03
spring.thymeleaf.cache= true #启用模板缓存
spring.thymeleaf.encoding= UTF-8 #模板编码
spring.thymeleaf.mode= HTML5 #应用于模板的模板模式
spring.thymeleaf.prefix= classpath:/resouces/templates/ #指定模板页面存放路径
spring.thymeleaf.suffix= .html #指定模板页面名称的后缀

上述配置中,spring.thymeleaf.cache表示是否开启Thymeleaf模板缓存,默认为true,在开发过程中通常会关闭缓存,保证项目调试过程中数据能够及时响应;spring.thymeleaf.prefix指定了Thymeleaf模板页面的存放路径,默认为classpath:/templates;spring.thymeleaf.suffix指定了Thymeleaf模板页面的名称后缀,默认为.html

静态资源的访问

开发Web应用时,难免需要使用静态资源。Spring Boot默认设置了静态资源的访问路径,默认将/**所有访问映射到以下目录。
1)classpath:/META-INF/resources/:项目类路径下的META-INF文件夹下的resources文件夹下的所有文件。
2)classpath:/resources/:项目类路径下的resources文件夹下的所有文件。
3)classpath:/static/:项目类路径下的static文件夹下的所有文件。
4)classpath:/public/:项目类路径下的public文件夹下的所有文件。
使用Spring Initializr方式创建的Spring Boot项目会默认生成一个resources目录,在resources目录中新建public、resources、static3个子目录,Spring Boot默认会依次从public、resources、static里面查找静态资源。

使用Thymeleaf完成数据的页面展示

创建Spring Boot项目,引入Thymeleaf依赖

编写配置文件

打开application.properties全局配置文件,在该文件中队Thymeleaf模板页面的数据缓存进行设置

server.port= 8080
server.servlet.context-path= /chapter04
spring.thymeleaf.cache= false

将Thymeleaf默认开启的缓存设置为了false,用来关闭页面缓存。

创建Web控制类

在chapter04项目中创建名com.example.chapter04.controller的包,并在该包下创建一个用于前端模板页面动态数据替换效果测试的访问实体类LoginController

package com.example.chapter04.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.Calendar;

@Controller
public class LoginController {
    @GetMapping("/toLoginPage")
    public String toLoginPage(Model model){
        model.addAttribute("currentYear", Calendar.getInstance().get(Calendar.YEAR));
        return "login";
    }
}

toLoginPage()方法向登录页面login.html跳转时,携带了表示当前年份信息的currentYear。

创建模板页面并引入静态资源文件

在resouces的templates目录下创建一个用户登录的模板页面login.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="Content-Type" content="text/html" charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">
    <title>Title</title>
    <link th:href="@{/login/css/bootstrap.min.css}" rel="stylesheet">
    <link th:href="@{/login/css/signin.css}" rel="stylesheet">
</head>
<body>
    <form class="form-signin">
        <img class="mb-4" th:src="@{/login/img/img.jpg}" width="72" height="72">
        <h1 class="h3 mb-3 font-weight-normal">请登录</h1>
        <input type="text" class="form-control" placeholder="用户名" required="" autofocus="">
        <input type="password" class="form-control" placeholder="密码" required="">
        <div class="checkbox mb-3">
            <label>
                <input type="checkbox" value="remember-me">记住我
            </label>
        </div>
        <button class="btn btn-lg btn-primary btn-block" type="submit">请登录</button>
        <p class="mt-5 mb-3 text-muted">©<span th:text="${currentYear}">2018</span>-<span th:text="${currentYear}+1">2019</span> </p>
    </form>
</body>
</html>

先通过xmlns:th="http://www.thymeleaf.org"引入了Thymeleaf模板标签;然后使用th:hrefth:src分别引入了两个外联的样式文件和一个图片;最后使用th:text引入了后台动态传递过来的当前年份currentYear。
在项目的静态资源文件夹static下创建相应的目录和文件。

效果测试

使用Thymeleaf配置国际化页面

编写多语言国际化文件及配置文件

在项目的类路径resources下创建名称为i8n的文件夹,并在该文件夹中根据需要编写对应得多语言国家化文件login.properties、login_zh_CN.properties和login_en_US.properties文件
login.properties

login.tip= 请登录
login.username= 用户名
login.password= 密码
login.rememberme= 记住我
login.button= 登录

login_zh_CN.properties

login.tip= 请登录
login.username= 用户名
login.password= 密码
login.rememberme= 记住我
login.button= 登录

login_en_US.properties

login.tip=Please sign in
login.username=Username
login.password=Password
login.rememberme=Remember me
login.button=Login

login.properties为自定义默认语言配置文件
login_zh_CN.properties为自定义中文国际化文件
login_en_US.properties为自定义英文国际化文件
需要说明得是,Spring Boot默认识别得语言配置文件为类路径resources下的messages.properties;其他国际化文件得名称必须严格按照文件前缀名_语言代码_国家代码.properties的形式命名。
本项目默认语言配置文件名自定义为login.properties,因此如果项目需要引入自定义国家化文件,必须在项目的全局配置文件中进行国际化文件的基础名配置。

编写配置文件

application.properties

spring.messages.basename= i18n.login

根据国际化配置文件位置和名称,在项目全局配置文件中使用spring.messages.basename设置了自定义国际化文件的基础名。其中,i8n表示国际化文件相对项目类路径resources的位置,login表示多语言文件的前缀名。如果开发者完全按照Spring Boot默认识别机制,在项目类路径resources下编写messages.properties等国际化文件,可以省略国际化文件基础名的配置。

定制区域信息解析器

完成上一步中多语言国际化文件的编写和配置后,就可以正式在前端页面中结合Thymeleaf模板相关属性进行国际化语言设置和展示了,不过这种实现方式默认是使用请求头中的语言信息自动进行语言切换的,有些项目还会提供手动语言切换的功能,这就需要定制区域解析器了。
在chapter04项目中创建名com.example.config的包,并在该包下创建一个用于定制国际化功能区域信息解析器的自定义配置类MyLocalResovel

package com.example.chapter04.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.thymeleaf.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;

@Configuration
public class MyLocalResovel implements LocaleResolver {

    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        String l=request.getParameter("l");
        String header=request.getHeader("Accept-Language");
        Locale locale=null;
        if(!StringUtils.isEmpty(l)){
            String[] split=l.split("_");
            locale=new Locale(split[0],split[1]);
        }else{
            String[] splits=header.split(",");
            String[] split=splits[0].split("-");
            locale=new Locale(split[0],split[1]);
        }
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
        
    }
    @Bean
    public LocaleResolver localeResolver(){
        return new MyLocalResovel();
    }
}

MyLocalResovel配置类实现了LocaleResovel接口,并重写了LocaleResovel接口的resolveLocale()方法解析自定义语言。使用@Bean注解将当前配置类注册成Spring容器中一个Bean组件。这样就可以覆盖默认的LocaleResolver组件。在重写的resolveLocale()方法中,可以根据不同的需求切换语言信息从而获取请求的参数,只有请求不为空时,才可以进行语言的切换。
需要注意的是,在请求参数l的语言手动切换组装时,使用的是下划线_进行的切割,这是由多语言配置文件的格式决定的(例如 login_zh_CN.properties);而在请求头参数Accept-Language的语言自动切换组装时,使用的是短横线"_"进行的切割,这是由浏览器发送的请求头信息样式决定的(例如Accept-Language:en-US,en;1=0.9,zh-CN;1=0.8,zh;q=0.7)。

页面国际化使用

打开项目templates模板文件夹中的用户登录页面login.html,结合Thymeleaf模板引擎实现国际化功能。
login.html

峰哥说技术:08-Spring Boot整合FreeMarker视图

Spring Boot视图技术

峰哥说技术:09-Spring Boot整合JSP视图

解决spring-boot启动中碰到的问题:Cannot determine embedded database driver class for database type NONE(转)(代码片段

一张图,理顺 Spring Boot应用在启动阶段执行代码的几种方式

一张图帮你记忆,Spring Boot 应用在启动阶段执行代码的几种方式