国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
為你的基于SPRING的應(yīng)用增加簡(jiǎn)單規(guī)則引擎
摘要

這篇文章解釋了在J2EE應(yīng)用中規(guī)則引擎及聲明性業(yè)務(wù)邏輯的優(yōu)點(diǎn),并且描述如何為流行的Spring框架開(kāi)發(fā)簡(jiǎn)單的規(guī)則引擎。此文需要讀者對(duì)Spring有基本的了解。

任何大一點(diǎn)的軟件項(xiàng)目都包含了許多叫做業(yè)務(wù)邏輯的東西。業(yè)務(wù)邏輯的準(zhǔn)確描述還是有爭(zhēng)議的。在為典型應(yīng)用軟件的生成的大量代碼中,到處都是為如訂單處理、武器控制系統(tǒng)、圖形繪制等功能工作的零碎代碼。這些代碼與其他如處理持久化、日志、事務(wù)、語(yǔ)言偏好、框架特性及其他現(xiàn)代企業(yè)級(jí)應(yīng)用有明顯不同。

業(yè)務(wù)邏輯通常與其他代碼塊緊密的混和在一起。當(dāng)重量級(jí)的侵入式框架(如EJB)被使用時(shí),區(qū)別業(yè)務(wù)邏輯與框架生成的代碼就變得非常困難。

有一個(gè)軟件需求在需求定義文檔很難準(zhǔn)確描述,卻擁有使軟件項(xiàng)目成功或失敗的能力:適應(yīng)性,這是用來(lái)衡量軟件響應(yīng)業(yè)務(wù)變更容易程度的標(biāo)準(zhǔn)。

現(xiàn)代企業(yè)要求響應(yīng)快速及靈活,他們對(duì)企業(yè)軟件也有同樣的要求??赡苣憬裉煨量鄬?shí)現(xiàn)的業(yè)務(wù)規(guī)則在明天就被廢棄了而且要求你根據(jù)變更快速而準(zhǔn)確的改變。當(dāng)你的包含業(yè)務(wù)邏輯的代碼隱藏在大量其他代碼中時(shí),修改就變得緩慢、痛若且易出錯(cuò)了。

在今天的企業(yè)級(jí)軟件中沒(méi)有奇跡,比較流行的是規(guī)則引擎和各種業(yè)務(wù)過(guò)程管理(BPM)系統(tǒng)。如果你看一下市場(chǎng)上的宣傳,這類工具都承諾一件事:保存在倉(cāng)庫(kù)中的捕獲業(yè)務(wù)邏輯的圣杯能夠清晰的分離且由自己維護(hù),并隨時(shí)準(zhǔn)備讓你現(xiàn)有的應(yīng)用來(lái)調(diào)用。

雖然商業(yè)的規(guī)則引擎和BPM系統(tǒng)有許多優(yōu)點(diǎn),但也有不少缺點(diǎn)。最大的缺點(diǎn)就是價(jià)格,通常很容易就達(dá)到7位數(shù)。另一個(gè)就是除了主要的行業(yè)規(guī)范和眾多記在紙上的標(biāo)準(zhǔn)外缺乏事實(shí)上的標(biāo)準(zhǔn)。而且隨著越來(lái)越多的軟件項(xiàng)目采用敏捷、輕量級(jí)的快速開(kāi)發(fā)方法,這些重量級(jí)的工具變得不符合潮流了。
在這篇文章中,我們建立了一個(gè)簡(jiǎn)單的規(guī)則引擎,一方面平衡系統(tǒng)與業(yè)務(wù)邏輯的分離,另一方面由于他基于目前流行的強(qiáng)大的J2EE框架因而不需要承受商業(yè)軟件的復(fù)雜性與不協(xié)調(diào)性。

J2EE世界中的Spring時(shí)代

