20Demo01 一个基于HXFlow的Demo
来源:互联网 发布:2015公安部上牌数据 编辑:程序博客网 时间:2024/06/05 14:22
这是一个基于HXFlow的小demo
首先看一下流程图吧
这个业务, 也算是比较简单
1. 需求就是zhangsan填写申请记录, 然后提交到RM审批
2. 然后zhangsansan可以退回给zhangsan, 或者拒绝这个请求, 或者审批通过然后交给上一级RGM审核
3. 然后zhangsi可以将申请退回给shangsan, 或者拒绝这个请求, 或者审批通过, 正常流程结束
效果截图 [我去 gif画风崩了]
状态切换1 : picApply - rmAuth - rgmAuth - success
accept accept accept
状态切换2 : picApply - rmAuth - rgmAuth - failed
accept accept reject
状态切换3 : picApply - rmAuth - picApply
accept return
好了, 分享一下核心代码, 但是 项目依赖于HXLog, HXAttrHandler, HXMongo, 然后这三个项目是找不到的[有空分享出来], 因此 就当随便看看吧
这里有一些为了实现目的而妥协的地方, 比如 loadFlowInstance的使用, 因为 这是三个进程, 然后 都有各自的flowEngine, 因此 当给定的用户执行命令之前从新从db中load了一次该用户的所有task, 并加载到flowEngine中, 这样的实现不完善, 而且 还存在潜在的隐患
多个pic申请任务的时候id的冲突的解决问题[TaskIdGenerator, 更新taskId的生成策略]
某些地方异常处理的漏洞 等等
代码 也算是比较简单, 这里就不多解释了
Test01HXFlowUsage
/**
* file name : Test01HXFlowUsage.java
* created at : 19:14 2017-03-22
* created by 970655147
*/
public class Test01HXFlowUsage {
/**
* 一些上下文信息
*/
// 辅助输入的工具
public static final Scanner SCANNER = new Scanner(System.in);
// 记录当前登陆的用户的信息
public static User LOGGED_USER = null;
public static MysqlTaskDao DAO = new MysqlTaskDaoImpl(Task.PROTO_BEAN, new MysqlDbConfig()
.username("root").password("root")
.db("test02").table("hx_flow_task").id("id"));
public static final FlowEngine<State, Action> FLOW_ENGINE = new StandardFlowEngine();
public static final String TEST_FLOW_NAME = "jerry";
static {
StandardStateMachine.TransferMapBuilder<State, Action> builder = StandardStateMachine.TransferMapBuilder.start()
.add(ApplyState.PIC_APPLY, ApplyAction.ACCEPT, ApplyState.RM_AUTH, AcceptHandler.getInstance())
.add(ApplyState.RM_AUTH, ApplyAction.ACCEPT, ApplyState.RGM_AUTH, AcceptHandler.getInstance())
.add(ApplyState.RGM_AUTH, ApplyAction.ACCEPT, ApplyState.SUCCESS, AcceptHandler.getInstance())
.add(ApplyState.RM_AUTH, ApplyAction.RETURN, ApplyState.PIC_APPLY, ReturnHandler.getInstance())
.add(ApplyState.RGM_AUTH, ApplyAction.RETURN, ApplyState.PIC_APPLY, ReturnHandler.getInstance())
.add(ApplyState.RM_AUTH, ApplyAction.REJECT, ApplyState.FAILED, RejectHandler.getInstance())
.add(ApplyState.RGM_AUTH, ApplyAction.REJECT, ApplyState.FAILED, RejectHandler.getInstance());
// pic - rm - rgm - success
// \ | /
// failed
StateMachine<State, Action> stateMachine = new StandardStateMachine(ApplyState.PIC_APPLY, builder.build());
FLOW_ENGINE.deploy(TEST_FLOW_NAME, stateMachine);
}
/**
* 业务所需常量
*/
/**
* 模拟的命令
*/
public static final String LS = "ls";
public static final String APPLY_TASK = "apply";
public static final String DO = "do";
public static final String HELP = "help";
public static final String QUIT = "quit";
public static final Map<String, CmdExecutor> CMD_2_EXECUTOR = Tools.asMap(new String[]{
LS, APPLY_TASK, DO, HELP
}, new LsCmdExecutor(), new ApplyCmdExecutor(), new DoCmdExecutor(), new HelpCmdExecutor());
/**
* 三个测试用户
*/
public static final User RGM = new User("rgm", "rgm", Role.RGM, null);
public static final User RM = new User("rm", "rm", Role.RM, RGM.getUserName());
public static final User PIC = new User("pic", "pic", Role.PIC, RM.getUserName());
public static final Map<String, User> allUser = Tools.asMap(new String[]{
PIC.getUserName(), RM.getUserName(), RGM.getUserName()
}, PIC, RM, RGM);
// 以一个具体的场景模拟HXFlow的使用
public static void main(String[] args) throws Exception {
// ------------------------------------ prepare start ---------------------------------------------
// MysqlSqlGenerator.generateCreateTableSql的时候, 将Task声明为public, 否则 会访问不到getter
// Task task = new Task("1", "jerry", "apply", "taskName", "taskDesc", "handler");
// info(MysqlSqlGenerator.generateCreateTableSql("hx_flow_task", JSONObject.fromObject(task)) );
// info(JSONTransferableUtils.generateIdxes(Task.class, 3) );
// info(JSONTransferableUtils.generateDaoDaoImpl(Task.class, JSONTransferableUtils.TYPE_MYSQL) );
// ------------------------------------ prepare end ---------------------------------------------
while (true) {
User user = null;
while (true) {
info("please input userName : ");
String userName = SCANNER.nextLine();
info("please input password : ");
String pwd = SCANNER.nextLine();
user = allUser.get(userName);
if ((user != null) && (user.getPwd().equals(pwd))) {
break;
}
err("invalid userName or password !");
}
// logged in, then deal user's input
LOGGED_USER = user;
info("user " + LOGGED_USER.getUserName() + " logged in !");
while (true) {
info("please input an command, try help for more information !");
String cmd = SCANNER.nextLine();
loadFlowInstance(LOGGED_USER);
if (Tools.isEmpty(cmd)) {
continue;
}
cmd = cmd.trim().toLowerCase();
int idxOfBlank = cmd.indexOf(" ");
String firstArg = (idxOfBlank >= 0) ? cmd.substring(0, idxOfBlank) : cmd;
if (QUIT.equals(firstArg)) {
info("user " + LOGGED_USER.getUserName() + " logged out !");
break;
}
CmdExecutor executor = CMD_2_EXECUTOR.get(firstArg);
if (executor == null) {
warn("have no this cmd : " + cmd);
continue;
}
executor.execute(LOGGED_USER, cmd);
}
}
}
/**
* 加载给定的用户的所有flowIntance到flowEngine
*
* @param user 需要加载的任务所属的用户
* @return void
* @author 970655147 created at 2017-03-22 23:42
*/
private static void loadFlowInstance(User user) {
List<Task> tasks = null;
try {
tasks = DAO.findMany(Criteria.eq("handler", user.getUserName()), IDX_MANAGER.getDoLoad(), null);
} catch (Exception e) {
e.printStackTrace();
err("error while read user[" + user.getUserName() + "]'s tasks !");
return;
}
for (Task task : tasks) {
FLOW_ENGINE.addFlowInstance(task.getId(), task.getFlow(), ApplyState.DUMMY.idOf(task.getState()), null, null);
}
}
/**
* 执行命令的接口
*/
public static interface CmdExecutor {
/**
* 执行给定的命令
*
* @return
* @author 970655147 created at 2017-03-22 20:57
*/
public void execute(User user, String cmd);
}
/**
* 获取给定的用户的executor
*/
private static class LsCmdExecutor implements CmdExecutor {
@Override
public void execute(User user, String cmd) {
List<Task> tasks = null;
try {
tasks = DAO.findMany(Criteria.eq("handler", user.getUserName()), IDX_MANAGER.getDoLoad(), null);
} catch (Exception e) {
e.printStackTrace();
err("error while read user[" + user.getUserName() + "]'s tasks !");
return;
}
infoForPage("all tasks as follow");
for (Task task : tasks) {
info(task.toString());
}
infoForPage("all tasks ends");
}
}
/**
* 申请任务的命令executor
*/
private static class ApplyCmdExecutor implements CmdExecutor {
@Override
public void execute(User user, String cmd) {
if (user.getRole() != Role.PIC) {
err("can't create flow !");
return;
}
String flow = Tools.getStrInRangeWithStart(cmd, APPLY_TASK).trim();
String taskId = FLOW_ENGINE.startFlowInstance(flow, null, null);
if (Tools.isEmpty(taskId)) {
err("have no this flow : " + flow);
return;
}
info("please input taskName : ");
String name = SCANNER.nextLine();
info("please input taskDesc : ");
String desc = SCANNER.nextLine();
FlowTaskFacade<State, Action> taskFacade = FLOW_ENGINE.getTask(taskId, null);
Task task = new Task(taskId, taskFacade.flow(), taskFacade.now().id(), name, desc, user.getUserName());
try {
DAO.save(task, IDX_MANAGER.getDoLoad(), IDX_MANAGER.getDoFilter());
} catch (Exception e) {
err("error while save task[" + task + "] !");
}
}
}
/**
* 操作任务的executor
*/
private static class DoCmdExecutor implements CmdExecutor {
@Override
public void execute(User user, String cmd) {
String taskId = Tools.getStrInRangeWithStart(cmd, DO).trim();
FlowTaskFacade<State, Action> task = FLOW_ENGINE.getTask(taskId, null);
if (task == null) {
err("have no this task : " + taskId);
return;
}
StateMachine<State, Action> stateMachine = FLOW_ENGINE.getStateMachine(task.flow());
List<Action> nextActions = stateMachine.nextActions(task.now());
info("all action could apply as follow, please select one or quit");
for (Action action : nextActions) {
info(action.id());
}
String action = SCANNER.nextLine();
if (Tools.isEmpty(action)) {
err("empty action !");
return;
}
action = action.trim();
if (QUIT.equals(action)) {
return;
}
try {
boolean succ = FLOW_ENGINE.complete(task.id(), ApplyAction.DUMMY.idOf(action), user, null);
if (!succ) {
err("unknown action : " + action);
}
} catch (Exception e) {
e.printStackTrace();
err("error while complete task[" + task.toString() + "], with action : " + action);
}
}
}
/**
* 打印提示信息
*/
private static class HelpCmdExecutor implements CmdExecutor {
@Override
public void execute(User user, String cmd) {
info("this is a simple tests for HXFlow !");
info(" `ls` : ls current user's todo tasks !");
info(" `apply $flow` : apply an task for current user !");
info(" `do $taskId` : complete specified task !");
info(" `help` : show help information !");
}
}
/**
* pic - rmAuth, rmAuth -> rgmAuth, rgmAuth -> success
* 处理所有的accept部分的逻辑
*/
private static class AcceptHandler implements TransferHandler<State, Action> {
private static final AcceptHandler INSTANCE = new AcceptHandler();
public static AcceptHandler getInstance() {
return INSTANCE;
}
@Override
public boolean handle(TransferContext<State, Action> transferContext) throws Exception {
User user = (User) transferContext.extra();
IUpdateCriteria update = Criteria.set("state", transferContext.dstState().id()).add("handler", user.getLeader());
DAO.updateMany(Criteria.eq("id", transferContext.task().id()), update);
return true;
}
}
/**
* rmAuth -> pic, rgmAuth -> pic
* 处理所有的return部分的逻辑
*/
private static class ReturnHandler implements TransferHandler<State, Action> {
private static final ReturnHandler INSTANCE = new ReturnHandler();
public static ReturnHandler getInstance() {
return INSTANCE;
}
@Override
public boolean handle(TransferContext<State, Action> transferContext) throws Exception {
IUpdateCriteria update = Criteria.set("state", transferContext.dstState().id()).add("handler",PIC.getUserName());
DAO.updateMany(Criteria.eq("id", transferContext.task().id()), update);
return true;
}
}
/**
* rmAuth -> failed, rgmAuth -> failed
* 处理所有的reject部分的逻辑
*/
private static class RejectHandler implements TransferHandler<State, Action> {
private static final RejectHandler INSTANCE = new RejectHandler();
public static RejectHandler getInstance() {
return INSTANCE;
}
@Override
public boolean handle(TransferContext<State, Action> transferContext) throws Exception {
IUpdateCriteria update = Criteria.set("state", transferContext.dstState().id()).add("handler", null);
DAO.updateMany(Criteria.eq("id", transferContext.task().id()), update);
return true;
}
}
}
Task
public class Task implements JSONTransferable<Task, Integer> {
private String id;
private String flow;
private String state;
private String name;
private String desc;
private String handler;
// 省略其他getter & setter 以及JSONTransferable相关
}
User
public class User {
private String userName;
private String pwd;
private Role role;
private String leader;
// 省略其他getter & setter
}
ApplyState
public enum ApplyState implements State<ApplyState> {
PIC_APPLY("apply"), RM_AUTH("rmAuth"), RGM_AUTH("rgmAuth"), SUCCESS("success"), FAILED("failed"), DUMMY("dummy");
private static Map<String, ApplyState> ID_2_STATE = new HashMap<>();
static {
for(ApplyState state : values()) {
ID_2_STATE.put(state.id, state);
}
}
private String id;
ApplyState(String id) {
this.id = id;
}
@Override
public String id() {
return id;
}
@Override
public ApplyState create(String s, Object o) {
return idOf(s);
}
@Override
public ApplyState idOf(String s) {
return ID_2_STATE.get(s);
}
@Override
public ApplyState state() {
return this;
}
@Override
public Object extra() {
return null;
}
}
ApplyAction
public enum ApplyAction implements Action<ApplyAction> {
ACCEPT("accept"), RETURN("return"), REJECT("reject"), DUMMY("dummy");
private static Map<String, ApplyAction> ID_2_ACTION = new HashMap<>();
static {
for(ApplyAction state : values()) {
ID_2_ACTION.put(state.id, state);
}
}
private String id;
ApplyAction(String id) {
this.id = id;
}
@Override
public String id() {
return id;
}
@Override
public ApplyAction create(String s, Object o) {
return idOf(s);
}
@Override
public ApplyAction idOf(String s) {
return ID_2_ACTION.get(s);
}
@Override
public ApplyAction action() {
return this;
}
@Override
public Object extra() {
return null;
}
}
Role
public enum Role {
PIC, RM, RGM;
}
完
- 20Demo01 一个基于HXFlow的Demo
- 20 HXFlow
- Demo01:Activity的迁移
- demo01
- 基于directX的一个游戏DEMO
- 基于jquery的一个倒计时demo
- 一个基于ES5的vue小demo
- 一个基于netty的websocket聊天demo
- 一个基于Node的文件服务器demo的实现
- 一个基于线程池的网络处理服务器demo
- 基于UDP写的一个聊天小Demo
- 基于jquery easyui 的一个通讯录管理Demo
- 分享一个基于Swift3.0的ios入门学习Demo
- 一个基于ES6+webpack的vue小demo
- 基于 canvas 实现的一个截图小 demo
- 开发一个基于React Native的简易demo--前记
- 开发一个基于React Native的简易demo--源码
- 基于Oauth 2.0的一个登录注册demo
- 生物芯片(关灯问题 质因数分解定理)
- build.gradle配置
- 运算符的学后总结
- spring 源码如何导入到eclipse
- 【Android眼中的IOS】IOS开发快速解析Json数据(仿Android解析流程)
- 20Demo01 一个基于HXFlow的Demo
- [LeetCode]453. Minimum Moves to Equal Array Elements
- MySQL主从复制-双主结构
- 【JavaScript】性能优化篇
- 在O(1)时间复杂度删除链表节点
- mysql基础总结 语法篇
- 交换两个整型变量的两种方式
- lotou详解一:基本概念
- 输出100-200之间的素数