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

溫馨提示×

溫馨提示×

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

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

java后臺實現支付寶支付接口和支付寶訂單查詢接口(前端為APP)

發布時間:2020-09-28 09:05:51 來源:腳本之家 閱讀:472 作者:Ouyzc 欄目:編程語言

最近項目APP需要接入微信、支付寶支付功能,在分配開發任務時,聽說微信支付接口比支付寶支付接口要難實現,由于我開發經驗不是那么豐富(現工作經驗1年半)且未接觸過支付接口開發,組里剛好又有支付接口的老司機,所以很自然把簡單的支付寶接口開發任務交給了我,看來開發組的組長還是很好人的嘛.....,廢話就不多說了,我們開始吧!

實現支付寶接口詳細過程

1.去支付寶官網申請公司企業賬號并開通一個應用,在應用里簽約APP支付功能

具體的申請截圖步驟,在這里我就不詳細說了,因為這不是文章的重點,可參考支付寶官網。

經過這一步,我們可以得過開發中需要用到的幾個參數

①商戶appid  ②商戶公鑰、私鑰  ③支付寶公鑰  ④支付寶網關地址

解釋一下這幾個參數:

1.商戶appid是識別商戶的唯一ID,是讓支付寶識別,我們到底是哪一個商戶,這樣支付寶就能識別商戶對應的賬號、用戶號、收款賬號...等等一系列信息。

2.商戶公鑰、私鑰以及支付寶公鑰這3個參數是對商戶系統與支付寶進行信息交互的數字簽名用的,相信各位大學里也有學過關于數字簽名的一些知識,在這里,我就簡單說一下我理解的過程:首先是商戶系統需要給支付寶發送信息(支付、查詢等等....),涉及錢方面,咱們當前要謹慎一點對吧,所以我們需要對發送之前的信息加把鎖(用商戶私鑰進行簽名),然后再發送給支付寶。支付寶收到商戶發送的信息之后,發現上了把鎖,那肯定得要一把鑰匙(商戶公鑰)來解鎖對吧,所以商戶在跟支付寶簽約APP支付功能的時候,就得把這把鑰匙上傳給支付寶了,支付寶就可以用商戶的公鑰進行解鎖了。反過來也是一樣,支付寶需要發送信息給商戶信息,先用支付寶的私鑰進行簽名,再發送給商戶系統,商戶系統收到支付寶反饋過來的信息后,再用支付寶的公鑰進行解密。在這里我們并沒有用到支付寶的私鑰,所以我們并不需要得到支付寶的私鑰。這里放一個生成私鑰公鑰的支付寶官方工具

3.支付寶網關地址,是用來配置發送給支付寶的網關地址的。

2.將支付寶的SDK集成到項目系統里

支付寶的SDK指的就是支付寶提供的工具Jar包給我們開發者,SDK封裝了大量的基礎功能,使我們可以快速開發支付寶接口。這也是我在前面說的比微信支付接口更容易實現的原因。獲取支付寶SDK地址:支付寶SDK下載地址,這里我選擇JAVA的SDK。下載解壓后的SDK得到:

java后臺實現支付寶支付接口和支付寶訂單查詢接口(前端為APP)

alipay-sdk-java20180122110032.jar、commons-logging-1.1.1.jar是我們需要導入到項目里的,因為項目后臺的大致的架構是maven+springBoot+jpa,所以我們需要從maven里導入jar包,首先是導入commons-logging-1.1.1.jar,不用多說,咱直接在pom.xml里加上:

<dependency>
  <groupId>commons-logging</groupId>
  <artifactId>commons-logging</artifactId>
  <version>1.1.1</version>
</dependency>

然后是alipay-sdk-java20180122110032.jar,如果你也像上面一樣直接加入到pom.xml,會發現,咦,怎么一直下載不下來。當然alipy的包在線上的maven倉庫并沒有,所以我們需要導入到本地的maven倉庫。前提是配置好maven的環境變量,將包放在G:\alipay\sdk下,然后打開dos窗口,cd進入到G:\alipay\sdk下,執行maven如下命令:

 mvn install:install-file -DgroupId=com.alipay -DartifactId=sdk-java -Dversion=20180122110032 -Dpackaging=jar -Dfile=alipay-sdk-java20180122110032.jar

