前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringBoot入门建站全系列(八)集成模板引擎(thymeleaf)渲染页面

SpringBoot入门建站全系列(八)集成模板引擎(thymeleaf)渲染页面

原创
作者头像
品茗IT
修改2019-08-09 10:00:54
1.9K0
修改2019-08-09 10:00:54
举报
文章被收录于专栏:品茗IT品茗IT

SpringBoot入门建站全系列(八)集成模板引擎(thymeleaf)渲染页面

说到页面渲染,这里不得不给大家科普一下:

    1. html文件负责显示页面,后台数据可以通过ajax方式获取,如果数据完全使用ajax获取,这样页面和后端就没什么联系,这时候就可以成为前后端分离。
    1. jsp页面是一种页面渲染方式,它是对jsp文件解析后,将后台数据填充到html页面并返回到前端,这种方式是非前后端分离的,所以,脱离了容器,jsp页面啥都不是,根本打不开。jsp可以写java代码,可以写逻辑,功能很强大,但是也是它逐渐被抛弃的原因。
    1. 模板引擎, 目前是比较流行的一种写法,或许你会问:前后端分离已经很好用了,为啥还要用模板引擎?原因是这样的,前后端分离的页面,是不经过容器控制的,所以安全框架不能对它进行过滤,这是其一,其二、前后端分离的页面,数据是ajax异步获取的,所以首次打开页面时(比如爬虫爬取页面,未执行js等),获取到的只是一些html元素,没有数据填充,而模板引擎可以在获取html文件时就将数据填充进去。
    1. 模板引擎也是依赖于后端容器,页面中的内容使用标签进行替换。

本文不讲前后端分离,先讲下模板引擎,Springboot支持很多模板引擎,thymeleaf算是比较好用的一种。

一、Maven依赖

需要引入spring-boot-starter-thymeleaf和spring-boot-starter-web。

代码语言:txt
复制
<?xml version="1.0"?>
<project
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
	xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>com.cff</groupId>
		<artifactId>springbootwork</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>
	<artifactId>Thymeleaf</artifactId>
	<name>Thymeleaf</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

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

父pom管理了所有依赖jar包的版本,地址: https://www.pomit.cn/spring/SpringBootWork/pom.xml

二、thymeleaf配置

SpringBoot对thymeleaf做了很好的整合,隐藏了大部分细节,所以,我们只需要在Springboot的配置文件(一般是用application.properties)中加入以下配置即可:

代码语言:txt
复制
spring.thymeleaf.cache=false
spring.thymeleaf.enabled=true
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.content-type=text/html
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html

这里,

  • spring.thymeleaf.cache是对页面不缓存,这样修改了模板文件,立即生效。
  • spring.thymeleaf.prefix指明了模板文件的地址
  • spring.thymeleaf.suffix 指明了模板文件后缀。

另外三个参数就不说了,顾名思义。

三、thymeleaf的模板页面

这里建了一个模板文件detail.html文件。乍一看,它和html没啥区别,其实区别真不大,只是里面有thymeleaf的标签。

里面的th:开头的都是thymeleaf的标签,如th:href、th:onclick、th:text等。

