文章列表

图解支付系统的渠道路由设计

作者:微信小助手

<section class="mp_profile_iframe_wrp"> <mp-common-profile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzkwOTYyODA4Nw==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/ulUtYHPCwcibn6AYE0o71lQOA0v9XZ0COd4gDsMAGibibnwMnaM4C2ZV8XaUb5el7tdEXXJvVd0FrbeCspCkk7yCg/0?wx_fmt=png" data-nickname="隐墨星辰" data-alias="yinmo_sc" data-signature="10余年顶尖支付公司架构设计经验,精通国内和跨境支付业务及系统架构设计" data-from="0" data-is_biz_ban="0"></mp-common-profile> </section> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">大家好,我是隐墨星辰,今天和大家聊聊渠道路由设计。</span></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">这篇文章主要讲清楚:渠道路由是什么,为什么需要渠道路由,渠道路由的几种形态,一个简洁而实用的基于规则的渠道路由设计。</span></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">注:有些公司称渠道为通道,都是一个意思,为方便起见,本文统称为渠道。</span></p> <h1 data-lake-index-type="2" style="font-size: 28px;line-height: 36px;margin-top: 26px;margin-bottom: 10px;"><span lake-read-ignore="true">1. </span>一些背景知识</h1> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">有些支付公司没有区分</span><strong><span style="font-size: 16px;">支付方式咨询</span></strong><span style="font-size: 16px;">、</span><strong><span style="font-size: 16px;">渠道咨询</span></strong><span style="font-size: 16px;">、</span><strong><span style="font-size: 16px;">渠道路由,而是混在一起做掉</span></strong><span style="font-size: 16px;">,这样的好处是简单而实用,缺点是扩展性不足。下面将以扩展性最好的拆分方式来讲解。</span></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">下面是三者之间的简单关系图:</span></p> <p style="min-height: 24px;"><img class="rich_pages wxw-img" data-imgfileid="100001020" data-ratio="0.5518518518518518" src="/upload/4f004ef956494e674bc5b4f50ef3d386.png" data-type="png" data-w="1080" style="font-size: 16px;" width="1019"></p> <p style="min-height: 24px;"><span style="font-size: 16px;">说明:</span></p> <ol class="list-paddingleft-1" style="padding-left: 23px;"> <li><p><strong><span style="font-size: 16px;">支付方式咨询:</span></strong><span style="font-size: 16px;">根据用户的请求,组装</span><strong><span style="font-size: 16px;">可用支付方式列表</span></strong><span style="font-size: 16px;">返回给用户。由收银域提供服务。</span></p></li> <li><p><strong><span style="font-size: 16px;">渠道咨询:</span></strong><span style="font-size: 16px;">根据用户的请求,组装可用的</span><strong><span style="font-size: 16px;">渠道列表和渠道属性</span></strong><span style="font-size: 16px;">返回给收银域,再由收银域转换为支付方式返回给用户。由渠道网关提供服务。</span></p></li> <li><p><strong><span style="font-size: 16px;">渠道路由:</span></strong><span style="font-size: 16px;">当有多个渠道可用时,选择出</span><strong><span style="font-size: 16px;">最优的一个渠道</span></strong><span style="font-size: 16px;">。由渠道网关提供服务。</span></p></li> </ol> <p style="min-height: 24px;"><img class="rich_pages wxw-img" data-imgfileid="100001023" data-ratio="0.6564814814814814" src="/upload/048d9586fcc7191c6d0776aadd883fbb.png" data-type="png" data-w="1080" style="font-size: 16px;" width="1031"></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">再详细一点,如下:</span></p> <p style="min-height: 24px;text-indent: 2em;"><strong><span style="font-size: 16px;">支付方式咨询:</span></strong><span style="font-size: 16px;">解决用户可以使用哪些支付方式,比如余额、招行借记卡、招行信用卡等。比如虚拟商品不能使用信用卡,这种支付方式的管理就是支付方式咨询的职责。</span></p> <p style="min-height: 24px;text-indent: 2em;"><strong><span style="font-size: 16px;">渠道咨询:</span></strong><span style="font-size: 16px;">解决是否有渠道可以支持当前的支付行为。比如用户绑定了招行借记卡,但招行当前正在维护无法提供服务,那就将渠道状态设置为不可用,收银域对应的支付方式会置灰。</span></p> <p style="min-height: 24px;text-indent: 2em;"><strong><span style="font-size: 16px;">渠道路由:</span></strong><span style="font-size: 16px;">解决最优渠道问题。需要综合支付成功率、支付成本、用户体验、渠道状态等多种因素挑选出最优的一条渠道。</span></p> <h1 data-lake-index-type="2" style="font-size: 28px;line-height: 36px;margin-top: 26px;margin-bottom: 10px;"><span lake-read-ignore="true">2. </span>渠道路由核心作用</h1> <p style="min-height: 24px;"><img class="rich_pages wxw-img" data-imgfileid="100001021" data-ratio="0.6324074074074074" src="/upload/e63a6b8c2fcd23d8becbd9baa245ac76.png" data-type="png" data-w="1080" style="font-size: 16px;" width="862.5"></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">渠道路由核心作用是当有多个渠道同时满足业务诉求时,综合</span><strong><span style="color: #117CEE;font-size: 16px;">支付成功率、支付成本、用户体验、渠道状态</span></strong><span style="font-size: 16px;">等多种因素</span><strong><span style="color: #117CEE;font-size: 16px;">挑选出最优的一条渠道</span></strong><span style="font-size: 16px;">。具体如下:</span></p> <ol class="list-paddingleft-1" style="padding-left: 23px;"> <li><p><strong><span style="font-size: 16px;">提高支付成功率</span></strong><span style="font-size: 16px;">:通过选择最合适的渠道,可以提高支付的成功率,减少支付失败带来的用户流失。原因在于不同的渠道在其内部的风险偏好是不一样的,同一个请求在A渠道会失败,但在B渠道会成功。</span></p></li> <li><p><strong><span style="font-size: 16px;">优化成本</span></strong><span style="font-size: 16px;">:不同渠道的费用可能不同,通过合理的路由,可以降低支付成本。一些渠道还有阶梯收费,需要通过分流不同的渠道,保持整体成本最优。</span></p></li> <li><p><strong><span style="font-size: 16px;">提升用户体验</span></strong><span style="font-size: 16px;">:快速、稳定的支付体验能增强用户的满意度和忠诚度。用户如果经常在A渠道支付,新的请求过来后,仍然发给A渠道支付的成功率往往会更高。</span></p></li> <li><p><strong><span style="font-size: 16px;">负载均衡</span></strong><span style="font-size: 16px;">:将支付请求合理分配到不同的渠道,避免某个渠道过载,提升整体系统的稳定性。</span></p></li> </ol> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">举几个渠道路由应用的小场景:</span></p> <ol class="list-paddingleft-1" style="padding-left: 23px;"> <li><p><span style="font-size: 16px;">用户使用招行信用卡支付,支付平台同时对接了网联和银联,而网联和银联都支持招行信用卡,那么就需要渠道路由挑选一个渠道。</span></p></li> <li><p><span style="font-size: 16px;">做实名认证,平台对接了多个实名认证通道,通过渠道路由挑选一个认证渠道。</span></p></li> </ol> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">由上面可以看到,除了支付路由外,还可能有</span><strong><span style="font-size: 16px;">信息类渠道路由,</span></strong><span style="font-size: 16px;">比如实名认证类。</span></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">那退款有没有路由?显示没有。在银联做的支付,只能去银联退款。特殊的渠道也没有路由,比如用户选择使用支付宝支付,因为支付宝只能在支付宝做支付,所以无需路由。</span></p> <h1 data-lake-index-type="2" style="font-size: 28px;line-height: 36px;margin-top: 26px;margin-bottom: 10px;"><span lake-read-ignore="true">3. </span>渠道路由的设计原则</h1> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">渠道路由作为支付系统的核心模块,需要满足以下几个设计原则:</span></p> <ul class="list-paddingleft-1" style="padding-left: 23px;"> <li><p><strong><span style="font-size: 16px;">灵活性</span></strong><span style="font-size: 16px;">:路由规则需要支持动态调整。从业务的角度出发,有些场景考虑成本,有些场景考虑成功率,都能方便支持。</span></p></li> <li><p><strong><span style="font-size: 16px;">扩展性</span></strong><span style="font-size: 16px;">:设计时要考虑到未来可能新增的支付渠道,新增的决策因子,这些都不能在代码中写死,确保系统易于扩展。</span></p></li> <li><p><strong><span style="font-size: 16px;">高可用性</span></strong><span style="font-size: 16px;">:路由系统本身需要具备高可用性,确保在高并发和故障情况下仍能稳定运行,哪怕内部报错,仍然能返回一条可用的渠道。</span></p></li> <li><p><strong><span style="font-size: 16px;">性能</span></strong><span style="font-size: 16px;">:在保证准确性的前提下,路由决策需要快速,不能成为支付流程的瓶颈。</span></p></li> </ul> <h1 data-lake-index-type="2" style="font-size: 28px;line-height: 36px;margin-top: 26px;margin-bottom: 10px;"><span lake-read-ignore="true">4. </span>业界常见的几种路由形态</h1> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">根据业务的需要,通常有以下几种路由形态:</span></p> <ol class="list-paddingleft-1" style="padding-left: 23px;"> <li><p><strong><span style="font-size: 16px;">硬编码取第一个</span></strong><span style="font-size: 16px;">。在项目上线初期,为了赶进度,同时渠道也不多,常常在代码中写死取第一个,先保证支付主流程能走通。</span></p></li> <li><p><strong><span style="font-size: 16px;">基于规则的路由</span></strong><span style="font-size: 16px;">。通过预定义的规则提高灵活性和可扩展性。</span></p></li> <li><p><strong><span style="font-size: 16px;">智能路由</span></strong><span style="font-size: 16px;">。利用机器学习和大数据分析,根据历史数据和实时状态,智能地选择最佳渠道。</span></p></li> </ol> <h1 data-lake-index-type="2" style="font-size: 28px;line-height: 36px;margin-top: 26px;margin-bottom: 10px;"><span lake-read-ignore="true">5. </span>一种典型的基于规则的渠道路由设计</h1> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">基于规则的渠道路由是最常见的设计。简单地说,就是符合什么条件就执行什么样的分流逻辑。比如:支付平台对接了网联和银联,招行信用卡全部走网联,工行信用卡500块以内的走网联,500块以上的走银联。</span></p> <h2 data-lake-index-type="2" style="font-size: 24px;line-height: 32px;margin-top: 21px;margin-bottom: 5px;"><span lake-read-ignore="true">5.1. </span>核心流程设计</h2> <p style="min-height: 24px;"><img class="rich_pages wxw-img" data-imgfileid="100001022" data-ratio="1.2157407407407408" src="/upload/9f601962ec23a910c77e763ffa751d91.png" data-type="png" data-w="1080" style="font-size: 16px;" width="580.5"></p> <p style="min-height: 24px;"><span style="font-size: 16px;">说明:</span></p> <ol class="list-paddingleft-1" style="padding-left: 23px;"> <li><p><span style="font-size: 16px;">先进行唯一渠道判断,如果只有一条渠道,直接返回。</span></p></li> <li><p><span style="font-size: 16px;">判断规则,如果规则没有命中,那就从可用渠道中随机挑选一条。</span></p></li> <li><p><span style="font-size: 16px;">如果命中规则,再根据规则中的分流逻辑进行分流。</span></p></li> <li><p><span style="font-size: 16px;">最后返回唯一的一条渠道。</span></p></li> </ol> <h2 data-lake-index-type="2" style="font-size: 24px;line-height: 32px;margin-top: 21px;margin-bottom: 5px;"><span lake-read-ignore="true">5.2. </span>分流算法设计</h2> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">如果一个请求既可以走银联,也可以走网联,还可以走直连,有以下几种情况:</span></p> <ol class="list-paddingleft-1" style="padding-left: 23px;"> <li><p><span style="font-size: 16px;">没有命中任何一条规则,随机选择一条渠道。</span></p></li> <li><p><span style="font-size: 16px;">有多条规则可以命中,选择优先级最高的。</span></p></li> <li><p><span style="font-size: 16px;">命中的路由规则里,银联和网联分别是40%和40%,直连20%,根据规则分流。如果当前银联挂了,把银联按比例分配到网联和直连。</span></p></li> </ol> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">常见的分流算法是先把各渠道的分流比例换算成0-100区间的数字,从大到小排序,再根据用户ID取模、请求单号取模或生成一个随机数,再看这个数落在哪个区间,对应的渠道就是命中的渠道。</span></p> <p style="min-height: 24px;"><img class="rich_pages wxw-img" data-imgfileid="100001019" data-ratio="0.525" src="/upload/9929717aee12a7c8766ea06fb6150a28.png" data-type="png" data-w="1080" style="font-size: 16px;" width="712"></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">伪代码如下:</span></p> <pre data-language="java" style="border-width: 1px;border-style: solid;border-color: rgb(232, 232, 232);border-radius: 2px;background: rgb(249, 249, 249);padding: 16px;font-size: 13px;color: rgb(89, 89, 89);"><code>int random = 用户ID取模(或请求单号取模,或生成随机数);<br>for (int i = 0; i &lt; 分流集合.size(); i++) {<br> if (random -= 分流集合[i] &lt;= 0) {<br> return 命中的渠道;<br> }<br>}</code></pre> <h2 data-lake-index-type="2" style="font-size: 24px;line-height: 32px;margin-top: 21px;margin-bottom: 5px;"><span lake-read-ignore="true">5.3. </span>路由规则配置模型</h2> <p style="min-height: 24px;"><img class="rich_pages wxw-img" data-imgfileid="100001025" data-ratio="0.75" src="/upload/71d4e7d89e4861a9afd2fbb0d5f26dfe.png" data-type="png" data-w="1080" style="font-size: 16px;" width="547"></p> <p style="min-height: 24px;"><span style="font-size: 16px;">说明:</span></p> <ol class="list-paddingleft-1" style="padding-left: 23px;"> <li><p><strong><span style="font-size: 16px;">路由规则用于规则引擎运算是否命中</span></strong><span style="font-size: 16px;">。核心字段包括:规则ID、规则类型、规则表达式、优先级。实际实现时可根据各公司内部情况加字段。</span></p></li> </ol> <ol class="list-paddingleft-1" style="padding-left: 23px;list-style: none;"> <ol ne-level="1" class="list-paddingleft-1" style="padding-left: 23px;list-style: lower-alpha;"> <li><p><span style="font-size: 16px;">规则ID:用于分流配置做关联;</span></p></li> <li><p><span style="font-size: 16px;">规则类型:用于区分支付、实名认证等。</span></p></li> <li><p><span style="font-size: 16px;">规则表达式:用于规则引擎运算;</span></p></li> <li><p><span style="font-size: 16px;">优先级:用于排序,如果有多个规则都符合,以优先级最高的为准;</span></p></li> </ol> </ol> <ol start="2" class="list-paddingleft-1" style="padding-left: 23px;"> <li><p><strong><span style="font-size: 16px;">分流配置用于规则命中后,如何进行分流</span></strong><span style="font-size: 16px;">。核心字段包括:规则ID、渠道名、分流比例。</span></p></li> </ol> <ol class="list-paddingleft-1" style="padding-left: 23px;list-style: none;"> <ol ne-level="1" class="list-paddingleft-1" style="padding-left: 23px;list-style: lower-alpha;"> <li><p><span style="font-size: 16px;">规则ID:用于与路由规则进行关联。</span></p></li> <li><p><span style="font-size: 16px;">渠道名:表示要分流去的渠道。</span></p></li> <li><p><span style="font-size: 16px;">分流比例:说明有多少流量要分过去。</span></p></li> </ol> </ol> <ol start="3" class="list-paddingleft-1" style="padding-left: 23px;"> <li><p><strong><span style="font-size: 16px;">决策因子定义用于决策的条件</span></strong><span style="font-size: 16px;">。比如卡BIN,卡品牌,金额等。</span></p></li> </ol> <h2 data-lake-index-type="2" style="font-size: 24px;line-height: 32px;margin-top: 21px;margin-bottom: 5px;"><span lake-read-ignore="true">5.4. </span>规则引擎选择</h2> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">业务的规则引擎有很多,比如大名鼎鼎的Drools等,也可以选择自研,各公司可以根据自己的技术生态来选择。</span></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">我个人推荐QlExpress。推荐理由:简单实用。因为路由规则都非常简单,没有过于复杂的运算,不需要引入一些很重的规则引擎。</span></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">关于QlExpress的资料,可参考官网介绍。</span></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">后面会有QlExpress的规则示例。</span></p> <h2 data-lake-index-type="2" style="font-size: 24px;line-height: 32px;margin-top: 21px;margin-bottom: 5px;"><span lake-read-ignore="true">5.5. </span>决策子选择</h2> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">决策因子就是路由规则匹配的条件,一般有以下几种:</span></p> <ol class="list-paddingleft-1" style="padding-left: 23px;"> <li><p><span style="font-size: 16px;">金额:比如小于某个金额,或大于某个金额。</span></p></li> <li><p><span style="font-size: 16px;">卡品牌:VISA、MASTER、UPAY等。</span></p></li> <li><p><span style="font-size: 16px;">发卡行:CMB、ICBC等。</span></p></li> <li><p><span style="font-size: 16px;">卡类型:借记卡、信用卡等。</span></p></li> <li><p><span style="font-size: 16px;">卡BIN:某个号段的卡。</span></p></li> <li><p><span style="font-size: 16px;">业务场景字段:各公司自定,比如线下场景,线上场景等。</span></p></li> </ol> <h2 data-lake-index-type="2" style="font-size: 24px;line-height: 32px;margin-top: 21px;margin-bottom: 5px;"><span lake-read-ignore="true">5.6. </span>路由规则示例</h2> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">规则的编写和规则引擎强相关。下面以QLExpress做个示例。实际落地时,需要根据自己选择的规则引擎做改造。</span></p> <p style="min-height: 24px;text-indent: 2em;"><strong><span style="font-size: 16px;">假设</span></strong><span style="font-size: 16px;">:支付平台对接了网联和银联,要求:</span></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">1)招行信用卡全部走网联。</span></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">2)工行信用卡500块以内(不包含)的40%走网联,60%走银联。</span></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">3)工行信用卡500块以上的走银联。</span></p> <p style="min-height: 24px;text-indent: 2em;"><strong><span style="font-size: 16px;">一些基本的变量定义</span></strong><span style="font-size: 16px;">:</span></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">银行名称:bankName</span></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">支付方式:paymentMethod</span></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">卡类型:cardType</span></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">金额变量:amount</span></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">网联:NUCC</span></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">银联:UPAY</span></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">招行:CMB</span></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">工行:ICBC</span></p> <p style="min-height: 24px;text-indent: 2em;"><strong><span style="font-size: 16px;">定义规则</span></strong><span style="font-size: 16px;">:</span></p> <ol class="list-paddingleft-1" style="padding-left: 23px;"> <li><p><strong><span style="font-size: 16px;">规则1</span></strong><span style="font-size: 16px;">:</span><span style="color: #117CEE;font-size: 16px;">paymentMethod='card' &amp;&amp; cardType='credit' &amp;&amp; bankName='CMB'</span></p></li> </ol> <p style="min-height: 24px;text-indent: 2em;"><strong><span style="font-size: 16px;">分流</span></strong><span style="font-size: 16px;">:</span><span style="color: #117CEE;font-size: 16px;">NUCC:100</span></p> <ol start="2" class="list-paddingleft-1" style="padding-left: 23px;"> <li><p><strong><span style="font-size: 16px;">规则2</span></strong><span style="font-size: 16px;">:</span><span style="color: #117CEE;font-size: 16px;">paymentMethod='card' &amp;&amp; cardType='credit' &amp;&amp; bankName='ICBC' and amount &lt; 500.00</span></p></li> </ol> <p style="min-height: 24px;text-indent: 2em;"><strong><span style="font-size: 16px;">分流</span></strong><span style="font-size: 16px;">:</span><span style="color: #117CEE;font-size: 16px;">NUCC:40,UPAY:60</span></p> <ol start="3" class="list-paddingleft-1" style="padding-left: 23px;"> <li><p><strong><span style="font-size: 16px;">规则3</span></strong><span style="font-size: 16px;">:</span><span style="color: #117CEE;font-size: 16px;">paymentMethod='card' &amp;&amp; cardType='credit' &amp;&amp; bankName='ICBC' and amount &gt;= 500.00</span></p></li> </ol> <p style="min-height: 24px;text-indent: 2em;"><strong><span style="font-size: 16px;">分流</span></strong><span style="font-size: 16px;">:</span><span style="color: #117CEE;font-size: 16px;">UPAY:100</span></p> <h2 data-lake-index-type="2" style="font-size: 24px;line-height: 32px;margin-top: 21px;margin-bottom: 5px;"><span lake-read-ignore="true">5.7. </span>界面配置示例</h2> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">下面只是示意一个简单的路由配置。如果是多层次的与和或关系,需要产品经理做一些稍微复杂一点的界面。</span></p> <p style="min-height: 24px;text-indent: 2em;"><img class="rich_pages wxw-img" data-imgfileid="100001029" data-ratio="0.9879629629629629" src="/upload/7ba158de3490e83505864ed1440bd919.png" data-type="png" data-w="1080" style="font-size: 16px;" width="798.5"></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">说明:</span></p> <ol class="list-paddingleft-1" style="padding-left: 23px;"> <li><p><span style="font-size: 16px;">示例规则的业务诉求:工行信用卡500块以内(不包含)的40%走网联,60%走银联。</span></p></li> <li><p><span style="font-size: 16px;">后台保存的规则为:“paymentMethod='card' &amp;&amp; cardType='credit' &amp;&amp; bankName='ICBC' and amount &lt; 500.00”,分流有2两条,分别是:“NUCC:40”,“UPAY:60”。</span></p></li> <li><p><span style="font-size: 16px;">用于决策因子的元数据,需要提前定义好,包括这些字段的运算规则(比如开户行就不能使用大于、等于)。</span></p></li> </ol> <h2 data-lake-index-type="2" style="font-size: 24px;line-height: 32px;margin-top: 21px;margin-bottom: 5px;"><span lake-read-ignore="true">5.8. </span>一些调优思路</h2> <ol class="list-paddingleft-1" style="padding-left: 23px;"> <li><p><strong><span style="font-size: 16px;">用户最近支付成功记录优先,提高成功率</span></strong><span style="font-size: 16px;">。比如用户可以用银联,也可以使用网联,如果5天内最近一次使用了银联是成功的,那么为了成功率,可以考虑再次路由到银联去。因为从渠道风控的角度,已经成功的前提下,再次成功的可能性更大(余额不足除外)。</span></p></li> <li><p><strong><span style="font-size: 16px;">根据用户ID做分流</span></strong><span style="font-size: 16px;">,而不是当前订单号做分流,或者完全随机数。也就是使用伪随机。好处是同一个用户更大概率走到同一个渠道,有利于提高成功率,进而提升用户体验。</span></p></li> <li><p><strong><span style="font-size: 16px;">适当使用缓存</span></strong><span style="font-size: 16px;">,以提高运算速度。</span></p></li> </ol> <h1 data-lake-index-type="2" style="font-size: 28px;line-height: 36px;margin-top: 26px;margin-bottom: 10px;"><span lake-read-ignore="true">6. </span>加入自动化开关的渠道路由</h1> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">外部渠道服务经常不稳定,通过自动化开关模块监听支付引擎或渠道网关的支付结果消息,实时计算渠道的状态,</span><span style="color: #117CEE;font-size: 16px;">在渠道出现问题后自动关闭</span><span style="font-size: 16px;">,并推送给渠道路由。</span></p> <p style="min-height: 24px;"><img class="rich_pages wxw-img" data-imgfileid="100001026" data-ratio="0.5666666666666667" src="/upload/af58f5040a8d16199508ff6eaeaecac8.png" data-type="png" data-w="1080" style="font-size: 16px;" width="614.5"></p> <p style="min-height: 24px;"><span style="font-size: 16px;">说明:</span></p> <ol class="list-paddingleft-1" style="padding-left: 23px;"> <li><p><span style="font-size: 16px;">由自动化开关模块监听支付引擎的支付结果消息,每秒计算一次渠道的状态,在渠道出现问题后,自动关闭,并把结果推送给渠道路由。</span></p></li> <li><p><span style="font-size: 16px;">渠道关闭后,再发起探测服务,探测成功后,灰度打开渠道。</span></p></li> </ol> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">下图是渠道自动化渠道开关的示意图。有多种技术手段可以实现,基本原理就是基于滑动时间窗口算法来做,具体落地可以使用时序数据库,或者自己通过redis实现。</span></p> <p style="min-height: 24px;"><img class="rich_pages wxw-img" data-imgfileid="100001028" data-ratio="0.40925925925925927" src="/upload/2d4626d7dc26b96e00b8332f92d6ef4b.png" data-type="png" data-w="1080" style="font-size: 16px;" width="1007.5"></p> <p style="min-height: 24px;"><span style="font-size: 16px;">说明:</span></p> <ol class="list-paddingleft-1" style="padding-left: 23px;"> <li><p><span style="font-size: 16px;">初始是完成打开。</span></p></li> <li><p><span style="font-size: 16px;">指定时间内全部失败或指定时间内成功率低于阀值,关闭渠道。</span></p></li> <li><p><span style="font-size: 16px;">指定时间后,发起查询,如果查询渠道失败,持续关闭。</span></p></li> <li><p><span style="font-size: 16px;">如果查询成功,就灰度打开,如果灰度打开后的成功率不满足要求,就继续关闭。</span></p></li> <li><p><span style="font-size: 16px;">如果灰度打开后的成功率满足要求,就持续加大灰度,直到完成打开。</span></p></li> </ol> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">后面会单独起一篇文章来讲自动化渠道开关的设计与实现。</span></p> <h1 data-lake-index-type="2" style="font-size: 28px;line-height: 36px;margin-top: 26px;margin-bottom: 10px;"><span lake-read-ignore="true">7. </span>高阶的智能路由</h1> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">一些有实力的公司,通过算法和机器学习来做智能路由。所谓智能路由,就是不仅是根据路由规则来计算路由,而是根据当前的请求参数和渠道数据,综合成功率、成本、用户使用习惯、地域等多因子计算出最优的一条渠道。</span></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">这个方案有几个难题不好解决。</span></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">首先是公司实力足够强。有人才来做算法,且这些算法同学需要懂一点业务;</span></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">其次是经验不好总结。比如成功率提升了2%,是因为什么原因提升了?有一些不可解释性。</span></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">最后业务无法直接操作调优。比如有些场景下业务希望保成功率,有些场景下业务希望保较低的成本,智能路由如何调参?</span></p> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">我个人更倾向于【规则路由 + 离线数据分析】的组合。其中离线数据分析平台可以引入一些算法来分析各因子对成功率的影响,供业务人员决策,并调整路由规则。</span></p> <p style="min-height: 24px;"><img class="rich_pages wxw-img" data-imgfileid="100001027" data-ratio="0.4185185185185185" src="/upload/b6663bf3a7090392560f0291c70cf543.png" data-type="png" data-w="1080" style="font-size: 16px;" width="880.5"></p> <p style="min-height: 24px;"><span style="font-size: 16px;">说明:</span></p> <ol class="list-paddingleft-1" style="padding-left: 23px;"> <li><p><span style="font-size: 16px;">通过分析数据,找到影响成功率成本的因子。</span></p></li> <li><p><span style="font-size: 16px;">更新路由规则。</span></p></li> <li><p><span style="font-size: 16px;">重复第1步。</span></p></li> </ol> <h1 data-lake-index-type="2" style="font-size: 28px;line-height: 36px;margin-top: 26px;margin-bottom: 10px;"><span lake-read-ignore="true">8. </span>结束语</h1> <p style="min-height: 24px;text-indent: 2em;"><span style="font-size: 16px;">渠道路由在现代支付系统中扮演着至关重要的角色,一个高效、灵活的渠道路由设计能够显著提升支付成功率,优化成本,并改善用户体验。通过本文的介绍,希望能为大家在实际项目中设计和实现渠道路由提供一些有益的参考。</span></p>

