021_程序指令
1. Java程序員可以使用TemplateDirectiveModel接口在Java代碼中實現自定義指令。
2. 例子
2.1. 新建一個名為FMProgrammingDirective的動態Web工程, 同時添加相關jar包。
2.2. 編寫FMFactory.java
package com.fm.util;import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import freemarker.template.Configuration; import freemarker.template.TemplateExceptionHandler;public class FMFactory {private final static FMFactory instance = new FMFactory();private FMFactory() {}public static FMFactory getInstance() {return instance;}private Map<String, Configuration> map = new ConcurrentHashMap<String, Configuration>();// 創建單個Configuration實例public synchronized Configuration getCfg(Object servletContext, String path) {if(null != map.get(path)) {return map.get(path);}Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);cfg.setServletContextForTemplateLoading(servletContext, path);cfg.setDefaultEncoding("utf-8");cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);map.put(path, cfg);return cfg;}}2.3. 編寫UpperDirective.java
package com.fm.action;import java.io.IOException; import java.io.Writer; import java.util.Map; import freemarker.core.Environment; import freemarker.template.TemplateDirectiveBody; import freemarker.template.TemplateDirectiveModel; import freemarker.template.TemplateException; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException;/*** 自定義指令可以將在它開始標簽和結束標簽之內的字符都轉換為大寫形式。*/ public class UpperDirective implements TemplateDirectiveModel {public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException {// 沒有參數if (!params.isEmpty()) {throw new TemplateModelException("This directive doesn't allow parameters.");}if (loopVars.length != 0) {throw new TemplateModelException("This directive doesn't allow loop variables.");}// 標簽有中間內容if (body != null) {body.render(new UpperCaseFilterWriter(env.getOut()));} else {throw new RuntimeException("missing body");}}private static class UpperCaseFilterWriter extends Writer {private final Writer out;UpperCaseFilterWriter(Writer out) {this.out = out;}public void write(char[] cbuf, int off, int len) throws IOException {char[] transformedCbuf = new char[len];for (int i = 0; i < len; i++) {transformedCbuf[i] = Character.toUpperCase(cbuf[i + off]);}out.write(transformedCbuf);}public void flush() throws IOException {out.flush();}public void close() throws IOException {out.close();}}}2.4. 編寫RepeatDirective.java
package com.fm.action;import java.io.IOException; import java.io.Writer; import java.util.Iterator; import java.util.Map; import freemarker.core.Environment; import freemarker.template.SimpleNumber; import freemarker.template.TemplateBooleanModel; import freemarker.template.TemplateDirectiveBody; import freemarker.template.TemplateDirectiveModel; import freemarker.template.TemplateException; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateNumberModel;/*** 自定義指令可以一次又一次地執行其中的嵌套內容, 這個次數由指定的數字來確定, 可以使用<hr />將輸出的重復內容分開。*/ public class RepeatDirective implements TemplateDirectiveModel {private static final String PARAM_NAME_COUNT = "count";private static final String PARAM_NAME_HR = "hr";public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException {int countParam = 0;boolean countParamSet = false;boolean hrParam = false;Iterator paramIter = params.entrySet().iterator();while (paramIter.hasNext()) {Map.Entry ent = (Map.Entry) paramIter.next();String paramName = (String) ent.getKey();TemplateModel paramValue = (TemplateModel) ent.getValue();if (paramName.equals(PARAM_NAME_COUNT)) {if (!(paramValue instanceof TemplateNumberModel)) {throw new TemplateModelException("The \"" + PARAM_NAME_HR + "\" parameter " + "must be a number.");}countParam = ((TemplateNumberModel) paramValue).getAsNumber().intValue();countParamSet = true;if (countParam < 0) {throw new TemplateModelException("The \"" + PARAM_NAME_HR + "\" parameter " + "can't be negative.");}} else if (paramName.equals(PARAM_NAME_HR)) {if (!(paramValue instanceof TemplateBooleanModel)) {throw new TemplateModelException("The \"" + PARAM_NAME_HR + "\" parameter " + "must be a boolean.");}hrParam = ((TemplateBooleanModel) paramValue).getAsBoolean();} else {throw new TemplateModelException("Unsupported parameter: " + paramName);}}if (!countParamSet) {throw new TemplateModelException("The required \"" + PARAM_NAME_COUNT + "\" paramter" + "is missing.");}if (loopVars.length > 1) {throw new TemplateModelException("At most one loop variable is allowed.");}Writer out = env.getOut();if (body != null) {for (int i = 0; i < countParam; i++) {if (hrParam && i != 0) {out.write("<hr />");}if (loopVars.length > 0) {loopVars[0] = new SimpleNumber(i + 1);}body.render(env.getOut());}}}}2.5. 編寫ProgrammingDirective.java
package com.fm.action;import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.fm.util.FMFactory; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateException;public class ProgrammingDirective extends HttpServlet {private static final long serialVersionUID = 1L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {Configuration cfg = FMFactory.getInstance().getCfg(req.getServletContext(), "/WEB-INF/templates");Template template = cfg.getTemplate("programmingdirective.html");Map<String, Object> root = new HashMap<String, Object>();root.put("upper", new UpperDirective());root.put("repeat", new RepeatDirective());Writer out = new OutputStreamWriter(resp.getOutputStream());try {template.process(root, out);} catch (TemplateException e) {e.printStackTrace();}}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);} }2.6. 修改web.xml
2.7. 在/WEB-INF/templates目錄下編寫programmingdirective.html
<!DOCTYPE html> <html><head><meta charset="UTF-8" /><title>程序指令</title></head><body><h2>字符都轉換為大寫</h2>foo<br /><@upper>bar<br /><#list ["red", "green", "blue"] as color>${color}<br /></#list>baaz<br /></@upper>wombat<h2>循環執行其中的嵌套內容</h2><#assign x = 1><@repeat count=4>Test ${x}<#assign x++></@repeat><br /><br /><@repeat count=3 hr=true>Test</@repeat><br /><br /><@repeat count=3; cnt>${cnt}. Test</@repeat></body> </html>2.8. 運行項目
?
總結
- 上一篇: 020_程序方法
- 下一篇: 022_配置configuration