亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

通用驗證系統

系統 1857 0
本文較詳盡地介紹了jakarta開源項目的子項目之一commons-validator(通用驗證系統),版本是 1.0.2。它使用了一個xml文件來定義針對用戶輸入的數據驗證功能,整個驗證體系提供了很強的擴展性,使得開發者可以開發自己的驗證函數加入到這個驗 證體系中來。它對web應用程序提供了客戶端javascript驗證和服務端驗證的兩種選擇,但是它只是一個驗證體系,有些東西還需要自己開發特別是 validatoraction的開發,不過有了項目源代碼及其例子,還有struts這個優秀的開源項目的示范,使用好commons- validator驗證體系應該是挺容易的。本文就這個驗證體系作了些探討,希望對大家有用!

1. 前言

本文較詳盡地介紹了jakarta開源項目的子項目之一commons-validator(通用驗證系統),版本是1.0.2。它使用了一個xml文件 來定義針對用戶輸入的數據驗證功能,整個驗證體系提供了很強的擴展性,使得開發者可以開發自己的驗證函數加入到這個驗證體系中來。它對web應用程序提供 了客戶端javascript驗證和服務端驗證的兩種選擇,但是它只是一個驗證體系,有些東西還需要自己開發特別是validatoraction的開 發,不過有了項目源代碼及其例子,還有struts這個優秀的開源項目的示范,使用好commons-validator驗證體系應該是挺容易的。本文就 這個驗證體系作了些探討,希望對大家有用!

?




回頁首


2. 用戶問題

我 們在開發信息系統時,用戶界面往往是一個很容易忽視的但是確是相當重要的地方。我們有好多關于編寫后端代碼的設計模式,現在我們還擁有commons- validator這樣的優秀驗證體系對付用戶界面的用戶千變萬化的輸入可能。輸入驗證關乎到整個信息系統的強壯性,因為惡意的輸入數據可能導致信息系統 崩潰;輸入驗證還關乎到信息系統的友好性,因為不能給用戶提供正確的輸入導引經常搞得使用者手足無措,最后只有悲憤而去。

?




回頁首


3. 簡單分析

通過對上面用戶問題的描述,我們可以簡單分析一下驗證體系的基本特性:

  • 驗證體系應該具有良好的可擴展性,可以讓信息系統開發者開發自己的驗證功能,以滿足特殊系統的驗證要求。
  • 驗證體系應該能顯示準確的驗證錯誤信息,用以幫助使用者糾正錯誤,而且錯誤信息應該是外在可配置的,改變相應的錯誤信息不需要修改源代碼。
  • 對于web信息系統來說,應該能支持客戶端驗證和服務端驗證兩種方式。

?




回頁首


4. 使用界面

4.1. 配置文件

下面是驗證規則xml文件的元素關系圖,我將挑選一些重要而又相對復雜的元素進行講解。


通用驗證系統

1. 元素constant

"constant" 元素定義了"field"元素所使用的替換型參數的靜態值。 "constant-name" 和 "constant-value" 元素分別表示這個靜態值的引用標識和值

2. 元素validator

這個"validator"元素定義了formset元素字段所能使用的 validatoraction對象。

?

子元素 javascript
屬性
屬性名 可選性 注釋與缺省值
name required 驗證對象的標識
classname required 驗證對象的完全類名
method required 用來實現這個驗證的方法名
methodParams required 驗證方法的逗號隔開的參數類型列表
msg required 驗證失敗時使用的消息鍵
depends . 逗號隔開的這個驗證所依賴的其他驗證列表
jsFunctionname

3. 元素formset

"formset" 定義了一個針對locale的 form集. "form"元素定義了有待驗證的"field" 集,名字屬性是應用程序分配給這個"form"的引用標識。

?

子元素 constant form
屬性
屬性名 可選性 注釋與缺省值
language . locale對象的語言部分
country . locale對象的國家部分
variant . locale對象的語言變種部分

4. 元素field

"field" 元素定義了需要驗證的屬性,在web應用中,一個"field"對應于一個HTML 表單控件。驗證系統通過驗證一個JavaBean來驗證這個"field" 元素,這個元素可以接受4個屬性:

?

