java 审批流_一文读懂工作流

网上关于工作流引擎有比较多的简介,也有很多工作流的实际应用场景。本文结合笔者多年对工作流的经验来阐述一下对工作流的理解。

一、什么是工作流?

先贴上wiki百科对于工作流的定义

工作流(Workflow),是对工作流程及其各操作步骤之间业务规则的抽象、概括描述。 工作流建模,即将工作流程中的工作如何前后组织在一起的逻辑和规则,在计算机中以恰当的模型表達并对其实施计算。 工作流要解决的主要问题是:为实现某个业务目标,利用计算机在多个参与者之间按某种预定规则自动传递文档、信息或者任务。

那么再简单点说,我认为工作流就是对业务的流程化抽象。WFMC给出了工作流参考模型如下:

c88917513aeaadabe15a224642cf9fdb.png

为什么称之为“流”,则是各个节点通过内外部驱动触发引起节点的推进,形成一个流式的状态达到业务终点。比如一次用户查看淘宝商品的费用、一次支付成功后的权益开通、一次用户注册、一次调度任务的运行等,都是可以是一个工作流。

从代码层面上来说,工作流是对业务逻辑代码的按照指定的流程格式化。即原来可以用代码直接完成的任务流程,借助工作流工具来进行标准格式化、视图化。

另外要提一点,工作流本身是一种工程化的设计思想,在特定场景下,也是一种业务的实现方式。对于狭义的通用工程来说,工作流只是一种设计模式,或者说思维方式,不涉及任何的具体编码,即所有业务代码还是需要人工完成,只是用工作流的方式来规划和编排代码运行方式。而对于某些垂直的业务,工作流本身就是业务实现的具体方式,比如审批流的配置,可以直接通过工作流引擎的方式,直接实现配置化编排业务。

3586b23d4f54d30352ae96c33ed128c3.png

现在业务都趋于融合,所以很多工作流提供了默认的实现,也提供了自定义的实现。比如阿里巴巴旗下的业务【宜搭】就宣称“0代码搭建应用”。宜搭本身就是一种用工作流的思维提供的应用搭建平台。

二、什么是工作流引擎

1、工作流引擎

我们明白为什么需要工作流以及什么是工作流的定义。那么工作流引擎则是实现驱动工作流的一套实现工具。工作流本质上是业务流的抽象,因此不同分类的业务流则形成了不同的工作流,进而有不同的工作流引擎来负责对不同类别的工作流进行具体的定义和实现。

工作流设计器,我们常说的工作流引擎,一般都包括设计器的能力,即负责对业务流程的拖拽式工具, 有插件式也有WEB云端式的。

比如我们上述的审批流,则是一种特殊的工作流,该业务流程的特点,就是需要较多的人工介入参与同意/拒绝的操作。

因此实现审批流的引擎提供的图形化配置能力,并且具备和组织用户直接关联的功能及调用外部服务的能力。

849941b24bf9113ba161c785654f29c5.png

上面三张分别是一个工作流引擎的插件视图、XML源码和编译生成的运行代码,可以看到通引擎,可以把视图解析成一套简单的可执行代码框架,帮助编排我们自己实现所需要的业务BEAN。

通用型的工作流引擎,比较知名的有jBPM5与Activiti,阿里巴巴集团则使用tbbpm多一些。下面是国外对于常用的开源的工作流引擎的一个对比。

4ef0689f0e4acbec6b8e535ab7ecc10a.png

注1:对比数据来自:https://workflowengine.io/blog/java-workflow-engines-comparison/

2、tbbpm和activiti对比

a776e1e139d646a7bb4ede1ae8b5d2e1.png

市面上比较知名的开源工作流引擎有jbpm和acitivi。

三、为什么需要工作流

相信大家都了解流水线的好处,蒸汽时代就是将手工化转变成了流水线化,手工有明显的一个缺点,就是生产效率极低,而流水线则可以提高生成效率。

那么工作流则是将业务流水线化,从原来的一团处理逻辑清晰的划分成为若干个步骤,每个步骤流转清晰明显。每个模块有非常高的内聚,模块之前有非常清晰的依赖。

外网最高的工作流的优点回答如下:
Workflows can help streamline and automate repeatable business tasks, minimizing room for errors and increasing overall efficiency. This, in turn, dramatically improves your business. Managers can make quicker, smarter decisions and employees are empowered to collaborate in a more productive and agile way.

