浏览代码

add:mec-workflow

yonge 5 年之前
父节点
当前提交
e311374b31

+ 66 - 0
mec-workflow/pom.xml

@@ -0,0 +1,66 @@
+<?xml version="1.0"?>
+<project
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+	xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>com.ym</groupId>
+		<artifactId>mec</artifactId>
+		<version>1.0</version>
+	</parent>
+	<artifactId>mec-workflow</artifactId>
+	<name>mec-workflow</name>
+	<url>http://maven.apache.org</url>
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+	</properties>
+	
+	<dependencies>
+		
+		<dependency>
+			<groupId>org.springframework.cloud</groupId>
+			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>org.springframework.cloud</groupId>
+			<artifactId>spring-cloud-starter-security</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>org.springframework.cloud</groupId>
+			<artifactId>spring-cloud-sleuth-zipkin</artifactId>
+		</dependency>
+
+		<!-- swagger-spring-boot -->
+		<dependency>
+			<groupId>com.spring4all</groupId>
+			<artifactId>swagger-spring-boot-starter</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>com.alibaba</groupId>
+			<artifactId>druid-spring-boot-starter</artifactId>
+		</dependency>
+		
+		<dependency>
+			<groupId>mysql</groupId>
+			<artifactId>mysql-connector-java</artifactId>
+		</dependency>
+		
+		<dependency>
+			<groupId>com.ym</groupId>
+			<artifactId>common-core</artifactId>
+		</dependency>
+		
+		<dependency>
+			<groupId>com.ym</groupId>
+			<artifactId>mec-auth-api</artifactId>
+		</dependency>
+		
+		<dependency>
+			<groupId>com.ym</groupId>
+			<artifactId>snakerflowy</artifactId>
+		</dependency>
+	</dependencies>
+</project>

+ 24 - 0
mec-workflow/src/main/java/com/ym/mec/workfow/WorkflowApplication.java

@@ -0,0 +1,24 @@
+package com.ym.mec.workfow;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+import com.spring4all.swagger.EnableSwagger2Doc;
+
+@SpringBootApplication
+@EnableDiscoveryClient
+@EnableFeignClients("com.ym.mec")
+@MapperScan("com.ym.mec.workflow.dal.dao")
+@ComponentScan(basePackages = { "com.ym.mec", "org.snaker.engine" })
+@Configuration
+@EnableSwagger2Doc
+public class WorkflowApplication {
+	public static void main(String[] args) {
+		SpringApplication.run(WorkflowApplication.class, args);
+	}
+}

+ 36 - 0
mec-workflow/src/main/java/com/ym/mec/workfow/config/ResourceServerConfig.java

@@ -0,0 +1,36 @@
+package com.ym.mec.workfow.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
+import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
+import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
+
+import com.ym.mec.common.security.BaseAccessDeniedHandler;
+import com.ym.mec.common.security.BaseAuthenticationEntryPoint;
+
+@Configuration
+@EnableResourceServer
+public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
+
+	@Autowired
+	private BaseAccessDeniedHandler baseAccessDeniedHandler;
+
+	@Autowired
+	private BaseAuthenticationEntryPoint baseAuthenticationEntryPoint;
+
+	@Override
+	public void configure(HttpSecurity http) throws Exception {
+		http.authorizeRequests().antMatchers("/v2/api-docs", "/news/list", "/news/query/*").permitAll()// 任何人不登录都可以获取的资源
+				// .antMatchers("/ipController/**").hasIpAddress("127.0.0.1") //特定ip可以不登录获取资源
+				// .antMatchers("/ipControll/**").access("isAuthenticated() and hasIpAddress('127.0.0.1')")// 特定ip必须登录才能获取
+				.anyRequest().authenticated().and().csrf().disable();
+	}
+
+	@Override
+	public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
+		resources.authenticationEntryPoint(baseAuthenticationEntryPoint).accessDeniedHandler(baseAccessDeniedHandler);
+	}
+
+}

+ 106 - 0
mec-workflow/src/main/java/com/ym/mec/workfow/config/WebMvcConfig.java