代码语言:txt
复制
<!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"/>
    <meta name="keywords" th:attr="content=${data.data.catory}"/>
    <meta name="description" th:attr="content=${data.data.title}"/>
    <title th:text="${data.data.title}">品茗IT-博文详情</title>

    <!-- CSS  -->
    <link href="https://lib.baomitu.com/material-design-icons/3.0.1/iconfont/material-icons.min.css" rel="stylesheet">
    <link href="https://lib.baomitu.com/materialize/0.100.2/css/materialize.min.css" type="text/css" rel="stylesheet" media="screen,projection"/>
	
	<script src="https://lib.baomitu.com/jquery/3.3.0/jquery.min.js"></script>
    <style>

        nav ul a,
        nav .brand-logo {
            color: #444;
        }
		.side-nav{
			max-width: 50%;
		}
        p {
            line-height: 2rem;
        }

        .button-collapse {
            color: #26a69a;
        }

        .parallax-container {
            min-height: 380px;
            line-height: 0;
            height: auto;
            color: rgba(255,255,255,.9);
        }
        .parallax-container .section {
            width: 100%;
        }

        @media only screen and (max-width : 992px) {
            .parallax-container .section {
                position: absolute;
                top: 40%;
            }
            #index-banner .section {
                top: 10%;
            }
            
        }

        @media only screen and (max-width : 600px) {
            #index-banner .section {
                top: 0;
            }
            
            .collection .collection-item.avatar {
			    padding-left: 15px;
			}
        }

        .icon-block {
            padding: 0 15px;
        }
        .icon-block .material-icons {
            font-size: inherit;
        }

        footer.page-footer {
            margin: 0;
        }
        
        .token.punctuation {
		    color: #999;
		}
		pre {
		    -moz-osx-font-smoothing: initial;
		    -webkit-font-smoothing: initial;
		    background-color: #f8f8f8;
		    font-family: 'Roboto Mono', Monaco, courier, monospace;
		    line-height: 1.5rem;
		    margin: 1.2em 0;
		    overflow: auto;
		    padding: 0 1.4rem;
		    position: relative;
		    word-wrap: normal;
		}
		pre > code {
		    -moz-osx-font-smoothing: initial;
		    -webkit-font-smoothing: initial;
		    background-color: #f8f8f8;
		    border-radius: 2px;
		    color: #525252;
		    display: block;
		    font-family: 'Roboto Mono', Monaco, courier, monospace;
		    font-size: 0.8rem;
		    line-height: inherit;
		    margin: 0 2px;
		    max-width: inherit;
		    overflow: inherit;
		    padding: 2.2em 5px;
		    white-space: inherit;
		}
		
		.dialog{
            position: relative;
            display: inline-block;
            max-width: 200px;
            padding: 4px 8px;
            border-radius: 2px;
            background-color: #dddddd;
            line-height: 20px;
            font-size: 14px;
        }
        .u-tri:before{
            position: absolute;
            left: 77px;
            top: 11px;
            content: '';
            border-top: 8px solid transparent;
            border-bottom: 8px solid transparent;
            border-right: 12px solid transparent;
            border-left: 12px solid #dddddd;
        }
		.question{
			font-size: 22px;
			font-weight: bold;
			color: #112f6b;
		}
		.question-index{
			font-size: 10px;
			color: grey;
		}
		.btn{
			padding: 0 1rem;
			color:#2196f3 ;
		}
		.authorName{
			padding-left:10px;
			font-size: 14px;
			color: #64b5f6 ;
			cursor: pointer;
		}
		.createTime{
			padding-left:10px;
			font-size: 12px;
			color: grey;
		}
		.catory{
			padding-left:5px;
			font-size: 14px;
			color: grey;
		}
		.catory:before{
			content:"【";
		}
		.catory:AFTER{
			content:"】";
		}
		.outer {
			overflow: hidden;
			text-overflow: ellipsis;
			/*设置成弹性盒子 */
			display: -webkit-box;
			/*显示的个数 */
			-webkit-line-clamp: 2;
			/* 属性规定框的子元素应该被水平或垂直排列。 */
			-webkit-box-orient: vertical;
		}
		.editBtn{
			padding-right:40px;
		}
		.form-control {
		    display: block;
		    width: 100%;
		    height: 50px;
		    padding: 6px 12px;
		    font-size: 14px;
		    line-height: 1.42857143;
		    color: #555;
		    background-color: #fff;
		    background-image: none;
		    border: 1px solid #ccc;
		    border-radius: 4px;
		    -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
		    box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
		    -webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
		    -o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
		    transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
		}
		.comment-form{
			height: 100px;
		}
		.comments-list-area{
			padding: 20px 10px;
		}
		.comments-area{
			padding: 20px 10px;
		}
		.important-text{
			font-weight: bold;
			color:#112f6b;
		}
		.replyCommentBtn{
			margin-left:10px;
			color:light-blue;
		}
		.replyCommentBtn:hover{
			color:#1565c0;
		}
		.fixed-menu{
			position: relative;
		}
    </style>
</head>
<body class="amber lighten-5">
<!-- header end -->
<div class="fixed-menu hide-on-med-and-down">
    <ul id="tree" class="ztree" style='width:100%'>
		
    </ul>