别再手动部署jar包了,太low!动态上传热部署真的太爽了!

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" data-mpa-powered-by="yiban.io" style="outline: 0px;visibility: visible;"> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;visibility: visible;line-height: 1.75em;"> <span style="outline: 0px;font-size: 16px;visibility: visible;letter-spacing: 1px;">近期开发系统过程中遇到的一个需求,系统给定一个接口,用户可以自定义开发该接口的实现,并将实现打成jar包,上传到系统中。系统完成热部署,并切换该接口的实现。</span> <span style="outline: 0px;font-size: 16px;letter-spacing: 0px;visibility: visible;"><br style="outline: 0px;visibility: visible;"></span> </section> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 20px;visibility: visible;"><strong style="outline: 0px;visibility: visible;">定义简单的接口</strong></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;line-height: 26px;visibility: visible;"><span style="outline: 0px;font-size: 16px;visibility: visible;">这里以一个简单的计算器功能为例,接口定义比较简单,直接上代码。</span></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;visibility: visible;"><code style="padding: 16px;outline: 0px;overflow-x: auto;background: rgb(39, 40, 34);color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;visibility: visible;"><span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;visibility: visible;">public</span>&nbsp;<span style="outline: 0px;line-height: 26px;visibility: visible;"><span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;visibility: visible;">interface</span>&nbsp;<span style="outline: 0px;font-weight: bold;color: white;line-height: 26px;visibility: visible;">Calculator</span>&nbsp;</span>{<br style="outline: 0px;visibility: visible;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;line-height: 26px;visibility: visible;"><span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;visibility: visible;">int</span>&nbsp;<span style="outline: 0px;color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;visibility: visible;">calculate</span><span style="outline: 0px;line-height: 26px;visibility: visible;">(<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;visibility: visible;">int</span>&nbsp;a,&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;visibility: visible;">int</span>&nbsp;b)</span></span>;<br style="outline: 0px;visibility: visible;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;line-height: 26px;visibility: visible;"><span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;visibility: visible;">int</span>&nbsp;<span style="outline: 0px;color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;visibility: visible;">add</span><span style="outline: 0px;line-height: 26px;visibility: visible;">(<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;visibility: visible;">int</span>&nbsp;a,&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;visibility: visible;">int</span>&nbsp;b)</span></span>;<br style="outline: 0px;visibility: visible;">}<br style="outline: 0px;visibility: visible;"></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 20px;visibility: visible;"><strong style="outline: 0px;visibility: visible;">该接口的一个简单的实现</strong></h3> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;line-height: 1.75em;"> <span style="outline: 0px;font-size: 16px;">考虑到用户实现接口的两种方式,使用spring上下文管理的方式,或者不依赖spring管理的方式,这里称它们为注解方式和反射方式。</span> <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;outline: 0px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span style="outline: 0px;font-size: 16px;">calculate</span></code> <span style="outline: 0px;font-size: 16px;">方法对应注解方式,add方法对应反射方式。计算器接口实现类的代码如下:</span> </section> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;"><code style="padding: 16px;outline: 0px;overflow-x: auto;background: rgb(39, 40, 34);color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;"><span style="outline: 0px;color: rgb(117, 113, 94);line-height: 26px;">@Service</span><br style="outline: 0px;"><span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="outline: 0px;line-height: 26px;"><span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">class</span>&nbsp;<span style="outline: 0px;font-weight: bold;color: white;line-height: 26px;">CalculatorImpl</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">implements</span>&nbsp;<span style="outline: 0px;font-weight: bold;color: white;line-height: 26px;">Calculator</span>&nbsp;</span>{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(117, 113, 94);line-height: 26px;">@Autowired</span><br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;CalculatorCore&nbsp;calculatorCore;<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(117, 113, 94);line-height: 26px;">/**<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;注解方式<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(117, 113, 94);line-height: 26px;">@Override</span><br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;line-height: 26px;"><span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">int</span>&nbsp;<span style="outline: 0px;color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">calculate</span><span style="outline: 0px;line-height: 26px;">(<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">int</span>&nbsp;a,&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">int</span>&nbsp;b)</span>&nbsp;</span>{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">int</span>&nbsp;c&nbsp;=&nbsp;calculatorCore.add(a,&nbsp;b);<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">return</span>&nbsp;c;<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;}<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(117, 113, 94);line-height: 26px;">/**<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;反射方式<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(117, 113, 94);line-height: 26px;">@Override</span><br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;line-height: 26px;"><span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">int</span>&nbsp;<span style="outline: 0px;color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">add</span><span style="outline: 0px;line-height: 26px;">(<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">int</span>&nbsp;a,&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">int</span>&nbsp;b)</span>&nbsp;</span>{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">return</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;CalculatorCore().add(a,&nbsp;b);<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;}<br style="outline: 0px;">}<br style="outline: 0px;"></code></pre> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;line-height: 1.75em;"> <span style="outline: 0px;font-size: 16px;">这里注入</span> <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;outline: 0px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span style="outline: 0px;font-size: 16px;">CalculatorCore</span></code> <span style="outline: 0px;font-size: 16px;">的目的是为了验证在注解模式下,系统可以完整的构造出bean的依赖体系,并注册到当前spring容器中。</span> <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;outline: 0px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span style="outline: 0px;font-size: 16px;">CalculatorCore</span></code> <span style="outline: 0px;font-size: 16px;">的代码如下:</span> </section> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;"><code style="padding: 16px;outline: 0px;overflow-x: auto;background: rgb(39, 40, 34);color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;"><span style="outline: 0px;color: rgb(117, 113, 94);line-height: 26px;">@Service</span><br style="outline: 0px;"><span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="outline: 0px;line-height: 26px;"><span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">class</span>&nbsp;<span style="outline: 0px;font-weight: bold;color: white;line-height: 26px;">CalculatorCore</span>&nbsp;</span>{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;line-height: 26px;"><span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">int</span>&nbsp;<span style="outline: 0px;color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">add</span><span style="outline: 0px;line-height: 26px;">(<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">int</span>&nbsp;a,&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">int</span>&nbsp;b)</span>&nbsp;</span>{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">return</span>&nbsp;a+b;<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;}<br style="outline: 0px;">}<br style="outline: 0px;"></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 20px;"><strong style="outline: 0px;">反射方式热部署</strong></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;line-height: 26px;"><span style="outline: 0px;font-size: 16px;">用户把jar包上传到系统的指定目录下,这里定义上传jar文件路径为jarAddress,jar的Url路径为jarPath。</span></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;"><code style="padding: 16px;outline: 0px;overflow-x: auto;background: rgb(39, 40, 34);color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;"><span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">private</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">static</span>&nbsp;String&nbsp;jarAddress&nbsp;=&nbsp;<span style="outline: 0px;color: rgb(166, 226, 46);line-height: 26px;">"E:/zzq/IDEA_WS/CalculatorTest/lib/Calculator.jar"</span>;<br style="outline: 0px;"><span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">private</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">static</span>&nbsp;String&nbsp;jarPath&nbsp;=&nbsp;<span style="outline: 0px;color: rgb(166, 226, 46);line-height: 26px;">"file:/"</span>&nbsp;+&nbsp;jarAddress;<br style="outline: 0px;"></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;line-height: 26px;"><span style="outline: 0px;font-size: 16px;">并且可以要求用户填写jar包中接口实现类的完整类名。接下来系统要把上传的jar包加载到当前线程的类加载器中,然后通过完整类名,加载得到该实现的Class对象。然后反射调用即可,完整代码:</span></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;"><code style="padding: 16px;outline: 0px;overflow-x: auto;background: rgb(39, 40, 34);color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;"><span style="outline: 0px;color: rgb(117, 113, 94);line-height: 26px;">/**<br style="outline: 0px;">&nbsp;*&nbsp;热加载Calculator接口的实现&nbsp;反射方式<br style="outline: 0px;">&nbsp;*/</span><br style="outline: 0px;"><span style="outline: 0px;line-height: 26px;"><span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">static</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">void</span>&nbsp;<span style="outline: 0px;color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">hotDeployWithReflect</span><span style="outline: 0px;line-height: 26px;">()</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">throws</span>&nbsp;Exception&nbsp;</span>{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;URLClassLoader&nbsp;urlClassLoader&nbsp;=&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;URLClassLoader(<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;URL[]{<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;URL(jarPath)},&nbsp;Thread.currentThread().getContextClassLoader());<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;Class&nbsp;clazz&nbsp;=&nbsp;urlClassLoader.loadClass(<span style="outline: 0px;color: rgb(166, 226, 46);line-height: 26px;">"com.nci.cetc15.calculator.impl.CalculatorImpl"</span>);<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;Calculator&nbsp;calculator&nbsp;=&nbsp;(Calculator)&nbsp;clazz.newInstance();<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">int</span>&nbsp;result&nbsp;=&nbsp;calculator.add(<span style="outline: 0px;line-height: 26px;">1</span>,&nbsp;<span style="outline: 0px;line-height: 26px;">2</span>);<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(result);<br style="outline: 0px;">}<br style="outline: 0px;"></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 20px;"><strong style="outline: 0px;">注解方式热部署</strong></h3> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;line-height: 1.75em;"> <span style="outline: 0px;font-size: 16px;">如果用户上传的jar包含了spring的上下文,那么就需要扫描jar包里的所有需要注入spring容器的bean,注册到当前系统的spring容器中。其实,这就是一个类的热加载+动态注册的过程。</span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;line-height: 1.75em;"> <span style="outline: 0px;font-size: 16px;">直接上代码:</span> </section> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;"><code style="padding: 16px;outline: 0px;overflow-x: auto;background: rgb(39, 40, 34);color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;"><span style="outline: 0px;color: rgb(117, 113, 94);line-height: 26px;">/**<br style="outline: 0px;">&nbsp;*&nbsp;加入jar包后&nbsp;动态注册bean到spring容器,包括bean的依赖<br style="outline: 0px;">&nbsp;*/</span><br style="outline: 0px;"><span style="outline: 0px;line-height: 26px;"><span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">static</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">void</span>&nbsp;<span style="outline: 0px;color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">hotDeployWithSpring</span><span style="outline: 0px;line-height: 26px;">()</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">throws</span>&nbsp;Exception&nbsp;</span>{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;Set&lt;String&gt;&nbsp;classNameSet&nbsp;=&nbsp;DeployUtils.readJarFile(jarAddress);<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;URLClassLoader&nbsp;urlClassLoader&nbsp;=&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;URLClassLoader(<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;URL[]{<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;URL(jarPath)},&nbsp;Thread.currentThread().getContextClassLoader());<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">for</span>&nbsp;(String&nbsp;className&nbsp;:&nbsp;classNameSet)&nbsp;{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class&nbsp;clazz&nbsp;=&nbsp;urlClassLoader.loadClass(className);<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">if</span>&nbsp;(DeployUtils.isSpringBeanClass(clazz))&nbsp;{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BeanDefinitionBuilder&nbsp;beanDefinitionBuilder&nbsp;=&nbsp;BeanDefinitionBuilder.genericBeanDefinition(clazz);<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;defaultListableBeanFactory.registerBeanDefinition(DeployUtils.transformName(className),&nbsp;beanDefinitionBuilder.getBeanDefinition());<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;}<br style="outline: 0px;">}<br style="outline: 0px;"></code></pre> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;line-height: 1.75em;"> <span style="outline: 0px;font-size: 16px;">在这个过程中,将jar加载到当前线程类加载器的过程和之前反射方式是一样的。然后扫描jar包下所有的类文件,获取到完整类名,并使用当前线程类加载器加载出该类名对应的class对象。判断该class对象是否带有spring的注解,如果包含,则将该对象注册到系统的spring容器中。</span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;line-height: 1.75em;"> <span style="outline: 0px;font-size: 16px;">DeployUtils包含读取jar包所有类文件的方法、判断class对象是否包含sping注解的方法、获取注册对象对象名的方法。代码如下:</span> </section> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;"><code style="padding: 16px;outline: 0px;overflow-x: auto;background: rgb(39, 40, 34);color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;"><span style="outline: 0px;color: rgb(117, 113, 94);line-height: 26px;">/**<br style="outline: 0px;">&nbsp;*&nbsp;读取jar包中所有类文件<br style="outline: 0px;">&nbsp;*/</span><br style="outline: 0px;"><span style="outline: 0px;line-height: 26px;"><span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">static</span>&nbsp;Set&lt;String&gt;&nbsp;<span style="outline: 0px;color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">readJarFile</span><span style="outline: 0px;line-height: 26px;">(String&nbsp;jarAddress)</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">throws</span>&nbsp;IOException&nbsp;</span>{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;Set&lt;String&gt;&nbsp;classNameSet&nbsp;=&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;HashSet&lt;&gt;();<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;JarFile&nbsp;jarFile&nbsp;=&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;JarFile(jarAddress);<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;Enumeration&lt;JarEntry&gt;&nbsp;entries&nbsp;=&nbsp;jarFile.entries();<span style="outline: 0px;color: rgb(117, 113, 94);line-height: 26px;">//遍历整个jar文件</span><br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">while</span>&nbsp;(entries.hasMoreElements())&nbsp;{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JarEntry&nbsp;jarEntry&nbsp;=&nbsp;entries.nextElement();<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;name&nbsp;=&nbsp;jarEntry.getName();<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">if</span>&nbsp;(name.endsWith(<span style="outline: 0px;color: rgb(166, 226, 46);line-height: 26px;">".class"</span>))&nbsp;{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;className&nbsp;=&nbsp;name.replace(<span style="outline: 0px;color: rgb(166, 226, 46);line-height: 26px;">".class"</span>,&nbsp;<span style="outline: 0px;color: rgb(166, 226, 46);line-height: 26px;">""</span>).replaceAll(<span style="outline: 0px;color: rgb(166, 226, 46);line-height: 26px;">"/"</span>,&nbsp;<span style="outline: 0px;color: rgb(166, 226, 46);line-height: 26px;">"."</span>);<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;classNameSet.add(className);<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;}<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">return</span>&nbsp;classNameSet;<br style="outline: 0px;">}<br style="outline: 0px;"></code></pre> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;"><code style="padding: 16px;outline: 0px;overflow-x: auto;background: rgb(39, 40, 34);color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;"><span style="outline: 0px;color: rgb(117, 113, 94);line-height: 26px;">/**<br style="outline: 0px;">&nbsp;*&nbsp;方法描述&nbsp;判断class对象是否带有spring的注解<br style="outline: 0px;">&nbsp;*/</span><br style="outline: 0px;"><span style="outline: 0px;line-height: 26px;"><span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">static</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">boolean</span>&nbsp;<span style="outline: 0px;color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">isSpringBeanClass</span><span style="outline: 0px;line-height: 26px;">(Class&lt;?&gt;&nbsp;cla)</span>&nbsp;</span>{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">if</span>&nbsp;(cla&nbsp;==&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">null</span>)&nbsp;{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">return</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">false</span>;<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;}<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(117, 113, 94);line-height: 26px;">//是否是接口</span><br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">if</span>&nbsp;(cla.isInterface())&nbsp;{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">return</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">false</span>;<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;}<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(117, 113, 94);line-height: 26px;">//是否是抽象类</span><br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">if</span>&nbsp;(Modifier.isAbstract(cla.getModifiers()))&nbsp;{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">return</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">false</span>;<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;}<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">if</span>&nbsp;(cla.getAnnotation(Component<span style="outline: 0px;line-height: 26px;">.<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">class</span>)&nbsp;!</span>=&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">null</span>)&nbsp;{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">return</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">true</span>;<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;}<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">if</span>&nbsp;(cla.getAnnotation(Repository<span style="outline: 0px;line-height: 26px;">.<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">class</span>)&nbsp;!</span>=&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">null</span>)&nbsp;{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">return</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">true</span>;<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;}<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">if</span>&nbsp;(cla.getAnnotation(Service<span style="outline: 0px;line-height: 26px;">.<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">class</span>)&nbsp;!</span>=&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">null</span>)&nbsp;{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">return</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">true</span>;<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;}<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">return</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">false</span>;<br style="outline: 0px;">}<br style="outline: 0px;"></code></pre> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;"><code style="padding: 16px;outline: 0px;overflow-x: auto;background: rgb(39, 40, 34);color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;"><span style="outline: 0px;color: rgb(117, 113, 94);line-height: 26px;">/**<br style="outline: 0px;">&nbsp;*&nbsp;类名首字母小写&nbsp;作为spring容器beanMap的key<br style="outline: 0px;">&nbsp;*/</span><br style="outline: 0px;"><span style="outline: 0px;line-height: 26px;"><span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">static</span>&nbsp;String&nbsp;<span style="outline: 0px;color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">transformName</span><span style="outline: 0px;line-height: 26px;">(String&nbsp;className)</span>&nbsp;</span>{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;tmpstr&nbsp;=&nbsp;className.substring(className.lastIndexOf(<span style="outline: 0px;color: rgb(166, 226, 46);line-height: 26px;">"."</span>)&nbsp;+&nbsp;<span style="outline: 0px;line-height: 26px;">1</span>);<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">return</span>&nbsp;tmpstr.substring(<span style="outline: 0px;line-height: 26px;">0</span>,&nbsp;<span style="outline: 0px;line-height: 26px;">1</span>).toLowerCase()&nbsp;+&nbsp;tmpstr.substring(<span style="outline: 0px;line-height: 26px;">1</span>);<br style="outline: 0px;">}<br style="outline: 0px;"></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 20px;"><strong style="outline: 0px;">删除jar时,需要同时删除spring容器中注册的bean</strong></h3> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;line-height: 1.75em;"> <span style="outline: 0px;font-size: 16px;">在jar包切换或删除时,需要将之前注册到spring容器的bean删除。spring容器的bean的删除操作和注册操作是相逆的过程,这里要注意使用同一个spring上下文。</span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;line-height: 1.75em;"> <span style="outline: 0px;font-size: 16px;">代码如下:</span> </section> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;"><code style="padding: 16px;outline: 0px;overflow-x: auto;background: rgb(39, 40, 34);color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;"><span style="outline: 0px;color: rgb(117, 113, 94);line-height: 26px;">/**<br style="outline: 0px;">&nbsp;*&nbsp;删除jar包时&nbsp;需要在spring容器删除注入<br style="outline: 0px;">&nbsp;*/</span><br style="outline: 0px;"><span style="outline: 0px;line-height: 26px;"><span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">static</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">void</span>&nbsp;<span style="outline: 0px;color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">delete</span><span style="outline: 0px;line-height: 26px;">()</span>&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">throws</span>&nbsp;Exception&nbsp;</span>{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;Set&lt;String&gt;&nbsp;classNameSet&nbsp;=&nbsp;DeployUtils.readJarFile(jarAddress);<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;URLClassLoader&nbsp;urlClassLoader&nbsp;=&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;URLClassLoader(<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;URL[]{<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;URL(jarPath)},&nbsp;Thread.currentThread().getContextClassLoader());<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">for</span>&nbsp;(String&nbsp;className&nbsp;:&nbsp;classNameSet)&nbsp;{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class&nbsp;clazz&nbsp;=&nbsp;urlClassLoader.loadClass(className);<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">if</span>&nbsp;(DeployUtils.isSpringBeanClass(clazz))&nbsp;{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;defaultListableBeanFactory.removeBeanDefinition(DeployUtils.transformName(className));<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;}<br style="outline: 0px;">}<br style="outline: 0px;"></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 20px;"><strong style="outline: 0px;">测试</strong></h3> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;line-height: 1.75em;"> <span style="outline: 0px;font-size: 16px;">测试类手动模拟用户上传jar的功能。测试函数写了个死循环,一开始没有找到jar会抛出异常,捕获该异常并睡眠10秒。这时候可以把jar手动放到指定的目录下。</span> </section> <section style="padding-top: 8px;padding-bottom: 8px;outline: 0px;line-height: 1.75em;"> <span style="outline: 0px;font-size: 16px;">代码如下:</span> </section> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;"><code style="padding: 16px;outline: 0px;overflow-x: auto;background: rgb(39, 40, 34);color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;">&nbsp;ApplicationContext&nbsp;applicationContext&nbsp;=&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;ClassPathXmlApplicationContext(<span style="outline: 0px;color: rgb(166, 226, 46);line-height: 26px;">"applicationContext.xml"</span>);<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;DefaultListableBeanFactory&nbsp;defaultListableBeanFactory&nbsp;=&nbsp;(DefaultListableBeanFactory)&nbsp;applicationContext.getAutowireCapableBeanFactory();<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">while</span>&nbsp;(<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">true</span>)&nbsp;{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">try</span>&nbsp;{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hotDeployWithReflect();<br style="outline: 0px;"><span style="outline: 0px;color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hotDeployWithSpring();</span><br style="outline: 0px;"><span style="outline: 0px;color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete();</span><br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="outline: 0px;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">catch</span>&nbsp;(Exception&nbsp;e)&nbsp;{<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(<span style="outline: 0px;line-height: 26px;">1000</span>&nbsp;*&nbsp;<span style="outline: 0px;line-height: 26px;">10</span>);<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br style="outline: 0px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br style="outline: 0px;"></code></pre> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="margin-bottom: 0px;outline: 0px;"> <section style="outline: 0px;"> <span style="color: rgb(136, 136, 136);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 12px;letter-spacing: 0.544px;text-wrap: wrap;background-color: rgb(255, 255, 255);">原文:</span> <span style="color: rgb(136, 136, 136);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 12px;letter-spacing: 0.544px;text-wrap: wrap;background-color: rgb(255, 255, 255);">https://blog.csdn.net/zhangzhiqiang_0912</span> </section> </section>

解放大脑:ChatGPT + PlantUML = 不用画图了

作者:微信小助手

<p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">对于程序员来说,写文档这件事是绝大多数程序员不喜欢甚至非常讨厌的一件事儿,枯燥、乏味。我本身其实并不太排斥写文档、画图这些,当然了,比起写代码来说,我还是更喜欢写代码的。</span></p> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">但是写文档和补文档是两码事,有类似经历的同学应该能够理解,懂的都懂。项目开始前写文档还好,比如写登录功能、画登录流程图,这其实是一个设计的过程,写好文档后可以直接作为开发指导,还是很有价值的。而项目完成后补文档,感觉就是在浪费生命。</span></p> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">刚写的时候还行,一边写一边画图,还有精力注意图的美感,写了两天就彻底放飞了,美感不美感的放一边,关键是已经不想画了。</span></p> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">于是我找到了这个方法,用 ChatGPT 直接生成 PlantUML,微调一下就可以了,甚至有的调都不调,直接用了。</span></p> <h2 data-tool="mdnice编辑器" style="margin-top: 20px;margin-left: 0px;margin-right: 0px;"><span style="font-size: 15px;"><span style="color: rgb(34, 34, 34);line-height: 1.5em;letter-spacing: 0em;font-weight: 700;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">什么是 PlantUML</span></span></h2> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">PlantUML是一个通用性很强的工具,可以快速、直接地创建各种图表。利用简单直观的语言,用户可以毫不费力地绘制各种类型的图表。支持序列图、用例图、类图、对象图、活动图、组件图、部署图、状态图、时序图。</span></p> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">「毫不费力」这个特点非常有吸引力,当然没那么夸张,还是要费点力气的。它有自己的一套语法,类似于写代码的方式表示各个实体之间的关系、指示要生成哪种类型的图。用过 Markdown 的一下就能理解。</span></p> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">举个例子,下面的代码可以表示 Client 向 Server 发送 Hello。</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;margin-top: 10px;margin-bottom: 10px;"><p style="overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;margin-left: 0px;margin-right: 0px;"><span style="font-size: 14px;">@startuml<br>!theme&nbsp;materia-outline<br>Client&nbsp;-&gt;&nbsp;Server&nbsp;:&nbsp;Hello<br>@enduml</span></p></pre> <p style="margin-bottom: 0px;background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;font-family: Georgia, &quot;SF Pro Text&quot;, &quot;SF Pro Icons&quot;, &quot;Helvetica Neue&quot;, PingFangTC-light, PingFang-SC-light, Helvetica, Arial, sans-serif;font-size: 16px;color: rgb(0, 0, 0);line-height: 1.5em;word-spacing: 3px;letter-spacing: 5px;word-break: break-word;text-align: left;margin-left: 0px;margin-right: 0px;"><br></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: visible;"> <img class="rich_pages wxw-img" data-imgfileid="301989899" data-ratio="0.6269592476489029" src="/upload/f10db2b085a467b6a46802004ede4a1b.png" data-type="png" data-w="319" style="display: block;margin-top: 20px;margin-bottom: 20px;max-width: 90%;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> </figure> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">如果你想自己用它的语法规则,通过写代码的方式画图,可以到官网 https://plantuml.com/zh/ 上学习一下语法。</span></p> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">可以直接在 PlantUML 在线环境上运行</span></p> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;"> https://www.plantuml.com/plantuml/uml/SyfFKj2rKt3CoKnELR1Io4ZDoSa70000</span></p> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">上方写代码,下面就直接生成对应的 UML 图了,可以调整样式,可以下载各种格式的图片。</span></p> <p><img class="rich_pages wxw-img" data-imgfileid="301989902" data-ratio="0.5416666666666666" src="/upload/10b1366493c084f505e4464f7cb08a22.png" data-type="png" data-w="1080" style="display: block;margin-top: 20px;margin-bottom: 20px;max-width: 90%;border-radius: 6px;object-fit: contain;box-shadow: rgb(180, 180, 180) 0em 0em 0.5em 0px;"></p> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">也可以在本地安装运行,支持 Java 包运行,也支持 Docker 。</span></p> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">另外,像 VSCode 这些编辑器或者一些笔记软件都有对应的插件支持,可以搜索安装。</span></p> <h2 data-tool="mdnice编辑器" style="margin-top: 20px;margin-left: 0px;margin-right: 0px;"><span style="font-size: 15px;"><span style="color: rgb(34, 34, 34);line-height: 1.5em;letter-spacing: 0em;font-weight: 700;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">ChatGPT + PlantUML</span></span></h2> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">如果你还是觉得不够「毫不费力」,那可以让 ChatGPT 直接生成给你。</span></p> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">打开 ChatGPT ,在「探索 GPT」里面可以搜索 “PlantUML Diagram Wizard”,这个应用是专门用来帮你画 PlantUML 的,但是使用的话需要 GPT-4o,如果超过最大限制,则需要开通 plus 才能用,有实力的同学可以用这个。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: visible;"> <img class="rich_pages wxw-img" data-imgfileid="301989901" data-ratio="0.42685185185185187" src="/upload/41196a9b4dac0ee2c9573d2d983d67ff.png" data-type="png" data-w="1080" style="display: block;margin-top: 20px;margin-bottom: 20px;max-width: 90%;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> </figure> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">不用它也完全可以,我就直接用的免费版 ChatGPT-3.5,效果也没有问题。除此之外,用 Kimi 等大模型应该也问题不大。</span></p> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">那应该怎么给 ChatGPT 提示词呢?</span></p> <ol data-tool="mdnice编辑器" style="margin: 8px 0px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 1.8em;letter-spacing: 0em;"> <span style="font-size: 15px;">首先你必须知道你要画的是什么类型的图,序列图、用例图、类图、对象图、活动图、组件图、部署图、状态图、时序图,类型关键词必须准确给到 GPT。</span> </section></li> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 1.8em;letter-spacing: 0em;"> <span style="font-size: 15px;">描述要清晰,这是必须的,就像你解释给别人一样,只不过 GPT 的理解能力更强一些。</span> </section></li> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 1.8em;letter-spacing: 0em;"> <span style="font-size: 15px;">如果有代码的话,必要情况下给一些解释。</span> </section></li> </ol> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">下面我举几个例子,不一定是最好的,但是基本上能解决问题。</span></p> <h3 data-tool="mdnice编辑器" style="margin: 30px 0px 15px;"><span style="font-size: 15px;"><span style="color: rgb(34, 34, 34);line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;">画类图</span></span></h3> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">有时候 IDEA 能解决一部分问题,比如我查看一个 </span><code style="font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);"><span style="font-size: 15px;">serverImpl</span></code><span style="font-size: 15px;">的类图,但是更大范围的关系就不行了,比如我还想看到 Controller 调用 Service 的关系。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: visible;"> <img class="rich_pages wxw-img" data-imgfileid="301989900" data-ratio="0.5527777777777778" src="/upload/6b59856f2c02b0f698eddb2f6960c01a.png" data-type="png" data-w="1080" style="display: block;margin-top: 20px;margin-bottom: 20px;max-width: 90%;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> </figure> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">用 ChatGPT 怎么做呢?</span></p> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">第一步就是将代码给到 ChatGPT。这一步要看你的代码量有多少,如果代码量不多的话,可以一次性都给它,如果多的话,ChatGPT 的输入token 是有限制的,就要分批次告诉它。</span></p> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">第一步 prompt:</span><code style="font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);"><span style="font-size: 15px;">接下来我会发给你几个 java 文件,在我告诉你开始画图之前,你只需要记住文件的内容就好了</span></code><span style="font-size: 15px;">。之后GPT会表示明白了,请你发送文件内容。</span></p> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">第二步:将你要画的文件一个个的输送给 GPT。</span></p> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">第三步:</span><code style="font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);"><span style="font-size: 15px;">好了,请帮我生成 PlantUML 格式的类图,请开始画图吧</span></code><span style="font-size: 15px;">。</span></p> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">然后 GPT 就会输出一个 PlantUML 代码段。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: visible;"> <img class="rich_pages wxw-img" data-imgfileid="301989911" data-ratio="1.0425925925925925" src="/upload/f69fa54b53627731b7c22d61d089c131.png" data-type="png" data-w="1080" style="margin-top: 20px;margin-bottom: 20px;max-width: 90%;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> </figure> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">之后粘贴到 https://www.plantuml.com/plantuml/uml/SyfFKj2rKt3CoKnELR1Io4ZDoSa70000 &nbsp;在线环境中,然后选一个主题,就可以把图弄下来了。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: visible;"> <img class="rich_pages wxw-img" data-imgfileid="301989905" data-ratio="0.6666666666666666" src="/upload/9b6b7c233fca85678cfefa5530ee0e49.png" data-type="png" data-w="1080" style="display: block;margin-top: 20px;margin-bottom: 20px;max-width: 90%;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> </figure> <h2 data-tool="mdnice编辑器" style="margin-top: 20px;margin-left: 0px;margin-right: 0px;"><span style="font-size: 15px;"><span style="color: rgb(34, 34, 34);line-height: 1.5em;letter-spacing: 0em;font-weight: 700;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">时序图</span></span></h2> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">接下来我将一个登录流程的描述告诉 GPT 让它画出时序图。</span></p> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">prompt 如下:</span></p> <blockquote data-tool="mdnice编辑器" style="margin-top: 20px;margin-bottom: 20px;border-style: none;border-top-width: 3px;border-bottom-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);width: auto;height: auto;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;overflow: auto;border-left-width: initial;border-left-color: initial;padding-top: 15px;padding-right: 10px;padding-bottom: 15px;line-height: 1.75;border-radius: 13px;color: rgb(53, 53, 53);background: rgb(245, 245, 245);"> <p style="letter-spacing: 0em;display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;margin-left: 0px;margin-right: 0px;"><span style="font-size: 15px;">“</span></p> <p style="text-indent: 0em;padding-top: 8px;padding-bottom: 8px;line-height: 1.8em;letter-spacing: 0em;font-size: 16px;margin-left: 0px;margin-right: 0px;"><span style="font-size: 15px;">以客户端、登录服务、数据库为3个主体,画出整个登录过程的Sequence diagrams:客户端输入手机号,调用登录服务,查询数据库,查看手机号是否存在,如果不存在,直接通知客户端用户不存,如果存在,登录服务查询数据库验证手机号和密码是否匹配,如果匹配,返回用户信息,客户端跳转到首页</span></p> <p style="float: right;display: block;font-size: 2em;color: rgb(248, 57, 41);font-family: Arial, serif;line-height: 1em;font-weight: 700;margin-left: 0px;margin-right: 0px;"><span style="font-size: 15px;">”</span></p> </blockquote> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">其实描述的并不是那么条理很清晰,但是 GPT 比较聪明,它能理解。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: visible;"> <img class="rich_pages wxw-img" data-imgfileid="301989908" data-ratio="1.000925925925926" src="/upload/78fb421afa54361d8ede654a56f442b8.png" data-type="png" data-w="1080" style="display: block;margin-top: 20px;margin-bottom: 20px;max-width: 90%;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> </figure> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">最后还是粘贴到在线环境上,查看并下载最终的UML图。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: visible;"> <img class="rich_pages wxw-img" data-imgfileid="301989906" data-ratio="0.5472222222222223" src="/upload/8130f94ba9a7582a15d90b44bd154e43.png" data-type="png" data-w="1080" style="display: block;margin-top: 20px;margin-bottom: 20px;max-width: 90%;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> </figure> <p style="font-size: 15px;line-height: 1.8;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;margin: 0.6em 0px;"><span style="font-size: 15px;">怎么样,是不是能够偷下懒了。</span></p>

