Activiti提供DefaultProcessDiagramGenerator用于生成流程InputStream流,可用于生成图片,并且可高亮某些节点、连线等,使用方法如下:
String processDefinitionId = "xxx";
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
ProcessDiagramGenerator pdg = new DefaultProcessDiagramGenerator();
InputStream inputStream = pdg.generateDiagram(bpmnModel, "png",
highLightedActivitiesList,highLightedFlowsList,
processEngine.getProcessEngineConfiguration().getActivityFontName(),
processEngine.getProcessEngineConfiguration().getLabelFontName(),
processEngine.getProcessEngineConfiguration().getAnnotationFontName(),
null, 1);
"generateDiagram"方法的具体参数可参考API。
其中有三个字体名称ActivityFontName
、LabelFontName
、AnnotationFontName
可在XML配置文件中进行声明,当前项目使用微软雅黑
。
问题:
在window环境下生成的图片可正常显示,但是部署到linux环境下中文字体无法显示。
原因:
该问题是由于linux环境下没有中文字体文件。
解决方案:
1.在linux环境下安装需要的字体文件,具体步骤网上可查询。
2.将字体文件放入项目中,在生成流程图的时候进行加载,从而实现不依赖服务器系统字体。
--------------------本文主要介绍如何实现解决方案2。----------------------------
查看DefaultProcessDiagramGenerator.generateDiagram()
方法源码可以看到生成图片主要涉及的类和方法如下:
类 | 方法 | 说明 |
---|---|---|
DefaultProcessDiagramGenerator | generateProcessDiagram() | |
DefaultProcessDiagramGenerator | initProcessDiagramCanvas() | 计算X、Y等变量,并调用canvas |
DefaultProcessDiagramCanvas | initialize() | 字体创建的核心 |
根据上述表格得知,如果需要加载项目中的字体文件,则需要重写DefaultProcessDiagramCanvas
类的核心方法initialize
。
- 创建自定义Canvas类
CustomizedProcessDiagramCanvas
继承DefaultProcessDiagramCanvas
并重写initialize
方法,如下:
package com.fangjie.activiti.config;
import org.activiti.image.impl.DefaultProcessDiagramCanvas;
import org.activiti.image.util.ReflectUtil;
import org.springframework.util.StringUtils;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
/**
* @author fangjie
* @Description: ${todo}
*/
public class CustomizedProcessDiagramCanvas extends DefaultProcessDiagramCanvas {
public CustomizedProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
super(width, height, minX, minY, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
}
public CustomizedProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType) {
super(width, height, minX, minY, imageType);
}
@Override
public void initialize(String imageType) {
if ("png".equalsIgnoreCase(imageType)) {
this.processDiagram = new BufferedImage(canvasWidth, canvasHeight, BufferedImage.TYPE_INT_ARGB);
} else {
this.processDiagram = new BufferedImage(canvasWidth, canvasHeight, BufferedImage.TYPE_INT_RGB);
}
this.g = processDiagram.createGraphics();
if ("png".equalsIgnoreCase(imageType) == false) {
this.g.setBackground(new Color(255, 255, 255, 0));
this.g.clearRect(0, 0, canvasWidth, canvasHeight);
}
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setPaint(Color.black);
//activityFontName字体加载
Font font = this.loadFontFromResources(this.activityFontName, Font.BOLD, FONT_SIZE);
g.setFont(font);
this.fontMetrics = g.getFontMetrics();
//labelFontName字体加载
LABEL_FONT = this.loadFontFromResources(this.labelFontName, Font.ITALIC, 10);
//annotationFontName字体加载
ANNOTATION_FONT = this.loadFontFromResources(this.annotationFontName, Font.PLAIN, FONT_SIZE);
try {
USERTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/userTask.png", customClassLoader));
SCRIPTTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/scriptTask.png", customClassLoader));
SERVICETASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/serviceTask.png", customClassLoader));
RECEIVETASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/receiveTask.png", customClassLoader));
SENDTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/sendTask.png", customClassLoader));
MANUALTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/manualTask.png", customClassLoader));
BUSINESS_RULE_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/businessRuleTask.png", customClassLoader));
SHELL_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/shellTask.png", customClassLoader));
CAMEL_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/camelTask.png", customClassLoader));
MULE_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/muleTask.png", customClassLoader));
TIMER_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/timer.png", customClassLoader));
COMPENSATE_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/compensate-throw.png", customClassLoader));
COMPENSATE_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/compensate.png", customClassLoader));
ERROR_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/error-throw.png", customClassLoader));
ERROR_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/error.png", customClassLoader));
MESSAGE_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/message-throw.png", customClassLoader));
MESSAGE_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/message.png", customClassLoader));
SIGNAL_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/signal-throw.png", customClassLoader));
SIGNAL_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/signal.png", customClassLoader));
} catch (IOException e) {
LOGGER.warn("Could not load image for process diagram creation: {}", e.getMessage());
}
}
/**
* 根据名称从resources中加载字体
*
* @param fontName
* @param fontStyle
* @param fontSize
* @return
*/
public Font loadFontFromResources(String fontName, int fontStyle, float fontSize) {
Font font = null;
if (StringUtils.isEmpty(fontName)) {
return font;
}
try {
//加载resources下的字体文件,文件命名与设置的字体名称一一对应
InputStream fontInputStream = this.getClass().getResourceAsStream("/fonts/" + fontName + ".ttc");
//未找到项目中相应的字体文件,则使用系统的字体
if (fontInputStream == null) {
return new Font(fontName, fontStyle, (int) fontSize);
}
font = Font.createFont(Font.TRUETYPE_FONT, fontInputStream);
//设置字体类型
if (fontStyle > -1) {
font = font.deriveFont(fontStyle);
}
//设置字体大小
if (fontSize > -1) {
font = font.deriveFont(fontSize);
}
} catch (FontFormatException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return font;
}
}
2.创建自定义Generator类CustomizedProcessDiagramGenerator
继承DefaultProcessDiagramGenerator
并重写相关方法,如下:
package com.fangjie.activiti.config;
import org.activiti.bpmn.model.*;
import org.activiti.bpmn.model.Process;
import org.activiti.image.impl.DefaultProcessDiagramCanvas;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import java.util.List;
/**
* @author fangjie
* @Description: ${todo}
*/
public class CustomizedProcessDiagramGenerator extends DefaultProcessDiagramGenerator {
@Override
protected DefaultProcessDiagramCanvas generateProcessDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, List<String> highLightedFlows, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor) {
prepareBpmnModel(bpmnModel);
DefaultProcessDiagramCanvas processDiagramCanvas = initProcessDiagramCanvas(bpmnModel, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
/**
* 此处省略源码剩余部分代码
*/
}
protected static DefaultProcessDiagramCanvas initProcessDiagramCanvas(BpmnModel bpmnModel, String imageType, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
/**
* 此处省略源码前部分代码
*/
//返回上面自定义的canvas类
return new CustomizedProcessDiagramCanvas((int) maxX + 10, (int) maxY + 10, (int) minX, (int) minY,
imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
}
}
3.将文章开头部分代码进行修改如下:
String processDefinitionId = "xxx";
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
//创建自定义的Generator类
ProcessDiagramGenerator pdg = new CustomizedProcessDiagramGenerator();
InputStream inputStream = pdg.generateDiagram(bpmnModel, "png",
highLightedActivitiesList,highLightedFlowsList,
processEngine.getProcessEngineConfiguration().getActivityFontName(),
processEngine.getProcessEngineConfiguration().getLabelFontName(),
processEngine.getProcessEngineConfiguration().getAnnotationFontName(),
null, 1);