導入成功后,在項目的pom.xml里繼續添加

<!-- 支付寶SDK -->
<dependency>
  <groupId>com.alipay</groupId>
  <artifactId>sdk-java</artifactId>
  <version>20180122110032</version>
</dependency>

到此,我們就順利把支付寶SDK集成到項目里,是不是有點小興奮,我們很快可以開發了!

3.看支付寶提供的API和網上各位牛人總結的經驗,后臺使用支付寶的SDK與支付寶進行交互

先看一下支付寶支付流程的圖:

java后臺實現支付寶支付接口和支付寶訂單查詢接口(前端為APP)

首先,我們來理一理開發的思路,按照我當前項目的需求,關于支付這一塊大概操作流程是:用戶在APP上選好要購買的商品,點擊“立即購買”,跳轉到訂單詳細頁面。選擇支付方式,點擊“確定支付”跳轉到支付寶APP,付款完成后,跳轉回APP,完成支付。這個過程,當用戶點擊“確定支付”時,APP需要調用商戶后臺接口。

這時候就是我們所需要做的事情:先是生成商戶系統一筆未支付的訂單,獲得商戶訂單ID(商戶系統生成)和訂單的一些其他信息,然后再調用支付寶的SDK提供的數字簽名方法,將需要傳給支付寶的信息進行加簽,然后把加簽后的字符串返回給APP。APP拉起支付寶APP,再把這個加簽的字符串傳給支付寶,完成支付。APP接收到同步通知后,還需要再次調用商戶后臺的接口(雖然同步通知也有付款情況,但需要以后臺通知為準),校驗訂單最終的付款情況。按照支付寶API上所說,當完成支付后,支付寶會做2個操作,一個是同步返回信息給APP,一個是異步通知商戶后臺返回支付狀態等信息,并且最終的支付結果是以異步通知為準。所以我們還需要考慮到一點,就是當用戶支付成功之后,商戶系統暫時沒有接收到支付寶的異步通知時。我們需要拿著這個商戶訂單ID主動調用SDK支付寶的查詢接口,去獲取該訂單的支付情況,并最終返回給APP。這個查詢的接口應該是給APP收到同步通知后,請求商戶系統后臺進行校驗的時候調用的。

根據我們上面思考所得,后臺只需要對外提供3個接口即可

1.用戶點擊“立即購買”時調用商戶后臺接口,后臺返回加簽后的訂單信息字符串

2.在支付完成之后,支付寶異步通知商戶后臺訂單的付款情況

3.在支付完成之后,跳轉回APP時,APP調用商戶后臺進行最終付款校驗

想通想明白之后,終于接一下我們要敲代碼了,哈哈哈哈

首先,我們來準備一下需要傳給支付寶SDK的公共基本參數,我把參數放到一個單獨的類里,你也可以放到數據庫里,代碼如下:

public class AlipayConfig {
  // 1.商戶appid
  //public static String APPID = "2017...";  
  
  //2.私鑰 pkcs8格式的
  public static String RSA_PRIVATE_KEY ="MIIEwAIBADANBg.....";
  
  // 3.支付寶公鑰
  public static String ALIPAY_PUBLIC_KEY = "MIIBIjANBgkq.....";
  
  // 4.服務器異步通知頁面路徑 需http://或者https://格式的完整路徑,不能加?id=123這類自定義參數,必須外網可以正常訪問
  public static String notify_url = "http://www.xxx.com/alipay/notify_url.do";
  
   //5.頁面跳轉同步通知頁面路徑 需http://或者https://格式的完整路徑,不能加?id=123這類自定義參數,必須外網可以正常訪問 商戶可以自定義同步跳轉地址
  public static String return_url = "http://www.xxx.com/alipay/return_url.do";
  
  // 6.請求支付寶的網關地址
  public static String URL = "https://openapi.alipay.com/gateway.do";  
  