直接编辑修改jar包——JarEditor

作者:微信小助手

<h2 style="margin-top: 15px;margin-bottom: 15px;line-height: 1.5;font-size: 1.45rem;border-bottom: 1px solid var(--border-color-b);opacity: 0.98;color: rgb(36, 36, 36);font-family: Ubuntu, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Oxygen, Cantarell, &quot;Fira Sans&quot;, &quot;Droid Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif;letter-spacing: normal;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">反编译Jar包</h2> <blockquote style="margin-top: 10px;margin-bottom: 10px;border-left: 5px solid var(--primary-color);padding: 10px 15px;color: rgb(36, 36, 36);font-family: Ubuntu, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Oxygen, Cantarell, &quot;Fira Sans&quot;, &quot;Droid Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif;letter-spacing: normal;text-align: left;white-space: normal;"> <p>反编译Jar包,修改class文件,是开发过程中经常遇到的,特别是修改第三方程序修复问题的时候。通常都通过反编译class再编译成class,再替换回jar文件,过程比较麻烦。</p> </blockquote> <p style="margin-bottom: 0px;color: rgb(36, 36, 36);font-family: Ubuntu, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Oxygen, Cantarell, &quot;Fira Sans&quot;, &quot;Droid Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif;font-size: 15px;letter-spacing: normal;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">推荐一款IDEA插件工具,可以直接编辑Jar文件,使用非常方便。</p> <h2 style="margin-top: 15px;margin-bottom: 15px;line-height: 1.5;font-size: 1.45rem;border-bottom: 1px solid var(--border-color-b);opacity: 0.98;color: rgb(36, 36, 36);font-family: Ubuntu, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Oxygen, Cantarell, &quot;Fira Sans&quot;, &quot;Droid Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif;letter-spacing: normal;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">直接编辑 jar 工具——JarEditor</h2> <p style="margin-bottom: 0px;color: rgb(36, 36, 36);font-family: Ubuntu, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Oxygen, Cantarell, &quot;Fira Sans&quot;, &quot;Droid Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif;font-size: 15px;letter-spacing: normal;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">安装插件<br><img class="rich_pages wxw-img" data-imgfileid="100000600" data-ratio="0.8388704318936877" src="/upload/2f0b8aeae6077a87b8a70af0932530de.png" data-type="png" data-w="602" style="vertical-align: middle;border-style: none;margin-top: 8px;margin-bottom: 8px;border-radius: 5px;display: block;cursor: pointer;"></p> <p style="margin-bottom: 0px;color: rgb(36, 36, 36);font-family: Ubuntu, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Oxygen, Cantarell, &quot;Fira Sans&quot;, &quot;Droid Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif;font-size: 15px;letter-spacing: normal;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><br></p> <p style="margin-bottom: 0px;color: rgb(36, 36, 36);font-family: Ubuntu, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Oxygen, Cantarell, &quot;Fira Sans&quot;, &quot;Droid Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif;font-size: 15px;letter-spacing: normal;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">使用插件,编辑Jar文件<br><img class="rich_pages wxw-img" data-imgfileid="100000601" data-ratio="0.5483870967741935" src="/upload/7663f75a24563fe29090e9b517e4cb4f.png" data-type="png" data-w="1054" style="vertical-align: middle;border-style: none;margin-top: 8px;margin-bottom: 8px;border-radius: 5px;display: block;cursor: pointer;">切换 Jar Editor 编辑可直接修改Class,修改完之后点击 Save 保存并编译修改内容,然后点击 Build Jar 即可将编译保存的 class 文件写入到 Jar 包内。</p> <p style="margin-bottom: 0px;color: rgb(36, 36, 36);font-family: Ubuntu, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Oxygen, Cantarell, &quot;Fira Sans&quot;, &quot;Droid Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif;font-size: 15px;letter-spacing: normal;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><br><img class="rich_pages wxw-img" data-imgfileid="100000599" data-ratio="0.2554517133956386" src="/upload/7eb88898113a4faf1887863dfd3dc4c5.png" data-type="png" data-w="642" style="vertical-align: middle;border-style: none;margin-top: 8px;margin-bottom: 8px;border-radius: 5px;display: block;cursor: pointer;">在 jar 文件右键,可看到 JarEditor 的 New 和 Delete 操作,可以新增文件和删除文件。</p> <p><br></p> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>

