最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring?Data?Jpa框架最佳實(shí)踐示例

 更新時(shí)間:2022年02月24日 15:54:52   作者:kl  
這篇文章主要為大家介紹了Spring?Data?Jpa框架最佳實(shí)踐示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪

前言

Spring Data Jpa框架的目標(biāo)是顯著減少實(shí)現(xiàn)各種持久性存儲(chǔ)的數(shù)據(jù)訪問(wèn)層所需的樣板代碼量。

Spring Data Jpa存儲(chǔ)庫(kù)抽象中的中央接口是Repository。它需要領(lǐng)域?qū)嶓w類以及領(lǐng)域?qū)嶓wID類型作為類型參數(shù)來(lái)進(jìn)行管理。該接口主要用作標(biāo)記接口,以捕獲要使用的類型并幫助您發(fā)現(xiàn)擴(kuò)展該接口的接口。

CrudRepository、JpaRepository是更具體的數(shù)據(jù)操作抽象,一般我們?cè)陧?xiàng)目中使用的時(shí)候定義我們的領(lǐng)域接口然后繼承CrudRepository或JpaRepository即可實(shí)現(xiàn)實(shí)現(xiàn)基礎(chǔ)的CURD方法了,但是這種用法有局限性,不能處理超復(fù)雜的查詢,而且稍微復(fù)雜的查詢代碼寫起來(lái)也不是很優(yōu)雅,所以下面看看怎么最優(yōu)雅的解決這個(gè)問(wèn)題。

擴(kuò)展接口用法

/**
 * @author: kl @kailing.pub
 * @date: 2019/11/11
 */
@Repository
public interface SendLogRepository extends JpaRepository {
    /**
     * 派生的通過(guò)解析方法名稱的查詢
     * @param templateName
     * @return
     */
    ListfindSendLogByTemplateName(String templateName);
    /**
     * HQL
     * @param templateName
     * @return
     */
    @Query(value ="select SendLog from  SendLog s where s.templateName = :templateName")
    ListfindByTempLateName(String templateName);
    /**
     * 原生sql
     * @param templateName
     * @return
     */
    @Query(value ="select s.* from  sms_sendlog s where s.templateName = :templateName",nativeQuery = true)
    ListfindByTempLateNameNative(String templateName);
}

優(yōu)點(diǎn):

  • 1、這種擴(kuò)展接口的方式是最常見(jiàn)的用法,繼承JpaRepository接口后,立馬擁有基礎(chǔ)的CURD功能
  • 2、還可以通過(guò)特定的方法名做解析查詢,這個(gè)可以算spring Data Jpa的最特殊的特性了。而且主流的IDE對(duì)這種使用方式都有比較好的自動(dòng)化支持,在輸入要解析的方法名時(shí)會(huì)給出提示。
  • 3、可以非常方便的以注解的形式支持HQL和原生SQL

缺陷:

  • 1、復(fù)雜的分頁(yè)查詢支持不好

缺陷就一條,這種擴(kuò)展接口的方式要實(shí)現(xiàn)復(fù)雜的分頁(yè)查詢,有兩種方式,而且這兩種方式代碼寫起來(lái)都不怎么優(yōu)雅,而且會(huì)把大量的條件拼接邏輯寫在調(diào)用查詢的service層。

  • 第一種、實(shí)例查詢(Example Query)方式:
public void testExampleQuery() {
        SendLog log = new SendLog();
        log.setTemplateName("kl");
        /*
         * 注意:withMatcher方法的propertyPath參數(shù)值填寫領(lǐng)域?qū)ο蟮淖侄沃?,而不是?shí)際的表字段
         */
        ExampleMatcher matcher = ExampleMatcher.matching()
                .withMatcher("templateName", match -> match.contains());
        Example example = Example.of(log, matcher);
        Pageable pageable = PageRequest.of(0, 10);
        Page logPage = repository.findAll(example, pageable);
    }

