前面我已经介绍了如何在spirngboot2.0中使用freemarker和jsp,今天我们来说一下如何在springboot2.0中如何使用Thymeleaf。由于自己对Thymeleaf没有了解过,在写这篇文章前我查看Thymeleaf官方教程并写的关于Thymeleaf 2篇博客thymeleaf基础教程 - 搭建杂货铺项目环境(一) 和 thymeleaf基础教程 - 阅读官方教程(二)。
为了在开发过程中使我们的修改立刻生效我们需要在application.properties中配置spring.thymeleaf.cache = false
先给大家官方提供杂货铺项目的效果:
第一步我们要先在pom.xml中 引入Thymeleaf start 依赖,具体代码如下:
org.springframework.boot
spring-boot-starter-thymeleaf
如果要使用模板布局需要单独引入 thymeleaf-layout-dialect。
nz.net.ultraq.thymeleaf
thymeleaf-layout-dialect
关于Thymeleaf 国际化的问题 如果不配置 spring.messages.basename 默认的会取 message.properties 中的信息 如果需要自定义国际化的内容需要添加LocaleResolverConfig 配置类内容如下:
package com.lijunkui.thymeleaf;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
@Configuration
public class LocaleResolverConfig {
@Bean(name="localeResolver")
public LocaleResolver localeResolverBean() {
return new SessionLocaleResolver();
}
}
然后再Controller 中定义操作语言环境
如果没有定义 message_en_US.properties 和 message_zh_CN.properties 会默认取message.properties中的信息
如果 Locale = Locale.CHINA 就取 message_zh_CN.properties
如果 Locale = Locale.US 就取 message_en_US.properties。
如果Locale = Locale.US 没有message_en_US.properties 但是有message_zh_CN.properties 取得是message_zh_CN.properties中的信息 而不是message.properties中的信息 这个很费解。
我在这里采用官方的示例项目的商品列表稍微修改一下尽可能把常用的操作给大家进行展示,方便大家快速查阅。关于Thymeleaf的语法请查看 thymeleaf基础教程 - 阅读官方教程(二)。样式文件参考thymeleaf基础教程 - 搭建杂货铺项目环境(一)。使用Thymeleaf核心内容都在页面上,但是也需要后台数据支撑,下面我们下说明一下后台提供数据代码。
用户类
package com.lijunkui.thymeleaf.product.model;
public class User {
private String firstName = null;
private String lastName = null;
private String nationality = null;
private Integer age = null;
public User(final String firstName, final String lastName,
final String nationality, final Integer age) {
super();
this.firstName = firstName;
this.lastName = lastName;
this.nationality = nationality;
this.age = age;
}
public String getFirstName() {
return this.firstName;
}
public String getLastName() {
return this.lastName;
}
public String getName() {
return this.firstName + " " + this.lastName;
}
public String getNationality() {
return this.nationality;
}
public Integer getAge() {
return this.age;
}
}
商品类
package com.lijunkui.thymeleaf.product.model;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
public class Product {
private Integer id = null;//商品id
private String name = null;//商品名称
private BigDecimal price = null;//商品价格
private boolean inStock = false;//是否有货
private List comments = new ArrayList();//评论
public Product() {
super();
}
public Product(final Integer id, final String name, final boolean inStock, final BigDecimal price) {
super();
this.id = id;
this.name = name;
this.price = price;
this.inStock = inStock;
}
public Integer getId() {
return this.id;
}
public void setId(final Integer id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(final String name) {
this.name = name;
}
public BigDecimal getPrice() {
return this.price;
}
public void setPrice(final BigDecimal price) {
this.price = price;
}
public boolean isInStock() {
return this.inStock;
}
public void setInStock(final boolean inStock) {
this.inStock = inStock;
}
public List getComments() {
return this.comments;
}
}
评论类
package com.lijunkui.thymeleaf.product.model;
public class Comment {
private Integer id = null;//评论id
private String text = null;//评论内容
public Comment() {
super();
}
public Comment(final Integer id, final String text) {
this.id = id;
this.text = text;
}
public Integer getId() {
return this.id;
}
public void setId(final Integer id) {
this.id = id;
}
public String getText() {
return this.text;
}
public void setText(final String text) {
this.text = text;
}
}
查询商品数据的DAO这里都是写死的数据没有什么可说的。
package com.lijunkui.thymeleaf.product.repositories;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.lijunkui.thymeleaf.product.model.Comment;
import com.lijunkui.thymeleaf.product.model.Product;
public class ProductRepository {
private static final ProductRepository INSTANCE = new ProductRepository();
private final Map productsById;
public static ProductRepository getInstance() {
return INSTANCE;
}
private ProductRepository() {
super();
this.productsById = new LinkedHashMap();
final Product prod1 = new Product(1, "鲜甜罗勒", true, new BigDecimal("4.99"));
final Product prod2 = new Product(2, "意大利番茄", false, new BigDecimal("1.25"));
final Product prod3 = new Product(3, "黄柿子椒", true, new BigDecimal("2.50"));
final Product prod4 = new Product(4, "车达奶酪", true, new BigDecimal("18.75"));
final Product prod5 = new Product(5, "超纯椰子油", true, new BigDecimal("6.34"));
final Product prod6 = new Product(6, "有机番茄酱", true, new BigDecimal("1.99"));
final Product prod7 = new Product(7, "全麦片麦片粥", true, new BigDecimal("3.07"));
final Product prod8 = new Product(8, "传统西红柿罗勒酱", true, new BigDecimal("2.58"));
final Product prod9 = new Product(9, "藜麦粉", true, new BigDecimal("3.02"));
final Product prod10 = new Product(10, "蜜柚汁", true, new BigDecimal("2.58"));
final Product prod11 = new Product(11, "100%纯枫糖浆", true, new BigDecimal("5.98"));
final Product prod12 = new Product(12, "意大利面酱", false, new BigDecimal("2.08"));
final Product prod13 = new Product(13, "香草酥麦片", false, new BigDecimal("1.75"));
final Product prod14 = new Product(14, "初榨橄榄油", false, new BigDecimal("5.01"));
final Product prod15 = new Product(15, "烤蒜意大利面酱", true, new BigDecimal("2.40"));
final Product prod16 = new Product(16, "蔬菜浓汤罐头", true, new BigDecimal("2.19"));
final Product prod17 = new Product(17, "杏仁乳1L", true, new BigDecimal("3.24"));
final Product prod18 = new Product(18, "有机鸡肉野米汤", true, new BigDecimal("3.17"));
final Product prod19 = new Product(19, "紫胡萝卜、黑莓、藜麦和希腊酸奶", true, new BigDecimal("8.88"));
final Product prod20 = new Product(20, "南瓜胡萝卜胡萝卜汁", false, new BigDecimal("3.90"));
final Product prod21 = new Product(21, "有机菜籽油", true, new BigDecimal("10.13"));
final Product prod22 = new Product(22, "马铃薯玉米卷饼", true, new BigDecimal("2.44"));
final Product prod23 = new Product(23, "玉米杂烩汤罐头", true, new BigDecimal("2.30"));
final Product prod24 = new Product(24, "有机柠檬汁", true, new BigDecimal("2.48"));
final Product prod25 = new Product(25, "辣罗勒酱", true, new BigDecimal("4.72"));
final Product prod26 = new Product(26, "甜龙舌兰蜜", true, new BigDecimal("6.46"));
final Product prod27 = new Product(27, "黑烤花生酱", false, new BigDecimal("3.48"));
final Product prod28 = new Product(28, "无糖柠檬绿茶", true, new BigDecimal("18.34"));
final Product prod29 = new Product(29, "全谷物薄片谷物", true, new BigDecimal("3.52"));
final Product prod30 = new Product(30, "燕麦卷", true, new BigDecimal("4.00"));
this.productsById.put(prod1.getId(), prod1);
this.productsById.put(prod2.getId(), prod2);
this.productsById.put(prod3.getId(), prod3);
this.productsById.put(prod4.getId(), prod4);
this.productsById.put(prod5.getId(), prod5);
this.productsById.put(prod6.getId(), prod6);
this.productsById.put(prod7.getId(), prod7);
this.productsById.put(prod8.getId(), prod8);
this.productsById.put(prod9.getId(), prod9);
this.productsById.put(prod10.getId(), prod10);
this.productsById.put(prod11.getId(), prod11);
this.productsById.put(prod12.getId(), prod12);
this.productsById.put(prod13.getId(), prod13);
this.productsById.put(prod14.getId(), prod14);
this.productsById.put(prod15.getId(), prod15);
this.productsById.put(prod16.getId(), prod16);
this.productsById.put(prod17.getId(), prod17);
this.productsById.put(prod18.getId(), prod18);
this.productsById.put(prod19.getId(), prod19);
this.productsById.put(prod20.getId(), prod20);
this.productsById.put(prod21.getId(), prod21);
this.productsById.put(prod22.getId(), prod22);
this.productsById.put(prod23.getId(), prod23);
this.productsById.put(prod24.getId(), prod24);
this.productsById.put(prod25.getId(), prod25);
this.productsById.put(prod26.getId(), prod26);
this.productsById.put(prod27.getId(), prod27);
this.productsById.put(prod28.getId(), prod28);
this.productsById.put(prod29.getId(), prod29);
this.productsById.put(prod30.getId(), prod30);
prod2.getComments().add(new Comment(1, "I'm so sad this product is no longer available!"));
prod2.getComments().add(new Comment(2, "When do you expect to have it back?"));
prod13.getComments().add(new Comment(3, "Very tasty! I'd definitely buy it again!"));
prod13.getComments().add(new Comment(4, "My kids love it!"));
prod13.getComments().add(new Comment(5, "Good, my basic breakfast cereal. Though maybe a bit in the sweet side..."));
prod13.getComments().add(new Comment(6, "Not that I find it bad, but I think the vanilla flavouring is too intrusive"));
prod13.getComments().add(new Comment(7, "I agree with the excessive flavouring, but still one of my favourites!"));
prod13.getComments().add(new Comment(8, "Cheaper than at the local store!"));
prod13.getComments().add(new Comment(9, "I'm sorry to disagree, but IMO these are far too sweet"));
prod13.getComments().add(new Comment(10, "Good. Pricey though."));
prod9.getComments().add(new Comment(11, "Made bread with this and it was great!"));
prod9.getComments().add(new Comment(12, "Note: this comes actually mixed with wheat flour"));
prod14.getComments().add(new Comment(13, "Awesome Spanish oil. Buy it now."));
prod14.getComments().add(new Comment(14, "Would definitely buy it again. Best one I've tasted"));
prod14.getComments().add(new Comment(15, "A bit acid for my taste, but still a very nice one."));
prod14.getComments().add(new Comment(16, "Definitely not the average olive oil. Really good."));
prod16.getComments().add(new Comment(17, "Great value!"));
prod24.getComments().add(new Comment(18, "My favourite :)"));
prod30.getComments().add(new Comment(19, "Too hard! I would not buy again"));
prod30.getComments().add(new Comment(20, "Taste is OK, but I agree with previous comment that bars are too hard to eat"));
prod30.getComments().add(new Comment(21, "Would definitely NOT buy again. Simply unedible!"));
}
public List findAll() {
return new ArrayList(this.productsById.values());
}
public Product findById(final Integer id) {
return this.productsById.get(id);
}
}
商品业务层类
package com.lijunkui.thymeleaf.product.service;
import java.util.List;
import com.lijunkui.thymeleaf.product.model.Product;
import com.lijunkui.thymeleaf.product.repositories.ProductRepository;
public class ProductService {
public ProductService() {
super();
}
public List findAll() {
return ProductRepository.getInstance().findAll();
}
public Product findById(final Integer id) {
return ProductRepository.getInstance().findById(id);
}
}
日历的工具类
package com.lijunkui.thymeleaf.util;
import java.util.Calendar;
public class CalendarUtil {
public static Calendar calendarFor(
final int year, final int month, final int day, final int hour, final int minute) {
final Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month - 1);
cal.set(Calendar.DAY_OF_MONTH, day);
cal.set(Calendar.HOUR_OF_DAY, hour);
cal.set(Calendar.MINUTE, minute);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal;
}
private CalendarUtil() {
super();
}
}
以上的代码是我们提供数据的基础代码,内容并不复杂我们这里就不过多解释了
商品前台访问的控制器,后台数据展示的核心主要是将所有商品列表数据,当前日期,以及登录用户的信息(这里是写死的模拟代码)。
package com.lijunkui.thymeleaf.product;
import java.util.Calendar;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import com.lijunkui.thymeleaf.product.model.Product;
import com.lijunkui.thymeleaf.product.model.User;
import com.lijunkui.thymeleaf.product.service.ProductService;
/**
* 商品Controller
* @author zhuoqianmingyue
*
*/
@Controller
public class ProductController {
private ProductService productService = new ProductService();
@RequestMapping("/")
public String useT(Model model,HttpServletRequest request) {
//获取所有的商品
List allProducts = productService.findAll();
model.addAttribute("prods", allProducts);
//获取当前日期
model.addAttribute("today", Calendar.getInstance());
//设置访问用户信息到session
request.getSession(true).setAttribute("user", new User("桌前", "明月", "CHINA", null));
return "productList";
}
}
后台application.properties thymeleaf配置信息 和 thymeleaf 国际化配置信息
#thymeleaf的编码配置
spring.thymeleaf.encoding=UTF-8
#thymeleaf的缓存设置 false是禁用缓存
spring.thymeleaf.cache =false
#模板模式
spring.thymeleaf.mode=HTML5
#模板后缀名称
spring.thymeleaf.suffix=.html
#模板路径
spring.thymeleaf.prefix=classpath:/templates/
#国际化配置文件名称 默认为messages
spring.messages.basename=message
#国际化配置的编码
spring.messages.encoding=UTF-8
footer.html:页面布局的页脚信息
© 2011 The Good Thymes Virtual Grocery
productList.html :商品列表页面
在线杂货店
Welcome to our grocery store, Sebastian!
Today is: 13 February 2011
商品列表
商品名称
价格
是否有货
评价
Onions
2.41
yes
2 comment/s
查看
Blue Lettuce
9.55
no
0 comment/s
Mild Cinnamon
1.99
yes
3 comment/s
查看
© 2011 The Static Templates
message.properties :国际化默认配置信息
true=yes
false=no
date.format=MMMM dd'','' yyyy
home.welcome=Welcome to our grocery store,{0}!(default message)
message_zh_CN.properties :国际化中文环境配置信息
home.welcome=欢迎来到我们的杂货店, {0}!
true=是
false=否
date.format=MMMM dd'','' yyyy
message_en_US.properties:国际化英文环境配置信息
true=yes
false=no
date.format=MMMM dd'','' yyyy
home.welcome=Welcome to our grocery store,{0}!
项目文件路径如下图 :
演示工具和版本说明:
开发工具:Spring Tool Suite(STS)
JDK版本:1.8.0_144
springboot版本:2.0.5.RELEASE
查看源码