1. 程式人生 > >Activiti Modeler整合之後,部署之後流程圖片顯示亂碼問題分析與解決

Activiti Modeler整合之後,部署之後流程圖片顯示亂碼問題分析與解決

Activiti 流程圖片顯示亂碼問題分析與解決

Activiti新手常見的問題是,部署成功流程後,獲取顯示的流程圖片(PNG)為亂碼,主要體現為中文無法正確顯示。在這裡分析一下亂碼出現的原因,以及解決方案。不喜歡問為什麼的同學可以直接跳到解決方法段落。

表現

Activiti流程圖亂碼常見有兩種情況:

  1. 所有中文字元變成方塊


  2. 所有中文字元變成無意義漢字


造成這兩種情況的錯誤原因以及解決方法並不相同,但都與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)