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啦。

中文字符變成無意義漢字

由于問題出在編碼方式上,因此有幾種修改方式

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的代碼,可別直接拿來用哦。
顯示字符為空白

這個嚴格來說并不是“亂碼”,解決方法也很簡單:畫流程圖的時候,少寫幾個字,或者把框框拖動搞大一點就可以了~

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容