Handlebars块级Helpers

1.Handlebars简单介绍:

     Handlebars是JavaScript一个语义模板库,通过对view和data的分离来快速构建Web模板。它采用"Logic-less template"(无逻辑模版)的思路,在加载时被预编译,而不是到了客户端执行到代码时再去编译, 这样可以保证模板加载和运行的速度。Handlebars兼容Mustache,你可以在Handlebars中导入Mustache模板。

2.参考文章:

    Handlebars官网:http://handlebarsjs.com/

    Handlebars中文介绍(王赛):http://www.ghostchina.com/introducing-the-handlebars-js-templating-engine/

    Handlebars中文文档 - 块级helpers(译自官方版):https://segmentfault.com/a/1190000000347965

    Handlebars.js 中文文档:http://keenwon.com/992.html

    js模版引擎handlebars.js实用教程:http://www.cnblogs.com/iyangyuan/p/3471227.html

    handlebars玩家指南:http://cnodejs.org/topic/56a2e8b1cd415452622eed2d

    com.github.jknack.handlebars.Helper:http://www.programcreek.com/java-api-examples/index.php?api=com.github.jknack.handlebars.Helper

3.块级Helpers使用技巧:

   Handlebars内置了with,eachif,unless,log这5种基本的Helpers。

   if标签只能判断true或false,不能执行一些复杂的运算逻辑。

   这些基本的Helpers并不能满足我们所有的需求,因此需要自定义一些辅助Helpers。

   ① 基本Helpers—each使用示例:orderList.hbs