图解 Jenkins Pipeline 的前端自动化部署,用上后真香!

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="margin-bottom: 0px;padding-left: 10px;padding-right: 10px;background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;font-family: Optima, PingFangSC-light, serif;font-size: 16px;color: rgb(0, 0, 0);line-height: 1.5em;word-spacing: 0em;letter-spacing: 0em;word-break: break-word;text-align: left;" data-mpa-powered-by="yiban.io"> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">你好,我是悟空。</p> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;"><span style="font-size: 13px;color: rgb(0, 0, 0);">本文目录如下:</span></p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li style="font-size: 13px;color: rgb(0, 0, 0);"><p><span style="font-size: 13px;color: rgb(0, 0, 0);">一、Jenkins 前端部署思路</span></p></li> <ul style="list-style-type: square;margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li style="font-size: 13px;color: rgb(0, 0, 0);"><p><span style="font-size: 13px;color: rgb(0, 0, 0);">1.1 整体架构图</span></p></li> <li style="font-size: 13px;color: rgb(0, 0, 0);"><p><span style="font-size: 13px;color: rgb(0, 0, 0);">1.2 部署步骤</span></p></li> </ul> <li style="font-size: 13px;"><p>二、Pipeline和自由风格对比</p></li> <li style="font-size: 13px;color: rgb(0, 0, 0);"><p><span style="font-size: 13px;color: rgb(0, 0, 0);">三、Pipeline 核心脚本</span></p></li> <ul style="list-style-type: square;margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li style="font-size: 13px;color: rgb(0, 0, 0);"><p><span style="font-size: 13px;color: rgb(0, 0, 0);">3.1 获取 Git 代码分支</span></p></li> <li style="font-size: 13px;color: rgb(0, 0, 0);"><p><span style="font-size: 13px;color: rgb(0, 0, 0);">3.2 拷贝依赖包</span></p></li> <li style="font-size: 13px;color: rgb(0, 0, 0);"><p><span style="font-size: 13px;color: rgb(0, 0, 0);">3.3 编译代码</span></p></li> <li style="font-size: 13px;color: rgb(0, 0, 0);"><p><span style="font-size: 13px;color: rgb(0, 0, 0);">3.4 备份代码</span></p></li> <li style="font-size: 13px;color: rgb(0, 0, 0);"><p><span style="font-size: 13px;color: rgb(0, 0, 0);">3.5 上传代码</span></p></li> <li style="font-size: 13px;color: rgb(0, 0, 0);"><p><span style="font-size: 13px;color: rgb(0, 0, 0);">3.6 更新代码</span></p></li> <li style="font-size: 13px;color: rgb(0, 0, 0);"><p><span style="font-size: 13px;color: rgb(0, 0, 0);">3.7 清理代码</span></p></li> <li style="font-size: 13px;color: rgb(0, 0, 0);"><p><span style="font-size: 13px;color: rgb(0, 0, 0);">3.8 邮件通知</span></p></li> </ul> <li style="font-size: 13px;color: rgb(0, 0, 0);"><p><span style="border-radius: 0px;border-width: initial;border-style: none;border-color: initial;font-size: 13px;color: rgb(0, 0, 0);">四、总结</span><span style="color: rgb(53, 53, 53);font-size: 16px;letter-spacing: 0.04em;text-indent: 0em;background-color: rgba(0, 0, 0, 0.05);word-spacing: 0em;"></span></p></li> </ul> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;border-style: none;border-width: 1px;border-color: rgb(0, 0, 0);border-radius: 0px;box-shadow: none;flex-direction: unset;float: unset;height: auto;justify-content: unset;line-height: 1.5em;overflow: unset;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="font-size: 18px;color: rgb(34, 34, 34);line-height: 1.8em;letter-spacing: 0em;padding-left: 10px;border-style: none none none solid;border-width: 1px 1px 1px 5px;border-color: rgb(0, 0, 0) rgb(0, 0, 0) rgb(0, 0, 0) rgb(248, 57, 41);border-radius: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;box-shadow: none;display: block;font-weight: bold;flex-direction: unset;float: unset;height: auto;justify-content: unset;overflow: unset;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;">二、Jenkins 前端部署思路</span></h2> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;display: flex;"><span style="line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;">1.1 整体架构图</span></h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="304487900" data-ratio="0.7518518518518519" src="/upload/402f108e7bb9e8c174fc40f0fc0a64f2.png" data-type="png" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 16px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;display: flex;"><span style="line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;">1.2 部署步骤</span></h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="304487901" data-ratio="1.8877551020408163" src="/upload/b90c02f062625985bbcf8bed4ddfc9a8.png" data-type="png" data-w="588" style="display: block;margin-right: auto;margin-left: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 16px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> </figure> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;border-style: none;border-width: 1px;border-color: rgb(0, 0, 0);border-radius: 0px;box-shadow: none;flex-direction: unset;float: unset;height: auto;justify-content: unset;line-height: 1.5em;overflow: unset;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"></h2> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;color: rgb(0, 0, 0);font-family: Optima, PingFangSC-light, serif;letter-spacing: normal;text-align: left;text-wrap: wrap;align-items: unset;background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;border-style: none;border-width: 1px;border-color: rgb(0, 0, 0);border-radius: 0px;box-shadow: none;flex-direction: unset;float: unset;height: auto;justify-content: unset;line-height: 1.5em;overflow: unset;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="padding-left: 10px;font-size: 18px;color: rgb(34, 34, 34);line-height: 1.8em;letter-spacing: 0em;border-style: none none none solid;border-width: 1px 1px 1px 5px;border-color: rgb(0, 0, 0) rgb(0, 0, 0) rgb(0, 0, 0) rgb(248, 57, 41);border-radius: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;box-shadow: none;display: block;font-weight: bold;flex-direction: unset;float: unset;height: auto;justify-content: unset;overflow: unset;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;">二、Pipeline和自由风格对比</span></h2> <p data-tool="mdnice编辑器" style="margin-bottom: 0px;padding-top: 8px;padding-bottom: 8px;font-family: Optima, PingFangSC-light, serif;font-size: 16px;text-align: left;text-indent: 0em;text-wrap: wrap;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;">Jenkins是一个开源的自动化服务器,它可以帮助自动化各种任务,包括构建、测试和部署软件。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 0px;padding-top: 8px;padding-bottom: 8px;font-family: Optima, PingFangSC-light, serif;font-size: 16px;text-align: left;text-indent: 0em;text-wrap: wrap;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;">上次我们讲解了如何通过 Jenkins 的<strong style="color: rgb(248, 57, 41);background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;">自由风格的软件项目</strong>来配置前端的自动化部署,如下图所示,如何选择自由风格的软件项目。优点就是简单!</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima, PingFangSC-light, serif;font-size: 16px;letter-spacing: normal;text-align: left;text-wrap: wrap;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="304487899" data-ratio="0.30462962962962964" src="/upload/96bb027f27c5b52300af8d621d35a81b.png" data-type="png" data-w="1080" style="margin-right: auto;margin-left: auto;display: block;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 16px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> </figure> <p data-tool="mdnice编辑器" style="margin-bottom: 0px;padding-top: 8px;padding-bottom: 8px;font-family: Optima, PingFangSC-light, serif;font-size: 16px;text-align: left;text-indent: 0em;text-wrap: wrap;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;">这次我们将讲解如何通过<strong style="color: rgb(248, 57, 41);background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;">流水线(Pipeline)</strong>方式来部署前端项目。优点就是更加灵活!如下图所示,就是选择 Pipeline 方式。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima, PingFangSC-light, serif;font-size: 16px;letter-spacing: normal;text-align: left;text-wrap: wrap;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="304487898" data-ratio="0.33796296296296297" src="/upload/d5b85e296a60ac7175c52b206389e931.png" data-type="png" data-w="1080" style="margin-right: auto;margin-left: auto;display: block;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 16px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> </figure> <p data-tool="mdnice编辑器" style="margin-bottom: 0px;padding-top: 8px;padding-bottom: 8px;font-family: Optima, PingFangSC-light, serif;font-size: 16px;text-align: left;text-indent: 0em;text-wrap: wrap;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;">在Jenkins中,有两种主要类型的任务:Pipeline任务和自由风格项目(Freestyle project)。</p> <ol data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;width: 557.438px;color: rgb(0, 0, 0);font-family: Optima, PingFangSC-light, serif;font-size: 16px;letter-spacing: normal;text-align: left;text-wrap: wrap;"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> <strong style="color: rgb(248, 57, 41);background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;">Pipeline任务</strong>: </section></li> <ul class="list-paddingleft-1" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;width: 531.896px;list-style-type: disc;"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> Pipeline任务是Jenkins 2.0引入的一个新特性,它使用Jenkinsfile来定义整个构建流程。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> Jenkinsfile是一个文本文件,使用Groovy语言的DSL(领域特定语言),可以定义构建的各个阶段和步骤。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> Pipeline任务支持复杂的构建流程,包括多个阶段和步骤,以及并行执行等高级功能。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> Pipeline任务可以很容易地与源代码管理系统集成,支持持续集成(CI)和持续交付(CD)。 </section></li> </ul> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> <strong style="color: rgb(248, 57, 41);background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;">自由风格项目</strong>: </section></li> <ul class="list-paddingleft-1" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;width: 531.896px;list-style-type: disc;"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> 自由风格项目是Jenkins早期版本中的主要任务类型,允许用户通过Jenkins的Web界面配置构建步骤。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> 这种类型的项目没有固定的构建流程定义方式,用户可以手动添加构建步骤、配置插件和参数等。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> 自由风格项目适合快速设置简单的构建任务,但对于复杂的构建流程,可能不如Pipeline任务灵活和强大。 </section></li> </ul> </ol> <p data-tool="mdnice编辑器" style="margin-bottom: 0px;padding-top: 8px;padding-bottom: 8px;font-family: Optima, PingFangSC-light, serif;font-size: 16px;text-align: left;text-indent: 0em;text-wrap: wrap;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;">两者的主要区别包括:</p> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;width: 557.438px;color: rgb(0, 0, 0);font-family: Optima, PingFangSC-light, serif;font-size: 16px;letter-spacing: normal;text-align: left;text-wrap: wrap;"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> <strong style="color: rgb(248, 57, 41);background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;">定义方式</strong>:Pipeline任务通过Jenkinsfile定义,而自由风格项目通过Jenkins的Web界面配置。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> <strong style="color: rgb(248, 57, 41);background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;">灵活性和扩展性</strong>:Pipeline任务更加灵活,支持复杂的构建流程和高级功能,如并行执行和模板化。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> <strong style="color: rgb(248, 57, 41);background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;">集成度</strong>:Pipeline任务更容易与源代码管理系统集成,实现自动化的CI/CD流程。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> <strong style="color: rgb(248, 57, 41);background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;">学习和使用难度</strong>:Pipeline任务可能需要用户学习Jenkinsfile的语法和DSL,而自由风格项目则更直观,易于上手。 </section></li> </ul> <blockquote data-tool="mdnice编辑器" style="margin-top: 20px;margin-bottom: 20px;padding: 10px 10px 10px 20px;border-top: 3px none rgba(0, 0, 0, 0.4);border-right: 3px none rgba(0, 0, 0, 0.4);border-bottom: 3px none rgba(0, 0, 0, 0.4);border-left-style: none;border-left-color: rgba(0, 0, 0, 0.4);font-family: Optima, PingFangSC-light, serif;letter-spacing: normal;text-align: left;text-wrap: wrap;border-radius: 0px;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(0, 0, 0, 0.05);width: auto;height: auto;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;overflow: auto;"> <span style="display: block;color: rgb(248, 57, 41);font-size: 28px;line-height: 1.5em;letter-spacing: 0em;font-weight: bold;">“</span> <p style="padding-top: 8px;padding-bottom: 8px;text-indent: 0em;color: rgb(53, 53, 53);font-size: 16px;line-height: 1.8em;letter-spacing: 0.04em;">提示:Pipeline 任务代表了Jenkins的未来方向,提供了更高级的自动化构建能力,而自由风格项目则适合快速设置简单的构建任务。随着Jenkins的发展,越来越多的用户和组织倾向于使用Pipeline任务来实现更高效的自动化流程。</p> </blockquote> <span style="font-size: 18px;color: rgb(34, 34, 34);line-height: 1.8em;letter-spacing: 0em;padding-left: 10px;border-style: none none none solid;border-width: 1px 1px 1px 5px;border-color: rgb(0, 0, 0) rgb(0, 0, 0) rgb(0, 0, 0) rgb(248, 57, 41);border-radius: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;box-shadow: none;display: block;font-weight: bold;flex-direction: unset;float: unset;height: auto;justify-content: unset;overflow: unset;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;">三、Pipeline 核心脚本</span> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;display: flex;"><span style="line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;">3.1 获取 Git 代码分支</span></h3> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;"><span style="font-size: 18px;line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;">3.1.1 Git 分支插件</span></h4> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">用了一个插件 gitParameter,可以获取 git 仓库的分支,部署的时候,可以选择分支。如下图所示,Git 仓库有 develop 和 master 分支,默认选中 develop 分支。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="304487897" data-ratio="0.5982142857142857" src="/upload/87e9d62404a3b222968b39a00a7acba7.png" data-type="png" data-w="448" style="display: block;margin-right: auto;margin-left: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 16px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="304487903" data-ratio="1.0192926045016077" src="/upload/dfce32a0abce11a3ed78e79c94f458f5.png" data-type="png" data-w="622" style="display: block;margin-right: auto;margin-left: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 16px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;"><span style="font-size: 18px;line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;">3.1.2 Git 环境变量</span></h4> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="304487902" data-ratio="0.3397312859884837" src="/upload/febdbd37ebac2aa4827fc5ef0dbf7920.png" data-type="png" data-w="1042" style="display: block;margin-right: auto;margin-left: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 16px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;"><span style="font-size: 18px;line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;">3.1.3 获取 Git 分支代码</span></h4> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="304487905" data-ratio="0.6694444444444444" src="/upload/3f84a0a3af0a1fa23a500351290f4b8b.png" data-type="png" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 16px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> </figure> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">这个步骤中有一一行关键的代码,可以通过 Git 插件获取选择的 Git 分支。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="304487906" data-ratio="0.12222222222222222" src="/upload/8635e7be78a76227d2e4b2cdb0b4c03e.png" data-type="png" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 16px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;display: flex;"><span style="line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;">3.2 拷贝依赖包</span></h3> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">因为 node_modules 不会上传到 git 仓库,所以我们需要提前准备好。</p> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">而我们项目我是先在有网的 Linux 服务器上用 npm install 命令下载的依赖包,然后手动压缩拷贝到 jenkins 服务器的 passjava 目录。</p> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">当执行部署的时候,会从 passjava 目录将 node_modules 压缩包拷贝并解压到 jenkins 的当前工作目录。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="304487904" data-ratio="0.43333333333333335" src="/upload/83af63c4ef303031f99cc758a85b9a67.png" data-type="png" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 16px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;display: flex;"><span style="line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;">3.3 编译代码</span></h3> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">编译前端代码可以用 npm run build xx 命令,然后将编译后的 dist 目录压缩。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="304487909" data-ratio="0.549074074074074" src="/upload/395c5455dc14b30d98fae5ed3672277c.png" data-type="png" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 16px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;display: flex;"><span style="line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;">3.4 备份代码</span></h3> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">将 web 服务器上多个前端项目移动到备份目录 web-bak 。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="304487911" data-ratio="0.6027777777777777" src="/upload/83e518bffd4bb9586d9ed556a2295a94.png" data-type="png" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 16px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;display: flex;"><span style="line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;">3.5 上传代码</span></h3> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">将编译后的代码包上传到 web 服务器。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="304487908" data-ratio="1.1231481481481482" src="/upload/42ba1e4002666272df761c63752c84b3.png" data-type="png" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 16px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;display: flex;"><span style="line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;">3.6 更新代码</span></h3> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">将 dist 压缩包解压,然后将多个前端工程拷贝到 web 目录。如 passjavabase, passjava-channel, project-contract 目录拷贝到 passjava-web-micro 目录。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="304487910" data-ratio="0.5435185185185185" src="/upload/17917f493e7803b08d0eacf993124a70.png" data-type="png" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 16px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;display: flex;"><span style="line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;">3.7 清理代码</span></h3> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">清理 web 服务器上备份的代码。</p> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">以下命令是查找并删除指定路径下超过7天未修改的目录。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="304487907" data-ratio="0.1111111111111111" src="/upload/2e732ded3df95cc05b049304bfd7b63a.png" data-type="png" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 16px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> </figure> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">这条命令会找到 <code style="color: rgb(248, 57, 41);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">/nfs-data/passjava/web-bak/</code> 目录下所有超过7天未修改的子目录,并将其打印出来,然后删除这些目录。</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> <strong style="color: rgb(248, 57, 41);background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;">查找超过7天未修改的目录:</strong> </section></li> <ul style="list-style-type: disc;margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(0, 0, 0);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> <code style="background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">-mindepth 1</code>:确保查找从指定目录的子目录开始,不包括指定的根目录。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> <code style="background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">-maxdepth 1</code>:限制查找仅在指定目录的第一层子目录中进行。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> <code style="background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">-type d</code>:只考虑目录,不包括文件。“-type -f” 只考虑文件,不包括目录。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> <code style="background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">-mtime +7</code>:筛选出修改时间超过7天的目录。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> <code style="background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">-print</code>:打印出这些目录的路径。 </section></li> </ul> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> <strong style="color: rgb(248, 57, 41);background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;">删除找到的目录:</strong> </section></li> <ul style="list-style-type: disc;margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(0, 0, 0);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;"> <code style="background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">-exec rm -rf {} +</code>:对找到的每个目录执行 <code style="background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">rm -rf</code> 命令,递归且强制删除该目录及其内容。 </section></li> </ul> </ol> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">该步骤的完整代码如下:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="304487912" data-ratio="0.5638888888888889" src="/upload/1afb88a330a0d3e6c6977bd5614a2a14.png" data-type="png" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 16px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;display: flex;"><span style="line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;">3.8 邮件通知</span></h3> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">详见笔者之前写的一篇:<a href="https://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451970945&amp;idx=1&amp;sn=6acb09c9c207e02eff92bbd14e8592ba&amp;chksm=8d1fe21eba686b08ec938d97233a8554674df37b6b93eecb7a5ea685c4e16ff8951f914a255c&amp;token=1409580416&amp;lang=zh_CN&amp;scene=21#wechat_redirect" style="color: rgb(248, 57, 41);font-weight: bold;border-style: none none solid;border-width: 1px;border-color: rgb(30, 107, 184) rgb(30, 107, 184) rgb(248, 57, 41);border-radius: 0px;" data-linktype="2">持续集成:Jenkins Pipeline 邮件通知</a></p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;border-style: none;border-width: 1px;border-color: rgb(0, 0, 0);border-radius: 0px;box-shadow: none;flex-direction: unset;float: unset;height: auto;justify-content: unset;line-height: 1.5em;overflow: unset;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="font-size: 18px;color: rgb(34, 34, 34);line-height: 1.8em;letter-spacing: 0em;padding-left: 10px;border-style: none none none solid;border-width: 1px 1px 1px 5px;border-color: rgb(0, 0, 0) rgb(0, 0, 0) rgb(0, 0, 0) rgb(248, 57, 41);border-radius: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;box-shadow: none;display: block;font-weight: bold;flex-direction: unset;float: unset;height: auto;justify-content: unset;overflow: unset;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;">四、总结</span></h2> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">通过使用 Jenkins Pipeline 进行前端自动化部署,团队可以更加高效地管理和部署前端应用程序,减少人为错误和手动操作带来的风险,提升整体的开发和部署效率。</p> <p data-tool="mdnice编辑器" style="color: rgb(53, 53, 53);line-height: 1.8em;letter-spacing: 0.04em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">本文通过图解+代码的方式讲解了前端自动化部署的步骤,文中的脚本针对前端的三个模块进行打包,比较耗时,所以后续可以优化的地方是支持选择部署前端的不同模块。</p> </section>

【超实用攻略】SpringBoot开发者的福音:5分钟掌握接口防抖绝技,一劳永逸解决重复提交噩梦!

作者:微信小助手