  // 7.編碼
  public static String CHARSET = "UTF-8";
  
  // 8.返回格式
  public static String FORMAT = "json";
  
  // 9.加密類型
  public static String SIGNTYPE = "RSA2";
  
}

1.實現第一個接口:用戶點擊“立即購買”時調用商戶后臺接口,后臺返回加簽后的訂單信息字符串。我把主要的處理邏輯寫在Service層了,Controller層直接調用就可以,這里就不放Controller層的代碼了

生成商戶訂單的代碼,我就不放了,這個根據各自的業務需求來做,生成后訂單之后,把訂單信息傳進來該方法進行處理,返回加簽后的字符串,直接返回給APP即可,代碼如下:

/**
 * 獲取支付寶加簽后臺的訂單信息字符串
 * 
 * @param request
 * @return
 */
 @Override
 @Transactional(propagation = Propagation.REQUIRED)
 public String getAliPayOrderStr(OrderTest orderTest) {
 
 //最終返回加簽之后的,app需要傳給支付寶app的訂單信息字符串 
 String orderString = "";
 logger.info("==================支付寶下單,商戶訂單號為:"+orderTest.getOutTradeNo());
 
 //創建商戶支付寶訂單(因為需要記錄每次支付寶支付的記錄信息,單獨存一個表跟商戶訂單表關聯,以便以后查證)
 AlipaymentOrder alipaymentOrder=new AlipaymentOrder();
 alipaymentOrder.setClubOrderId(orderTest.getId().toString());//商家訂單主鍵
 alipaymentOrder.setOutTradeNo(orderTest.getOutTradeNo());//商戶訂單號
 alipaymentOrder.setTradeStatus((byte) 0);//交易狀態
 alipaymentOrder.setTotalAmount(Double.parseDouble(orderTest.getTotalAmount()));//訂單金額
 alipaymentOrder.setReceiptAmount(0.00);//實收金額
 alipaymentOrder.setInvoiceAmount(0.00);//開票金額
 alipaymentOrder.setBuyerPayAmount(0.00);//付款金額
 alipaymentOrder.setRefundFee(0.00); //總退款金額
  
 try{ 
 //實例化客戶端(參數:網關地址、商戶appid、商戶私鑰、格式、編碼、支付寶公鑰、加密類型),為了取得預付訂單信息
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, 
         AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, 
         AlipayConfig.ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE);
    
        //實例化具體API對應的request類,類名稱和接口名稱對應,當前調用接口名稱:alipay.trade.app.pay 
        AlipayTradeAppPayRequest ali_request = new AlipayTradeAppPayRequest();
    
        //SDK已經封裝掉了公共參數,這里只需要傳入業務參數。以下方法為sdk的model入參方式
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
    
        //業務參數傳入,可以傳很多,參考API
        //model.setPassbackParams(URLEncoder.encode(request.getBody().toString())); //公用參數(附加數據)
        model.setBody(orderTest.getBody());            //對一筆交易的具體描述信息。如果是多種商品,請將商品描述字符串累加傳給body。
        model.setSubject(orderTest.getSubjecy());         //商品名稱
        model.setOutTradeNo(orderTest.getOutTradeNo());      //商戶訂單號(自動生成)
        // model.setTimeoutExpress("30m");     //交易超時時間
        model.setTotalAmount(orderTest.getTotalAmount());     //支付金額
        model.setProductCode("QUICK_MSECURITY_PAY");      //銷售產品碼(固定值)
        ali_request.setBizModel(model); 
        logger.info("====================異步通知的地址為:"+alipayment.getNotifyUrl());
        ali_request.setNotifyUrl(AlipayConfig.notify_url);    //異步回調地址(后臺)
        ali_request.setReturnUrl(AlipayConfig.return_url);   //同步回調地址(APP)
    
        // 這里和普通的接口調用不同,使用的是sdkExecute
 AlipayTradeAppPayResponse alipayTradeAppPayResponse = alipayClient.sdkExecute(ali_request); //返回支付寶訂單信息(預處理)
 orderString=alipayTradeAppPayResponse.getBody();//就是orderString 可以直接給APP請求,無需再做處理。
 this.createAlipayMentOrder(alipaymentOrder);//創建新的商戶支付寶訂單
 
 } catch (AlipayApiException e) {
  e.printStackTrace();
  logger.info("與支付寶交互出錯,未能生成訂單,請檢查代碼!");
 } 
 
    return orderString;
 }

