中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么使用java Netty實現傳輸文件、分片發送、斷點續傳

發布時間:2021-11-18 10:16:25 來源:億速云 閱讀:613 作者:iii 欄目:編程語言

這篇文章主要講解了“怎么使用java Netty實現傳輸文件、分片發送、斷點續傳”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“怎么使用java Netty實現傳輸文件、分片發送、斷點續傳”吧!

開發環境

1、jdk1.8【jdk1.7以下只能部分支持netty】
2、Netty4.1.36.Final【netty3.x 4.x 5每次的變化較大,接口類名也隨著變化】

代碼示例

itstack-demo-netty-2-04
└── src
   ├── main
   │   └── java
   │       └── org.itstack.demo.netty
   │           ├── client
   │           │   ├── MyChannelInitializer.java
   │           │   ├── MyClientHandler.java
   │           │   └── NettyClient.java
   │           ├── codec
   │           │   ├── ObjDecoder.java
   │           │   └── ObjEncoder.java
   │           ├── domain
   │           │   ├── Constants.java
   │           │   ├── FileBurstData.java
   │           │   ├── FileBurstInstruct.java
   │           │   ├── FileDescInfo.java
   │           │   └── FileTransferProtocol.java
   │           ├── server
   │           │   ├── MyChannelInitializer.java
   │           │   ├── MyServerHandler.java
   │           │   └── NettyServer.java
   │           └── util
   │               ├── CacheUtil.java
   │               ├── FileUtil.java
   │               ├── MsgUtil.java
   │               └── SerializationUtil.java
   │
   └── test
        └── java
            └── org.itstack.demo.test
                ├── ApiTest.java
                ├── NettyClientTest.java
                └── NettyServerTest.java

演示部分重點代碼塊,完整代碼下載關注公眾號;bugstack蟲洞棧

client/MyClientHandler.java *文件客戶端;channelRead處理文件協議,其中模擬傳輸過程中斷,場景測試可以注釋掉

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
   //數據格式驗證
   if (!(msg instanceof FileTransferProtocol)) return;

   FileTransferProtocol fileTransferProtocol = (FileTransferProtocol) msg;
   //0傳輸文件'請求'、1文件傳輸'指令'、2文件傳輸'數據'
   switch (fileTransferProtocol.getTransferType()) {
       case 1:
           FileBurstInstruct fileBurstInstruct = (FileBurstInstruct) fileTransferProtocol.getTransferObj();
           //Constants.FileStatus {0開始、1中間、2結尾、3完成}
           if (Constants.FileStatus.COMPLETE == fileBurstInstruct.getStatus()) {
               ctx.flush();
               ctx.close();
               System.exit(-1);
               return;
           }
           FileBurstData fileBurstData = FileUtil.readFile(fileBurstInstruct.getClientFileUrl(), fileBurstInstruct.getReadPosition());
           ctx.writeAndFlush(MsgUtil.buildTransferData(fileBurstData));
           System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " bugstack蟲洞棧客戶端傳輸文件信息。FILE:" + fileBurstData.getFileName() + " SIZE(byte):" + (fileBurstData.getEndPos() - fileBurstData.getBeginPos()));
           break;
       default:
           break;
   }

   /**模擬傳輸過程中斷,場景測試可以注釋掉
    *
    */
   System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " bugstack蟲洞棧客戶端傳輸文件信息[主動斷開鏈接,模擬斷點續傳]");
   ctx.flush();
   ctx.close();
   System.exit(-1);

}

domain/FileBurstData.java *文件分片數據塊

/**
* 文件分片數據
* 蟲洞棧:https://bugstack.cn
* 公眾號:bugstack蟲洞棧  {獲取學習源碼}
* 蟲洞群:①群5398358 ②群5360692
* Create by fuzhengwei on 2019
*/
public class FileBurstData {

   private String fileUrl;     //客戶端文件地址
   private String fileName;    //文件名稱
   private Integer beginPos;   //開始位置
   private Integer endPos;     //結束位置
   private byte[] bytes;       //文件字節;再實際應用中可以使用非對稱加密,以保證傳輸信息安全
   private Integer status;     //Constants.FileStatus {0開始、1中間、2結尾、3完成}

