Activiti Modeler整合之後,部署之後流程圖片顯示亂碼問題分析與解決
Activiti 流程圖片顯示亂碼問題分析與解決
Activiti新手常見的問題是,部署成功流程後,獲取顯示的流程圖片(PNG)為亂碼,主要體現為中文無法正確顯示。在這裡分析一下亂碼出現的原因,以及解決方案。不喜歡問為什麼的同學可以直接跳到解決方法段落。
表現
Activiti流程圖亂碼常見有兩種情況:
-
所有中文字元變成方塊
-
所有中文字元變成無意義漢字
造成這兩種情況的錯誤原因以及解決方法並不相同,但都與Activiti部署、生成流程圖的方法有關。下面先介紹Activiti的流程圖生成方式。
背景介紹
Activiti中,使用的流程定義一般都是符合BPMN2.0標準的xml文字檔案,字尾可以是.bpmn20.xml,.xml。其中包含了流程的全部定義內容,包括各節點、節點關聯關係,以及用於定義顯示的DI元素。
在部署流程定義時,Activiti引擎會判斷,是否同時提供了流程圖檔案?如果一起提供了流程圖檔案,Activiti就省事了,直接使用這個檔案作為流程圖。
一般來說我們都不會先製作好流程圖檔案再部署,也就是說,部署時只有一個xml檔案。這時候Activiti就需要自己生成對應的流程圖檔案了。
流程圖檔案會儲存在Activiti的資料庫ACT_GE_BYTEARRAY表中,作為BLOB儲存。每個流程對應一個流程圖檔案。所以流程圖在部署時就已經確定,除非重新部署或手動處理,否則不管配置怎麼修改,顯示的都是最初的流程圖。
Activiti用於生成流程圖的工具類是
org.activiti.image.impl.DefaultProcessDiagramGenerator
這個類不止可以生成流程圖,還可以生成流程執行狀態圖。具體可以參閱其中各方法的註釋。
出錯原因分析
中文字元變成方塊
在部署流程時,生成流程圖的程式碼位於
org.activiti.engine.impl.bpmn.deployer.BpmnDeployer.deploy():154 (Activiti 5.22中) byte[] diagramBytes = IoUtil.readInputStream(processEngineConfiguration. getProcessDiagramGenerator().generateDiagram(bpmnParse.getBpmnModel(), "png", processEngineConfiguration.getActivityFontName(), processEngineConfiguration.getLabelFontName(),processEngineConfiguration.getAnnotationFontName(), processEngineConfiguration.getClassLoader()), null);
可見在這裡,需要在processEngineConfiguration裡,儲存有正確的LabelFontName,以及AnnotationFontName作為引數,Generator才能正確生成(非英文)的流程圖片。
中文字元變成無意義漢字
出現這種問題,基本上都是在Activiti提供的demo程式——Explorer中設計、部署流程的時候出現的。原因是demo程式有bug。
Activiti Explorer中提供的Activiti Modeler,是一個Web流程設計器。用於編輯、儲存流程模型。這裡請注意,不能用於新建,它生成的也只是流程模型,不是流程定義。生成的流程模型是Json格式的,也儲存在ACT_GE_BYTEARRAY表中。
然後在Activiti Explorer中提供了“部署”的操作。對應的程式碼為(Activiti 5.22中)(實際有兩個部署方式,不過畫線部署的是這個。另一個是填表單方式部署,問題類似)
org.activiti.editor.ui.EditorProcessDefinitionDetailPanel.deployModelerModel()
protected void deployModelerModel(final ObjectNode modelNode) {
BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(model);
String processName = modelData.getName() + ".bpmn20.xml";
Deployment deployment = repositoryService.createDeployment()
.name(modelData.getName())
.addString(processName, new String(bpmnBytes))
.deploy();
ExplorerApp.get().getViewManager().showDeploymentPage(deployment.getId());
}
大意是,將Modeler的資料格式(Json modelNode),轉換為Activiti內部交換格式(BpmnModel model),再轉成xmlbyte(byte[] bpmnBytes),然後在部署的時候再作為String加入部署.addString(processName, new String(bpmnBytes))
很繞是不是?Activiti的開發者也把自己繞暈了,導致這裡出現了bug。
public byte[] convertToXML(BpmnModel model) {
return convertToXML(model, DEFAULT_ENCODING);
}
轉換為xmlbyte的方法裡,指定了編碼方式(為UTF-8)。但是再轉回字串的時候,卻沒有指定編碼方式!new String(bpmnBytes)
在未指定編碼方式的時候,new String使用jvm定義的預設編碼方式解析,而我們一般使用的都是gb2312,因此導致問題。
解決方法
再次強調,修改之後,需要重新部署或手動生成流程圖片,才能看到效果!
中文字元變成方塊
在Activiti的配置中,加上字型配置即可。
對於Spring使用者,在Spring配置檔案中找到Activiti流程引擎定義的地方
<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
<property name="dataSource" ref="dataSource"/>
<property name="transactionManager" ref="transactionManager"/>
<property name="databaseSchemaUpdate" value="true"/>
...
在其中加上幾個引數(按照Activiti的版本不同,引數數量不一定。用IDE提示,把所有帶有font的都設定上就好了)。字型可以按照喜好設定,但需要保證tomcat執行時可以找到(例如預設安裝的linux伺服器很可能就沒有)。
<property name="activityFontName" value="宋體"/>
<property name="labelFontName" value="宋體"/>
<property name="annotationFontName" value="宋體"/>
重啟tomcat使配置生效,重新部署流程以重新生成流程圖。方塊字就ok啦。
正如上所說,這只是window下的解決辦法,在linux系統上仍然會出現亂碼,這是因為
本人系統activiti配置檔案設定的“宋體”,因此需在window系統中找到宋體字型複製到linux系統中進行安裝。
1,進入C:\Windows\Fonts,找到“宋體 常規”檔案simsun.ttc
2,進入cd /usr/java/jdk1.7.0_79/jre/lib/fonts,新建fallback
3,將此檔案複製到此資料夾下,
4,重啟伺服器,
5,重新部署流程,問題解決
中文字元變成無意義漢字
由於問題出在編碼方式上,因此有幾種修改方式
1. 修改jvm預設引數。
在tomcat的vm執行引數上,加上-Dfile.encoding=UTF-8。不過副作用是導致整個專案都執行在utf-8下,對於寫的不嚴謹的專案,可能導致其它地方預設使用gb2312編碼的程式碼出錯。
2. 修改Explorer部署部分的程式碼
將org.activiti.editor.ui.EditorProcessDefinitionDetailPanel.deployModelerModel():348
修改為.addString(processName, new String(bpmnBytes, "UTF-8"))
即可。
-
可以直接修改activiti的原始碼,編譯後使用。
-
也可以在自己的專案下,手動建立
org.activiti.editor.ui.EditorProcessDefinitionDetailPanel
類,把Activiti的原始碼貼進去,再修改正確。這樣我們重寫的類就會由classloader優先載入,覆蓋Activiti自己的實現,達到修改的目的。
3. 說到底Explorer只是Activiti提供的demo樣例。自己寫的時候,可以參考Explorer的程式碼,可別直接拿來用哦。
顯示字元為空白
這個嚴格來說並不是“亂碼”,解決方法也很簡單:畫流程圖的時候,少寫幾個字,或者把框框拖動搞大一點就可以了~
(轉載於:http://www.jianshu.com/p/8f8b4de761ab)