2.實現第二個接口:在支付完成之后,支付寶異步通知商戶后臺訂單的付款情況,這個是支付寶每隔一段時間來訪問一次的接口,直到你返回success,才會停止訪問,這里我分了2個地方進行調用

/**
 * 支付寶支付成功后.異步請求該接口
 * @param request
 * @return
 * @throws IOException
 */ 
 @RequestMapping(value="/notify_url",method=RequestMethod.POST)
 @ResponseBody
 public String notify(HttpServletRequest request,HttpServletResponse response) throws IOException { 
 logger.info("==================支付寶異步返回支付結果開始");
 //1.從支付寶回調的request域中取值 
 //獲取支付寶返回的參數集合
    Map<String, String[]> aliParams = request.getParameterMap(); 
    //用以存放轉化后的參數集合
    Map<String, String> conversionParams = new HashMap<String, String>(); 
   for (Iterator<String> iter = aliParams.keySet().iterator(); iter.hasNext();) { 
     String key = iter.next(); 
     String[] values = aliParams.get(key); 
     String valueStr = ""; 
     for (int i = 0; i < values.length; i++) { 
       valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ","; 
     } 
     // 亂碼解決,這段代碼在出現亂碼時使用。如果mysign和sign不相等也可以使用這段代碼轉化 
     // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "uft-8"); 
     conversionParams.put(key, valueStr); 
   }  
   logger.info("==================返回參數集合:"+conversionParams);
  String status=alipayMentOrderService.notify(conversionParams);
  return status;
 }
 /**
 * 支付寶異步請求邏輯處理
 * @param request
 * @return
 * @throws IOException
 */ 
 public String notify(Map<String, String> conversionParams){
 
 logger.info("==================支付寶異步請求邏輯處理");
  
  //簽名驗證(對支付寶返回的數據驗證,確定是支付寶返回的)
   boolean signVerified = false;  
   
   try { 
     //調用SDK驗證簽名
     signVerified = AlipaySignature.rsaCheckV1(conversionParams, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, AlipayConfig.SIGNTYPE); 
     
   } catch (AlipayApiException e) { 
   logger.info("==================驗簽失敗 !"); 
     e.printStackTrace();     
   }  
   
   //對驗簽進行處理
   if (signVerified) {
   //驗簽通過    
   //獲取需要保存的數據
     String appId=conversionParams.get("app_id");//支付寶分配給開發者的應用Id
   String notifyTime=conversionParams.get("notify_time");//通知時間:yyyy-MM-dd HH:mm:ss
   String gmtCreate=conversionParams.get("gmt_create");//交易創建時間:yyyy-MM-dd HH:mm:ss
   String gmtPayment=conversionParams.get("gmt_payment");//交易付款時間
   String gmtRefund=conversionParams.get("gmt_refund");//交易退款時間
   String gmtClose=conversionParams.get("gmt_close");//交易結束時間
   String tradeNo=conversionParams.get("trade_no");//支付寶的交易號
   String outTradeNo = conversionParams.get("out_trade_no");//獲取商戶之前傳給支付寶的訂單號(商戶系統的唯一訂單號)
   String outBizNo=conversionParams.get("out_biz_no");//商戶業務號(商戶業務ID,主要是退款通知中返回退款申請的流水號)
   String buyerLogonId=conversionParams.get("buyer_logon_id");//買家支付寶賬號
   String sellerId=conversionParams.get("seller_id");//賣家支付寶用戶號
   String sellerEmail=conversionParams.get("seller_email");//賣家支付寶賬號
   String totalAmount=conversionParams.get("total_amount");//訂單金額:本次交易支付的訂單金額,單位為人民幣(元)
   String receiptAmount=conversionParams.get("receipt_amount");//實收金額:商家在交易中實際收到的款項,單位為元
   String invoiceAmount=conversionParams.get("invoice_amount");//開票金額:用戶在交易中支付的可開發票的金額
   String buyerPayAmount=conversionParams.get("buyer_pay_amount");//付款金額:用戶在交易中支付的金額  
   String tradeStatus = conversionParams.get("trade_status");// 獲取交易狀態 
   
   //支付寶官方建議校驗的值(out_trade_no、total_amount、sellerId、app_id)
   AlipaymentOrder alipaymentOrder=this.selectByOutTradeNo(outTradeNo); 
  
   if(alipaymentOrder!=null&&totalAmount.equals(alipaymentOrder.getTotalAmount().toString())&&AlipayConfig.APPID.equals(appId)){
    //修改數據庫支付寶訂單表(因為要保存每次支付寶返回的信息到數據庫里,以便以后查證)
    alipaymentOrder.setNotifyTime(dateFormat(notifyTime));
    alipaymentOrder.setGmtCreate(dateFormat(gmtCreate));
    alipaymentOrder.setGmtPayment(dateFormat(gmtPayment));
    alipaymentOrder.setGmtRefund(dateFormat(gmtRefund));
    alipaymentOrder.setGmtClose(dateFormat(gmtClose));
    alipaymentOrder.setTradeNo(tradeNo);
    alipaymentOrder.setOutBizNo(outBizNo);
    alipaymentOrder.setBuyerLogonId(buyerLogonId);
    alipaymentOrder.setSellerId(sellerId);
    alipaymentOrder.setSellerEmail(sellerEmail);
    alipaymentOrder.setTotalAmount(Double.parseDouble(totalAmount));
    alipaymentOrder.setReceiptAmount(Double.parseDouble(receiptAmount));
    alipaymentOrder.setInvoiceAmount(Double.parseDouble(invoiceAmount));
    alipaymentOrder.setBuyerPayAmount(Double.parseDouble(buyerPayAmount));
    switch (tradeStatus) // 判斷交易結果
           {
           case "TRADE_FINISHED": // 交易結束并不可退款
           alipaymentOrder.setTradeStatus((byte) 3);
             break;
           case "TRADE_SUCCESS": // 交易支付成功
           alipaymentOrder.setTradeStatus((byte) 2);        
             break;
           case "TRADE_CLOSED": // 未付款交易超時關閉或支付完成后全額退款
           alipaymentOrder.setTradeStatus((byte) 1);
             break;
           case "WAIT_BUYER_PAY": // 交易創建并等待買家付款
           alipaymentOrder.setTradeStatus((byte) 0);
             break;
           default:
             break;
           }
    int returnResult=this.updateByPrimaryKey(alipaymentOrder);  //更新交易表中狀態
          
     if(tradeStatus.equals("TRADE_SUCCESS")) {  //只處理支付成功的訂單: 修改交易表狀態,支付成功
      
       if(returnResult>0){
          return "success";
       }else{
          return "fail";
       }
     }else{
       return "fail";
     }
    
   }else{
    logger.info("==================支付寶官方建議校驗的值(out_trade_no、total_amount、sellerId、app_id),不一致!返回fail");
    return"fail";
   }
 
   } else { //驗簽不通過  
   logger.info("==================驗簽不通過 !");
     return "fail";
   }
 
 }