举个例子,退款本身非常复杂,运营、产品、技术、财务可能都无法从单一的角色来解释清楚到底退款的整个链路和关键环节,但是通过工作流的方式来呈现,则所有人能快速看到退款到底是个什么样的业务。

根据实际业务中对工作流的大量使用,我们总结出工作流有以下的优点:

1、业务可视化

首先,最大的优点,就是可以借助工作流引擎,让业务可视化,可以通过视图看到整个业务流程,每个节点执行什么业务逻辑一目了然,分支处理、异常处理也非常清晰。

da1c66c29722261c734ba6a0bad7a474.png

如上述工作流,你一眼就看到,退款成功后该处理哪些事情。业务懂了,自然写代码也就更快了。

2、业务可编排

如果业务永远不变化,那么我们硬编码在一个方法里也无所谓。但是我们知道业务千变万化的,软件设计很重要的一个指标就是灵活可扩展。工作流流程的重编排,则可以使得业务进一步在代码层面增加灵活性。可以通过节点的调整来快速调整业务流程,可以灵活增删节点,而不至于对整个流程有影响。

还是以上面的为例,如果要增加一个【关闭用户权益】的节点,或者删除【用户消息】,那么我们很容易利用工作流增删原有流程。这里实现了代码可维护里最核心的两点:

改动代码最简单和改动代码最快

3、自动重试

对于某些工作流来说,工作流引擎提供了框架层面持久化和自动重试的能力。

77c496bbdfc2c2b08af253974bdd7f8a.png

上述是实际交易生产系统接收支付宝支付成功后回调后要处理的异步流程。而且在业务变化时,还需要对流程里动态增删业务功能。由于像【优惠券处理】或者【活动处理】节点依赖条件较多,很可能会处理失败需要重试,但是又不想把所有节点重试一遍,此时工作流引擎的持久化和节点重试能力,则是非常完美的方案。

四、工作流使用场景

那么适合用工作流的业务有什么特点?

1、领域业务高复杂度

对于偏向业务系统的逻辑,并且具备一定的领域专业性,比如进销存、CRM、订单管理等具备一定的领域复杂度的业务,可以用工作流模式,来实现业务的可视化。从全局的业务视角来观察整体系统架构,而不至于在代码大山面前无从下手。

2、多节点、长链路

比如询价需要经过加载用户信息、加载商品、加载优惠、计费等多个节点,每个节点都相对独立。此类业务就比较适合用无状态的内存工作流。

3、状态持久化和自动重试

对于异步的调度流程,例如订单支付成功后,驱动下游业务系统开通、发送用户提醒消息、扣减库存等异步流程节点,需要持久化每个节点的执行状态,同时在流程失败的情况下系统框架能进行重试恢复。

五、工作流分类

那么工作流该如何分类,如何抽象和归类自身的业务?这是一个首要问题,从经验上来看,我们把工作流按照业务特性分成了以下几类:

1、内存工作流

4e065f20f7f794130f5e171f718b9f21.png

内存工作流是最近简单的一类工作流,该类工作流无需持久化,无需状态,在内存调用完成即可。这种工作流也表示业务本身无状态、无需持久化的。比如用户的一次询价行为,用户到详情页查看价格和库存,对于后端来说是一个非常复杂的调用流程,因此会把这一次调用抽象成工作流。

8d9be2ca4915a32a679829462fd204bd.png

此类流程用硬编码的方式也能很好的实现,但是用工作流的方式,则会使得业务可视化,从视图上就能快速的看出业务是如何运转的,有哪些分支等。同时也使的每个节点能够最大程度的复用。

2、状态机工作流

fa782ddf91cb8e01b3b706c25c952193.png

当我们需要记录每个节点是否执行成功,并且具备系统自动重试的时候,我们就需要状态机工作流。状态机是在内存工作流的基础上,增加每个节点状态持久化,并增加重试机制。

我们以一个工作流为例,状态机工作流的一个实例,即对应一个业务上产的流程实例,对应在market_bpm_statemachine_instance的一条记录。

23d1eed9239d8c976a972ec94e38efae.png

在一条实例里,记录当前处理节点[current_node]、当前处理状态[status]、当前节点重试次数[retry_times]、当前节点处理异常信息[error_message]以及业务主键ID[biz_id]。

