2021SC@SDUSC
目录
一、Render
1.SmartFieldRender
渲染器接口,JPress的渲染器都要实现SmartFieldRender接口,通过其onRender()方法来生成 html 的内容。
public interface SmartFieldRender { public String onRender(SmartField field, Object value); }
JPress的渲染器有如下:
2.DateRender
DateRender是JPress模板的Input 输入框的渲染器,它自定义了input的模板属性protected static String template:
public class DateRender implements SmartFieldRender { protected static String template = "" + "<div class=\"form-group row\">\n" + " <label class=\"col-sm-2 col-form-label\">{label}</label>\n" + " <div class=\"col-sm-6\">\n" + " <input type=\"text\" class=\"form-control date\"\n" + " id=\"{id}\"\n" + " name=\"{name}\"\n" + " data-date-format=\"yyyy-mm-dd\"\n" + " placeholder=\"{placeholder}\" value=\"{value}\" {attrs}/>\n" + " <p class=\"text-muted\">{helpText}</p>\n" + " </div>\n" + "</div>"; @Override public String onRender(SmartField field, Object value) { return RenderKit.render(template, field, value); } }
再通过自己的onRender方法把输入框模板渲染出去,具体返回一个RenderKit.render(template, field, value)。RenderKit.render(template, field, value)的具体方法体如下:
public static String render(String template, SmartField field, Object value) { if (StrUtil.isBlank(template)) { return template; } template = replace(template, "{label}", field.getLabel()); template = replace(template, "{id}", field.getId()); template = replace(template, "{name}", field.getName()); template = replace(template, "{placeholder}", field.getPlaceholder()); template = replace(template, "{value}", value == null ? field.getValue() : value); template = replace(template, "{helpText}", field.getHelpText()); template = replace(template, "{attrs}", field.getAttrs()); return template; }
很明显,这个方法可以把input输入框模板的label、id、name等属性替换掉,形成自己的模板。那么,SmartField field又是什么呢?
二、SmartField
1.SmartField
SmartField也是SmartField包下的一个类,结构如下:
public class SmartField { public static final String TYPE_INPUT = "input"; public static final String TYPE_TEXTAREA = "textarea"; public static final String TYPE_SELECT = "select"; public static final String TYPE_CHECKBOX = "checkbox"; public static final String TYPE_SWITCH = "switch"; public static final String TYPE_RADIO = "radio"; public static final String TYPE_IMAGE = "image"; public static final String TYPE_FILE = "file"; public static final String TYPE_DATE = "date"; public static final String TYPE_DATETIME = "datetime"; private String id; private String label; private String name; private String placeholder; private String type; private String value; private String valueText; private String helpText; private String attrs; private int orderNo; x private SmartFieldRender render; ...... public SmartField addAttr(String key, Object value) { StringBuilder s = new StringBuilder() .append(key) .append("=\"") .append(value.toString()) .append("\" "); this.attrs = this.attrs == null ? s.toString() : this.attrs + s.toString(); return this; } public SmartFieldRender getRender() { return render == null ? SmartFieldRenderFactory.getRender(type) : render; } public String render() { if (StrUtil.isBlank(this.name)) { return getRender().onRender(this, null); } Object data = doGetDataFromControllerByName(this.name); return getRender().onRender(this, data); } public Object doGetDataFromControllerByName(String name) { ...... } }
可以发现这个类拥有大部分模板的属性,比如模板的id、标题、占位符、类型等,其中特别留意attrs属性,它为特殊模板留了其他的属性,例如 "rows" = "3"。可以发现attrs属性是一个字符串,通过addAttr()方法可以发现attrs属性的具体结构:
public SmartField addAttr(String key, Object value) { StringBuilder s = new StringBuilder() .append(key) .append("=\"") .append(value.toString()) .append("\" "); this.attrs = this.attrs == null ? s.toString() : this.attrs + s.toString(); return this; }
它把key放在StringBuilder的头部,把value给toString后,保存在StringBuilder的尾部,所以可以了解到attrs的结构大概是key="value.toString()"的格式。
render属性是上文提到的SmartFieldRender接口对象,通过代码发现每个属性的render可以从SmartFieldRenderFactory获得。
public SmartFieldRender getRender() { return render == null ? SmartFieldRenderFactory.getRender(type) : render; }
2. SmartFieldRenderFactory
渲染器工厂,负责为模板提供渲染器。发现它有个静态私有属性renderMap,用于保存工厂中的渲染器。
public class SmartFieldRenderFactory { private static Map<String, SmartFieldRender> renderMap = new ConcurrentHashMap<>(); static { registerRender(SmartField.TYPE_INPUT, new InputRender()); registerRender(SmartField.TYPE_TEXTAREA, new TextareaRender()); registerRender(SmartField.TYPE_SELECT, new SelectRender()); registerRender(SmartField.TYPE_CHECKBOX, new CheckboxRender()); registerRender(SmartField.TYPE_SWITCH, new SwitchRender()); registerRender(SmartField.TYPE_RADIO, new RadioRender()); registerRender(SmartField.TYPE_IMAGE, new ImageRender()); registerRender(SmartField.TYPE_FILE, new FileRender()); registerRender(SmartField.TYPE_DATE, new DateRender()); registerRender(SmartField.TYPE_DATETIME, new DatetimeRender()); } public static void registerRender(String type, SmartFieldRender render) { renderMap.put(type, render); } public static SmartFieldRender getRender(String type) { return renderMap.get(type); } public static Map<String, SmartFieldRender> getRenderMap() { return renderMap; } }
提供源码发现,工厂一开始就初始化(registerRender)各个类型的工厂,并且通过getRender()方法向外提供渲染器。
以上为JPress的模板类、模板渲染的实现代码分析。