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

SpringBoot環(huán)境下junit單元測(cè)試速度優(yōu)化方式

 更新時(shí)間:2021年09月03日 09:56:15   作者:安安靜靜寫bug  
這篇文章主要介紹了SpringBoot環(huán)境下junit單元測(cè)試速度優(yōu)化方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

1、提高單元測(cè)試效率

背景

在項(xiàng)目提測(cè)前,自己需要對(duì)代碼邏輯進(jìn)行驗(yàn)證,所以單元測(cè)試必不可少。

但是現(xiàn)在的java項(xiàng)目幾乎都是基于SpringBoot系列開發(fā)的,所以在進(jìn)行單元測(cè)試時(shí),執(zhí)行一個(gè)測(cè)試類就要啟動(dòng)springboot項(xiàng)目,加載上下文數(shù)據(jù),每次執(zhí)行一次測(cè)試都要再重新加載上下文環(huán)境,這樣就會(huì)很麻煩,浪費(fèi)時(shí)間;在一次項(xiàng)目中,我們使用自己的技術(shù)框架進(jìn)行開發(fā),每次單元測(cè)試時(shí)都要初始化很多數(shù)據(jù)(例如根據(jù)數(shù)據(jù)模型建立表,加載依賴其它模塊的類),這樣導(dǎo)致每一次單元測(cè)試時(shí)都會(huì)花3-5分鐘時(shí)間(MacOs 四核Intel Core i5 內(nèi)存:16g),所以很有必要優(yōu)化單元測(cè)試效率,節(jié)約開發(fā)時(shí)間。

2、單元測(cè)試如何執(zhí)行

首先要優(yōu)化單元測(cè)試,那要知道單元測(cè)試是怎樣執(zhí)行的

引入相關(guān)測(cè)試的maven依賴,例如junit,之后在測(cè)試方法加上@Test注解即可,在springboot項(xiàng)目測(cè)試中還需要在測(cè)試類加上@RunWith注解 然后允許需要測(cè)試的方法即可

補(bǔ)充說(shuō)明

  • @RunWith 就是一個(gè)運(yùn)行器
  • @RunWith(JUnit4.class) 就是指用JUnit4來(lái)運(yùn)行
  • @RunWith(SpringJUnit4ClassRunner.class),讓測(cè)試運(yùn)行于Spring測(cè)試環(huán)境
  • @RunWith(Suite.class) 的話就是一套測(cè)試集合,
  • @ContextConfiguration Spring整合JUnit4測(cè)試時(shí),使用注解引入多個(gè)配置文件@RunWith

SpringBoot環(huán)境下單元測(cè)試一般是加@RunWith(SpringJUnit4ClassRunner.class)注解,SpringJUnit4ClassRunner繼承BlockJUnit4ClassRunner類,然后在測(cè)試方式時(shí)會(huì)執(zhí)行SpringJUnit4ClassRunner類的run方法(重寫了BlockJUnit4ClassRunner的run方法),run方法主要是初始化spring環(huán)境數(shù)據(jù),與執(zhí)行測(cè)試方法

3、項(xiàng)目中使用

在我們項(xiàng)目中,是通過(guò)一個(gè)RewriteSpringJUnit4ClassRunner類繼承SpringJUnit4ClassRunner,然后@RunWith(RewriteSpringJUnit4ClassRunner.class)來(lái)初始化我們框架中需要的數(shù)據(jù),

RewriteSpringJUnit4ClassRunner里面是通過(guò)重寫withBefores方法,在withBefores方法中去初始化數(shù)據(jù)的,之后通過(guò)run方法最后代理執(zhí)行測(cè)試方法

4、優(yōu)化單測(cè)思路

通過(guò)上面說(shuō)明,可以知道每次測(cè)試一個(gè)方法都要初始化springboot環(huán)境與加載自己框架的數(shù)據(jù),所以有沒(méi)有一種方式可以只需要初始化 一次數(shù)據(jù),就可以反復(fù)運(yùn)行測(cè)試的方法呢?