<section data-mpa-template="t" mpa-paragraph-type="ignored" style="margin-bottom: 0px;text-wrap: wrap;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);" data-mpa-powered-by="yiban.io"> <p style="text-align: center;"><span style="word-spacing: 0.1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;letter-spacing: 0px;text-align: left;"></span><br mpa-from-tpl="t"></p> <section data-mpa-template="t" mpa-from-tpl="t"> <section mpa-from-tpl="t"> <section style="width:100%;text-align:center;" data-width="100%" mpa-from-tpl="t"> <section style="display:inline-block;width:auto;" mpa-from-tpl="t"> <section style="width: 45px;margin-right: auto;margin-bottom: -12px;margin-left: auto;background-color: #fefefe;transform: translateZ(10px);-webkit-transform: translateZ(10px);-moz-transform: translateZ(10px);-ms-transform: translateZ(10px);-o-transform: translateZ(10px);" mpa-from-tpl="t"> <img data-imgfileid="100130339" data-ratio="1" src="/upload/2f587a759a9336e658edf1970c0a8632.png" data-w="100" data-width="100%" style="display: block;width: 100%;"> </section> <section style="display:inline-block;width:auto;height:auto;" mpa-from-tpl="t"> <section style="border-width: 1px;border-style: solid;border-color: rgb(102, 102, 102);height: 40px;" mpa-from-tpl="t"> <br> </section> <section style="margin-top:-37px;margin-right:-3px;margin-bottom:-3px;margin-left:3px;" mpa-from-tpl="t"> <section style="display: inline-block;height: 40px;line-height: 40px;padding-right: 15px;padding-left: 15px;border-width: 1px;border-style: solid;border-color: rgb(255, 116, 128);width: 100%;" data-width="100%" mpa-from-tpl="t"> <p mpa-is-content="t">前言</p> </section> </section> </section> </section> </section> </section> </section> <p style="text-align: center;"><span style="word-spacing: 0.1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;letter-spacing: 0px;text-align: left;"></span></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">作为一名老码农,在开发后端Java业务系统,包括各种管理后台和小程序等。在这些项目中,我设计过单/多租户体系系统,对接过许多开放平台,也搞过消息中心这类较为复杂的应用,但幸运的是,我至今还没有遇到过线上系统由于代码崩溃导致资损的情况。这其中的原因有三点:一是业务系统本身并不复杂;二是我一直遵循某大厂代码规约,在开发过程中尽可能按规约编写代码;三是经过多年的开发经验积累,我成为了一名熟练工,掌握了一些实用的技巧。</p> <h2 data-tool="mdnice编辑器"><span style="display: none;"></span><br mpa-from-tpl="t"></h2> <section data-mpa-template="t" mpa-from-tpl="t"> <blockquote style="margin: 5px auto;padding: 0px;max-width: 100%;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 25.6px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;color: rgb(68, 153, 231);" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <blockquote style="margin: 5px auto;padding: 0px;max-width: 100%;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;text-align: center;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto -38px;padding: 0px 15px;max-width: 100%;display: inline-block;background-color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <p style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;clear: both;min-height: 1em;color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"><span style="font-family: Arial, Helvetica, sans-serif;"><strong mpa-from-tpl="t"><span style="border-color: rgb(68, 153, 231);color: rgb(255, 255, 255);font-size: 16px;" mpa-is-content="t">啥是防抖</span></strong></span></p> </section> <section style="margin: -40px 25px 50px;padding: 0px;max-width: 100%;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 3px 0px 0px;padding: 10px 0px;max-width: 100%;box-sizing: border-box;display: inline-block;width: 495px;color: rgb(68, 153, 231);float: left;border-color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 1em 0px 0px;padding: 0px;max-width: 100%;box-sizing: border-box;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);clear: both;color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px 0px -3px;padding: 0px;max-width: 100%;float: right;border-color: rgb(68, 153, 231);width: 6px;border-radius: 50%;background-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;height: 6px !important;" mpa-from-tpl="t"> <br> </section> <section style="margin: 0px 0px -2px;padding: 0px;max-width: 100%;text-align: left;border-color: rgb(68, 153, 231);width: 6px;border-radius: 50%;background-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;height: 6px !important;" mpa-from-tpl="t"> <br> </section> <section style="margin: -20px 0px 0px;padding: 0px;max-width: 100%;box-sizing: border-box;text-decoration: inherit;color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box;border-top: 1px solid rgb(68, 153, 231);width: 495px;float: left;border-right-color: rgb(68, 153, 231);border-bottom-color: rgb(68, 153, 231);border-left-color: rgb(68, 153, 231);color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <br> </section> </section> </section> </section> </section> </section> </blockquote> </section> </blockquote> </section> <p><br></p> <p><br></p> <p><img class="rich_pages wxw-img" data-imgfileid="100130313" data-ratio="0.38902147971360385" src="/upload/7b6ea0322977caeb93ccadbfcc883ccc.png" data-type="other" data-w="838"></p> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 10px;padding-right: 10px;padding-bottom: 10px;line-height: 1.8;border-radius: 0px 0px 10px 10px;color: rgb(14, 136, 235);background: rgb(255, 255, 255);box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.2em;word-spacing: 0.1em;line-height: 26px;font-size: 15px;">❝</p> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.2em;word-spacing: 0.1em;line-height: 26px;font-size: 15px;">所谓防抖,一是防用户手抖,二是防网络抖动。在Web系统中,表单提交是一个非常常见的功能,如果不加控制,容易因为用户的误操作或网络延迟导致同一请求被发送多次,进而生成重复的数据记录。要针对用户的误操作,前端通常会实现按钮的loading状态,阻止用户进行多次点击。而对于网络波动造成的请求重发问题,仅靠前端是不行的。为此,后端也应实施相应的防抖逻辑,确保在网络波动的情况下不会接收并处理同一请求多次。</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">一个理想的防抖组件或机制,我觉得应该具备以下特点:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 逻辑正确,也就是不能误判; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 响应迅速,不能太慢; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 易于集成,逻辑与业务解耦; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 良好的用户反馈机制,比如提示“您点击的太快了” </section></li> </ol> <h2 data-tool="mdnice编辑器"><span style="display: none;"></span><br mpa-from-tpl="t"></h2> <p><br></p> <section data-mpa-template="t" mpa-from-tpl="t"> <blockquote style="margin: 5px auto;padding: 0px;max-width: 100%;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 25.6px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;color: rgb(68, 153, 231);" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <blockquote style="margin: 5px auto;padding: 0px;max-width: 100%;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;text-align: center;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto -38px;padding: 0px 15px;max-width: 100%;display: inline-block;background-color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <p style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;clear: both;min-height: 1em;color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"><span style="font-family: Arial, Helvetica, sans-serif;"><strong mpa-from-tpl="t"><span style="border-color: rgb(68, 153, 231);color: rgb(255, 255, 255);font-size: 16px;" mpa-is-content="t">思路解析</span></strong></span></p> </section> <section style="margin: -40px 25px 50px;padding: 0px;max-width: 100%;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 3px 0px 0px;padding: 10px 0px;max-width: 100%;box-sizing: border-box;display: inline-block;width: 495px;color: rgb(68, 153, 231);float: left;border-color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 1em 0px 0px;padding: 0px;max-width: 100%;box-sizing: border-box;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);clear: both;color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px 0px -3px;padding: 0px;max-width: 100%;float: right;border-color: rgb(68, 153, 231);width: 6px;border-radius: 50%;background-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;height: 6px !important;" mpa-from-tpl="t"> <br> </section> <section style="margin: 0px 0px -2px;padding: 0px;max-width: 100%;text-align: left;border-color: rgb(68, 153, 231);width: 6px;border-radius: 50%;background-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;height: 6px !important;" mpa-from-tpl="t"> <br> </section> <section style="margin: -20px 0px 0px;padding: 0px;max-width: 100%;box-sizing: border-box;text-decoration: inherit;color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box;border-top: 1px solid rgb(68, 153, 231);width: 495px;float: left;border-right-color: rgb(68, 153, 231);border-bottom-color: rgb(68, 153, 231);border-left-color: rgb(68, 153, 231);color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <br> </section> </section> </section> </section> </section> </section> </blockquote> </section> </blockquote> </section> <p><br></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">前面讲了那么多,我们已经知道接口的防抖是很有必要的了,但是在开发之前,我们需要捋清楚几个问题。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>哪一类接口需要防抖?<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">接口防抖也不是每个接口都需要加,一般需要加防抖的接口有这几类:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 用户输入类接口:比如搜索框输入、表单输入等,用户输入往往会频繁触发接口请求,但是每次触发并不一定需要立即发送请求,可以等待用户完成输入一段时间后再发送请求。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 按钮点击类接口:比如提交表单、保存设置等,用户可能会频繁点击按钮,但是每次点击并不一定需要立即发送请求,可以等待用户停止点击一段时间后再发送请求。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 滚动加载类接口:比如下拉刷新、上拉加载更多等,用户可能在滚动过程中频繁触发接口请求,但是每次触发并不一定需要立即发送请求,可以等待用户停止滚动一段时间后再发送请求。 </section></li> </ul> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>如何确定接口是重复的?<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">防抖也即防重复提交,那么如何确定两次接口就是重复的呢?首先,我们需要给这两次接口的调用加一个时间间隔,大于这个时间间隔的一定不是重复提交;其次,两次请求提交的参数比对,不一定要全部参数,选择标识性强的参数即可;最后,如果想做的更好一点,还可以加一个请求地址的对比。</p> <h2 data-tool="mdnice编辑器"><span style="display: none;"></span><br mpa-from-tpl="t"></h2> <p><br></p> <section data-mpa-template="t" mpa-from-tpl="t"> <blockquote style="margin: 5px auto;padding: 0px;max-width: 100%;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 25.6px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;color: rgb(68, 153, 231);" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <blockquote style="margin: 5px auto;padding: 0px;max-width: 100%;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;text-align: center;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto -38px;padding: 0px 15px;max-width: 100%;display: inline-block;background-color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <p style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;clear: both;min-height: 1em;color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"><span style="font-family: Arial, Helvetica, sans-serif;"><strong mpa-from-tpl="t"><span style="border-color: rgb(68, 153, 231);color: rgb(255, 255, 255);font-size: 16px;" mpa-is-content="t">分布式部署下如何做接口防抖?</span></strong></span></p> </section> <section style="margin: -40px 25px 50px;padding: 0px;max-width: 100%;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 3px 0px 0px;padding: 10px 0px;max-width: 100%;box-sizing: border-box;display: inline-block;width: 495px;color: rgb(68, 153, 231);float: left;border-color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 1em 0px 0px;padding: 0px;max-width: 100%;box-sizing: border-box;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);clear: both;color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px 0px -3px;padding: 0px;max-width: 100%;float: right;border-color: rgb(68, 153, 231);width: 6px;border-radius: 50%;background-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;height: 6px !important;" mpa-from-tpl="t"> <br> </section> <section style="margin: 0px 0px -2px;padding: 0px;max-width: 100%;text-align: left;border-color: rgb(68, 153, 231);width: 6px;border-radius: 50%;background-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;height: 6px !important;" mpa-from-tpl="t"> <br> </section> <section style="margin: -20px 0px 0px;padding: 0px;max-width: 100%;box-sizing: border-box;text-decoration: inherit;color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box;border-top: 1px solid rgb(68, 153, 231);width: 495px;float: left;border-right-color: rgb(68, 153, 231);border-bottom-color: rgb(68, 153, 231);border-left-color: rgb(68, 153, 231);color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <br> </section> </section> </section> </section> </section> </section> </blockquote> </section> </blockquote> </section> <p><br></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">有两个方案:</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>使用共享缓存<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">流程图如下:</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><img class="rich_pages wxw-img" data-imgfileid="100130314" data-ratio="1.9378238341968912" src="/upload/cb4740cf9cc38b1e57e85c2f5102a3e7.png" data-type="other" data-w="772"></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <br> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>使用分布式锁<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">流程图如下:</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><img class="rich_pages wxw-img" data-imgfileid="100130315" data-ratio="2.063888888888889" src="/upload/ec09978c5f17f0d4b14cdb7d833e657c.png" data-type="other" data-w="720"></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <br> </figure> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 10px;padding-right: 10px;padding-bottom: 10px;line-height: 1.8;border-radius: 0px 0px 10px 10px;color: rgb(14, 136, 235);background: rgb(255, 255, 255);box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.2em;word-spacing: 0.1em;line-height: 26px;font-size: 15px;">❝</p> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.2em;word-spacing: 0.1em;line-height: 26px;font-size: 15px;">常见的分布式组件有Redis、Zookeeper等,但结合实际业务来看,一般都会选择Redis,因为Redis一般都是Web系统必备的组件,不需要额外搭建。</p> </blockquote> <h2 data-tool="mdnice编辑器"><span style="display: none;"></span><br mpa-from-tpl="t"></h2> <p><br></p> <section data-mpa-template="t" mpa-from-tpl="t"> <blockquote style="margin: 5px auto;padding: 0px;max-width: 100%;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 25.6px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;color: rgb(68, 153, 231);" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <blockquote style="margin: 5px auto;padding: 0px;max-width: 100%;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;text-align: center;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto -38px;padding: 0px 15px;max-width: 100%;display: inline-block;background-color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <p style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;clear: both;min-height: 1em;color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"><span style="font-family: Arial, Helvetica, sans-serif;"><strong mpa-from-tpl="t"><span style="border-color: rgb(68, 153, 231);color: rgb(255, 255, 255);font-size: 16px;" mpa-is-content="t">具体实现</span></strong></span></p> </section> <section style="margin: -40px 25px 50px;padding: 0px;max-width: 100%;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 3px 0px 0px;padding: 10px 0px;max-width: 100%;box-sizing: border-box;display: inline-block;width: 495px;color: rgb(68, 153, 231);float: left;border-color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 1em 0px 0px;padding: 0px;max-width: 100%;box-sizing: border-box;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);clear: both;color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px 0px -3px;padding: 0px;max-width: 100%;float: right;border-color: rgb(68, 153, 231);width: 6px;border-radius: 50%;background-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;height: 6px !important;" mpa-from-tpl="t"> <br> </section> <section style="margin: 0px 0px -2px;padding: 0px;max-width: 100%;text-align: left;border-color: rgb(68, 153, 231);width: 6px;border-radius: 50%;background-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;height: 6px !important;" mpa-from-tpl="t"> <br> </section> <section style="margin: -20px 0px 0px;padding: 0px;max-width: 100%;box-sizing: border-box;text-decoration: inherit;color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box;border-top: 1px solid rgb(68, 153, 231);width: 495px;float: left;border-right-color: rgb(68, 153, 231);border-bottom-color: rgb(68, 153, 231);border-left-color: rgb(68, 153, 231);color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <br> </section> </section> </section> </section> </section> </section> </blockquote> </section> </blockquote> </section> <p><br></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">现在有一个保存用户的接口</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG21P0xNPUnGvumlv2cs3YYawa1pILVMR3CNriaGrTxicU0PZicSoC3FgzCwWeu65XAlgTJN7k1Am6IDpiajmV2xmf93/640?wx_fmt=svg&amp;from=appmsg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #61aeee;line-height: 26px;">@PostMapping</span>(<span style="color: #98c379;line-height: 26px;">"/add"</span>)<br><span style="color: #61aeee;line-height: 26px;">@RequiresPermissions</span>(value&nbsp;=&nbsp;<span style="color: #98c379;line-height: 26px;">"add"</span>)<br><span style="color: #61aeee;line-height: 26px;">@Log</span>(methodDesc&nbsp;=&nbsp;<span style="color: #98c379;line-height: 26px;">"添加用户"</span>)<br><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;ResponseEntity&lt;String&gt;&nbsp;<span style="color: #61aeee;line-height: 26px;">add</span><span style="line-height: 26px;">(@RequestBody&nbsp;AddReq&nbsp;addReq)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">return</span>&nbsp;userService.add(addReq);<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">AddReq.java</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG21P0xNPUnGvumlv2cs3YYawa1pILVMR3CNriaGrTxicU0PZicSoC3FgzCwWeu65XAlgTJN7k1Am6IDpiajmV2xmf93/640?wx_fmt=svg&amp;from=appmsg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">package</span>&nbsp;com.summo.demo.model.request;<br><span style="color: #c678dd;line-height: 26px;">import</span>&nbsp;java.util.List;<br><span style="color: #c678dd;line-height: 26px;">import</span>&nbsp;lombok.Data;<br><span style="color: #61aeee;line-height: 26px;">@Datapublic</span>&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">AddReq</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #5c6370;font-style: italic;line-height: 26px;">/**&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;用户名称&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;String&nbsp;userName;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #5c6370;font-style: italic;line-height: 26px;">/**&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;用户手机号&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;String&nbsp;userPhone;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #5c6370;font-style: italic;line-height: 26px;">/**&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;角色ID列表&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;List&lt;Long&gt;&nbsp;roleIdList;}<br></code></pre> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 10px;padding-right: 10px;padding-bottom: 10px;line-height: 1.8;border-radius: 0px 0px 10px 10px;color: rgb(14, 136, 235);background: rgb(255, 255, 255);box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.2em;word-spacing: 0.1em;line-height: 26px;font-size: 15px;">❝</p> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.2em;word-spacing: 0.1em;line-height: 26px;font-size: 15px;">目前数据库表中没有对userPhone字段做UK索引,这就会导致每调用一次add就会创建一个用户,即使userPhone相同。</p> </blockquote> <h2 data-tool="mdnice编辑器"><span style="display: none;"></span><br mpa-from-tpl="t"></h2> <p><br></p> <section data-mpa-template="t" mpa-from-tpl="t"> <blockquote style="margin: 5px auto;padding: 0px;max-width: 100%;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 25.6px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;color: rgb(68, 153, 231);" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <blockquote style="margin: 5px auto;padding: 0px;max-width: 100%;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;text-align: center;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto -38px;padding: 0px 15px;max-width: 100%;display: inline-block;background-color: rgb(68, 153, 231);border-color: rgb(68, 153, 231)

23.4K Star,轻松将任何网页变成桌面应用程序

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="margin-bottom: 0px;padding-left: 10px;padding-right: 10px;background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;font-family: Optima, &quot;Microsoft YaHei&quot;, PingFangSC-regular, serif;font-size: 16px;color: rgb(0, 0, 0);line-height: 1.5em;word-spacing: 0em;letter-spacing: 0em;word-break: break-word;text-align: left;" data-mpa-powered-by="yiban.io"> <p data-tool="mdnice编辑器" style="line-height: 1.8em;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">今天推荐一个可以将各种网页快速打包成桌面应用程序,支持 Mac、Windows 和 Linux。相比 Electron,Pake 更加小巧易用,速度更快,并且实现了通用的快捷键透传、沉浸式窗口、拖动、打包样式兼容等特性。对于需要将网页应用打包成桌面应用的开发者来说,Pake 提供了一个方便、高效的开源工具。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 20px;margin-right: 10px;margin-bottom: 10px;"><span style="display: none;"></span><span style="font-size: 22px;color: rgb(51, 51, 51);line-height: 1.5em;letter-spacing: 0em;font-weight: bolder;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(255, 127, 80);">热门案例</span><span style="display: none;"></span></h2> <p data-tool="mdnice编辑器" style="line-height: 1.8em;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">WeRead<img class="rich_pages wxw-img" data-imgfileid="100004468" data-ratio="0.6675925925925926" data-type="png" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;border-radius: 10px;height: auto !important;" src="/upload/8db88837876f479a3ba54426133d3a9f.png">推特<img class="rich_pages wxw-img" data-imgfileid="100004470" data-ratio="0.6648148148148149" data-type="png" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;border-radius: 10px;height: auto !important;" src="/upload/218a35dee8abfda4b02479f89dbee2b0.png"></p> <p data-tool="mdnice编辑器" style="line-height: 1.8em;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">ChatGPT<img class="rich_pages wxw-img" data-imgfileid="100004469" data-ratio="0.6555555555555556" data-type="png" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;border-radius: 10px;height: auto !important;" src="/upload/5740ca937597644a7ca0db35e0db786c.png">YouTube<img class="rich_pages wxw-img" data-imgfileid="100004471" data-ratio="0.6583333333333333" data-type="png" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;border-radius: 10px;height: auto !important;" src="/upload/4f00c7642012b98c926f04d97d28c5aa.png">小红书</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100004475" data-ratio="0.6796296296296296" data-type="png" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;height: auto !important;" src="/upload/f23a540d2dfb758288d07d9955c5218d.png"> </figure> <h2 data-tool="mdnice编辑器" style="margin-top: 20px;margin-right: 10px;margin-bottom: 10px;"><span style="display: none;"></span><span style="font-size: 22px;color: rgb(51, 51, 51);line-height: 1.5em;letter-spacing: 0em;font-weight: bolder;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(255, 127, 80);">在开始之前</span><span style="display: none;"></span></h2> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 1.8em;letter-spacing: 0em;"> <strong style="color: rgb(0, 0, 0);background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;">对于初学者</strong>:使用流行的包来了解 Pake 的功能,或者尝试使用 GitHub Actions 打包您的应用程序。请随时在 讨论 中寻求帮助! </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 1.8em;letter-spacing: 0em;"> <strong style="color: rgb(0, 0, 0);background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;">对于开发人员</strong>:“命令行打包”完全支持 macOS。对于 Windows/Linux 用户,它需要一些修补。在开始之前 配置您的环境。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 1.8em;letter-spacing: 0em;"> <strong style="color: rgb(0, 0, 0);background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;">对于黑客</strong>:对于既擅长前端开发又擅长 Rust 的人来说,通过下面的 定制开发 来更多地定制你的应用程序功能怎么样? </section></li> </ol> <h2 data-tool="mdnice编辑器" style="margin-top: 20px;margin-right: 10px;margin-bottom: 10px;"><span style="display: none;"></span><span style="font-size: 22px;color: rgb(51, 51, 51);line-height: 1.5em;letter-spacing: 0em;font-weight: bolder;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(255, 127, 80);">命令行打包</span><span style="display: none;"></span></h2> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100004474" data-ratio="0.625" data-type="gif" data-w="640" style="display: block;margin-right: auto;margin-left: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;height: auto !important;" src="/upload/14ceb84b6653af9349c7279fccd13915.png"> </figure> <p data-tool="mdnice编辑器" style="line-height: 1.8em;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;"><strong style="background-attachment: scroll;background-clip: border-box;background-image: none;background-origin: padding-box;background-position: 0% 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;">Pake 提供了一个命令行工具,使包定制流程更快、更轻松。请参阅 文档 了解更多信息。</strong></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;margin-top: 10px;margin-bottom: 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/YCOL3hU8ffURHTvwHibZ4ksrK5hUb6d7iauJooUTvsib4FsEhhQmdQpaelich2IRHx3ia4h78zgicjWexyWNwMA3RkY3TDTF4Uib3NO/640?wx_fmt=svg&amp;from=appmsg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style=""><span style="color: #5c6370;font-style: italic;line-height: 26px;">#&nbsp;Install&nbsp;with&nbsp;npm</span><br>npm&nbsp;install&nbsp;-g&nbsp;pake-cli<br><br><span style="color: #5c6370;font-style: italic;line-height: 26px;">#&nbsp;Command&nbsp;usage</span><br>pake&nbsp;url&nbsp;[OPTIONS]...<br><br><span style="color: #5c6370;font-style: italic;line-height: 26px;">#&nbsp;Feel&nbsp;free&nbsp;to&nbsp;play&nbsp;with&nbsp;Pake!&nbsp;It&nbsp;might&nbsp;take&nbsp;a&nbsp;while&nbsp;to&nbsp;prepare&nbsp;the&nbsp;environment&nbsp;the&nbsp;first&nbsp;time&nbsp;you&nbsp;launch&nbsp;Pake.</span><br>pake&nbsp;https://weekly.tw93.fun&nbsp;--name&nbsp;Weekly&nbsp;--hide-title-bar<br></code></pre> <p data-tool="mdnice编辑器" style="line-height: 1.8em;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">如果您不熟悉命令行,可以使用* GitHub Actions *在线编译包。请参阅 教程 以获取更多信息。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 20px;margin-right: 10px;margin-bottom: 10px;"><span style="display: none;"></span><span style="font-size: 22px;color: rgb(51, 51, 51);line-height: 1.5em;letter-spacing: 0em;font-weight: bolder;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(255, 127, 80);">发展</span><span style="display: none;"></span></h2> <p data-tool="mdnice编辑器" style="line-height: 1.8em;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">开始之前准备好环境。确保您的计算机上安装了 Rust<code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">&gt;=1.63</code>和 Node <code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">&gt;=16</code>(例如)。<code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">16.18.1</code>有关安装指南,请参阅 Tauri 文档。</p> <p data-tool="mdnice编辑器" style="line-height: 1.8em;letter-spacing: 0em;text-indent: 0em;padding-top: 8px;padding-bottom: 8px;">如果你对这些不熟悉,最好尝试一下上面的工具一键打包。</p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;margin-top: 10px;margin-bottom: 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/YCOL3hU8ffURHTvwHibZ4ksrK5hUb6d7iauJooUTvsib4FsEhhQmdQpaelich2IRHx3ia4h78zgicjWexyWNwMA3RkY3TDTF4Uib3NO/640?wx_fmt=svg&amp;from=appmsg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style=""><span style="color: #5c6370;font-style: italic;line-height: 26px;">#&nbsp;Install&nbsp;Dependencies</span><br>npm&nbsp;i<br><br><span style="color: #5c6370;font-style: italic;line-height: 26px;">#&nbsp;Local&nbsp;development&nbsp;[Right-click&nbsp;to&nbsp;open&nbsp;debug&nbsp;mode.]</span><br>npm&nbsp;run&nbsp;dev<br><br><span style="color: #5c6370;font-style: italic;line-height: 26px;">#&nbsp;Pack&nbsp;application</span><br>npm&nbsp;run&nbsp;build<br></code></pre> <h2 data-tool="mdnice编辑器" style="margin-top: 20px;margin-right: 10px;margin-bottom: 10px;"><span style="display: none;"></span><span style="font-size: 22px;color: rgb(51, 51, 51);line-height: 1.5em;letter-spacing: 0em;font-weight: bolder;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(255, 127, 80);">高级用法</span><span style="display: none;"></span></h2> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 1.8em;letter-spacing: 0em;"> 在使用 Pake 之前,您可以参考 代码库结构,这对您的开发有很大帮助。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 1.8em;letter-spacing: 0em;"> 修改 src-tauri 目录下文件中的 <code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">url</code>和 <code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">productName</code>字段 <code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">pake.json</code>,需要同步修改文件中的“domain”字段 <code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">tauri.config.json</code>,以及文件中的 <code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">icon</code>和字段。您可以从目录中选择一个或从 macOSicons 下载一个以满足您的产品需求。 <code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">identifier``tauri.xxx.conf.json``icon``icons</code> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 1.8em;letter-spacing: 0em;"> 对于窗口属性的配置,可以通过修改文件来改变属性的、(或不) 、(或不)的 <code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">pake.json</code>值。要适应 Mac 上的沉浸式标题,请更改为,查找该元素,然后添加该属性。 <code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;">width``height``fullscreen``resizable``windows``hideTitleBar``true``Header``padding-top</code> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 1.8em;letter-spacing: 0em;"> 样式重写、广告去除、JS 注入、容器消息通信、自定义快捷键等高级用法,请参见 Pake 的高级用法。 </section></li> </ol> </section>