上面代碼實(shí)現(xiàn)的語(yǔ)義是模糊查詢templateName等于"kl"的記錄并分頁(yè),乍一看這個(gè)代碼還過(guò)得去哈,其實(shí)當(dāng)查詢的條件多一點(diǎn),這種代碼就會(huì)變得又臭又長(zhǎng),而且只支持基礎(chǔ)的字符串類型的字段查詢,如果查詢條件有時(shí)間篩選的話就不支持了,在復(fù)雜點(diǎn)多表關(guān)聯(lián)的話就更GG了,所以這種方式不合格直接上黑名單了。

  • 第二種、繼承JpaSpecificationExecutor方式:

JPA 2引入了一個(gè)標(biāo)準(zhǔn)API,您可以使用它來(lái)以編程方式構(gòu)建查詢。Spring Data JPA提供了使用JPA標(biāo)準(zhǔn)API定義此類規(guī)范的API。這種方式首先需要繼承JpaSpecificationExecutor接口,下面我們用這種方式實(shí)現(xiàn)和上面相同語(yǔ)義的查詢:

public void testJpaSpecificationQuery() {
        String templateName = "kk";
        Specification specification = (Specification) (root, query, criteriaBuilder) -> {
            Predicate predicate = criteriaBuilder.like(root.get("templateName"),templateName);
            query.where(predicate);
            return predicate;
        };

        Pageable pageable = PageRequest.of(0, 2);
        Page logPage = sendLogRepository.findAll(specification, pageable);
    }

這種方式顯然更對(duì)味口了吧,而且也支持復(fù)雜的查詢條件拼接,比如日期等。唯一的缺憾是領(lǐng)域?qū)ο蟮膶傩宰址枰謱懥?,而且接口只?huì)提供findAll(@Nullable Specificationspec, Pageable pageable)方法,各種復(fù)雜查詢邏輯拼接都要寫在service層。對(duì)于架構(gòu)分層思想流行了這么多年外加強(qiáng)迫癥的人來(lái)說(shuō)實(shí)在是不能忍,如果單獨(dú)封裝一個(gè)Dao類編寫復(fù)雜的查詢又顯的有點(diǎn)多余和臃腫

SPRING DATA JPA最佳實(shí)踐

在詳細(xì)介紹最佳實(shí)踐前,先思考和了解一個(gè)東西,Spring Data Jpa是怎么做到繼承一個(gè)接口就能實(shí)現(xiàn)各種復(fù)雜查詢的呢?這里其實(shí)是一個(gè)典型的代理模式的應(yīng)用,只要繼承了最底層的Repository接口,在應(yīng)用啟動(dòng)時(shí)就會(huì)幫你生成一個(gè)代理實(shí)例,而真正的目標(biāo)類才是最終執(zhí)行查詢的類,這個(gè)類就是:SimpleJpaRepository,它實(shí)現(xiàn)了JpaRepository、JpaSpecificationExecutor的所有接口,所以只要基于SimpleJpaRepository定制Repository基類,就能擁有繼承接口一樣的查詢功能,而且可以在實(shí)現(xiàn)類里編寫復(fù)雜的查詢方法了。

一、繼承SIMPLEJPAREPOSITORY實(shí)現(xiàn)類

/**
 * @author: kl @kailing.pub
 * @date: 2019/11/8
 */
public abstract class BaseJpaRepository extends SimpleJpaRepository {
    public EntityManager em;
    BaseJpaRepository(ClassdomainClass, EntityManager em) {
        super(domainClass, em);
        this.em = em;
    }
}

構(gòu)造一個(gè)SimpleJpaRepository實(shí)例,只需要一個(gè)領(lǐng)域?qū)ο蟮念愋?,和EntityManager 實(shí)例即可,EntityManager在Spring的上下文中已經(jīng)有了,會(huì)自動(dòng)注入。領(lǐng)域?qū)ο箢愋驮诰唧w的實(shí)現(xiàn)類中注入即可。如:

/**
 * @author: kl @kailing.pub
 * @date: 2019/11/11
 */