思路

首先每一次單測(cè)都需要重新加載數(shù)據(jù),跑完一次程序就結(jié)束了,所以每次測(cè)試方法時(shí)都要重新加載數(shù)據(jù),

如果只需要啟動(dòng)一次把環(huán)境數(shù)據(jù)都加載了,然后之后都單元測(cè)試方法都使用這個(gè)環(huán)境呢那不就能解決這個(gè)問(wèn)題么。

我們是不是可以搞一個(gè)服務(wù)器,把基礎(chǔ)環(huán)境與數(shù)據(jù)都加載進(jìn)去,然后每次執(zhí)行單元測(cè)試方法時(shí),通過(guò)服務(wù)器代理去執(zhí)行這個(gè)方法,不就可以了嗎

5、實(shí)現(xiàn)方式

首先我們可以用springboot的方式啟動(dòng)一個(gè)服務(wù),通常使用的內(nèi)置tomcat作為服務(wù)啟,之后暴露一個(gè)http接口,入?yún)樾枰獔?zhí)行的類和方法,然后通過(guò)反射去執(zhí)行這個(gè)方法;還可以通過(guò)啟動(dòng)jetty服務(wù),通過(guò)jetty提供的handler處理器就可以處理請(qǐng)求,jetty相對(duì)于tomcat處理請(qǐng)求更加方便

服務(wù)是有了,那怎樣將單元測(cè)試方法代理給服務(wù)器呢?前面提到過(guò),通過(guò)@RunWith注入的類,在單元測(cè)試方法運(yùn)行時(shí)會(huì)執(zhí)行@RunWith注入的類相應(yīng)的方法,所以我們可以在@RunWith注入的類里面做文章,拿到測(cè)試類與方法,然后通過(guò)http訪問(wèn)服務(wù)器,然后服務(wù)器去代理執(zhí)行測(cè)試方法

6、編碼實(shí)現(xiàn)

下面將通過(guò)兩種不同方式實(shí)現(xiàn),以Jetty為服務(wù)器啟動(dòng),與以Tomcat為服務(wù)器啟動(dòng)

6.1 Jetty作為服務(wù)啟動(dòng)

首先編寫服務(wù)啟動(dòng)類,并在spring容器準(zhǔn)備好后加載我們公司框架相關(guān)數(shù)據(jù),這里使用jetty作為服務(wù)器,下面代碼是核心方法

// 只能寫在測(cè)試目錄下,因?yàn)閷懺趹?yīng)用程序目錄下在序列化時(shí),找不到測(cè)試目錄下的類-》InvokeRequest類中的Class<?> testClass反序列化不出來(lái)
@SpringBootApplication
@ComponentScan(value = "包路徑")
public class DebugRunner {
    public static void main(String... args) {
        SpringApplication.run(DebugRunner.class, args);
        System.out.println("================================success========================");
    }
    @EventListener
    public void onReady(ContextRefreshedEvent event) {
        // 加載框架數(shù)據(jù)
    }
    @Bean
    public JettyServer jettyServer(ApplicationContext applicationContext) {
        return new JettyServer(port, applicationContext);
    }
}

使用jetty作為服務(wù)器,并且注入處理器HttpHandler