在企業(yè)級(jí)軟件的復(fù)雜性變得不能忍受及業(yè)務(wù)邏輯問(wèn)題越來(lái)越重要時(shí),Spring及類似的框架產(chǎn)生了??梢詳喽⊿pring在以后很長(zhǎng)一段時(shí)間內(nèi)是企業(yè)級(jí)Java中的佼佼者。Spring提供了很多工具及少量代碼約定使J2EE的開(kāi)發(fā)更面向?qū)ο?,更容易也更有趣?br>
Spring的核心是IoC原則,這是一個(gè)奇特而超負(fù)荷的名字,但包含下面的簡(jiǎn)單想法:
●功能代碼需要分開(kāi)到更小的可管理片斷
●這些片斷是簡(jiǎn)單的,標(biāo)準(zhǔn)的JavaBean(簡(jiǎn)單的Java類擁有但不包含全部的JavaBean規(guī)范)
●你不需要參與管理這些Bean(如創(chuàng)建、銷毀、設(shè)置依賴)
●相反Spring容器通過(guò)上下文定義來(lái)為你做這些(通常為XML文件格式)

Spring也提供了很多其他特性,如完整而強(qiáng)大的MVC框架,簡(jiǎn)便的JDBC開(kāi)發(fā)包裝及其他框架。但那些主題已經(jīng)超出這篇幅文章的討論范圍。

在我描述需要什么來(lái)創(chuàng)建基于SPRING應(yīng)用的簡(jiǎn)單規(guī)則引擎之前,讓我們想一下為什么這是一種好的想法。

規(guī)則引擎設(shè)計(jì)有兩點(diǎn)有趣的特性使其更有價(jià)值:
●首先,從應(yīng)用領(lǐng)域分離了業(yè)務(wù)邏輯代碼。
●其次,可配置性意味著業(yè)務(wù)規(guī)則的定義及其使用的順序被存儲(chǔ)在應(yīng)用的外部,這樣就可以由規(guī)則創(chuàng)建人員來(lái)控制而不是應(yīng)用的使用者或者開(kāi)發(fā)人員了。

Spring為規(guī)則引擎提供了一個(gè)好的方法。一個(gè)良好編碼的Spring應(yīng)用的強(qiáng)組件化的設(shè)計(jì)會(huì)使你的代碼變成更小的、可管理的分散片斷,這樣就更易在Spring的上下文定義中配置。
繼續(xù)了解在規(guī)則引擎設(shè)計(jì)的需求與Spring設(shè)計(jì)提供的功能之間的結(jié)合點(diǎn)。

基于Spring的規(guī)則引擎的設(shè)計(jì)

我們?cè)赟pring控制的JavaBean基礎(chǔ)上開(kāi)始設(shè)計(jì),這里我們叫做規(guī)則引擎組件。我們來(lái)定義下面兩種我們可能需要的組件類型:
●操作—在應(yīng)用邏輯中確定用來(lái)做什么的組件
●規(guī)則—在一系列行為的邏輯流中做出決定的組件

我們都是面向?qū)ο笤O(shè)計(jì)的追隨者,下面的基類建立了所有我們的組件需要通過(guò)參數(shù)被其他組件調(diào)用的基本功能:

public abstract class AbstractComponent {
   public abstract void execute(Object arg) throws Exception;
}


當(dāng)然基類是抽象的因?yàn)槲覀兏静恍枰@樣的實(shí)例。
AbstractAction的代碼擴(kuò)展了基類來(lái)實(shí)現(xiàn)其他具體的操作:

public abstract class AbstractAction extends AbstractComponent {

   private AbstractComponent nextStep;
  
   public void execute(Object arg) throws Exception {
      this.doExecute(arg);
      if(nextStep != null)
         nextStep.execute(arg);
   }
  
   protected abstract void doExecute(Object arg) throws Exception;

   public void setNextStep(AbstractComponent nextStep) {
      this.nextStep = nextStep;
   }

   public AbstractComponent getNextStep() {
      return nextStep;
   }

}


你可以看到,AbstractAction做兩件事:首先他保存在規(guī)則引擎中被激活的下一個(gè)組件的定義;其次在他的execute()方法中,調(diào)用被具體類實(shí)現(xiàn)的doExecute()方法,在doExecute()返回后,如果存在下一個(gè)組件則調(diào)用他。
我們的AbstractRule也相當(dāng)簡(jiǎn)單:

public abstract class AbstractRule extends AbstractComponent {

   private AbstractComponent positiveOutcomeStep;
   private AbstractComponent negativeOutcomeStep;
  
