COM这个单词大家听得不少了它到底是什么它到底有没有实用价值。如果它对我们有用那么在Visual FoxPro怎样编写COM组件。笔者将站在Visual FoxPro开发人员的立场上与大家一起探讨以上问题希望对您有所帮助。可能这是一篇国内很难看到的有关Visual FoxPro与COM的文章所以肤浅、不当之处难以避免我就尽力而为了两年多前我为了一个极其复杂的报表而头疼时偶然想到了Word这一伟大的书写工具——用 Word还有什么写不出的于是我就使用DDE控制Word这实在是一场噩梦无法实现复杂的功能因为我不知道与Word通讯的语法。正当我犯愁之时天赐良机我参加了美国的一个工业ERP的培训那套ERP实际上就是一组用VC写的控制逻辑当时范例中使用VB调用它们。老外告诉我用Delphi、PB都可以调用……它们能行那么Visual FoxPro应该也行尝试之下果然不出所料。我是学VBA出身的水平很差所以我知道Word其实一套组件那么Visual FoxPro与Word的通讯就不成问题了……很快的我写出了一套很棒的专用报表程序我也深深的被COM技术所吸引我知道一个新时代来到了我的第一次COM经历就是这样Visual FoxPro充当COM客户端程序由Word提供相关服务。这种由Visual FoxPro充当COM的客户机控制其他的COM组件在这两年间我做过不少应用如Excel、Power Point、WHSWindows 系统提供的脚本组件、ADO……有时候我甚至会用VB写一个组件供Visual FoxPro调用这种应用常用于API的调用Visual FoxPro不支持结构类型的变量这样调用很多API函数时就发生了极大的困难用VB把相关的API函数重新封装就可以解决问题了。现在我遇到Visual FoxPro不能解决的问题时总是考虑一下操作系统是不是提供相应的COM组件或是有没有第三方的组件可以被调用……COM为Visual FoxPro 带来了什么Visual FoxPro还可以编写COM服务器这种组件可以在其他支持COM的语言里调用实现他们难以实现的功能当然多数是数据库方面的问题。我使用Visual FoxPro的编写COM组件也是因为一个工业控制项目当时工业数据被采集到PC机的客户端时客户希望保存数据到数据库并提供相应的查询、报表功能。这种要求不过分但对于工业控制软件来讲却是有难度的软件分工不同、开发人员各有专长。我知道在过去对于同类的问题基本上有两种方法一种就是用C访问底层的Fox函数库另一种就是外部执行Fox程序。前一种对开发人员的要求很高并且很难实现丰富多彩的功能例如要同时访问SQL Server数据库与DBC怎么办问题多多后一种效果更是不好稳定性太差我看到过不少这样的应用给我的感觉就是老是出错说到这里大家也许明白了COM实际上解决了应用程序的整合您可以在客户不知不觉中使用了好多其他语言的优势很简单的完成任务。从界面效果来说别人看到的还是程序的主界面不会有其他窗口跳出来影响画面从程序的控制来说更有好处有过外部调用exe文件的人都知道很难控制它的运行进程、知道它的运行结果就像“断了线的风筝”——只能由它去了现在有了COM组件您可以完全摆脱这个局面了调用它的方法、设定它的属性、响应它的事件于是它就很听话了就像客户程序自身的一部分。COM的又一个好处就是扩展了Visual FoxPro的应用范围现在我们可以简单的把Fox程序分布到各种场合商业、工业、互联网只要有数据库处理事务的地方与其它系统无缝的集成在一起我做的那个工业应用就是这样。COM技术的还可以为软件开发带来新的思路不同语言的程序员可以在一起工作不同模块可以被做成独立的组件这样更容易维护升级软件时就只要替换部分的组件。这里我想到了国内现在比较流行的软件开发业务——为财务软件做接口很多客户希望自己的MIS系统与财务软件连在一起数据共享。现在的做法是“硬连接数据库直接操作数据”这样很不好——财务数据得不到保全、系统的二次开发变得只有财务软件公司能做因为数据库的结构、业务的记录只有他们清楚。如果财务软件包是一套组件财务软件只是这一组件的实现那么这种二次开发就变得安全、容易了。关于财务软件的评论只是从COM技术的角度出发不考虑其他因素COM的缺陷COM这么好但并非没有缺陷。我认为最主要的是版本问题就是人们常说的“Dll Hell”常用ActiveX控件的人对这种问题一定是有体验的COM也一样。比如控制Word的代码就要很小心Word的版本甚至是语言种类不然的话保不准程序就会出错……COM的另外一个缺点就是COM组件的运行效率主要是在被建立实体对象的时候显得有点慢这个问题我们可以通过“早期绑定”、连接池来解决即使不能很好的改善我认为这个问题也是无关痛痒的毕竟COM的好处太大了……Visual FoxPro 与三层构架按正常的逻辑写COM必定要写三层应用实际上要把Visual FoxPro配置在三层结构的中间层编写COM是唯一的方法但是各位务必明白COM组件并非只能用于三层构架上文我提到的各种应用基本上不属于三层应用的范畴。三层构架把整个软件系统分为用户界面、商业逻辑、数据存储这三个层次。三层构架的特色在于用户界面不直接与数据库打交道所有客户请求都必须通过中间层组件更新到数据库中。这样就有两大好处头一个好处就是商业逻辑代码的统一维护再一条好处就是解决大量用户同时访问数据库的问题。把所有的商业逻辑都写在中间层里这样当商业逻辑变化时就可以之更新中间层的程序对客户界面不产生影响。这是一种理想笔者认为用户界面设计与数据关联性很大大家在设计单层结构、双层结构时应该是有这个体会的怎样的数据源就必须有怎样的界面与之相配三层应用中用户界面与中间层打交道同样界面就必须跟着中间层走如果中间层的商业逻辑明显变化用户界面是不可能不变的。于是代码的统一维护并没有带来各类用户界面相对稳定这样代码的统一维护只是一个诱人的果子吃了也不见得甜。三层结构最诱人的地方在于解决大量用户同时访问数据库的问题。我们知道当前最好的Oracle 数据库可同时支持500个连接不幸的是实践证明当活动连接达到这个数目时数据库服务器往往是承担不起的。500个请求同时访问数据库这在Web领域、在大型企业都是很细松平常的事情。解决之道无非是减轻某一时刻数据库服务器的压力在进一步说就是分配工作到不同的数据库服务器、让客户请求排队等候别一窝蜂的挤到数据库那里这就是动态负载平衡和排队机制那么谁来完成这项工作呢用户界面是理所当然不可能的数据库已经很吃力了当然也不能再麻烦它了只有中间层可以胜任。现在的MTS、COM就是这样的工具Visual FoxPro的组件支持MTS、COM于是将我们的编写的组件放在MTS、COM中运行我们就享用到了MTS、COM的特性一切不需要我们操心。微软为什么强调Visual FoxPro 在Web服务器的应用Web服务组件是最典型的中间层应用它的特色是用户界面通过组件与服务器的交互的次数较少例如在客户端我们查询一批数据中间层得到请求检索数据库返回光标并即时产生HTML文档返回给客户完成后就可以释放组件。同样这个行为在单层、两层应用中可能就很复杂可能我们需要对查询结果进行维护再更新到服务器再刷新光标……Web应用下的数据库强调是的查询——根据复杂的逻辑产生查询结果而对数据的维护不太看中。这就是为什么Web专用数据库MySQL不支持事务处理、存储过程的原因吧……对于这种应用作为专业的数据库开发程序Visual FoxPro可以说是手到擒来、不在话下的开发起来也没有什么难度所以微软强调Visual FoxPro在Web上的应用是很有道理的。还有一种三层应用就是企业级应用它的特点就是利用三层结构实现两层或单层结构下的应用程序同时利用三层构架解决商业代码的维护和大量数据访问的问题。可以想象这种企业级的应用对开发组件的要求是很高在国外往往有专业的公司开发这类组件用户只需根据实际应用做二次开发。据我所知Delphi的第三方产品中就有这样的东西价格异常昂贵比Delphi还贵很多……Visual FoxPro同样也能开发这样的组件只是难度问题……处于商业角度微软不提Visual FoxPro在这方面的应用是有道理的毕竟与其它工具相比我们没有什么优势……Visual FoxPro的COM基础说句实话目前用COM的人很多写COM组件的人很少。我个人只经历过两次实际应用一次上文已经提过了再一次是我的一个朋友做的Delphi做的界面Visual FoxPro开发的数据处理程序很棒的应用以后有机会请他谈谈。由于工作的关系我不使用Fox做开发了以后这种开发机会可能更少撰写此文也是希望广大狐友发挥各自的聪明才智发挥Visual FoxPro的至强威力。愿做抛砖引玉人Visual FoxPro能够编写的组件种类COM是Component Object Model的简写这种技术是建立在面向对象的程序设计思想上的天然的满足多层分布是应用。在Visual FoxPro中我们可以编写两种类型的COM服务器COM Server进程外组件out-of-process和进程内组件(in-process)。进程外组件以Exe作为后缀名进程内组件以Dll作为后缀名其中进程内组件又分为单线程single-threaded组件和多线程multi-threaded组件。到底把我们编写的程序做成这样的组件完全由Visual FoxPro来完成编译工作如下图图1连编选项对话框进程内组件与客户程序运行在同一个内存空间中这样数据交流的速度就比较快了但是如果这个组件崩溃就会影响客户程序。由于进程内组件与客户程序在同一个内存空间运行这样如果要替换更新组件就必须卸下整个运用程序这对普通的应用是无所谓的但是对于web应用却是很有影响更换组件就必须荡下整个web服务器大家是不是知道VFP黄页http://www.universalthread.com就时常发布通告用几个小时更新网站进程外组件与客户程序运行在不同的内存空间这样数据交换的速度就慢了但两者互不干扰这就有点像Visual FoxPro调用Word一样Word是一个进程外COM组件如果Word出错Visual FoxPro作为客户程序并不会受什么影响顶多是触发一个错误。组件与组件用户界面进程内组件不能带界面元素进程外组件可以带有界面元素这就是Word为什么看上去像一个普通的exe但却是一个COM组件的原因了。这里我有一点想法与大家交流既使是进程外组件它可以带界面但在开发时我们要尽力减少模式表单因为COM组件往往处于无人职守状态不时跳出模式表单让用户确认是不现实的如果模式表单不被用户回应COM程序进程将被堵塞以后的客户机的请求就无法响应了。Visual FoxPro规定开发的程序被编译成进程内组件后将忽略界面元素同时新的Vfp6t.dll运行时刻库只有进程内组件可以使用这个运行库许多用户界面命令和函数已被删除其中包括旧的 FoxPro 2.x READ 和 …Get/Say 支持。另外存在于Vfp6r.dll 运行时刻中的某些设计器例如表设计器和报表设计器已被删除。Vfp6t.dll 运行时刻仍支持表单等可视类。由此可见设计进程内调用组件时“无人看守状态”的问题不是很突出的问题出在进程外组件。如果我们能确定用户可以随时响应模式表单就像Word那样的话这个问题也就不成其为问题了但是组件确实时运行在“无人看守状态”这个问题就不得不被考虑Visual FoxPro提供了sys(2335)的函数来处理进程外组件的“无人看守状态”问题由于本文着重讨论进程内组件的开发这里不再多说了。我们的第一个COM组件在98年Visual FoxPro 6推出时当时Visual FoxPro只能开发进程外组件与单线程的进程内组件考虑到当时进程内组件运行效果、运行稳定性都不很好国外的Fox专家提醒我们不要使用Visual FoxPro开发进程内组件。随着Visual FoxPro 6的第一个服务包Visual Studio SP3 的推出Visual FoxPro 具备了多线程组件的开发能力前文提到的轻巧、专门支持进程内组件的运行时刻Vfp6t.dll也被推出Visual FoxPro 在COM组件的编译上趋向于多线程的进程内组件当然每一种类型的组件都有各自的特点在不同的场合各有其存在的合理性。本文假设用户使用Visual FoxPro 6的SP3以上版本把范例代码编译成为多线程的进程内组件这样的话不打补丁的Visual FoxPro是不能适应本文的当然如果你有Visual FoxPro 7那么您会明显感到无论是开发效率还是运行效率都比6.0版本要好得多即使是Beta 版本。现在就来看看我们的第一个COM组件吧这是一个十分简单的程序它的功能就是向表里面加入一条记录如果添加失败就产生出提示。也许您不满意这个组建的微弱功能那么您就发挥自己的聪明才智吧这里我们只是表达一个意思……数据库Demo.dbc中有两个表分别是Item.dbf和Sys_id.dbfItem.dbf的结构如下字段名称字段类型宽度默认值字段有效性规则IdI4Getid(1)First_nameC6! Empty(First_name)Last_nameC6! Empty(Last_name)SexC2Inlist(sex,男,女)BirthdayD8Year(Birthday)1980DescM4其中字段ID的默认值数据库存储过程Getid()的返回值Getid()可以从Sys_id表中返回唯一的整型数据具体如下procedure getid lpara lTableid local lCurrid[1] update sys_id set curr_idcurr_id1 where tableidlTableid select curr_id from sys_id where tableidlTableid into array lCurrid if select(sys_id)0 use in sys_id endif return lCurrid[1]endproc这段代码很简单唯一值得一提的是及时关闭数据表。笔者个人以为这应该是COM编程的一个特点——减少数据库与组件的连接时间。虽然这里我们的应用不是三层构架但我还是希望把这个精神传递给大家。也许有人有疑问多次连接会不会很耗费时间或是系统资源这个问题是很复杂的总体来说三层应用中优化效率的关键是数据库服务器最好不要保存每个连接的状态要做到这个就必须保证连接是瞬时的。然而连接的瞬时往往会造成连接的频率增加对于大型服务器型数据库oracle、SQL Server等连接到它们往往又是很慢的甚至连接的速度要以分钟计算这样看来“瞬时连接”好像是不足取于是人们提出了种种优化方案如连接池等以解决连速度问题。不过对于dbc这样的文件型数据库来说每次连接数据库打开表的速度很快特别是使用Fox本身的数据引擎所以是否及时关闭连接表在这里显得不很重要不过当我们编写连接到大型数据库组建的时候特别是用于三层体系的组件这个问题千万要好好考虑因为这是优化系统效率的关键接着就是我们的组件代码了COM的编写必须是基于OOP面向对象的行为COM组件本身就是一个对象。在Visual FoxPro中我们建立COM组件的方法就是定义一个OLEPUBLIC类我们可以通过类设计器建立它也可以通过prg文件建立它不过随着Visual FoxPro 7的推出后一种可能更为流行,原因是支持私有工作期的session类表单类也支持私有工作期但资源消耗较大只能通过prg定义通过prg定义的类可以在Visual Studio.NET中直接调试而其他的不行由于Visual FoxPro设计的COM组件基本不带界面所以类设计器的“可视化”无优势可言在加上Visual FoxPro 7的高效开发环境prg的简洁更见优势。废话就不多说了下面就是我们COM组件的完整代码#define CL chr(13)chr(10)define class vfpcomtest as session olepublicDatasession2PROCEDURE setpathLPARAMETERS cNewValIF RIGHT(cNewVal,1)\cNewValcNewVal\ENDIFOPEN DATABASE cNewValdemo.dbc SHARED ENDPROCprocedure destroyIF DBUSED(demo)CLOSE DATABASESENDIFendprocfunction add_itemlpara cFirst_Name,cLast_Name,cSex,dBirthday,mDesclocal dBirthdayif pcount()5error 添加操作时缺少参数return endifinsert into item(first_name,last_name,sex,birthday,desc) value(m.cFirst_Name,m.cLast_Name,m.cSex,m.dBirthday,mDesc)if select(item)0use in itemendifendfuprocedure error(lError,lMethod,lLine) local cTextif select(item)0use in itemendifcText;出错时间transform(datetime())CL;错误代码str(lError,4)CL;错误提示message()CL;错误方法lMethodCL;错误行号transform(lLine)CLCLstrtofile(cText,c:\com.txt,.t.)comreturnerror(Visual FoxPro COM 服务器,cText)endprocenddefine1.我们定义了一个OLEPUBLIC类它的名称是VFPCOMTEST它的基类是SESSION类。SESSION类是Visual FoxPro 6 SP3以后才提供的它具有占用资源小、支持私有工作期的特色于是成为定义COM组件特别是进程内组件如果希望开发带界面的进程外组件就不能用它了的最佳选择我们加入了OLEPUBLIC关键字这是编译成为COM组件的关键切不可省略。在代码中我们使用以下语句完成这些工作。define class vfpcomtest as session olepublicenddefine2.接着我们设置类的DataSession属性的默认值为2表示使用私有工作期如果设定它的值为1表示使用默认工作期这与表单的DataSession属性是一样的。3.由于我们使用DBC数据库演示所以数据库所处的路径对系统来说就很重要。这里我们提供了一个SetPath方法来定位并打开数据库PROCEDURE setpathLPARAMETERS cNewValIF RIGHT(cNewVal,1)\cNewValcNewVal\ENDIFOPEN DATABASE cNewValdemo.dbc SHARED ENDPROC4.这个类的关键方法程序是ADD_ITEM它的代码如下function add_itemlpara cFirst_Name,cLast_Name,cSex,dBirthday,mDesclocal dBirthdayif pcount()5error 添加操作时缺少参数return endifinsert into item(first_name,last_name,sex,birthday,desc) value(m.cFirst_Name,m.cLast_Name,m.cSex,m.dBirthday,mDesc)if select(item)0use in itemendifendfu很简单吧有一点要说的就是当参数少于5个时我们使用Error命令产生一个用户自定义错误Error命令时Visual FoxPro 6中的新增加命令更详细的使用大家可以参看有关资料。这里还有一点想说的是在Visual FoxPro 的类定一种中过程(procedure)与函数(function)是一样的选用谁可以根据您的喜好。5.当COM组件被释放时我们必须做一些清理工作这些代码可以写在Destroy事件中如果想在COM组件被建立时作一些初始化工作可以把代码写在Init事件中。6.接着就是我们这个COM组件最关键的一段代码出错陷阱。COM组件总是在后台运行的甚至有时是在无人看守状态运行的所以稳健的错误陷阱程序是十分重要的。COM组件可以很简单就像我们的例子但必须稳健编写COM程序要写的第一个方法程序就是Error方法。Error方法是Session类的自带的方法程序当产生错误时被触发。我们的代码如下procedure error(lError,lMethod,lLine) local cText if select(item)0 use in item endif cText; 出错时间transform(datetime())CL; 错误代码str(lError,4)CL; 错误提示message()CL; 错误方法lMethodCL; 错误行号transform(lLine)CLCL strtofile(cText,c:\com.txt,.t.) comreturnerror(Visual FoxPro COM 服务器,cText)endproc在这段代码中我们首先整理战场——关闭数据表接着我们产生一个字符串记录下有关本次出错的信息并将它写入文本文件中作为历史纪录登记在案最后我们使用了COMRETURNERROR()函数告诉客户程序COM组件出错了!下面我们就讨论一下COM组件的错误处理。情况一如果我们在组件中不写任何错误陷阱程序如类的ERROR方法或是ON ERROR例程大家必须明白这是极其愚蠢的做法除非您能保证程序不出错。在这种情况下如果COM组件发生错误客户程序是可以得到组件出错的信息的。这里的问题在于COM组件出错后是不是可以接着正常运行恐怕必须要处理一下残局才可以重新投入战斗这个问题在普通编程中大家应该已经明白了。情况二COM组件中拥有错误陷阱但没有使用COMRETURNERROR()函数告诉客户程序COM组件发生了错误。这时一旦错误发生就会触发有关错误处理程序错误处理程序会调整COM的运行状态使它恢复正常这与普通程序的想法、做法是一致的。当错误被处理后COM组件恢复到正常状态于是COM组件的客户程序就不会知道COM组件曾经发生过错误。这不是一种理想的状况它降低了COM组件与客户程序的互动性。就拿我们的例程来说如果添加记录时发生错误记录明明没有被加入数据表格但由于客户程序得不到COM组件出错消息它很可能会提示用户记录添加成功这样就有误会了。情况三当我们分析了前面两种情况我们就会理解COMRETURNERROR()函数的意义先用错误处理陷阱容错再用COMRETURNERROR()告诉客户程序COM组件发生了错误这是两全其美之举。以下是关于COMRETURNERROR()的用法COMRETURNERROR(cServerName,cErrorMessage)1.cServerNameCOM 服务程序的名称可任意指定。2.cErrorMesage错误信息文本一般可以用Message()函数返回值填入。如果要得到更详细的信息可以向本例中那样先组织文本。COM组件是Windows系统下的一种规范它的出错信息其实是一个结构类型的变量要让客户程序知道COM组件出错了只要把这个结构填写即可。Visual FoxPro为我们省了麻烦我们可以使用COMRETURUERROR()轻易的完成这一工作……对于客户程序得到的组件出错信息实际只是一个事后的通知如果在COM中我们已经处理了错误正常情况是这样客户程序就不必担心COM的运行状态仍然可以继续使用这个组件。所以总结一下整个错误处理过程COM组件必须自己处理自己发生的错误错误处理完毕再用COMRETURNERROR()函数向客户程序返回出错信息。编译我们的COM组件一般来说在编译前我们应该设定项目的有关信息不过这里Visual FoxPro好像有个小小的不足——通过prg文件建立的OLEPUBLIC类在初次连遍前项目信息对话框的服务程序页是不可用的。所以在“正式”连编前您可以任意编译以下这样就可以设置COM组件的属性了。项目信息对话框的服务程序页这里有两个属性很重要实例和项目名。实例实例有三种选项不可创建、单独使用、多重使用。1.如果我们选择“不可创建”那么即使把代码编译成为COM组件进程内或是进程外这个组件都不能作为COM对象被使用而只能作为普通的Visual FoxPro类在Visual FoxPro内部使用2.单独使用与多重使用的区别在于在系统中组件建立多少个实例应付客户请求。这个选项只对进程外组件或单线程的进程内组件有效。这里我们用进程外组件来说明问题我们把我们的代码它编译成单独使用的进程外组件在Visual FoxPro中调用它ox1ctreateobject(vfpcomtest.vfpcomtest)ox2ctreateobject(vfpcomtest.vfpcomtest)这时打开Window 2000的任务管理器您会看到单独使用时,COM组件对产生多个实例。我们把我们的代码它编译成多重使用的进程外组件在Visual FoxPro中调用它ox1ctreateobject(vfpcomtest.vfpcomtest)ox2ctreateobject(vfpcomtest.vfpcomtest)这时打开Window 2000的任务管理器您会看到多重使用时,COM组件对产生一个实例。3.对于进程内的多线程组件来说总是创建“多重使用”的组件“单独使用”总是被忽略的。项目名这个设定牵涉到怎样调用COM组件默认情况下设这样的项目名.OLEPUBLIC的类名这里就是Vfpcomtest.Vfpcomtest。调用它时就是ox1ctreateobject(vfpcomtest.vfpcomtest)正式联编像图中这样设定(重新生成组件ID选中也可)按确定就行了。这里可能会出现的错误就是不能更新文件。我们在开发组件时往往反复调试、反复联编这样如果逐渐正处于调用状态的话联编就会出错这时只要释放组件即可在Visual FoxPro中如下rele ox*假设先前执行过oxcreateobject(vfpcomtest.vfpcomtest)应用我们的COM组件在Visual FoxPro中应用oxCREATEOBJECT(vfpcomtest.vfpcomtest)建立COM对象ox.setpath (D:\First_com\)设定数据库的位置ox.add_item(f1,l1,1男,{^1975-12-26},测试)添加一条记录rele ox释放组件在Delphi中应用我已经写一个简单的测试程序大家可以看看。猫猫的心里话加菲猫的VFP|狐友会社群接收投稿啦加菲猫的VFP用VFP不局限VFP用VFP混合一切。无论是VFP还是JS还是C只要能混合起来都可以发表。商业模式销售技巧、需求规划、产品设计的知识通通可以发表。暂定千字50元红包优秀的文章红包更大一经发表红包到手。如何帮助使用VFP的人用VFP的人有专业的有非专业了很多人其实是小白问出的问题是小白如果问题不对我们引导他们问正确的问题。无论如何请不要嘲笑他们说帮助都不看这么简单的问题都不会嘲笑别人不行而无法提出建设性答案是很low的。我们无论工作需要还是有自己的软件都是是需要真正的知识如何让更多人学习真正的VFP知识呢只需要点赞在看能转发朋友圈就更好了。加菲猫的vfp倡导用VFP极简混合开发少写代码、快速出活用VFP但不局限于VFP各种语言混合开发。我已经带领一百多名会员成功掌到VFP的黑科技进入了移动互联网时代接下来我们要进入物联网领域。2026年狐友会社群会员继续招募中社群会员获取的权益有祺佑三层开发框架商业版猫框终身免费升级终身技术支持。开放的录播课程有微信小程序微信公众号开发H5 APP开发Extjs BS开发VFP面向对象进阶VFP中间层开发,VFP Layui 开发源码类资源有支付组件源码短信源码权限组件源码一些完整系统的源码。这个可以单独出售的需要的可以联系我。会员也可以实现群内资源对接可以接分包合作等各项商业或技术业务