package com.norteksoft.mms.base.utils; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import net.htmlparser.jericho.Element; import net.htmlparser.jericho.FormControl; import net.htmlparser.jericho.FormField; import net.htmlparser.jericho.FormFields; import net.htmlparser.jericho.OutputDocument; import net.htmlparser.jericho.Source; import freemarker.cache.StringTemplateLoader; import freemarker.template.Configuration; import freemarker.template.SimpleHash; import freemarker.template.Template; import freemarker.template.TemplateException; /** * 根据给定的对象及HTML片段给HTML片段赋值 * HTML片段中所有需要填充的域的name属性必须和对象中的属性名对应; * 动态select选项的需要提供 @see SelectOptions 的对应实现类 * * @author xj */ public class FreeMarkertUtils { private static String DATA_TYPE_PROP_NAME = "datatype"; private static String DEFAULT_ENTITY_NAME = "obj_value_prefix"; private static Configuration config = null; enum DataType{ AMOUNT("金额"), TEXT("文本"), NUMBER("数字"), DATE("日期"), TIME("时间"); public String code; DataType(String code){ this.code=code; } public Short getIndex(){ return (short)(this.ordinal()+1); } public String getCode(){ return this.code; } } private FreeMarkertUtils(){} private static void init() throws TemplateException{ if (config == null) { config = new Configuration(); config.setTemplateLoader(new StringTemplateLoader()); config.setClassicCompatible(true); config.setLocale(Locale.CHINA); } } /** * 根据Map * @param dataModel * @param html * @param addPrefix 是否添加前缀,为实体时设置为true * @return */ public static String render(Map<?, ?> dataModel, String html, boolean addPrefix) { String ret = null; BufferedReader reader=null; StringWriter stringWriter=null; BufferedWriter writer=null; try { init(); html = templateProcess(html, addPrefix); reader= new BufferedReader(new StringReader(html)); Template template = new Template(null, reader, config, "UTF-8"); SimpleHash root = new SimpleHash(); root.putAll(dataModel); stringWriter= new StringWriter(); writer = new BufferedWriter(stringWriter); template.process(root, writer); writer.flush(); ret = stringWriter.toString(); } catch (Exception ex) { ret = null; ex.printStackTrace(); throw new RuntimeException(ex.getMessage()); }finally{ try { if(reader != null) reader.close(); if(writer != null) writer.close(); } catch (IOException e) { throw new RuntimeException(e.getMessage()); } } return ret; } /** * 根据对象为HTML片段赋值(实体) * @param valueObject * @param html * @return */ public static String render(Object valueObject, String html){ String resultHtml = html; if(valueObject == null){ resultHtml = selectOptionsProcess(html); }else{ Map<String, Object> test = new HashMap<String, Object>(); test.put(DEFAULT_ENTITY_NAME, valueObject); resultHtml = render(test, html, true); } return resultHtml; } /* * 将HTML解析为FreemMrker可以出来的模板 * @param html * @return * @throws IOException */ private static String templateProcess(String html, boolean addPrefix) throws IOException{ html = selectOptionsProcess(html); Source source = getSourceByHtml(html); OutputDocument outputDocument = new OutputDocument(source); //处理动态select的选项 FormFields formFields=source.getFormFields(); for(FormField field : formFields){ //将表单的域替换为free mark可替换的模板 formFieldProcess(field, outputDocument, addPrefix); } html = outputDocument.toString().replaceAll("<", "<").replaceAll(">", ">"); return html; } /* * 根据Html获取jericho的Source * @param html * @return * @throws IOException */ private static Source getSourceByHtml(String html) throws IOException{ BufferedReader reader = null; Source source = null; try { reader = new BufferedReader(new StringReader(html)); source = new Source(reader); } finally{ reader.close(); } return source; } /* * 处理动态select的选项 * @param html * @return */ private static String selectOptionsProcess(String html){ Source source; try { source = getSourceByHtml(html); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e.getMessage()); } OutputDocument outputDocument = new OutputDocument(source); //selectOptionsProcess(source, outputDocument); return outputDocument.toString(); } /* * 将表单的域替换为free mark可替换的模板 * @param field * @param outputDocument */ private static void formFieldProcess(FormField field, OutputDocument outputDocument, boolean addPrefix){ Collection<FormControl> controls = field.getFormControls(); if(controls.size() == 1){ //类型不为radio、checkbox的input和select、textarea singleTagProcess(field.getFormControl(), outputDocument, addPrefix); }else{ //类型为radio、checkbox的input sameNameTagsProcess(controls, outputDocument, addPrefix); } } /* * 类型不为radio、checkbox的input和select、textarea * @param field * @param outputDocument * @return */ private static OutputDocument singleTagProcess(FormControl control, OutputDocument outputDocument, boolean addPrefix){ String valueExpr = ""; List<Element> subElements = control.getAllElements(); if(addPrefix) valueExpr = DEFAULT_ENTITY_NAME+"." + subElements.get(0).getAttributeValue("name"); else valueExpr = subElements.get(0).getAttributeValue("name"); //简单input和textarea if(subElements.size() == 1){ //日期类型 if(DataType.DATE.toString().equals(subElements.get(0).getAttributeValue(DATA_TYPE_PROP_NAME))){ control.setValue(new StringBuilder("<#if ").append(valueExpr).append("?exists>${") .append(valueExpr).append("?date}</#if>").toString()); }else{ control.setValue("${"+valueExpr+"}"); } outputDocument.replace(control); }else{//select boolean isFirst = true; String newElementString = ""; for(Element sub : subElements){ if(isFirst){isFirst = false; continue;} newElementString = new StringBuilder(" <#if ").append(valueExpr).append("==\"") .append(sub.getAttributeValue("value")).append("\">selected='selected'</#if>>").toString(); outputDocument.replace(sub.getBegin(), sub.getEnd(), sub.toString().replaceFirst(">", newElementString)); } } return outputDocument; } /* * 类型为radio、checkbox的input * @param controls * @param outputDocument * @return */ private static OutputDocument sameNameTagsProcess(Collection<FormControl> controls, OutputDocument outputDocument, boolean addPrefix){ Element element = null; String newElementString = ""; String valueExpr = ""; for(FormControl control : controls){ element = control.getElement(); if(addPrefix) valueExpr = DEFAULT_ENTITY_NAME+"." + element.getAttributeValue("name"); else element.getAttributeValue("name"); if("radio".equals(element.getAttributeValue("type"))){ //radio newElementString = new StringBuilder(" <#if ").append(valueExpr).append("==\"") .append(element.getAttributeValue("value")).append("\">checked='checked'</#if>>").toString(); }else if("checkbox".equals(element.getAttributeValue("type"))){ //check-box newElementString = new StringBuilder(" <#if (").append(valueExpr) .append("?exists && ").append(valueExpr).append("?contains(\"") .append(element.getAttributeValue("value")).append("\"))>checked='checked'</#if>>").toString(); } outputDocument.replace(element.getBegin(), element.getEnd(), element.toString().replaceFirst(">", newElementString)); } System.out.println(outputDocument.toString()); return outputDocument; } }