<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    JAVA隨筆

     

    規則容器的實現

    希望大家提出保貴意見~


    優點:

    1、規則規范業務流程,且現有規則已經實現不僅使用在流程平臺上且可以其他模塊,如:作業計劃。僅需配置。
    2、支持xml中配置表達式,工程人員將輸入/輸出參數使用表達式配置進行賦值(不需書寫任何代碼),故而影響流程的流向。
    3、支持xml中配置規則分組,并將規則賦予優先級,規則會按照規則分組優先級執行規則,直到滿足規則條件退出。
    4、支持除表達式復雜的業務邏輯,工程人員可以開發java代碼實現業務方法,在xml中簡單配置即可以實現復雜業務邏輯。
    5、支持listener,在調用規則之前、之后都會觸發before(),after()方法。工程人員可按業務編寫多個lisener,使lisener有效只需要簡單xml配置。
    6、支持輸入輸出參數的驗證,根據二次開發人員的xml配置,按輸入輸出參數配置類型進行驗證,若輸入/輸出參數不符合業務要求則拋出異常。

    發展:
    1、xml的web頁面配置,提供eclipse plugin配置,將需要手動xml配置的地方使用web,eclipse plugin的方式實現工具配置,
    其中可實現,若需要判斷值,如執行類型,工程人員在配置xml時每次要查數據庫對應找出值配上,而現在只要求二次二發人員提供取數據庫表的方法,
    規則配置工具會將表中的內存如:1,草稿;2,轉派;這些內容以下拉列表方式供工程人員選對,以節省工程人員的麻煩。
    2、支持drools。
    3、與使用規則的組件更有機的結果,如流程平臺、作業計劃。

    依賴關系:
    1、文件配置
    2、castor
    3、ongl

    使用:
    規則關心的是輸入/輸出參數,也即將輸入參數以java.util.Map傳入,通過key="參數名稱",value="參數類型"
    根據傳入的參數組合條件,將輸出參數以java.util.Map類型返回,也通過key="參數名稱",value="參數類型"

    以com.boco.eoms.commons.rule.test.service.RuleServiceFacadeTest.java 為例測試自定義java規則及規則分組調用

    為說明例子,我編寫了com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample.java及同包下的Rule1InputParameter2Sample.java
    做為輸入參數

    com.boco.eoms.commons.rule.Rule1OutputParameter1Sample.java及同包下Rule1OutputParameter2Sample.java做為輸出參數

    com.boco.eoms.commons.rule.Rule1Sample.java及com.boco.eoms.commons.rule.Rule2Sample.java為例說明自定義java規則及規則分組

    com.boco.eoms.commons.rule.sample.Rule1ListenerSample.java為自定義listener

    com.boco.eoms.commons.rule.sample.RuleSample.xml配置規則,先介紹輪廓,之后會詳細介紹

    rule的說明是個比較不好說明的東西,所以有些枯燥,:-)

    配置文件如下說明:

    <?xml version="1.0" encoding="UTF-8"?>
    <ruleEngine>
     
     <groups>
      <!--規則分組(路由)-->
      <group id="group1">
       <!-- 引用Rule2Sample,Rule1Sample兩個規則,優先級為2,優先級別以-1...正無窮遞增,即-1為最低優先級,默認規則優先級為-1 -->
       <groupRef ruleId="Rule2Sample" pri="2" />
       <groupRef ruleId="Rule1Sample" pri="1" />
      </group>
     </groups>
     <!-- 表達式樣式 ,使用自定義java規則不需定義,先不用觀注-->
     <expStyles>
      <expStyle id="rule1Express"
       style=" ( $parameter != $l{springbean.getNames} || false ) &amp;&amp; $text ? $r{springbean.getName} : 3 " />
     </expStyles>
     <rules>
      <!-- 規則 className為規則包+類名 ,id為唯一標識,記好了,將來調用時要用RuleId-->
      <rule className="com.boco.eoms.commons.rule.sample.Rule1Sample"
       id="Rule1Sample">
       <!-- 輸入參數定義 ,由使用規則組件的開發人員定義,rule1InputParameter1Sample為key,-->
       <!--類型為com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample,這里要定義正確呀,否則驗證不通過,也不通路由的~-->
       <input>
        <parameter name="rule1InputParameter1Sample"
         type="com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample" />
        <parameter name="rule1InputParameter2Sample"
         type="com.boco.eoms.commons.rule.sample.Rule1InputParameter2Sample" />
       </input>
       <!-- 輸出參數,expression為表達式,暫不關注,name及type和輸入參數一樣,drl是支持drools的預留接口,expStyleId表達式樣式ID,暫不關心-->
       <output>
        <parameter
         expression=""
         name="rule1OutputParameter1Sample"
         type="com.boco.eoms.commons.rule.sample.Rule1OutputParameter1Sample"
         drl=""
         expStyleId="rule1Express" />

        <parameter
         expression=""
         name="rule1OutputParameter2Sample"
         type="com.boco.eoms.commons.rule.sample.Rule1OutputParameter2Sample"
         drl=""
         expStyleId="rule1Express" />
       </output>
       <!--自定義listener,Rule1ListenerSample為自定義,RuleCheckListener為系統提供驗證listener驗證,若不需要驗證將RuleCheckListener去掉即可(不推薦)-->
       <listeners>
        <listener
         name="com.boco.eoms.commons.rule.sample.Rule1ListenerSample" />
        <listener
         name="com.boco.eoms.commons.rule.listener.RuleCheckListener" />
       </listeners>
      </rule>

      <rule className="com.boco.eoms.commons.rule.sample.Rule2Sample"
       id="Rule2Sample">
       <input>
        <parameter name="rule1InputParameter1Sample"
         type="com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample" />
        <parameter name="rule1InputParameter2Sample"
         type="com.boco.eoms.commons.rule.sample.Rule1InputParameter2Sample" />
       </input>
       <output>
        <parameter
         expression=" ( ${rule1InputParameter1Sample.name} != 'value3' || false) &amp;&amp; true ? $b{springbean.getName} : 3 "
         name="rule1OutputParameter1Sample"
         type="com.boco.eoms.commons.rule.sample.Rule1OutputParameter1Sample"
         drl="classpath:com.boco.eoms.commons.rule.sample.rule1Parameter1Sample.drl"
         expStyleId="rule1Express" />

        <parameter
         expression=" rule1InputParameter1Sample.name != '234' &amp;&amp; rule1InputParameter1Sample.age >10 ? rule1InputParameter1Sample.name : rule1InputParameter1Sample.age "
         name="rule1OutputParameter2Sample"
         type="com.boco.eoms.commons.rule.sample.Rule1OutputParameter2Sample"
         drl="classpath:com.boco.eoms.commons.rule.sample.rule1Parameter2Sample.drl"
         expStyleId="rule1Express" />
       </output>
       <listeners>
       <listener
         name="com.boco.eoms.commons.rule.sample.Rule1ListenerSample" />
        <listener
         name="com.boco.eoms.commons.rule.listener.RuleCheckListener" />
       </listeners>
      </rule>
     </rules>
    </ruleEngine>


    OK,現在我們看看自定義java寫了什么


    public class Rule1Sample extends RuleService {

     /**
      * @param ruleListeners
      * @param rules
      * @param rule
      * @param xmlPath
      */
     public Rule1Sample(List ruleListeners, RuleEngine rules, Rule rule,
       String xmlPath) {
      super(ruleListeners, rules, rule, xmlPath);
     }

     /**
      * 二次開發人員需實現的業務接口
      *
      * @param map
      *            根據配置文件中input的配置,二次開發人員取出配置的參數,
      *            如sample配置key="rule1InputParameter1Sample",value="com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample"
      *            key="rule1Parameter2InputSample",value="com.boco.eoms.commons.rule.sample.Rule1InputParameter2Sample"
      *            這時二次發人員在execute中按這種方式取參數
      *            com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample
      *            param1=(com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample)
      *            map.get("rule1InputParameter1Sample");
      *            com.boco.eoms.commons.rule.sample.Rule1InputParameter2Sample
      *            param2=(com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample)
      *            map.get("rule1InputParameter2Sample");
      *
      * @return 根據配置文件output的配置,二次開發人員需返回配置的參數 如sample配置
      *         key="rule1OutputParameter1Sample",value="com.boco.eoms.commons.rule.sample.Rule1OutputParameter1Sample"
      *         key="rule1OutputParameter2Sample",value="com.boco.eoms.commons.rule.sample.Rule1OutputParameter2Sample"
      *         配置人員需按業務要求,返回
      *         map.put("rule1OutputParameter1Sample",com.boco.eoms.commons.rule.sample.Rule1OutputParameter1Sample);
      *         map.put("rule1OutputParameter2Sample",com.boco.eoms.commons.rule.sample.Rule1OutputParameter2Sample);
      *         return map;
      * @throws RuleException
      */
     public Map execute(Map map,Rule rule) throws RuleException {
      // 規則業務
      // 取輸入參數
      Rule1InputParameter1Sample inputParam1 = (Rule1InputParameter1Sample) map
        .get("rule1InputParameter1Sample");
      Rule1InputParameter2Sample inputParam2 = (Rule1InputParameter2Sample) map
        .get("rule1InputParameter2Sample");

      Map outMap = new HashMap();
      Rule1OutputParameter1Sample outParam1 = new Rule1OutputParameter1Sample();
      Rule1OutputParameter2Sample outParam2 = new Rule1OutputParameter2Sample();
      // 模擬規則,年齡大于10數,姓名不為匿名,則outParam1設為可通過
      if (inputParam1.getAge() > 10
        && !"anonym".equals(inputParam1.getName())) {
       // 為說明業務邏輯所以將setName放入判斷條件
       outParam1.setName(inputParam1.getName());
       outParam1.setOk(true);
      } else {
       // 為說明業務邏輯所以將setName放入判斷條件
       outParam1.setName(inputParam1.getName());
       outParam1.setOk(false);
      }
      // 性別為男則通過
      if ("male".equals(inputParam2.getSex())) {
       outParam2.setSex("male");
       outParam2.setOk(true);
      } else {
       outParam2.setSex("male");
       outParam2.setOk(false);
      }
      outMap.put("rule1OutputParameter1Sample", outParam1);
      outMap.put("rule1OutputParameter2Sample", outParam2);
      // 返回輸出參數
      return outMap;
     }

    }

    以Rule1Sample.java為例,需繼承RuleService并實現execute方法,業務邏輯寫在該方法內,如Rule1Sample.java

    按照配置的輸入/輸出參數進行操作。

    同時開發人員需要 像RuleServiceFacadeTest這樣調用,按注釋調用,請看注釋

     


    public class RuleServiceFacadeTest extends TestCase {
     private RuleServiceFacade facade;

     private Map<String, Object> inputMap;

     private Rule1InputParameter1Sample inputParam1;

     private Rule1InputParameter2Sample inputParam2;

     private String xmlPath = "";

     private String groupId = "";

     /**
      * 輸入參數初始化
      */
     protected void setUp() throws Exception {
      facade = RuleServiceFacade.create();
      // 測試輸入參數類弄與xml是否匹配
      inputMap = new HashMap<String, Object>();
      inputParam1 = new Rule1InputParameter1Sample();
      inputParam2 = new Rule1InputParameter2Sample();
      inputParam1.setAge(10);
      inputParam1.setName("qjb");
      inputParam2.setSex("male");

      inputMap.put("rule1InputParameter1Sample", inputParam1);
      inputMap.put("rule1InputParameter2Sample", inputParam2);
      xmlPath = "classpath:com/boco/eoms/commons/rule/sample/RuleSample.xml";
      groupId = "group1";
      super.setUp();
     }

     protected void tearDown() throws Exception {
      super.tearDown();
     }

     /**
      * 以classpath:com/boco/eoms/commons/rule/sample/RuleSample.xml為配置文件,調用rule1Sample為ruleId,以inputMap為輸入參數,
      *
      */
     public void testInvokeRuleService() {
      try {
       facade.invokeRuleService(xmlPath, "Rule1Sample", inputMap);
      } catch (RuleException e) {
       fail();
      }
     }

     /**
      * 以規則分組(路由)方式調用,調用groupId即group1,按照xml配置是調用了兩個rule,按照優先級(數字由大到小)先后調用
      * 以不同輸入參數調用
      */
     public void testInvokeRuleGroupForDiffInputMap() {

      Map<String, Map> map = new HashMap<String, Map>();
      Map outMap = null;
      // 以不同輸入參數調用
      map.put("Rule1Sample", inputMap);
      map.put("Rule2Sample", inputMap);
      try {
       outMap = facade.invokeRuleGroupForDiffInputMap(xmlPath, groupId,
         map);

      } catch (RuleException e) {
       fail();
      }
      checkOutMap(outMap);
     }

     /**
      * 以規則分組(路由)方式調用,調用groupId即group1,按照xml配置是調用了兩個rule,按照優先級(數字由大到小)先后調用
      * 以相同輸入參數調用
      *
      */
     public void testInvokeRuleGroupForSampeInputMap() {
      Map outMap = null;
      try {
       outMap = facade.invokeRuleGroupForSampeInputMap(xmlPath, groupId,
         inputMap);
      } catch (RuleException e) {
       e.printStackTrace();
       fail();
      }
      checkOutMap(outMap);
     }

     /**
      * 驗證輸出參數,用于測試
      *
      * @param outMap
      */
     private void checkOutMap(Map outMap) {
      Rule1OutputParameter2Sample outPram2 = (Rule1OutputParameter2Sample) outMap
        .get("rule1OutputParameter2Sample");
      assertEquals(outPram2.getSex(), "male");
      assertEquals(outPram2.isOk(), true);
     }
    }

    這時再看自定義的listener

    com.boco.eoms.commons.rule.sample.Rule1ListenerSample.java

     

    public class Rule1ListenerSample implements IRuleListener {

     private Logger logger = Logger.getLogger(this.getClass());

     /**
      * 執行規則后調用
      */
     public void after(Map inputMap, Rule rule) throws RuleException {
      logger.debug(rule.getId() + " after");

     }

     /**
      * 執行規則前調用
      */
     public void before(Map outputMap, Rule rule) throws RuleException {
      logger.debug(rule.getId() + " before");
     }
    }

    需要實現IRuleListener.java的after及before方法

    ok,運行com.boco.eoms.commons.rule.RuleServiceFacadeTest.java測試用例。

    暈了吧~,重新看下,OK,以上內容為自定義調用,下面說說表達式方式調用

     

     

     

    以com.boco.eoms.commons.rule.test.service.ExpressionRuleServiceTest.java 為例測試表達式的規則


    按com.boco.eoms.commons.rule.sample.ExpressionRuleSample.xml中配置

    <?xml version="1.0" encoding="UTF-8"?>
    <ruleEngine>
     <!-- 表達式樣式,用于規則工具定義,暫不關心 -->
     <expStyles>
      <expStyle id="rule1Express"
       style=" ( $parameter != $l{springbean.getNames} || false ) &amp;&amp; $text ? $r{springbean.getName} : 3 " />
     </expStyles>
     <rules>
      <!-- 這里一定要配className="com.boco.eoms.commons.rule.service.ExpressionRuleService"這個類,表達式類-->
      <rule
       className="com.boco.eoms.commons.rule.service.ExpressionRuleService"
       id="ExpressionRule">
       <!-- 輸入參數定義 ,由使用規則組件的開發人員定義,rule1InputParameter1Sample為key,-->
       <!--類型為com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample,這里要定義正確呀,否則驗證不通過,也不通路由的~-->
       <input>
        <parameter name="rule1InputParameter1Sample"
         type="com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample" />
        <parameter name="rule1InputParameter2Sample"
         type="com.boco.eoms.commons.rule.sample.Rule1InputParameter2Sample" />
       </input>
       <!-- 輸出參數,expression為表達式,暫不關注,name及type和輸入參數一樣,drl是支持drools的預留接口,expStyleId表達式樣式ID,暫不關心-->
       <output>
        <!--expression 表達式 rule1InputParameter1Sample.age指com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample中的getAge()方法。 -->
        <!-- 其中&amp;&amp;在讀入程序時,將用&&(與)替換, -->
        <!-- 解釋一下,其中要使用輸入參數必須要以"#"號開頭
        rule1InputParameter1Sample 及rule2InputParameter1Sample從map中取出(這里開發人員不必關心,由規則幫你處理)
        
        if(rule1InputParameter1Sample.getAge()>5 && "qjb".equals(rule1InputParameter1Sample.getName()){
         return rule1InputParameter1Sample.getResult();
        }
        else{
         return rule1InputParameter1Sample.getStr(rule1InputParameter1Sample.getName());
        }
        
        規則容器將返回值寫入輸出map中,以name=rule1OutputParameter1Sample為key值,value即為返回值
        -->
        <parameter
         expression="#rule1InputParameter1Sample.age>5 &amp;&amp; #rule1InputParameter1Sample.name=='qjb'?#rule1InputParameter1Sample.result:#rule1InputParameter1Sample.getStr(#rule1InputParameter1Sample.name)"
         name="rule1OutputParameter1Sample"
         type="java.lang.String"
         drl="" expStyleId="" />


        <!-- 再來解釋下第二個輸出參數表達式
         
         if(rule1InputParameter1Sample.getAge()>5)){
          rule1InputParameter1Sample.setAge(5);
         }
         else{
          rule1InputParameter1Sample.setAge(6);
         }
         return rule1InputParameter1Sample;
        -->
        <parameter
         expression="#rule1InputParameter1Sample.age>5?#rule1InputParameter1Sample.setAge(5):#rule1InputParameter1Sample.setAge(6),#rule1InputParameter1Sample"
         name="rule1OutputParameter2Sample"
         type="com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample"
         drl="" expStyleId="" />
       </output>
       <!--listener第一個例子,不需要表達式配置功能一樣-->
       <listeners>
        <listener
         name="com.boco.eoms.commons.rule.sample.Rule1ListenerSample" />
        <listener
         name="com.boco.eoms.commons.rule.listener.RuleCheckListener" />
       </listeners>
      </rule>
     </rules>
    </ruleEngine>

    運行com.boco.eoms.commons.rule.test.service.ExpressionRuleServiceTest.java測試用例

    仔細看下測試用例,應該很好理解,

    恭喜,恭喜,熟練掌握rule了吧?:-)

     

    痛苦的再寫下去,再說說rule的擴展吧~

    基于rule去擴展是很簡單的~

    舉個例子,其實表達式的支持,就是我擴展的一個類,看下
    com.boco.eoms.commons.rule.service.ExpressionRuleService.java

    public class ExpressionRuleService extends RuleService {

     @Override
     protected Map<String, Object> execute(Map<String, Object> inputMap,
       Rule rule) throws RuleException {
      // 創建表達式解析service
      OgnlExpressionService oes = OgnlExpressionService.create(null);
      Map<String, Object> outMap = new HashMap<String, Object>();
      // 取輸出參數
      for (Iterator it = rule.getOutput().getParameters().iterator(); it
        .hasNext();) {

       Parameter para = (Parameter) it.next();
       // 將輸出參數配置的表達式結果按照配置名稱寫入outMap
       outMap.put(para.getName(), oes.getValue(para.getExpression(),
         inputMap));

      }

      return outMap;
     }

     /**
      * @param ruleListeners
      * @param rules
      * @param rule
      * @param xmlPath
      */
     public ExpressionRuleService(List ruleListeners, RuleEngine rules,
       Rule rule, String xmlPath) {
      super(ruleListeners, rules, rule, xmlPath);
     }

    }


    看下,沒什么內容吧,只需繼承RuleService,重寫execute方法,在里面實現你的業務邏輯,
    其實就是自定義規則,但也可以寫成通用的呀。就像將來要擴展的drools一樣,將來新增個
    DroolsRuleService就OK了。這時在xml配置時,在className配置剛剛寫的DroolsRuleService的類就OK了。
    這樣就實現了對drools的支持

      <rule
       className="com.boco.eoms.commons.rule.service.ExpressionRuleService"
       id="ExpressionRule">
       <!-- 輸入參數定義 ,由使用規則組件的開發人員定義,rule1InputParameter1Sample為key,-->
       <!--類型為com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample,這里要定義正確呀,否則驗證不通過,也不通路由的~-->
       <input>
        <parameter name="rule1InputParameter1Sample"
         type="com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample" />
        <parameter name="rule1InputParameter2Sample"
         type="com.boco.eoms.commons.rule.sample.Rule1InputParameter2Sample" />
       </input>
     
     
    再說說監聽,有人說你的監聽不是沒用的嗎,我要實現自定義業務邏輯,只需在execute方法最前端及后端加上我要在listener中要做的事,
    這不一樣能解決嗎,OK,我們來看下,完全沒錯,可以解決,除非你想將listener的東西藕荷在業務邏輯,當然listener的before(),after()方法
    不包含你的業務邏輯。再說下,若你不實現自定義規則呢,你怎么實現在before(),after()方法的內容呢,哈哈。再以一個例子說明,其實rule的
    參數驗證機制就是一個listener實現的,看一下com.boco.eoms.rule.listener.RuleCheckListener.java


    public class RuleCheckListener implements IRuleListener {

     public void after(Map map, Rule rule) throws RuleException {
      // 取輸入參數
      for (Iterator outputIt = rule.getOutput().getParameters().iterator(); outputIt
        .hasNext();) {
       Parameter para = (Parameter) outputIt.next();
       // 驗證map中的所存的對象與xml配置是否相符
       RuleConfigWrapper.checkMapType(map, para);
      }

     }

     public void before(Map map, Rule rule) throws RuleException {
      // 取輸入參數
      for (Iterator inputIt = rule.getInput().getParameters().iterator(); inputIt
        .hasNext();) {
       Parameter para = (Parameter) inputIt.next();
       // 驗證map中的所存的對象與xml配置是否相符
       RuleConfigWrapper.checkMapType(map, para);
      }

     }

    }

    這就是輸入/輸出參數與xml配置的驗證呀,呵呵~

    OK,現在編寫你的listenr吧

    只需實現IRuleListener,并實現after(),befor()方法,

    配置時在xml中配置,貼一段

     


       
       <listeners>
        <listener
         name="com.boco.eoms.commons.rule.sample.Rule1ListenerSample" />
        <listener
         name="com.boco.eoms.commons.rule.listener.RuleCheckListener" />
       </listeners>
       
       
       
    很簡單吧~

    posted on 2007-04-28 09:49 曲靜波 閱讀(1335) 評論(0)  編輯  收藏 所屬分類: others

    導航

    統計

    常用鏈接

    留言簿(3)

    隨筆分類(9)

    隨筆檔案(8)

    文章分類

    友情鏈接

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲爆乳少妇无码激情| 精品无码一区二区三区亚洲桃色| 亚洲精品456人成在线| 亚洲视频在线观看免费视频| 亚洲色欲色欲www在线丝| a级黄色毛片免费播放视频| 国产亚洲成人久久| a级毛片毛片免费观看永久| 久久精品国产亚洲一区二区| 大妹子影视剧在线观看全集免费| 91麻豆精品国产自产在线观看亚洲| 亚洲精品国产日韩无码AV永久免费网 | 亚洲人6666成人观看| 国产91免费视频| 亚洲乱码一区二区三区国产精品| 成人免费无码大片a毛片| 国产成人亚洲精品播放器下载 | 亚洲精品无码Av人在线观看国产| 久久国产精品萌白酱免费| 亚洲一区动漫卡通在线播放| 成年女人毛片免费观看97| 日韩在线视精品在亚洲| 中文字幕专区在线亚洲| 99久久综合精品免费| 亚洲综合欧美色五月俺也去| 国产精品自在自线免费观看| 中文在线免费观看| 亚洲国产精品人久久电影| 国产在线19禁免费观看| 中文字幕无线码中文字幕免费| 亚洲韩国—中文字幕| 香蕉高清免费永久在线视频| 国产V片在线播放免费无码 | 免费av一区二区三区| 亚洲一区精品视频在线| 日产国产精品亚洲系列| 99热在线免费观看| 亚洲av无码一区二区三区在线播放| 国产中文在线亚洲精品官网| 亚洲免费在线视频| 另类小说亚洲色图|