1.编辑器界面
流程编辑器2.插件下载
activiti的explore模块:
https://github.com/Activiti/Activiti/tree/master/modules/activiti-webapp-explorer2
3.编辑器前端部分
仅保留一些静态资源就行了,将这些文件放入项目的web目录下。
需要的文件
其中的editor-app就是编辑器,modeler.html是编辑器的入口页面。
diagram-viewer是流程跟踪插件,虽然这次用不着,但之后会用到。
还有一个界面组件文件,在resource下,名称叫stencilset.json。本身是英文的,可以通过替换它来达到汉化的效果。但现在还是先把它放到项目中去。
界面组件
在editor-app/app-cfg.js中配置一下项目url。这个url是编辑器相关的后台服务的url。
ACTIVITI.CONFIG = {
'contextRoot' : '/service',
};
我去掉了项目名。
4.后端部分
先引入两个activiti的模块,因为编辑器会用到这两个模块。
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-modeler</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-diagram-rest</artifactId>
<version>${activiti.version}</version>
</dependency>
其中需要将modeler模块的源代码放到src中,因为需要在其中做部分修改,主要是url的映射。
源码:
https://github.com/Activiti/Activiti/tree/master/modules/activiti-modeler
其中有3个类,都是Controller:
StencilsetRestResource #获取编辑器组件及配置项信息。
ModelEditorJsonRestResource #根据modelId获取model的节点信息,编辑器根据返回的json进行绘图。
ModelSaveRestResource #编辑器制图之后,将节点信息以json的形式提交给这个Controller,然后由其进行持久化操作。
需要修改的地方就三个,在每个Controller类上加上@RequestMapping注解,并指定值为"service"(对应前台app-cfg.js中配置的url)。
···
@RequestMapping("service")
public class StencilsetRestResource {
···
···
@RequestMapping("service")
public class ModelEditorJsonRestResource implements ModelDataJsonConstants {
···
···
@RequestMapping("service")
public class ModelSaveRestResource implements ModelDataJsonConstants {
···
最后别忘了添加包扫描,扫描activiti提供的这些controller。
@SpringBootApplication
@ComponentScan({"org.activiti","com.jerryl"})
public class SpringBootWithActivitiApplication {
···
这样整合部分就基本结束了,此时编辑器已经可以使用了。
至于界面的汉化,界面上各个组件,各个标签上的文字都是在resource下的stencilset.json文件中设置的,可以在网上找一个汉化后的stencilset.json文件替换掉,就能看到中文界面了。
5.modeler相关方法的封装
主要需要封装4个方法:1.新建一个空的模型;2.所有模型列表;3.发布模型;4.删除模型;(activiti已提供了保存和获取模型节点信息的方法,就是上面的那3个类)
由于这里涉及前后端交互,实现方式随意,主要是activiti的api的调用。
参考代码:
/**
* Created by liuruijie on 2017/2/21.
* 模型管理
*/
@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();
//完善ModelEditorSource
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();
}
}
补上demo代码,供参考。
https://github.com/DangerousPrayer/spring-boot-with-activiti
activiti version 5.22.0
spring boot version 1.5.1
网友评论
都在https://github.com/DangerousPrayer/spring-boot-with-activiti里。
你看看能不能用吧。
:
"Required request body is missing: public void org.activiti.rest.editor.model.ModelSaveRestResource.saveModel(java.lang.String,org.springframework.util.MultiValueMap<java.lang.String, java.lang.String>)"
message
:
"Bad request"
不过需要改下thymeleaf的解析模式,在application.properties中加上```spring.thymeleaf.mode=LEGACYHTML5```,然后引入nekohtml的依赖。这样普通的html文件被thymeleaf解析也不会出错了。