子元素 msg arg0 arg1 arg2 arg3 var
屬性
屬性名 可選性 注釋與缺省值
property required 這個"field" 元素對應的JavaBean屬性。
depends . 逗號隔開的validatoraction 對象列表,所有的validatoraction對象驗證通過,這個"field"才驗證有效。
page . JavaBean可能有一個page屬性,只有"page"屬性小于或等于 JavaBean page屬性的"field" 元素才會被處理。這個機制對"向導"性的應用非常有用。
缺省值[0]
indexedListProperty . "indexedListProperty"是一個返回數組或集合的方法。

5. 元素msg

"msg" 元素定義了一個定制消息鍵,用來為驗證失敗的"field"提供消息文本。 當"field"沒有子元素"msg" 元素時,每個validatoraction對象則使用自己的消息屬性。

?

屬性
屬性名 可選性 注釋與缺省值
name . 對應于這個消息的validatoraction對象。
key . 消息資源文件中的消息鍵。
resource . 如果這個值為 "false","key"屬性將是直接的消息文本。缺省值[true]

6. 元素arg0|arg1|arg2|arg3

這 是4個參數元素,定義了validator 或field 消息模版中的4個替換值。比如validator的msg對應的消息資源是"必須提供{0}字段,而且字段的長度不能小于{1}字符! ",在顯示錯誤的時候,其中{0}將被arg0的消息文本替換,而{1}將被arg1的消息文本替換。

?

屬性
屬性名 可選性 注釋與缺省值
name . 對應于這個消息的validatoraction對象。
key . 消息資源文件中的消息鍵。
resource . 如果這個值為 "false","key"屬性將是直接的消息文本。缺省值[true]

7. 元素var

"field"能通過這個元素向某個validatoraction對象傳遞參數,這些參數也能被arg?元素通過語法${var:var-name}引用。它的子元素var-name和var-value分別為變量標識和變量的值。

4.2. 應用編程接口

如 圖《Commons-validator的API》所示,commons-validator的類明顯的分成三種,第一種為代表驗證規則文件中各個元素的 類,本文稱元素類,第二種是程序準備驗證資料和驗證的類,本文稱fa?ade類,第三種是實現了通用功能的類,本文稱工具類。元素類代表了驗證規則文件中 的各個元素,對于編程者來說主要作用是用他們來得到消息文本;fa?ade類用來使Commons-validator驗證系統融入到應用系統中;而工具 類有助于編程者寫實現各種validatorAction的類。具體的使用參見下面的代碼樣例。


通用驗證系統

4.3. 代碼樣例

雖然common-validation是為web應用寫的驗證體系,它同時也能用在java應用程序中,為了把注意力放在驗證系統的介紹上,下面的驗證樣例使用java應用程序來表演。

4.3.1. 定義驗證規則

驗 證規則是一個xml文件,定義了需要驗證的表單,及其表單的各個字段以及字段的驗證要求,另外validator元素是用來完成各個字段的驗證要求的。本 例定義了一個輸入表單nameForm及其兩個字段,兩個字段都必須提供,而且age字段還必須是整數;還定義了兩個驗證動作int和required, 分別滿足整數要求和必須提供的要求:

            <form-validation> 
	<global>      
		<validator name="int" 
			classname="org.i505.validator.MyTypeValidator" 
			method="validateInt"    
			methodParams="java.lang.Object,org.apache.commons.validator.Field"
			msg="errors.int"/>    
		<validator name="required"        
			classname="org.i505.validator.MyValidator"  
			method="validateRequired"           
			methodParams="java.lang.Object,org.apache.commons.validator.Field"    
<!---->			msg="errors.required"/> 
	</global>
<formset> 
<form name="nameForm"> 
	<field property="username"  depends="required">    
		<arg0 key="nameForm.username.displayname"/>    
	</field>    
	<field  property="age" depends="required,int">       
		<arg0 key="nameForm.age.displayname"/>      
	</field>  
</form> 
</formset>  
</form-validation>

          

?

4.3.2. 編寫消息資源文件

commons-validator的消息資源包括兩大部份,第一部分是包括了參數占位符的validatoraction對象的消息,第二部分是各個輸入表單輸入數據的顯示信息,用作驗證失敗時的信息顯示。本例中值包括了一個輸入表單的顯示信息:

            # validatoraction對象的消息
errors.required=必須提供{0}字段!
errors.int= {0}字段必須是整數!
# nameForm輸入表單的各個輸入數據的顯示信息
nameForm.username.displayname=姓名
nameForm.age.displayname=年齡

          

?

4.3.3. 編寫validatorAction

