1 import java.io.IOException; 2 import java.io.Writer; 3 import java.util.Iterator; 4 import java.util.Map; 5 6 import freemarker.core.Environment; 7 import freemarker.template.SimpleNumber; 8 import freemarker.template.TemplateBooleanModel; 9 import freemarker.template.TemplateDirectiveBody; 10 import freemarker.template.TemplateDirectiveModel; 11 import freemarker.template.TemplateException; 12 import freemarker.template.TemplateModel; 13 import freemarker.template.TemplateModelException; 14 import freemarker.template.TemplateNumberModel; 15 16 /** 17 * FreeMarker 自定義標籤實現重複輸出內容體。 18 * 19 * 20 * 參數: 21 * count: 重複的次數,必須的且非負整數。 22 * hr: 設置是否輸出HTML標籤 "hr" 元素. Boolean. 可選的默認爲fals. 23 * 24 * 25 * 循環變量: 只有一個,可選的. 從1開始。 26 * 27 * 28 */ 29 public class RepeatDirective implements TemplateDirectiveModel { 30 31 private static final String PARAM_NAME_COUNT = "count"; 32 private static final String PARAM_NAME_HR = "hr"; 33 34 public void execute(Environment env, Map params, TemplateModel[] loopVars, 35 TemplateDirectiveBody body) throws TemplateException, IOException { 36 37 // --------------------------------------------------------------------- 38 // 處理參數 39 40 int countParam = 0; 41 boolean countParamSet = false; 42 boolean hrParam = false; 43 44 Iterator paramIter = params.entrySet().iterator(); 45 while (paramIter.hasNext()) { 46 Map.Entry ent = (Map.Entry) paramIter.next(); 47 48 String paramName = (String) ent.getKey(); 49 TemplateModel paramValue = (TemplateModel) ent.getValue(); 50 51 if (paramName.equals(PARAM_NAME_COUNT)) { 52 if (!(paramValue instanceof TemplateNumberModel)) { 53 throw new TemplateModelException("The \"" + PARAM_NAME_HR 54 + "\" parameter " + "must be a number."); 55 } 56 countParam = ((TemplateNumberModel) paramValue).getAsNumber() 57 .intValue(); 58 countParamSet = true; 59 if (countParam < 0) { 60 throw new TemplateModelException("The \"" + PARAM_NAME_HR 61 + "\" parameter " + "can't be negative."); 62 } 63 } else if (paramName.equals(PARAM_NAME_HR)) { 64 if (!(paramValue instanceof TemplateBooleanModel)) { 65 throw new TemplateModelException("The \"" + PARAM_NAME_HR 66 + "\" parameter " + "must be a boolean."); 67 } 68 hrParam = ((TemplateBooleanModel) paramValue).getAsBoolean(); 69 } else { 70 throw new TemplateModelException("Unsupported parameter: " 71 + paramName); 72 } 73 } 74 if (!countParamSet) { 75 throw new TemplateModelException("The required \"" 76 + PARAM_NAME_COUNT + "\" paramter" + "is missing."); 77 } 78 79 if (loopVars.length > 1) { 80 throw new TemplateModelException( 81 "At most one loop variable is allowed."); 82 } 83 84 // Yeah, it was long and boring... 85 86 // --------------------------------------------------------------------- 87 // 真正開始處理輸出內容 88 89 Writer out = env.getOut(); 90 if (body != null) { 91 for (int i = 0; i < countParam; i++) { 92 // 輸出 <hr> 若是 參數hr 設置爲true 93 if (hrParam && i != 0) { 94 out.write("<hr>"); 95 } 96 97 // 設置循環變量 98 if (loopVars.length > 0) { 99 loopVars[0] = new SimpleNumber(i + 1); 100 } 101 102 // 執行標籤內容(same as <#nested> in FTL). 103 body.render(env.getOut()); 104 } 105 } 106 } 107 108 }
1 import java.io.File; 2 import java.io.IOException; 3 import java.io.Writer; 4 import java.util.Map; 5 6 import freemarker.template.Configuration; 7 import freemarker.template.DefaultObjectWrapper; 8 import freemarker.template.Template; 9 import freemarker.template.TemplateException; 10 11 /** 12 * 13 * 模板工具類 14 */ 15 public class FreeMarkertUtil { 16 /** 17 * @param templatePath 模板文件存放目錄 18 * @param templateName 模板文件名稱 19 * @param root 數據模型根對象 20 * @param templateEncoding 模板文件的編碼方式 21 * @param out 輸出流 22 */ 23 public static void processTemplate(String templatePath, String templateName, String templateEncoding, Map<?,?> root, Writer out){ 24 try { 25 Configuration config=new Configuration(); 26 File file=new File(templatePath); 27 //設置要解析的模板所在的目錄,並加載模板文件 28 config.setDirectoryForTemplateLoading(file); 29 //設置包裝器,並將對象包裝爲數據模型 30 config.setObjectWrapper(new DefaultObjectWrapper()); 31 32 //獲取模板,並設置編碼方式,這個編碼必需要與頁面中的編碼格式一致 33 Template template=config.getTemplate(templateName,templateEncoding); 34 //合併數據模型與模板 35 36 template.process(root, out); 37 out.flush(); 38 out.close(); 39 } catch (IOException e) { 40 e.printStackTrace(); 41 }catch (TemplateException e) { 42 e.printStackTrace(); 43 } 44 45 } 46 }
1 import java.io.OutputStreamWriter; 2 import java.util.HashMap; 3 import java.util.Map; 4 5 /** 6 * 7 * 客戶端測試模板輸入類 8 */ 9 public class RepeatTest { 10 public static void main(String[] args) { 11 Map<String,Object> root=new HashMap<String, Object>(); 12 13 root.put("repeat", new RepeatDirective()); 14 15 FreeMarkertUtil.processTemplate("src/templates","repeat.ftl", "UTF-8", root, new OutputStreamWriter(System.out)); 16 17 } 18 }
1 模板文件repeat.ftl以下: 2 3 4 5 <#assign x = 1> 6 7 一個參數: 8 <@repeat count=4> 9 Test ${x} 10 <#assign x = x + 1> 11 </@repeat> 12 13 二個參數: 14 <@repeat count=3 hr=true> 15 Test 16 </@repeat> 17 18 循環變量: 19 <@repeat count=3; cnt> 20 ${cnt}. Test
輸出結果:java