@Repository
public class SendLogJpaRepository extends BaseJpaRepository {
    public SendLogJpaRepository(EntityManager em) {
        super(SendLog.class, em);
    }
    /**
     * 原生查詢
     * @param templateName
     * @return
     */
    public SendLog findByTemplateName(String templateName){
        String sql = "select * from send_log where templateName = :templateName";
        Query query =em.createNativeQuery(sql);
        query.setParameter("templateName",templateName);
        return (SendLog) query.getSingleResult();
    }
    /**
     * hql查詢
     * @param templateName
     * @return
     */
    public SendLog findByTemplateNameNative(String templateName){
        String hql = "from SendLog where templateName = :templateName";
        TypedQueryquery =em.createQuery(hql,SendLog.class);
        query.setParameter("templateName",templateName);
       return query.getSingleResult();
    }
    /**
     *  JPASpecification 實(shí)現(xiàn)復(fù)雜分頁(yè)查詢
     * @param logDto
     * @param pageable
     * @return
     */
    public PagefindAll(SendLogDto logDto,Pageable pageable) {
        Specification specification = (Specification) (root, query, criteriaBuilder) -> {
            Predicate predicate = criteriaBuilder.conjunction();
            if(!StringUtils.isEmpty(logDto.getTemplateName())){
                predicate.getExpressions().add( criteriaBuilder.like(root.get("templateName"),logDto.getTemplateName()));
            }
            if(logDto.getStartTime() !=null){
                predicate.getExpressions().add(criteriaBuilder.greaterThanOrEqualTo(root.get("createTime").as(Timestamp.class),logDto.getStartTime()));
            }
            query.where(predicate);
            return predicate;
        };
        return  findAll(specification, pageable);
    }
}

通過(guò)繼承BaseJpaRepository,使SendLogJpaRepository擁有了JpaRepository、JpaSpecificationExecutor接口中定義的所有方法功能。而且基于抽象基類中EntityManager實(shí)例,也可以非常方便的編寫HQL和原生SQL查詢等。最賞心悅目的是不僅擁有了最基本的CURD等功能,而且超復(fù)雜的分頁(yè)查詢也不分家了。只是JpaSpecification查詢方式還不是特別出彩,下面繼續(xù)最佳實(shí)踐

二、集成QUERYDSL結(jié)構(gòu)化查詢

Querydsl是一個(gè)框架,可通過(guò)其流暢的API來(lái)構(gòu)造靜態(tài)類型的類似SQL的查詢。這是Spring Data Jpa文檔中對(duì)QueryDsl的描述。Spring Data Jpa對(duì)QueryDsl的擴(kuò)展支持的比較好,基本可以無(wú)縫集成使用。Querydsl定義了一套和JpaSpecification類似的接口,使用方式上也類似,由于QueryDsl多了一個(gè)maven插件,可以在編譯期間生成領(lǐng)域?qū)ο蟛僮鲗?shí)體,所以在拼接復(fù)雜的查詢條件時(shí)相比較JpaSpecification顯的更靈活好用,特別在關(guān)聯(lián)到多表查詢的時(shí)候。下面看下怎么集成:

1、快速集成

因?yàn)橹坝袑戇^(guò)最簡(jiǎn)單的QueryDsl集成方式,所以這里就不在贅述了,具體參見(jiàn)《Querydsl結(jié)構(gòu)化查詢之jpa》,

2、豐富BaseJpaRepository基類

/**
 * @author: kl @kailing.pub
 * @date: 2019/11/8
 */
public abstract class BaseJpaRepository extends SimpleJpaRepository {
    public EntityManager em;
    protected final QuerydslJpaPredicateExecutorjpaPredicateExecutor;
    BaseJpaRepository(ClassdomainClass, EntityManager em) {
        super(domainClass, em);
        this.em = em;
        this.jpaPredicateExecutor = new QuerydslJpaPredicateExecutor<>(JpaEntityInformationSupport.getEntityInformation(domainClass, em), em, SimpleEntityPathResolver.INSTANCE, getRepositoryMethodMetadata());
    }
}

在BaseJpaRepository基類中新增了QuerydslJpaPredicateExecutor實(shí)例,它是Spring Data Jpa基于QueryDsl的一個(gè)實(shí)現(xiàn)。用來(lái)執(zhí)行QueryDsl的Predicate相關(guān)查詢。集成QueryDsl后,復(fù)雜分頁(yè)查詢的畫風(fēng)就變的更加清爽了,如:

/**
     * QSendLog實(shí)體是QueryDsl插件自動(dòng)生成的,插件會(huì)自動(dòng)掃描加了@Entity的實(shí)體,生成一個(gè)用于查詢的EntityPath類
     */
    private  final  static QSendLog sendLog = QSendLog.sendLog;
    public PagefindAll(SendLogDto logDto, Pageable pageable) {
        BooleanExpression expression = sendLog.isNotNull();
        if (logDto.getStartTime() != null) {
            expression = expression.and(sendLog.createTime.gt(logDto.getStartTime()));
        }
        if (!StringUtils.isEmpty(logDto.getTemplateName())) {
            expression = expression.and(sendLog.templateName.like("%"+logDto.getTemplateName()+"%"));
        }
        return jpaPredicateExecutor.findAll(expression, pageable);
    }

到目前為止,實(shí)現(xiàn)相同的復(fù)雜分頁(yè)查詢,代碼已經(jīng)非常的清爽和優(yōu)雅了,在復(fù)雜的查詢?cè)谶@種模式下也變的非常的清晰。但是,這還不是十分完美的。還有兩個(gè)問(wèn)題需要解決下:

  • QuerydslJpaPredicateExecutor實(shí)現(xiàn)的方法不支持分頁(yè)查詢同時(shí)又有字段排序。下面是它的接口定義,可以看到,要么分頁(yè)查詢一步到位但是沒(méi)有排序,要么排序查詢返回List列表自己封裝分頁(yè)。
public interface QuerydslPredicateExecutor{
	OptionalfindOne(Predicate predicate);
	IterablefindAll(Predicate predicate);
	IterablefindAll(Predicate predicate, Sort sort);
	IterablefindAll(Predicate predicate, OrderSpecifier... orders);
	IterablefindAll(OrderSpecifier... orders);
	PagefindAll(Predicate predicate, Pageable pageable);
	long count(Predicate predicate);
	boolean exists(Predicate predicate);
}
  • 復(fù)雜的多表關(guān)聯(lián)查詢QuerydslJpaPredicateExecutor不支持

3、最終的BaseJpaRepository形態(tài)

Spring Data Jpa對(duì)QuerDsl的支持畢竟有限,但是QueryDsl是有這種功能的,像上面的場(chǎng)景就需要特別處理了。最終改造的BaseJpaRepository如下:

/**
 * @author: kl @kailing.pub
 * @date: 2019/11/8
 */
public abstract class BaseJpaRepository extends SimpleJpaRepository {
    protected final JPAQueryFactory jpaQueryFactory;
    protected final QuerydslJpaPredicateExecutorjpaPredicateExecutor;
    protected final EntityManager em;
    private final EntityPathpath;
    protected final Querydsl querydsl;
    BaseJpaRepository(ClassdomainClass, EntityManager em) {
        super(domainClass, em);
        this.em = em;
        this.jpaPredicateExecutor = new QuerydslJpaPredicateExecutor<>(JpaEntityInformationSupport.getEntityInformation(domainClass, em), em, SimpleEntityPathResolver.INSTANCE, getRepositoryMethodMetadata());
        this.jpaQueryFactory = new JPAQueryFactory(em);
        this.path = SimpleEntityPathResolver.INSTANCE.createPath(domainClass);
        this.querydsl = new Querydsl(em, new PathBuilder(path.getType(), path.getMetadata()));
    }
    protected PagefindAll(Predicate predicate, Pageable pageable, OrderSpecifier... orders) {
        final JPAQuery countQuery = jpaQueryFactory.selectFrom(path);
        countQuery.where(predicate);
        JPQLQueryquery = querydsl.applyPagination(pageable, countQuery);
        query.orderBy(orders);
        return PageableExecutionUtils.getPage(query.fetch(), pageable, countQuery::fetchCount);
    }
}

