背景
上司們需要檢視一些彙總資料,這些彙總資料可從離線數倉平台查詢得到,而企微是一個比較好的企業内部通訊工具。
基于此,現在全職負責(一個人負責前端,後端,測試,小部分産品設計)的報表平台,具備功能點:Impala資料推送到企微。
頁面設計大緻如下:
問題
因為另外一個任務執行時間比較久,故而想知道資料源某個表的數量級,然後把這個數字以可視化的方式發到自己的企微。故而在來源處修改上面的SQL為:
select count(*) from ods.aaa
點選自動生成名額,把上面這個SQL語句的查詢字段自動填充到企微發送模版裡面,得到:
{count(*)}
本地測試,繼續運作,突然報錯:
ERROR c.x.c.a.b.d.b.JdbcDataProvider- jdbc execAutoWork impala-2-target error: {}
java.util.regex.PatternSyntaxException: Dangling meta character '*' near index 8
\{count(*)}
^
at com.xy.cloudiview.autojob.business.dataprovider.business.TargetProvider.execAutoWorkTo(TargetProvider.java:58)
at com.xy.cloudiview.autojob.business.dataprovider.business.JdbcDataProvider.execAutoWork(JdbcDataProvider.java:180)
at com.xy.cloudiview.autojob.business.service.DataProviderService.execAutoWork(DataProviderService.java:194)
at com.xy.cloudiview.autojob.controller.AutoJobController.execAutoWork(AutoJobController.java:33)
排查
對應的代碼片段:
public JSONObject execAutoWorkTo(Map query, List<Map<String, Object>> datalist) {
if (CollectionUtils.isEmpty(datalist)) {
return null;
}
String jobName = query.get("jobName") + "";
// 取使用者limit數和限制條數的較小值
int num = Math.min(datalist.size(), targetNum);
List<Map<String, Object>> mapResultList = datalist.subList(0, num);
String sendMsg = query.get("targetTemplate") + "";
List<String> targetList = StringUtil.getMatchValue(sendMsg);
StringBuilder finalMsg = new StringBuilder();
for (Map<String, Object> mapResult : mapResultList) {
for (String target : targetList) {
Object obj = mapResult.get(target);
sendMsg = sendMsg.replaceAll("\\{" + target + "}", String.valueOf(obj));
}
finalMsg.append(sendMsg).append(";");
}
}
斷點調試,再現問題:
幾乎也不需要Google,原因很顯然。因為程式實作邏輯是:對企微模版,即需要發送的内容,進行替換時使用
replaceAll()
方法,即使用正規表達式實作替換,報錯PatternSyntaxException,因為有正則保留字元
*
。
解決
問題已然定位。
如何解決呢?
前面提到,需要實作的功能已經說的很清楚(産品經理角色提出的需求),但是産品在設計這個功能時,很大機率上不會意識到使用者輸入的SQL語句裡面會出現
count(*)
(并且沒有加上
as cnt
别名),也不知道程式員在實作這個功能時,會用到正規表達式全局比對替換。
現在的處境,隻有我一個人在負責這個産品,我作為一個所謂全棧工程師,要如何解決這種潛在問題。
一開始,想着從使用者界面(前端使用React Ant Design實作)入口,限制使用者輸入正則保留字元,即加上rules校驗,不允許使用者輸入保留字元。使用者體驗不是很好?保留字元有哪些呢?
差一點走偏。。。
從後端來實作。解決方案很簡單,當然也不是一蹴而就想到:
sendMsg = sendMsg.replace("{" + target + "}", String.valueOf(obj));