当某个节点处理失败后,节点置为异常状态,工作流调度模块会捞取失败的节点继续按照工作流预定义的流程重试, 直到重试到指定的配置次数后,将整个流程置为执行失败,此时需要人工介入。

另外,一般的工作流引擎提供了默认集成的调度框架,我们也可以自己采用第三方的调度工具,只要使用IStateMachineQueryService框架内置的接口查询出待执行的数据即可。

3、人工工作流

4b795ed61d64989226643c71fd2b4e69.png

人工工作流,又可以认为是外部触发驱动工作流,至少是存在一个或者多个节点是待外部确认才能推进整体业务流程。

和状态机相比,人工工作流多了外部触发的功能。为某一些需要外部触发的业务提供了很好的支持,比如业务流程依赖审批的,比如退款流程,需要负责人审批通过后才能进行打款;比如报销打款,需要财务审批成功后,才能对报销单进行打款核销;还有一些物流流程,用户确认到货后,驱动流程继续往下走,比如提供售后服务、关闭物流单等。

以工作流为例,人工工作流的设计会稍微复杂一些,分了多个表,每个表我简介一下其意义

bpm_workflow_instance : 工作流实例表,表示一个具体执行的业务流 bpm_task_instance : 任务实例,将工作流的每个节点当做一个任务实例存储下来,描述一个工作流实例里 每个节点的具体状态 bpm_param_instance : 参数实例,工作流或者任务实例的上下文入参快照 bpm_timer_task:处理定时任务表,比如人工节点未审批自动超期等 bpm_sequence :生成上述四个表的主键ID表

可以看到和状态机相比,人工工作流多了对每个任务的流式快照以及定时功能,主要是解决人工等外部触发的自动、超期等问题。

六、工作流设计准则

我们可以认为,对于复杂流式业务,面向工作流编程是一个思路,也是一个基本设计理念和方向。如何面向工作流设计?如何让工作流更好的辅助业务编排和业务推进,则是一个需要认真思考的话题。

1、流程抽象

首要的工作,就是要把业务抽象流程化。即将业务用精简的流程图的方式展现出来。对业务的深刻理解,才能抽象出业务流程,包括业务链路、关键节点和分支、异常和重试逻辑、是否需要持久化、是否需要外部输入信息。

这个环节实际上就是领域驱动设计里的,成为领域专家或者和领域业务专家对焦业务的重要部分,即深入业务,读出业务真正的核心流程、异常流程、分支流程以及容错流程。

f93ad6fb01844911288d585cc4d3ab7f.png

86567e47abd0737a76665c8a1a63ab46.png

这里需要对业务流程多问几个问题,比如询价流程里,商品加载不到怎么处理?退款流程里等待ISV确认同意退款,如果ISV一直没有同意怎么办?报销流程里,审批单提交了财务人员离职了怎么办?这些问题都思考清楚了,对整体业务流程也就有了一个全面的认识,才能清楚的定义真正的业务流程和业务流程闭环。

另外,根据业务类型,选择是否需要持久化节点,比如用户询价、查看商品详情等只读业务,则直接采用内存式工作流;如果有持久化重试需求,比如处理支付回调消息,驱动开通用户权益,当流程处理失败,必须保存当前的流程快照并且需要进行重试补偿,则可以选用状态机工作流。当需要有外部用户触发,例如用户审批等人工节点参与,则可以使用人工工作流。

画出最优的业务流程图,是工作流设计中的首要,也是最重要的一个步骤。

2、流程编排

完成业务流程产出后,就要利用工作流引擎工具提供的功能,对业务流进行具体的实现,即“流程编排”。流程编排包括几部分:画出工作流图、工作流配置等。

如上述的退款业务,首先需要将业务流程化编排,抽象出核心的关键节点,比如【退订判断】,判断是否符合退款条件,其次【更新订单】将订单更新为退款申请中,给用户一个良好的体验,然后将【订购置为退款中】,防止退款期间系统产生新的订单,然后【汇金申请退订】向底层交易发起退款申请,根据底层返回成功和失败分别做【订单订购恢复】的回滚操作以及【保存退款申请】的结束动作。

编排需要判断哪些是自动节点,哪些需要用判断节点,调用失败如何处理等。就理论上而言,每个节点都可能执行失败,即每个节点都可以做成判断节点,但是这样的缺点很明显,主要链路不清晰,分支非常多,即大家会额外的去关注节点失败的分支,尽管实际上可能无需单独关注异常分支。