新增了findAll(Predicate predicate, Pageable pageable, OrderSpecifier... orders)方法,用于支持復(fù)雜分頁(yè)查詢的同時(shí)又有字段排序的查詢場(chǎng)景。其次的改動(dòng)是引入了JPAQueryFactory實(shí)例,用于多表關(guān)聯(lián)的復(fù)雜查詢。使用方式如下:

/**
     * QSendLog實(shí)體是QueryDsl插件自動(dòng)生成的,插件會(huì)自動(dòng)掃描加了@Entity的實(shí)體,生成一個(gè)用于查詢的EntityPath類
     */
    private  final  static QSendLog qSendLog = QSendLog.sendLog;
    private  final static QTemplate qTemplate = QTemplate.template;

    public PagefindAll(SendLogDto logDto, Template template, Pageable pageable) {
        JPAQuery  countQuery = jpaQueryFactory.selectFrom(qSendLog).leftJoin(qTemplate);
        countQuery.where(qSendLog.templateCode.eq(qTemplate.code));
        if(!StringUtils.isEmpty(template.getName())){
            countQuery.where(qTemplate.name.eq(template.getName()));
        }
        JPQLQuery query = querydsl.applyPagination(pageable, countQuery);
        return PageableExecutionUtils.getPage(query.fetch(), pageable, countQuery::fetchCount);
    }

三、集成P6SPY打印執(zhí)行的SQL

上面的功能以及十分完美了,但是談到最佳實(shí)踐似乎少了一個(gè)打印SQL的功能。在使用Jpa的結(jié)構(gòu)化語(yǔ)義構(gòu)建復(fù)雜查詢時(shí),經(jīng)常會(huì)因?yàn)楦鞣N原因?qū)е虏樵兊慕Y(jié)果集不是自己想要的,但是又沒(méi)法排查,因?yàn)椴恢雷罱K執(zhí)行的sql是怎么樣的。Spring Data Jpa也有打印sql的功能,但是比較雞肋,它打印的是沒(méi)有替換查詢參數(shù)的sql,沒(méi)法直接復(fù)制執(zhí)行。所以這里推薦一個(gè)工具p6spy,p6spy是一個(gè)打印最終執(zhí)行sql的工具,而且可以記錄sql的執(zhí)行耗時(shí)。使用起來(lái)也比較方便,簡(jiǎn)單三步集成:

1、引入依賴

<dependency>
                <groupId>p6spy</groupId>
                <artifactId>p6spy</artifactId>
                <version>${p6spy.version}</version>
</dependency>

 2、修改數(shù)據(jù)源鏈接字符串

jdbc:mysql://127.0.0.1:3306 改成 jdbc:p6spy:mysql://127.0.0.1:3306

 3、添加配置spy.propertis配置

appender=com.p6spy.engine.spy.appender.Slf4JLogger
logMessageFormat=com.p6spy.engine.spy.appender.CustomLineFormat
customLogMessageFormat = executionTime:%(executionTime)| sql:%(sqlSingleLine)

這個(gè)是最簡(jiǎn)化的自定義打印的配置,更多配置可參考:https://p6spy.readthedocs.io/en/latest/configandusage.html

結(jié)語(yǔ)

最后的BaseJpaRepository功能上基本滿足了所有的查詢需求,又做了基礎(chǔ)查詢和復(fù)雜查詢的不分離,不至于把大量的復(fù)雜查詢拼接邏輯寫到service層,或者是新建的復(fù)雜查詢類里。徹底解決了文首提出的那些問(wèn)題?;赒ueryDsl的復(fù)雜查詢代碼邏輯清晰,結(jié)構(gòu)優(yōu)雅,極力推薦使用。最后,在安利下p6spy,一個(gè)非常實(shí)用的打印sql的工具,可以幫助排查分析JPA最終生成執(zhí)行的sql語(yǔ)句,其打印的sql語(yǔ)句可以直接復(fù)制到mysql管理工具中執(zhí)行的。