我們從驗證定義規則文件中可以看出validator元素定義的int和required validatorAction分別使用了org.i505.validator.MyTypeValidator和 org.i505.validator.MyValidator兩個類,這個元素還定義了它們使用的驗證方法validateInt和 validateRequired以及方法的參數類型列表。下面是這兩個類的代碼:

            package org.i505.validator;import 
org.apache.commons.validator.Field;
import org.apache.commons.validator.GenericTypeValidator;
import org.apache.commons.validator.ValidatorUtil;
public class MyTypeValidator { 
	public static Integer validateInt(Object bean, Field field) {   
		String value = ValidatorUtil.getValueAsString(bean, field.getProperty());
		Integer x= GenericTypeValidator.formatInt(value);   
		return x;   
	}
}                                                        

          


            package org.i505.validator;
import org.apache.commons.validator.Field;
import org.apache.commons.validator.GenericValidator;
import org.apache.commons.validator.ValidatorUtil;  
public class MyValidator {            
	public static boolean validateRequired(Object bean, Field field) {  
		String value = ValidatorUtil.getValueAsString(bean, field.getProperty()); 
		return !GenericValidator.isBlankOrNull(value);  
	}
}                                                         

          

?

4.3.4. 編寫javabean

commons-validator是一個針對web應用的輸入驗證體系,驗證規則中的form定義是針對html form表單的,但是common-validator在內部驗證時需要javabean。這個javabean的各個屬性就代表了html form表單的輸入控制。所以針對前面的驗證規則,我們實現的javabean需要定義兩個屬性:age和username,代碼如下:

            public class ValidateBean extends Object {
	String username;String age;  
	public void setUsername (String username) {
		this. username = username;   
	}   
	public String getUsername () {
		return this.username;  
	}   
	public void setAge (String age) {
		this.age = age; 
	} 
	public String getAge () {	
		return this.age;  
	} 
	public String toString() {
		return "{ username =" + this.username + ", age=" + this.age + "}";   
	}
}

          

?

注意,這個驗證BEAN的age屬性的類型是字符串 型的,因為它只是代表了html form表單的輸入控制的值,原始的用戶輸入數據基本上都可以用String來表示,如果我們申明age屬性的類型時整數型,則我們在html form表單的值到BEAN的age屬性就經過了一次類型轉換,這個早于我們的整型驗證,所以可能有產生類型轉換錯誤的危險。

4.3.5. 編寫驗證主程序

編寫驗證主程序主要有下面五步:

  1. 創建和處理ValidatorResources對象,這要借助于ValidatorResourcesInitializer類利用驗證規則定義文件初始化這個對象。
  2. 創建要驗證的bean對象
  3. 用驗證規則定義文件中定義的某個form創建validator對象,并且告訴這個對象要驗證的bean對象。
  4. 運行validator對象的validate()方法實際驗證bean對象
  5. 打印驗證結果

下面是依據上面所述步驟編寫的實例代碼,代碼中進行了三次驗證,第一次是驗證兩個屬性都是空的bean對象,第二次是age屬性不合法的bean對象,第三次是兩個屬性都合法的bean對象:

            public static void main(String[] args) throws IOException, ValidatorException {   
	InputStream in = null;  
	try {        
		ValidatorResources resources = new ValidatorResources();       
		in = ValidateExample.class.getResourceAsStream("myvalidator-example.xml");   
<!---->		ValidatorResourcesInitializer.initialize(resources, in);      
		ValidateBean bean = new ValidateBean();           
		Validator validator = new Validator(resources, "nameForm");   
		validator.addResource(Validator.BEAN_KEY, bean);       
		ValidatorResults results = null;          
		results = validator.validate();       
		printResults(bean, results, resources);   
		bean.setUsername("龔永生");           
		bean.setAge("很年輕");          
		results = validator.validate();  
		printResults(bean, results, resources);   
		bean.setAge("28");    
		results = validator.validate();   
		printResults(bean, results, resources);    
	}
	finally {     
		if (in != null) { 
			in.close();     
		}
	}
}

          

?

4.3.6. 打印驗證結果

打 印驗證結果可能是驗證體系中最復雜的一部分,因為它涉及到驗證文件和消息資源文件,涉及到好多對象以及它們復雜的關系。特別需要指出的是錯誤消息文本的顯 示。下面的代碼包括三個部分:第一部分是使用資源文件生成ResourceBundle對象,注意你的資源文件必須在classloader能找到的地 方;第二部分是實際打印驗證結果;第三部分是個顯示中文消息的函數。