   ... get/set
}

domain/FileBurstInstruct.java *文件分片指令

/**
* 文件分片指令
* 蟲洞棧:https://bugstack.cn
* 公眾號:bugstack蟲洞棧  {獲取學習源碼}
* 蟲洞群:①群5398358 ②群5360692
* Create by fuzhengwei on @2019
*/
public class FileBurstInstruct {

   private Integer status;       //Constants.FileStatus {0開始、1中間、2結尾、3完成}
   private String clientFileUrl; //客戶端文件URL
   private Integer readPosition; //讀取位置

   ... get/set
}

domain/FileDescInfo.java *文件傳輸信息

/**
* 文件描述信息
* 蟲洞棧:https://bugstack.cn
* 公眾號:bugstack蟲洞棧  {獲取學習源碼}
* 蟲洞群:①群5398358 ②群5360692
* Create by fuzhengwei on @2019
*/
public class FileDescInfo {

   private String fileUrl;
   private String fileName;
   private Long fileSize;

   ... get/set
}

domain/FileTransferProtocol.java *文件傳輸協議

/**
* 文件傳輸協議
* 蟲洞棧:https://bugstack.cn
* 公眾號:bugstack蟲洞棧  {獲取學習源碼}
* 蟲洞群:5360692
* Create by fuzhengwei on @2019
*/
public class FileTransferProtocol {

   private Integer transferType; //0請求傳輸文件、1文件傳輸指令、2文件傳輸數據
   private Object transferObj;   //數據對象;(0)FileDescInfo、(1)FileBurstInstruct、(2)FileBurstData

   ... get/set
}

serverMyServerHandler.java *文件服務端;channelRead處理文件協議,并包含了保存續傳信息,用于斷點續傳

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
   //數據格式驗證
   if (!(msg instanceof FileTransferProtocol)) return;

   FileTransferProtocol fileTransferProtocol = (FileTransferProtocol) msg;
   //0傳輸文件'請求'、1文件傳輸'指令'、2文件傳輸'數據'
   switch (fileTransferProtocol.getTransferType()) {
       case 0:
           FileDescInfo fileDescInfo = (FileDescInfo) fileTransferProtocol.getTransferObj();

           //斷點續傳信息,實際應用中需要將斷點續傳信息保存到數據庫中
           FileBurstInstruct fileBurstInstructOld = CacheUtil.burstDataMap.get(fileDescInfo.getFileName());
           if (null != fileBurstInstructOld) {
               if (fileBurstInstructOld.getStatus() == Constants.FileStatus.COMPLETE) {
                   CacheUtil.burstDataMap.remove(fileDescInfo.getFileName());
               }
               //傳輸完成刪除斷點信息
               System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " bugstack蟲洞棧服務端,接收客戶端傳輸文件請求[斷點續傳]。" + JSON.toJSONString(fileBurstInstructOld));
               ctx.writeAndFlush(MsgUtil.buildTransferInstruct(fileBurstInstructOld));
               return;
           }

           //發送信息
           FileTransferProtocol sendFileTransferProtocol = MsgUtil.buildTransferInstruct(Constants.FileStatus.BEGIN, fileDescInfo.getFileUrl(), 0);
           ctx.writeAndFlush(sendFileTransferProtocol);
           System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " bugstack蟲洞棧服務端,接收客戶端傳輸文件請求。" + JSON.toJSONString(fileDescInfo));
           break;
       case 2:
           FileBurstData fileBurstData = (FileBurstData) fileTransferProtocol.getTransferObj();
           FileBurstInstruct fileBurstInstruct = FileUtil.writeFile("E://", fileBurstData);

           //保存斷點續傳信息
           CacheUtil.burstDataMap.put(fileBurstData.getFileName(), fileBurstInstruct);

           ctx.writeAndFlush(MsgUtil.buildTransferInstruct(fileBurstInstruct));
           System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " bugstack蟲洞棧服務端,接收客戶端傳輸文件數據。" + JSON.toJSONString(fileBurstData));

           //傳輸完成刪除斷點信息
           if (fileBurstInstruct.getStatus() == Constants.FileStatus.COMPLETE) {
               CacheUtil.burstDataMap.remove(fileBurstData.getFileName());
           }
           break;
       default:
           break;
   }

}