</div>
<!-- content -->
<div class="section no-pad-bot " >
	<div class="container">
		<div class="card-panel" style="min-height:90vh;padding: 0px">
			<ul class="collection" id="issueList" style="border: none">
			    <li class="collection-item avatar">
			    	<div class="row">
			    		<div class="col s12"><span class="question" id="title"  th:text="${data.data.title}">Spring序列化布尔类型错误</span></div>
			    	</div>
			    	<div class="row">
			    		<span class="catory" id="catory"  th:text="${data.data.catory}">【软件使用】</span>
			    		<span class="createTime" id="createTime" th:text="${#dates.format(data.data.createTime,'yyyy-MM-dd HH:mm:ss')}">2019-03-06</span>
			    		<span class="createTime" id="openStatus" th:text="${data.data.open}==0?'公开':'私有'">未知</span>
			    		
			    		<a class="authorName" id="authorName" th:href="'/page/userData.html?user=' + ${data.data.author}" th:text="${data.data.author}">匿名</a>
			    		<span style="padding-left:20px;" class="createTime">点赞:<span class="starNum" id="starNum" th:text="${data.data.star}">1</span></span>
			    		
			    		<a id="editBtn" class="editBtn right" th:href="'/page/issue/editIssue.html?id=' + ${data.data.id}" th:if="${#strings.equals(data.remark,data.data.author)}">编辑</a>
			    	</div>
			    	<div class="divider"></div>
			    	<div class="row" style="margin-top: 2rem;">
			    		<div class="col s12">
			    			<span class="answer markdown-section" id="content" ></span>
			    		</div>
			    	</div>
			    	
			    </li>
			   
			</ul>
			<div class="divider"></div>
			<div class="center" style="padding-top: 20px;;left: 45%;padding-bottom: 20px;">
		    	<a id="starBtn" th:onclick="'javascript:issueStar(' + ${data.data.id} + ');'" class="waves-effect waves-light btn light-blue lighten-5"><i id="star_icon" class="material-icons right">favorite_border</i>赞</a>
	    	</div>
		</div>
	</div>
</div>

<!-- footer start -->
<footer class="page-footer teal">
    <div class="container">
        <div class="row">
            <div class="col l8 s12">
                <h5 class="white-text">网站简介.</h5>
                <p class="grey-text text-lighten-4">
                    本站提供多领域的技术解决方案,包括web网站、小程序、开源项目、h5等。
                </p>
            </div>
            

        </div>
    </div>
    <div class="footer-copyright">
        <div class="container">
            Copyright (c) 2018-present, 陈付菲.
            <a class="grey-text text-lighten-4 right" ></a>
        </div>
    </div>
</footer>
<!-- footer end -->

</body>

<script src="https://lib.baomitu.com/materialize/0.100.2/js/materialize.min.js"></script>
<script th:inline="javascript">
    $(function () {
    	
       	
    });
    
</script>

</html>

四、thymeleaf的页面控制器

使用模板引擎,需要我们自己控制ModelAndView。这里的ModelAndView的viewName是detail,结合thymeleaf的配置,就是找spring.thymeleaf.prefix + viewName + spring.thymeleaf.suffix 指定的这个文件。

代码语言:txt
复制
package com.cff.springbootwork.thymeleaf.web;

import java.util.Date;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

import com.cff.springbootwork.thymeleaf.dto.FQuestionInfo;
import com.cff.springbootwork.thymeleaf.dto.ResultCode;
import com.cff.springbootwork.thymeleaf.dto.ResultModel;

@RestController
@RequestMapping("/thymeleaf")
public class ThymeleafRest {
	@RequestMapping("/page")
	public <FQuestionIndex> ModelAndView getThymeleaf() {
		ModelAndView modelAndView = new ModelAndView("detail");

		try {
			FQuestionInfo fQuestionInfo = new FQuestionInfo();
			fQuestionInfo.setAuthor("cff");
			fQuestionInfo.setCatory("大爷");
			fQuestionInfo.setId(123123123L);
			fQuestionInfo.setOpen(1);
			fQuestionInfo.setStar(123);
			fQuestionInfo.setTitle("我就是一个测试模板引擎的实体而已。");

			fQuestionInfo.setCreateTime(new Date());

			ResultModel retOk = ResultModel.ok(fQuestionInfo);
			modelAndView.addObject("data", retOk);
		} catch (Exception e) {
			e.printStackTrace();
			modelAndView.addObject("data", new ResultModel(ResultCode.CODE_00004));
		}

		return modelAndView;
	}
}

这里面,FQuestionInfo 是保存数据的一个实体,ResultModel是一个统一返回的实体,其实可以写成一个实体,都是作为返回数据的。

modelAndView使用addObject("data", retOk);将数据传递给viewName指定的模板文件,解析后返回一个html文件给浏览器。

页面如下:

在这里插入图片描述
在这里插入图片描述

五、过程中使用到的实体

详细完整的实体,可以访问品茗IT-博客《SpringBoot入门建站全系列(八)集成模板引擎(thymeleaf)渲染页面》

快速构建项目

Spring组件化构建

喜欢这篇文章么,喜欢就加入我们一起讨论SpringBoot技术吧!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • SpringBoot入门建站全系列(八)集成模板引擎(thymeleaf)渲染页面
    • 一、Maven依赖
      • 二、thymeleaf配置
        • 三、thymeleaf的模板页面
          • 四、thymeleaf的页面控制器
            • 五、过程中使用到的实体
              • 快速构建项目
              相关产品与服务
              容器服务
              腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档