以上就是Spring Data Jpa框架最佳實(shí)踐示例的詳細(xì)內(nèi)容,更多關(guān)于Spring Data Jpa框架的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 使用Java 8 Lambda表達(dá)式將實(shí)體映射到DTO的操作

    使用Java 8 Lambda表達(dá)式將實(shí)體映射到DTO的操作

    這篇文章主要介紹了使用Java 8 Lambda表達(dá)式將實(shí)體映射到DTO的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-08-08
  • SpringBoot圖文并茂詳解如何引入mybatis與連接Mysql數(shù)據(jù)庫(kù)

    SpringBoot圖文并茂詳解如何引入mybatis與連接Mysql數(shù)據(jù)庫(kù)

    這篇文章主要介紹了SpringBoot如何引入mybatis與連接Mysql數(shù)據(jù)庫(kù),本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • SpringBoot Starter機(jī)制及整合tomcat的實(shí)現(xiàn)詳解

    SpringBoot Starter機(jī)制及整合tomcat的實(shí)現(xiàn)詳解

    這篇文章主要介紹了SpringBoot Starter機(jī)制及整合tomcat的實(shí)現(xiàn),我們知道SpringBoot自己在“后臺(tái)”幫我們配置了很多原本需要我們手動(dòng)去的東西,至于這個(gè)“后臺(tái)”是啥,就是Starter機(jī)制
    2022-09-09
  • Java中圖片的常用操作代碼總結(jié)

    Java中圖片的常用操作代碼總結(jié)

    這篇文章主要為大家詳細(xì)介紹了Java中對(duì)圖片進(jìn)行常用操作處理的代碼,例如生成自定義圖片、獲取圖片格式、圖片的裁剪與壓縮等,感興趣的小伙伴可以了解一下
    2022-11-11
  • Springboot服務(wù)實(shí)現(xiàn)執(zhí)行SQL腳本文件

    Springboot服務(wù)實(shí)現(xiàn)執(zhí)行SQL腳本文件

    這篇文章主要介紹了Springboot服務(wù)實(shí)現(xiàn)執(zhí)行SQL腳本文件方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Maven中resources標(biāo)簽的用法詳解

    Maven中resources標(biāo)簽的用法詳解

    本文主要介紹了Maven中resources標(biāo)簽的用法詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • 詳解Java中static關(guān)鍵字的使用和原理

    詳解Java中static關(guān)鍵字的使用和原理

    static可以用來(lái)修飾的成員變量和成員方法,被修飾的成員是屬于類的,而不是單單是屬于某個(gè)對(duì)象的。本文就來(lái)詳細(xì)說(shuō)說(shuō)他的使用和原理,需要的可以參考一下
    2022-10-10
  • idea中創(chuàng)建maven的Javaweb工程并進(jìn)行配置(圖文教程)

    idea中創(chuàng)建maven的Javaweb工程并進(jìn)行配置(圖文教程)

    這篇文章主要介紹了idea中創(chuàng)建maven的Javaweb工程并進(jìn)行配置,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),文中給大家提到了tomcat的運(yùn)行方法,具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-02-02
  • Java Socket編程實(shí)例(一)- TCP基本使用

    Java Socket編程實(shí)例(一)- TCP基本使用

    這篇文章主要講解Java Socket編程中TCP的基本使用,希望能給大家做一個(gè)參考。
    2016-06-06
  • Spring Boot jar中沒(méi)有主清單屬性的解決方法

    Spring Boot jar中沒(méi)有主清單屬性的解決方法

    這篇文章主要介紹了Spring Boot jar中沒(méi)有主清單屬性的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03

最新評(píng)論

安国市| 张家口市| 陇南市| 怀集县| 贺兰县| 平顺县| 原平市| 吴堡县| 宜兰市| 湄潭县| 松滋市| 正蓝旗| 正宁县| 威远县| 鄂托克前旗| 鄂伦春自治旗| 前郭尔| 桃园市| 黑河市| 景泰县| 日喀则市| 呼和浩特市| 宁海县| 平阳县| 印江| 镇康县| 额尔古纳市| 丰镇市| 盐津县| 阿坝| 宁国市| 厦门市| 乐清市| 吉安市| 天全县| 和林格尔县| 项城市| 高州市| 清涧县| 旺苍县| 株洲市|