util/FileUtil.java *文件讀寫工具,分片讀取寫入處理類

/**
* 文件讀寫工具
* 蟲洞棧:https://bugstack.cn
* 公眾號:bugstack蟲洞棧  {獲取學習源碼}
* 蟲洞群:5360692
* Create by fuzhengwei on @2019
*/
public class FileUtil {

   public static FileBurstData readFile(String fileUrl, Integer readPosition) throws IOException {
       File file = new File(fileUrl);
       RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");//r: 只讀模式 rw:讀寫模式
       randomAccessFile.seek(readPosition);
       byte[] bytes = new byte[1024];
       int readSize = randomAccessFile.read(bytes);
       if (readSize <= 0) {
           randomAccessFile.close();
           return new FileBurstData(Constants.FileStatus.COMPLETE);//Constants.FileStatus {0開始、1中間、2結尾、3完成}
       }
       FileBurstData fileInfo = new FileBurstData();
       fileInfo.setFileUrl(fileUrl);
       fileInfo.setFileName(file.getName());
       fileInfo.setBeginPos(readPosition);
       fileInfo.setEndPos(readPosition + readSize);
       //不足1024需要拷貝去掉空字節
       if (readSize < 1024) {
           byte[] copy = new byte[readSize];
           System.arraycopy(bytes, 0, copy, 0, readSize);
           fileInfo.setBytes(copy);
           fileInfo.setStatus(Constants.FileStatus.END);
       } else {
           fileInfo.setBytes(bytes);
           fileInfo.setStatus(Constants.FileStatus.CENTER);
       }
       randomAccessFile.close();
       return fileInfo;
   }

   public static FileBurstInstruct writeFile(String baseUrl, FileBurstData fileBurstData) throws IOException {

       if (Constants.FileStatus.COMPLETE == fileBurstData.getStatus()) {
           return new FileBurstInstruct(Constants.FileStatus.COMPLETE); //Constants.FileStatus {0開始、1中間、2結尾、3完成}
       }

       File file = new File(baseUrl + "/" + fileBurstData.getFileName());
       RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");//r: 只讀模式 rw:讀寫模式
       randomAccessFile.seek(fileBurstData.getBeginPos());      //移動文件記錄指針的位置,
       randomAccessFile.write(fileBurstData.getBytes());        //調用了seek(start)方法,是指把文件的記錄指針定位到start字節的位置。也就是說程序將從start字節開始寫數據
       randomAccessFile.close();

       if (Constants.FileStatus.END == fileBurstData.getStatus()) {
           return new FileBurstInstruct(Constants.FileStatus.COMPLETE); //Constants.FileStatus {0開始、1中間、2結尾、3完成}
       }

       //文件分片傳輸指令
       FileBurstInstruct fileBurstInstruct = new FileBurstInstruct();
       fileBurstInstruct.setStatus(Constants.FileStatus.CENTER);            //Constants.FileStatus {0開始、1中間、2結尾、3完成}
       fileBurstInstruct.setClientFileUrl(fileBurstData.getFileUrl());      //客戶端文件URL
       fileBurstInstruct.setReadPosition(fileBurstData.getEndPos() + 1);    //讀取位置

       return fileBurstInstruct;
   }

}

util/MsgUtil.java *傳輸消息體構建工具類

/**
* 消息構建工具
* 蟲洞棧:https://bugstack.cn
* 公眾號:bugstack蟲洞棧  {獲取學習源碼}
* 蟲洞群:5360692
* Create by fuzhengwei on @2019
*/
public class MsgUtil {