实时ETL工具:Apache NiFi介绍和教程

作者:微信小助手

<section style="outline: 0px;line-height: 27.2px;visibility: visible;margin-bottom: 0px;"> <section style="outline: 0px;visibility: visible;"> <section data-border="1" style="outline: 0px;display: inline-block;border-width: 10px;border-style: solid;border-color: transparent;-webkit-border-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/ianq03UUWGmJjUVsLldsQyMMJy7p0rviazYUENd7KNlSqnWRbBZeXtwfAgyBwj9xVd1Rx1oypdUB26Su9f5sFPOg/640?wx_fmt=png&quot;) 30 fill stretch;line-height: 0em;visibility: visible;"> <img class="rich_pages wxw-img __bg_gif" data-backh="279" data-backw="558" data-imgfileid="100002131" data-ratio="0.5" src="/upload/e3957b1c9db354deb5d9082b2532b9bd.png" data-type="gif" data-w="640" style="outline: 0px;vertical-align: inherit;width: 100%;visibility: visible !important;height: auto;"> </section> </section> </section> <section style="margin-bottom: 0px;outline: 0px;font-family: system-ui, -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-wrap: wrap;background-color: rgb(255, 255, 255);line-height: 27.2px;visibility: visible;"> <p style="text-align: center;"><br></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100002138" data-ratio="0.47058823529411764" data-s="300,640" src="/upload/63b1c03ae1e2f0f61959b9d47f9ae72b.jpg" data-type="jpeg" data-w="850" style="width: 255px;height: auto;"></p> <section style="outline: 0px;text-align: center;line-height: normal;visibility: visible;"> <br> </section> </section> <section style="margin-bottom: 0px;outline: 0px;font-family: system-ui, -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-indent: 0em;text-wrap: wrap;background-color: rgb(255, 255, 255);line-height: normal;visibility: visible;"> <span style="outline: 0px;letter-spacing: 0.578px;visibility: visible;"></span> </section> <section style="margin-bottom: 0px;outline: 0px;font-family: system-ui, -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-indent: 0em;text-wrap: wrap;background-color: rgb(255, 255, 255);line-height: 1.6em;visibility: visible;"> <span style="outline: 0px;letter-spacing: 0.578px;text-decoration-style: solid;text-decoration-color: rgba(0, 0, 0, 0.9);visibility: visible;"></span> </section> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 1.3em;text-wrap: wrap;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: normal;text-align: left;background-color: rgb(255, 255, 255);border-bottom: 2px solid rgb(239, 112, 96);visibility: visible;"><span style="margin-right: 3px;padding: 3px 10px 1px;outline: 0px;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;visibility: visible;font-size: 22px;text-decoration-style: solid;text-decoration-color: rgb(255, 255, 255);">1.<span style="letter-spacing: 0.578px;text-wrap: wrap;">背景和历史</span></span></h2> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">Apache NiFi </span></strong> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">(Niagara Files) 是由美国国家安全局(NSA)开发,并于2014年捐赠给Apache软件基金会的一个开源项目。它的设计初衷是为了简化和自动化数据在不同系统之间的传输和处理,解决数据集成中的挑战。随着数据量和数据源的不断增加,NiFi 被设计为一个高效、灵活且可扩展的平台,以应对复杂的数据流需求。</span> </section> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 1.3em;text-wrap: wrap;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: normal;text-align: left;background-color: rgb(255, 255, 255);border-bottom: 2px solid rgb(239, 112, 96);visibility: visible;"><span style="margin-right: 3px;padding: 3px 10px 1px;outline: 0px;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;visibility: visible;font-size: 22px;text-decoration-style: solid;text-decoration-color: rgb(255, 255, 255);">2.<span style="letter-spacing: 0.578px;"><span style="letter-spacing: 0.578px;text-wrap: wrap;">核心概念和架构</span></span></span></h2> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">FlowFile</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">定义:</span></strong> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">FlowFile 是 NiFi 中的基本数据单元,包含实际的数据内容和元数据。每个FlowFile 由内容和属性两部分组成。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">内容:</span></strong> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">实际的数据。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">属性:</span></strong> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">键值对形式的元数据,用于描述内容或控制处理逻辑。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">Processor</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">定义:</span></strong> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">处理器是执行数据处理任务的组件。NiFi 提供了丰富的处理器库,用于执行各种操作,如数据过滤、转换、路由、聚合等。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">类型:</span></strong> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">包括数据输入/输出处理器、转换处理器、路由处理器等。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">Connection</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">定义:</span></strong> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">连接器用于将处理器连接起来,定义数据流路径。连接器可以在处理器之间缓冲数据,控制数据流速率和优先级。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">属性:</span></strong> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">包括队列大小、优先级策略等。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">Process Group</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">定义:</span></strong> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">处理组是用于组织和管理一组相关处理器和连接器的容器,可以嵌套,实现数据流的模块化和层次化管理。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">作用:</span></strong> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">支持复杂数据流的结构化设计,提高可维护性和重用性。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">Controller Service</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">定义:</span></strong> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">控制器服务是共享的资源服务,如数据库连接池、分布式缓存等,供多个处理器使用。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">作用:</span></strong> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">简化配置管理,提高资源利用率。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">Reporting Task</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">定义:</span></strong> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">报告任务用于生成和发送系统运行报告,包括统计信息、监控指标等。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">作用:</span></strong> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">提供系统运行状态的可见性,支持运维和优化。</span> </section> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 1.3em;text-wrap: wrap;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;text-align: left;background-color: rgb(255, 255, 255);border-bottom: 2px solid rgb(239, 112, 96);visibility: visible;"><span style="margin-right: 3px;padding: 3px 10px 1px;outline: 0px;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;visibility: visible;font-size: 22px;text-decoration-style: solid;text-decoration-color: rgb(255, 255, 255);"><span style="text-wrap: wrap;letter-spacing: normal;">3.</span><span style="letter-spacing: 0.578px;text-wrap: wrap;">主要功能</span></span></h2> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">可视化编排</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">通过拖放式界面创建和管理数据流,降低复杂数据集成任务的门槛。</span> <span style="letter-spacing: 0.578px;text-indent: 0em;">支持实时监控和调试,提供数据流的全生命周期管理。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">实时数据处理</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">支持实时数据采集、处理和传输,确保数据的及时性和一致性。</span> <span style="letter-spacing: 0.578px;text-indent: 0em;">内置丰富的实时处理器,如Kafka、MQTT、HTTP等,支持各种数据源和协议。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">数据路由和控制</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">支持基于内容、属性和规则的数据路由,实现复杂的流控制和分支。</span> <span style="letter-spacing: 0.578px;text-indent: 0em;">提供强大的条件判断和决策功能,动态调整数据流路径。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">数据转换和增强</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">内置多种数据转换处理器,支持数据格式转换、清洗、聚合和增强。</span> <span style="letter-spacing: 0.578px;text-indent: 0em;">支持自定义脚本(如Groovy、Jython)进行复杂的数据处理。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">扩展性和可定制性</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">基于插件架构,支持自定义处理器、控制器服务和报告任务的扩展。</span> <span style="letter-spacing: 0.578px;text-indent: 0em;">提供丰富的API和SDK,支持二次开发和集成。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">安全性和合规性</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">提供细粒度的用户认证和权限控制,确保数据访问的安全性。</span> <span style="letter-spacing: 0.578px;text-indent: 0em;">支持数据加密、审计和溯源,满足企业级安全和合规要求。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">集群和分布式处理</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">支持分布式集群部署,提高系统的可扩展性和容错能力。</span> <span style="letter-spacing: 0.578px;text-indent: 0em;">提供自动负载均衡和故障恢复,确保高可用性。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="letter-spacing: 0.578px;text-indent: 0em;"><br></span> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="340" data-backw="578" data-galleryid="" data-imgfileid="100002154" data-ratio="0.588659793814433" data-s="300,640" src="/upload/ac2131ddc863a99db36b9780bc4fe843.png" data-type="png" data-w="970" style="width: 100%;height: auto;"></p> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="letter-spacing: 0.578px;text-indent: 0em;"></span> </section> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 1.3em;text-wrap: wrap;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: normal;text-align: left;background-color: rgb(255, 255, 255);border-bottom: 2px solid rgb(239, 112, 96);visibility: visible;"><span style="margin-right: 3px;padding: 3px 10px 1px;outline: 0px;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;visibility: visible;font-size: 22px;text-decoration-style: solid;text-decoration-color: rgb(255, 255, 255);">4.<span style="letter-spacing: 0.578px;"><span style="letter-spacing: 0.578px;text-wrap: wrap;">架构深度解析</span></span></span></h2> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">Web UI</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">用户界面,通过浏览器访问,用于创建、管理和监控数据流。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">提供可视化的设计和调试工具,支持实时数据流的操作和监控。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">Flow Controller</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">数据流控制器,负责协调NiFi实例中的数据流和任务调度。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">管理处理器的执行顺序和资源分配,确保数据流的高效运行。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">Extension System</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">扩展系统,支持通过插件扩展NiFi的功能,如自定义处理器、控制器服务和报告任务。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">提供丰富的API和SDK,支持第三方扩展和集成。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">Content Repository</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">内容存储库,用于存储FlowFile的实际数据。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">提供高效的数据存储和访问机制,支持大规模数据的持久化和检索。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">FlowFile Repository</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">FlowFile存储库,用于存储FlowFile的元数据和状态信息。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">管理FlowFile的生命周期和状态变迁,支持数据流的可靠传输。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">Provenance Repository</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">溯源存储库,用于跟踪和记录数据流的历史和变更。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">提供详细的数据溯源信息,支持审计和故障排查。</span> </section> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 1.3em;text-wrap: wrap;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: normal;text-align: left;background-color: rgb(255, 255, 255);border-bottom: 2px solid rgb(239, 112, 96);visibility: visible;"><span style="margin-right: 3px;padding: 3px 10px 1px;outline: 0px;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;visibility: visible;font-size: 22px;text-decoration-style: solid;text-decoration-color: rgb(255, 255, 255);">5.<span style="letter-spacing: 0.578px;"><span style="letter-spacing: 0.578px;text-wrap: wrap;">使用案例</span></span></span></h2> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">物联网(IoT)数据集成</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">收集、处理和分析来自各种传感器和设备的数据。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">实现设备数据的实时监控和智能分析,支持预测性维护和优化。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">实时数据处理</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">处理和传输实时数据流,如日志数据、点击流数据和金融交易数据。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">提供高效的数据处理和分析能力,支持实时决策和响应。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">数据湖建设</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">从各种数据源采集数据并存储到数据湖中,为后续分析和处理提供支持。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">实现数据的集中存储和管理,支持大数据分析和机器学习。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">ETL(抽取、转换、加载)流程自动化</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">自动化ETL流程,简化数据仓库和数据集市的构建。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">提供高效的数据转换和加载能力,支持复杂的数据集成任务。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">多云和混合云数据集成</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">在不同云平台和本地环境之间集成数据,确保数据的一致性和可用性。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">支持跨平台的数据流管理和监控,实现云资源的优化利用。</span> </section> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 1.3em;text-wrap: wrap;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: normal;text-align: left;background-color: rgb(255, 255, 255);border-bottom: 2px solid rgb(239, 112, 96);visibility: visible;"><span style="margin-right: 3px;padding: 3px 10px 1px;outline: 0px;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;visibility: visible;font-size: 22px;text-decoration-style: solid;text-decoration-color: rgb(255, 255, 255);">6.<span style="letter-spacing: 0.578px;"><span style="letter-spacing: 0.578px;text-wrap: wrap;">系统要求</span></span></span></h2> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">在安装Apache NiFi之前,请确保您的系统满足以下要求:</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">操作系统:Linux, macOS, 或 Windows</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">Java:Oracle JDK 8 或者 11</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">内存:至少1GB的可用内存(推荐4GB以上)</span> </section> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 1.3em;text-wrap: wrap;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: normal;text-align: left;background-color: rgb(255, 255, 255);border-bottom: 2px solid rgb(239, 112, 96);visibility: visible;"><span style="margin-right: 3px;padding: 3px 10px 1px;outline: 0px;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;visibility: visible;font-size: 22px;text-decoration-style: solid;text-decoration-color: rgb(255, 255, 255);">7.<span style="letter-spacing: 0.578px;"><span style="letter-spacing: 0.578px;text-wrap: wrap;">安装步骤</span></span></span></h2> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">下载 Apache NiFi</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">访问Apache NiFi官网下载最新版本的NiFi压缩包。</span> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="ruby"><code><span class="code-snippet_outer"><span class="code-snippet__symbol">https:</span>/<span class="code-snippet__regexp">/archive.apache.org/dist</span><span class="code-snippet__regexp">/nifi/</span></span></code></pre> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="403" data-backw="578" data-galleryid="" data-imgfileid="100002139" data-ratio="0.6980942828485457" data-s="300,640" src="/upload/e14b3a0484c7e7dc3a9fe4238698e159.png" data-type="png" data-w="997" style="width: 100%;height: auto;"></p> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <strong><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">Windows选择nifi-x.x.x-bin.zip</span></strong></strong> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <strong><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">Linux选择nifi-x.x.x-bin.tar.gz</span></strong></strong> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <strong><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"><br></span></strong></strong> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">选择合适的二进制分发(如 nifi-</span> <version> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">-bin.tar.gz 或 nifi-</span> <version> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">-bin.zip)。</span> </version> </version> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">解压缩文件</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">在下载目录中解压缩文件:bash</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="css"><code><span class="code-snippet_outer"><span class="code-snippet__selector-tag">tar</span> <span class="code-snippet__selector-tag">-xvzf</span> <span class="code-snippet__selector-tag">nifi--bin</span><span class="code-snippet__selector-class">.tar</span><span class="code-snippet__selector-class">.gz</span></span></code></pre> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <version> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </version> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <version> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"> 或者cmd</span> </version> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="css"><code><span class="code-snippet_outer"><span class="code-snippet__selector-tag">unzip</span> <span class="code-snippet__selector-tag">nifi--bin</span><span class="code-snippet__selector-class">.zip</span></span></code></pre> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <version> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </version> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">配置环境变量</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">配置 JAVA_HOME 环境变量,确保指向正确的Java安装目录。bash</span> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="javascript"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">export</span> JAVA_HOME=<span class="code-snippet__regexp">/path/</span>to/java</span></code></pre> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">将 NiFi 的 bin 目录添加到 PATH 环境变量中(可选)。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="ruby"><code><span class="code-snippet_outer">export PATH=$PATH<span class="code-snippet__symbol">:/path/to/nifi-/bin</span></span></code></pre> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <version> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </version> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">启动 NiFi</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">进入 NiFi 解压目录下的 bin 目录,运行启动脚本:bash</span> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="sql"><code><span class="code-snippet_outer">./nifi.sh <span class="code-snippet__keyword">start</span> </span></code></pre> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">或者在 Windows 系统上:cmd</span> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="css"><code><span class="code-snippet_outer"><span class="code-snippet__selector-tag">nifi</span><span class="code-snippet__selector-class">.bat</span> <span class="code-snippet__selector-tag">start</span></span></code></pre> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">验证安装</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">打开浏览器,访问 http://localhost:8080/nifi。如果一切正常,您将看到NiFi的Web用户界面。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"><br></span> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="300" data-backw="578" data-galleryid="" data-imgfileid="100002140" data-ratio="0.5194444444444445" data-s="300,640" src="/upload/50771971abf83de6a57b5148e050816b.png" data-type="png" data-w="1080" style="width: 100%;height: auto;"></p> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 1.3em;text-wrap: wrap;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: normal;text-align: left;background-color: rgb(255, 255, 255);border-bottom: 2px solid rgb(239, 112, 96);visibility: visible;"><span style="margin-right: 3px;padding: 3px 10px 1px;outline: 0px;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;visibility: visible;font-size: 22px;text-decoration-style: solid;text-decoration-color: rgb(255, 255, 255);">8.<span style="letter-spacing: 0.578px;"><span style="letter-spacing: 0.578px;text-wrap: wrap;">配置和使用教程</span></span></span></h2> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">访问NiFi Web UI</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">在浏览器中打开 http://localhost:8080/nifi,您将看到NiFi的图形化用户界面。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">创建数据流</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">添加处理器:</span></strong> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">在画布上右键单击,选择 Add Processor,从列表中选择一个处理器(如 GenerateFlowFile)。</span> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="296" data-backw="578" data-galleryid="" data-imgfileid="100002141" data-ratio="0.512962962962963" data-s="300,640" src="/upload/a6ba962e85028ef6d141559a922a0483.png" data-type="png" data-w="1080" style="width: 100%;height: auto;"></p> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">配置处理器:</span></strong> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">双击处理器图标,打开配置窗口。根据需要配置处理器参数。</span> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="296" data-backw="578" data-galleryid="" data-imgfileid="100002142" data-ratio="0.512962962962963" data-s="300,640" src="/upload/d0021c763f56120743efa733a2967898.png" data-type="png" data-w="1080" style="width: 100%;height: auto;"></p> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">连接处理器:</span></strong> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">选择一个处理器,点击箭头图标,将其连接到另一个处理器,配置连接属性。</span> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="296" data-backw="578" data-galleryid="" data-imgfileid="100002143" data-ratio="0.512962962962963" data-s="300,640" src="/upload/6d54252b8eee5f12dfbcd7e317e52373.png" data-type="png" data-w="1080" style="width: 100%;height: auto;"></p> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">数据流示例</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">生成测试数据:添加一个 GenerateFlowFile 处理器,配置 Custom Text 属性为 Hello, NiFi!。</span> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100002147" data-ratio="0.512962962962963" data-s="300,640" src="/upload/89c21f3ae03f910f9dc4bd6179bab742.png" data-type="png" data-w="1080" style=""></p> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100002148" data-ratio="0.512962962962963" data-s="300,640" src="/upload/e3a3a40bce96ad4ee746da2d5cae421f.png" data-type="png" data-w="1080" style=""></p> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">添加一个 LogAttribute 处理器,将 GenerateFlowFile 处理器输出连接到 LogAttribute 处理器。</span> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100002150" data-ratio="0.512962962962963" data-s="300,640" src="/upload/e157b69c5a0695ef04e9c1eceb92b566.png" data-type="png" data-w="1080" style=""></p> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100002149" data-ratio="0.512962962962963" data-s="300,640" src="/upload/6c8d0c87e163f160f54444f2dc617be3.png" data-type="png" data-w="1080" style=""></p> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">启动数据流:点击工具栏中的启动按钮,启动所有处理器。您将在 LogAttribute 的日志中看到生成的测试数据。</span> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100002153" data-ratio="0.512962962962963" data-s="300,640" src="/upload/b177ebdefff6cd105f549bd3a370d810.png" data-type="png" data-w="1080" style=""></p> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">监控和管理数据流</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">监控数据流:</span></strong> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">在NiFi UI中,您可以实时查看数据流的状态、处理速率和流量。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">查看数据溯源:</span></strong> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">右键单击处理器,选择 View data provenance,可以查看数据流的详细历史记录和变更信息。</span> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100002151" data-ratio="0.512962962962963" data-s="300,640" src="/upload/0866c144db4355076c695f298223d5d8.png" data-type="png" data-w="1080" style=""></p> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100002152" data-ratio="0.512962962962963" data-s="300,640" src="/upload/ad37dd05c09671db9f54bd610d80d71a.png" data-type="png" data-w="1080" style=""></p> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">停止和重启 NiFi</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">停止 NiFi:在 bin 目录下运行停止脚本:bash</span> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="sql"><code><span class="code-snippet_outer">./nifi.sh <span class="code-snippet__keyword">stop</span> </span></code></pre> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">或者在 Windows 系统上:cmd</span> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="css"><code><span class="code-snippet_outer"><span class="code-snippet__selector-tag">nifi</span><span class="code-snippet__selector-class">.bat</span> <span class="code-snippet__selector-tag">stop</span></span></code></pre> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">重启 NiFi:运行启动脚本即可重启NiFi。</span> </section> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 1.3em;text-wrap: wrap;outline: 0px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: normal;text-align: left;background-color: rgb(255, 255, 255);border-bottom: 2px solid rgb(239, 112, 96);visibility: visible;"><span style="margin-right: 3px;padding: 3px 10px 1px;outline: 0px;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;visibility: visible;font-size: 22px;text-decoration-style: solid;text-decoration-color: rgb(255, 255, 255);">9.<span style="letter-spacing: 0.578px;"><span style="letter-spacing: 0.578px;text-wrap: wrap;">高级配置</span></span></span></h2> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">安全配置</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">用户认证:NiFi 支持LDAP、Kerberos和单点登录(SSO)等多种用户认证方式。可以在 conf/nifi.properties 文件中配置相关参数。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">数据加密:NiFi 支持传输层加密(TLS/SSL)和内容加密。在 conf/nifi.properties 和 conf/bootstrap.conf 文件中配置加密参数。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">集群部署</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">配置集群节点:在 conf/nifi.properties 文件中,配置集群节点的主机名和端口。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">启用集群模式:在 conf/nifi.properties 文件中,设置 nifi.cluster.is.node 为 true,并配置 nifi.cluster.node.address 和 nifi.cluster.node.protocol.port。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">管理集群:使用集群管理工具(如 Apache Ambari)监控和管理NiFi集群。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="color: rgb(239, 112, 97);"><strong><span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">扩展和自定义</span></strong></span> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);"></span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">自定义处理器:NiFi 提供了丰富的API和SDK,支持开发自定义处理器、控制器服务和报告任务。</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px;text-indent: 0em;"> <span style="font-size: 17px;letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);">插件安装:将自定义的NiFi组件打包成NAR(NiFi Archive)文件,放置到 lib 目录下,重启NiFi即可加载新组件。</span> </section> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 1.3em;text-wrap: wrap;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: normal;text-align: left;background-color: rgb(255, 255, 255);border-bottom: 2px solid rgb(239, 112, 96);visibility: visible;"><span style="margin-right: 3px;padding: 3px 10px 1px;outline: 0px;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;visibility: visible;font-size: 22px;text-decoration-style: solid;text-decoration-color: rgb(255, 255, 255);">感谢阅读,共同进步</span></h2> <p style="margin-bottom: 0px;"><br></p> <section class="mp_profile_iframe_wrp" style="margin-bottom: 0px;outline: 0px;"> <mp-common-profile class="js_uneditable custom_select_card mp_profile_iframe js_wx_tap_highlight" data-pluginname="mpprofile" data-id="MzUzOTgxODU2MA==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/PGwz1wSJNqX2s4FNJDx1ic7xiaffGnAT1f3vymn6eKrk7wNichB3YwvOicaLZ2Cxn6utz70XBDU0zO9GNDKxtlibAGQ/300?wx_fmt=png&amp;wxfrom=19" data-nickname="码奋" data-alias="Coding_Fervor" data-signature="请步伐坚定" data-from="2" data-is_biz_ban="0" data-origin_num="80" data-isban="0" data-biz_account_status="0" data-index="0"></mp-common-profile> </section> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>