   public void execute(Object arg) throws Exception {
      boolean outcome = makeDecision(arg);
      if(outcome)
         positiveOutcomeStep.execute(arg);
      else
         negativeOutcomeStep.execute(arg);

   }

   protected abstract boolean makeDecision(Object arg) throws Exception;


// 為簡(jiǎn)單起見(jiàn),positiveOutcomeStep和negativeOutcomeStep 的Getters 和 setters均已省略
在其execute()方法中,AbstractAction調(diào)用由子類實(shí)現(xiàn)的makeDecision()方法,然后根據(jù)方法的返回值,調(diào)用組件定義的肯定或否定結(jié)果的方法。
在我們介紹了SpringRuleEngine類后我們的設(shè)計(jì)就基本完成了:

public class SpringRuleEngine {
  
   private AbstractComponent firstStep;
  
   public void setFirstStep(AbstractComponent firstStep) {
      this.firstStep = firstStep;
   }
  
   public void processRequest(Object arg) throws Exception {
      firstStep.execute(arg);
   }
  
}


這就是我們規(guī)則引擎主類的全部:定義第一個(gè)業(yè)務(wù)邏輯中的組件及開(kāi)始執(zhí)行的方法。
但是請(qǐng)稍等,在哪里綁定我們的類使之可以工作呢?下面你就可以看到如何利用Spring來(lái)幫助我們完成工作的方法了。

在操作中的基于Spring的規(guī)則引擎

讓我們看一下這個(gè)框架如何工作的具體實(shí)例吧。想象下面的用例:我們需要開(kāi)發(fā)負(fù)責(zé)貸款申請(qǐng)的應(yīng)用程序。我們需要滿足下面的條件:
●檢查應(yīng)用的完整性否則駁回
●檢查應(yīng)用是否來(lái)自我們授權(quán)處理業(yè)務(wù)的應(yīng)用。
●檢查申請(qǐng)者的月收支比是否滿足我們的要求。
●輸入的申請(qǐng)通過(guò)我們不知道實(shí)現(xiàn)細(xì)節(jié)的持久服務(wù)被存儲(chǔ)在數(shù)據(jù)庫(kù)中,我們只知道他的接口(可能這個(gè)開(kāi)發(fā)被外包到印度了)
●業(yè)務(wù)規(guī)則是可以改變的,這也是為什么需要規(guī)則引擎的設(shè)計(jì)了。

首先,設(shè)計(jì)一個(gè)表示貸款申請(qǐng)的類:

public class LoanApplication {
  
   public static final String INVALID_STATE = "Sorry we are not doing business in your state";
   public static final String INVALID_INCOME_EXPENSE_RATIO = "Sorry we cannot provide the loan given this expense/income ratio";
   public static final String APPROVED = "Your application has been approved";
   public static final String INSUFFICIENT_DATA = "You did not provide enough information on your application";
   public static final String INPROGRESS = "in progress";
  
   public static final String[] STATUSES =
      new String[] {
         INSUFFICIENT_DATA, INVALID_INCOME_EXPENSE_RATIO, INVALID_STATE, APPROVED, INPROGRESS
      };

   private String firstName;
   private String lastName;
   private double income;
   private double expences;
   private String stateCode;
   private String status;
  
   public void setStatus(String status) {
      if(!Arrays.asList(STATUSES).contains(status))
         throw new IllegalArgumentException("invalid status:" + status);
      this.status = status;
   }

// 其他getters and setters已被省略

}


我們使用的持久服務(wù)擁有如下接口:

public interface LoanApplicationPersistenceInterface {
   public void recordApproval(LoanApplication application) throws Exception;
   public void recordRejection(LoanApplication application) throws Exception;
   public void recordIncomplete(LoanApplication application) throws Exception;
}


我們迅速開(kāi)發(fā)一個(gè)什么也不做只是用來(lái)滿足接口約定的MockLoanApplicationPersistence類來(lái)欺騙接口。
我們使用下面的SpringRuleEngine類的子類來(lái)加載Spring上下文并開(kāi)始處理:

public class LoanProcessRuleEngine extends SpringRuleEngine {
   public static final SpringRuleEngine getEngine(String name) {
      ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("SpringRuleEngineContext.xml");
      return (SpringRuleEngine) context.getBean(name);
   }
}


這時(shí)候,我們已經(jīng)有了代碼框架了,因此是時(shí)候?qū)慗Unit測(cè)試了,代碼如下。其中包含一些假設(shè):我們期望公司僅在兩種州運(yùn)作,德克薩斯和密歇根。而且我們只接受收支比在70%或更好的人的貸款申請(qǐng)。