<h1>订单列表</h1>
    <div class="record">
        <table class="order>
            <thead>
            <tr class="centerTr" >
                <th >采购凭证号</th>
                <th >公司</th>
                <th >供应商编号</th>
                <th >项目交货日期</th>
                <th >产地</th>
            </tr>
            </thead>
            <tbody>
            {{#each _DATA_.orderList}}
                <tr>
                    <td>{{purproofno}}</td>
                    <td>{{company}}</td>
                    <td>{{supplierno}}</td>
                    <td>{{projectdate}}</td>
                    <td>{{proplace}}</td>
                </tr>
            {{/each}}
            </tbody>
        </table>
    </div>

   ② 自定义Helpers使用示例:handlebars.coffee

Handlebars.registerHelper 'jsonToStr', (json, options) ->
  JSON.stringify(json)

Handlebars.registerHelper 'add', (a,b, options) ->
  a + b

Handlebars.registerHelper "formatPrice", (price, type, options) ->
  return if not price?
  if type is 1
    formatedPrice = (price / 100)
    roundedPrice = parseInt(price / 100)
  else
    formatedPrice = (price / 100).toFixed(2)
    roundedPrice = parseInt(price / 100).toFixed(2)
  if `formatePrice == roundedPrice` then roundedPrice else formatedPrice

Handlebars.registerHelper "formatDate", (date, type, options) ->
  return unless date
  switch type
    when "gmt" then moment(date).format("EEE MMM dd HH:mm:ss Z yyyy")
    when "day" then moment(date).format("YYYY-MM-DD")
    when "minute" then moment(date).format("YYYY-MM-DD HH:mm")
    else moment(date).format("YYYY-MM-DD HH:mm:ss")

Handlebars.registerHelper "lt", (a, b, options) ->
  if a < b
    options.fn(this)
  else
    options.inverse(this)

Handlebars.registerHelper "gt", (a, b, options) ->
  if a > b
    options.fn(this)
  else
    options.inverse(this)

Handlebars.registerHelper 'of', (a, b, options) ->
  values = if _.isArray b then b else b.split(",")
  if _.contains(values, a.toString()) or _.contains values, a
    options.fn(this)
  else
    options.inverse(this)

Handlebars.registerHelper 'length', (a, options) ->
  length = a.length

Handlebars.registerHelper "isArray", (a, options) ->
  if _.isArray a
    options.fn(this)
  else
    options.inverse(this)

Handlebars.registerHelper "between", (a, b, c, options) ->
  if a >= b and a <= c
    options.fn(this)
  else
    options.inverse(this)

Handlebars.registerHelper "multiple", (a, b, c, options) ->
  if c isnt 0 then a * b / c else 0

Handlebars.registerHelper "contain", (a, b, options) ->
  return options.inverse @ if a is undefined or b is undefined
  array = if _.isArray a then a else a.toString().split(",")
  if _.contains a, b then options.fn @ else options.inverse @

Handlebars.registerHelper "match", (a, b, options) ->
  return options.inverse @ if a is undefined or b is undefined
  if new RegExp(a).exec(b) is null then options.inverse @ else options.fn @

Handlebars.registerHelper "isOdd", (a, b, options) ->
  if a % b == 1
    options.fn(this)
  else
    options.inverse(this)

   handlebars.coffee编译成handlebarsApp.js的结果:

  Handlebars.registerHelper('jsonToStr', function(json, options) {
    return JSON.stringify(json);
  });

  Handlebars.registerHelper('add', function(a, b, options) {
    return a + b;
  });

  Handlebars.registerHelper("formatPrice", function(price, type, options) {
    var formatedPrice, roundedPrice;
    if (price == null) {
      return;
    }
    if (type === 1) {
      formatedPrice = price / 100;
      roundedPrice = parseInt(price / 100);
    } else {
      formatedPrice = (price / 100).toFixed(2);
      roundedPrice = parseInt(price / 100).toFixed(2);
    }
    if (formatedPrice == roundedPrice) {
      return roundedPrice;
    } else {
      return formatedPrice;
    }
  });

  Handlebars.registerHelper("formatDate", function(date, type, options) {
    if (!date) {
      return;
    }
    switch (type) {
      case "gmt":
        return moment(date).format("EEE MMM dd HH:mm:ss Z yyyy");
      case "day":
        return moment(date).format("YYYY-MM-DD");
      case "minute":
        return moment(date).format("YYYY-MM-DD HH:mm");
      default:
        return moment(date).format("YYYY-MM-DD HH:mm:ss");
    }
  });

  Handlebars.registerHelper("lt", function(a, b, options) {
    if (a < b) {
      return options.fn(this);
    } else {
      return options.inverse(this);
    }
  });

  Handlebars.registerHelper("gt", function(a, b, options) {
    if (a > b) {
      return options.fn(this);
    } else {
      return options.inverse(this);
    }
  });

  Handlebars.registerHelper('of', function(a, b, options) {
    var values;
    values = _.isArray(b) ? b : b.split(",");
    if (_.contains(values, a.toString()) || _.contains(values, a)) {
      return options.fn(this);
    } else {
      return options.inverse(this);
    }
  });

  Handlebars.registerHelper('length', function(a, options) {
    var length;
    return length = a.length;
  });

  Handlebars.registerHelper("isArray", function(a, options) {
    if (_.isArray(a)) {
      return options.fn(this);
    } else {
      return options.inverse(this);
    }
  });

  Handlebars.registerHelper("between", function(a, b, c, options) {
    if (a >= b && a <= c) {
      return options.fn(this);
    } else {
      return options.inverse(this);
    }
  });

  Handlebars.registerHelper("multiple", function(a, b, c, options) {
    if (c !== 0) {
      return a * b / c;
    } else {
      return 0;
    }
  });

  Handlebars.registerHelper("contain", function(a, b, options) {
    var array;
    if (a === void 0 || b === void 0) {
      return options.inverse(this);
    }
    array = _.isArray(a) ? a : a.toString().split(",");
    if (_.contains(a, b)) {
      return options.fn(this);
    } else {
      return options.inverse(this);
    }
  });

  Handlebars.registerHelper("match", function(a, b, options) {
    if (a === void 0 || b === void 0) {
      return options.inverse(this);
    }
    if (new RegExp(a).exec(b) === null) {
      return options.inverse(this);
    } else {
      return options.fn(this);
    }
  });

  Handlebars.registerHelper("isOdd", function(a, b, options) {
    if (a % b === 1) {
      return options.fn(this);
    } else {
      return options.inverse(this);
    }
  });
View Code

 Spring MVC框架中引入handlebars插件:

  Maven配置:handlebars和handlebars-springmvc。

<dependency>
    <groupId>com.github.jknack</groupId>
    <artifactId>handlebars</artifactId>
    <version>4.0.5</version>
</dependency>
<dependency>
    <groupId>com.github.jknack</groupId>
    <artifactId>handlebars-springmvc</artifactId>
    <version>4.0.5</version>
</dependency>

   在Spring MVC配置文件servlet-context.xml中添加handlebars视图解析器配置:

<bean id="handlebarsViewResolver" class="com.github.jknack.handlebars.springmvc.HandlebarsViewResolver">
   <property name="prefix" value="/page/" />
   <property name="suffix" value=".html" />
   <property name="contentType" value="text/html;charset=utf-8" />
   <property name="failOnMissingFile" value="false" />
   <property name="cache" value="false" />
</bean>

    Controller中实现代码:

package com.ouc.handlebars.controller;

import java.util.HashMap;
import java.util.Map;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HandlebarsController {

    @RequestMapping(value = "/testHandlebars", method = RequestMethod.GET)
    public ModelAndView helloWorld() {  
        Map<String, Object> map = new HashMap<String, Object>();  
        map.put("helloWorld", "Hello World!");  
        return new ModelAndView("helloWorld",  map);
    }
        
}

   前端helloWorld.html文件:

<!DOCTYPE >
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Hello World</title>
    <script type="text/javascript" src="js/jquery/jquery.min.js"></script>    
    <script type="text/javascript" src="js/handlebars/handlebars-4.0.5.js"></script>
</head>
<body>
    <div>
        {{helloWorld}}
    </div>    
</body>
</html>

 ④ 自定义Helpers后台实现:OucHandlebarHelpers.java

package ouc.handlebars.web.helpers;

import com.github.jknack.handlebars.Helper;
import com.github.jknack.handlebars.Options;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import ouc.handlebars.common.utils.MapBuilder;
import ouc.handlebars.common.utils.NumberUtils;
import ouc.handlebars.common.utils.Splitters;
import ouc.handlebars.pampas.engine.handlebars.HandlebarsEngine;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.Hours;
import org.joda.time.Minutes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Component
public class OucHandlebarHelpers {
    @Autowired
    private HandlebarsEngine handlebarEngine;

    @PostConstruct
    public void init() {
        handlebarEngine.registerHelper("isEmpty", new Helper<Object>() {
            @Override
            public CharSequence apply(Object obj, Options options) throws IOException {
                if (obj == null || obj.equals("")) {
                    return options.fn();
                } else {
                    return options.inverse();
                }
            }
        });

        //此标签相当于 and 连接的if判断
        handlebarEngine.registerHelper("multipleEquals", new Helper<Object>() {
            @Override
            public CharSequence apply(Object source, Options options) throws IOException {
                CharSequence ch=options.fn();
                CharSequence ch2=options.inverse();

                String obj1=String.valueOf(source);
                Object[] other=options.params;
                if(!Objects.equal(obj1,String.valueOf(other[0]))){
                    return ch2;
                }

                for (int i = 1; i < other.length; i+=2) {
                    if(!Objects.equal(String.valueOf(other[i]),String.valueOf(other[i+1]))){
                        return ch2;
                    }
                }
                return ch;
            }
        });

        handlebarEngine.registerHelper("get", new Helper<Object>() {
            @Override
            public CharSequence apply(Object context, Options options) throws IOException {
                Object collections;
                Object param = options.param(0);
                if (context instanceof List || context instanceof Map) {
                    collections = context;
                }
                else {
                    collections = Splitters.COMMA.splitToList(String.valueOf(context));
                }

                if (param == null) {
                    return null;
                }

                if(collections instanceof List){
                    return ((List)collections).get(Integer.valueOf(param.toString())).toString();
                }
                else{
                    return ((Map)collections).get(param).toString();
                }
            }
        });

        handlebarEngine.registerHelper("contain", new Helper<Object>() {
            @Override
            public CharSequence apply(Object context, Options options) throws IOException {
                Object collections;
                Object param = options.param(0);
                if (context instanceof Collection || context instanceof Map ) {
                    collections = context;
                }
                else{
                    collections = Splitters.COMMA.splitToList(String.valueOf(context));
                }

                if (param == null) {
                    return options.fn();
                }

                if(collections instanceof Collection){
                    if(((Collection)collections).contains(param)){
                        return options.fn();
                    }
                    else{
                        return options.inverse();
                    }
                }
                else {
                    Map map = (Map)collections;
                    String check = options.param(1, "ALL");
                    if("key".equalsIgnoreCase(check)){
                        if(map.keySet().contains(param)){
                            return options.fn();
                        }
                        else{
                            return options.inverse();
                        }
                    }
                    else if("value".equalsIgnoreCase(check)){
                        if(map.values().contains(param)){
                            return options.fn();
                        }
                        else{
                            return options.inverse();
                        }
                    }
                    else{
                        if(map.keySet().contains(param) || map.values().contains(param)){
                            return options.fn();
                        }
                        else{
                            return options.inverse();
                        }
                    }
                }
            }
        });

        handlebarEngine.registerHelper("containAny", new Helper<Object>() {
            @Override
            public CharSequence apply(Object context, Options options) throws IOException {
                Object collections;
                if (context instanceof Collection || context instanceof Map) {
                    collections = context;
                } else {
                    collections = Splitters.COMMA.splitToList(String.valueOf(context));
                }

                if (options.params == null || options.params.length == 0) {
                    return options.fn();
                }

                if(collections instanceof Collection){
                    for (Object param : options.params) {
                        for (String p : Splitters.COMMA.splitToList((String)param)) {
                            if (((Collection)collections).contains(p)) {
                                return options.fn();
                            }
                        }
                    }
                    return options.inverse();
                } else {
                    Map map = (Map)collections;
                    for (Object param : options.params) {
                        for (String p : Splitters.COMMA.splitToList((String) param)) {
                            if (map.keySet().contains(p) || map.values().contains(p)) {
                                return options.fn();
                            }
                        }
                    }
                    return options.inverse();
                }
            }
        });

        /**
         *
         * 传参 a, b, c
         * 然后a是一个"2015-08-12"或者''2015-08-12 12:00:00"
         * b的值可以是"dayStart",''now","dayEnd","2015-08-15",''2015-08-15 12:00:00"中的一个
         * 如果b是dayStart, a就和当天的0点0分比较
         * 如果b是now, a就和现在时间比较
         * 如果b是dayEnd, a就和第二天的0点0分比较
         * 如果b是一个date,a就和b比较
         * 第三个参数:
         * 设置时间的比较级别:s:秒,m:分,h:小时,d:天
         */
        handlebarEngine.registerHelper("comDate", new Helper<Object>() {
            @Override
            public CharSequence apply(Object context, Options options) throws IOException {
                //获取参数
                Object param2 = options.param(0);

                //默认按照秒比较时间
                String comType = MoreObjects.firstNonNull((String) options.param(1), "s");

                if(context == null || param2 == null){
                    return options.fn();
                }else{
                    Date comTime1 = new DateTime(context).toDate();//Date)param1;

                    String param = (String)param2;
                    Date comTime2;
                    if(Objects.equal(param , "dayStart")){
                        //compare1与当天的0点0分比较

                        comTime2 = DateTime.now().withTime(0 , 0, 0, 0).toDate();
                    }else if(Objects.equal(param , "now")){
                        //compare1就和现在时间比较

                        comTime2 = DateTime.now().toDate();
                    }else if(Objects.equal(param , "dayEnd")){
                        //compare1就和第二天的0点0分比较

                        comTime2 = DateTime.now().plusDays(1).withTime(0 , 0, 0, 0).toDate();
                    }else{
                        //compare1就和compare2比较

                        comTime2 = DateTime.parse(param).toDate();
                    }

                    if(compareTime(comTime1 , comTime2 , comType)){
                        return options.inverse();
                    }else{
                        return options.fn();
                    }
                }
            }
        });

        /**
         * 格式化金钱 第一个参数格式化到得金额,第二个是保留小数的位数,第三个是传值为空时返回
         * 什么数据,E-empty string(默认),Z-zero
         * {{formatPrice 变量名 "W" 2 E}}
         */
        handlebarEngine.registerHelper("formatPrice", new Helper<Number>() {
            Map<String, Integer> sdfMap = MapBuilder.<String, Integer>of().put(
                    "W", 1000000,
                    "Q", 100000,
                    "B", 10000,
                    "Y", 100
            ).map();
            @Override
            public CharSequence apply(Number price, Options options) throws IOException {
                String defaultValue = "E";
                if (options.params != null && options.params.length ==3) {
                    defaultValue = options.param(2).toString();
                }
                if (price == null) return defValue(defaultValue);

                if (options.params == null || options.params.length == 0){
                    return NumberUtils.formatPrice(price);
                }
                else if( options.params.length == 1){
                    Object param1 = options.param(0);
                    int divisor = sdfMap.get(param1.toString().toUpperCase()) == null?1:sdfMap.get(param1.toString().toUpperCase());
                    return getDecimalFormat(2).format(price.doubleValue()/divisor);
                }
                else if (options.params.length == 2 || options.params.length ==3 ){
                    Object param1 = options.param(0);
                    Object param2 = options.param(1);
                    int divisor = sdfMap.get(param1.toString().toUpperCase()) == null?1:sdfMap.get(param1.toString().toUpperCase());
                    return getDecimalFormat(Integer.valueOf(param2.toString())).format(price.doubleValue() / divisor);
                }
                return "";
            }
        });

        /**
         * Usage: <span>{{formatDecimal 10101.2 2}}</span> ->
         *        <span> 10,101.20 </span>
         * 第一个参数是传入的数,第二是保留小数位
         * 默认不保留小数位
         */
        handlebarEngine.registerHelper("formatDecimal", new Helper<Number>() {

            @Override
            public CharSequence apply(Number number, Options options) throws IOException {
                if (number == null) {
                    return "0";
                }
                DecimalFormat df;
                if (options.params == null || options.params.length == 0) {
                    df = getDecimalFormat(0);
                } else {
                    df = getDecimalFormat(Integer.valueOf(options.params[0].toString()));
                }
                return df.format(number.doubleValue());
            }
        });
    }

    private String defValue(String defaultValue) {
        if (defaultValue.toUpperCase().equals("E")) {
            return "";
        }
        if (defaultValue.toUpperCase().equals("Z")) {
            return "0";
        }
        return "";
    }

    private DecimalFormat getDecimalFormat(Integer digits){
        DecimalFormat decimalFormat = new DecimalFormat();
        Integer fractionDigits = digits == null? 2:digits;
        decimalFormat.setMaximumFractionDigits(fractionDigits);
        decimalFormat.setMinimumFractionDigits(fractionDigits);
        return decimalFormat;
    }

    /**
     * 比较开始时间以及结束时间之间的大小(按照比较级别)
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param comType   比较级别
     * @return  Boolean
     * 返回是否大于(true:大于, false:小于)
     */
    private Boolean compareTime(Date startTime , Date endTime, String comType){
        Boolean result = false;
        if(Objects.equal(comType , "s")){
            //按照秒比较
            result = startTime.after(endTime);
        }else if(Objects.equal(comType , "m")){
            //按照分钟比较
            result = Minutes.minutesBetween(new DateTime(startTime), new DateTime(endTime)).getMinutes() > 0;
        }else if(Objects.equal(comType , "h")){
            //按照小时比较
            result = Hours.hoursBetween(new DateTime(startTime), new DateTime(endTime)).getHours() > 0;
        }else if(Objects.equal(comType , "d")){
            //按照天比较
            result = Days.daysBetween(new DateTime(startTime), new DateTime(endTime)).getDays() > 0;
        }

        return result;
    }

}
View Code

  ⑤ HandlebarsEngine.java

package ouc.handlebars.pampas.engine.handlebars;  
   
import com.github.jknack.handlebars.Handlebars;  
import com.github.jknack.handlebars.HandlebarsException;  
import com.github.jknack.handlebars.Helper;  
import com.github.jknack.handlebars.Template;  
import com.github.jknack.handlebars.io.TemplateLoader;  
import com.google.common.base.Optional;  
import com.google.common.base.Strings;  
import com.google.common.base.Throwables;  
import com.google.common.cache.CacheBuilder;  
import com.google.common.cache.CacheLoader;  
import com.google.common.cache.LoadingCache;  
import com.google.common.collect.Maps;  
import ouc.handlebars.pampas.common.UserNotLoginException;  
import ouc.handlebars.pampas.common.UserUtil;  
import ouc.handlebars.pampas.engine.RenderConstants;  
import ouc.handlebars.pampas.engine.Setting;  
import ouc.handlebars.pampas.engine.config.ConfigManager;  
import ouc.handlebars.pampas.engine.config.model.Component;  
import ouc.handlebars.pampas.engine.mapping.Invoker;  
import lombok.extern.slf4j.Slf4j;  
import org.springframework.beans.factory.annotation.Autowired;  
   
import javax.servlet.ServletContext;  
import java.io.FileNotFoundException;  
import java.util.Map;  
import java.util.concurrent.TimeUnit;  
   
/**  
 * Author: Wu Ping  
 */ 
@org.springframework.stereotype.Component  
@Slf4j 
public class HandlebarsEngine {  
   
    private Handlebars handlebars;  
   
    private Invoker invoker;  
   
    private final LoadingCache<String, Optional<Template>> caches;  
   
    private ConfigManager configManager;  
   
    @Autowired 
    public HandlebarsEngine(Invoker invoker,  
                            Setting setting,  
                            ConfigManager configManager,  
                            ServletContext servletContext) {  
        this.invoker = invoker;  
        TemplateLoader templateLoader = new GreatTemplateLoader(servletContext, 

"/views", ".hbs");  
        this.handlebars = new Handlebars(templateLoader);  
        this.caches = initCache(!setting.isDevMode());  
        this.configManager = configManager;  
    }  
   
    private LoadingCache<String, Optional<Template>> initCache(boolean buildCache) {  
        if (buildCache) {  
            return CacheBuilder.newBuilder().expireAfterWrite(5, 

TimeUnit.MINUTES).build(new CacheLoader<String, Optional<Template>>() {  
                @Override 
                public Optional<Template> load(String path) throws Exception {  
                    Template t = null;  
                    try {  
                        t = handlebars.compile(path);  
                    } catch (Exception e) {  
                        log.error("failed to compile template(path={}), cause:

{}",path, e.getMessage());  
                    }  
                    return Optional.fromNullable(t);  
                }  
            });  
        }  
        return null;  
    }  
   
    public <T> void registerHelper(String name, Helper<T> helper) {  
        handlebars.registerHelper(name, helper);  
    }  
   
    public String execInline(String templateStr, Map<String, Object> params) {  
        return execInline(templateStr, params, null);  
    }  
   
    public String execInline(String templateStr, Map<String, Object> params, String 

cacheKey) {  
        try {  
            if (params == null) {  
                params = Maps.newHashMap();  
            }  
            Template template;  
            if (caches == null || cacheKey == null) {  
                template = handlebars.compileInline(templateStr);  
            } else {  
                template = caches.getUnchecked("inline/" + cacheKey).orNull();  
            }  
            if(template == null){  
                log.error("failed to exec handlebars' template:{}", templateStr);  
                return "";  
            }  
            return template.apply(params);  
        } catch (Exception e) {  
            log.error("exec handlebars' template failed: {},cause:{}", templateStr, 

Throwables.getStackTraceAsString(e));  
            return "";  
        }  
   
    }  
   
    @SuppressWarnings("unchecked")  
    public String execPath(String path, Map<String, Object> params, boolean 

isComponent) throws FileNotFoundException {  
        try {  
            if (params == null) {  
                params = Maps.newHashMap();  
            }  
   
            Template template;  
            if (isComponent) {  
                if (caches == null) {  
                    template = handlebars.compile("component:" + path);  
                } else {  
                    template = caches.getUnchecked("component:" + path).orNull();  
                }  
                params.put(RenderConstants.COMPONENT_PATH, path);  
            } else {  
                if (caches == null) {  
                    template = handlebars.compile(path);  
                } else {  
                    template = caches.getUnchecked(path).orNull();  
                }  
            }  
   
            params.put(RenderConstants.USER, UserUtil.getCurrentUser()); //user  
            params.put(RenderConstants.HREF, configManager.getFrontConfig

().getCurrentHrefs(Setting.getCurrentHost()));  
            if(template == null){  
                log.error("failed to exec handlebars' template:path={}", path);  
                return "";  
            }  
            return template.apply(params);  
   
        } catch (Exception e) {  
            Throwables.propagateIfInstanceOf(e, FileNotFoundException.class);  
            if (e instanceof HandlebarsException) {  
                Throwables.propagateIfInstanceOf(e.getCause(), 

UserNotLoginException.class);  
            }  
            log.error("failed to execute handlebars' template(path={}),cause:{} ",  
                    path, Throwables.getStackTraceAsString(e));  
        }  
   
        return "";  
    }  
   
    public String execComponent(final Component component, final Map<String, Object> 

context) {  
        if (!Strings.isNullOrEmpty(component.getService())) {  
            Object object = null;  
            try {  
                object = invoker.invoke(component.getService(), context);  
            } catch (UserNotLoginException e) {  
                log.error("user doesn't login.");  
                if (context.get(RenderConstants.DESIGN_MODE) == null) {  
                    throw e; // 非 DESIGN_MODE 时未登录需要抛出  
                }  
            } catch (Exception e) {  
                log.error("error when invoke component, component: {}", component, e); 

 
                context.put(RenderConstants.ERROR, e.getMessage());  
            }  
            context.put(RenderConstants.DATA, object);  
        }  
        try {  
            return execPath(component.getPath(), context, true);  
        } catch (Exception e) {  
            log.error("failed to execute handlebars' template(path={}),cause:{} ",  
                    component.getPath(), Throwables.getStackTraceAsString(e));  
        }  
        return "";  
    }  
   
} 
View Code

   整个块级Helpers的介绍基本就到这里了,前面介绍handlebars的文章都不错。

   李白准备在黄鹤楼上题诗的时候看了崔颢写的诗,他认为崔颢的诗可以称为是千古绝唱,觉着自己写不出可以超越崔颢的作品,所以慨叹:“眼前有景道不得,崔颢题诗在上头”。

原文地址:https://www.cnblogs.com/wp5719/p/5707895.html