Activiti新手常見(jiàn)的問(wèn)題是,部署成功流程后沙庐,獲取顯示的流程圖片(PNG)為亂碼鲤妥,主要體現(xiàn)為中文無(wú)法正確顯示佳吞。在這里分析一下亂碼出現(xiàn)的原因,以及解決方案棉安。不喜歡問(wèn)為什么的同學(xué)可以直接跳到解決方法段落底扳。
表現(xiàn)
Activiti流程圖亂碼常見(jiàn)有兩種情況:
-
所有中文字符變成方塊
-
所有中文字符變成無(wú)意義漢字
造成這兩種情況的錯(cuò)誤原因以及解決方法并不相同,但都與Activiti部署贡耽、生成流程圖的方法有關(guān)衷模。下面先介紹Activiti的流程圖生成方式。
背景介紹
Activiti中菇爪,使用的流程定義一般都是符合BPMN2.0標(biāo)準(zhǔn)的xml文本文件算芯,后綴可以是.bpmn20.xml,.xml凳宙。其中包含了流程的全部定義內(nèi)容熙揍,包括各節(jié)點(diǎn)、節(jié)點(diǎn)關(guān)聯(lián)關(guān)系氏涩,以及用于定義顯示的DI元素届囚。
在部署流程定義時(shí),Activiti引擎會(huì)判斷是尖,是否同時(shí)提供了流程圖文件意系?如果一起提供了流程圖文件,Activiti就省事了饺汹,直接使用這個(gè)文件作為流程圖蛔添。
一般來(lái)說(shuō)我們都不會(huì)先制作好流程圖文件再部署,也就是說(shuō)兜辞,部署時(shí)只有一個(gè)xml文件迎瞧。這時(shí)候Activiti就需要自己生成對(duì)應(yīng)的流程圖文件了。
流程圖文件會(huì)保存在Activiti的數(shù)據(jù)庫(kù)ACT_GE_BYTEARRAY表中逸吵,作為BLOB保存凶硅。每個(gè)流程對(duì)應(yīng)一個(gè)流程圖文件。所以流程圖在部署時(shí)就已經(jīng)確定扫皱,除非重新部署或手動(dòng)處理足绅,否則不管配置怎么修改,顯示的都是最初的流程圖韩脑。
Activiti用于生成流程圖的工具類(lèi)是
org.activiti.image.impl.DefaultProcessDiagramGenerator
這個(gè)類(lèi)不止可以生成流程圖氢妈,還可以生成流程運(yùn)行狀態(tài)圖。具體可以參閱其中各方法的注釋扰才。
出錯(cuò)原因分析
中文字符變成方塊
在部署流程時(shí)允懂,生成流程圖的代碼位于
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);
可見(jiàn)在這里,需要在processEngineConfiguration里衩匣,保存有正確的LabelFontName蕾总,以及AnnotationFontName作為參數(shù)粥航,Generator才能正確生成(非英文)的流程圖片。
中文字符變成無(wú)意義漢字
出現(xiàn)這種問(wèn)題生百,基本上都是在Activiti提供的demo程序——Explorer中設(shè)計(jì)递雀、部署流程的時(shí)候出現(xiàn)的。原因是demo程序有bug蚀浆。
Activiti Explorer中提供的Activiti Modeler缀程,是一個(gè)Web流程設(shè)計(jì)器。用于編輯市俊、保存流程模型杨凑。這里請(qǐng)注意,不能用于新建摆昧,它生成的也只是流程模型撩满,不是流程定義。生成的流程模型是Json格式的绅你,也保存在ACT_GE_BYTEARRAY表中伺帘。
然后在Activiti Explorer中提供了“部署”的操作。對(duì)應(yīng)的代碼為(Activiti 5.22中)(實(shí)際有兩個(gè)部署方式忌锯,不過(guò)畫(huà)線(xiàn)部署的是這個(gè)伪嫁。另一個(gè)是填表單方式部署,問(wèn)題類(lèi)似)
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的數(shù)據(jù)格式(Json modelNode),轉(zhuǎn)換為Activiti內(nèi)部交換格式(BpmnModel model)张咳,再轉(zhuǎn)成xmlbyte(byte[] bpmnBytes),然后在部署的時(shí)候再作為String加入部署
.addString(processName, new String(bpmnBytes))
很繞是不是似舵?Activiti的開(kāi)發(fā)者也把自己繞暈了晶伦,導(dǎo)致這里出現(xiàn)了bug。
public byte[] convertToXML(BpmnModel model) {
return convertToXML(model, DEFAULT_ENCODING);
}
轉(zhuǎn)換為xmlbyte的方法里啄枕,指定了編碼方式(為UTF-8)。但是再轉(zhuǎn)回字符串的時(shí)候族沃,卻沒(méi)有指定編碼方式频祝!
new String(bpmnBytes)
在未指定編碼方式的時(shí)候,new String使用jvm定義的默認(rèn)編碼方式解析脆淹,而我們一般使用的都是gb2312常空,因此導(dǎo)致問(wèn)題。
解決方法
再次強(qiáng)調(diào)盖溺,修改之后漓糙,需要重新部署或手動(dòng)生成流程圖片,才能看到效果烘嘱!
中文字符變成方塊
在Activiti的配置中昆禽,加上字體配置即可蝗蛙。
對(duì)于Spring用戶(hù),在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"/>
...
在其中加上幾個(gè)參數(shù)(按照Activiti的版本不同醉鳖,參數(shù)數(shù)量不一定捡硅。用IDE提示,把所有帶有font的都設(shè)置上就好了)盗棵。字體可以按照喜好設(shè)置壮韭,但需要保證tomcat運(yùn)行時(shí)可以找到(例如默認(rèn)安裝的linux服務(wù)器很可能就沒(méi)有)。
<property name="activityFontName" value="宋體"/>
<property name="labelFontName" value="宋體"/>
<property name="annotationFontName" value="宋體"/>
重啟tomcat使配置生效纹因,重新部署流程以重新生成流程圖喷屋。方塊字就ok啦。
中文字符變成無(wú)意義漢字
由于問(wèn)題出在編碼方式上瞭恰,因此有幾種修改方式
1. 修改jvm默認(rèn)參數(shù)屯曹。
在tomcat的vm運(yùn)行參數(shù)上,加上-Dfile.encoding=UTF-8寄疏。不過(guò)副作用是導(dǎo)致整個(gè)項(xiàng)目都運(yùn)行在utf-8下是牢,對(duì)于寫(xiě)的不嚴(yán)謹(jǐn)?shù)捻?xiàng)目,可能導(dǎo)致其它地方默認(rèn)使用gb2312編碼的代碼出錯(cuò)陕截。
2. 修改Explorer部署部分的代碼
將org.activiti.editor.ui.EditorProcessDefinitionDetailPanel.deployModelerModel():348
修改為.addString(processName, new String(bpmnBytes, "UTF-8"))
即可驳棱。
可以直接修改activiti的源碼,編譯后使用农曲。
也可以在自己的項(xiàng)目下社搅,手動(dòng)創(chuàng)建
org.activiti.editor.ui.EditorProcessDefinitionDetailPanel
類(lèi),把Activiti的源碼貼進(jìn)去乳规,再修改正確形葬。這樣我們重寫(xiě)的類(lèi)就會(huì)由classloader優(yōu)先加載,覆蓋Activiti自己的實(shí)現(xiàn)暮的,達(dá)到修改的目的笙以。
3. 說(shuō)到底Explorer只是Activiti提供的demo樣例。自己寫(xiě)的時(shí)候冻辩,可以參考Explorer的代碼猖腕,可別直接拿來(lái)用哦。
顯示字符為空白
這個(gè)嚴(yán)格來(lái)說(shuō)并不是“亂碼”恨闪,解決方法也很簡(jiǎn)單:畫(huà)流程圖的時(shí)候倘感,少寫(xiě)幾個(gè)字,或者把框框拖動(dòng)搞大一點(diǎn)就可以了~