@@ -0,0 +1,106 @@
+package com.ym.mec.workfow.config;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.format.FormatterRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
+import com.ym.mec.common.config.EnumConverterFactory;
+import com.ym.mec.common.enums.BaseEnum;
+
+@Configuration
+public class WebMvcConfig implements WebMvcConfigurer {
+
+	/**
+	 * 枚举类的转换器 addConverterFactory
+	 */
+	@Override
+	public void addFormatters(FormatterRegistry registry) {
+		registry.addConverterFactory(new EnumConverterFactory());
+	}
+
+	@SuppressWarnings("rawtypes")
+	@Bean
+	@Primary
+	public ObjectMapper ObjectMapper() {
+		ObjectMapper objectMapper = new ObjectMapper();
+		// 对于空的对象转json的时候不抛出错误
+		objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
+		// 禁用遇到未知属性抛出异常
+		objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
+		// 序列化BigDecimal时不使用科学计数法输出
+		objectMapper.configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true);
+		// 日期和时间格式化
+		JavaTimeModule javaTimeModule = new JavaTimeModule();
+		javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+		javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+		javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
+		javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+		javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+		javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
+
+		// BaseEnum序列化
+		javaTimeModule.addSerializer(BaseEnum.class, new JsonSerializer<BaseEnum>() {
+
+			@Override
+			public void serialize(BaseEnum enumObj, JsonGenerator jsonGenerator, SerializerProvider serializers) throws IOException {
+				jsonGenerator.writeString(enumObj.getCode().toString());
+			}
+
+		});
+
+		// Date序列化和反序列化
+		javaTimeModule.addSerializer(Date.class, new JsonSerializer<Date>() {
+			@Override
+			public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
+				SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+				String formattedDate = formatter.format(date);
+				jsonGenerator.writeString(formattedDate);
+			}
+		});
+
+		javaTimeModule.addDeserializer(Date.class, new JsonDeserializer<Date>() {
+			@Override
+			public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
+				SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+				String date = jsonParser.getText();
+				try {
+					return format.parse(date);
+				} catch (ParseException e) {
+					throw new RuntimeException(e);
+				}
+			}
+		});
+
+		objectMapper.registerModule(javaTimeModule);
+		return objectMapper;
+	}
+
+}

+ 52 - 0
mec-workflow/src/main/java/com/ym/mec/workfow/controller/flow/FlowController.java

@@ -0,0 +1,52 @@
+package com.ym.mec.workfow.controller.flow;
+
+import org.snaker.engine.SnakerEngine;
+import org.snaker.engine.access.Page;
+import org.snaker.engine.access.QueryFilter;
+import org.snaker.engine.entity.HistoryOrder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.ym.mec.auth.api.client.SysUserFeignService;
+import com.ym.mec.auth.api.entity.SysUser;
+import com.ym.mec.common.controller.BaseController;
+
+@RestController
+@RequestMapping(value = "/snaker/flow")
+public class FlowController extends BaseController {
+
+	@Autowired
+	private SnakerEngine snakerEngine;
+
+	@Autowired
+	private SysUserFeignService SysUserFeignService;
+
+	/**
+	 * 流程实例查询
+	 * @param model
+	 * @param page
+	 * @return
+	 */
+	@GetMapping(value = "order")
+	public Object order(Page<HistoryOrder> page) {
+		return succeed(snakerEngine.query().getHistoryOrders(page, new QueryFilter()));
+	}
+
+	/**
+	 * 抄送实例已读
+	 * @param id
+	 * @param url
+	 * @return
+	 */
+	@PostMapping(value = "ccread")
+	public Object ccread(String id) {
+		SysUser user = SysUserFeignService.queryUserInfo();
+
+		snakerEngine.order().updateCCStatus(id, new String[] { user.getId() + "" });
+		return succeed();
+	}
+
+}

+ 144 - 0
mec-workflow/src/main/java/com/ym/mec/workfow/controller/flow/ProcessController.java