3.實現第三個接口:在支付完成之后,跳轉回APP時,APP調用商戶后臺進行最終付款校驗。我把主要的處理邏輯寫在Service層了,Controller層直接調用就可以,這里就不放Controller層的代碼了。

/**
 * 向支付寶發起訂單查詢請求
 * @param request
 * @return
 * @throws IOException
 */ 
 @Override
 public Byte checkAlipay(String outTradeNo) {
 logger.info("==================向支付寶發起查詢,查詢商戶訂單號為:"+outTradeNo);
 
 try {
 //實例化客戶端(參數:網關地址、商戶appid、商戶私鑰、格式、編碼、支付寶公鑰、加密類型)
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, 
     AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, 
     AlipayConfig.ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE);
 AlipayTradeQueryRequest alipayTradeQueryRequest = new AlipayTradeQueryRequest();
 alipayTradeQueryRequest.setBizContent("{" +
 "\"out_trade_no\":\""+outTradeNo+"\"" +
 "}");
 AlipayTradeQueryResponse alipayTradeQueryResponse = alipayClient.execute(alipayTradeQueryRequest); 
 if(alipayTradeQueryResponse.isSuccess()){
  
   AlipaymentOrder alipaymentOrder=this.selectByOutTradeNo(outTradeNo);
   //修改數據庫支付寶訂單表
   alipaymentOrder.setTradeNo(alipayTradeQueryResponse.getTradeNo());
   alipaymentOrder.setBuyerLogonId(alipayTradeQueryResponse.getBuyerLogonId());
   alipaymentOrder.setTotalAmount(Double.parseDouble(alipayTradeQueryResponse.getTotalAmount()));
   alipaymentOrder.setReceiptAmount(Double.parseDouble(alipayTradeQueryResponse.getReceiptAmount()));
   alipaymentOrder.setInvoiceAmount(Double.parseDouble(alipayTradeQueryResponse.getInvoiceAmount()));
   alipaymentOrder.setBuyerPayAmount(Double.parseDouble(alipayTradeQueryResponse.getBuyerPayAmount()));
   switch (alipayTradeQueryResponse.getTradeStatus()) // 判斷交易結果
          {
          case "TRADE_FINISHED": // 交易結束并不可退款
           alipaymentOrder.setTradeStatus((byte) 3);
            break;
          case "TRADE_SUCCESS": // 交易支付成功
           alipaymentOrder.setTradeStatus((byte) 2);      
            break;
          case "TRADE_CLOSED": // 未付款交易超時關閉或支付完成后全額退款
           alipaymentOrder.setTradeStatus((byte) 1);      
            break;
          case "WAIT_BUYER_PAY": // 交易創建并等待買家付款
           alipaymentOrder.setTradeStatus((byte) 0);
            break;
          default:
            break;
          }
   this.updateByPrimaryKey(alipaymentOrder); //更新表記錄
   return alipaymentOrder.getTradeStatus();
 } else {
  logger.info("==================調用支付寶查詢接口失敗!");
 }
 } catch (AlipayApiException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
 }
 return 0;
 }