public class SpringRuleEngineTest extends TestCase {

   public void testSuccessfulFlow() throws Exception {
      SpringRuleEngine engine = LoanProcessRuleEngine.getEngine("SharkysExpressLoansApplicationProcessor");
      LoanApplication application = new LoanApplication();
      application.setFirstName("John");
      application.setLastName("Doe");
      application.setStateCode("TX");
      application.setExpences(4500);
      application.setIncome(7000);
      engine.processRequest(application);
      assertEquals(LoanApplication.APPROVED, application.getStatus());
   }
  
   public void testInvalidState() throws Exception {
      SpringRuleEngine engine = LoanProcessRuleEngine.getEngine("SharkysExpressLoansApplicationProcessor");
      LoanApplication application = new LoanApplication();
      application.setFirstName("John");
      application.setLastName("Doe");
      application.setStateCode("OK");
      application.setExpences(4500);
      application.setIncome(7000);
      engine.processRequest(application);
      assertEquals(LoanApplication.INVALID_STATE, application.getStatus());
   }
  
   public void testInvalidRatio() throws Exception {
      SpringRuleEngine engine = LoanProcessRuleEngine.getEngine("SharkysExpressLoansApplicationProcessor");
      LoanApplication application = new LoanApplication();
      application.setFirstName("John");
      application.setLastName("Doe");
      application.setStateCode("MI");
      application.setIncome(7000);
      application.setExpences(0.80 * 7000); //too high      
      engine.processRequest(application);
      assertEquals(LoanApplication.INVALID_INCOME_EXPENSE_RATIO, application.getStatus());
   }
  
   public void testIncompleteApplication() throws Exception {      
      SpringRuleEngine engine = LoanProcessRuleEngine.getEngine("SharkysExpressLoansApplicationProcessor");
      LoanApplication application = new LoanApplication();
      engine.processRequest(application);
      assertEquals(LoanApplication.INSUFFICIENT_DATA, application.getStatus());
   }

      
顯然單元測(cè)試會(huì)失敗因?yàn)槲覀冞€沒(méi)有實(shí)現(xiàn)任何的邏輯。然而,隨著項(xiàng)目的進(jìn)展,越來(lái)越多的測(cè)試通過(guò),最后JUnit測(cè)試就全部通過(guò)了。
讓我們繼續(xù)操作和規(guī)則的實(shí)現(xiàn)。我們希望操作與持久服務(wù)交互因此我們需要一個(gè)通用基類:

public abstract class AbstractPersistenceAwareAction extends AbstractAction {
   private LoanApplicationPersistenceInterface persistenceService;
   public void setPersistenceService(LoanApplicationPersistenceInterface persistenceService) {
      this.persistenceService = persistenceService;
   }
   public LoanApplicationPersistenceInterface getPersistenceService() {
      return persistenceService;
   }
}


在我們的進(jìn)程中第一個(gè)請(qǐng)求貸款申請(qǐng)的業(yè)務(wù)規(guī)則已經(jīng)完成:

public class ValidApplicationRule extends AbstractRule {
   protected boolean makeDecision(Object arg) throws Exception {
      LoanApplication application = (LoanApplication) arg;
      if(application.getExpences() == 0 ||
            application.getFirstName() == null ||
            application.getIncome() == 0 ||
            application.getLastName() == null ||
            application.getStateCode() == null) {
         application.setStatus(LoanApplication.INSUFFICIENT_DATA);
         return false;
      }
      return true;
   }
}


注意這個(gè)類的一些有趣的現(xiàn)象:他是完全自包含的。他可以由自己實(shí)例化或者任何外部的應(yīng)用容器,而類中的邏輯可以獨(dú)立的開(kāi)發(fā)和測(cè)試。這些現(xiàn)象使類成為基于規(guī)則應(yīng)用的完美的程序塊。