   /**
    * 構建對象;請求傳輸文件(客戶端)
    *
    * @param fileUrl  客戶端文件地址
    * @param fileName 文件名稱
    * @param fileSize 文件大小
    * @return 傳輸協議
    */
   public static FileTransferProtocol buildRequestTransferFile(String fileUrl, String fileName, Long fileSize) {

       FileDescInfo fileDescInfo = new FileDescInfo();
       fileDescInfo.setFileUrl(fileUrl);
       fileDescInfo.setFileName(fileName);
       fileDescInfo.setFileSize(fileSize);

       FileTransferProtocol fileTransferProtocol = new FileTransferProtocol();
       fileTransferProtocol.setTransferType(0);//0請求傳輸文件、1文件傳輸指令、2文件傳輸數據
       fileTransferProtocol.setTransferObj(fileDescInfo);

       return fileTransferProtocol;

   }

   /**
    * 構建對象;文件傳輸指令(服務端)
    * @param status          0請求傳輸文件、1文件傳輸指令、2文件傳輸數據
    * @param clientFileUrl   客戶端文件地址
    * @param readPosition    讀取位置
    * @return                傳輸協議
    */
   public static FileTransferProtocol buildTransferInstruct(Integer status, String clientFileUrl, Integer readPosition) {

       FileBurstInstruct fileBurstInstruct = new FileBurstInstruct();
       fileBurstInstruct.setStatus(status);
       fileBurstInstruct.setClientFileUrl(clientFileUrl);
       fileBurstInstruct.setReadPosition(readPosition);

       FileTransferProtocol fileTransferProtocol = new FileTransferProtocol();
       fileTransferProtocol.setTransferType(Constants.TransferType.INSTRUCT); //0傳輸文件'請求'、1文件傳輸'指令'、2文件傳輸'數據'
       fileTransferProtocol.setTransferObj(fileBurstInstruct);

       return fileTransferProtocol;
   }

   /**
    * 構建對象;文件傳輸指令(服務端)
    *
    * @return 傳輸協議
    */
   public static FileTransferProtocol buildTransferInstruct(FileBurstInstruct fileBurstInstruct) {
       FileTransferProtocol fileTransferProtocol = new FileTransferProtocol();
       fileTransferProtocol.setTransferType(Constants.TransferType.INSTRUCT);  //0傳輸文件'請求'、1文件傳輸'指令'、2文件傳輸'數據'
       fileTransferProtocol.setTransferObj(fileBurstInstruct);
       return fileTransferProtocol;
   }

   /**
    * 構建對象;文件傳輸數據(客戶端)
    *
    * @return 傳輸協議
    */
   public static FileTransferProtocol buildTransferData(FileBurstData fileBurstData) {
       FileTransferProtocol fileTransferProtocol = new FileTransferProtocol();
       fileTransferProtocol.setTransferType(Constants.TransferType.DATA); //0傳輸文件'請求'、1文件傳輸'指令'、2文件傳輸'數據'
       fileTransferProtocol.setTransferObj(fileBurstData);
       return fileTransferProtocol;
   }

}

test/NettyServerTest.java *服務端啟動器

/**
* 蟲洞棧:https://bugstack.cn
* 公眾號:bugstack蟲洞棧  {獲取學習源碼}
* 蟲洞群:①群5398358 ②群5360692
* Create by fuzhengwei on 2019
*/
public class NettyServerTest {

   public static void main(String[] args) {
       //啟動服務
       new NettyServer().bing(7397);
   }

}

test/NettyClientTest.java *客戶端啟動器

/**
* 蟲洞棧:https://bugstack.cn
* 公眾號:bugstack蟲洞棧  {獲取學習源碼}
* 蟲洞群:①群5398358 ②群5360692
* Create by fuzhengwei on 2019
*/
public class NettyClientTest {

   public static void main(String[] args) {

       //啟動客戶端
       ChannelFuture channelFuture = new NettyClient().connect("127.0.0.1", 7397);

       //文件信息{文件大于1024kb方便測試斷點續傳}
       File file = new File("C:\\Users\\fuzhengwei\\Desktop\\測試傳輸文件.rar");
       FileTransferProtocol fileTransferProtocol = MsgUtil.buildRequestTransferFile(file.getAbsolutePath(), file.getName(), file.length());

       //發送信息;請求傳輸文件
       channelFuture.channel().writeAndFlush(fileTransferProtocol);

   }

}