validator對象的validate()方法會把驗證結果保存到其返回的ValidatorResults對象 中,它保存了bean對象被驗證的每個屬性的各種驗證要求的驗證結果對象ValidatorResult,首先我們可以獲取bean對象對應的驗證文件定 義的form,從而得到相應的消息鍵和其它信息,而且通過這些信息從ValidatorResults對象中獲取相應的ValidatorResult對 象,利用ValidatorResult對象isValid函數可以判斷驗證的成功與否,如果驗證沒通過,可以使用form的信息顯示錯誤消息文本。

            private static ResourceBundle apps =    
	ResourceBundle.getBundle(      
	     "org.i505.validator.myapplicationResources");  
		 public static void printResults(     
			ValidateBean bean,     
			ValidatorResults results,    
			ValidatorResources resources) {   
				boolean success = true;  
				Form form = resources.get(Locale.getDefault(), "nameForm");  
<!---->				System.out.println("\n\n驗證:");   
				System.out.println(bean);  
				Iterator propertyNames = results.get();    
				while (propertyNames.hasNext()) {    
					String propertyName = (String) propertyNames.next();      
<!---->					Field field = (Field) form.getFieldMap().get(propertyName);  
<!---->					String prettyFieldName = getGBKMsg(apps.getString(field.getArg0().getKey()));   
<!---->					ValidatorResult result = results.getValidatorResult(propertyName);    
<!---->					Map actionMap = result.getActionMap();     
					Iterator keys = actionMap.keySet().iterator();   
					while (keys.hasNext()) {      
						String actName = (String) keys.next();      
<!---->						ValidatorAction action = resources.getValidatorAction(actName);          
<!---->						System.out.println(         
						propertyName                 
						+ "["                   
						+ actName               
						+ "] ("               
						+ (result.isValid(actName) ? "驗證通過" : "驗證失敗")     
<!---->						+ ")");       
					if (!result.isValid(actName)) {    
						success = false;               
						String message = getGBKMsg(apps.getString(action.getMsg()));     
<!---->						Object[] args = { prettyFieldName };             
<!---->						System.out.println(                
							"錯誤信息是: "                   
							+ MessageFormat.format(message, args));     
<!---->							}     
						}       
					}    
					if (success) {   
						System.out.println("表單驗證通過"); 
					}
					else {
						System.out.println("表單驗證失敗"); 
					}
				}   
				public static String getGBKMsg(String msg){   
					String gbkStr="";    
					try {		
						gbkStr=new String(msg.getBytes("iso-8859-1"),"gbk");	
<!---->					}
					catch (UnsupportedEncodingException e) {	
						// TODO Auto-generated catch block		
<!---->						e.printStackTrace();	
					}	
					return gbkStr; 
				}

          

?

驗證結果如下:

            驗證:{ username =null, age=null}
age[required] (驗證失敗)錯誤信息是: 必須提供年齡字段!
username[required] (驗證失敗)錯誤信息是: 必須提供姓名字段!
表單驗證失敗
驗證:{ username =龔永生, age=很年輕}
age[required] (驗證通過)
age[int] (驗證失敗)
錯誤信息是: 年齡字段必須是整數!
username[required] (驗證通過)表單驗證失敗
驗證:{ username =龔永生, age=28}
age[required] (驗證通過)
age[int] (驗證通過)
username[required] (驗證通過)
表單驗證通過

          





回頁首


5. 內部剖析

5.1. 類之間的聯系

ValidatorResults對象有個map,以field的getKey()為鍵,這個field的驗證結果ValidatorResult對象為值。

ValidatorResult對象也有個map,以field的各個validator元素的名字為鍵(在field元素的depends中定一個field的validator元素列表),以一個表示驗證成功與否的對象為值。

ValidatorResources對象包含一個map,以Locale的某種字符串表示為鍵,FormSet 為值(所以formset有多種版本),還包含一個map,保存了全局常量,以常量名為鍵,常量值為值;還包含一個map,以validator元素的 name屬性為鍵, validatorAction對象為值。

Formset對象包含一個map,以form的name屬性為鍵,Form對象為值;還包含一個map,以formset元素的子元素Constant的name為鍵,子元素Constant的值為值。

Form對象包含一個map,以Field元素對應的Field對象的getKey()為鍵,Field對象為值;另外還擁有一個保存順序的field對象數組。

