整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          velocity模板html格式縮進問題

          elocity中常常會寫出#foreach #if #else #end等語句,
          但由于模板文件中html本身就帶有縮進,所以最終的縮進,并不符合velocity語句的含義。當主要針對velocity邏輯閱讀時,很不方便

          沒有處理格式代碼:

          模板代碼:

          模板代碼截圖


          生成html文件截圖:

          #if產生縮進后的截圖

          解決辦法:

          “#if#foreach#else#end”這些語法,不用任何縮進。并且行尾加##注釋,表示不解析后面空格


          定格寫,末尾加##注釋


          取消縮進后結果


          velocity-wiki地址

          https://cwiki.apache.org/confluence/display/velocity/VelocityWhitespaceTruncatedByLineComment

          解決辦法截圖

          “我不是在教你學壞,而是教你如何提高生產效率。” ----------- 牛頓

          人類社會能夠一直進步發展出現在的文明世界,最大的一個原因就是這個世界上懶人居多,懶人為了偷懶就需要提高生產效率,效率提高節省下來的時間才能創造出藝術、娛樂以及更高效率的科學技術。程序員們如何提高生產效率?創造一個自己為自己干活!

          今天給大家介紹一個代碼生成神器Velocity,Velocity作為一款基于Java的強大模板引擎,其擁有簡潔的設計和強大的功能,新手也能很快上手。從此以后你就可以擺脫無聊且繁雜的crud代碼,給自己留下詩和遠方的閑暇時光。

          效果展示

          話不多說,以下截圖是我利用Velocity寫的一個代碼生成的工具,支持Mysql或Pgsql兩種數據庫。新項目開發的時候,你只需要設計好你的表結構,在界面上填寫包名、地址后綴、模塊名等信息即可。剩下的事情交給Velocity,它會幫你完成從controller、service、dao的所有通用接口。

          生成代碼壓縮包里的目錄結構,前后端代碼都有。

          以下是適用于Mybatis框架的Velocity模板生成的代碼文件。Velocity的優點之一就是它將生成代碼需要的數據模型與模板解耦,所以對模板的修改可以做到非常的絲滑,數據模型做好了基本上不用做大的調整,剩下的就是DIY自己的模板文件。

          也許有人會質疑說,idea中不是有很多代碼生成插件嗎?我認為別人寫的總歸沒有那么靈活,我自己決定使用Velocity也是因為工作中遇到了一個開源項目需要二開,在使用別人的個性化框架期間,一個一個新建Java文件太費鼠標了,所以我才決定自己寫一套模板。

          Velocity

          Velocity的核心理念是遵循Model-View-Controller(MVC)設計模式,它致力于將視圖邏輯與業務邏輯徹底分離。它允許前端開發者使用一種專門的語法來引用預定義好的數據模型,而無需直接編寫Java代碼。這種設計不僅極大地簡化了前端開發者的工作量,也使得后端開發者能夠專注于后端邏輯的優化與實現,兩者并行工作,極大地提升了開發效率。

          Maven 依賴如下:

          <properties>
              <velocity-tools-version>2.0</velocity-tools-version>
          </properties>
          
          <dependency>
              <groupId>org.apache.velocity</groupId>
              <artifactId>velocity-tools</artifactId>
              <version>${velocity-tools-version}</version>
          </dependency>

          Velocity原理

          Velocity引擎的工作流程大致如下:

          • 開發者創建包含占位符和控制結構的模板文件;
          • 這些模板通過Velocity引擎解析時,引擎會根據提供的數據模型動態替換模板中的占位符;
          • 生成所需的HTML頁面、Java文件或任何其他類型的輸出文件。

          Hello Velocity World!

          <html>
          <body>
          	#set( $foo = "Velocity" )
          	Hello $foo World!
          </body>
          <html>

          輸出結果:

          Hello Velocity World!

          代碼實際上很簡單,聲明了一個 foo 的變量,給它賦值 "Velocity", 在 body 中顯示 “Hello $foo World! ”,Velocity 會將 foo 變量的值替換為 "Velocity"。

          以上就是一個使用 Velocity 模板語言(VTL) 的簡單應用。VTL 主要是采用引用的方式將動態的內容嵌入到輸出文件里面。

          建議點贊+收藏+關注,方便以后復習查閱。

          語法

          VTL 語法主要分為四種:

          • 引用。通過 ${variableName} 的方式引用一個變量的屬性或者方法;
          • 控制。提供一些邏輯分支或者遍歷的控制命令,如 #if, #else, #elseif, #foreach 等。
          • 導入與包含。大型項目中,Velocity允許在模板之間進行內容的復用和模塊化設計,如 #parse 和 #include 指令;
          • 宏定義。宏可以封裝一段邏輯或輸出格式,供模板多次調用以減少重復代碼。

          注釋

          單行注釋:

          ## 我是IT果果日記。

          多行注釋:

          #*
           我是IT果果日記
           我來自東土大唐
           要去往西天拜佛求經
          *#

          引用

          引用的簡單語法可以寫作 ` $+標識符 ` 的格式。標識符必須以字母開頭并區分大小寫,剩下的標識符由以下幾種類型組成:

          • 字母 (a .. z, A .. Z)
          • 數字 (0 .. 9)
          • 下劃線 ("_")
          • 連字符("-")

          引用的變量都會處理成字符串對象,例如一個整形對象,Velocity 會調用其 toString() 方法將其轉化為字符串。

          Velocity 里的引用分為三種類型:

          • 變量
          • 屬性
          • 方法

          變量的引用:

          $itguoguo

          屬性的引用:

          ## 這里的屬性Money既可以是屬性的引用,也可以是getMoney()方法的引用,由Velocity來決定是哪一個引用。
          $itguoguo.Money

          方法的引用:

          ## 方法的引用格式:$+標識符+方法體
          $itguoguo.getMoney()
          $itguoguo.setMoney( "1,0000,0000¥" )
          $itguoguo.setWifies( ["劉亦菲", "董璇", "夏思凝"] )

          此外還有兩種特殊的引用:形式引用(Formal Reference Notation)安靜引用(Quiet Reference Notation)

          形式引用常用于引用與文本相鄰的情況。例如,我要顯示"I have one billionRMB",我可以寫成"I have one $unitRMB"。我的本意是想通過引用變量unit動態的顯示RMB的數量,結果因為unit和RMB相鄰導致Velocity將unitRMB視作了引用變量。這種情況就可以使用形式引用。像醬紫的 "I have one ${unit}RMB"。

          ## 形式引用
          ${itguoguo.getMoney()}
          ${itguoguo.setMoney( "1,0000,0000¥" )}
          ${itguoguo.setWifies( ["劉亦菲", "董璇", "夏思凝"] )}

          安靜引用常用于引用變量不存在的情況。

          ## 普通引用,Velocity返回值:$money
          <input type="text" name="money" value="$money"/>
          ## 安靜引用,Velocity返回空字符串
          <input type="text" name="money" value="$!money"/>

          控制

          If / ElseIf / Else 代碼示例

          ## foo為空或者false,表達式判定為假,不會輸出內容
          #if( $foo )
             <div>Hello ITGuoGuo!</div>
          #end
          
          ## If / ElseIf / Else
          #if( $foo < 5 )
              <div>up</div>
          #elseif( $foo == 5 )
              <div>down</div>
          #elseif( $bar == 6 )
              <div>left</div>
          #else
              <div>right</div>
          #end

          Velocity 將在第一個為真的表達式停止并輸出內容。

          && / || / ! 代碼示例

          #if( $foo && $bar )
             <div>邏輯與</div>
          #end
          
          #if( $foo || $bar )
              <div>邏輯或</div>
          #end
          
          #if( !$foo )
              <div>邏輯非</div>
          #end

          邏輯非與安靜引用里的 ! 容易混淆,邏輯非的 ! 用在 $ 之前,安靜引用的 ! 用在 $ 之后。

          foreach 代碼示例

          ## names 可以是一個列表或數組
          <ul>
          #foreach( $name in $names )
              <li>$name</li>
          #end
          </ul>
          
          ## people 可以是一個鍵值對
          <ul>
          #foreach( $key in $people.keySet() )
              <li>Key: $key -> Value: $people.get($key)</li>
          #end
          </ul>
          
          ## Velocity 還可以在循環里使用計數缺省變量 $velocityCount,從1開始計數。
          <table>
          #foreach( $person in $people )
              <tr><td>$velocityCount</td>
              <td>$person.Name</td></tr>
          #end
          </table>

          Velocity 默認為 foreach 指令提供了計數變量 $velocityCount ,從1開始計數。也可以在 velocity.properties 文件中配置計數起始的位置。例如下面的配置:

          ## 循環計數變量名默認 velocityCount
          directive.foreach.counter.name = velocityCount
          
          ## 循環計數默認起始位從0開始
          directive.foreach.counter.initial.value = 0

          包含/解析

          include 代碼示例

          #include( "ItGuoGuo.txt" )

          ItGuoGuo.txt 文件將被插入到 #include 指令被定義的位置;

          ItGuoGuo.txt 文件不會被 Velocity 解析,如果需要的引入文件被解析可以使用 parse 指令;

          include 引入的文件必須是配置參數 TEMPLATE_ROOT 所定義目錄下的,默認為當前目錄。

          ## 引入多個文件使用逗號分隔
          #include( "ItGuoGuo1.gif","ItGuoGuo2.txt","ItGuoGuo3.htm" )
          
          ## 引用文件名最好使用變量,例如 $ItGuoGuoReference
          #include( "ItGuoGuo.txt", $ItGuoGuoReference )

          parse 代碼示例

          #parse( "ItGuoGuo.vm" )

          ItGuoGuo.vm 將被 Velocity 解析,即 ItGuoGuo.vm 可以是靜態文件也可以是動態文件;

          parse 指令只有一個參數;

          parse 引入的文件必須是配置參數 TEMPLATE_ROOT 所定義目錄下的,默認為當前目錄。

          下面是由兩個 vm 文件共同完成的邏輯,首先是主文件 main.vm:

          main.vm 倒計時開始
          #set( $cnt = 10 )
          #parse( "parsed.vm" )
          main.vm 倒計時完成!

          主文件申明了一個 cnt 變量,將在 parsed.vm 文件中做遞減處理:

          $cnt
          #set( $cnt = $cnt - 1 )
          #if( $cnt > 0 )
              #parse( "parsed.vm" )
          #else
              parsed.vm 倒計時完成!
          #end

          程序首先進入 main.vm 申明一個 cnt 變量,通過引入 parsed.vm 文件遞歸執行遞減操作,當 cnt 變量遞減為0時打印 “parsed.vm 倒計時完成!” ,最后回到 main.vm 打印 “main.vm 倒計時完成!”

          停止

          stop 代碼示例

          #stop

          stop 指令會停止模板引擎的執行,通常用作代碼調試。

          macro 指令示例

          #macro( emptytd )
          <tr><td></td></tr>
          #end
          
          #emptytd()

          定義一個名為 emptytd 的宏,然后執行它,就會顯示一行空表格。

          #macro( colorrows $color $texts )
          #foreach( $text in $texts )
              <tr><td bgcolor=$color>$text</td></tr>
          #end
          #end

          定義一個名為 colorrows 的宏,第一個參數表示顏色,第二個參數表示表格里的內容。

          #set( $list = ["one","two","three","four","five"] )
          #set( $color = "red" )
          <table>
              #tablerows( $color $list )
          </table>

          調用 colorrows 這個宏,傳遞兩個參數,注意變量 $list 替換了 $texts,輸出如下:

          #set( $list = ["one","two","three","four","five"] )
          #set( $color = "red" )
          <table>
              #tablerows( $color $list )
          </table>

          宏一般用來在多個模板中共享,這樣可以減少模板內的重復工作量,也減少了出錯的機率。

          轉義

          Velocity 的指令使用 $ 和 # 開頭,如果在模板里需要使用這兩個特殊字符,需要做轉義處理。

          I have $1000000000!
          I have $money!

          00000000 不需要做轉義,因為引用變量名必須是大寫或這小寫字母開頭。$money 是否需要轉義要看你想輸出 money 這個變量還是 “money” 這個字符串。

          #set( $money = "1,000,000,000" )
          I have $money!
          I have \$money!

          輸出結果如下:

          I have 1,000,000,000!
          I have $money!

          還有一種情況是引用變量的值需要轉義,可以使用 Velocity 的擴展工具 EscapeTool,Maven 依賴如下:

          <dependency>
              <groupId>org.apache.velocity.tools</groupId>
              <artifactId>velocity-tools-generic</artifactId>
              <version>3.1</version>
          </dependency>

          代碼生成

          前面提到過 Velocity 生成代碼的原理是將數據模型和模板合并,輸出指定格式的文件。下面我們就來自己動手利用 Velocity 寫一個生成代碼的小工具。

          數據模型

          首先需要定義自己的數據模型,因為我們寫的這個工具是用來生成 crud 代碼的,所以數據模型里的字段主要就是表的元信息。表的元信息實體類如下:

          列的元信息實體類如下:

          定義好數據模型之后,我們需要調用數據庫查找這些信息。以 Mysql 為例:

          模板文件

          多個模板文件可以共用一套數據模型,當前我們以生成實體類文件為例,實體模板如下:

          合并生成

          最后是將數據模型合并到模板文件,生成代碼文件:

          參考

          velocity中文文檔 https://wizardforcel.gitbooks.io/velocity-doc/content/1.html

          建議點贊+收藏+關注,方便以后復習查閱。

          (此處已添加書籍卡片,請到客戶端查看)

          #頭條創作挑戰賽#

          導讀

          近期一次需求開發涉及到了Java Veloctiy,由于當前vue項目無法在本地編譯運行velocity,且開發成本過高,如果需要調試則要發布后才能看到效果。之前有類似的案例,遂嘗試繼續采用這種方式解決,但是通過比對認為該方案遷移到本項目中的成本較高,且需要改動大量配置文件。

          基于以上,我們便嘗試將veloctiy本地工程化,嘗試跟vue和webpack的結合,實現熱更等開發常用需求。

          本文把velocity工程化的心路歷程記錄下來,主要給大家描述我們在解決問題過程中的一些感悟,同時文中也詳細介紹了具體方案。

          2

          背景

          本文提到的“Velocity”指的是Java Velocity,后面全部以“velocity”代稱。

          本文不對Velocity基礎概念做詳細介紹,默認閱讀本文的讀者具備velocity基礎相關知識。如果確有不清楚的地方,可依據參考文獻提供的文檔或搜索引擎進一步了解。


          3

          現狀

          行業現狀:

          隨著前端技術的發展,頁面的開發逐步形成了前后端分離的開發模式,形成了以vue、react等主流前端框架為主的MVVM模式。

          回首再面對這些基于Velocity的舊系統,無論是后端還是前端人員維護,都會存在諸多問題:
          1. RD不熟悉前端開發模式,需要花大量時間學習前端js和框架。

          2. Velocity渲染依賴Java環境,FE需要花費大量精力學習Maven工程、環境配置,且前端MVC框架版本老,開發效率低。

          內部業務現狀:

          原有項目涉及面較廣,基于Velocity開發的情況分散在不同業務系統中,隨著業務需求的迭代,維護成本越來越高。解決方案一般是針對高頻迭代的業務模塊進行前后端分離開發,但這樣會帶來新的問題:

          1. 使用新項目重構原有項目成本高

          2. 覆蓋面不廣

          3. 周期長

          4. 重構本身不能為業務帶來更高的價值

          如下圖,我們在本地開發velocity模版頁面時,目前基本處于盲寫階段,不能即時查看,造成開發時間大量浪費在部署和聯調中。

          基于以上問題,我們團隊在維護的時候探索一種新的方式,旨在提升開發效率,解決本地編譯運行velocity模版。


          4

          實現

          以我們團隊維護的本地服務大類頁為例。

          該項目基于vue,近期一次需求迭代中,需要把部分頁面內容前置到服務端交由java預渲染,然而本地開發目前不支持模擬java 環境運行velocity模版。因此需把velocity和vue進行整合,降低開發成本,讓FE無痛開發,不論是編譯還是打包上線都跟普通vue項目無差異。

          基于此目標,需要實現一個velocity+mvc+mvvm的混合架構,該架構需具備兩個能力:

          1. 把velocity模版頁面進行本地渲染,然后跟vue的index.html模版頁面進行整合

          2.讓vue把dom掛載到整合后的模版頁面中

          現在思考第一個問題,如何實現上面的架構?回顧剛才我們描述的架構需要具備的能力,可以分為兩段:

          第一段是velocity+mvc,上線后由服務端執行

          第二段是mvvm,上線后由客戶端執行

          問題進一步明確,基于以上兩段,我們需要做的事可以分為3步:

          1. 本地實現一套velocity模版渲染引擎,實現velocity頁面的渲染和mock數據填充

          2. 把渲染好的velocity模版整合到vue的模版文件index.html中

          3. 把整合了velocity頁面的vue模版文件index.html交給vue進行dom掛載

          好了,到此,我們不再停留在理論層面,而是需要考慮怎么實現以上三步。由于后面步驟依賴前面步驟的產物,所以我們按順序實現。

          現在思考第二個問題,velocity渲染引擎應該具備什么能力?

          根據第一步的描述,該引擎需要在前端本地編譯運行velocity模版頁面,同時支持mock數據的渲染。

          總結一下就是兩點:1 渲染velocity 2 支持mock數據

          目前本地渲染velocity的主流方式是在本地運行一套java服務,但是當前需求開發伙伴對java不太了解,并且一些配置項對我們來說較為復雜,這與我們在現狀中描述的問題不謀而合,這條路不適合我們。換個思路,java能跑服務,js不能嗎?答案很明顯,可以,是nodejs。雖然對java不熟悉,但是nodejs我們熟啊。

          通過調研,發現nodejs有類似java velocity的模版引擎,能運行velocity模版,同時能支持mock數據。接下來嘗試把該引擎接入項目中。

          下面是接入引擎時嘗試的兩種方式:

          方法一:在vue執行入口文件index.js前啟動node服務,然后通過在node服務中使用引擎提供的編譯和運行方法把velocity模版頁面加載好供后續使用。

          方法二:把該引擎寫在webpack的loader中,隨著webpack的執行邏輯編譯velocity。

          如果大家對vue本地運行時各個頁面加載的順序有了解,應該能看出來方法一存在問題,我們逐個實現,看看問題在哪里。

          方法一具體實現:

          以下代碼為當時在本地調試時臨時編寫,僅用于幫助大家理解思路。不具有參考性。核心代碼會加注釋。

          step1: 改造vue入口文件index.js

          // setup中啟動node服務,編譯velocity并生成一個html文件到指定文件夾下
          import './setup';
          // entry是原有vue的index.js入口文件內容
          import './entry';

          step2: 實現setup.js

          import Axios from 'axios';
          
          
          // 該方法向本地啟動的node服務發送請求,告訴node服務需要重新編譯模版
          (() => {
            new Promise((resolve, reject) => {
              Axios.get('initdom')
                .then(() => {
                  resolve();
                })
                .catch((err) => {
                  reject(err);
                });
            });
          })();

          step3: 實現node服務

          // node服務在本地手動啟動
          // 這里需要在全局安裝velocityjs包,用于后續命令執行
          const http = require('http');
          const fs = require('fs');
          const { exec } = require('child_process');
          
          
          const hostname = '127.0.0.1';
          const port = 3000;
          
          
          const server = http.createServer((req, res) => {
            if (req.url === '/initdom') {
              res.statusCode = 200;
          
          
              res.setHeader('Content-Type', 'text/plain');
              // 該命令用于執行velocity模版頁面,并且生成html文件到執行目錄下
              exec('velocity ./index.vm', { encoding: 'utf-8' }, (error, stdout, stderr) => {
                if (error) {
                  console.error(error);
                }
          
          
                if (stderr) {
                  console.error(stderr);
                }
          
          
                const isExist = fs.existsSync('模版文件地址');
          
          
                if (isExist) {
                  console.log('file is exist');
                  fs.rmSync('生成html文件地址');
                }
          
          
                console.log('file is rewriting');
                fs.writeFileSync('生成html文件地址', stdout);
                console.log('file is rewrited');
                // html文件生成成功后,通知前端,執行后續邏輯
                res.end('模版編譯成功');
              });
            } else {
              console.log('url is not correct!!!');
            }
          });
          
          
          server.listen(port, hostname, () => {
            console.log(`Server running at http://${hostname}:${port}/`);
          });

          step4: 本地啟動node服務和vue項目

          // 啟動node服務
          node node.js
          // 啟動vue
          npm run dev

          至此,方法一整個流程實現,項目啟動后確實也符合我們的預期,但是前文提到的問題在哪里?大家知道,我們平時本地開發中很重要的一個需求是熱更新。當我改動mock數據后發現,生成的html文件中的mock數據確實變動了,但是我需要刷新兩次瀏覽器才能在頁面中體現出來,也就是說熱更生效了,但又沒完全生效。

          問題在于vue讀取html文件的時機早于html文件生成的時機,那么能把html文件生成的邏輯再前置嗎?基于方法一很明顯不行,而且方法一需要本地啟動node服務,通過請求接口的方式實現服務啟動,這很不優雅,因此考慮換個方式。

          我們知道webpack提供了自定義loader的機制,允許我們創建loader預處理指定的文件。

          vue cli支持通過webpack chain添加新的loader。

          回顧方法一遇到的問題,嘗試用webpack loader實現。

          方法二具體實現:

          下圖為整體流程圖:

          實現方法二之前我們再思考一個問題,隨著項目逐步迭代,可能會對velocity模版文件進行拆分,同時一些外部文件也需要注入到最后的html文件中,而且后續還會逐步把代碼進行升級。好消息是velocity提供了#parse和#include能力,配合script和api接口我們能夠實現velocity+vue的單文件組件化模式。

          下圖為文件基本結構:

          基于這個結構,我們搭建一套前端沙盒環境,通過在本地json文件中保存mock服務端的數據,然后開發velocity-loader引擎來解析velocity模版,嵌入到webpack loader中,實時解析文件并注入mock數據到模版中,解決方法一中遇到的熱更問題。如下圖。

          下面貼上方法二實現的相關代碼。

          step1: 配置webpack chain

          config.module.rule('velocity')
                // 只處理.vm結尾的文件
                .test(/.vm$/)
                .exclude.add(/node_modules/).end()
                .use('html-loader')
                .loader('html-loader')
                .end()
          
          
                .use('velocity-loader')
                .loader(path.resolve(__dirname, './v-loader.js'))
                .options({
                  basePath: path.join(__dirname, 'src'),
                });

          step2: 實現velocity-loader引擎

          這里只寫部分核心代碼,其他的代碼為其他配置項,跟本文關系不大。

          module.exports = function (content) {
            const callback = this.async();
          
          
            const filePath = this.resourcePath;
            const fileDirPath = path.dirname(filePath);
          
          
            watcher = this.addDependency;
          
          
            // mock文件名稱這里寫死,用于描述,實際可進行配置
            const mockPath = path.join(fileDirPath, 'mock.js');
            let mock = {};
          
          
            // 判斷mock文件是否存在,如果存在則進行監聽,實現熱更
            if (fs.existsSync(mockPath)) {
              watcher(mockPath);
              delete require.cache[mockPath];
              // eslint-disable-next-line global-require
              mock = require(mockPath);
            }
          
          
            // 使用compile解析velocity模版
            content = new Compile(parse(content), {
              escape: false,
            }).render(mock, macros(filePath, {}, mock));
          
          
            // 返回html內容給webpack,進行下一步處理
            callback(null, content);
          };
          至此,我們解決了本地編譯運行velocity模版的問題,也實現了mock數據和熱更,提升了開發效率和開發體驗,維護成本并沒有增加。

          5

          總結

          其實到現在關于本地編譯運行velocity已經有很多方案且大都成熟,只是我們要么直接使用了現有的方案,要么沒遇到這種情況,寫這篇文章的目的也是想把自己在解決問題時的思路描述出來,做個總結。


          參考文獻

          [1] velocity官網:https://velocity.apache.org/

          [2] velocityjs官網: https://github.com/shepherdwind/velocity.js

          [3] webpack 官網:https://www.webpackjs.com/loaders/

          [4] vue官網:https://cli.vuejs.org/zh/guide/webpack.html


          作者簡介

          雷鳴生:LBG-FE

          來源:微信公眾號:58技術

          出處:https://mp.weixin.qq.com/s/LqBf6H-6o88tMfl59IRPbw


          主站蜘蛛池模板: 日韩一区二区久久久久久| 国产成人精品一区二三区熟女 | 3D动漫精品啪啪一区二区下载 | 精品国产一区二区三区久久狼| 亚洲国产成人久久一区二区三区 | 国产成人综合亚洲一区| 中文字幕色AV一区二区三区| 3D动漫精品一区二区三区| 日本一区二区三区精品国产| 亚洲一区影音先锋色资源| 久久婷婷久久一区二区三区| 精品亚洲一区二区三区在线播放| 精品香蕉一区二区三区| 亚洲性日韩精品国产一区二区| 国产精品一区二区久久精品无码| 国产一区二区三区不卡在线看| 午夜一区二区在线观看| 久久国产精品无码一区二区三区| 任你躁国语自产一区在| 国产在线观看一区精品| 亚洲人成网站18禁止一区| 国产一区在线视频观看| 视频一区视频二区在线观看| 麻豆国产一区二区在线观看| 中文字幕永久一区二区三区在线观看 | 欲色影视天天一区二区三区色香欲| 日本一区二区三区免费高清在线| 久久人妻内射无码一区三区 | 国产a∨精品一区二区三区不卡| 国精品无码一区二区三区在线蜜臀 | 国产成人av一区二区三区在线| 亚洲爆乳精品无码一区二区| 亚洲综合在线一区二区三区| 无码少妇一区二区浪潮免费| 91精品福利一区二区三区野战| 少妇特黄A一区二区三区| 国产韩国精品一区二区三区久久| 性色av无码免费一区二区三区 | 一区二区不卡在线| 免费一本色道久久一区| 国产亚洲福利精品一区二区|