e7e2ffd3930cfc69e6137700959b6416.png

如上图所示,同样的一个流程,可以有两种编排的方法,进而也导致了接口有着不同的设计。那么到底如何编排节点是最优的?有个约定的标准:

以业务流程判断为分支节点,屏蔽系统或非预期的业务异常分支,系统或非预期的业务异常在工作流框架外统一处理

即以上述退款为例,调用订单更新在正常情况下理论上应该一定是成功的,因此无需设计成判断节点,可以直接设置成自动节点,当该接口发生不在预期的异常时,可以直接throw系统异常,直接在节点外进行捕获处理。具体参考“异常处理”步骤的推荐做法。

3、接口设计

面向工作流的接口设计原则,首先满足接口本身的设计原则“高内聚低耦合”。为了满足节点工作流的复用性,接口尽量要保持基本入参,而不要使用复杂对象或者弱类型的MAP入参。

    /**      * 订单置为退款中(一个不好的设计,中间的一个节点,入参采用了复杂上下文请求ProdRefundApplyRequest,其他业务无法复用)      * @return     */     
ServiceResult<Boolean> updateOrderRefunding(ProdRefundApplyRequest     prodRefundApplyRequest);

上述接口则抽象度不够,导致调用困难(组装ProdRefundApplyRequest上下文复杂),复用困难(其他业务可能不包含ProdRefundApplyRequest内的字段或者属性)。

/**      * isv 确认(一个好的设计,中间的一个节点,入参采用了基本的入参,其他节点和业务可以快速复用)      *      
* @param mainOrderId 退款主订单      
* @param opUid       
操作人uid      
* @param orgId       操作人的组织id      
* @return      * @throws ServiceException      
*/     
Boolean confirmByProvider(Long mainOrderId, Long orgId,      Long opUid) throws ServiceException;

4、异常处理

如何统一处理工作流中的异常?一般的工作流引擎工具中就设计了对异常的统一处理方式。但是还是需要接口设计本身对异常加以处理,避免对于异常的处理不合理,导致流程难以理解和捕捉。

5d35dcc69b15f05e12aab820318bfce4.png

上图就是一个较为通用的处理办法,工作流本身不处理业务异常,业务异常统一上抛至应用层处理。另外捕获Exception,防止工作流本身产生的任何异常(如果工作流已经处理,则可以忽略)。

统一处理异常的优点是可以统一工作流节点错误实现方式,还可以打印错误提醒日志,方便快速定位工作流运行期间产生的异常问题。

七、总结与思考

工作流提供了一种很好的工程化的方式来解决业务问题,使得业务抽象、流程格式化、易维护和易拓展,一定程度的业务可视化。

从工程上来说,通用工作流即是一块可同步执行或异步执行的代码块上,增加了格式化和视图化。

当然,工作流设计模式也不是放之四海皆准。引入工作流本身会增加工程难度,特别是目前没有一个非常极致体验的工作流引擎的情况下。就笔者来说,常用的tbbpm就存在较多的问题,比如图形拖拽不美观、上下文变量设置麻烦、容易出异常未知问题。另外对于一些简单的业务逻辑,几段代码搞定的,也无需考虑使用工作流。

工作流用的好的话,也是对整体业务思维逻辑的体现。工作流能划清楚,至少业务已经懂了,剩下的只是撸码问题,而撸码是最简单的。就好比一个算法题,设计算法是最难的,具体代码实现则降低了一个数量级,当然,编程功底不过关的另说。

工作流用得好,从另外一个角度来说,业务可维护、业务可视化,对后来者学习和维护的成本都很低。基本上来说,用工作流设计的逻辑,很少出现翔一样的不可维护,想打人的代码。

工作流用的好,整个流程具备闭环,具有很强的容错性。异常分支的考虑、错误节点的重试、异常节点告警、节点持久化、超时节点配置,系统就具备很强的鲁棒性了。

工作流用的好,当然,下班就会更早。

总而言之,只要符合复杂领域多节点长链路的业务,都可以采用工作流的方式,至少,可以使用工作流的思考方式。

关注我,交流更多工作流

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/532186.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

postgresql 查询序列_时间序列数据库(TSDB)初识与选择