field對象擁有一個map,以var的名字為鍵,var對象為值。

Validator對象包含一個map,以各個validator元素的methodParams參數列表中的名字為鍵,相應的對象為值,這個map的鍵和值將會用作調用相應validator元素中的methods屬性指定方法的參數。

通過這些map,commons-validator在驗證系統各個類間鋪了一張類關系表,見下圖:


通用驗證系統

5.2. 如何調用validatorAction

驗 證規則的validator元素定義了validatorAction,而field元素則通過depends屬性引用了這些 validatorAction。從上面代碼樣例中的驗證主程序可以知道validator.validate()方法是針對某個form元素的,它將對 這個form元素的各個field進行驗證,對field進行驗證也就是調用field元素的depends屬性引用的各個validator元素定義的 驗證方法。

validator元素使用classname、method和methodParams三個屬性定義了一個驗證方法, 比如下面的xml片斷就定義了一個驗證整數的驗證方法validateInt,這個方法帶有兩個參數,類型依次是 java.lang.Object,org.apache.commons.validator.Field。驗證方法validateInt將在 org.i505.validator.MyTypeValidator代碼中實現。

            <validator name="int"     
	classname="org.i505.validator.MyTypeValidator"  
	method="validateInt"        
	methodParams="java.lang.Object,org.apache.commons.validator.Field" 
	msg="errors.int"/>

          

?

講了這么多,現在的問題是validator.validate()方法是如何調用各個驗證方法(比如validateInt)的?

我們用一個順序圖和一段代碼剖析這個問題。


通用驗證系統

上圖是個簡要的順序圖,這個順序圖的解釋圖下:

1. 向validator對象增加資源(向資源map增加項)

2. 實際驗證

對form定義的每個field,調用如下步驟:

#begin

3. 驗證一個field

對field的每個validatoraction,執行如下步驟:

#begin

4. 驗證一個validatoraction

5. 合并驗證結果

#end

#end

下面代碼詳細解釋了上面的第四步:驗證一個validatoraction。

            // Add these two Objects to the resources since they reference  
	// the current validator action and field   
	hResources.put(VALIDATOR_ACTION_KEY, va);   
	hResources.put(FIELD_KEY, field);      
	Class c = getClassLoader().loadClass(va.getClassname());   
	List lParams = va.getMethodParamsList();       
	int size = lParams.size();      
	int beanIndexPos = -1;      
	int fieldIndexPos = -1;    
	Class[] paramClass = new Class[size];          
	Object[] paramValue = new Object[size];       
	for (int x = 0; x < size; x++) {            
		String paramKey = (String) lParams.get(x); 
		if (BEAN_KEY.equals(paramKey)) {         
			beanIndexPos = x;         
		}       
		if (FIELD_KEY.equals(paramKey)) {     
			fieldIndexPos = x;                
		}
		// There were problems calling getClass on paramValue[]      
		paramClass[x] = getClassLoader().loadClass(paramKey);    
		paramValue[x] = hResources.get(paramKey);       
	}       
	Method m = c.getMethod(va.getMethod(), paramClass);     
	// If the method is static we don't need an instance of the class    
	// to call the method.  If it isn't, we do.        
	if (!Modifier.isStatic(m.getModifiers())) {       
		try {              
			if (va.getClassnameInstance() == null) {    
				va.setClassnameInstance(c.newInstance());    
			}
		} 
		catch (Exception ex) {           
			log.error(                 
				"Couldn't load instance "         
				+ "of class "                 
				+ va.getClassname()          
				+ ".  "                 
				+ ex.getMessage());     
			}
		}
		Object result = null;           
		if (field.isIndexed()) {        
			Object oIndexed =           
				PropertyUtils.getProperty(   
				hResources.get(BEAN_KEY),     
				field.getIndexedListProperty());   
				Object indexedList[] = new Object[0]; 
				if (oIndexed instanceof Collection) {  
					indexedList = ((Collection) oIndexed).toArray();   
<!---->				}
				else if (oIndexed.getClass().isArray()) {  
					indexedList = (Object[]) oIndexed;      
				}   
				// Set current iteration object to the parameter array      
<!---->				paramValue[beanIndexPos] = indexedList[pos];   
				// Set field clone with the key modified to represent     
				// the current field           
				Field indexedField = (Field) field.clone();          
				indexedField.setKey(                
				ValidatorUtil.replace(          
					indexedField.getKey(),      
					Field.TOKEN_INDEXED,        
					"[" + pos + "]"));  
					paramValue[fieldIndexPos] = indexedField;     
					result = m.invoke(va.getClassnameInstance(), paramValue);       
<!---->					results.add(field, va.getName(), isValid(result), result);      
<!---->					if (!isValid(result)) {           
						return false;              
					}
				}
				else {         
					result = m.invoke(va.getClassnameInstance(), paramValue);        
<!---->					results.add(field, va.getName(), isValid(result), result);   
<!---->					if (!isValid(result)) {             
						return false;                
					}
				}

          

