Spring boot 整合activiti modeler
前言
瞎整了一个晚上加一个上午,终于整合完成了,记录以便下次使用
Spring boot版本:1.5.3
activiti版本:5.22.0
一、目录结构

其中:
二、整合流程
2.1 复制文件
首先从官方下载activiti5.22.0版本的全代码包,并在本地解压待用
- 从
activiti-webapp-explorer2
中复制src\main\java\org\activiti\explorer\servlet
路径下的文件(图中的A部分)到本地项目中(如启动后无法访问静态资源文件,则删除DispatherServletConfiguration.java这个文件) - 从
activiti-webapp-explorer2
中复制src\main\resources
路径下的stencilset.json
文件到本地项目的resources目录下(我这里为了管理放在了resources/activiti/modeler目录下) - 从
activiti-webapp-explorer2
中复制src\main\webapp
路径下的文件(图中C部分)到本地项目的resources/public/static目录下 - 从
activiti-modeler
中复制src\main\java\org\activiti\rest\editor
路径下的文件(图中的B部分)到本地项目中
以上拷贝的路径参考上图
2.2 修改文件
为了整合能够达到效果,我们需要对以下文件进行修改
1)修改本地项目的pom.xml
,增加如下依赖
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter-basic</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter-actuator</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-rest</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-codec</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-css</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-svg-dom</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-svggen</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-explorer</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-diagram-rest</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-simple-workflow</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring</artifactId>
<version>${activiti.version}</version>
</dependency>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
2)修改DispatcherServletConfiguration.java
改为如下:
@Configuration
@ComponentScan({"org.activiti.rest.editor", "org.activiti.rest.diagram"})
public class DispatcherServletConfiguration {
private final Logger log = LoggerFactory.getLogger(DispatcherServletConfiguration.class);
@Bean
public SessionLocaleResolver localeResolver() {
return new SessionLocaleResolver();
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
log.debug("Configuring localeChangeInterceptor");
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("language");
return localeChangeInterceptor;
}
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
log.debug("Creating requestMappingHandlerMapping");
RequestMappingHandlerMapping requestMappingHandlerMapping = new RequestMappingHandlerMapping();
requestMappingHandlerMapping.setUseSuffixPatternMatch(false);
Object[] interceptors = {localeChangeInterceptor()};
requestMappingHandlerMapping.setInterceptors(interceptors);
return requestMappingHandlerMapping;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
3)修改StencilsetRestResource.java
(如果在拷贝stencilset.json
时没有放在resources目录下)
将
InputStream stencilsetStream = this.getClass().getClassLoader().getResourceAsStream("stencilset.json")
改为
InputStream stencilsetStream = this.getClass().getClassLoader().getResourceAsStream("activiti.modeler/stencilset.json")
4)修改StencilsetRestResource.java
、ModelEditorJsonRestResource.java
、ModelSaveRestResource.java
统一在类上加
@RequestMapping(value = "/service")
5)修改Spring boot 启动类Application.java
在里面增加注解
@ComponentScan({"org.activiti.rest.diagram", "com.westcatr.rd"})
@EnableAsync
同时增加一个filter
@Bean
public JsonpCallbackFilter filter(){
return new JsonpCallbackFilter();
}
6)修改editor-app
下的app-cfg.js
,将
ACTIVITI.CONFIG = {
'contextRoot' : 'activiti-webapp-explorer2/service',
};
改为
ACTIVITI.CONFIG = {
'contextRoot' : '/service',
};
7)修改ModelSaveRestResource.java
(主要是因为集成后保存时候报400错误)
将代码改为如下
@RestController
@RequestMapping(value = "/service")
public class ModelSaveRestResource implements ModelDataJsonConstants {
protected static final Logger LOGGER = LoggerFactory.getLogger(ModelSaveRestResource.class);
@Autowired
private RepositoryService repositoryService;
@Autowired
private ObjectMapper objectMapper;
@RequestMapping(value="/model/{modelId}/save", method = RequestMethod.PUT)
@ResponseStatus(value = HttpStatus.OK)
public void saveModel(@PathVariable String modelId, @RequestParam("name") String name,
@RequestParam("json_xml") String json_xml, @RequestParam("svg_xml") String svg_xml,
@RequestParam("description") String description) {
try {
Model model = repositoryService.getModel(modelId);
ObjectNode modelJson = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
modelJson.put(MODEL_NAME, name);
modelJson.put(MODEL_DESCRIPTION, description);
model.setMetaInfo(modelJson.toString());
model.setName(name);
repositoryService.saveModel(model);
repositoryService.addModelEditorSource(model.getId(), json_xml.getBytes("utf-8"));
InputStream svgStream = new ByteArrayInputStream(svg_xml.getBytes("utf-8"));
TranscoderInput input = new TranscoderInput(svgStream);
PNGTranscoder transcoder = new PNGTranscoder();
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
TranscoderOutput output = new TranscoderOutput(outStream);
transcoder.transcode(input, output);
final byte[] result = outStream.toByteArray();
repositoryService.addModelEditorSourceExtra(model.getId(), result);
outStream.close();
} catch (Exception e) {
LOGGER.error("Error saving model", e);
throw new ActivitiException("Error saving model", e);
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
8)修改activiti-modeler
编辑关闭时返回的路径
整合完成后,启动项目,访问http://localhost:8080/static/modeler.html?modelId=1
我们可以看到一个空白的编辑器,里面什么也木有。原因是什么呢,是因为我们的modelId=1是乱输入的,他应该要和数据库表ACT_RE_MODEL
对应起来才对。那么这张表里的数据如何来的呢,我们需要自己写一个Controller,对应封装4个方法:1.新建一个空的模型;2.所有模型列表;3.发布模型;4.删除模型;(activiti已提供了保存修改和获取模型节点信息的方法,就是上面C部分的那3个类)
参考代码(该部分代码感谢:http://www.jianshu.com/p/cf766a713a86)
@RestController
@RequestMapping("models")
public class ModelerController {
@Autowired
ProcessEngine processEngine;
@Autowired
ObjectMapper objectMapper;
/**
* 新建一个空模型
* @return
* @throws UnsupportedEncodingException
*/
@PostMapping
public Object newModel() throws UnsupportedEncodingException {
RepositoryService repositoryService = processEngine.getRepositoryService();
Model model = repositoryService.newModel();
String name = "new-process";
String description = "";
int revision = 1;
String key = "process";
ObjectNode modelNode = objectMapper.createObjectNode();
modelNode.put(ModelDataJsonConstants.MODEL_NAME, name);
modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
modelNode.put(ModelDataJsonConstants.MODEL_REVISION, revision);
model.setName(name);
model.setKey(key);
model.setMetaInfo(modelNode.toString());
repositoryService.saveModel(model);
String id = model.getId();
ObjectNode editorNode = objectMapper.createObjectNode();
editorNode.put("id", "canvas");
editorNode.put("resourceId", "canvas");
ObjectNode stencilSetNode = objectMapper.createObjectNode();
stencilSetNode.put("namespace",
"http://b3mn.org/stencilset/bpmn2.0#");
editorNode.put("stencilset", stencilSetNode);
repositoryService.addModelEditorSource(id,editorNode.toString().getBytes("utf-8"));
return ToWeb.buildResult().redirectUrl("/modeler.html?modelId="+id);
}
/**
* 获取所有模型
* @return
*/
@GetMapping
public Object modelList(){
RepositoryService repositoryService = processEngine.getRepositoryService();
List<Model> models = repositoryService.createModelQuery().list();
return ToWeb.buildResult().putData("models", models);
}
/**
* 删除模型
* @param id
* @return
*/
@DeleteMapping("{id}")
public Object deleteModel(@PathVariable("id")String id){
RepositoryService repositoryService = processEngine.getRepositoryService();
repositoryService.deleteModel(id);
return ToWeb.buildResult().refresh();
}
/**
* 发布模型为流程定义
* @param id
* @return
* @throws Exception
*/
@PostMapping("{id}/deployment")
public Object deploy(@PathVariable("id")String id) throws Exception {
RepositoryService repositoryService = processEngine.getRepositoryService();
Model modelData = repositoryService.getModel(id);
byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());
if (bytes == null) {
return ToWeb.buildResult().status(Config.FAIL)
.msg("模型数据为空,请先设计流程并成功保存,再进行发布。");
}
JsonNode modelNode = new ObjectMapper().readTree(bytes);
BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
if(model.getProcesses().size()==0){
return ToWeb.buildResult().status(Config.FAIL)
.msg("数据模型不符要求,请至少设计一条主线流程。");
}
byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(model);
String processName = modelData.getName() + ".bpmn20.xml";
Deployment deployment = repositoryService.createDeployment()
.name(modelData.getName())
.addString(processName, new String(bpmnBytes, "UTF-8"))
.deploy();
modelData.setDeploymentId(deployment.getId());
repositoryService.saveModel(modelData);
return ToWeb.buildResult().refresh();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
三、activiti modeler 导入现有流程文件
我们经常会使用其他的工具来制作bpmn文件,如使用eclipse的activiti designer,在我们的项目集成好activiti modeler后,就不需要再用其他工具来编辑了。那么如何将现有的bpmn文件导入到继承好的activiti modeler里呢。
通过对源码的查看,可以从activiti-exporer
中的ImportUploadReceiver.java
里找到一些思路,我们可以新建一个上传方法,即可上传我们的现有bpmn文件。代码如下:
@RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
public void deployUploadedFile(
@RequestParam("uploadfile") MultipartFile uploadfile) {
InputStreamReader in = null
try {
try {
boolean validFile = false
String fileName = uploadfile.getOriginalFilename()
if (fileName.endsWith(".bpmn20.xml") || fileName.endsWith(".bpmn")) {
validFile = true
XMLInputFactory xif = XmlUtil.createSafeXmlInputFactory()
in = new InputStreamReader(new ByteArrayInputStream(uploadfile.getBytes()), "UTF-8")
XMLStreamReader xtr = xif.createXMLStreamReader(in)
BpmnModel bpmnModel = new BpmnXMLConverter().convertToBpmnModel(xtr)
if (bpmnModel.getMainProcess() == null || bpmnModel.getMainProcess().getId() == null) {
// notificationManager.showErrorNotification(Messages.MODEL_IMPORT_FAILED,
// i18nManager.getMessage(Messages.MODEL_IMPORT_INVALID_BPMN_EXPLANATION))
System.out.println("err1")
} else {
if (bpmnModel.getLocationMap().isEmpty()) {
// notificationManager.showErrorNotification(Messages.MODEL_IMPORT_INVALID_BPMNDI,
// i18nManager.getMessage(Messages.MODEL_IMPORT_INVALID_BPMNDI_EXPLANATION))
System.out.println("err2")
} else {
String processName = null
if (StringUtils.isNotEmpty(bpmnModel.getMainProcess().getName())) {
processName = bpmnModel.getMainProcess().getName()
} else {
processName = bpmnModel.getMainProcess().getId()
}
Model modelData
modelData = repositoryService.newModel()
ObjectNode modelObjectNode = new ObjectMapper().createObjectNode()
modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, processName)
modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1)
modelData.setMetaInfo(modelObjectNode.toString())
modelData.setName(processName)
repositoryService.saveModel(modelData)
BpmnJsonConverter jsonConverter = new BpmnJsonConverter()
ObjectNode editorNode = jsonConverter.convertToJson(bpmnModel)
repositoryService.addModelEditorSource(modelData.getId(), editorNode.toString().getBytes("utf-8"))
}
}
} else {
// notificationManager.showErrorNotification(Messages.MODEL_IMPORT_INVALID_FILE,
// i18nManager.getMessage(Messages.MODEL_IMPORT_INVALID_FILE_EXPLANATION))
System.out.println("err3")
}
} catch (Exception e) {
String errorMsg = e.getMessage().replace(System.getProperty("line.separator"), "<br/>")
// notificationManager.showErrorNotification(Messages.MODEL_IMPORT_FAILED, errorMsg)
System.out.println("err4")
}
} finally {
if (in != null) {
try {
in.close()
} catch (IOException e) {
// notificationManager.showErrorNotification("Server-side error", e.getMessage())
System.out.println("err5")
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
补充:上面的是之前做项目整合时的流程记录,看到有朋友说不能够整合,今天按照流程重新整合了一遍,并上传了代码,传送门:http://download.csdn.net/detail/chenhai201/9862887