@@ -0,0 +1,144 @@
+/* Copyright 2012-2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.ym.mec.workfow.controller.flow;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang.StringUtils;
+import org.snaker.engine.SnakerEngine;
+import org.snaker.engine.access.Page;
+import org.snaker.engine.access.QueryFilter;
+import org.snaker.engine.entity.HistoryTask;
+import org.snaker.engine.entity.Process;
+import org.snaker.engine.entity.Task;
+import org.snaker.engine.helper.AssertHelper;
+import org.snaker.engine.helper.StringHelper;
+import org.snaker.engine.model.ProcessModel;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import com.ym.mec.common.controller.BaseController;
+
+/**
+ * 流程定义
+ * @author yuqs
+ * @since 0.1
+ */
+@RestController
+@RequestMapping(value = "/snaker/process")
+public class ProcessController extends BaseController {
+
+	@Autowired
+	private SnakerEngine snakerEngine;
+
+	/**
+	 * 流程定义查询列表
+	 * @param model
+	 * @return
+	 */
+	@GetMapping(value = "list")
+	public Object processList(Page<Process> page, String displayName) {
+		QueryFilter filter = new QueryFilter();
+		if (StringHelper.isNotEmpty(displayName)) {
+			filter.setDisplayName(displayName);
+		}
+		return succeed(snakerEngine.process().getProcesss(page, filter));
+	}
+
+	/**
+	 * 根据流程定义ID,删除流程定义
+	 * @param id
+	 * @return
+	 */
+	@PostMapping(value = "delete/{id}")
+	public Object processDelete(@PathVariable("id") String id) {
+		snakerEngine.process().undeploy(id);
+		return succeed();
+	}
+
+	/**
+	 * 添加流程定义后的部署
+	 * @param snakerFile
+	 * @param id
+	 * @return
+	 * @throws IOException 
+	 */
+	@PostMapping(value = "deploy")
+	public Object processDeploy(@RequestParam(value = "snakerFile") MultipartFile snakerFile, String id) throws IOException {
+		InputStream input = null;
+		try {
+			input = snakerFile.getInputStream();
+			if (StringUtils.isNotEmpty(id)) {
+				snakerEngine.process().redeploy(id, input);
+			} else {
+				snakerEngine.process().deploy(input);
+			}
+		} finally {
+			if (input != null) {
+				input.close();
+			}
+		}
+		return succeed();
+	}
+
+	@GetMapping(value = "json")
+	@ResponseBody
+	public Object json(String processId, String orderId) {
+		Process process = snakerEngine.process().getProcessById(processId);
+		AssertHelper.notNull(process);
+		ProcessModel model = process.getModel();
+		Map<String, Object> jsonMap = new HashMap<String, Object>();
+		if (model != null) {
+			jsonMap.put("process", model);
+		}
+
+		if (StringUtils.isNotEmpty(orderId)) {
+			List<Task> tasks = snakerEngine.query().getActiveTasks(new QueryFilter().setOrderId(orderId));
+			jsonMap.put("tasks", tasks);
+
+			List<HistoryTask> historyTasks = snakerEngine.query().getHistoryTasks(new QueryFilter().setOrderId(orderId));
+			jsonMap.put("historyTasks", historyTasks);
+		}
+		return jsonMap;
+	}
+
+	@GetMapping(value = "display")
+	public Object display(String orderId) {
+		List<HistoryTask> tasks = snakerEngine.query().getHistoryTasks(new QueryFilter().setOrderId(orderId));
+		return succeed(tasks);
+	}
+
+	/**
+	 * 显示独立的流程图
+	 */
+	@GetMapping(value = "diagram")
+	public String diagram(Model model, String processId, String orderId) {
+		model.addAttribute("processId", processId);
+		model.addAttribute("orderId", orderId);
+		return "snaker/diagram";
+	}
+}

+ 68 - 0
mec-workflow/src/main/java/com/ym/mec/workfow/controller/flow/SurrogateController.java

@@ -0,0 +1,68 @@
+/* Copyright 2012-2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.ym.mec.workfow.controller.flow;
+
+import org.snaker.engine.SnakerEngine;
+import org.snaker.engine.access.Page;
+import org.snaker.engine.access.QueryFilter;
+import org.snaker.engine.entity.Surrogate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.ym.mec.common.controller.BaseController;
+
+/**
+ * 委托授权
+ * @author yuqs
+ * @since 0.1
+ */
+@RestController
+@RequestMapping(value = "/snaker/surrogate")
+public class SurrogateController extends BaseController {
+
+	@Autowired
+	private SnakerEngine snakerEngine;
+
+	@GetMapping(value = "list")
+	public Object list(Page<Surrogate> page) {
+		return succeed(snakerEngine.manager().getSurrogate(page, new QueryFilter()));
+	}
+
+	@GetMapping(value = "view/{id}")
+	public Object view(@PathVariable("id") String id) {
+		return succeed(snakerEngine.manager().getSurrogate(id));
+	}
+
+	@PostMapping(value = "update")
+	public Object update(Surrogate surrogate) {
+		surrogate.setSdate(surrogate.getSdate() + " 00:00:00");
+		surrogate.setEdate(surrogate.getEdate() + " 23:59:59");
+		if (surrogate.getState() == null) {
+			surrogate.setState(1);
+		}
+		snakerEngine.manager().saveOrUpdate(surrogate);
+		return succeed();
+	}
+
+	@RequestMapping(value = "delete/{id}")
+	public Object delete(@PathVariable("id") String id) {
+		snakerEngine.manager().deleteSurrogate(id);
+		return succeed();
+	}
+}