測試結果

啟動NettyServerTest *默認接收地址為E盤根目錄

怎么使用java Netty實現傳輸文件、分片發送、斷點續傳

啟動NettyClientTest *設置傳輸文件

怎么使用java Netty實現傳輸文件、分片發送、斷點續傳

文件傳輸結果

怎么使用java Netty實現傳輸文件、分片發送、斷點續傳

服務端執行結果

itstack-demo-netty server start done. {關注公眾號:bugstack蟲洞棧,獲取源碼}
鏈接報告開始
鏈接報告信息:有一客戶端鏈接到本服務端。channelId:3a1df8c1
鏈接報告IP:127.0.0.1
鏈接報告Port:7397
鏈接報告完畢
2019-08-04 19:46:46 bugstack蟲洞棧服務端,接收客戶端傳輸文件請求。{"fileName":"測試傳輸文件.rar","fileSize":1400,"fileUrl":"C:\\Users\\fuzhengwei1\\Desktop\\測試傳輸文件.rar"}
2019-08-04 19:46:46 bugstack蟲洞棧服務端,接收客戶端傳輸文件數據。{"beginPos":0,"bytes":"UmFyIRoHAM+QcwAADQAAAAAAAAC4C3SgkkkAFAUAAIjDEQACJRsHe0WECE8dMyQAIAAAALLiytS0q8rkzsS8/i50eHQAbWpL1YsgT5OPoIdl9k4udAB4dACwS2heCZgVEQzPzUEXfAnhs2R75rhNbCQhNE3uMY4EBkBqQJ45izS4lFGujEk08xLGuhp4sSUSbzEscRICakGyOdARhIE6GEPucySJpY5kQ/Cq28ur4XdfH/j1V8UVoo5X5V+B3dl2f8qvvoxd3t6GPv8HZ7dXs+98XT6uJ0Oj8GZ4c6tvV6vzV865ka375utod+9i+pX/O1Uu1tT76tT38TE+Hq+tzud6Of9Xo9T0/S/xytLm12v4NWztfhnda3lbevs7dnXsWL1vT3Kte91triqYuHW/9bf3WPnjq5r5savbHd67V8Nu6r5+lmZtrP0eO63Ba+upVuWtf7bvByg2/0w+5hz8ru14ND5ex/Odw4F7uRWrYedwU2tXmw5m1u+S7lWdjvTq5e/Kv+1apZxrdjT2dHizdHDrlrH1cvkbrWe5k97u6WRnXdviw6zkvc3cD9TOt7+7W9z2/Ys+Sx9VTPwGeYLmrz+h8fQt5u5v8/3fZ5sXKnc4MOT1+n0upicmOVDT86GfY4bPf5vN7XSxMT5Mnsdry8e84///+quHp9l19fRz8vkds+O7qb+9pWe1WvXdb7NWza3vNO3V3cZZ2rPDr1svHwO3Nq14sBuZu3P1zOvuWP++s8ex9O95e5U/vW9/F7Jtb+p+PGeRtzlg8VfG5t5TyAAAAAAAAAAAAAAAARu1PHU9QX3wAAAAAAAAAAAAAAAiiXyXwAAAAAAAAAAAAAAAiiXyXwAAAAAAAAAAAAAAAiiXyXwAAAAAAAAAAAAAAAiiXyXwAEbDTyAAAAAAAAAAAAAEctTx1PUF98AAAAAAAAAAAAAAAIol8l8AAAAAAAAAAAAAAAIol8l8AAAAAAAAAAAAAAAIol8l8AAAAAAAAAAAAAAAIol8l8AAAABHx08gAAAAAAAAAAj108dT1BffAAAAAAAAAAAAAAACKJfJfAAAAAAAAAAAAAAACKJfJfAAAAAAAAAAAAAAACKJfJfAAAAAAAAAAAAAAACKJfJfAAAAAAAAgankAAAAAAAEZGnjqeoL74AAAAAAAAAAAAAAARRL5L4AAAAAAAAAAAAAAARRL5L4AAAAAAAAAAAAAAARRL5L4AAAAAAAAAAAAAAARRL5L4AAAAAAAAAAEYinkAAAAEH08dT1BffAAAAAAAAAAAAAAACKJfJfAAAAAAAAAAAAAAACKJfJfAAAAAAAAAAAAAAACKJfJfAAAAAAAAAAAAAAACKJfJfAAAAAAAAAAA==","endPos":1024,"fileName":"測試傳輸文件.rar","fileUrl":"C:\\Users\\fuzhengwei1\\Desktop\\測試傳輸文件.rar","status":1}
2019-08-04 19:46:46 bugstack蟲洞棧服務端,接收客戶端傳輸文件數據。{"beginPos":1025,"bytes":"AAI8VPIAEfZTx1PUF98AAAAAAAAAAAAAAAIol8l8AAAAAAAAAAAAAAAIol8l8AAAAAAAAAAAAAAAIol8l8AAAAAAAAAAAAAAAIol8l8AAAAAAAAAAAAAAAIol8l8R+dPIAAAAAAAAAAAAAAAjt08dT1BffAAAAAAAAAAAAAAACKJfJfAAAAAAAAAAAAAAACKJfJfAAAAAAAAAAAAAAACKJfJfAAAAAAAAAAAAAAACKJfJfAAAIWp5AAAAAAAAAAAAEYGnjqeoL74AAAAAAAAAAAAAAARRL5L4AAAAAAAAAAAAAAARRL5L4AAAAAAAAAAAAAAARRL5L4AAAAAAAAAAAAAAARRL5L4AAAAABGYp5AAAAAAAAAEc/Tx1PUF98AAAAAAAAIyFPIAAAAAACB6eOp6gvvgAAAAAAAAAARiKeQAAAAQfTx1PUF98AAAAAAAAAAAAAjAU8gACF6eOp6gvvgAAAAAAAAAAAAAABFH9IDEPXsAQAcA","endPos":1400,"fileName":"測試傳輸文件.rar","fileUrl":"C:\\Users\\fuzhengwei1\\Desktop\\測試傳輸文件.rar","status":2}
客戶端斷開鏈接/127.0.0.1:7397