干货 | 携程门票「秒杀系统」的设计与实践

作者:微信小助手

<section class="mp_profile_iframe_wrp" data-mpa-powered-by="yiban.io"> <mp-common-profile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzAwMjI0ODk0NA==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/SfAHMuUxqJ2JicQpKzblLHz64qoibVa3ATNA4rH8mIYXAF3OErAzxFKHzf5qiaiblb4rAMuAXXMJHEcKcvaHv4ia9rA/0?wx_fmt=png" data-nickname="悟空聊架构" data-alias="PassJava666" data-signature="用故事讲解分布式、架构。 《 JVM 性能调优实战》专栏作者, 《Spring Cloud 实战 PassJava》开源作者, 自主开发了 PMP 刷题小程序。" data-from="0" data-is_biz_ban="0"></mp-common-profile> </section> <section style="margin-right: 8px;margin-bottom: 0px;margin-left: 8px;outline: 0px;font-family: system-ui, -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-wrap: wrap;background-color: rgb(255, 255, 255);line-height: 1.6em;visibility: visible;"> <section powered-by="xiumi.us" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;font-size: 16px;letter-spacing: 0.544px;text-align: left;justify-content: flex-start;display: flex;flex-flow: row;visibility: visible;"> <section style="padding: 23px;outline: 0px;display: inline-block;width: 677px;vertical-align: top;align-self: flex-start;flex: 0 0 auto;height: auto;border-style: dashed;border-width: 1px;border-color: rgb(95, 145, 183);background-color: rgba(95, 145, 183, 0.07);visibility: visible;"> <section powered-by="xiumi.us" style="outline: 0px;justify-content: flex-start;display: flex;flex-flow: row;visibility: visible;"> <section style="margin-right: 7px;outline: 0px;display: inline-block;vertical-align: middle;width: auto;align-self: center;flex: 0 0 auto;min-width: 10%;height: auto;visibility: visible;"> <section powered-by="xiumi.us" style="outline: 0px;visibility: visible;"> <section style="outline: 0px;text-align: justify;font-size: 14px;color: rgb(95, 145, 183);visibility: visible;"> <p style="outline: 0px;visibility: visible;"><strong style="letter-spacing: 0.544px;outline: 0px;font-size: 15px;visibility: visible;">作者简介</strong><br></p> </section> </section> </section> </section> <section powered-by="xiumi.us" style="outline: 0px;font-size: 14px;text-align: justify;visibility: visible;"> <p style="outline: 0px;visibility: visible;"><span style="outline: 0px;letter-spacing: 0.578px;visibility: visible;">Liang,携程技术专家,专注系统性能、稳定性、承载能力和交易质量,在技术架构演进、高并发等领域有丰富的实践经验。</span></p> <p style="outline: 0px;visibility: visible;"><span style="outline: 0px;letter-spacing: 0.578px;visibility: visible;"><strong>团队开放岗位:</strong>后端开发-资深/专家(海外交易系统)、资深后端开发专家-BMS</span></p> </section> </section> </section> </section> <section style="margin: 24px 8px;line-height: 1.5em;"> <span style="font-size: 14px;color: rgb(0, 0, 0);">本文概述了携程门票预订交易系统在应对秒杀活动中面临的挑战与应对策略。第一部分阐述了业务激增对系统架构的考验;第二部分深入剖析了系统架构的优化路径,涵盖读热点、写入性能瓶颈、强一致性事务处理及流量精细化控制等关键问题的解决方案,并总结了确保系统高可用性与持续性的治理措施。希望这些内容能够对大家有所帮助或启发。</span> </section> <ul class="list-paddingleft-1" style="list-style-type: disc;margin-left: 8px;margin-right: 8px;"> <li> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 14px;color: rgb(136, 136, 136);">一、背景</span> </section></li> <li> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 14px;color: rgb(136, 136, 136);">二、秒杀活动案例分析</span> </section></li> <li> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 14px;color: rgb(136, 136, 136);">三、系统架构设计与演进</span> </section></li> <li> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 14px;color: rgb(136, 136, 136);">3.1 系统稳定性挑战与应对策略</span> </section></li> <li> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 14px;color: rgb(136, 136, 136);">3.2 写数据一致性挑战与应对策略</span> </section></li> <li> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 14px;color: rgb(136, 136, 136);">3.3 实现高可用的可持续性</span> </section></li> <li> <section style="margin-left: 8px;margin-right: 8px;"> <span style="font-size: 14px;color: rgb(136, 136, 136);">四、总结</span> </section></li> </ul> <p style="margin: 24px 8px;line-height: 1.75em;"><strong><span style="letter-spacing: 0.034em;font-size: 17px;">一、背景</span></strong><br></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">后疫情时代旅游行业快速复苏,各类营销秒杀活动变得越发频繁,面对亿级流量的冲击,系统架构面临挑战。研发团队需要保障大流量下的功能稳定性,为国内外用户提供流畅的预订体验,因此需要对核心的预订交易系统进行应用架构升级,从而确保系统在高并发情况下仍能稳定高效运行。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">本文将介绍在应对流量高峰、突破系统瓶颈、强化系统稳定性等方面的应对策略与优化效果。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="letter-spacing: 0.034em;font-size: 17px;">二、秒杀活动案例分析</span></strong> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">回顾大家曾经参与过的秒杀或大促活动,如双十一、618、12306节假日抢票、演唱会抢票时,会有相似的感受:</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">1)<strong>紧张刺激</strong>:活动通常定时开售,期待与紧张并存。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">2)<strong>系统压力</strong>:在高峰期,系统容易出现卡顿、宕机或提示“太火爆”或需要排队等待,让人倍感焦虑。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">3)<strong>结果未知</strong>:尽管全力以赴,但结果往往不尽如人意,有时抢到了票无法支付或者可能被退单。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">这些活动在预订交易系统中也会呈现相似的特征:</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">1)<strong>大流量、高并发</strong>:大流量、高并发、强事务性,对系统性能提出严峻挑战。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">2)<strong>时间敏感性</strong>:准时开售,用户争抢热点资源,系统需要确保实时、准确地响应。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">3)<strong>履约保障</strong>:从订前到订后,系统需要确保履约的顺利进行,避免用户因系统问题而遭受损失。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">与传统电商相比,携程门票交易系统具有两大特点:</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">1)<strong>强一致性</strong>:用户预订后保证出票且尽可能快速确认,确保每一笔交易都能履约。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">2)<strong>多维度和跨商品组合限购</strong>:限购规则复杂多变,例如多维度和跨商品组合限购,保障每位用户有公平购票的机会,避免囤票行为。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">接下来回顾历史上有过的携程门票大型秒杀/活动案例。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">1) 2020年8月8日~9月1日:“惠游湖北”活动,携程独家承办,首次面对日常流量45倍 (数十万QPS) 峰值的流量挑战,虽然刚开始系统出现不稳定的情况,但最终还是成功应对。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">2) 2021年9月14日:北京环球影城开业开售活动,携程门票在与其他友商的同期竞争中,成为唯一稳定出票且销量最高的交易平台。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">3) 2023年9月15日:武汉动物园开园,在供应商系统出现异常、友商页面卡顿有大量退单的情况下,携程门票预订依然能保持顺畅下单。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">4) 2024年4月10日:IU(李知恩)全球演唱会门票在Ctrip.com和Trip.com国际站同时秒杀,携程门票再次表现稳定,预订过程丝滑流畅,10秒内售罄。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">以下是部分历史秒杀活动峰值流量与日常峰值流量的对比数据:</span> </section> <p style="text-align: center;margin-bottom: 24px;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="304487976" data-ratio="0.6157407407407407" data-s="300,640" src="/upload/086b8263209e212c14576b58790f2841.png" data-type="png" data-w="1080" style="width: 443px;height: 273px;"></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;letter-spacing: 0.034em;">数据显示出活动的流量激增通常远超系统日常处理的极限,如果没有针对预订交易系统进行优化,用户可能会遇到各种问题,例如:</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">1)<strong>页面打开慢、卡顿、宕机</strong>:直接影响用户购物体验,系统会出现Redis或DB超负载,供应商接口不稳定等情况。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">2)<strong>付款后不能确认/退款</strong>:付款后,无法及时确认订单状态或进行退款操作,系统出现库存超卖/少卖等情况。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">要避免出现上述情况,就要求系统具备高度的可扩展性和灵活性,同时在架构、缓存、数据库、流量控制等多方面进行全面优化。接下来我们通过具体场景来分析系统遇到的问题和应对策略,了解系统架构设计与演进过程。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 17px;"><strong>三、系统架构设计与演进</strong></span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">整体而言,预订交易系统的目标是:稳、准、快。</span> </section> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <span style="font-size: 15px;">稳:确保系统稳定可靠,保障售卖流程无间断。</span> </section></li> <li> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <span style="font-size: 15px;">准:实现数据一致性,确保履约准确无误。</span> </section></li> <li> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <span style="font-size: 15px;">快:提供流畅的预订体验,实现快速确认。</span> </section></li> </ul> <p style="margin: 24px 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 0.034em;">在大流量高并发场景下,要达到这些目标就可以进行有针对性的改造升级,接下来展开阐述。</span><br></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">3.1 系统稳定性挑战与应对策略</span></strong> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">当系统遇到洪峰流量时,容易出现页面打开慢、卡顿等问题,主要原因有以下几点:</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">1) Redis超负载与缓存热点。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">2) 数据库超负载。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">3) 供应商系统不稳定。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">接下来针对这3个常见问题,阐述相应的应对策略。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">问题一:Redis超负载与缓存热点</span></strong> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">当Redis面临负载问题时,可以使用水平扩容这种常规手段让流量分摊到更多实例。然而扩容虽能降低大多数实例的CPU使用率,但在处理特定热点数据时,各实例的CPU使用率仍然可能出现不均衡的情况,即缓存热点问题;此外还会存在缓存大Key问题。</span> </section> <p style="text-align: center;margin-bottom: 24px;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="304487975" data-ratio="0.48148148148148145" data-s="300,640" src="/upload/d00bcdd284a5a12071da75b0c27fd325.png" data-type="png" data-w="1080" style=""></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">1) 缓存热点问题</span></strong> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">如下图所示,node-1 节点存在2个热点访问,请求量远高于其他节点。缓存热点会导致实例负载不均衡,从而严重影响响应速度。</span> </section> <p style="text-align: center;margin-bottom: 24px;"><strong><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="304487977" data-ratio="0.3527777777777778" data-s="300,640" src="/upload/a6f0b1ba456c80a9ddd0ff896d260e6a.png" data-type="png" data-w="1080" style=""></strong></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">缓存热点应对方案:热点识别自动构建多级缓存</span></strong> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">将单位时间内高频访问的Key,识别出来。例如:同一个Key,1秒内单机访问10次。</span> </section> <p style="text-align: center;margin-bottom: 24px;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="304487978" data-ratio="0.4074074074074074" data-s="300,640" src="/upload/160bdf34453405a5bc56380780cf6525.png" data-type="png" data-w="1080" style=""></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">如上图所示,自动发现Hot keys或将指定的Key加入到本地缓存。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <em><span style="font-size: 12px;">秒杀时:短暂的本地缓存可以减少Redis单实例热点,对数据的一致性不会有较大影响。</span></em> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">优化效果</span></strong> <span style="font-size: 15px;">:开启多级缓存后,同一个缓存key访问性能明显提升,对应Redis访问量也明显降低(如下图所示)。</span> </section> <p style="text-align: center;margin-bottom: 24px;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="304487979" data-ratio="0.3" data-s="300,640" src="/upload/4eb02db92a43f07f994c2affa1a7b0e5.png" data-type="png" data-w="1080" style=""></p> <p style="text-align: center;margin-bottom: 24px;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="304487983" data-ratio="0.2962962962962963" data-s="300,640" src="/upload/1dce5450ec199ca5c3249de44a072fc9.png" data-type="png" data-w="1080" style=""></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">2) 缓存大Key问题</span></strong> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">缓存大key的危害主要包括:阻塞请求、内存占用大、阻塞网络等。不仅会降低Redis的性能,还可能影响整个系统的稳定性(如下图所示)。</span> </section> <p style="text-align: center;margin-bottom: 24px;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="304487980" data-ratio="0.9923076923076923" data-s="300,640" src="/upload/8db462f75f2b0254dc6e59c5c4b8f31f.png" data-type="png" data-w="780" style="width: 244px;height: 242px;"><span style="font-size: 15px;letter-spacing: 0.034em;text-align: justify;">&nbsp;</span></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">通过memtier-benchmark工具在生产环境下压测:200KB以上比10KB以内的性能慢3倍,吞吐能力也下降76%(如下图所示)。</span> </section> <p style="text-align: center;margin-bottom: 24px;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="304487984" data-ratio="0.9722222222222222" data-s="300,640" src="/upload/e527a479b777bc64c730b5e46e204e43.png" data-type="png" data-w="1080" style="width: 309px;height: 301px;"></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">缓存大Key应对方案:</span></strong> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">a)<strong>精简缓存对象</strong>:去除缓存中的冗余字段。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">b)<strong>压缩缓存对象</strong>:采用压缩比更高的压缩方式,缩小缓存对象。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">c)<strong>拆分大Key</strong>:若精简和压缩后还是过大,根据业务逻辑,将大Key拆分成多个小Key。(注意拆分后IO次数会增加,高负载下性能不一定会变好,需要根据压测结果来评估最终性能)</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">d)<strong>长期治理</strong>:建立长期治理机制,定期扫描Redis中的大Key,每周跟进,将隐患在日常治理中消除。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">优化效果</span></strong> <span style="font-size: 15px;">:在大Key优化后,Redis查询性能有较为明显的提升(如下图所示,缓存查询耗时从300μs优化至100μs)。</span> </section> <p style="text-align: center;margin-bottom: 24px;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="304487981" data-ratio="0.3138888888888889" data-s="300,640" src="/upload/5bfab2a0a3bf531221d0a87c92a2681d.png" data-type="png" data-w="1080" style=""></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">问题二:数据库超负载</span></strong> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">系统中商品信息的变更往往伴随着缓存失效的问题,尤其在高并发和秒杀场景下,大量请求可能直接穿透缓存层,对数据库造成巨大压力,甚至引发性能故障。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">缓存更新策略优化:应对商品变更导致的数据库压力</span></strong> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">1) 常见的缓存架构设计问题</span></strong> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">监听器收到消息后删除相应的缓存Key。这种方式在一般情况下是有效的,但在高并发和大流量场景下,它存在几个突出的问题:</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">a)<strong>缓存击穿</strong>:由于缓存的Key被立即删除,大量请求在缓存未更新之前会直接访问数据库,导致数据库压力骤增。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">b)<strong>消息处理延迟</strong>:在高并发场景下,消息处理可能产生延迟,导致缓存更新不及时,进一步加剧数据库压力。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">2) 缓存更新策略的优化</span></strong> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">为了应对这些挑战,采取了一系列优化措施,主要包括:</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">a)<strong>缓存覆盖更新策略</strong>:替代直接删除缓存Key的做法,采用了缓存覆盖更新策略。当商品信息发生变更时,系统不再删除缓存Key,而是直接更新该Key对应的缓存值。避免了流量穿透到底层数据库。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">b)<strong>消息聚合</strong>:针对商品变化消息量过大的问题,引入了消息聚合机制。将商品多次变化消息在一段时间窗口内合并成一个,减少消息处理的频率。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">c)<strong>异步更新缓存</strong>:为了进一步降低对数据库的实时压力,采用了异步更新缓存的策略。当商品信息发生变更时,系统不会立即更新缓存,而是将更新任务放入一个异步队列中,由后台线程异步处理。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">缓存更新策略变化如下图所示:</span></strong> </section> <p style="text-align: center;margin-bottom: 24px;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="304487982" data-ratio="0.4222222222222222" data-s="300,640" src="/upload/f89126dacae9972465b2a33e9fe8268a.png" data-type="png" data-w="1080" style=""></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;letter-spacing: 0.034em;">问题三:供应商系统不稳定</span></strong> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">供应商系统因大流量导致响应缓慢或被限流,影响整体系统的稳定性。</span> </section> <p style="text-align: center;margin-bottom: 24px;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="304487985" data-ratio="0.5231481481481481" data-s="300,640" src="/upload/7c865d7141ecac8fdd08851d2b2482ff.png" data-type="png" data-w="1080" style="width: 509px;height: 266px;"></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">应对供应商系统不稳定性的技术策略优化</span></strong> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">当供应商系统面临大流量冲击时,往往会出现响应缓慢甚至被限流的情况,这直接影响了我们自身系统的稳定性和用户体验。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">供应商订单对接问题</span></strong> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">当与供应商进行订单对接时,可能会遇到以下问题:</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">a)<strong>被供应商限流</strong>:在高并发场景下,供应商系统可能会对我们限流。这会导致我们的订单提交受阻,影响业务流转。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">b)<strong>供应商系统不稳定</strong>:由于各种原因,供应商系统可能会出现不稳定的情况,导致订单处理延迟或失败。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">为了缓解上述问题,我们采取以下技术策略:</span></strong> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">1)<strong>削峰填谷/缓冲池</strong>:利用消息队列作为订单提交的缓冲池,将订单信息先写入队列,再由后台服务异步处理。这样可以将订单提交的高峰流量削平,减少对供应商系统的瞬时压力。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">2)<strong>禁售策略</strong></span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">•<strong>自动禁售</strong>:建立对供应商系统的健康度监控机制,实时监测其响应速度、错误率等指标。一旦发现供应商系统出现不稳定或限流的情况,及时触发禁售策略。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">•<strong>定期重试</strong>:对于因供应商系统问题而失败的订单,设定了一个重试机制,定期尝试重新提交。同时,根据供应商系统的恢复情况,动态调整重试的频率和次数。</span> </section> <p style="text-align: center;margin-bottom: 24px;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="304487988" data-ratio="0.36018518518518516" data-s="300,640" src="/upload/9ffd4ca7b370febaa25401eee1d62518.png" data-type="png" data-w="1080" style=""></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">优化效果</span></strong> <span style="font-size: 15px;">:通过实施上述技术和策略优化,可以有效确保供应商系统能力不影响下单吞吐量(如下图所示)。</span> </section> <p style="text-align: center;margin-bottom: 24px;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="304487986" data-ratio="0.5398148148148149" data-s="300,640" src="/upload/1d2186c089811f23704587e523e12e0c.png" data-type="png" data-w="1080" style="width: 495px;height: 267px;"></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">上述的优化措施落地后能够提升系统的稳定性,然而鉴于流量的不确定性,<strong>即使流量超过系统负载能力,系统也要正常运行</strong>,因此仍然需要有相应的流量控制策略。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">流量控制策略优化:确保秒杀活动稳定运行</span></strong> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">如下图所示,不同页面对应的流量和系统(承载能力)是不同的,需要控制好每个过程的流量,确保整体系统的稳定性。</span> </section> <p style="text-align: center;margin-bottom: 24px;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="304487987" data-ratio="0.5046296296296297" data-s="300,640" src="/upload/c5aae591ec87fe462880d5b992bf2940.png" data-type="png" data-w="1080" style="width: 498px;height: 251px;"><span style="font-size: 15px;letter-spacing: 0.034em;text-align: justify;">&nbsp;</span></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">以70万人购买5000张票的秒杀活动为例,可采取以下限流策略:</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">1) SOA限流:接口与应用级限流</span></strong> </section> <p style="text-align: center;margin-bottom: 24px;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="304487989" data-ratio="0.30092592592592593" data-s="300,640" src="/upload/88b290d2a4ed5ca81bd30a6193a1d359.png" data-type="png" data-w="1080" style="width: 547px;height: 165px;"><span style="font-size: 15px;letter-spacing: 0.034em;text-align: justify;">&nbsp;</span></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">通过服务治理框架对服务接口进行限流(SOA限流),在秒杀/活动等场景会影响到其他商品的正常售卖。对此可针对秒杀活动的特殊需求,设计自定义的限流策略,如按秒杀商品限流、页面级限流等,细化商品维度的流量控制。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">2) 自定义限流:商品级限流</span></strong> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">a)针对单个秒杀商品设置独立的限流阈值,即使某个商品超负载,也不会影响整体系统的可用性。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">b)同时,对于未知的秒杀突增流量,也可以支持热点商品自动限流,与Redis 热Key 发现类似,自动识别热点访问的商品,并添加到商品级限流中,从而确保整体系统的稳定运行。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">如下图所示,我们采用了商品维度的自定义限流策略,该策略将1秒内的请求流量划分为10个独立的100毫秒(可配置)滑动窗口。每个窗口都会平分一部分流量,以确保下游服务的并发量得到有效控制。这种方法不仅降低了下游服务的压力,也为用户提供更加均衡的流量分配。</span> </section> <p style="text-align: center;margin-bottom: 24px;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="304487990" data-ratio="0.31296296296296294" data-s="300,640" src="/upload/b3aae8da37f64af806c77a098f27c28b.png" data-type="png" data-w="1080" style=""></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">结合商品级限流能力,控制进入每一个页面的流量,形成多层次的限流防护体系,根据秒杀库存预估售卖时长,控制进入到每一个页面的流量比例,这样也能够大幅减少服务器资源投入。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">优化效果</span></strong> <span style="font-size: 15px;">:自定义限流可控制进入每一个页面的流量,超负载也不影响整体的可用性,服务器资源的投入也可控。</span> </section> <p style="text-align: center;margin-bottom: 24px;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="304487993" data-ratio="0.46574074074074073" data-s="300,640" src="/upload/2b7527b29d14445f2398860394daac03.png" data-type="png" data-w="1080" style=""></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">本部分阐述了系统稳定性的挑战及优化,包括Redis超负载与缓存热点、数据库超负载、供应商系统不稳定等。通过热点识别自动构建多级缓存、缓存覆盖更新策略、削峰填谷/缓冲池、自定义限流等多种技术策略,使得系统稳定性问题得到有效解决。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">3.2 写数据一致性挑战与应对策略</span></strong> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">下单过程中的库存扣减的精确执行,这种数据一致性的实现效果会直接影响订单是否能够成功履约,而传统关系型数据库的并发更新存在显著瓶颈,因此需要专项优化。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">扣减库存问题</span></strong> <span style="font-size: 15px;">:性能瓶颈 – MySQL热点行扣减库存(行级锁)。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">技术策略</span></strong> <span style="font-size: 15px;">:扣减库存异步化,异步扣库存主要分3步(见下图):</span> </section> <p style="text-align: center;margin-bottom: 24px;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="304487992" data-ratio="0.4324074074074074" data-s="300,640" src="/upload/6c77c4ad0400af623e6c77e69c418838.png" data-type="png" data-w="1080" style=""></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">1)初始化:秒杀商品设置好活动场次,将秒杀库存同步至Redis。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">2)扣库存:活动开始时,先从Redis扣减库存,在通过消息通知异步扣减DB库存,削除DB更新同一行的峰值。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">3)还库存:如果有退订,先判断DB中是否有扣减记录,如果有,则先退DB再退Redis;如果没有,重试多次。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">扣还库存过程中也会存在超时等未知情况,此处细节过多不再展开。按照业务“可少买不超卖”的原则,即使在这个过程中数据可能存在短暂的延时,但能够确保最终一致性。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">优化效果</span></strong> <span style="font-size: 15px;">:库存扣减异步化,消除行级锁瓶颈。现在系统能够轻松支撑数十万单/分钟交易流量。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">3.3 实现高可用的可持续性</span></strong> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">系统是不断演进的,如何保持并持续优化系统能力就成为新的课题。因此日常架构健康度持续治理、以及大型活动和节假日保障体系是实现高可用“可持续性”的关键。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">3.3.1&nbsp;架构健康度治理</span></strong> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">基于架构健康度实现系统质量的量化管理,实现研发生命周期各个环节的跟踪和优化,如下图所示可细分为三部分:</span> </section> <p style="text-align: center;margin-bottom: 24px;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="304487994" data-ratio="0.34074074074074073" data-s="300,640" src="/upload/d10c1d3c8ac8cbab432514bb7ff15194.png" data-type="png" data-w="1080" style=""></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">a) 系统运行健康度:通过系统各个维度运行时的健康状态和问题来反映系统质量。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">b) 架构设计健康度:服务数量、调用关系的复杂度、循环依赖、调用层级过深等因素都会影响系统的稳定性和性能。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">c) 工程化健康度:基于应用的工程质量和效率状态,反应出开发的工程化水平。</span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <strong><span style="font-size: 15px;">3.3.2 大型活动和节假日保障体系</span></strong> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">无论大型活动还是节假日,都需要提前准备好应急预案,做好压测,提前保证系统的高可用。</span> </section> <p style="text-align: center;margin-bottom: 24px;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="304487991" data-ratio="0.45" data-s="300,640" src="/upload/9da4056f6b6daca5a580432818317ed7.png" data-type="png" data-w="1080" style=""></p> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 17px;"><strong>四、总结</strong></span> </section> <section style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 24px;"> <span style="font-size: 15px;">本文总结了携程门票的预订交易系统在承接秒杀活动中面临的挑战与应对策略。重点解决了读热点、写瓶颈、强事务、流量控制等诸多细节问题,同时通过日常的架构健康度治理和制定专项的保障计划,持续对系统进行优化,确保系统在高负载下依然能够稳定运行,实现系统的持续高可用。</span> </section>