public class JettyServer {
    private volatile boolean running = false;
    private Server server;
    private final Integer port;
    private final ApplicationContext applicationContext;
    public JettyServer(Integer port, ApplicationContext applicationContext) {
        this.port = port;
        this.applicationContext = applicationContext;
    }
    @PostConstruct
    public void init() {
        this.startServer();
    }
    private synchronized void startServer() {
        if (!running) {
            try {
                running = true;
                doStart();
            } catch (Throwable e) {
                log.error("Fail to start Jetty Server at port: {}, cause: {}", port, Throwables.getStackTraceAsString(e));
                System.exit(1);
            }
        } else {
            log.error("Jetty Server already started on port: {}", port);
            throw new RuntimeException("Jetty Server already started.");
        }
    }
    private void doStart() throws Throwable {
        if (!assertPort(port)) {
            throw new IllegalArgumentException("Port already in use!");
        }
        server = new Server(port);
        // 注冊(cè)處理的handler
        server.setHandler(new HttpHandler(applicationContext));
        server.start();
        log.info("Jetty Server started on port: {}", port);
    }
    /**
     * 判斷端口是否可用
     *
     * @param port 端口
     * @return 端口是否可用
     */
    private boolean assertPort(int port) {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(port);
            return true;
        } catch (IOException e) {
            log.error("An error occur during test server port, cause: {}", Throwables.getStackTraceAsString(e));
        } finally {
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    log.error("An error occur during closing serverSocket, cause: {}", Throwables.getStackTraceAsString(e));
                }
            }
        }
        return false;
    }
}

HttpHandler處理http請(qǐng)求

public class HttpHandler extends AbstractHandler {
    private ObjectMapper objectMapper = new ObjectMapper();
    private Map<String, Method> methodMap = new ConcurrentHashMap<>();
    private final ApplicationContext applicationContext;
    public HttpHandler(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
    private InvokeRequest readRequest(HttpServletRequest request) throws IOException {
        int contentLength = request.getContentLength();
        ServletInputStream inputStream = request.getInputStream();
        byte[] buffer = new byte[contentLength];
        inputStream.read(buffer, 0, contentLength);
        inputStream.close();
        return objectMapper.readValue(buffer, InvokeRequest.class);
    }
    private void registerBeanOfType(Class<?> type) {
        BeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClassName(type.getName());
        ((DefaultListableBeanFactory) (((GenericApplicationContext) applicationContext).getBeanFactory()))
                .registerBeanDefinition(type.getName(), beanDefinition);
    }
    private Method getMethod(Class clazz, String methodName) {
        String key = clazz.getCanonicalName() + ":" + methodName;
        Method md = null;
        if (methodMap.containsKey(key)) {
            md = methodMap.get(key);
        } else {
            Method[] methods = clazz.getMethods();
            for (Method mth : methods) {
                if (mth.getName().equals(methodName)) {
                    methodMap.putIfAbsent(key, mth);
                    md = mth;
                    break;
                }
            }
        }
        return md;
    }
    private InvokeResult execute(InvokeRequest invokeRequest) {
        Class<?> testClass = invokeRequest.getTestClass();
        Object bean;
        try {
            bean = applicationContext.getBean(testClass.getName());
        } catch (Exception e) {
            registerBeanOfType(testClass);
            bean = applicationContext.getBean(testClass.getName());
        }
        InvokeResult invokeResult = new InvokeResult();
        Method method = getMethod(testClass, invokeRequest.getMethodName());
        try {
            // 遠(yuǎn)程代理執(zhí)行
            method.invoke(bean);
            invokeResult.setSuccess(true);
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            if (!(e instanceof InvocationTargetException)
                    || !(((InvocationTargetException) e).getTargetException() instanceof AssertionError)) {
                log.error("fail to invoke code, cause: {}", Throwables.getStackTraceAsString(e));
            }
            invokeResult.setSuccess(false);
            // 記錄異常類
            InvokeFailedException invokeFailedException = new InvokeFailedException();
            invokeFailedException.setMessage(e.getMessage());
            invokeFailedException.setStackTrace(e.getStackTrace());
            // 由Assert拋出來(lái)的錯(cuò)誤
            if (e.getCause() instanceof AssertionError) {
                invokeFailedException.setAssertionError((AssertionError) e.getCause());
            }
            invokeResult.setException(invokeFailedException);
        } catch (Exception e) {
            log.error("fail to invoke code, cause: {}", Throwables.getStackTraceAsString(e));
            invokeResult.setSuccess(false);
            InvokeFailedException invokeFailedException = new InvokeFailedException();
            invokeFailedException.setMessage(e.getMessage());
            invokeFailedException.setStackTrace(e.getStackTrace());
        }
        return invokeResult;
    }
    @Override
    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) {
        try {
            InvokeRequest invokeRequest = readRequest(request);
            InvokeResult invokeResult = execute(invokeRequest);
            String result = objectMapper.writeValueAsString(invokeResult);
            response.setHeader("Content-Type", "application/json");
            response.getWriter().write(result);
            response.getWriter().close();
        } catch (Exception e) {
            try {
                response.getWriter().write(Throwables.getStackTraceAsString(e));
                response.getWriter().close();
            } catch (Exception ex) {
                log.error("fail to handle request");
            }
        }
    }
}
public class InvokeRequest implements Serializable {
    private static final long serialVersionUID = 6162519478671749612L;
    /**
     * 測(cè)試方法所在的類
     */
    private Class<?> testClass;
    /**
     * 測(cè)試的方法名
     */
    private String methodName;
}

