国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

微信公眾帳號開發-自定義菜單的創建及菜單事件響應的實例

2019-11-26 13:22:03
字體:
來源:轉載
供稿:網友

微信開發公眾平臺自定義菜單需要花錢認證才能實現,不想花錢只能玩測試賬號了,不過這并不影響開發。我的開發都是基于柳峰老師的微信公眾平臺應用開發做的。

只要我們使用公眾平臺測試賬號就可以開發自定義菜單了,比較方便,測試賬號開放了很多接口,很方便。

在開發自定義菜單的時候可以參考微信公眾平臺開發者文檔的自定義菜單創建。

一、自定義菜單

1、自定義菜單最多包括3個一級菜單,每個一級菜單最多包含5個二級菜單。

2、一級菜單最多4個漢字,二級菜單最多7個漢字,多出來的部分將會以“...”代替。

3、創建自定義菜單后,菜單的刷新策略是,在用戶進入公眾號會話頁或公眾號profile頁時,如果發現上一次拉取菜單的請求在5分鐘以前,就會拉取一下菜單,如果菜單有更新,就會刷新客戶端的菜單。測試時可以嘗試取消關注公眾賬號后再次關注,則

可以看到創建后的效果。

自定義菜單接口可實現多種類型按鈕,如下:

1、click:點擊推事件

用戶點擊click類型按鈕后,微信服務器會通過消息接口推送消息類型為event 的結構給開發者(參考消息接口指南),并且帶上按鈕中開發者填寫的key值,開發者可以通過自定義的key值與用戶進行交互;

2、view:跳轉URL

用戶點擊view類型按鈕后,微信客戶端將會打開開發者在按鈕中填寫的網頁URL,可與網頁授權獲取用戶基本信息接口結合,獲得用戶基本信息。

3、scancode_push:掃碼推事件

用戶點擊按鈕后,微信客戶端將調起掃一掃工具,完成掃碼操作后顯示掃描結果(如果是URL,將進入URL),且會將掃碼的結果傳給開發者,開發者可以下發消息。

4、scancode_waitmsg:掃碼推事件且彈出“消息接收中”提示框

用戶點擊按鈕后,微信客戶端將調起掃一掃工具,完成掃碼操作后,將掃碼的結果傳給開發者,同時收起掃一掃工具,然后彈出“消息接收中”提示框,隨后可能會收到開發者下發的消息。

5、pic_sysphoto:彈出系統拍照發圖

用戶點擊按鈕后,微信客戶端將調起系統相機,完成拍照操作后,會將拍攝的相片發送給開發者,并推送事件給開發者,同時收起系統相機,隨后可能會收到開發者下發的消息。

6、pic_photo_or_album:彈出拍照或者相冊發圖

用戶點擊按鈕后,微信客戶端將彈出選擇器供用戶選擇“拍照”或者“從手機相冊選擇”。用戶選擇后即走其他兩種流程。

7、pic_weixin:彈出微信相冊發圖器

用戶點擊按鈕后,微信客戶端將調起微信相冊,完成選擇操作后,將選擇的相片發送給開發者的服務器,并推送事件給開發者,同時收起相冊,隨后可能會收到開發者下發的消息。

8、location_select:彈出地理位置選擇器

用戶點擊按鈕后,微信客戶端將調起地理位置選擇工具,完成選擇操作后,將選擇的地理位置發送給開發者的服務器,同時收起位置選擇工具,隨后可能會收到開發者下發的消息。

9、media_id:下發消息(除文本消息)

用戶點擊media_id類型按鈕后,微信服務器會將開發者填寫的永久素材id對應的素材下發給用戶,永久素材類型可以是圖片、音頻、視頻、圖文消息。請注意:永久素材id必須是在“素材管理/新增永久素材”接口上傳后獲得的合法id。

10、view_limited:跳轉圖文消息URL

用戶點擊view_limited類型按鈕后,微信客戶端將打開開發者在按鈕中填寫的永久素材id對應的圖文消息URL,永久素材類型只支持圖文消息。請注意:永久素材id必須是在“素材管理/新增永久素材”接口上傳后獲得的合法id

二、訪問自定義菜單接口

1:獲取access_token

自定義菜單的創建、查詢和刪除需要調用公眾平臺開放的自定義菜單接口,而調用該接口需要先獲取access_token(接口訪問憑證),這些接口全都是基于https協議的,因此我們先要解決如何在Java程序中發送https請求的問題。

獲取接口訪問憑證access_token:

獲取access_token是通過GET方式訪問如下鏈接:
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