Process finished with exit code -1

客戶端執行結果

itstack-demo-netty client start done. {關注公眾號:bugstack蟲洞棧,獲取源碼}
鏈接報告開始
鏈接報告信息:本客戶端鏈接到服務端。channelId:71399d8c
鏈接報告IP:127.0.0.1
鏈接報告Port:54974
鏈接報告完畢
2019-08-04 19:46:46 bugstack蟲洞棧客戶端傳輸文件信息。FILE:測試傳輸文件.rar SIZE(byte):1024
2019-08-04 19:46:46 bugstack蟲洞棧客戶端傳輸文件信息。FILE:測試傳輸文件.rar SIZE(byte):375

Process finished with exit code -1

感謝各位的閱讀,以上就是“怎么使用java Netty實現傳輸文件、分片發送、斷點續傳”的內容了,經過本文的學習后,相信大家對怎么使用java Netty實現傳輸文件、分片發送、斷點續傳這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

阿尔山市| 天长市| 安新县| 堆龙德庆县| 沂南县| 巧家县| 三门县| 新化县| 岢岚县| 台南市| 额济纳旗| 德化县| 宜阳县| 封丘县| 樟树市| 含山县| 滨州市| 凌云县| 孝感市| 会泽县| 稷山县| 云霄县| 赤水市| 新晃| 遵化市| 甘南县| 讷河市| 铜鼓县| 马鞍山市| 宁明县| 安徽省| 建德市| 孙吴县| 大宁县| 普安县| 綦江县| 平邑县| 府谷县| 揭西县| 辽阳市| 自贡市|