?

這段代碼首先增加了兩個資源:目前正在驗證的field和validatoraction,接著實例化驗證方法所在類的一個對象,接著按照資源map的鍵/值和驗證方法的參數類列表構造驗證方法的參數列表,最后調用驗證方法所在類的一個對象的驗證方法。

?




回頁首


6. 遺留問題

我 們說commons-validator是個通用的驗證系統,它確實是個不錯的東西,但是要想在實際系統中使用它還需要一定的工作,特別是想利用它的客戶 端驗證時尤為如此。所幸的是struts項目為我們使用這些這個驗證系統作了很經典的示范,本人認為有必要把struts項目的這些工作移到 commons-validator項目中來,這樣它的可用性將大大提高。

?




回頁首


7. 總結

作 為一個驗證的通用框架,有些功能不是立即可用的,它需要開發者再次包裝。Struts就重新包裝了commons-validator的客戶端驗證機制, 使得這種機制在開發struts程序來說是立即可用的。有了這些包裝,剩下的任務就是開發validatoraction來滿足不同的驗證要求了。另外 struts還提供了驗證和某個正則表達式匹配的輸入,它使用了commons-validator的perl5正則表達式匹配機制。

在開發web信息系統時,除了驗證輸入外,我們還需要注意數據的輸出。Web的界面是html代碼,而且這個代碼是由瀏 覽器來解釋的,如果我們的內部數據包括了html代碼的保留字,輕一點危害是破壞瀏覽器對html的解釋,搞壞了我們的最后界面;重一點的是引入安全隱 患,癱瘓信息系統。下面這段代碼可用于過濾html保留字,學著URLEncoding的樣,我把它稱為HTMLEncoding:

    public static String HTMLEncoding (String value) {   
	if (value == null)        
   return (null);     
   char content[] = new char[value.length()];    
   value.getChars(0, value.length(), content, 0); 
   StringBuffer result = new StringBuffer(content.length + 50);     
   for (int i = 0; i < content.length; i++) {        
	switch (content[i]) {         
	case '<':                
		result.append("<");             
		break;       
	case '>':        
		result.append(">");  
		break;          
	case '&':        
		result.append("&");   
		break;         
	case '"':        
		result.append(""");       
		break;         
	case '\'':      
		result.append("'");  
		break;          
	注釋與缺省值:        
	result.append(content[i]); 
}     
}     
return (result.toString());   
}

  

通用驗證系統


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 久久99国产精品久久99无号码 | 羞羞的视频网站 | 久久免费毛片 | www亚洲视频 | 欧美成人另类69 | 亚洲国产精品综合一区在线 | 成人欧美一区二区三区在线观看 | 91在线视屏| 久久99久久99 | 精品视频在线视频 | 欧美特黄一级aa毛片 | 国产亚洲精品美女久久久久 | 国产在线五月综合婷婷 | 免费毛片a线观看 | 国产精品人成福利视频 | 国产成人刺激视频在线观看 | 911精品国产亚洲日本美国韩国 | 亚洲国产欧美在线 | 久久成人午夜 | 99国产欧美久久精品 | 五月婷婷基地 | 久久91亚洲精品久久91综合 | 亚洲欧美综合一区 | 国产精品久久久影院 | 四虎最新紧急入口 | www.夜夜骑| 久久久久久国产精品免费免 | 国产大学生一级毛片绿象 | 国产一区二区三区乱码网站 | 露脸超嫩97后在线播放 | 久久精品国产久精国产 | 四虎成年永久免费网站 | 久久久久久免费视频 | 天天操夜夜操免费视频 | 四虎成人精品在永久免费 | 欧美精品blacked中文字幕 | 奇米777四色影视在线看 | 久久99精品一区二区三区 | 欧美毛片一级 | 91精品国产色综合久久 | 午夜在线视频一区二区三区 |