Java自定義模板設計

還是首先講一下需求。一個普通的web form表單提交,根據模板自動生成指定格式的結果。form的優勢在格式化數據,使得各屬性非常直觀的展現出來,用戶可以更加簡單直觀的進行輸入。但業務上的最終結果卻不可以是form,所以就有了這個需求。需求的本質有點類似el表達式的替換,但是這個表達式模板是動態配置的,而不是常見的xml靜態文件。

總結一下需求,概括來講是這樣:根據用戶的輸入,將業務屬性填充實時設置的模板生成最終結果。

不難發現這裏的幾個關鍵點。

  1. 模板要實時可以配置,這裏採用db方式。
  2. 存在用戶輸入的行爲,也就意味着存在不穩定因素,包括特殊字符,空等。但是因爲是填充,可以過濾掉特殊字符,只要處理null即可。(需求上需要處理null)
  3. 既然是填充,就要保證兩點。一是填充的對象不能混淆錯亂,二是填充的順序不能出錯。
  4. 該模板是當做第三方jar依賴注入的,所以必須規避掉任何業務因素。
想清楚了設計的重點,再來看看設計,先看類圖。


實體層:
TemplateEl:el表達式的設計。因爲只是簡單的文本模板,所以只要關心el的前綴、後綴即可。這裏的html配置是爲了前臺效果展示、編輯用的。propertyMethod是考慮到不同系統、程序員在聲明getter、setter方法時可能不一致,所以顯示錶達了。
TemplateElFormat:針對特殊el屬性,有一定的格式約定。我目前只用到了時間格式,後面會有介紹。
Template:常見的group+unique code 唯一標示模板。
TemplateElConfig:就是一張普通的mapping表。
ResultVo:根據業務需求返回指定的VO。這裏建議用一個Abstract類來爲模板服務。

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裏面的,各業務系統只要控制如何結構化調用就行了。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章