+ 192 - 0
mec-workflow/src/main/java/com/ym/mec/workfow/controller/flow/TaskController.java

@@ -0,0 +1,192 @@
+package com.ym.mec.workfow.controller.flow;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang.StringUtils;
+import org.snaker.engine.SnakerEngine;
+import org.snaker.engine.access.Page;
+import org.snaker.engine.access.QueryFilter;
+import org.snaker.engine.entity.HistoryOrder;
+import org.snaker.engine.entity.Task;
+import org.snaker.engine.entity.WorkItem;
+import org.snaker.engine.model.TaskModel.TaskType;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.ym.mec.auth.api.client.SysUserFeignService;
+import com.ym.mec.auth.api.entity.SysUser;
+import com.ym.mec.common.controller.BaseController;
+
+/**
+ * Snaker流程引擎常用Controller
+ * @author yuqs
+ * @since 0.1
+ */
+@RestController
+@RequestMapping(value = "/snaker/task")
+public class TaskController extends BaseController {
+
+	@Autowired
+	private SnakerEngine snakerEngine;
+
+	@Autowired
+	private SysUserFeignService SysUserFeignService;
+
+	@GetMapping(value = "active")
+	public Object homeTaskList(Model model) {
+
+		SysUser user = SysUserFeignService.queryUserInfo();
+
+		List<String> list = new ArrayList<String>();
+		list.add(user.getUsername());
+
+		String[] assignees = new String[list.size()];
+		list.toArray(assignees);
+
+		Page<WorkItem> majorPage = new Page<WorkItem>(5);
+		Page<WorkItem> aidantPage = new Page<WorkItem>(3);
+		Page<HistoryOrder> ccorderPage = new Page<HistoryOrder>(3);
+		List<WorkItem> majorWorks = snakerEngine.query().getWorkItems(majorPage,
+				new QueryFilter().setOperators(assignees).setTaskType(TaskType.Major.ordinal()));
+		List<WorkItem> aidantWorks = snakerEngine.query().getWorkItems(aidantPage,
+				new QueryFilter().setOperators(assignees).setTaskType(TaskType.Aidant.ordinal()));
+		List<HistoryOrder> ccWorks = snakerEngine.query().getCCWorks(ccorderPage, new QueryFilter().setOperators(assignees).setState(1));
+
+		model.addAttribute("majorWorks", majorWorks);
+		model.addAttribute("majorTotal", majorPage.getTotalCount());
+		model.addAttribute("aidantWorks", aidantWorks);
+		model.addAttribute("aidantTotal", aidantPage.getTotalCount());
+		model.addAttribute("ccorderWorks", ccWorks);
+		model.addAttribute("ccorderTotal", ccorderPage.getTotalCount());
+		return succeed(model);
+	}
+
+	/**
+	 * 根据当前用户查询待办任务列表
+	 * @param model
+	 * @return
+	 */
+	@GetMapping(value = "user")
+	public Object userTaskList(Page<WorkItem> page) {
+		SysUser user = SysUserFeignService.queryUserInfo();
+
+		snakerEngine.query().getWorkItems(page, new QueryFilter().setOperator(user.getUsername()));
+		return succeed(page);
+	}
+
+	@PostMapping(value = "actor/add")
+	public Object addTaskActor(String orderId, String taskName, String operator) {
+		List<Task> tasks = snakerEngine.query().getActiveTasks(new QueryFilter().setOrderId(orderId));
+		for (Task task : tasks) {
+			if (task.getTaskName().equalsIgnoreCase(taskName) && StringUtils.isNotEmpty(operator)) {
+				snakerEngine.task().addTaskActor(task.getId(), operator);
+			}
+		}
+		return succeed();
+	}
+
+	@GetMapping(value = "tip")
+	public Object addTaskActor(String orderId, String taskName) {
+		List<Task> tasks = snakerEngine.query().getActiveTasks(new QueryFilter().setOrderId(orderId));
+		StringBuilder builder = new StringBuilder();
+		String createTime = "";
+		for (Task task : tasks) {
+			if (task.getTaskName().equalsIgnoreCase(taskName)) {
+				String[] actors = snakerEngine.query().getTaskActorsByTaskId(task.getId());
+				for (String actor : actors) {
+					builder.append(actor).append(",");
+				}
+				createTime = task.getCreateTime();
+			}
+		}
+		if (builder.length() > 0) {
+			builder.deleteCharAt(builder.length() - 1);
+		}
+		Map<String, String> data = new HashMap<String, String>();
+		data.put("actors", builder.toString());
+		data.put("createTime", createTime);
+		return succeed(data);
+	}
+
+	/**
+	 * 活动任务查询列表
+	 * @param model
+	 * @return
+	 */
+	@GetMapping(value = "active/more")
+	public Object activeTaskList(Page<WorkItem> page, Integer taskType) {
+		SysUser user = SysUserFeignService.queryUserInfo();
+
+		List<String> list = new ArrayList<String>();
+		list.add(user.getUsername());
+
+		String[] assignees = new String[list.size()];
+		list.toArray(assignees);
+		snakerEngine.query().getWorkItems(page, new QueryFilter().setOperators(assignees).setTaskType(taskType));
+		return succeed(page);
+	}
+
+	/**
+	 * 活动任务查询列表
+	 * @param model
+	 * @return
+	 */
+	@GetMapping(value = "active/ccmore")
+	public Object activeCCList(Page<HistoryOrder> page) {
+		SysUser user = SysUserFeignService.queryUserInfo();
+
+		List<String> list = new ArrayList<String>();
+		list.add(user.getUsername());
+
+		String[] assignees = new String[list.size()];
+		list.toArray(assignees);
+		snakerEngine.query().getCCWorks(page, new QueryFilter().setOperators(assignees).setState(1));
+		return succeed(page);
+	}
+
+	/**
+	 * 活动任务的驳回
+	 * @param model
+	 * @param taskId
+	 * @return
+	 */
+	@PostMapping(value = "reject")
+	public Object activeTaskReject(String taskId) {
+
+		SysUser user = SysUserFeignService.queryUserInfo();
+
+		snakerEngine.executeAndJumpTask(taskId, user.getUsername(), null, null);
+		return succeed();
+	}
+
+	/**
+	 * 历史完成任务查询列表
+	 * @param model
+	 * @return
+	 */
+	@GetMapping(value = "history")
+	public Object historyTaskList(Page<WorkItem> page) {
+		SysUser user = SysUserFeignService.queryUserInfo();
+		snakerEngine.query().getHistoryWorkItems(page, new QueryFilter().setOperator(user.getUsername()));
+		return succeed(page);
+	}
+
+	/**
+	 * 历史任务撤回
+	 * @param taskId
+	 * @return
+	 */
+	@PostMapping(value = "undo")
+	public Object historyTaskUndo(String taskId) {
+		SysUser user = SysUserFeignService.queryUserInfo();
+		snakerEngine.task().withdrawTask(taskId, user.getUsername());
+		return succeed();
+	}
+}

