首页 文章 精选 留言 我的

精选列表

搜索[整合],共10003篇文章
优秀的个人博客,低调大师

微信小程序+java后端整合笔记

用到的工具和技术. 1.微信web开发工具小程序版 2.Myeclipse 2014 3.WebSocket 4.Maven 3.3.9 5.Tomcat 7 步骤 1.安装配置Maven,使用Myeclipse创建web project 使用Maven项目结构. 具体步骤:点击打开链接 2.打开微信web开发工具,由于是内部开发测试,故不要填写 appID, 创建新项目,把项目放在Maven项目目录下 src/main/webapp/项目名 3.创建Websocket 实现握手通信. 以下代码均来自网络资料. java服务器端: [javascript] view plain copy packagewebsocketTest; importjava.io.IOException; importjava.util.concurrent.CopyOnWriteArraySet; importjavax.websocket.*; importjavax.websocket.server.ServerEndpoint; /** *@ServerEndpoint注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端, *注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端 */ @ServerEndpoint("/websocket") publicclassTestWebSocket{ //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。 privatestaticintonlineCount=0; //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识 privatestaticCopyOnWriteArraySet<TestWebSocket>webSocketSet=newCopyOnWriteArraySet<TestWebSocket>(); //与某个客户端的连接会话,需要通过它来给客户端发送数据 privateSessionsession; /** *连接建立成功调用的方法 *@paramsession可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据 */ @OnOpen publicvoidonOpen(Sessionsession){ this.session=session; webSocketSet.add(this);//加入set中 addOnlineCount();//在线数加1 System.out.println("有新连接加入!当前在线人数为"+getOnlineCount()); } /** *连接关闭调用的方法 */ @OnClose publicvoidonClose(){ webSocketSet.remove(this);//从set中删除 subOnlineCount();//在线数减1 System.out.println("有一连接关闭!当前在线人数为"+getOnlineCount()); } /** *收到客户端消息后调用的方法 *@parammessage客户端发送过来的消息 *@paramsession可选的参数 */ @OnMessage publicvoidonMessage(Stringmessage,Sessionsession){ System.out.println("来自客户端的消息:"+message); //群发消息 for(TestWebSocketitem:webSocketSet){ try{ item.sendMessage(message); }catch(IOExceptione){ e.printStackTrace(); continue; } } } /** *发生错误时调用 *@paramsession *@paramerror */ @OnError publicvoidonError(Sessionsession,Throwableerror){ System.out.println("发生错误"); error.printStackTrace(); } /** *这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。 *@parammessage *@throwsIOException */ publicvoidsendMessage(Stringmessage)throwsIOException{ this.session.getBasicRemote().sendText(message); //this.session.getAsyncRemote().sendText(message); } publicstaticsynchronizedintgetOnlineCount(){ returnonlineCount; } publicstaticsynchronizedvoidaddOnlineCount(){ TestWebSocket.onlineCount++; } publicstaticsynchronizedvoidsubOnlineCount(){ TestWebSocket.onlineCount--; } } [javascript] view plain copy 微信小程序客户端: [javascript] view plain copy <prename="code"class="javascript">varapp=getApp() Page({ onLoad:function(){ wx.connectSocket({ url:"ws://localhost:8080/TestYMG/websocket", }) wx.onSocketOpen(function(){ console.log('WebSocket连接已经打开!') wx.sendSocketMessage({ data:'HELLO,WORLD'+Math.random()*0XFFFFFF.toString() }) }); wx.onSocketMessage(function(data){ console.log(data); });</pre><prename="code"class="javascript">//监听是否关闭 wx.onSocketClose(function(){ console.log('WebSocket连接已经关闭!') }); },</pre><prename="code"class="javascript">//手动关闭连接 setclose:function(e){ console.log('WebSocket连接正在关闭!') wx.closeSocket(); } }) </pre><br> <p></p> <pre></pre> <p></p> 原文地址http://www.bieryun.com/671.html

优秀的个人博客,低调大师

python+ueditor+七牛云存储整合

开发环境:python pyramid。 參考网址:http://developer.qiniu.com/docs/v6/sdk/python-sdk.html,http://my.oschina.net/duoduo3369/blog/174655 项目中要将ueditor集成到站点,可是图片上传有问题。于是採取client(终端用户) => 七牛 => 业务server的方式来处理图片。具体的流程这篇文章写的非常清楚:http://my.oschina.net/duoduo3369/blog/174655,只是是java的,并且也没做图片显示的处理。 整个流程例如以下: 下面是几个关键步骤: 签名生成token 配置项目服务端请求路径:/ueditor/uptoken用来生成uptoken。 @view_defaults(route_name='ueditor') class UeditorView(object): def __init__(self, request): self.request = request self.db = request.db qiniu.conf.ACCESS_KEY = "your access_key" qiniu.conf.SECRET_KEY = "your secret_key" self.bucket_name="你的七牛空间名" @view_config(renderer='jsonp', match_param=('action=uptoken')) def uptoken(self): policy = qiniu.rs.PutPolicy(self.bucket_name) token= policy.token() return dict(token=token) @view_config(renderer='jsonp', match_param=('action=imgmanage')) def imgmanage(self): pass 另一个/ueditor/imgmanage用来图片管理的,这个临时没做。使用前先用easy_install安装qiniu的包并import一下。 配置ueditor上传请求 我用的版本号是ueditor1_2_6_1-jsp-utf8版本号。要修改的是dialogs/image/image.html文件: 在body里面加入一个表单,用来向七牛server上传token: <input id="qiniu_token" type="hidden" name="token" /> 在javascript标签中增加下面代码用来向项目server获取uptoken: $(function(){ $.get("/ueditor/uptoken", function(data) { $("#qiniu_token").val(data["token"]); }); }); 然后在上传button点击事件$G("upload").onclick中加入token參数: var postParams = { "dir":baidu.g("savePath").value, "token":$("#qiniu_token").val()//for qiniu yun token }; 还须要改ueditor下的ueditor.config.js文件,在window.UEDITOR_CONFIG配置中改动图片上传配置: window.UEDITOR_CONFIG = { //为编辑器实例加入一个路径。这个不能被凝视 UEDITOR_HOME_URL : URL //图片上传配置区 ,imageUrl:"http://up.qiniu.com/" //图片上传提交地址 ,imagePath:"http://shikeim.qiniudn.com/" //图片修正地址。这是七牛云应用空间的地址 ,imageFieldName:"file"//七牛结合须要改成file这样图片就能够正常上传到七牛云server了。 在ueditor中显示图片 调试了好久,发现image.html以下有个回调函数对象callbacks。这是上传成功的回调函数: // 单个文件上传完毕的回调 uploadCompleteCallback: function(data){ try{ var info = eval("(" + data.hash + ")"); info && imageUrls.push(info); selectedImageCount--; }catch(e){ console.log("excetion!up load failed..."); } }, 但其实七牛云图片上传成功了,响应的却是uploadErrorCallback上传失败回调函数。于是将原来的uploadErrorCallback凝视掉,自己又一次写了个: //qiniu yun 上传... uploadErrorCallback: function(data){ try{ var info = eval("(" + data.info + ")"); imgurl={normal:info['hash'],small:info['hash']+'-small'}; imageUrls.push(imgurl); // console.log(imageUrls); selectedImageCount--; }catch(e){ console.log("excetion!up load failed..."); } },imgurl就是七牛云返回的server端图片文件名称。我在七牛云上做了配置上传的图片有原版normal。还有缩略图版small。这两个都返回了。便于编辑器处理。 改完之后发现图片能插入了,可是无法正确显示,审查元素发现是图片名undefined。于是又看image.js的源代码,发现插入图片的是insertBatch函数,于是就该了下: /** * 插入多张图片 */ function insertBatch() { if (imageUrls.length < 1) return; var imgObjs = [], align = findFocus("localFloat", "name"); for (var i = 0, ci; ci = imageUrls[i++];) { var tmpObj = {}; console.log(ci); tmpObj.title = ci.title; tmpObj.floatStyle = align; //修正显示时候的地址数据,假设后台返回的是图片的绝对地址,那么此处无需修正 tmpObj._src = tmpObj.src = editor.options.imagePath + ci.small;//这里使用缩略图 imgObjs.push(tmpObj); } insertImage(imgObjs); hideFlash(); }至此图片上传成功集成。只是另一些小细节须要完好。 总结 有问题先网上查。查的目的不是找答案,而是找思路。明确思路后看文档,答案都在源代码中。 本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5096223.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Spark 整合hive 实现数据的读取输出

实验环境: linux centOS 6.7 vmware虚拟机 spark-1.5.1-bin-hadoop-2.1.0 apache-hive-1.2.1 eclipse 或IntelJIDea 本次使用eclipse. 代码: 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 import org.apache.spark.SparkConf; import org.apache.spark.api.java.JavaSparkContext; import org.apache.spark.sql.DataFrame; import org.apache.spark.sql.hive.HiveContext; public class SparkOnHiveDemo{ public static void main(String[]args){ //首先还是创建SparkConf SparkConfconf= new SparkConf().setAppName( "HiveDataSource" ); //创建JavaSparkContext JavaSparkContextsc= new JavaSparkContext(conf); //创建HiveContext,注意,这里,它接收的是SparkContext作为参数,不是JavaSparkContext HiveContexthiveContext= new HiveContext(sc.sc()); //1.可以使用HiveContext下面的sql(xxx语句)执行HiveSQL语句 //1.删除表,创建表 //stars_infos,stars_scores hiveContext.sql( "DROPTABLEIFEXISTSstars_infos" ); hiveContext.sql( "CREATETABLEIFNOTEXISTSstars_infos(nameSTRING,ageINT)" + "rowformatdelimitedfieldsterminatedby','" ); //2.向表里面导入数据 hiveContext.sql( "LOADDATA" + "LOCALINPATH" + "'/root/book/stars_infos.txt'" + "INTOTABLEstars_infos" ); hiveContext.sql( "DROPTABLEIFEXISTSstars_scores" ); hiveContext.sql( "CREATETABLEIFNOTEXISTSstars_scores(nameSTRING,scoreINT)" + "rowformatdelimitedfieldsterminatedby','" ); hiveContext.sql( "LOADDATA" + "LOCALINPATH" + "'/root/book/stars_score.txt'" + "INTOTABLEstars_scores" ); //3.从一张已经存在的hive表里面拿数据,转换为DF DataFramesuperStarDataFrame=hiveContext.sql( "SELECTsi.name,si.age,ss.score" + "FROMstars_infossi" + "JOINstars_scoresssONsi.name=ss.name" + "WHEREss.score>=90" ); //4.把DF的数据再持久化到hive中去,千万别和registerTemtable搞混了 hiveContext.sql( "DROPTABLEIFEXISTSsuperStar" ); superStarDataFrame.saveAsTable( "superStar" ); //5.直接从Hive中得到DF hiveContext.table( "superStar" ).show(); sc.close(); } } 元数据: 可以下载附件,然后上传到指定的目录下。 把程序打包jar后上传到linux指定的目录下,写一个脚本。脚本附件见正文。具体内容修改即可。 运行脚本就可以了。当然要保证MySQL数据库正常,hive正常。 附件:http://down.51cto.com/data/2366931 本文转自 ChinaUnicom110 51CTO博客,原文链接:http://blog.51cto.com/xingyue2011/1956798

优秀的个人博客,低调大师

JeeSite 整合 Magic API 快速 Java 接口发布框架

介绍 magic-api 是一个基于Java的接口快速开发框架,编写接口将通过magic-api提供的UI界面完成,自动映射为HTTP接口,无需定义Controller、Service、Dao、Mapper、XML、VO等Java对象即可完成常见的HTTP API接口开发。 完美搭配可视化数据大屏提供数据接口。 特性 支持MySQL、MariaDB、Oracle、DB2、PostgreSQL、SQLServer 等支持jdbc规范的数据库 支持非关系型数据库Redis、Mongodb 支持集群部署、接口自动同步。 支持分页查询以及自定义分页查询 支持多数据源配置,支持在线配置数据源 支持SQL缓存,以及自定义SQL缓存 支持自定义JSON结果、自定义分页结果 支持对接口权限配置、拦截器等功能 支持运行时动态修改数据源 支持Swagger接口文档生成 基于magic-script脚本引擎,动态编译,无需重启,实时发布 支持Linq式查询,关联、转换更简单 支持数据库事务、SQL支持拼接,占位符,判断等语法 支持文件上传、下载、输出图片 支持脚本历史版本对比与恢复 支持脚本代码自动提示、参数提示、悬浮提示、错误提示 支持导入Spring中的Bean、Java中的类 支持在线调试 支持自定义工具类、自定义模块包、自定义类型扩展、自定义方言、自定义列名转换等自定义操作 快速运行 环境准备:JDK 1.8 or 11、17、Maven 3.6+、无需准备数据库(使用内嵌 H2 DB) 下载源码:https://gitee.com/thinkgem/jeesite-magic-api/repository/archive/main.zip 执行脚本:/modules/magic-api/bin/package.bat(sh)编译打包 Magic API 模块 执行脚本:/web-fast/bin/run-tomcat.bat(sh)启动 Web 服务(会自动初始化库) 浏览器访问:http://127.0.0.1:8980/账号 system 密码 admin 部署常见问题:https://jeesite.com/docs/faq/ 快速开始 三分钟写出查询接口 创建分组 点击创建分组按钮后,输入分组信息,点击创建。 新建接口 右键分组,点击新建接口。 在编辑器输入内容后,填写接口名称和及其路径。 var sql = """ select * from js_sys_user """ return db.select(sql) 右上角点击保存按钮保存接口。 访问接口 右上角点击运行按钮,查看执行结果。 MagicAPI 文档 文档地址:https://ssssssss.org 在线演示:https://magic-api.ssssssss.org JeeSite 文档 部署文档:http://jeesite.com/docs/install-deploy/ 常见问题:http://jeesite.com/docs/faq/ 更多文档:http://jeesite.com/docs JeeSite 介绍 JeeSite 快速开发平台,不仅仅是一个后台开发框架,它是一个企业级快速开发解决方案,后端基于经典组合 Spring Boot、Shiro、MyBatis,前端采用 Beetl、Bootstrap、AdminLTE 经典开发模式,或者分离版 Vue3、Vite、Ant Design Vue、TypeScript、Vben Admin 最先进技术栈。提供在线代码生成功能,可自动创建业务模块工程和微服务模块工程,自动生成前端代码和后端代码;包括功能模块如:组织机构、角色用户、菜单及按钮授权、数据权限、系统参数、内容管理、工作流等。采用松耦合设计,微内核和插件架构,模块增减便捷;界面无刷新,一键换肤;众多账号安全设置,密码策略;文件在线预览;消息推送;多元化第三方登录;在线定时任务配置;支持集群,支持SAAS;支持多数据源;支持读写分离、分库分表;支持微服务应用。 JeeSite 快速开发平台的主要目的是能够让初级的研发人员快速的开发出复杂的业务功能,中高级人员有时间做一些更有用的事情。让开发者注重专注业务,其余有平台来封装技术细节,降低技术难度,从而节省人力成本,缩短项目周期,提高软件安全质量。 JeeSite 自 2013 年发布以来已被广大爱好者用到了企业、政府、医疗、金融、互联网等各个领域中,JeeSite 架构精良、易于扩展、大众思维的设计模式、工匠精神打磨每一个细节,深入开发者的内心,并荣获开源中国《最受欢迎中国开源软件》奖杯,期间也帮助了不少刚毕业的大学生,教师作为入门教材,快速的去实践。 JeeSite4 的升级,作者结合了多年总结和经验,以及各方面的应用案例,对架构完成了一次全部重构,也纳入很多新的思想。不管是从开发者模式、底层架构、逻辑处理还是到用户界面,用户交互体验上都有很大的进步,在不忘学习成本、提高开发效率的情况下,安全方面也做和很多工作,包括:身份认证、密码策略、安全审计、日志收集等众多安全选项供你选择。努力为大中小微企业打造全方位企业级快速开发解决方案。 优势 JeeSite 整体架构清晰、稳定技术先进、源代码书写规范、经典技术会的人多、易于维护、易于扩展、安全稳定。 JeeSite 功能全,知识点非常多,也非常少。因为她使用的都是一些通用的技术,通俗的设计风格,大多数基础知识点多数人都能掌握,所以每一个 JeeSite 的功能点都非常容易掌握。只要你学会使用这些功能和组件的应用,就可以顺利的完成系统开发了。 JeeSite 是一个低代码开发平台,具有较高的封装度、扩展性,封装不是限制你去做一些事情,而是在便捷的同时,也具有较好的扩展性,在不具备一些功能的情况下,JeeSite 提供了扩展接口,提供了原生调用方法。 大家都在用 Spring,也在学习 Spring 的优点,Spring 提供了较好的扩展性,可又有多少人去修改它的源代码呢,退一步说,大家去修改了 Spring 的源码,反而会对未来升级造成很大困扰,您说不是呢?这样的例子很多,所以不要纠结,我们非常注重这一点,JeeSite 也一样具备强大的扩展性。 为什么说 JeeSite 比较易于学习?JeeSite 很好的把握了设计的 “度”,避免过度设计的情况。过度设计是在产品设计过程中忽略了产品和用户的实际需求,反而带来了不必要的复杂性,而忽略了系统的学习、开发和维护成本。 至今 JeeSite 平台架构已经非常稳定。 JeeSite 精益求精,用心打磨每一个细节。 JeeSite 是一个专业的平台,是一个让你使用放心的平台。 安全方面优势:https://jeesite.com/docs/feature/ JeeSite 生态系统 分布式微服务(Spring Cloud):https://gitee.com/thinkgem/jeesite4-cloud Flowable业务流程引擎(BPM):http://jeesite.com/docs/bpm/ JFlow工作流引擎:https://gitee.com/thinkgem/jeesite4-jflow 多站点内容管理模块(CMS):https://jeesite.com/docs/cms/ 手机端移动端:https://gitee.com/thinkgem/jeesite4-uniapp PC客户端程序:https://gitee.com/thinkgem/jeesite-client Vue3分离版本:https://gitee.com/thinkgem/jeesite-vue JeeSite统一认证:https://jeesite.com/docs/oauth2-server TopIAM统一认证:https://gitee.com/thinkgem/jeesite-topiam MaxKey统一认证:https://gitee.com/thinkgem/jeesite-maxkey MybatisPlus:https://gitee.com/thinkgem/jeesite-mybatisplus Magic接口快速开发:https://gitee.com/thinkgem/jeesite-magic-api 内外网中间件:https://my.oschina.net/thinkgem/blog/4624519

优秀的个人博客,低调大师

Spring Boot 整合流程引擎 Flowable,so easy!

为啥想写 flowable 呢?原因很简单,因为最近在录的 tienchin 项目视频会用到,先写一篇文章和大家打打预防针,后面视频再细讲。 流程引擎,也算是一个比较常见的工具了,我们在日常的很多开发中都会用到,当然用的最多的就是 OA 系统了,但是在一些非 OA 系统中,我们也会涉及到,比如一个 CRM 中,可能会有合同管理的需求,合同的审批,也是需要流程引擎的。 所以今天我们来简单聊聊流程引擎,顺便写一个简单的例子,小伙伴们一起来感受下流程引擎到底是个啥。 1. 流程引擎介绍 Flowable 是一个使用 Java 编写的轻量级业务流程引擎。Flowable 流程引擎可用于部署 BPMN2.0 流程定义(用于定义流程的行业 XML 标准),创建这些流程定义的流程实例,进行查询,访问运行中或历史的流程实例与相关数据,等等。 Java 领域另一个流程引擎是 Activiti,不过我觉得这两个东西,只要你会使用其中一个,另一个就不在话下。 咱就不废话了,上代码吧。 2. 创建项目 首先我们创建一个 Spring Boot 项目,引入 Web、和 MySQL 驱动两个依赖,如下图: 项目创建成功之后,我们引入 flowable 依赖,如下: <dependency> <groupid>org.flowable</groupid> <artifactid>flowable-spring-boot-starter</artifactid> <version>6.7.2</version> </dependency> 这个会帮我们做一些自动化配置,默认情况下,所以位于 resources/processes 的流程都会被自动部署。 接下来我们在 application.yaml 中配置一下数据库连接信息,当项目启动的时候会自动初始化数据库,将来流程引擎运行时候的数据会被自动持久化到数据库中。 spring: datasource: username: root password: 123 url: jdbc:mysql:///flowable?serverTimezone=Asia/Shanghai&amp;useSSL=false 好啦,配置完成后,我们就可以启动项目了。项目启动成功之后,flowable 数据库中就会自动创建如下这些表,将来流程引擎相关的数据都会自动保存到这些表中。 默认的表比较多,截图只是其中一部分。 3. 画流程图 画流程图算是比较有挑战的一个步骤了,也是流程引擎使用的关键。官方提供了一些流程引擎绘制工具,这个我就不说了,感兴趣的小伙伴可以自行去体验;IDEA 也自带了一个流程可视化的工具,但是特别难用,我这里也就 不说了。 这里说一下我常用的 IDEA 插件 Flowable BPMN visualizer,如下图: 插件怎么安装就不用我教了吧,小伙伴们自行安装即可。 装好插件之后,我们在 resources 目录下新建 processes 目录,这个目录下的流程文件将来会被自动部署。 接下来我们在 processes 目录下,新建一个 BPMN 文件(插件装好了就有这个选项了),如下: 我们来画个请假的流程,就叫做 ask_for_leave.bpmn20.xml,注意最后面的 .bpmn20.xml 是固定后缀。 文件创建出来之后,右键单击,选择 View BPMN(Flowable) Diagram,就打开了可视化页面了,我们就可以来绘制自己的流程图了。 我的请假流程画出来是这样: 员工发起一个请假流程,首先是组长审核,组长审核通过了,就进入到经理审核,经理审核通过了,这个流程就结束了,如果组长审核未通过或者经理审核未通过,则流程给员工发送一个请假失败的通知,流程结束。 我们来看下这个流程对应的 XML 文件,一些流程细节会在 XML 文件中体现出来,如下: <process id="ask_for_leave" name="ask_for_leave" isexecutable="true"> <usertask id="leaveTask" name="请假" flowable:assignee="#{leaveTask}" /> <usertask id="zuzhangTask" name="组长审核" flowable:assignee="#{zuzhangTask}" /> <usertask id="managerTask" name="经理审核" flowable:assignee="#{managerTask}" /> <exclusivegateway id="managerJudgeTask" /> <exclusivegateway id="zuzhangJudeTask" /> <endevent id="endLeave" name="结束" /> <startevent id="startLeave" name="开始" /> <sequenceflow id="flowStart" sourceRef="startLeave" targetRef="leaveTask" /> <sequenceflow id="modeFlow" sourceRef="leaveTask" targetRef="zuzhangTask" /> <sequenceflow id="zuzhang_go" sourceref="zuzhangJudeTask" targetref="managerTask" name="通过"> <conditionexpression xsi:type="tFormalExpression"><![CDATA[${checkResult=='通过'}]]></conditionexpression> </sequenceflow> <sequenceflow id="zuzhang_reject" sourceref="zuzhangJudeTask" targetref="sendMail" name="拒绝"> <conditionexpression xsi:type="tFormalExpression"><![CDATA[${checkResult=='拒绝'}]]></conditionexpression> </sequenceflow> <sequenceflow id="jugdeFlow" sourceRef="managerTask" targetRef="managerJudgeTask" /> <sequenceflow id="flowEnd" name="通过" sourceref="managerJudgeTask" targetref="endLeave"> <conditionexpression xsi:type="tFormalExpression"><![CDATA[${checkResult=='通过'}]]></conditionexpression> </sequenceflow> <sequenceflow id="rejectFlow" name="拒绝" sourceref="managerJudgeTask" targetref="sendMail"> <conditionexpression xsi:type="tFormalExpression"><![CDATA[${checkResult=='拒绝'}]]></conditionexpression> </sequenceflow> <servicetask id="sendMail" flowable:exclusive="true" name="发送失败提示" isForCompensation="true" flowable:class="org.javaboy.flowable.AskForLeaveFail" /> <sequenceflow id="endFlow" sourceRef="sendMail" targetRef="askForLeaveFail" /> <endevent id="askForLeaveFail" name="请假失败" /> <sequenceflow id="zuzhangTask_zuzhangJudeTask" sourceRef="zuzhangTask" targetRef="zuzhangJudeTask" /> </process> 结合 XML 文件我来和大家解释一下这里涉及到的 Flowable 中的组件,我们来看下: <process> : 表示一个完整的工作流程。 <startevent> : 工作流中起点位置,也就是图中的绿色按钮。 <endevent> : 工作流中结束位置,也就是图中的红色按钮。 <usertask> : 代表一个任务审核节点(组长、经理等角色),这个节点上有一个 flowable:assignee 属性,这表示这个节点该由谁来处理,将来在 Java 代码中调用的时候,我们需要指定对应的处理人的 ID 或者其他唯一标记。 <servicetask>:这是服务任务,在具体的实现中,这个任务可以做任何事情。 <exclusivegateway> : 逻辑判断节点,相当于流程图中的菱形框。 <sequenceflow> :链接各个节点的线条,sourceRef 属性表示线的起始节点,targetRef 属性表示线指向的节点,我们图中的线条都属于这种。 流程图这块松哥和大家稍微说一下,咋一看这个图挺复杂很难画,但是实际上只要你认认真真去捋一捋这里边的各个属性,基本上很快就明白到底是怎么一回事,我也相信各位小伙伴都有这样的悟性。 4. 开发接口 接下来我们写几个接口,来体验一把流程引擎。 在正式体验之前,我们先来熟悉几个类,这几个类我们一会写代码会用到。 4.1 Java 类梳理 ProcessDefinition 这个最好理解,就是流程的定义,也就相当于规范,每个 ProcessDefinition 都会有一个 id。 ProcessInstance 这个就是流程的一个实例。简单来说,ProcessDefinition 相当于是类,而 ProcessInstance 则相当于是根据类 new 出来的对象。 Activity Activity 是流程标准规范 BPMN2.0 里面的规范,流程中的每一个步骤都是一个 Activity。 Execution Execution 的含义是流程的执行线路,通过 Execution 可以获得当前 ProcessInstance 当前执行到哪个 Activity了。 Task Task 就是当前要做的工作。 实际上这里涉及到的东西比较多,不过我们今天先整一个简单的例子,所以上面这些知识点暂时够用了。 4.2 查看流程图 在正式开始之前,我们先准备一个接口,用来查看流程图的实时执行情况,这样方便我们查看流程到底执行到哪一步了。 具体的代码如下: @RestController public class HelloController { @Autowired RuntimeService runtimeService; @Autowired TaskService taskService; @Autowired RepositoryService repositoryService; @Autowired ProcessEngine processEngine; @GetMapping("/pic") public void showPic(HttpServletResponse resp, String processId) throws Exception { ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); if (pi == null) { return; } List<execution> executions = runtimeService .createExecutionQuery() .processInstanceId(processId) .list(); List<string> activityIds = new ArrayList&lt;&gt;(); List<string> flows = new ArrayList&lt;&gt;(); for (Execution exe : executions) { List<string> ids = runtimeService.getActiveActivityIds(exe.getId()); activityIds.addAll(ids); } /** * 生成流程图 */ BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId()); ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration(); ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator(); InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0, false); OutputStream out = null; byte[] buf = new byte[1024]; int legth = 0; try { out = resp.getOutputStream(); while ((legth = in.read(buf)) != -1) { out.write(buf, 0, legth); } } finally { if (in != null) { in.close(); } if (out != null) { out.close(); } } } } 这就一个工具,没啥好说的,一会大家看完后面的代码,再回过头来看这个接口,很多地方就都懂了。 4.3 开启一个流程 为了方便,接下来的代码我们都在单元测试中完成。 首先我们来开启一个流程,代码如下: String staffId = "1000"; /** * 开启一个流程 */ @Test void askForLeave() { HashMap<string, object> map = new HashMap&lt;&gt;(); map.put("leaveTask", staffId); ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("ask_for_leave", map); runtimeService.setVariable(processInstance.getId(), "name", "javaboy"); runtimeService.setVariable(processInstance.getId(), "reason", "休息一下"); runtimeService.setVariable(processInstance.getId(), "days", 10); logger.info("创建请假流程 processId:{}", processInstance.getId()); } 首先由员工发起一个请假流程,map 中存放的 leaveTask 是我们在 XML 流程文件中提前定义好的,提前定义好当前这个任务创建之后,该由谁来处理,这里我们是假设由工号为 1000 的员工来发起这样一个请假流程。同时,我们还设置了一些额外信息。ask_for_leave 是我们在 XML 文件中定义的一个 process 的名称。 好啦,现在我们执行这个单元测试方法,执行完成后,控制台会打印出当前这个流程的 id,我们拿着这个 id 去访问 4.2 小节的接口,结果如下: 可以看到,请假用红色的框框起来了,说明当前流程走到了这一步。 4.4 将请求提交给组长 接下来,我们就需要将这个请假流程向后推进一步,将请假事务提交给组长,代码如下: String zuzhangId = "90"; /** * 提交给组长审批 */ @Test void submitToZuzhang() { //员工查找到自己的任务,然后提交给组长审批 List<task> list = taskService.createTaskQuery().taskAssignee(staffId).orderByTaskId().desc().list(); for (Task task : list) { logger.info("任务 ID:{};任务处理人:{};任务是否挂起:{}", task.getId(), task.getAssignee(), task.isSuspended()); Map<string, object> map = new HashMap&lt;&gt;(); //提交给组长的时候,需要指定组长的 id map.put("zuzhangTask", zuzhangId); taskService.complete(task.getId(), map); } } 首先我们利用 staffId 查找到当前员工的 id,进而找到当前员工需要执行的任务,遍历这个任务,调用 taskService.complete 方法将任务提交给组长,注意在 map 中指定组长的 id。 提交完成后,我们再去看流程图片,如下: 可以看到,流程图走到组长审批了。 4.5 组长审批 组长现在有两种选择,同意或者拒绝,同意的代码如下: /** * 组长审批-批准 */ @Test void zuZhangApprove() { List<task> list = taskService.createTaskQuery().taskAssignee(zuzhangId).orderByTaskId().desc().list(); for (Task task : list) { logger.info("组长 {} 在审批 {} 任务", task.getAssignee(), task.getId()); Map<string, object> map = new HashMap&lt;&gt;(); //组长审批的时候,如果是同意,需要指定经理的 id map.put("managerTask", managerId); map.put("checkResult", "通过"); taskService.complete(task.getId(), map); } } 通过组长的 id 查询组长的任务,同意的话,需要指定经理,也就是这个流程下一步该由谁来处理。 拒绝的代码如下: /** * 组长审批-拒绝 */ @Test void zuZhangReject() { List<task> list = taskService.createTaskQuery().taskAssignee(zuzhangId).orderByTaskId().desc().list(); for (Task task : list) { logger.info("组长 {} 在审批 {} 任务", task.getAssignee(), task.getId()); Map<string, object> map = new HashMap&lt;&gt;(); //组长审批的时候,如果是拒绝,就不需要指定经理的 id map.put("checkResult", "拒绝"); taskService.complete(task.getId(), map); } } 拒绝的话,就没那么多事了,直接设置 checkResult 为拒绝即可。 假设这里执行了同意,那么流程图如下: 4.6 经理审批 经理审批和组长审批差不多,只不过经理这里是最后一步了,不需要再指定下一位处理人了,同意的代码如下: /** * 经理审批自己的任务-批准 */ @Test void managerApprove() { List<task> list = taskService.createTaskQuery().taskAssignee(managerId).orderByTaskId().desc().list(); for (Task task : list) { logger.info("经理 {} 在审批 {} 任务", task.getAssignee(), task.getId()); Map<string, object> map = new HashMap&lt;&gt;(); map.put("checkResult", "通过"); taskService.complete(task.getId(), map); } } 拒绝代码如下: /** * 经理审批自己的任务-拒绝 */ @Test void managerReject() { List<task> list = taskService.createTaskQuery().taskAssignee(managerId).orderByTaskId().desc().list(); for (Task task : list) { logger.info("经理 {} 在审批 {} 任务", task.getAssignee(), task.getId()); Map<string, object> map = new HashMap&lt;&gt;(); map.put("checkResult", "拒绝"); taskService.complete(task.getId(), map); } } 4.7 拒绝流程 如果组长拒绝了或者经理拒绝了,我们也有相应的处理方案,首先在 XML 流程文件定义时,如下: <servicetask id="sendMail" flowable:exclusive="true" name="发送失败提示" isForCompensation="true" flowable:class="org.javaboy.flowable.AskForLeaveFail" /> 如果请假被拒绝,会进入到这个 serviceTask,serviceTask 对应的处理类是 org.javaboy.flowable.AskForLeaveFail,该类的代码如下: public class AskForLeaveFail implements JavaDelegate { @Override public void execute(DelegateExecution execution) { System.out.println("请假失败。。。"); } } 也就是请假失败会进入到这个方法中,现在我们就可以在这个方法中该干嘛干嘛了。 5. 小结 好啦,一个简单的请假流程,希望能带小伙伴们入门 flowable,公众后台回复 flowable,获取本文案例。 好啦,后面 tienchin 项目视频中我们再看看这个 flowable 在项目中如何使用:戳戳戳这里-->TienChin 项目配套视频来啦。</string,></task></string,></task></string,></task></string,></task></string,></task></string,></string></string></string></execution></sequenceflow></exclusivegateway></servicetask></usertask></endevent></startevent></process>

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Apache Tomcat

Apache Tomcat

Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。

Eclipse

Eclipse

Eclipse 是一个开放源代码的、基于Java的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。幸运的是,Eclipse 附带了一个标准的插件集,包括Java开发工具(Java Development Kit,JDK)。

JDK

JDK

JDK是 Java 语言的软件开发工具包,主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个java开发的核心,它包含了JAVA的运行环境(JVM+Java系统类库)和JAVA工具。