作者&#xff1a;码哥字节 如需转载联系我的公众号背景 这两年互联网行业掀着一股新风&#xff0c;总是听着各种高大上的新名词。大数据、人工智能、物联网、机器学习、商业智能、智能预警啊等等。以前的系统&#xff0c;做数据可视化&#xff0c;信息管理&#xff0c;流程控制…

concurrenthashmap实现原理_Mybatis:PageHelper分页插件源码及原理剖析

PageHelper是一款好用的开源免费的Mybatis第三方物理分页插件&#xff0c;其实我并不想加上好用两个字&#xff0c;但是为了表扬插件作者开源免费的崇高精神&#xff0c;我毫不犹豫的加上了好用一词作为赞美。原本以为分页插件&#xff0c;应该是很简单的&#xff0c;然而PageH…

计算机网络dst,计算机网络基础课程—Socket接口

什么是TCP/IP------本课程的主要部分TCP/IP如何工作-----TCP/IP软件结构与实现如何用TCP/IP-------TCP/IP应用程序编程接口前面说过&#xff0c;TCP/IP标准并不指定应用程序与TCP/IP协议软件的接口&#xff0c;但并不是说没有提供任何指导&#xff0c;首先&#xff0c;它指定了…

python输入圆的半径公式_[图文]铁路曲线正矢的计算公式

一、圆曲线正矢的计算1.1 圆曲线正矢的计算公式取圆曲线上两点拉一直线,叫做弦。弦上任意点至曲线上的垂直距离叫矢或叫矢距。在弦中央点的矢距叫正矢(下图)。AB一弦;AC、CB一半弦;CD一正矢;EF一矢距正矢计算公式为其中: f-正矢 C-弦长 R-半径 式中单位均为m。公式用文字表示即…

docker 安装nacos_康过来!Nacos配置和管理微服务的使用

Nacos 具有如下特性:服务发现和服务健康监测&#xff1a;支持基于DNS和基于RPC的服务发现&#xff0c;支持对服务的实时的健康检查&#xff0c;阻止向不健康的主机或服务实例发送请求&#xff1b;动态配置服务&#xff1a;动态配置服务可以让您以中心化、外部化和动态化的方式管…

matlab中如何调用gpu进行并行计算_极致安卓-Termux/Aid learning开启WebGL手机GPU并行计算...

在我的之前的测评中&#xff0c;我利用Termux和Aid Learning测试过基于C/C的openmp并行程序&#xff0c;基于Java的并行程序&#xff0c;还有基于MPI以及基于Java的分布式集群并行。但是很遗憾&#xff0c;一直无法成功开发基于OpenCL的GPU并行编程。这是主要是因为Android并没…

python默认编码方式_关于设置python默认编码方式的问题

2019-8-27 07:45:36 本帖最后由 傻纸 于 2019-8-27 10:02 编辑 查了一会资料得出的结论是如果你用的是python3.x&#xff0c;那么就最好别去设置sys.defaultencoding或者sys.stdout.encoding 记住在需要编码的时候用encode&#xff0c;解码的时候decode就可以了。。。 这个问题…

计算机科学与技术是属于什么学科,计算机科学与技术专业属于什么大类 属于哪个学科...

近日&#xff0c;有很多人咨询小编计算机科学与技术专业属于什么大类 属于哪个学科&#xff1f;现在小编统一回复一下大家计算机科学与技术专业属于工学类&#xff0c;下面是关于计算机科学与技术专业详细的介绍。1计算机科学与技术专业门类及学科介绍专业名称专业代码门类学科…

matlab imread_MATLAB图像处理:29:在几何变换输出中指定填充值

本示例说明如何指定imwarp执行几何变换时使用的填充值。执行转换时&#xff0c;输出图像中通常会有一些像素不属于原始输入图像。必须为这些像素分配一些值&#xff0c;称为填充值。默认情况下&#xff0c;imwarp将这些像素设置为零&#xff0c;并显示为黑色。使用FillValues参…

micopython 18b20_MicroPython控制8*8LED点阵显示温度

MicroPython顾名思义就是可以在单片机上跑的Python&#xff0c;借助Micro Python&#xff0c;用户完全可以通过Python脚本语言实现硬件底层的访问和控制&#xff0c;比如说控制LED灯泡、LCD显示器、读取电压、控制电机、访问SD卡等。目前支持MicroPython的开发板有好几种&#…