+ 68 - 0
mec-workflow/src/main/java/com/ym/mec/workfow/controller/web/LeaveController.java

@@ -0,0 +1,68 @@
+package com.ym.mec.workfow.controller.web;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.snaker.engine.SnakerEngine;
+import org.snaker.engine.access.QueryFilter;
+import org.snaker.engine.entity.Order;
+import org.snaker.engine.entity.Task;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.ym.mec.auth.api.client.SysUserFeignService;
+import com.ym.mec.auth.api.entity.SysUser;
+import com.ym.mec.common.controller.BaseController;
+
+@RequestMapping("leave")
+@RestController
+public class LeaveController extends BaseController {
+
+	@Autowired
+	private SysUserFeignService SysUserFeignService;
+
+	@Autowired
+	private SnakerEngine snakerEngine;
+
+	/**
+	 * 请假申请路由方法
+	 */
+	@PostMapping(value = "apply")
+	public Object apply(String processId, int days, String deptManager) {
+		SysUser user = SysUserFeignService.queryUserInfo();
+
+		Map<String, Object> params = new HashMap<String, Object>();
+		params.put("applyer", user.getUsername());
+		params.put("days", days);
+		params.put("deptManager", deptManager);
+
+		// 开启实例
+		Order order = snakerEngine.startInstanceById(processId, user.getUsername(), params);
+
+		// 获取当前任务
+		List<Task> tasks = snakerEngine.query().getActiveTasks(new QueryFilter().setOrderId(order.getId()).setOperator(user.getUsername()));
+		for (Task task : tasks) {
+			snakerEngine.executeTask(task.getId(), user.getUsername());
+		}
+
+		return succeed();
+	}
+
+	@PostMapping(value = "approve")
+	public Object approve(String taskId) {
+		SysUser user = SysUserFeignService.queryUserInfo();
+
+		List<Task> tasks = snakerEngine.executeTask(taskId, user.getUsername());
+
+		if (tasks.size() == 0) {
+			System.out.println("**********流程已结束*********");
+		} else {
+			System.out.println("**********流程未结束*********");
+		}
+
+		return succeed();
+	}
+}