鏈接中有三個參數,分別是grant_type、appid和secret。根據圖中的參數說明,grant_type傳固定值client_credential,而appid和secret就是申請完自定義菜單后微信分配給我們的。
請求發送成功后,微信服務器會返回一個json串,包含access_token和expires_in兩個元素。其中,access_token就是我們最終需要的憑證,而expires_in是憑證的有效期,單位是秒,7200秒也就是2個小時。這就意味著,不是每次訪問特殊接口,都需要重新獲取一次access_token,只要access_token還在有效期內,就一直可以使用。

2:菜單創建

創建菜單要調用菜單接口

接口調用請求說明

http請求方式:POST(請使用https協議) https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN

其實就是向地址https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN以POST方式提交一個JSON格式的菜單字符串。

三、封裝通用請求方法(自定義信任管理器)

創建菜單需要兩個接口,一個是獲取access_token接口,一個是自定義菜單接口,都是https請求。

1:創建證書信任管理器

對于https請求,我們需要一個證書信任管理器,這個管理器類需要自己定義,但需要實現X509TrustManager接口,代碼如下:

package org.liufeng.weixin.util;  import java.security.cert.CertificateException; import java.security.cert.X509Certificate;  import javax.net.ssl.X509TrustManager;  /**  * 證書信任管理器(用于https請求)  *  * @author liufeng  * @date 2013-08-08  */ public class MyX509TrustManager implements X509TrustManager {   public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {  }   public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {  }   public X509Certificate[] getAcceptedIssuers() {   return null;  } } 

證書管理器的作用就是信任指定所有證書。

2:創建通用https請求

通用https請求應該

1)支持HTTPS請求;

2)支持GET、POST兩種方式;

3)支持參數提交,也支持無參數的情況;

