<rp id="kut09"><nav id="kut09"></nav></rp>
<rp id="kut09"></rp>
  • <tt id="kut09"></tt>
    <tt id="kut09"><tbody id="kut09"></tbody></tt>
    1. <u id="kut09"></u>
    2. <tt id="kut09"><noscript id="kut09"></noscript></tt>
    3. springboot使用hibernate validation對參數校驗的實現方法

       更新時間:2020年12月29日 16:24:17   作者:狂盜一枝梅  
      這篇文章主要介紹了spring-boot 使用hibernate validation對參數進行優雅的校驗,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

      springboot天生支持使用hibernate validation對參數的優雅校驗,如果不使用它,只能對參數挨個進行如下方式的手工校驗,不僅難看,使用起來還很不方便:

      if(StringUtils.isEmpty(userName)){
      	throw new RuntimeException("用戶名不能為空");
      }

      下面將介紹hibernate validation的基本使用方法。

      一、引入依賴

      這里在springboot 2.4.1中進行實驗,引入以下依賴:

      <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>2.4.1</version>
       <relativePath/> <!-- lookup parent from repository -->
      </parent>
      
      <dependencies>
       <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
      
       <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-test</artifactId>
       <scope>test</scope>
       </dependency>
       <dependency>
       <groupId>org.projectlombok</groupId>
       <artifactId>lombok</artifactId>
       <version>1.18.16</version>
       </dependency>
       <dependency>
       <groupId>org.hibernate.validator</groupId>
       <artifactId>hibernate-validator</artifactId>
       <version>6.1.6.Final</version>
       </dependency>
      </dependencies>

      二、基本請求參數校驗

      如下的一個spring mvc的請求調用中有一個id參數(Integer類型),如果不允許它為空,該怎么做

      • 在Controller上加上@Validated注解
      • 在需要校驗的字段前面加上@NotNull(message = "用戶id不能為空")注解
      • 定義全局異常處理類,定制化返回結果
       @RestControllerAdvice
       @Slf4j
       public class ValidationAdvice {
       
       @ExceptionHandler(Exception.class)
       @ResponseBody
       public WrapperResult handler(Exception e) {
        //獲取異常信息,獲取異常堆棧的完整異常信息
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        e.printStackTrace(pw);
        //日志輸出異常詳情
        log.error(sw.toString());
        return WrapperResult.faild("服務異常,請稍后再試");
       }
       
       @ExceptionHandler(ConstraintViolationException.class)
       @ResponseBody
       public WrapperResult handler(ConstraintViolationException e) {
        StringBuffer errorMsg = new StringBuffer();
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        violations.forEach(x -> errorMsg.append(x.getMessage()).append(";"));
        return WrapperResult.faild(errorMsg.toString());
       }
       }

      Controller層代碼如下所示:

       @RestController
       @Slf4j
       @RequestMapping("/user")
       @Validated
       public class UserController {
       
       /**
       * 根據id查詢用戶信息
       *
       * @param id
       * @return
       */
       @GetMapping
       public WrapperResult<UserModel> findUser(@NotNull(message = "用戶id不能為空")
            @RequestParam(value = "id")
            String id) {
        return WrapperResult.success(new UserModel());
       }
       }

      如果發起請求127.0.0.1:8080/user?id= 則會返回結果

      {
       "status": 1,
       "data": "用戶id不能為空;",
       "msg": "FAIL",
       "success": false
       }

      三、對象內參數校驗

      上面是GET請求,下面介紹POST請求,請求對象內的參數校驗。

      1.Controller類上加上@Validated注解

      @RestController
      @Slf4j
      @RequestMapping("/user")
      **@Validated**
      public class UserController {
      }

      2.在POST請求方法參數前面加上@Validated 注解

       @PostMapping("/mobile-regist")
       public WrapperResult<Boolean> mobileRegit(@Validated @RequestBody UserModel userModel) {
       return WrapperResult.success(true);
       }

      3.在上面介紹的ValidationAdvice類中加上對象參數校驗異常捕獲

      //處理校驗異常,對于對象類型的數據的校驗異常
       @ExceptionHandler(MethodArgumentNotValidException.class)
       @ResponseBody
       public WrapperResult handler(MethodArgumentNotValidException e) {
       StringBuffer sb = new StringBuffer();
       List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
       allErrors.forEach(msg -> sb.append(msg.getDefaultMessage()).append(";"));
       return WrapperResult.faild(sb.toString());
       }

      UserModel類的定義如下:

      @Data
      @Builder
      @NoArgsConstructor
      @AllArgsConstructor
      @Accessors(chain = true)
      public class UserModel {
      
       @NotEmpty(message = "姓名不能為空")
       private String name;
      
       @NotEmpty(message = "手機號不能為空")
      // @Mobile(message = "手機號格式不正確")
       private String mobile;
      
       @NotEmpty(message = "電子郵箱不能為空")
      	@Email(message = "電子郵箱格式不正確")
       private String email;
      
       private String password;
      
       private String address;
      
       @NotNull(message = "年齡不能為空")
       @Min(value = 12, message = "允許注冊年齡最小為12歲")
       @Max(value = 24, message = "允許年齡最大為24歲")
       private Integer age;
      
       @NotEmpty(message = "聯系人不允許為空")
       @Size(min = 1, max = 3, message = "聯系人長度只允許1到3之間")
       private List<String> contacts;
      }

      如果POST請求如下所示

      {
       "name":"",
       "mobile":"12666666666",
       "email":"",
       "password":"",
       "address":"",
       "age": null,
       "contacts":[
      
       ]
      }

      則會返回如下定制化返回結果:

      {
       "status": 1,
       "data": "電子郵箱不能為空;聯系人長度只允許1到3之間;年齡不能為空;聯系人不允許為空;姓名不能為空;手機號格式不正確;",
       "msg": "FAIL",
       "success": false
      }

      四、自定義校驗器

      像是@NotNull、@Email等注解都是hibernate validation 內置的注解,我們想開發像是@Email注解一樣功能的注解,如何做呢,比如@Mobile,它的使用方法將和@Email一模一樣。

      首先,先定義一個工具類存放ValidationUtil兩個常量值

      public class ValidationUtil {
       //手機號校驗正則
       public static final String MOBILE_REGX = "^[1][3-9][0-9]{9}$";
      
       public static final String MOBILE_MSG = "手機號格式錯誤";
      }

      1.定義注解Mobile

      具體代碼可以參考@Email的實現,直接將Email名字改成Mobile即可,如下所示:

      @Documented
      @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
      @Retention(RUNTIME)
      public @interface Mobile {
      
       String message() default ValidationUtil.MOBILE_MSG;
      
       Class<?>[] groups() default {};
      
       Class<? extends Payload>[] payload() default {};
      
       String regexp() default ValidationUtil.MOBILE_REGX;
      
       Pattern.Flag[] flags() default {};
      
       @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
       @Retention(RUNTIME)
       @Documented
       public @interface List {
       Mobile[] value();
       }
      }

      2.定義MobileValidator實現對參數的校驗邏輯

      public class MobileValidator implements ConstraintValidator<Mobile, String> {
      
       private String regexp;
      
       @Override
       public void initialize(Mobile constraintAnnotation) {
       //獲取校驗的手機號的格式
       this.regexp = constraintAnnotation.regexp();
       }
      
       @Override
       public boolean isValid(String value, ConstraintValidatorContext context) {
       if (!StringUtils.hasText(value)) {
        return true;
       }
       return value.matches(regexp);
       }
      }

      3.使用方法和@Email一模一樣

      不贅述

      五、分組校驗

      假設一個用戶注冊的場景,用戶注冊有三種方式

      • 用戶名+圖形驗證碼注冊
      • 郵箱+郵箱驗證碼注冊
      • 手機號+短信驗證碼注冊

      用戶注冊的時候除了方式不一樣,其他用戶信息基本相同,后端開了三個接口對應著著三種注冊方式,請求體中我們使用一個Model封裝了以上所有信息,包含著用戶名、郵箱、手機號等信息,這時候不同的接口被調用,model中需要校驗的參數就不一樣了:

      用戶名注冊的時候郵箱地址和手機號可以為空,但是用戶名不能為空;通過郵箱注冊的時候,郵箱地址不能為空,但是用戶名和手機號可以為空;......

      分組校驗專門應對這種情況。

      1.首先定義三個接口,表示三種組類別

      public interface ValidEmail {
      }
      
      public interface ValidMobile {
      }
      
      public interface ValidUserName {
      }

      2.在UserModel實體類上指名組類別

      @Data
      @Builder
      @NoArgsConstructor
      @AllArgsConstructor
      @Accessors(chain = true)
      public class UserModel {
      
       @NotEmpty(message = "姓名不能為空", groups = {ValidUserName.class})
       @UserName(groups = {ValidUserName.class})
       private String name;
      
       @NotEmpty(message = "手機號不能為空", groups = {ValidMobile.class})
       @Mobile(groups = {ValidMobile.class})
       private String mobile;
      
       @NotEmpty(message = "電子郵箱不能為空", groups = {ValidEmail.class})
       @Email(message = "電子郵箱格式不正確", groups = {ValidEmail.class})
       private String email;
      
       private String password;
      
       private String address;
      
       @NotNull(message = "年齡不能為空")
       @Min(value = 12, message = "允許注冊年齡最小為12歲", groups = {ValidEmail.class,ValidMobile.class,ValidUserName.class})
       @Max(value = 24, message = "允許年齡最大為24歲",groups = {ValidEmail.class,ValidMobile.class,ValidUserName.class})
       private Integer age;
      
       @NotEmpty(message = "聯系人不允許為空",groups = {ValidEmail.class,ValidMobile.class,ValidUserName.class})
       @Size(min = 1, max = 3, message = "聯系人長度只允許1到3之間",groups = {ValidEmail.class,ValidMobile.class,ValidUserName.class})
       private List<String> contacts;
      }

      3.Controller方法上指名驗證組別

       /**
       * 手機號注冊
       *
       * @param userModel
       * @return
       */
       @PostMapping("/mobile-regist")
       public WrapperResult<Boolean> mobileRegit(@Validated(ValidMobile.class) @RequestBody UserModel userModel) {
       return WrapperResult.success(true);
       }

      這時候進行如下請求:

      POST http://127.0.0.1:8080/user/mobile-regist

      {
       "mobile":"12666666666",
       "password":"",
       "address":"",
       "age": null,
       "contacts":[
      
       ]
      
      }

      則會返回結果:

      {
      "status": 1,
      "data": "聯系人長度只允許1到3之間;手機號格式錯誤;聯系人不允許為空;",
      "msg": "FAIL",
      "success": false
      }

      該請求中并沒有傳遞email和username字段,而且結果中也未校驗出這兩個字段,符合預期結果。

      六、手動校驗

      此處的手動校驗并非是使用if/else進行簡單的手動校驗,而是使用Validation自帶的校驗工具對使用了@NotNull等注解的實體對象進行屬性校驗。

      首先先獲取Valiation對象:

      private static final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();

      1. 全屬性校驗

      /**
       * 驗證某個對象所有字段
       *
       * @param obj
       * @param <T>
       * @return
       */
      public static <T> ValidationResult validateEntity(T obj) {
       ValidationResult result = new ValidationResult();
       Set<ConstraintViolation<T>> set = validator.validate(obj, Default.class);
       if (!CollectionUtils.isEmpty(set)) {
       result.setHasErrors(true);
       Map<String, String> errorMsg = new HashMap<>();
       for (ConstraintViolation<T> cv : set) {
        errorMsg.put(cv.getPropertyPath().toString(), cv.getMessage());
       }
       result.setErrorMsg(errorMsg);
       }
       return result;
      }

      2.某個字段的單獨校驗

      /**
      * 驗證某個對象某個字段
      *
      * @param obj
      * @param propertyName
      * @param <T>
      * @return
      */
      public static <T> ValidationResult validateProperty(T obj, String propertyName) {
       ValidationResult result = new ValidationResult();
       Set<ConstraintViolation<T>> set = validator.validateProperty(obj, propertyName, Default.class);
       if (!CollectionUtils.isEmpty(set)) {
       result.setHasErrors(true);
       Map<String, String> errorMsg = new HashMap<>();
       for (ConstraintViolation<T> cv : set) {
        errorMsg.put(propertyName, cv.getMessage());
       }
       result.setErrorMsg(errorMsg);
       }
       return result;
      }

      ValidationResult的定義如下:

      @Data
      @Builder
      @NoArgsConstructor
      @AllArgsConstructor
      @Accessors(chain = true)
      public class ValidationResult {
       private Boolean hasErrors;
       private Map<String, String> errorMsg;
      }

      七、文件上傳校驗

      1.tomcat容器下文件上傳校驗

      在springboot+tomcat架構下的文件上傳校驗,假如已經有了如下的配置:

      spring:
       servlet:
       multipart:
       max-file-size: 1MB
       max-request-size: 1MB

      這表示只允許上傳小于1MB大小的文件,如果不指定異常處理器,默認會報前端400,在ValidationAdvice類中添加如下代碼可以自定義返回結果:

      //文件上傳文件大小超出限制
       @ExceptionHandler(MaxUploadSizeExceededException.class)
       @ResponseBody
       public WrapperResult<Map<String,Object>> fileSizeException(MaxUploadSizeExceededException exception) {
       log.error("文件太大,上傳失敗",exception);
       return WrapperResult.faild("只允許上傳不大于"+exception.getMaxUploadSize()+"的文件");
       }

      2.其它容器

      在Jetty容器中1中的方法可能會失效,未驗證;在undertow容器中是一定會失效,已經驗證。undertow容器畢竟和spring-boot沒有完全打磨好,不建議現階段使用。

      八、附錄

      1.所有校驗規則注解說明

      注解 說明
      @Null 被注解的元素必須為空
      @NotNull 被注解的元素必須不為空
      @AssertTrue 被注解的元素必須為true
      @AssertFlase 被注解的元素必須為false
      @Min(value) 被注解的元素必須是數字,且必須大于指定的最小值
      @Max(value) 被注解的元素必須是數字,且必須小于指定的最大值
      @DecimalMin(value) 被注解的元素必須是數字,且必須大于指定的最小值
      @DecaimalMax(value) 被注解的元素必須是數字,且必須小于指定的最大值
      @Size(max=,min=) 被注解元素的大小必須在指定的范圍內
      @Digit(integer,fraction) 被注解元素必須是數字,且其值必須在可接受的范圍內
      @Past 被注解元素必須是一個過去的日期
      @Futrue 被注解元素必須是一個將來的日期
      @Pattern(regex=,flag=) 被注解元素必須符合指定的正則表達式
      @NotBlank 驗證非空,且長度必須大于0
      @Email 被注解的元素必須是電子郵件地址
      @Length(max=,min=) 被注解的字符串大小必須在指定的范圍內
      @NotEmpty 被注解的字符串必須非空
      @Range(max=,min=) 被注解的元素必須在指定范圍內

      2.校驗規則注解例子

      // 空和非空檢查: @Null、@NotNull、@NotBlank、@NotEmpty
      @Null(message = "驗證是否為 null")
      private Integer isNull;
      
      @NotNull(message = "驗證是否不為 null, 但無法查檢長度為0的空字符串")
      private Integer id;
      
      @NotBlank(message = "檢查字符串是不是為 null,以及去除空格后長度是否大于0")
      private String name;
        
      @NotEmpty(message = "檢查是否為 NULL 或者是 EMPTY")
      private List<String> stringList;
        
      // Boolean值檢查: @AssertTrue、@AssertFalse
      @AssertTrue(message = " 驗證 Boolean參數是否為 true")
      private Boolean isTrue;
        
      @AssertFalse(message = "驗證 Boolean 參數是否為 false ")
      private Boolean isFalse;
        
      // 長度檢查: @Size、@Length
      @Size(min = 1, max = 2, message = "驗證(Array,Collection,Map,String)長度是否在給定范圍內")
      private List<Integer> integerList;
       
      @Length(min = 8, max = 30, message = "驗證字符串長度是否在給定范圍內")
      private String address;
       
      // 日期檢查: @Future、@FutureOrPresent、@Past、@PastOrPresent
      @Future(message = "驗證日期是否在當前時間之后")
      private Date futureDate;
       
      @FutureOrPresent(message = "驗證日期是否為當前時間或之后")
      private Date futureOrPresentDate;
       
      @Past(message = "驗證日期是否在當前時間之前")
      private Date pastDate;
       
      @PastOrPresent(message = "驗證日期是否為當前時間或之前")
      private Date pastOrPresentDate;
       
      // 其它檢查: @Email、@CreditCardNumber、@URL、@Pattern、
      @ScriptAssert、@UniqueElements
      @Email(message = "校驗是否為正確的郵箱格式")
      private String email;
       
      @CreditCardNumber(message = "校驗是否為正確的信用卡號")
      private String creditCardNumber;
       
      @URL(protocol = "http", host = "127.0.0.1", port = 8080, message= "校驗是否為正確的URL地址")
      private String url;
       
      @Pattern(regexp = "^1[3|4|5|7|8][0-9]{9}$", message = "正則校驗是否為正確的手機號")
      private String phone;
        
      // 對關聯對象元素進行遞歸校驗檢查
      @Valid
      @UniqueElements(message = "校驗集合中的元素是否唯一")
      private List<CalendarEvent> calendarEvent;
      
      @Data
      @ScriptAssert(lang = "javascript", script ="_this.startDate.before(_this.endDate)",message = "通過腳本表達式校驗參數")
      private class CalendarEvent {
       private Date startDate;
       private Date endDate;
      }
      
      // 數值檢查: @Min、@Max、@Range、@DecimalMin、@DecimalMax、@Digits
      @Min(value = 0, message = "驗證數值是否大于等于指定值")
      @Max(value = 100, message = "驗證數值是否小于等于指定值")
      @Range(min = 0, max = 100, message = "驗證數值是否在指定值區間范圍內")
      private Integer score;
      
      @DecimalMin(value = "10.01", inclusive = false, message = "驗證數值是否大于等于指定值")
      @DecimalMax(value = "199.99", message = "驗證數值是否小于等于指定值")
      @Digits(integer = 3, fraction = 2, message = "限制整數位最多為3,小數位最多為2")
      private BigDecimal money;

      九、源代碼地址

      https://gitee.com/kdyzm/validation-spring-boot-demo

      到此這篇關于spring-boot 使用hibernate validation對參數進行優雅的校驗的文章就介紹到這了,更多相關spring-boot校驗參數內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!

      相關文章

      • Java 添加和刪除PDF圖層的示例代碼

        Java 添加和刪除PDF圖層的示例代碼

        本文將介紹如何使用Spire.PDF for Java來添加和刪除PDF圖層,本文通過示例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友參考下吧
        2020-02-02
      • Spring-Boot框架初步搭建

        Spring-Boot框架初步搭建

        本篇文章主要介紹了Spring-Boot框架初步搭建,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
        2017-03-03
      • SSM框架+Plupload實現分塊上傳大文件示例

        SSM框架+Plupload實現分塊上傳大文件示例

        這篇文章主要介紹了SSM框架+Plupload實現分塊上傳示例(Spring+SpringMVC+MyBatis+Plupload),將用戶選中的文件(可多個)分隔成一個個小塊,依次向服務器上傳,有興趣的可以了解一下。
        2017-03-03
      • Spring boot實現一個簡單的ioc(1)

        Spring boot實現一個簡單的ioc(1)

        這篇文章主要為大家詳細介紹了Spring boot實現一個簡單的ioc,具有一定的參考價值,感興趣的小伙伴們可以參考一下
        2017-04-04
      • 談談Java中try-catch-finally中的return語句

        談談Java中try-catch-finally中的return語句

        我們知道return語句用在某一個方法中,一是用于返回函數的執行結果,二是用于返回值為void類型的函數中,僅僅是一個return語句(return ;),此時用于結束方法的執行,也即此return后的語句將不會被執行,當然,這種情況下return語句后不能再有其它的語句了
        2016-01-01
      • java 讀取文件方法的總結

        java 讀取文件方法的總結

        這篇文章主要介紹了java 讀取文件方法的總結的相關資料,這里提供文件讀取5種方法并附實例,需要的朋友可以參考下
        2017-08-08
      • Java中使用輾轉相除法求最大公約數

        Java中使用輾轉相除法求最大公約數

        這篇文章主要介紹了Java中使用輾轉相除法求最大公約數,本文直接給出代碼實例,需要的朋友可以參考下
        2015-05-05
      • Java數據結構之散列表(動力節點Java學院整理)

        Java數據結構之散列表(動力節點Java學院整理)

        散列表(Hash table,也叫哈希表),是根據關鍵字(key value)而直接進行訪問的數據結構。這篇文章給大家介紹了java數據結構之散列表,包括基本概念和散列函數相關知識,需要的的朋友參考下吧
        2017-04-04
      • MyBatis自定義類型轉換器實現加解密

        MyBatis自定義類型轉換器實現加解密

        這篇文章主要介紹了MyBatis自定義類型轉換器實現加解密的相關資料,需要的朋友可以參考下
        2016-07-07
      • java 從服務器下載文件并保存到本地的示例

        java 從服務器下載文件并保存到本地的示例

        本篇文章主要介紹了java 從服務器下載文件并保存到本地的示例,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
        2018-02-02

      最新評論

      218彩票 www.szbaled.com:监利县| www.zhuangshita88.com:铜鼓县| www.dibangjiaju.com:淳安县| www.isabel-duque.com:四川省| www.glitznglow.com:读书| www.cp9557.com:邓州市| www.greenvocational.com:河曲县| www.thecreditscholar.com:当雄县| www.ipslo.com:新民市| www.wwwhg8194.com:松潘县| www.carahedgepeth.com:商丘市| www.chinajx6688.com:松阳县| www.racetorecoverynow.org:瓮安县| www.jvbkv.cn:富宁县| www.bicaraperpustakaan.com:常熟市| www.voipepoch.com:东兰县| www.ltswordpress.com:临洮县| www.bleedingblack.com:天津市| www.phuengoat.com:奉贤区| www.n3969.com:桓台县| www.thetalisker.com:吉林市| www.blackeyedtease.com:尚志市| www.jb908.com:班玛县| www.anjiutea.com:田东县| www.askabin.net:珲春市| www.thewinconcept.com:武平县| www.lnkqxx.com:盐亭县| www.oversuns.com:延寿县| www.notarydmv.com:兴业县| www.slrhfoundation.org:化隆| www.gearsexporters.com:太康县| www.njkaigao.com:正镶白旗| www.wisataboyolali.com:大邑县| www.ggnotes.com:措勤县| www.czmjjr.com:维西| www.yiyituofu.com:南通市| www.12580lv.com:武胜县| www.nb-xinghai.com:枣阳市| www.biji-rumput.com:田东县| www.wdzx88.com:乐安县| www.appstoremarketingpro.com:吉首市| www.rbdp668.com:饶平县| www.mfnck.com:孝昌县| www.impobol.com:岑溪市| www.char-o-lotranch.com:四会市| www.kagithanecicekci.com:仙居县| www.poengun.com:乌鲁木齐市| www.dickalerts.com:海丰县| www.c-c-creekside.com:和顺县| www.suqinwood.com:泽库县| www.ntbdyp.com:霍林郭勒市| www.ugqwh.com:商城县| www.salsa-101.com:临潭县| www.90wlog.com:昌图县| www.bungamelati.com:乌鲁木齐市| www.792642.com:绩溪县| www.alternateexpressions.com:类乌齐县| www.mtpgm.com:叶城县| www.tintasetinteiros.com:肃宁县| www.ko600.com:台北县| www.fieldsue.com:宜宾市| www.shgsfwls.com:荔浦县| www.trade-address.com:桐柏县| www.sparta-gym.com:安吉县| www.40photography.com:车致| www.webcamquestion.com:陵水| www.yr597.com:永平县| www.tolkieninterviews.com:桃江县| www.moto-journal.com:阜城县| www.ge176.com:六安市| www.wxjtjd.com:西和县| www.excelsisairways.com:上犹县| www.sky161.com:武山县| www.zhfu8.com:巴彦县| www.basicherbals.com:青神县| www.hongliansy.com:墨竹工卡县| www.quenetic.com:宝坻区| www.ctocmall.com:巴彦县| www.gumur.com:克山县| www.allnaturessafeway.com:岑溪市| www.ydgongce.com:平乐县| www.lanzengping.com:兴义市| www.xxjxzz.com:丰城市| www.coralclay.com:禄劝|