+ 60 - 0
mec-workflow/src/main/resources/application.yml

@@ -0,0 +1,60 @@
+server:
+  port: 8010
+
+eureka:
+  client:
+    serviceUrl:
+      defaultZone: http://admin:admin123@localhost:8761/eureka/eureka/
+
+spring:
+  application:
+    name: workflow-server
+    
+  datasource:
+    name: test
+    url: jdbc:mysql://120.26.238.168:3306/snaker_web?useUnicode=true&characterEncoding=UTF8&serverTimezone=Asia/Shanghai
+    username: snaker_web
+    password: snaker_web
+    # 使用druid数据源
+    type: com.alibaba.druid.pool.DruidDataSource
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    filters: stat
+    maxActive: 20
+    initialSize: 1
+    maxWait: 60000
+    minIdle: 1
+    timeBetweenEvictionRunsMillis: 60000
+    minEvictableIdleTimeMillis: 300000
+    validationQuery: select 'x'
+    testWhileIdle: true
+    testOnBorrow: false
+    testOnReturn: false
+    poolPreparedStatements: true
+    maxOpenPreparedStatements: 20
+    
+
+mybatis:
+    mapperLocations: classpath:config/mybatis/*.xml
+    
+swagger:
+  base-package: com.ym.mec.workflow.controller
+  
+  
+##认证 
+security:
+  oauth2:
+    client:
+      client-id: app
+      client-secret: app
+    resource:
+      token-info-uri: http://localhost:8001/oauth/check_token
+  
+#spring boot admin 相关配置
+management:
+  endpoints:
+    web:
+      exposure:
+        include: "*"
+  endpoint:
+    health:
+      show-details: ALWAYS

+ 21 - 0
mec-workflow/src/main/resources/config/mybatis/Global.mapper.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+
+<mapper namespace="global">
+
+	<sql id="limit">
+		<if test="offset != null">
+			 limit #{offset},#{rows}
+		</if>
+	</sql>
+
+	<sql id="orderby">
+		<if test="sort != null and sort != ''">
+			 ORDER BY ${sort}
+			 <if test="order != null and order != ''">
+			 	${order}
+			 </if>
+		</if>
+	</sql>	
+ </mapper>

+ 20 - 0
mec-workflow/src/main/resources/flows/leave.snaker

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<process displayName="请假流程测试" name="leave">
+<start displayName="start1" layout="24,124,-1,-1" name="start1">
+<transition g="" name="transition1" offset="0,0" to="apply"/>
+</start>
+<end displayName="end1" layout="570,124,-1,-1" name="end1"/>
+<task assignee="${applyer}" displayName="请假申请" layout="117,122,-1,-1" name="apply" performType="ANY">
+<transition g="" name="transition2" offset="0,0" to="approveDept"/>
+</task>
+<task assignee="${deptManager}" displayName="部门经理审批" layout="272,122,-1,-1" name="approveDept" performType="ANY">
+<transition g="" name="transition3" offset="0,0" to="decision1"/>
+</task>
+<decision displayName="decision1" layout="426,124,-1,-1" name="decision1">
+<transition displayName="&lt;=5天" expr="${days &lt;= 5}" g="" name="transition4" offset="0,0" to="end1"/>
+<transition displayName="&gt;5天" expr="${days &gt; 5}" g="" name="transition5" offset="0,0" to="approveBoss"/>
+</decision>
+<task assignee="boss" displayName="总经理审批" layout="404,231,-1,-1" name="approveBoss" performType="ANY">
+<transition g="" name="transition6" offset="0,0" to="end1"/>
+</task>
+</process>

+ 9 - 3
pom.xml

@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 	<modelVersion>4.0.0</modelVersion>
 
 	<groupId>com.ym</groupId>
@@ -72,6 +71,12 @@
 			</dependency>
 
 			<dependency>
+				<groupId>com.ym</groupId>
+				<artifactId>snakerflowy</artifactId>
+				<version>1.0</version>
+			</dependency>
+
+			<dependency>
 				<groupId>io.zipkin.java</groupId>
 				<artifactId>zipkin-server</artifactId>
 				<version>${zipkin.version}</version>
@@ -312,5 +317,6 @@
 		<module>cms</module>
 		<module>mec-im</module>
 		<module>workflowy</module>
-	</modules>
+	  <module>mec-workflow</module>
+  </modules>
 </project>

+ 2 - 1
workflowy/src/main/java/org/snaker/engine/model/NodeModel.java

@@ -145,7 +145,8 @@ public abstract class NodeModel extends BaseModel implements Action {
         return models;
     }
 
-    protected <T> void addNextModels(List<T> models, TransitionModel tm, Class<T> clazz) {
+    @SuppressWarnings("unchecked")
+	protected <T> void addNextModels(List<T> models, TransitionModel tm, Class<T> clazz) {
         if(clazz.isInstance(tm.getTarget())) {
             models.add((T)tm.getTarget());
         } else {

+ 37 - 0
workflowy/src/test/resources/test/generator/leave.snaker

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+  ~ /* Copyright 2013-2014 the original author or authors.
+  ~  *
+  ~  * Licensed under the Apache License, Version 2.0 (the "License");
+  ~  * you may not use this file except in compliance with the License.
+  ~  * You may obtain a copy of the License at
+  ~  *
+  ~  *     http://www.apache.org/licenses/LICENSE-2.0
+  ~  *
+  ~  * Unless required by applicable law or agreed to in writing, software
+  ~  * distributed under the License is distributed on an "AS IS" BASIS,
+  ~  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~  * See the License for the specific language governing permissions and
+  ~  * limitations under the License.
+  ~  */
+  -->
+
+<process displayName="请假流程测试" instanceUrl="/snaker/flow/all" name="leave">
+<start displayName="start1" layout="24,124,-1,-1" name="start1">
+<transition g="" name="transition1" offset="0,0" to="apply"/>
+</start>
+<end displayName="end1" layout="570,124,-1,-1" name="end1"/>
+<task assignee="apply.operator" displayName="请假申请" form="/flow/leave/apply" layout="117,122,-1,-1" name="apply" performType="ANY">
+<transition g="" name="transition2" offset="0,0" to="approveDept"/>
+</task>
+<task assignee="approveDept.operator" displayName="部门经理审批" form="/flow/leave/approveDept" layout="272,122,-1,-1" name="approveDept" performType="ANY">
+<transition g="" name="transition3" offset="0,0" to="decision1"/>
+</task>
+<decision displayName="decision1" expr="#day &gt; 2 ? 'transition5' : 'transition4'" layout="426,124,-1,-1" name="decision1">
+<transition displayName="&lt;=2天" g="" name="transition4" offset="0,0" to="end1"/>
+<transition displayName="&gt;2天" g="" name="transition5" offset="0,0" to="approveBoss"/>
+</decision>
+<task assignee="approveBoss.operator" displayName="总经理审批" form="/flow/leave/approveBoss" layout="404,231,-1,-1" name="approveBoss" performType="ANY">
+<transition g="" name="transition6" offset="0,0" to="end1"/>
+</task>
+</process>