現(xiàn)在是時(shí)候通過(guò)Spring容器來(lái)綁定對(duì)象了。就象你在單元測(cè)試中看到的一樣,我們使用LoanProcessRuleEngine類作為入口指向請(qǐng)求名為SharkysExpressLoansApplicationProcessor的Bean的規(guī)則引擎。下面是這個(gè)Bean如何在SpringRuleEngineContext.xml定義:

   <!-- 規(guī)則引擎處理器 -->
   <bean id="SharkysExpressLoansApplicationProcessor" class="SpringRuleEngine">
      <property name="firstStep">
         <ref bean="ValidApplicationRule"/>
      </property>
   </bean>
這個(gè)Bean簡(jiǎn)單地指明ValidApplicationRule為業(yè)務(wù)處理的第一個(gè)步驟。這個(gè)組件如下定義:
   <!-- validation -->
   <bean id="ValidApplicationRule" class="ValidApplicationRule">
      <property name="positiveOutcomeStep">
         <ref bean="ValidStateRule"/>
      </property>
      <property name="negativeOutcomeStep">
         <ref bean="RejectionAction"></ref>
      </property>
   </bean>


你可以看到,規(guī)則自身也在Spring上下文中定義:如果貸款申請(qǐng)是合法的,應(yīng)用會(huì)檢查是否正確的州;否則控制傳遞給RejectionAction。
RejectionAction也很簡(jiǎn)單:

public class ProcessRejectionAction extends AbstractPersistenceAwareAction {
   protected void doExecute(Object arg) throws Exception {
      LoanApplication application = (LoanApplication) arg;
      if(LoanApplication.INSUFFICIENT_DATA.equals(application.getStatus()))
         this.getPersistenceService().recordIncomplete(application);
      else
         this.getPersistenceService().recordRejection(application);
   }
}


它在Spring上下文中如下定義(注意引用了被偽類欺騙的持久服務(wù)):

   <!-- rejection -->
   <bean id="RejectionAction" class="ProcessRejectionAction">
      <property name="persistenceService">
         <ref bean="LoanApplicationPersistenceService"/>
      </property>

   </bean>
   <!-- persistence service -->
   <bean id="LoanApplicationPersistenceService" class="MockLoanApplicationPersistence"/>


我們的下一個(gè)業(yè)務(wù)規(guī)則檢查是否貸款申請(qǐng)來(lái)自合法的州:

public class ValidStateRule extends AbstractRule {

   private List validStates;
  
   protected boolean makeDecision(Object arg) throws Exception {
      LoanApplication application = (LoanApplication) arg;
      if(validStates.contains(application.getStateCode())) {
         return true;
      }
      application.setStatus(LoanApplication.INVALID_STATE);
      return false;
   }

   public void setValidStates(List validStates) {
      this.validStates = validStates;
   }
}


有趣的是,我們的代碼并不知道哪些州是合法的。這些業(yè)務(wù)信息由上下文來(lái)定義:

   <!-- check valid state -->
   <bean id="ValidStateRule" class="ValidStateRule">
      <property name="validStates">
         <list>
            <value>TX</value>
            <value>MI</value>
         </list>
      </property>
      <property name="positiveOutcomeStep">
         <ref bean="ValidIncomeExpenseRatioRule"/>
      </property>
      <property name="negativeOutcomeStep">
         <ref bean="RejectionAction"></ref>
      </property>
   </bean>


Spring的內(nèi)建功能再一次讓我們從代碼中抽取出邏輯流程和參數(shù)數(shù)據(jù),僅在外部配置就可以了。
如你所見(jiàn),Spring應(yīng)用容器為我們的類提供了所有必須的綁定。在啟動(dòng)時(shí),Spring創(chuàng)建所有必須的對(duì)象并設(shè)置相關(guān)的依賴。在運(yùn)行時(shí),我們的業(yè)務(wù)規(guī)則通過(guò)定義在Spring上下文而不是代碼中的邏輯和參數(shù)數(shù)據(jù)來(lái)執(zhí)行。

貸款申請(qǐng)示例的其他部分可以用相同方法來(lái)配置和開(kāi)發(fā)。完整的源程序及對(duì)應(yīng)的Spring配置可以在資源中找到。

