Handlebars.java学习笔记

背景

最近在做一个移动收银的项目,需要使用到银行的设备进行收银。由于使用的是银行设备,每次更新APP是都需要经过银行审核才能上线,这就加大了应用上线的复杂度。而且银行的pos机,性能也有限,通过http请求访问web页面会比较缓慢,会影响收银等操作,影响用户体验。
对于一个新项目来说,在没有经过长时间试运行之前,积累不够,稳定性肯定有所欠缺,基本都需要不断的迭代更新,不断的完善系统交互。估而老大希望将可以预见经常变化的页面的开发工作后置到服务端,避免频繁发布app。如小票打印,由后端生成好最终的打印模板并且输出,app在接收到模板后直接渲染打印,这样如果模板有变化也只需要发布服务端就好,不需要走app的上架流程。

Freemarker

页面模板化,我第一个想到的是Java模板引擎Freemarker。

FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。

Freemarker可以将表现层和业务逻辑层代码完全分开,提高代码的可读性;同时能使得开发过程中的人员分工更加明确,实现前后端分离。
Freemarker实现前端页面热部署设计可以参考下图。Freemarker的技术文档网上特别丰富,本文不多做描述。

在这里插入图片描述

Handlebars.java

移动收银系统只需要将部分页面模板化,直接使用Freemarker感觉有点大材小用,也相对复杂。在老大的推荐下了解到了Handlebars.java。

Handlebars 是一种简单的 模板语言,相对于Freemarker更为简单。
它使用模板和输入对象来生成 HTML 或其他文本格式。Handlebars 模板看起来像常规的文本,但是它带有嵌入式的 Handlebars 表达式 。

基础用法

1、表达式是一些以双花括号 {{}} 括起来的内容;
2、在 Handlebars 中, {{expression}} 返回的值是 HTML 转义的。如果一个表达式的内容包含 &等HTML特殊字符时,Handlebars会自动转义。如果你不希望 Handlebars 转义字符的话,可以 修改为{{{expression}}};
3、Handlebars的入参可以是任何类型,String、Map、自定义对象;
4、Handlebars的模板可以是一个hbs、html等格式的文件,也可以是一个字符串。

if助手
{{#if condition}}
...
{{/if}}
for循环表达式(each助手)
{{#each list}}
...
{{/each}}
代码实现
maven
<dependency>
	<groupId>com.github.jknack</groupId>
    <artifactId>handlebars</artifactId>
    <version>4.2.0</version>
</dependency>
加载解析模板------文件
	private final static String LOCAL_ROOT_PATH = "/";
	private final static String TEMPLATE_PREFIX = "/templates";
	public static String compile(String templateName,Object var1){
		TemplateLoader loader = new FileTemplateLoader(new File(LOCAL_ROOT_PATH));
		loader.setPrefix(TEMPLATE_PREFIX);
		Handlebars handlebars = new Handlebars(loader);
		try {
			Template template = handlebars.compile(templateName);
			return template.apply(var1);
		} catch (Exception e) {
			LOGGER.warn(LogEvent.of(HANDLEBARS_LOG_EVENT,"handlebars 封装模板异常 message : {} , e : {}",e.getLocalizedMessage(),e));
		}
		return null;
	}
加载解析模板------字符串

字符串形式更为便捷,可以丢到redis中,能提升性能,更新也更为方便

	public static String compileInline(String templateName,Object var1){
		String key = VposRedisConstant.VPOS_HANDLEBARS_KEY + templateName;
		String templateString = getTemplateString(key,templateName);
		if(StringUtils.isEmpty(templateString)){
			return null;
		}
		Handlebars handlebars = new Handlebars();
		try {
			Template template = handlebars.compileInline(templateString);
			return template.apply(var1);
		} catch (Exception e) {
			LOGGER.warn(LogEvent.of(HANDLEBARS_LOG_EVENT,"handlebars 封装模板异常 message : {} , e : {}",e.getLocalizedMessage(),e));
		}
		return null;
	}

	private static String getTemplateString(String key,String templateName){
		String templateString = RedisUtil.getInstance().getString(key);
		if(StringUtils.isNotEmpty(templateString)){
			return templateString;
		}
		File template = FileUtil
				.downloadFile(TEMPLATES_PATH, templateName + TEMPLATE_SUFFIX_HBS, TEMPLATE_TEMPORARY_PATH);
		templateString = FileUtils.readFileToString(template, "utf-8");
		if(StringUtils.isNotEmpty(templateString)){
			FcsVposRedisUtil.getInstance().set(key,templateString,36000);
		}
		return templateString;
	}
入参
String template = HandlebarsUtils.compileInline("sale.hbs",orderTemplate);

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class OrderTemplate {
	private List<PayModel> PayModels;
	private String totalPayAmount;
	private double orderGoodsMoney;
	private double orderDiscount;
}

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class PayModel{
	private String payMethod;
	private String payMethodName;
	private String amount;
}

模板样例
<div class="diary-detail-h5">
  <div class="d-flex flex-row justify-content-start align-items-center flex-wrapper">
    <div class="d-flex flex-row flex-fill justify-content-start align-items-start flex-demo">
      <p class="p-justify vpos-diary-bold">销售商品总金额:</p></div>
    <div class="d-flex flex-row flex-fill justify-content-end align-items-start flex-demo">
      <p class="vpos-diary-bold">{{orderGoodsMoney}}</p></div>
  </div>
  {{#if orderDiscount '!=' null}}
  <div class="d-flex flex-row justify-content-start align-items-center flex-wrapper">
    <div class="d-flex flex-row flex-fill justify-content-start align-items-start flex-demo">
      <p class="p-justify vpos-diary-bold">销售优惠合计:</p></div>
    <div class="d-flex flex-row flex-fill justify-content-end align-items-start flex-demo">
      <p class="vpos-diary-bold">{{orderDiscount}}</p></div>
  </div>
  {{/if}}
  
  
  <div class="vpos-diary-comp">
    <p class="vpos-diary-bold vpos-detail-title">收款明细</p>
    <div class="vpos-day-dummary-line-list">
	{{#each PayModels}}
      <div class="d-flex flex-row justify-content-start align-items-center flex-wrapper">
        <div class="d-flex flex-row flex-fill justify-content-start align-items-start flex-demo">
          <p class="p-justify">{{payMethodName}}</p></div>
        <div class="d-flex flex-row flex-fill justify-content-end align-items-start flex-demo">
          <p>{{amount}}</p>
        </div>
      </div>
	{{/each}}
      <div class="d-flex flex-row justify-content-start align-items-center flex-wrapper">
        <div class="d-flex flex-row flex-fill justify-content-start align-items-start flex-demo">
          <p class="p-justify vpos-diary-bold">收款合计:</p></div>
        <div class="d-flex flex-row flex-fill justify-content-end align-items-start flex-demo">
          <p class="vpos-diary-bold">{{totalPayAmount}}</p></div>
      </div>
    </div>
  </div>
  
</div>

参考资料

Handlebars.java还有很多其他用法,如with、unless、helpers等,详情见:https://github.com/jknack/handlebars.java

作者:张伟峰

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值