編寫SpringDelegateRunner繼承SpringJUnit4ClassRunner

public class SpringDelegateRunner extends ModifiedSpringJUnit4ClassRunner {
    private ObjectMapper objectMapper = new ObjectMapper();
    private final Class<?> testClass;
    private final Boolean DEBUG_MODE = true;
    public SpringDelegateRunner(Class<?> clazz) throws InitializationError {
        super(clazz);
        this.testClass = clazz;
    }
    /**
     * 遞交給遠(yuǎn)程執(zhí)行
     *
     * @param method   執(zhí)行的方法
     * @param notifier Runner通知
     */
    @Override
    protected void runChild(FrameworkMethod method, RunNotifier notifier) {
        Description description = describe(method);
        if (isIgnored(method)) {
            notifier.fireTestIgnored(description);
            return;
        }
        InvokeRequest invokeRequest = new InvokeRequest();
        invokeRequest.setTestClass(method.getDeclaringClass());
        invokeRequest.setMethodName(method.getName());
        try {
            notifier.fireTestStarted(description);
            String json = objectMapper.writeValueAsString(invokeRequest);
            // http請(qǐng)求訪問(wèn)服務(wù)器
            String body = HttpRequest.post("http://127.0.0.1:" + DebugMaskUtil.getPort()).send(json).body();
            if (StringUtils.isEmpty(body)) {
                notifier.fireTestFailure(new Failure(description, new RuntimeException("遠(yuǎn)程執(zhí)行失敗")));
            }
            InvokeResult invokeResult = objectMapper.readValue(body, InvokeResult.class);
            Boolean success = invokeResult.getSuccess();
            if (success) {
                notifier.fireTestFinished(description);
            } else {
                InvokeFailedException exception = invokeResult.getException();
                if (exception.getAssertionError() != null) {
                    notifier.fireTestFailure(new Failure(description, exception.getAssertionError()));
                } else {
                    notifier.fireTestFailure(new Failure(description, invokeResult.getException()));
                }
            }
        } catch (Exception e) {
            notifier.fireTestFailure(new Failure(description, e));
        }
        }
    }

6.2 Tomcat作為容器啟動(dòng)