ip变更会影响账号登陆吗_【教程】PUBG账号被盗导致封禁申诉解封教程

很多朋友询问PUBG在被盗号后被盗号者开挂导致永封该如何申诉解封&#xff0c;现在结合一些玩家被盗号及成功申诉的经历&#xff0c;详列一下步骤。本方法只适用于被盗后开挂导致封禁的账号&#xff0c;那些自己开挂被封的孤儿不用往下看了。一.先向steam客服申诉 找回自己的ste…

滤镜怎么调_手机、电脑怎么剪辑视频?真心求推荐实用工具

自从加入了短视频自媒体运营这个行业以后&#xff0c;我就开始接触到各种各样的手机、电脑视频剪辑、制作软件&#xff0c;用它们来处理、完成被安排到的工作任务。很多时候&#xff0c;我也用它们来剪视频&#xff0c;借此来练练手、积累下素材。记得刚进入这个行业的时候&…

2021计算机基础知识题库,2021~2021计算机基础知识练习题

2021~2021计算机基础知识练习题 2021~2021计算机基础知识练习题 北京联合大学 2021~2021计算机基础知识练习题 一、选择题 1.记录在存储介质上的一组相关信息的集合称为______。 A)程序 B)磁盘 C)软件 D)文件 2.当一个文件更名后&#xff0c;文件的内容会______。 A)完全消失 B…

计算机背板知识,你知道背板的选购技巧吗?

原标题&#xff1a;你知道背板的选购技巧吗&#xff1f;背板就是母板&#xff0c;子板插在上面构成系统&#xff0c;计算机背板说成背板也成立&#xff0c;只不过背板更多的知识线路板而已&#xff0c;没有实际的器件&#xff0c;只起信号通路作用。背板在设备机箱的后面。一般…

git 切换分支_git 入门教程之分支总览

分支就是一条独立的时间线,既有分支,必有主干,正如一棵树谈到树枝,必有树干一样的道理.我们先前对git 的全部操作默认都是在主干上进行的,这个主干也是一种特殊的分支,名为 master 分支.无论是穿越历史还是撤销更改,我们都或多或少接触过时间线,git 管理的版本串在一起就组成了…

正在锁定计算机 win7转圈圈打不开,Win7网络连接图标一直转圈的原因和解决方法...

Win7网络连接图标一直转圈是什么情况&#xff1f;如果用户发现Win7系统中的网络图标一直处在转圈状态&#xff0c;则表示该网络不能正常加载&#xff0c;且无法识别&#xff0c;笔者通过检查发现网络依赖的服务Network List Service没有自动启动&#xff0c;启动之后可解决该问…

jvm内存模型和java内存模型_JVM运行时内存模型综述

JVM内存模型JVM分为五个区域&#xff1a;虚拟机栈、本地方法栈、方法区、堆、程序计数器。JVM不同区域的占用内存大小不同&#xff0c;一般情况下堆最大&#xff0c;程序计数器较小。JVM五个区中虚拟机栈、本地方法栈、程序计数器为线程私有&#xff0c;方法区和堆为线程共享区…

getline没有与参数列表匹配的重载函数_C++新增基础功能解析—函数重载功能的使用...

喜欢的可以收藏转发加关注“函数重载”指的是可以有多个同名的函数&#xff0c;因此 名称进行了重载。这两个术语指的是同一回事&#xff0c;但我们通常使用函数重载。可以通过函数重载来设计• 系列函数——它们完成相同的工作&#xff0c;但使用不同的参数列表。重载函数就像…

公关文秘专业要学计算机,文秘相关专业有哪些

文秘相关专业有哪些引导语&#xff1a;想必大多数人对文秘这个岗位都不陌生&#xff0c;那么与文秘相关专业有哪些呢&#xff1f;接下来是小编为你带来收集整理的文章&#xff0c;欢迎阅读&#xff01;一、中文类专业&#xff1a;中文及相关专业主要包括汉语言文学、汉语言、中…

java seek指针 换行符_Java网络编程探究|乐字节

大家好&#xff0c;我是乐字节小乐&#xff0c;上次给大家讲述了Java中的IO流之输出流|乐字节&#xff0c;本文将会给大家讲述网络编程。主要内容如下&#xff1a;网络 网络分层 IP位置 端口port 网络编程一、 网络 1、概念网络即将不同区域的电脑连接到一起&#xff0c; 组成局…