Activiti Modeler整合之后,部署之后流程图片显示乱码问题分析与解决

时间:2023-02-10 00:20:40

Activiti 流程图片显示乱码问题分析与解决

Activiti新手常见的问题是,部署成功流程后,获取显示的流程图片(PNG)为乱码,主要体现为中文无法正确显示。在这里分析一下乱码出现的原因,以及解决方案。不喜欢问为什么的同学可以直接跳到解决方法段落。

表现

Activiti流程图乱码常见有两种情况:

  1. 所有中文字符变成方块

    Activiti Modeler整合之后,部署之后流程图片显示乱码问题分析与解决
  2. 所有中文字符变成无意义汉字

    Activiti Modeler整合之后,部署之后流程图片显示乱码问题分析与解决

造成这两种情况的错误原因以及解决方法并不相同,但都与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

Activiti Modeler整合之后,部署之后流程图片显示乱码问题分析与解决

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)