




已阅读5页,还剩10页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
所有相关的osworkflow的文档大家可以到/space/OSWorkflow处得到,我这里就我的理解,以及对osworkflow文档阅读的心得(绝大部分局限在翻译上,中间参杂个人理解成分)。希望和各位有同样爱好的朋友共同进步。可以通过msn:与我取得联系。下面就开始正文:在此文以及我的后继关于osworkflow的文档中,不会对工作流相关的基本概念进行解释,这些必备的知识还是需要个人自己充电的。Osworkflow与目前绝大多书的工作流系统是不同的,而最大的不同点体现在它的韧性上和灵活程度上,在商业界和开源世界都存在它的影子。最开始大家可能比较难于理解,举个例子:osworkflow并不强制要求您用图形工具来开发工作流,推荐的首选办法是手写xml文件(即手写过程定义的xml文档,而图形工具操作的实质也是操作此xml,图形工具只是给非专业人士如业务分析人员,过程定义人员使用的)。它充分胜任这种整合,就想现存代码和数据库之间整合一样。虽然这样似乎看起来并不太适合进行快速所谓的“即插即用”工作流解决方案,但是osworkflow所提供的解决方案能够提供足够的灵活度来满足一个大型各种应用的所有需求。Osworkflow的韧性: 可以把osworkflow看做一个低层次的工作流实现。在其他工作流系统中像loops和conditions这样的情况可以以图形图标形式展现出来,在osworkflow中必须进行编码。就是说最起码的脚本语言必须来如此设定。所以并不希望非技术人员来修改工作流。尽管一些系统提供了GUI操作来完成简单的工作流编辑,但是这种做法并不是十全十美的,如当这样改变流程后,此工作流周边的应用往往被破坏。所以osworkflow始终认为最好的变更控制办法就是以开发人员(前提:熟知每个变化)来做这些操作。Osworkflow在2.5.0版本就开始支持图形操作(designer),2.6.0和2.7.0做了许多改进。打算在3.0中正式推出。所以现在在使用GUI操作时候还是需要进行一些适当的预防手段的。Osworkflow内部使用的是有限状态机的概念(对于这部分理解不好的,可以参看UML中的状态图部分,就可以有个初步理解)。每个状态都是通过一个step ID和一个状态来共同描述的。一个变迁(从一个状态到另外一个状态)只有在一个action发生的前提下才会被触发。在一个工作流的生命周期中始终会有一个或多个活动的状态。简单的讲就是以工作流引擎和简单xml为基础来完成商务工作流过程处理。先决知识准备部分: Osworkflow包括:Oscore 2.0.1+Propertryset 1.2+Jakarta commons-loggingBeanshell(可选)BSF(可选)EJB接口(并不是一定要在EJB container中)Xml解析(在jdk1.4中并不是必须的)Osworkflow 的api部分将会支持jdk1.3+。GUI designer部分需要1.4的JVM。关于soap和工作调度:GLUE部分(我还没接触过,不敢乱讲,大家看原英文解释部分吧。)大致意思是说如果需要soap或者远程作业调度支持的,就需要下载GLUE专业库。另外还有就是Quartz来支持。如果在应用服务器上run Quartz,那么就经过适当配置就不再需要GLUE了,但是必须把作业调度的local参数设置为true。运行例子: 简单的部署没有什么特别说。仅仅把osworkflow所带的例子拷贝到tomcat(举例)的webapps下就可以了。所带的这个例子不需要配置什么DB,当然也就做不了持久性处理(即所有的所有都没存储到实际数据库中。)当然这并不是实际应用当中所想见到的,这个例子的意义就在于简单的理解osworkflow。对于进行持久数据存储的例子在英文原件中有,我就不复制粘贴过来了。大家自己去看就可以了。具体都是如何修改配置文件,如果tomcat的server.xml文件,以及必要的jar拷贝工作。这些实际应用的例子会在后继文档中也许会有阐述,如果特别简单就不多写这方面东西了。感觉上不会复杂。呵呵_持久存储:Osworkflow共提供了五种存储机制:memorystore(默认)自带的例子就是如此,SerializableStore,JDBCStore,ofbizstore,和EJBStore.如果上述这些都没满足您的要求,那就得自己来实现osworkflow的接口com.opensymphony.workflow.spi.workflows了。具体看api吧。本文只是入门篇,大致知道有这么一回事的。不同的存储实现需要不同的配置设置工作。推荐大家看api(此部分)来完成配置。原文中给出了JDBC的配置例子:请参看原文。工作流定义部分: Osworkflow 尽最大可能使用配置来保证灵活度。仅一个文件osworkflow.xml需要在classpath中。这个文件设置了持久存储的方法(jdbc,ejb,ofbiz),工作流工厂类被用来加载工作流定义内容。默认的工厂是:com.opensymphony.workflow.loader.xmlworkflowfactory。从classpath中加载文件。在测试的时候,更改工作流定义文件然后重新加载它,你可以通过一个reload参数来指定是否完成自动重载。如果想指定自己的工作流定义,需要继承com.opensymphony.workflow.loader.Abstractworkflowfactory。然后剩下的就是你自己的任务了。com.opensymphony.workflow.loader.JDBCWorkflowFactory是一个选择工厂,他允许你存储工作流定义为数据库内容而不是在xml文件中。 一般配置如下: osworkflow.xml: . workflows.xml: 本文结束,谢谢!周日,莫映我们javaparty的伙伴讲了讲osworkflow,估计很多人还是一头雾水。目前国内似乎关注osworkflow的人越来越多,但是却没有多少人去关注其真正值得参考和学习的地方,这是不应该的。OSWorkflow的确非常灵活,但是我们不光需要知道“用的灵活”,还要知道“深层次的东东”。于是才有了这个系列介绍的打算:在阅读此系列之前,请队FSM又算了解,也请先阅读一下这篇文档:/james999/archive/2004/10/29/158653.aspx 我们现在就先从osworkflow的一个实例如何初始化入手:首先OS的Workflow,和我们通常所理解的Engine并不是很一样。在OSWorkflow中没有“Service”的概念,所以每次访问的时候,都可以重新创建一个Workflow对象。我们可以把这个Workflow理解成一个Execute Engine或者Execute Runner。在一个访问请求中,一个Workfow对象负责维护一个流程实例的管理和操作。Workflow workflow = new BasicWorkflow(testuser);DefaultConfiguration config = new DefaultConfiguration();workflow.setConfiguration(config);long workflowId = workflow.initialize(mytest, 1, null);workflow.doAction(workflowId, 1, null);我们先来说说initialize方法,可以边看文档,边阅读osworkflow的AbstractWorkflow类:在你的一个工作流定义文件中,至少是需要定义一个initial action。这些initial action其实就是流程实例的可能运行起点。就如同我们通常说说的start node或者start activity等等。 . . 在initialize方法中,主要是存在四个功能:(1) 创建流程实例对象,在osworkflow中,流程实例对象用WorkflowEntry接口的子类实现(2) 构造临时变量的集合,即transientVars;用于在一个转移过程中临时保持数据状态(3) 获取指定的Action对象(4) 执行这个Action,并造成转移,即transitionWorkflow方法这几个功能中,重中之重,也是OSWorkflow的最为核心的算法,就是最后的转移。在这转移过程中,会执行下面的一系列操作:(这张列表最初是由 莫映 整理,我补充和修改了一些)(01) Get current step(获取当前的Step)(02) Validate transientVars(验证临时变量)(03) Validate inputs(验证输入的数据)如果step不为null(执行初始化action的时候,current step还不存在)(04) Execute post-functions(step-level) (执行step的post function)(05) Execute pre-functions(action-level) (执行action的pre function)(06) Check each conditional results (检查每一个条件的执行结果)(07) Execute pre-functions(result-level) (运行result的pre function)(08) Move current step into history (09) Create new current step(10) Execute pre-functions(step-level)(11) Execute post-functions(result-level)(12) Execute post-functions(action-level)如果是初始化动作(13) Mark the entry state as Activated 如果是结束动作(14) Set the entry state Completed 获取globalActions中可以自动执行的,并执行(15) perform available and auto global actionsOSWorkflow深层讲解系列(二)流程实例的结束之一收藏 下面来说说OSWorkflow流程实例的结束。在workflow pattern中有一种模式:Implicit Termination(隐性终止)。这种模式描述了这样一种情形:活动集中没有任何可以执行(或有可能执行)的活动,此时流程实例已经不能进行任何操作和运转。这个和我们通常所说的死锁,不是一回事情:流程的死锁是表示流程实例依然存在可以运行(或必需运行的)的活动实例,但是由于缺少资源而不能执行某项操作而造成流程实例没有正常运行。这种情况最为典型的就是,某一个出差了,但是没有设置代理,造成任务没有执行。在OSWorkflow支持了Implicit Termination。当然OSWorkflow也支持我们最为常用的设置结束点。先说说OSWorkflow对设置结束点的支持,这个是非常容易的,只需要将Step中的某一个Action的属性finish的值设置为“true”即可。既然这么简单,我为什么还要说呢?既然一个简单东东还拿来说,那就说明这个东东其实不简单。让我们来思考一个问题,OSWorkflow为什么会将finish这个属性放在了Action而不是放在了Step上呢?依据我们通常说理解的:在众多活动节点中,有一个结束节点,这个结束节点表示了流程实例结束的语义。实际上很多工作流引擎都是这么做的,shark,jbpm,yawl等等。这是因为在OSWorkflow的视角中,并没有一个Step这个概念。OSWorkflow真正只有两个视角:State和Action。而step和status只是联合扮演了state的角色。所以在OSWorkflow的执行引擎类中,只有doAction等等操作方法,而没有doStep之类的方法。对于执行引擎来说,其只知道,任何一种状态,都必然意味着是由某种action所引起的变化结果。Action上设置Finish,表示这个Action只要发生,其产生的结果状态就是“Finish”。这是FSM(有限状态机)的基本原则一个Finish状态的产生,就表示整个流程实例的结束。所以想把OSWorkflow的精华理解透彻,就必须在脑海中先暂时放弃“活动”、“结束点”、“起始点”之类的概念。 所以在这里顺便说一句额外的话,OSWorkflow其实并不是非常适合刚刚接触工作流的初学者。刚刚接触工作流的人,个人建议还是先钻研钻研WFMC的一些东东,虽然我们都说XPDL这不好,那不好,其实xpdl之中有很多值得参考的思想。再说说OSWorkflow对Implicit Termination的支持。Osworkflow对隐性终止是很容易的,虽然现实中,我们不会去故意去创造“隐性终止”这种情况,也更不希望这种情况的发生。在OSWorkflow任意一次的action的执行后,如果这个action没有造成流程实例的终结,那么就会去检测是否存在隐性终止的情况存在。public void doAction(long id, int actionId, Map inputs) if (!transitionWorkflow(entry, currentSteps, store, wf, action, transientVars, inputs, ps) checkImplicitFinish(id); /这个id是流程实例idtransitionWorkflow方法我们在第(一)篇中已经有所介绍了,再次就不再叙述。transitionWorkflow返回的结果是这个流程实例是否已经结束。在checkImplicitFinish方法中,主要是遍历当前所有的current step节点(这些current step节点就表示当前处于运行中的活动节点)。如果这些current step都没有被定义action,那么整个流程实例就存在隐性的结束。说道这里就结束了吗?当然不了,因为上面这百来字的短文太简单了,即使我不说,大家一看代码就会一清二楚。要说就说点让人值得思考的:在OSWorkflow中,几乎所有的status都是外界定义的,就是说你可以定义自己的status,然后再workflow.xml中指明某个action的结果造成另一个step的某种status。只有一处地方状态是osworkflow自己所约束的,就是action中的finish状态。osworkflow本身并不知道这些status本身所代表的具体含义。虽然osworkflow提供了几个status的定义参考,比如finish,queue等等。但是这些对osworkflow引擎来说,并没有实际的意义。所以在OSWorkflow的隐性终止判断中,就存在一个值得回味的地方。这个时候,我们在回过头来看看OSWorkflow的checkImplicitFinish方法:其回遍历所有的current step,并且依据每一个step的定义来判断(注意采用的是定义,而非step实例)。依据每一个current step是否存在action来判断。乍一看,可能很多人会认为这种判断是存在漏洞的:如某个step还在运行怎么办(这个step没有定义action)。 这就是值得回味的地方。在osworkflow中,你即使在同一个step中,想从一个status到另一种status,也必须定义action。如果这个step不存在action,那说明什么呢?就说明这个step的状态根本就不允许更改,既然不允许更改,那么这个step的实例也就没有任何运行的意义。 OSWorkflow的隐性终止的判断原则也就这么出来了。我一直都说OSWorkflow是遵循FSM的,那么是在什么地方遵循呢?就是在这些判断规则和原则上一点一滴的遵循。对于OSWorkflow来说那些,function,conditon只是一个外设。OSWorkflow讲解系列(三)Function与workitem收藏 接下来说说,如何利用OSWorkflow的function进行任务的分配: OSWorkflow是只是一个workflow engine的内核体。我们都说osworkflow非常的易扩展,但是这也同样说明了,用osworkflow去实现一个能够运行的工作流系统是非常繁琐的事情。繁琐并不是难,因为你要想实现一个流程,不得不自己去实现大量的condition和function。既然说到工作流,那么肯定会涉及到“任务交给谁做”的问题。但是OSWorkflow压根就没有管这种需求,对于其来说,其提供了c和f,如果再有什么额外的需求和功能,那么就扩展condition或function。于是,你不得不扩展一些function类去处理“角色”“任务分配”“提交任务”等等诸如此类的操作。在我的标题中提到了workitem,这个概念几乎在其他工作流引擎都有所体现,但是对osworkflow来说,这是一个空白区域。至于workitem的含义,请参考wfmc的Terminology & Glossary。OSWorkflow引擎只负责了“流程的运转”,当然这个运转会根据你所定义的Action和condtion来判断。Funtion对osworkflow来说,只是step、action、result执行过程需要调用的功能,至于这个功能作什么,OSWorkflow并不关心,引擎只是负责提供几个参数接口。public interface FunctionProvider public void execute(Map transientVars, Map args, PropertySet ps) throws WorkflowException;所有的Function实现类都必须实现这个FunctionProvider接口中execute方法,而且能够处理的信息,也全部来自这个方法中的三个参数:transientVars这个是最为核心的参数,记录非常重要的一些对象,比如WorkflowContext,WorkflowEntry,输入参数等等。args这个是function配置中的arg参数,具体请参考osworkflow dtdps是PropertySet对象,记录了流程实例所需要保存的数据,可以理解成osworkflow所描述的流程相关数据。 具体transienVars中包含哪些对象,请参考 FunctionProvider api doc。下面就说说如何利用Function进行任务的分配。个人建议你在Step的pre-function中做处理,配置如下: nucleus.assign.AssignmentFunction A role 22 看了这个配置形式,我想大家应该明白如何去处理。你可以在function中获取自己所定义的角色、根据角色获取人员、根据人员产生workitem 。你在function 所作的这一切操作对osworkflow engine来说都是透明的 你所产生的worklist所代表的含义只有你自己知道。其中我为什么会附加了一个arg属性:actionID?这是因为我需要告诉每一个workitem在其应该处理哪一个动作。 因为外部程序都是通过Workflow.doAction(long, int, java.util.Map) 这个接口来激活流程的运转或改变实例的状态。总体来说,利用osworkflow去实现一个完整的工作流例子,还是比较麻烦的。主要是要扩展和自己实现的太多。/*Author: Meanson Wang *Date: 2005-01-15*Email: */OSWORKFLOW-如何设置Osworkflow的日志及将级别设为DEBUG工作流OSWORKFLOW使用的是Commons-logging组件来进行日志管理。但默认的日志级别是【DEBUG】,虽然HANI的手册中提到【注意,是提到】了设置日志的方法,却并不怎么灵光。看他的MAIL LIST,也是爱理不理,到也是,不喜欢写手册是每个程序员的通病,更别提手把手教你如何配置他的软件啦,“一点技术成分都没有”。呵呵。其实很简单,了解了Commons-logging就一了百了。Commons-logging最强的地方就是,它可以使用多个日志组件来记录日志,自动搜索你的【CLASSPATH】的日志组件,顺序是 log4j - jdk1.4 logging api - jakarta commons - logging SimpleLog,换句话说,你的系统可以用以上任何一种日志组件来进行日志记录。很多余?如果你的产品A用LOG4J,而产品B用logging api,老板让你把A嵌入到B里,你就不必那么头痛啦。你可以用/WEB-INF/classes/perties来指定本系统的LOG组件:log4j:mons.logging.Log=mons.logging.impl.Log4JCategoryLogJDK 1.4 Lmons.logging.Log=mons.logging.impl.Jdk14LoggerJCL SimpleLmons.logging.Log=mons.logging.impl.SimpleLog呵呵在这里我们入正题啦。其实要DEBUG OSWORKFLOW很简单的。就两步,我们的目标是用log4j来管理日志:1.将log4j-1.2.8.jar放到WEB-INFlib里。2.在/WEB-INF/classes/建立perties和perties文件。【perties文件内容:指定用log4j】mons.logging.Log=mons.logging.impl.Log4JCategoryLog【perties文件内容:配置log4j】log4j.rootCategory=DEBUG, stdout, Rlog4j.appender.stdout=org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.layout=org.apache.log4j.PatternLayoutlog4j. 先说点题外话:如果各位哪位转载我的文章,非常欢迎,但请把出处写上!谢谢!欢迎讨论:msn:Osworkflow内置表结构(以mysql的表结构为例),具体需要参看其建表的sql语句,如字段类型、长度等,我在这里做一些必要的分析说明,如果你能够认真看,相信你可以看得懂。经过自己的实践摸索,认为各个表以及表中字段含义如下,从简单的说起: 1、 OS_GROUP:组结构表,如例子中分了bars、bazs、foos三个组。存储在该表的GROUPNAME字段内。2、 OS_USER:用户表,USERNAME字段存储用户名,PASSWORDHASH是经过加密过的密码。3、 OS_MEMBERSHIP:用户与组的关系表,USERNAME字段存储用户名,GROUPNAME字段存储组名,表示用户与组之间的关系。4、 表名:OS_CURRENTSTEP(正在执行的流程信息)列名说明约束ID主键ENTRY_ID当前执行的工作流的ENTRYID,即如约束所写OS_WFENTRY表的ID为其外键STEP_ID当前执行的STEPIDACTION_ID当前执行的ACTIONIDOWNER需要执行的用户OS_USER表的USERNAME为其外键START_DATE开始时间精确到秒,在初始化工作时候此值被设置。FINISH_DATE结束时间DUE_DATE 这个还不清楚,(猜测是trigger设置的日期,有谁知道请告诉我谢谢!)STATUS当前正在实现的step中的具体statusCALLER实际执行的用户OS_USER表的USERNAME为其外键5、 表名:OS_CURRENTSTEP_PREV(合成主键)如split过程,ID为2,3。PREVIOUS_ID都记录为1。则表示是由1分出2,3;此表实时变化,如一2分支执行完毕,那么就将此条记录删除。列名说明约束ID记录当前正在执行的IDOS_CURRENTSTEP的ID为其外键PREVIOUS_ID记录由哪个ID产生的当前正正在执行的信息OS_HISTORYSTEP的ID为其外键6、 表名:OS_HISTORYSTEP(此表结构与OS_CURRENTSTEP相同,说明也相同)只是这个表代表的已经被执行过的。列名说明约束ID主键ENTRY_IDOS_WFENTRY表的ID为其外键STEP_IDACTION_IDOWNEROS_USER表的USERNAME为其外键START_DATEFINISH_DATEDUE_DATESTATUSCALLEROS_USER表的USERNAME为其外键7、 表名:OS_HISTORYSTEP_PREV(联合主键)(记录历史记录表OS_HISTORYSTEP之间的关系,如都执行的1,2。但是2是由1引起发生的。那么ID为2,PREVIOUS_ID为1)列名说明约束ID历史记录中的被引发的IDOS_HISTORYSTEP(ID)PREVIOUS_ID历史记录中的主引发的IDOS_HISTORYSTEP(ID)8、 表名:OS_PROPERTYENTRY(GLOBAL_KEY, ITEM_KEY联合主键)存储propertyset的值列名说明GLOBAL_KEY这个值是在JDBCWorkflowStore类的public PropertySet getPropertySet(long entryId) HashMap args = new HashMap(1); args.put(globalKey, osff_ + entryId); return PropertySetManager.getInstance(jdbc, args); 赋值的。 规则如上面代码。Osff+entryid。 ITEM_KEYKey值,propertyset(“即为key”,)ITEM_TYPE具体参见pertyset包内properties里的各种value-type。存储对应的数字STRING_VALUEString值DATE_VALUEDateDATA_VALUEDataFLOAT_VALUEFloatNUMBER_VALUEnumber9、 表名:OS_STEPIDS列名说明ID主键,自动增量10、名:OS_WFENTRY列名说明ID主键标志NAME工作流名称,如例子中即为exampleSTATECREATED = 0;ACTIVATED = 1;SUSPENDED = 2;KILLED = 3;COMPLETED = 4;UNKNOWN = -1;接口选择:osworkflow提供几种实现com.opensymphony.workflow.Workflow。BasicWorkflow:不提供事务支持,你可以通过持久层来实现事务处理。Workflow wf = new BasicWorkflow(username)这里的username是用来关联当前请求的用户。EJBWorkflow:用ejb容器来管理事务。在ejb-jar.xml中进行配置。Workflow wf = new EJBWorkflow()这里没有必要想basicworkflow和ofbizworkflow那样给出username。因为ejb容器已经校验过的。Ofbizworkflow:与basicworkflow比较相似,不同只在于需要事务支持的方法由ofbiz TransactionUtil calls来包装。创建新的工作流实例:这里是以basicworkflow为例子Workflow wf = new BasicWorkflow(username);HashMap inputs = new HashMap();inputs.put(docTitle, request.getParameter(title);wf.initialize(workflowName, 1, inputs);执行action:Workflow wf = new BasicWorkflow(username);HashMap inputs = new HashMap();inputs.put(docTitle, request.getParameter(title);long id = Long.parseLong(request.getParameter(workflowId);wf.doAction(id, 1, inputs);查询:值得注意的是:并不是所有的 workflow stores支持查询。当前的hibernate,jdbc和内存工作流存储支持查询。Hibernate存储不支持mixed-type查询(如,一个查询使用到了历史和当前step contexts)。为了执行一个查询,需要构造出一个WorkflowExpressionQuery对象。查询方法是在这个对象上被调用的。简单查询、嵌套查询、mixed-context查询(不支持hibernate工作流存储)在docs文档的5.4部分都有。2.7版的osworkflow提供一种配置接口。默认实现是DefaultConfiguration,通过AbstractWorkflow的setconfiguration方法来更改历史遗留的singleton静态模型使其不会被使用。应该避免每次都创建新的工作流实例。遗留部分:Workflow workflow = new BasicWorkflow(blah);long workflowId = workflow.initialize(someflow, 1, new HashMap();workflow.doAction(workflowId, 2, new HashMap();./in some other class, called later onWorkflow workflow = new BasicWorkflow(blah);workflow.doAction(workflowId, 3, new HashMap();推荐方法:Workflow workflow = new BasicWorkflow(blah);Configuration config = new DefaultConfiguration();wo
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025-2030中国左炔诺孕酮片行业消费动态及营销趋势预测报告
- 三叉神经痛课件
- 六级证书面试题库精 编版:不同领域职业能力测试
- 小儿遗传代谢病课件
- 小儿辩日课件
- 大道项目安全文明施工管理工作总结
- 小儿艾条灸课件
- 2025秋新人教版初中英语八上 Unit 5 What a Delicious Meal!单词扩量讲义【增词汇强辨识】
- 大学生毕业实习目的与意义
- 大学生借款合同
- 2025年区块链应用操作员职业技能竞赛理论参考试指导题库500题(含答案)
- 2025年中国移动初级解决方案经理学习考试题库大全-上(单选题)
- DB35T 1951-2020福建省公共机构能耗定额标准
- 医疗机构从业人员规范
- 《研学旅行相关概念与理论基础综述》1900字
- 医院培训课件:《股骨头坏死》
- 保险基础知识简读本(2024版)
- 集团公司司库管理办法
- 住院患儿实施院内转运临床实践指南2023版课件
- 主播新手上路-打造游戏直播与娱乐新风向
- 2024-2025学年中职数学基础模块 下册高教版(2021·十四五)教学设计合集
评论
0/150
提交评论