@Slf4j
@Controller
@RequestMapping("junit")
public class TestController {
    private ObjectMapper objectMapper = new ObjectMapper();
    @Autowired
    private ApplicationContext applicationContext;
    private Map<String, Method> methodMap = new ConcurrentHashMap<>();
    @PostMapping("/test")
    public void test(HttpServletRequest request, HttpServletResponse response){
        int contentLength = request.getContentLength();
        ServletInputStream inputStream;
        byte[] buffer = null;
        try {
            inputStream = request.getInputStream();
            buffer = new byte[contentLength];
            inputStream.read(buffer, 0, contentLength);
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            InvokeRequest invokeRequest = objectMapper.readValue(buffer, InvokeRequest.class);
//            InvokeRequest invokeRequest = JsonUtil.getObject(new String(buffer),InvokeRequest.class);
            InvokeResult execute = execute(invokeRequest);
            String result = objectMapper.writeValueAsString(execute);
            log.info("==================="+result);
            response.setHeader("Content-Type", "application/json");
            response.getWriter().write(result);
            response.getWriter().close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private void registerBeanOfType(Class<?> type) {
        BeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClassName(type.getName());
        ((DefaultListableBeanFactory) (((GenericApplicationContext) applicationContext).getBeanFactory()))
                .registerBeanDefinition(type.getName(), beanDefinition);
    }
    private Method getMethod(Class clazz, String methodName) {
        String key = clazz.getCanonicalName() + ":" + methodName;
        Method md = null;
        if (methodMap.containsKey(key)) {
            md = methodMap.get(key);
        } else {
            Method[] methods = clazz.getMethods();
            for (Method mth : methods) {
                if (mth.getName().equals(methodName)) {
                    methodMap.putIfAbsent(key, mth);
                    md = mth;
                    break;
                }
            }
        }
        return md;
    }
    private InvokeResult execute(InvokeRequest invokeRequest) {
        Class<?> testClass = invokeRequest.getTestClass();
        Object bean;
        try {
            bean = applicationContext.getBean(testClass.getName());
        } catch (Exception e) {
            registerBeanOfType(testClass);
            bean = applicationContext.getBean(testClass.getName());
        }
        InvokeResult invokeResult = new InvokeResult();
        Method method = getMethod(testClass, invokeRequest.getMethodName());
        try {
            method.invoke(bean);
            invokeResult.setSuccess(true);
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            if (!(e instanceof InvocationTargetException)
                    || !(((InvocationTargetException) e).getTargetException() instanceof AssertionError)) {
                log.error("fail to invoke code, cause: {}", Throwables.getStackTraceAsString(e));
            }
            invokeResult.setSuccess(false);
            InvokeFailedException invokeFailedException = new InvokeFailedException();
            invokeFailedException.setMessage(e.getMessage());
            invokeFailedException.setStackTrace(e.getStackTrace());
            // 由Assert拋出來(lái)的錯(cuò)誤
            if (e.getCause() instanceof AssertionError) {
                invokeFailedException.setAssertionError((AssertionError) e.getCause());
            }
            invokeResult.setException(invokeFailedException);
        } catch (Exception e) {
            log.error("fail to invoke code, cause: {}", Throwables.getStackTraceAsString(e));
            invokeResult.setSuccess(false);
            InvokeFailedException invokeFailedException = new InvokeFailedException();
            invokeFailedException.setMessage(e.getMessage());
            invokeFailedException.setStackTrace(e.getStackTrace());
        }
        return invokeResult;
    }
}

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Spring多數(shù)據(jù)源切換失敗,發(fā)現(xiàn)與事務(wù)相關(guān)問(wèn)題

    Spring多數(shù)據(jù)源切換失敗,發(fā)現(xiàn)與事務(wù)相關(guān)問(wèn)題

    這篇文章主要介紹了Spring多數(shù)據(jù)源切換失敗,發(fā)現(xiàn)與事務(wù)相關(guān)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Java 高并發(fā)九:鎖的優(yōu)化和注意事項(xiàng)詳解

    Java 高并發(fā)九:鎖的優(yōu)化和注意事項(xiàng)詳解

    本文主要介紹Java高并發(fā)鎖的優(yōu)化和注意事項(xiàng),這里整理了詳細(xì)的資料,并講解了 1. 鎖優(yōu)化的思路和方法 2. 虛擬機(jī)內(nèi)的鎖優(yōu)化 3. 一個(gè)錯(cuò)誤使用鎖的案例 4. ThreadLocal及其源碼分析等知識(shí),有需要的小伙伴可以參考下
    2016-09-09
  • JAVA SPI機(jī)制詳解使用方法

    JAVA SPI機(jī)制詳解使用方法

    Java定義了一套JDBC的接口,但并未提供具體實(shí)現(xiàn)類,而是在不同云廠商提供的數(shù)據(jù)庫(kù)實(shí)現(xiàn)包。這篇文章給大家介紹Java的SPI機(jī)制,感興趣的朋友一起看看吧
    2022-07-07
  • 詳解spring注解配置啟動(dòng)過(guò)程

    詳解spring注解配置啟動(dòng)過(guò)程

    這篇文章主要為大家詳細(xì)介紹了詳解spring注解配置啟動(dòng)過(guò)程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • 解決java.lang.Error: Unresolved compilation problems:問(wèn)題

    解決java.lang.Error: Unresolved compilation pro

    這篇文章主要介紹了解決java.lang.Error: Unresolved compilation problems:問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • 在SpringBoot+MyBatis中優(yōu)雅處理多表數(shù)據(jù)清洗的實(shí)現(xiàn)步驟

    在SpringBoot+MyBatis中優(yōu)雅處理多表數(shù)據(jù)清洗的實(shí)現(xiàn)步驟

    數(shù)據(jù)清洗是指對(duì)數(shù)據(jù)進(jìn)行處理和糾錯(cuò),以去除或修復(fù)數(shù)據(jù)集中存在的錯(cuò)誤、不致、不完整和冗余的數(shù)據(jù),從而使數(shù)據(jù)更加準(zhǔn)確、可靠和有用,本文給大家介紹了在SpringBoot和MyBatis中優(yōu)雅處理多表數(shù)據(jù)清洗的實(shí)現(xiàn)步驟,需要的朋友可以參考下
    2025-03-03
  • Java中OGNL表達(dá)式語(yǔ)言的使用詳解

    Java中OGNL表達(dá)式語(yǔ)言的使用詳解

    本文介紹了OGNL(ObjectGraphNavigationLanguage)表達(dá)式語(yǔ)言,這是一種用于Java語(yǔ)言的對(duì)象圖導(dǎo)航和操作的表達(dá)式語(yǔ)言,它支持訪問(wèn)對(duì)象屬性、調(diào)用對(duì)象方法、執(zhí)行算術(shù)和邏輯運(yùn)算,以及處理集合和數(shù)組等操作,OGNL的語(yǔ)法簡(jiǎn)潔明了
    2024-12-12
  • Java實(shí)現(xiàn)PDF添加水印的完整方案

    Java實(shí)現(xiàn)PDF添加水印的完整方案

    在企業(yè)級(jí)應(yīng)用中,PDF水印是文檔安全管理的必備功能,無(wú)論是版權(quán)保護(hù)、版本標(biāo)識(shí),還是敏感信息管控,水印都扮演著重要角色,本文將提供一個(gè)生產(chǎn)級(jí)的PDF水印解決方案,需要的朋友可以參考下
    2026-02-02
  • mybatis實(shí)現(xiàn)表與對(duì)象的關(guān)聯(lián)關(guān)系_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    mybatis實(shí)現(xiàn)表與對(duì)象的關(guān)聯(lián)關(guān)系_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要介紹了mybatis實(shí)現(xiàn)表與對(duì)象的關(guān)聯(lián)關(guān)系_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理,需要的朋友可以參考下
    2017-09-09
  • 怎樣通過(guò)反射獲取非靜態(tài)內(nèi)部類實(shí)例

    怎樣通過(guò)反射獲取非靜態(tài)內(nèi)部類實(shí)例

    這篇文章主要介紹了怎樣通過(guò)反射獲取非靜態(tài)內(nèi)部類實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03

最新評(píng)論

镇雄县| 朝阳市| 新宾| 鄂托克前旗| 宁河县| 南皮县| 泗阳县| 峡江县| 江都市| 扬州市| 女性| 同德县| 满洲里市| 静乐县| 沭阳县| 清苑县| 林芝县| 榕江县| 南川市| 金乡县| 康平县| 岑巩县| 青阳县| 商洛市| 桓台县| 琼中| 镇坪县| 深圳市| 体育| 洛宁县| 龙游县| 青川县| 行唐县| 武平县| 承德县| 阳春市| 余江县| 龙陵县| 云林县| 宁海县| 郴州市|