全能文件解析神器:探索Apache Tika的无限可能

作者:微信小助手

<p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100002346" data-ratio="0.562962962962963" data-s="300,640" src="/upload/b14f74babdac607759b8f689e7879287.png" data-type="png" data-w="1080" style=""></p> <section class="mp_profile_iframe_wrp"> <mp-common-profile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzkxNDMyNjk0Mw==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/xqE6h1Ct8BxPibzlG4lXezZ0Fu5bJ7xLjMdoeXp5yODTia1hZvJb1d9AcM3pNbqlMSHHjicGbUaws4Gg0vgxwBt1Q/0?wx_fmt=png" data-nickname="Walter Sun Tech" data-alias="WalterSunTech" data-signature="科技改变未来,Walter Sun Tech是你的IT技术前沿观察站。汇集编程、云计算、网络安全、人工智能、数据分析等领域动态,一手掌握行业脉搏,启发创新思维,与你共探科技世界的无限可能。" data-from="0" data-is_biz_ban="0"></mp-common-profile> </section> <section dir="auto" style="margin-bottom: 16px;color: rgb(204, 204, 204);font-family: -apple-system, &quot;system-ui&quot;, &quot;Segoe WPC&quot;, &quot;Segoe UI&quot;, system-ui, Ubuntu, &quot;Droid Sans&quot;, sans-serif;font-size: 14px;letter-spacing: normal;text-align: start;text-wrap: wrap;text-indent: 2em;"> <span style="color: rgb(0, 0, 0);">Apache Tika是一个开源的内容分析工具集,它是由Apache软件基金会开发的。Tika帮助用户探测和抽取元数据以及结构化的内容(如文本)从各种类型的文件。Tika是一个底层库,经常用于搜索引擎、内容管理系统、数据分析任务等领域,无缝地集成到其他应用或服务中以增强对文件内容处理的能力。</span> </section> <h3 data-line="2" dir="auto" style="margin-top: 24px;font-weight: 600;margin-bottom: 16px;line-height: 1.25;font-size: 1.25em;color: rgb(204, 204, 204);font-family: -apple-system, &quot;system-ui&quot;, &quot;Segoe WPC&quot;, &quot;Segoe UI&quot;, system-ui, Ubuntu, &quot;Droid Sans&quot;, sans-serif;letter-spacing: normal;text-align: start;text-wrap: wrap;"><span style="color: rgb(0, 0, 0);">核心特性</span></h3> <ol data-line="4" class="list-paddingleft-1" dir="auto" style="margin-bottom: 0.7em;color: rgb(204, 204, 204);font-family: -apple-system, &quot;system-ui&quot;, &quot;Segoe WPC&quot;, &quot;Segoe UI&quot;, system-ui, Ubuntu, &quot;Droid Sans&quot;, sans-serif;font-size: 14px;letter-spacing: normal;text-align: start;text-wrap: wrap;"> <li style="color: rgb(0, 0, 0);"><p><span style="color: rgb(0, 0, 0);"><strong>文件格式自动探测</strong>:可以识别和验证超过一千种文件类型(包括文本、图像、视频和其他多媒体文件)。</span></p></li> <li style="color: rgb(0, 0, 0);"><p><span style="color: rgb(0, 0, 0);"><strong>元数据提取</strong>:从各种文件格式中提取元数据,如作者、标题、创建日期等。</span></p></li> <li style="color: rgb(0, 0, 0);"><p><span style="color: rgb(0, 0, 0);"><strong>内容抽取</strong>:提取文件内容,包括文本内容,可能还有嵌入的资源,如图像。</span></p></li> <li style="color: rgb(0, 0, 0);"><p><span style="color: rgb(0, 0, 0);"><strong>语言识别</strong>:可以识别文本的语言。</span></p></li> <li style="color: rgb(0, 0, 0);"><p><span style="color: rgb(0, 0, 0);"><strong>可扩展</strong>:可以通过自定义解析器和特定的文件处理器来扩展Tika的功能。</span></p></li> </ol> <h3 data-line="10" dir="auto" style="margin-top: 24px;font-weight: 600;margin-bottom: 16px;line-height: 1.25;font-size: 1.25em;color: rgb(204, 204, 204);font-family: -apple-system, &quot;system-ui&quot;, &quot;Segoe WPC&quot;, &quot;Segoe UI&quot;, system-ui, Ubuntu, &quot;Droid Sans&quot;, sans-serif;letter-spacing: normal;text-align: start;text-wrap: wrap;"><span style="color: rgb(0, 0, 0);">Tika架构组件</span></h3> <p data-line="12" dir="auto" style="margin-bottom: 16px;color: rgb(204, 204, 204);font-family: -apple-system, &quot;system-ui&quot;, &quot;Segoe WPC&quot;, &quot;Segoe UI&quot;, system-ui, Ubuntu, &quot;Droid Sans&quot;, sans-serif;font-size: 14px;letter-spacing: normal;text-align: start;text-wrap: wrap;"><span style="color: rgb(0, 0, 0);">Apache Tika主要由以下几个关键组件组成:</span></p> <ol data-line="14" class="list-paddingleft-2" dir="auto" style="margin-bottom: 0.7em;color: rgb(204, 204, 204);font-family: -apple-system, &quot;system-ui&quot;, &quot;Segoe WPC&quot;, &quot;Segoe UI&quot;, system-ui, Ubuntu, &quot;Droid Sans&quot;, sans-serif;font-size: 14px;letter-spacing: normal;text-align: start;text-wrap: wrap;"> <li style="color: rgb(0, 0, 0);"><p data-line="14" dir="auto" style="margin-bottom: 0.7em;"><span style="color: rgb(0, 0, 0);"><strong>Tika API</strong>:</span></p></li> <ul data-line="15" class="list-paddingleft-1" dir="auto" style="margin-bottom: 0.7em;"> <li style="color: rgb(0, 0, 0);"><p><span style="color: rgb(0, 0, 0);">核心API提供了解析文档和提取文档中的内容和元数据的基础框架。</span></p></li> </ul> <li style="color: rgb(0, 0, 0);"><p data-line="17" dir="auto" style="margin-bottom: 0.7em;"><span style="color: rgb(0, 0, 0);"><strong>Parser</strong>(解析器):</span></p></li> <ul data-line="18" class="list-paddingleft-1" dir="auto" style="margin-bottom: 0.7em;"> <li style="color: rgb(0, 0, 0);"><p><span style="color: rgb(0, 0, 0);">Tika使用一系列的解析器来处理不同类型的文件格式,并抽取内容和元数据。</span></p></li> </ul> <li style="color: rgb(0, 0, 0);"><p data-line="20" dir="auto" style="margin-bottom: 0.7em;"><span style="color: rgb(0, 0, 0);"><strong>Detector</strong>(探测器):</span></p></li> <ul data-line="21" class="list-paddingleft-1" dir="auto" style="margin-bottom: 0.7em;"> <li style="color: rgb(0, 0, 0);"><p><span style="color: rgb(0, 0, 0);">用于探测文件的媒体类型(MIME类型),判断文件内容的确切类型。</span></p></li> </ul> <li style="color: rgb(0, 0, 0);"><p data-line="23" dir="auto" style="margin-bottom: 0.7em;"><span style="color: rgb(0, 0, 0);"><strong>ContentHandler</strong>:</span></p></li> <ul data-line="24" class="list-paddingleft-1" dir="auto" style="margin-bottom: 0.7em;"> <li style="color: rgb(0, 0, 0);"><p><span style="color: rgb(0, 0, 0);">用于处理解析器抽取出的原始内容,可能转换成XHTML或其他格式。</span></p></li> </ul> <li style="color: rgb(0, 0, 0);"><p data-line="26" dir="auto" style="margin-bottom: 0.7em;"><span style="color: rgb(0, 0, 0);"><strong>MIME Repository</strong>:</span></p></li> <ul data-line="27" class="list-paddingleft-1" dir="auto" style="margin-bottom: 0.7em;"> <li style="color: rgb(0, 0, 0);"><p><span style="color: rgb(0, 0, 0);">一个MIME类型的数据库,帮助Tika探测具体的文件格式。</span></p></li> </ul> <li style="color: rgb(0, 0, 0);"><p data-line="29" dir="auto" style="margin-bottom: 0.7em;"><span style="color: rgb(0, 0, 0);"><strong>Metadata</strong>:</span></p></li> <ul data-line="30" class="list-paddingleft-1" dir="auto" style="margin-bottom: 0.7em;"> <li style="color: rgb(0, 0, 0);"><p><span style="color: rgb(0, 0, 0);">用来存储和访问文件元数据。</span></p></li> </ul> </ol> <h3 data-line="32" dir="auto" style="margin-top: 24px;font-weight: 600;margin-bottom: 16px;line-height: 1.25;font-size: 1.25em;color: rgb(204, 204, 204);font-family: -apple-system, &quot;system-ui&quot;, &quot;Segoe WPC&quot;, &quot;Segoe UI&quot;, system-ui, Ubuntu, &quot;Droid Sans&quot;, sans-serif;letter-spacing: normal;text-align: start;text-wrap: wrap;"><span style="color: rgb(0, 0, 0);">使用示例</span></h3> <section dir="auto" style="margin-bottom: 16px;color: rgb(204, 204, 204);font-family: -apple-system, &quot;system-ui&quot;, &quot;Segoe WPC&quot;, &quot;Segoe UI&quot;, system-ui, Ubuntu, &quot;Droid Sans&quot;, sans-serif;font-size: 14px;letter-spacing: normal;text-align: start;text-wrap: wrap;text-indent: 2em;"> <span style="color: rgb(0, 0, 0);">以下是一个使用Tika的基本的Java代码示例:</span> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="swift"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">import</span> org.apache.tika.exception.TikaException;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">import</span> org.apache.tika.metadata.Metadata;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">import</span> org.apache.tika.parser.AutoDetectParser;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">import</span> org.apache.tika.parser.ParseContext;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">import</span> org.apache.tika.parser.Parser;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">import</span> org.apache.tika.sax.BodyContentHandler;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">import</span> org.xml.sax.SAXException;</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">import</span> java.io.File;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">import</span> java.io.FileInputStream;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">import</span> java.io.IOException;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">import</span> java.io.InputStream;</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> <span class="code-snippet__class"><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">TikaExample</span> </span>{</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">static</span> void main(<span class="code-snippet__type">String</span>[] args) <span class="code-snippet__keyword">throws</span> <span class="code-snippet__type">IOException</span>, <span class="code-snippet__type">TikaException</span>, <span class="code-snippet__type">SAXException</span> {</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 创建一个内容处理器和一个元数据实例</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__type">BodyContentHandler</span> handler = new <span class="code-snippet__type">BodyContentHandler</span>();</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__type">Metadata</span> metadata = new <span class="code-snippet__type">Metadata</span>();</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__type">FileInputStream</span> inputstream = new <span class="code-snippet__type">FileInputStream</span>(new <span class="code-snippet__type">File</span>(<span class="code-snippet__string">"example.docx"</span>));</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__type">ParseContext</span> pcontext = new <span class="code-snippet__type">ParseContext</span>();</span></code><code><span class="code-snippet_outer"> </span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 自动检测文档类型(探测器的工作)</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__type">Parser</span> parser = new <span class="code-snippet__type">AutoDetectParser</span>();</span></code><code><span class="code-snippet_outer"> </span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 解析文档并提取内容和元数据</span></span></code><code><span class="code-snippet_outer"> parser.parse(inputstream, handler, metadata, pcontext);</span></code><code><span class="code-snippet_outer"> </span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 打印文档内容</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__type">System</span>.out.<span class="code-snippet__built_in">println</span>(<span class="code-snippet__string">"Contents of the document:"</span> + handler.<span class="code-snippet__built_in">toString</span>());</span></code><code><span class="code-snippet_outer"> </span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 打印元数据信息</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__type">String</span>[] metadataNames = metadata.names();</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">for</span> (<span class="code-snippet__type">String</span> name : metadataNames) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__type">System</span>.out.<span class="code-snippet__built_in">println</span>(name + <span class="code-snippet__string">": "</span> + metadata.<span class="code-snippet__keyword">get</span>(name));</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> </span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 关闭输入流</span></span></code><code><span class="code-snippet_outer"> inputstream.close();</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <section dir="auto" style="margin-bottom: 16px;color: rgb(204, 204, 204);font-family: -apple-system, &quot;system-ui&quot;, &quot;Segoe WPC&quot;, &quot;Segoe UI&quot;, system-ui, Ubuntu, &quot;Droid Sans&quot;, sans-serif;font-size: 14px;letter-spacing: normal;text-align: start;text-wrap: wrap;text-indent: 2em;"> <span style="color: rgb(0, 0, 0);">这段代码中使用了Tika的</span> <code style="font-family: var(--vscode-editor-font-family, &quot;SF Mono&quot;, Monaco, Menlo, Consolas, &quot;Ubuntu Mono&quot;, &quot;Liberation Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Courier New&quot;, monospace);color: var(--vscode-textPreformat-foreground);padding: 1px 3px;border-radius: 4px;font-size: 1em;line-height: 1.357em;"><span style="color: rgb(0, 0, 0);">AutoDetectParser</span></code> <span style="color: rgb(0, 0, 0);">,它可以自动检测和解析文件类型,并使用</span> <code style="font-family: var(--vscode-editor-font-family, &quot;SF Mono&quot;, Monaco, Menlo, Consolas, &quot;Ubuntu Mono&quot;, &quot;Liberation Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Courier New&quot;, monospace);color: var(--vscode-textPreformat-foreground);padding: 1px 3px;border-radius: 4px;font-size: 1em;line-height: 1.357em;"><span style="color: rgb(0, 0, 0);">BodyContentHandler</span></code> <span style="color: rgb(0, 0, 0);">来处理抽取到的文本内容。</span> </section> <h3 data-line="84" dir="auto" style="margin-top: 24px;font-weight: 600;margin-bottom: 16px;line-height: 1.25;font-size: 1.25em;color: rgb(204, 204, 204);font-family: -apple-system, &quot;system-ui&quot;, &quot;Segoe WPC&quot;, &quot;Segoe UI&quot;, system-ui, Ubuntu, &quot;Droid Sans&quot;, sans-serif;letter-spacing: normal;text-align: start;text-wrap: wrap;"><span style="color: rgb(0, 0, 0);">安装和依赖管理</span></h3> <section dir="auto" style="margin-bottom: 16px;color: rgb(204, 204, 204);font-family: -apple-system, &quot;system-ui&quot;, &quot;Segoe WPC&quot;, &quot;Segoe UI&quot;, system-ui, Ubuntu, &quot;Droid Sans&quot;, sans-serif;font-size: 14px;letter-spacing: normal;text-align: start;text-wrap: wrap;text-indent: 2em;"> <span style="color: rgb(0, 0, 0);">要在项目中使用Tika,通常需要通过依赖管理工具如Maven或Gradle来添加对应的依赖。</span> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="xml"><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;<span class="code-snippet__name">dependency</span>&gt;</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag">&lt;<span class="code-snippet__name">groupId</span>&gt;</span>org.apache.tika<span class="code-snippet__tag">&lt;/<span class="code-snippet__name">groupId</span>&gt;</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag">&lt;<span class="code-snippet__name">artifactId</span>&gt;</span>tika-core<span class="code-snippet__tag">&lt;/<span class="code-snippet__name">artifactId</span>&gt;</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag">&lt;<span class="code-snippet__name">version</span>&gt;</span>1.24<span class="code-snippet__tag">&lt;/<span class="code-snippet__name">version</span>&gt;</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;/<span class="code-snippet__name">dependency</span>&gt;</span></span></code></pre> </section> <section dir="auto" style="margin-bottom: 16px;color: rgb(204, 204, 204);font-family: -apple-system, &quot;system-ui&quot;, &quot;Segoe WPC&quot;, &quot;Segoe UI&quot;, system-ui, Ubuntu, &quot;Droid Sans&quot;, sans-serif;font-size: 14px;letter-spacing: normal;text-align: start;text-wrap: wrap;text-indent: 2em;"> <span style="color: rgb(0, 0, 0);">此外,也可以添加</span> <code style="font-family: var(--vscode-editor-font-family, &quot;SF Mono&quot;, Monaco, Menlo, Consolas, &quot;Ubuntu Mono&quot;, &quot;Liberation Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Courier New&quot;, monospace);color: var(--vscode-textPreformat-foreground);padding: 1px 3px;border-radius: 4px;font-size: 1em;line-height: 1.357em;"><span style="color: rgb(0, 0, 0);">tika-parsers</span></code> <span style="color: rgb(0, 0, 0);">模块依赖以支持更多类型的文件解析:</span> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="xml"><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;<span class="code-snippet__name">dependency</span>&gt;</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag">&lt;<span class="code-snippet__name">groupId</span>&gt;</span>org.apache.tika<span class="code-snippet__tag">&lt;/<span class="code-snippet__name">groupId</span>&gt;</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag">&lt;<span class="code-snippet__name">artifactId</span>&gt;</span>tika-parsers<span class="code-snippet__tag">&lt;/<span class="code-snippet__name">artifactId</span>&gt;</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag">&lt;<span class="code-snippet__name">version</span>&gt;</span>1.24<span class="code-snippet__tag">&lt;/<span class="code-snippet__name">version</span>&gt;</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag">&lt;/<span class="code-snippet__name">dependency</span>&gt;</span></span></code></pre> </section> <section dir="auto" style="margin-bottom: 16px;color: rgb(204, 204, 204);font-family: -apple-system, &quot;system-ui&quot;, &quot;Segoe WPC&quot;, &quot;Segoe UI&quot;, system-ui, Ubuntu, &quot;Droid Sans&quot;, sans-serif;font-size: 14px;letter-spacing: normal;text-align: start;text-wrap: wrap;text-indent: 2em;"> <span style="color: rgb(0, 0, 0);">Apache Tika还有一个独立的命令行接口,允许用户在没有Java编程的情况下运行Tika并提取文件内容。通过Tika的命令行可以直接查看文件的元数据或者文本内容,这对于快速测试或小型项目特别有用。</span> </section> <section dir="auto" style="margin-bottom: 16px;color: rgb(204, 204, 204);font-family: -apple-system, &quot;system-ui&quot;, &quot;Segoe WPC&quot;, &quot;Segoe UI&quot;, system-ui, Ubuntu, &quot;Droid Sans&quot;, sans-serif;font-size: 14px;letter-spacing: normal;text-align: start;text-wrap: wrap;text-indent: 2em;"> <span style="color: rgb(0, 0, 0);">总结一下,Apache Tika是一个强大的文档分析框架,适合处理和抽取大量不同文件格式的内容。它在搜索引擎索引、内容管理系统、数据分析等领域有着广泛的应用。</span> </section> <section class="mp_profile_iframe_wrp"> <mp-common-profile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzkxNDMyNjk0Mw==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/xqE6h1Ct8BxPibzlG4lXezZ0Fu5bJ7xLjMdoeXp5yODTia1hZvJb1d9AcM3pNbqlMSHHjicGbUaws4Gg0vgxwBt1Q/0?wx_fmt=png" data-nickname="Walter Sun Tech" data-alias="WalterSunTech" data-signature="科技改变未来,Walter Sun Tech是你的IT技术前沿观察站。汇集编程、云计算、网络安全、人工智能、数据分析等领域动态,一手掌握行业脉搏,启发创新思维,与你共探科技世界的无限可能。" data-from="0" data-is_biz_ban="0"></mp-common-profile> </section> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>