至此,代碼已經上完了,里面可能涉及部分業務代碼,如果各位需要拿代碼,需要把業務代碼換成自己所需要的。

建議:可以邊看API邊進行開發,主要是看我們需要給支付傳什么參數,支付寶可以給我們傳什么參數,不然沒看清除,你會多很多坑要踩的,親試過。

感覺太少圖片了,這里給幾張API的圖片。。你們也可以自己去看 一些支付寶API

java后臺實現支付寶支付接口和支付寶訂單查詢接口(前端為APP)

4.關于測試的一些事

支付寶有提供沙箱環境進行測試所使用,見支付寶沙箱調試指南。

但是樓主比較有米,直接用真實環境進行測試,其實測一次0.01元也是挺貴的吧,前提是你的電腦必須訪問外網和能夠被外網所訪問,建議可以找個內網穿透的工具。

寫了一整個下午,好累啊,本人新手,如有錯誤,請各位大神指教,希望對大家有用!!!!也希望大家多多支持億速云。

向AI問一下細節

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

AI

沽源县| 兴城市| 循化| 彭水| 合山市| 翼城县| 南岸区| 泸水县| 阿荣旗| 三河市| 洪洞县| 昂仁县| 桂东县| 克什克腾旗| 福安市| 宣城市| 泸西县| 济宁市| 泗阳县| 黄梅县| 隆子县| 晋城| 门头沟区| 武清区| 柘城县| 峨眉山市| 新泰市| 甘孜| 金沙县| 徐州市| 杭州市| 凤翔县| 铜梁县| 大化| 定襄县| 沁源县| 镇原县| 延安市| 孙吴县| 万源市| 兴国县|