上一篇文章中,已经对freemarker做了简单的了解;动态表单的概念大家也应该不陌生了,在《浅析动态表单》文章中已经做了一定的分析;jstl自定义标签也比较熟悉了,在此之前已经使用多次了。今天我们就使用freemarker+jstl自定义标签实现动态表单的显示。
下面是我总结的使用动态表单的主要步骤,大家做个参考:
本例在SSH项目里面实现,所以需要配置ActionForm,Document为本例的应用,其对应的ActionForm中另外添加类型为Map的props属性,用来获得与设置模板的变量:
public class DocumentActionForm extends ActionForm { private int id; /** * 页面上通过: * <input type="text" name="props(KEY)" > * ------->getProps().put(KEY,value) */ private Map props = new HashMap(); public int getId() { return id; } public void setId(int id) { this.id = id; } public Map getProps() { return props; } public void setProps(Map props) { this.props = props; } }
我们将模板都定义成.ftl文件,便于嵌套使用。下面列出了本例子当中的一些模板:
document_form.ftl:该模板定义表单域内容,也就是说,本例子主要通过该模板进行动态显示。根据用户相应的操作,该模板会根据fieldInput中的template属性,调用不同的子模板。
<table class="tableEdit" style="width:580px;" cellspacing="0" border="0" cellpadding="0"> <#assign i = 0> <#list form.fields as field> <#assign i = i + 1> <#if field_index % 2 = 0> <tr> </#if> <!--fieldLabel为actionForm里面定义的标签字段,此处意思为从表单域中取出标签--> <td class="tdEditLabel" >${field.fieldLabel}</td> <!--fieldInput里面的template字段表示模板的名称,针对这个页面表单元素,如何呈现为HTML代码--> <td class="tdEditContent"><#include "${field.fieldInput.template}"></td> <#if i = 2 || !field_has_next> <#assign i = 0> </tr> </#if> </#list> </table>
下面分别是file.ftl、select.ftl和text.ftl对应的子模板:
<input type="file" name="props(${field.fieldName})">
<select name="props(${field.fieldName})"> <#list field.items as item> <option value="${item.value}">${item.label}</option> </#list> </select>
<input type="text" name="props(${field.fieldName})">
FreeMarkerManager类里面定义了加载模板、设置对象包装器、设置异常处理器等一系列模板处理的步骤,也就是包含了对对模板的处理。
public class FreeMarkerManager { private static Configuration cfg =new Configuration(); static{ //定义模板的位置:从类路径中,相对于FreeMarkerManager所在的路径加载模板 cfg.setTemplateLoader(new ClassTemplateLoader(FreeMarkerManager.class, "templates")); //设置对象包装器 cfg.setObjectWrapper(new DefaultObjectWrapper()); //设置异常处理器 cfg.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER); } public static Configuration getConfiguration(){ return cfg; } }
本方法里面得到模板配置对象,对模板进行解释,进行输出。
/** * 用于freemarker的jstl界面显示函数 * @author lzq * */ public class DynaFormFunction { private static FormManager formManager; private static String defaultTemplate="document_form.ftl"; public static String form(int workflowId){ try { //查找表单定义 FlowForm form = formManager.findForm(workflowId); if (form == null) { return null; } //得到模板配置 Configuration cfg =FreeMarkerManager.getConfiguration(); Template template = null; if (form.getTemplate() == null || form.getTemplate().trim().equals("")) { template = cfg.getTemplate(defaultTemplate); }else { template = cfg.getTemplate(form.getTemplate()); } //最终输出的位置 Writer out = new StringWriter(); //数据模型 Map rootMap = new HashMap(); rootMap.put("form", form); //模板引擎,解释模板 template.process(rootMap, out); return out.toString(); } catch (Exception e) { e.printStackTrace(); return null; } } public void setFormManager(FormManager formManager) { DynaFormFunction.formManager = formManager; } public void setDefaultTemplate(String defaultTemplate) { DynaFormFunction.defaultTemplate = defaultTemplate; } }
JSTL自定义标签的对应的配置my.tld文件:
<?xml version="1.0" encoding="UTF-8" ?> <taglib> <tlib-version>1.1</tlib-version> <short-name>my</short-name> <uri>http://www.lzq.com/functions</uri> <function> <name>form</name> <function-class>com.lzq.web.DynaFormFunction</function-class> <function-signature>java.lang.String form(int)</function-signature> </function> </taglib>
页面调用JSTL:
${my:form(documentForm.workflowId) }
如此,便能在页面上显示动态的表单了。