總結(jié)

在這篇文章中,我演示了通過(guò)Spring幫助你開(kāi)發(fā)基于規(guī)則應(yīng)用的眾多方法中的一部分。你也可以使用其內(nèi)置的AOP來(lái)支持在你的規(guī)則和操作中混合日志及事務(wù)代碼而不會(huì)污染你先前的業(yè)務(wù)邏輯。

SPRING應(yīng)用上下文是可以重新加載的。應(yīng)用可以修改業(yè)務(wù)規(guī)則和參數(shù)(通過(guò)修改XML文件)并在運(yùn)行中重新加載上下文。想象這么做的GUI應(yīng)用。這么做可以提供與價(jià)格為數(shù)百萬(wàn)的商業(yè)的規(guī)則引擎系統(tǒng)的類似功能。
很期望這篇文章可以幫助你嘗試一些新鮮而以令人振奮的方法來(lái)使你的代碼在將來(lái)更加有效。

關(guān)于作者
Mikhail Garber是居住在達(dá)拉斯的獨(dú)立技術(shù)顧問(wèn),擁有超過(guò)12年的企業(yè)級(jí)軟件開(kāi)發(fā)的經(jīng)驗(yàn)。尤其擅長(zhǎng)Java/J2EE、數(shù)據(jù)庫(kù)、消息和開(kāi)源方案。已經(jīng)有很多如Mary Kay Cosmetics, Boeing Defense and Space, Verizon Wireless, the US government, Lockheed Martin及其他的組織接受他的指導(dǎo)。

資源
●下載這篇文章對(duì)應(yīng)的源程序
http://www.javaworld.com/javaworld/jw-04-2005/ruleengine/jw-0425-ruleengine.zip
●Spring:
http://www.Springframework.org
●更多有關(guān)SPRING的文章,瀏覽最近的JavaWorld的這些文章:
●“使用SPRING創(chuàng)建簡(jiǎn)單的工作流引擎” , Steve Dodge (2005年4月):
http://www.javaworld.com/javaworld/jw-04-2005/jw-0411-Spring.html
●"Pro Spring: Spring and EJB," Rob Harrop及Jan Machacek (2005年2月):
http://www.javaworld.com/javaworld/jw-02-2005/jw-0214-Springejb.html
●“讓你的ANT享受Spring” ,Josef Betancourt (2005年2月):
http://www.javaworld.com/javaworld/jw-02-2005/jw-0214-antSpring.html
●利用Spring, Struts, Hibernate, and Axis來(lái)“設(shè)計(jì)簡(jiǎn)單的面向服務(wù)的J2EE應(yīng)用框架”,F(xiàn)angjian Wu (2004年10月):
http://www.javaworld.com/javaworld/jw-10-2004/jw-1004-soa.html
●通過(guò)“用JSF工作”學(xué)習(xí)如何運(yùn)用JavaServer Faces, Spring, and Hibernate構(gòu)建網(wǎng)絡(luò)應(yīng)用, Derek Yang Shen (2004年7月):
http://www.javaworld.com/javaworld/jw-07-2004/jw-0719-jsf.html
●Mikhail Garber: “為對(duì)象持久使用搜索引擎技術(shù)”,(JavaWorld, 2005年1月):
http://www.javaworld.com/javaworld/jw-01-2005/jw-0103-search.html
●更多有關(guān)J2EE應(yīng)用開(kāi)發(fā)的文章,可以瀏覽JavaWorld的主題索引的J2EE部分
http://www.javaworld.com/channel_content/jw-j2ee-index.shtml?
●更多JAVA開(kāi)發(fā)工具的文章,可以游覽JavaWorld的主題索引的開(kāi)發(fā)工具部分
http://www.javaworld.com/channel_content/jw-tools-index.shtml
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
spring-boot(七)servlet等容器對(duì)象配置
Spring - OpenSource Project - JavaWorld@TW
依賴注入三種方式
Spring Security(3.1.7) CAS Authentication
Spring 中的國(guó)際化Message的簡(jiǎn)單例子(ApplicationContext)
Spring Boot 引入自定義yml
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服