還是首先講一下需求。一個普通的web form表單提交,根據模板自動生成指定格式的結果。form的優勢在格式化數據,使得各屬性非常直觀的展現出來,用戶可以更加簡單直觀的進行輸入。但業務上的最終結果卻不可以是form,所以就有了這個需求。需求的本質有點類似el表達式的替換,但是這個表達式模板是動態配置的,而不是常見的xml靜態文件。
總結一下需求,概括來講是這樣:根據用戶的輸入,將業務屬性填充到實時設置的模板生成最終結果。
不難發現這裏的幾個關鍵點。
- 模板要實時可以配置,這裏採用db方式。
- 存在用戶輸入的行爲,也就意味着存在不穩定因素,包括特殊字符,空等。但是因爲是填充,可以過濾掉特殊字符,只要處理null即可。(需求上需要處理null)
- 既然是填充,就要保證兩點。一是填充的對象不能混淆錯亂,二是填充的順序不能出錯。
- 該模板是當做第三方jar依賴注入的,所以必須規避掉任何業務因素。
Service層:
TemplateFactory:常規的工廠類,獲取指定生成器。
TemplateGenerator:常規的生成器。
還是老話,結構jar提供,實現在業務層。包括vo。這樣的好處是jar與業務完全隔離。壞處是每個業務系統都要寫一遍實現,而且存在衝突的風險。
下面補上實現類的generator實現,其他代碼沒什麼特別。
1. Exception是模板jar封裝過的幾類異常。因爲不存在業務代碼,所以無法控制調用方的傳參,模板可能會不存在。
//1. 獲取模板
Template template = this.templateLogic.findByGroupAndCode(groupCode, templateCode);
if (null == template) {
logger.info("Invalid template access. group code:{}, template code:{}", groupCode, templateCode);
result.setException(new TemplateNotExistException("Template not exists! Group code:" + groupCode + ",template code:" + templateCode) );
return;
}
2. 讀取模板配置的el。如果沒有任何配置,warning。這裏按seq讀取,爲模板拼接做準備。 //2. 讀取模板配置
List<TemplateElConfig> templateElConfigs = this.templateElConfigLogic.findByTemplateId(template.getId());
if (null == templateElConfigs || templateElConfigs.isEmpty() ) {
logger.info("There's no express configuration for template:{}", template.getName());
return;
}
3. 解析el的配置,生成最終字符串。
for (TemplateElConfig templateElConfig : templateElConfigs) {
TemplateEl el = this.templateElLogic.findOne(templateElConfig.getElId());
if (el == null) {
logger.info("Missing el config, template el config id:{}",templateElConfig.getId());
continue;
}
String datasourceValue = "";
//3.1
String methodName = el.getPropertyMethod();
if (StringUtils.isEmpty(methodName)) {
logger.info("Missing property method config for el:{}",el.getId());
continue;
}
try {
Method method = null;
Object propertyValue;
if (el.getEl().contains("Date")) {
method = (Method)datasource.getClass().getMethod(methodName);
propertyValue = (Date)method.invoke(datasource);
}else {
method = (Method)datasource.getClass().getMethod(methodName);
propertyValue = (String)method.invoke(datasource);
}
if (propertyValue instanceof Date) {
TemplateElFormat elFormat = this.templateElFormatLogic.findByElId(el.getId());
String timeFormat = DEFAULT_DATE_FORMAT;
if (null != elFormat) {
timeFormat = elFormat.getFormat();
}
SimpleDateFormat format = new SimpleDateFormat(timeFormat);
datasourceValue = format.format(propertyValue);
}else if (propertyValue instanceof String) {
datasourceValue = (String)propertyValue;
}
} catch (Exception e) {
logger.error("No such method.", e);
result.setException(new IllegalTemplateConfigException("No such method.", e));
return;
}
if (StringUtils.isNoneEmpty(datasourceValue)) {
if (StringUtils.isNoneEmpty(el.getPrefix())) {
buffer.append(el.getPrefix());
}
buffer.append(datasourceValue);
if (StringUtils.isNotEmpty(el.getSuffix())) {
buffer.append(el.getSuffix());
}
if (StringUtils.isNoneEmpty(el.getHtmlPrefix())) {
htmlBuffer.append(el.getHtmlPrefix());
}
htmlBuffer.append(datasourceValue);
if (StringUtils.isNotEmpty(el.getHtmlSuffix())) {
htmlBuffer.append(el.getHtmlSuffix());
}
}
}
這裏沒有業務邏輯,所以是可以放到jar裏面的,各業務系統只要控制如何結構化調用就行了。