package org.liufeng.weixin.util;  import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.ConnectException; import java.net.URL;  import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager;  import net.sf.json.JSONObject;  import org.slf4j.Logger; import org.slf4j.LoggerFactory;  /**  * 公眾平臺通用接口工具類  *  * @author liuyq  * @date 2013-08-09  */ public class WeixinUtil {  private static Logger log = LoggerFactory.getLogger(WeixinUtil.class);   /**   * 發起https請求并獲取結果   *   * @param requestUrl 請求地址   * @param requestMethod 請求方式(GET、POST)   * @param outputStr 提交的數據   * @return JSONObject(通過JSONObject.get(key)的方式獲取json對象的屬性值)   */  public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {   JSONObject jsonObject = null;   StringBuffer buffer = new StringBuffer();   try {    // 創建SSLContext對象,并使用我們指定的信任管理器初始化    TrustManager[] tm = { new MyX509TrustManager() };    SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");    sslContext.init(null, tm, new java.security.SecureRandom());    // 從上述SSLContext對象中得到SSLSocketFactory對象    SSLSocketFactory ssf = sslContext.getSocketFactory();     URL url = new URL(requestUrl);    HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();    httpUrlConn.setSSLSocketFactory(ssf);     httpUrlConn.setDoOutput(true);    httpUrlConn.setDoInput(true);    httpUrlConn.setUseCaches(false);    // 設置請求方式(GET/POST)    httpUrlConn.setRequestMethod(requestMethod);     if ("GET".equalsIgnoreCase(requestMethod))     httpUrlConn.connect();     // 當有數據需要提交時    if (null != outputStr) {     OutputStream outputStream = httpUrlConn.getOutputStream();     // 注意編碼格式,防止中文亂碼     outputStream.write(outputStr.getBytes("UTF-8"));     outputStream.close();    }     // 將返回的輸入流轉換成字符串    InputStream inputStream = httpUrlConn.getInputStream();    InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");    BufferedReader bufferedReader = new BufferedReader(inputStreamReader);     String str = null;    while ((str = bufferedReader.readLine()) != null) {     buffer.append(str);    }    bufferedReader.close();    inputStreamReader.close();    // 釋放資源    inputStream.close();    inputStream = null;    httpUrlConn.disconnect();    jsonObject = JSONObject.fromObject(buffer.toString());   } catch (ConnectException ce) {    log.error("Weixin server connection timed out.");   } catch (Exception e) {    log.error("https request error:{}", e);   }   return jsonObject;  } } 

四、封裝菜單實體類

1:按鈕的分類

我們通常會把自定義菜單項看做是按鈕,按鈕的類型分成click(點擊事件)和view(訪問網頁)。

click類型的按鈕有type、name和key3個屬性,而view類型的按鈕有type、name和url3個屬性

2:首先是調用獲取憑證接口后,微信服務器會返回json格式的數據:{"access_token":"ACCESS_TOKEN","expires_in":7200},我們將其封裝為一個AccessToken對象,對象有二個屬性:token和expiresIn,代碼如下:

package org.liufeng.weixin.pojo;  /**  * 微信通用接口憑證  *  * @author liufeng  * @date 2013-08-08  */ public class AccessToken {  // 獲取到的憑證  private String token;  // 憑證有效時間,單位:秒  private int expiresIn;   public String getToken() {   return token;  }   public void setToken(String token) {   this.token = token;  }   public int getExpiresIn() {   return expiresIn;  }   public void setExpiresIn(int expiresIn) {   this.expiresIn = expiresIn;  } } 

接下來是對菜單結構的封裝。因為我們是采用面向對象的編程方式,最終提交的json格式菜單數據就應該是由對象直接轉換得到,而不是在程序代碼中拼一大堆json數據。菜單結構封裝的依據是公眾平臺API文檔中給出的那一段json格式的菜單結構,如下所示:

click和view的請求示例

{  "button":[  {    "type":"click",   "name":"今日歌曲",   "key":"V1001_TODAY_MUSIC"  },  {   "name":"菜單",   "sub_button":[   {     "type":"view",    "name":"搜索",    "url":"http://www.soso.com/"   },   {    "type":"view",    "name":"視頻",    "url":"http://v.qq.com/"   },   {    "type":"click",    "name":"贊一下我們",    "key":"V1001_GOOD"   }]  }] }

3:封裝菜單結構

每個按鈕對象都要一個共同的name屬性,因此需要定義一個按鈕對象基類,所有的按鈕對象都需要繼承該類。基類的代碼如下:

package org.liufeng.weixin.pojo;  /**  * 按鈕的基類  *  * @author liufeng  * @date 2013-08-08  */ public class Button {  private String name;   public String getName() {   return name;  }   public void setName(String name) {   this.name = name;  } } 

接著是子菜單項的封裝。這里對子菜單是這樣定義的:沒有子菜單的菜單項,有可能是二級菜單項,也有可能是不含二級菜單的一級菜單。這類子菜單項一定會包含三個屬性:type、name和key,封裝的代碼如下:

package org.liufeng.weixin.pojo;  /**  * 普通按鈕(子按鈕)  *  * @author liufeng  * @date 2013-08-08  */ public class CommonButton extends Button {  private String type;  private String key;   public String getType() {   return type;  }   public void setType(String type) {   this.type = type;  }   public String getKey() {   return key;  }   public void setKey(String key) {   this.key = key;  } } 

對父菜單項的定義:包含有二級菜單項的一級菜單。這類菜單項包含有二個屬性:name和sub_button,而sub_button以是一個子菜單項數組。父菜單項的封裝代碼如下:

package org.liufeng.weixin.pojo;  /**  * 復雜按鈕(父按鈕)  *  * @author liufeng  * @date 2013-08-08  */ public class ComplexButton extends Button {  private Button[] sub_button;   public Button[] getSub_button() {   return sub_button;  }   public void setSub_button(Button[] sub_button) {   this.sub_button = sub_button;  } } 

對整個菜單進行封裝,菜單對象包含多個菜單項(最多只能有3個),這些菜單項即可以是子菜單項(不含二級菜單的一級菜單),也可以是父菜單項(包含二級菜單的菜單項)

package org.liufeng.weixin.pojo;  /**  * 菜單  *  * @author liufeng  * @date 2013-08-08  */ public class Menu {  private Button[] button;   public Button[] getButton() {   return button;  }   public void setButton(Button[] button) {   this.button = button;  } } 

這樣我們就完成了菜單實體類的封裝。

憑證access_token的獲取方法

繼續在先前通用請求方法的類WeixinUtil.java中加入以下代碼,用于獲取接口訪問憑證:

// 獲取access_token的接口地址(GET) 限200(次/天) public final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";  /**  * 獲取access_token  *  * @param appid 憑證  * @param appsecret 密鑰  * @return  */ public static AccessToken getAccessToken(String appid, String appsecret) {  AccessToken accessToken = null;   String requestUrl = access_token_url.replace("APPID", appid).replace("APPSECRET", appsecret);  JSONObject jsonObject = httpRequest(requestUrl, "GET", null);  // 如果請求成功  if (null != jsonObject) {   try {    accessToken = new AccessToken();    accessToken.setToken(jsonObject.getString("access_token"));    accessToken.setExpiresIn(jsonObject.getInt("expires_in"));   } catch (JSONException e) {    accessToken = null;    // 獲取token失敗    log.error("獲取token失敗 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));   }  }  return accessToken; } 

自定義菜單的創建方法

繼續在先前通用請求方法的類WeixinUtil.java中加入以下代碼,用于創建自定義菜單:

// 菜單創建(POST) 限100(次/天) public static String menu_create_url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";  /**  * 創建菜單  *  * @param menu 菜單實例  * @param accessToken 有效的access_token  * @return 0表示成功,其他值表示失敗  */ public static int createMenu(Menu menu, String accessToken) {  int result = 0;   // 拼裝創建菜單的url  String url = menu_create_url.replace("ACCESS_TOKEN", accessToken);  // 將菜單對象轉換成json字符串  String jsonMenu = JSONObject.fromObject(menu).toString();  // 調用接口創建菜單  JSONObject jsonObject = httpRequest(url, "POST", jsonMenu);   if (null != jsonObject) {   if (0 != jsonObject.getInt("errcode")) {    result = jsonObject.getInt("errcode");    log.error("創建菜單失敗 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));   }  }   return result; } 

調用封裝的方法創建自定義菜單

package org.liufeng.weixin.main;  import org.liufeng.weixin.pojo.AccessToken; import org.liufeng.weixin.pojo.Button; import org.liufeng.weixin.pojo.CommonButton; import org.liufeng.weixin.pojo.ComplexButton; import org.liufeng.weixin.pojo.Menu; import org.liufeng.weixin.util.WeixinUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory;  /**  * 菜單管理器類  *  * @author liufeng  * @date 2013-08-08  */ public class MenuManager {  private static Logger log = LoggerFactory.getLogger(MenuManager.class);   public static void main(String[] args) {   // 第三方用戶唯一憑證   String appId = "000000000000000000";   // 第三方用戶唯一憑證密鑰   String appSecret = "00000000000000000000000000000000";    // 調用接口獲取access_token   AccessToken at = WeixinUtil.getAccessToken(appId, appSecret);    if (null != at) {    // 調用接口創建菜單    int result = WeixinUtil.createMenu(getMenu(), at.getToken());     // 判斷菜單創建結果    if (0 == result)     log.info("菜單創建成功!");    else     log.info("菜單創建失敗,錯誤碼:" + result);   }  }   /**   * 組裝菜單數據   *   * @return   */  private static Menu getMenu() {   CommonButton btn11 = new CommonButton();   btn11.setName("天氣預報");   btn11.setType("click");   btn11.setKey("11");    CommonButton btn12 = new CommonButton();   btn12.setName("公交查詢");   btn12.setType("click");   btn12.setKey("12");    CommonButton btn13 = new CommonButton();   btn13.setName("周邊搜索");   btn13.setType("click");   btn13.setKey("13");    CommonButton btn14 = new CommonButton();   btn14.setName("歷史上的今天");   btn14.setType("click");   btn14.setKey("14");    CommonButton btn21 = new CommonButton();   btn21.setName("歌曲點播");   btn21.setType("click");   btn21.setKey("21");    CommonButton btn22 = new CommonButton();   btn22.setName("經典游戲");   btn22.setType("click");   btn22.setKey("22");    CommonButton btn23 = new CommonButton();   btn23.setName("美女電臺");   btn23.setType("click");   btn23.setKey("23");    CommonButton btn24 = new CommonButton();   btn24.setName("人臉識別");   btn24.setType("click");   btn24.setKey("24");    CommonButton btn25 = new CommonButton();   btn25.setName("聊天嘮嗑");   btn25.setType("click");   btn25.setKey("25");    CommonButton btn31 = new CommonButton();   btn31.setName("Q友圈");   btn31.setType("click");   btn31.setKey("31");    CommonButton btn32 = new CommonButton();   btn32.setName("電影排行榜");   btn32.setType("click");   btn32.setKey("32");    CommonButton btn33 = new CommonButton();   btn33.setName("幽默笑話");   btn33.setType("click");   btn33.setKey("33");    ComplexButton mainBtn1 = new ComplexButton();   mainBtn1.setName("生活助手");   mainBtn1.setSub_button(new CommonButton[] { btn11, btn12, btn13, btn14 });    ComplexButton mainBtn2 = new ComplexButton();   mainBtn2.setName("休閑驛站");   mainBtn2.setSub_button(new CommonButton[] { btn21, btn22, btn23, btn24, btn25 });    ComplexButton mainBtn3 = new ComplexButton();   mainBtn3.setName("更多體驗");   mainBtn3.setSub_button(new CommonButton[] { btn31, btn32, btn33 });    /**    * 這是公眾號xiaoqrobot目前的菜單結構,每個一級菜單都有二級菜單項    *    * 在某個一級菜單下沒有二級菜單的情況,menu該如何定義呢?   * 比如,第三個一級菜單項不是“更多體驗”,而直接是“幽默笑話”,那么menu應該這樣定義:   * menu.setButton(new Button[] { mainBtn1, mainBtn2, btn33 });    */   Menu menu = new Menu();   menu.setButton(new Button[] { mainBtn1, mainBtn2, mainBtn3 });    return menu;  } } 

注意:在運行以上代碼時,需要將appId和appSecret換成你自己公眾號的。

響應菜單點擊事件

package org.liufeng.course.service;  import java.util.Date; import java.util.Map;  import javax.servlet.http.HttpServletRequest;  import org.liufeng.course.message.resp.TextMessage; import org.liufeng.course.util.MessageUtil;  /**  * 核心服務類  *  * @author liufeng  * @date 2013-05-20  */ public class CoreService {  /**   * 處理微信發來的請求   *   * @param request   * @return   */  public static String processRequest(HttpServletRequest request) {   String respMessage = null;   try {    // 默認返回的文本消息內容    String respContent = "請求處理異常,請稍候嘗試!";     // xml請求解析    Map<String, String> requestMap = MessageUtil.parseXml(request);     // 發送方帳號(open_id)    String fromUserName = requestMap.get("FromUserName");    // 公眾帳號    String toUserName = requestMap.get("ToUserName");    // 消息類型    String msgType = requestMap.get("MsgType");     // 回復文本消息    TextMessage textMessage = new TextMessage();    textMessage.setToUserName(fromUserName);    textMessage.setFromUserName(toUserName);    textMessage.setCreateTime(new Date().getTime());    textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);    textMessage.setFuncFlag(0);     // 文本消息    if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {     respContent = "您發送的是文本消息!";    }    // 圖片消息    else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)) {     respContent = "您發送的是圖片消息!";    }    // 地理位置消息    else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)) {     respContent = "您發送的是地理位置消息!";    }    // 鏈接消息    else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)) {     respContent = "您發送的是鏈接消息!";    }    // 音頻消息    else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)) {     respContent = "您發送的是音頻消息!";    }    // 事件推送    else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) {     // 事件類型     String eventType = requestMap.get("Event");     // 訂閱     if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) {      respContent = "謝謝您的關注!";     }     // 取消訂閱     else if (eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)) {      // TODO 取消訂閱后用戶再收不到公眾號發送的消息,因此不需要回復消息     }     // 自定義菜單點擊事件     else if (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)) {      // 事件KEY值,與創建自定義菜單時指定的KEY值對應      String eventKey = requestMap.get("EventKey");       if (eventKey.equals("11")) {       respContent = "天氣預報菜單項被點擊!";      } else if (eventKey.equals("12")) {       respContent = "公交查詢菜單項被點擊!";      } else if (eventKey.equals("13")) {       respContent = "周邊搜索菜單項被點擊!";      } else if (eventKey.equals("14")) {       respContent = "歷史上的今天菜單項被點擊!";      } else if (eventKey.equals("21")) {       respContent = "歌曲點播菜單項被點擊!";      } else if (eventKey.equals("22")) {       respContent = "經典游戲菜單項被點擊!";      } else if (eventKey.equals("23")) {       respContent = "美女電臺菜單項被點擊!";      } else if (eventKey.equals("24")) {       respContent = "人臉識別菜單項被點擊!";      } else if (eventKey.equals("25")) {       respContent = "聊天嘮嗑菜單項被點擊!";      } else if (eventKey.equals("31")) {       respContent = "Q友圈菜單項被點擊!";      } else if (eventKey.equals("32")) {       respContent = "電影排行榜菜單項被點擊!";      } else if (eventKey.equals("33")) {       respContent = "幽默笑話菜單項被點擊!";      }     }    }     textMessage.setContent(respContent);    respMessage = MessageUtil.textMessageToXml(textMessage);   } catch (Exception e) {    e.printStackTrace();   }    return respMessage;  } } 

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 衡阳县| 宜黄县| 新龙县| 三穗县| 米林县| 赣榆县| 镇雄县| 珠海市| 静海县| 长泰县| 景洪市| 大渡口区| 阿坝| 布尔津县| 清河县| 井陉县| 景泰县| 阿合奇县| 新密市| 阿瓦提县| 沈丘县| 石家庄市| 龙里县| 溆浦县| 延边| 连城县| 曲麻莱县| 冀州市| 桓仁| 中西区| 马龙县| 招远市| 克山县| 抚远县| 陇川县| 封丘县| 宜城市| 广东省| 东乡县| 万宁市| 虞城县|