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

SpringBoot(JAVA)整合微信公眾號(hào)消息推送完整步驟(文本、圖片/視頻推送)

 更新時(shí)間:2024年09月25日 10:03:28   作者:刻苦的劉同學(xué)  
微信公眾號(hào)消息推送包括文本推送和圖文/視頻推送兩類,文本推送通過模板消息或自定義消息實(shí)現(xiàn),而圖文/視頻推送需先上傳素材至臨時(shí)/永久素材庫(kù),再上傳圖文消息,最后進(jìn)行消息推送,文中將實(shí)現(xiàn)的方法介紹的非常詳細(xì),需要的朋友可以參考下

網(wǎng)上那些都是零零碎碎的,不完整,重新整理下,代碼可直接使用。微信公眾號(hào)消息推送大致分為兩類,一是文本推送,二是帶圖片/視頻推送

文本推送很好理解,可以用模板消息以及自定義消息推送。

圖文/視頻推送就稍微麻煩些步驟分為 上傳素材到臨時(shí)/永久庫(kù)->上傳圖文消息->消息推送。

貼幾個(gè)官方文檔,有總比沒有好。

群發(fā)推送官網(wǎng)文檔https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Batch_Sends_and_Originality_Checks.html

上傳素材官方文檔https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/New_temporary_materials.html

官方素材上傳調(diào)試平臺(tái)https://mp.weixin.qq.com/debug/cgi-bin/apiinfo?t=index&type=%E5%9F%BA%E7%A1%80%E6%94%AF%E6%8C%81&form=%E5%A4%9A%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0%E6%8E%A5%E5%8F%A3%20/media/upload

一、文本推送

這里文本推送,可以采取模板和自定義推送內(nèi)容。以下是模板方式推送,在圖片/視頻推送中會(huì)使用自定義內(nèi)容推送演示。

首先需要在微信公眾號(hào)上把測(cè)試的環(huán)境弄好。

點(diǎn)擊開發(fā)者工具->公眾平臺(tái)測(cè)試賬號(hào)。進(jìn)去創(chuàng)建好對(duì)應(yīng)的消息模板以及關(guān)注該測(cè)試的公眾號(hào)。里面會(huì)有appID/appsecret,用戶,模板以及能體驗(yàn)接口的信息,沒有認(rèn)證的微信號(hào),有些接口是沒有權(quán)限的,而且部分接口在沒有認(rèn)證的情況下每天都會(huì)有調(diào)用次數(shù)限制。

添加依賴,因?yàn)轫?xiàng)目里面用了自己的http封裝類,需替換下

	<dependency>
	    <groupId>com.squareup.okhttp3</groupId>
	    <artifactId>okhttp</artifactId>
	    <version>5.0.0-alpha.14</version>
	</dependency>
	<dependency>
	    <groupId>com.squareup.okio</groupId>
	    <artifactId>okio</artifactId>
	    <version>3.6.0</version>
	</dependency>

WxToken

用于生成請(qǐng)求接口token

/**
 * 存儲(chǔ)微信公眾號(hào)Token的POJO類
 *
 * @author zjw
 * @description
 */
public class WxToken {

    // 存儲(chǔ)token信息
    private String accessToken;

    // 10:00:00
    // 12:00:00
    // 存儲(chǔ)當(dāng)前的token有效期到什么時(shí)間點(diǎn)
    private Long expire;

    public String getAccessToken() {
        // 獲取token之前,需要先判斷生存時(shí)間到了沒
        return expire == null || expire < (System.currentTimeMillis() / 1000) ? null : this.accessToken;
    }

    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }

    public Long getExpire() {
        return expire;
    }

    public void setExpire(Long expire) {
        this.expire = System.currentTimeMillis() / 1000 + expire;
    }
}

WxMagPushReq

這里要注意下模板的填充值data的格式,keyword1就是你在模板里面所需要替換的參數(shù)名稱,后面value就是參數(shù)的值,模板里面的參數(shù)是和傳入的參數(shù)需一一對(duì)應(yīng)

@Data
@Schema(description = "微信消息推送部分用戶實(shí)體")
@JsonInclude(JsonInclude.Include.NON_NULL) //這個(gè)注解是用于實(shí)體轉(zhuǎn)JSON的時(shí)候,空值就在轉(zhuǎn)換的時(shí)候排除掉
public class WxMagPushReq {
    @Schema(description = "用戶openid")
    private List<String> openIdList;

    @NotBlank(message = "模板id不能為空")
    @Schema(description = "模板id")
    private String templateId;
    @Schema(description = "模板需填充的值,keyword1就是模板里面需替換的參數(shù)名 如:{" +
            "                   \"keyword1\":{\n" +
            "                       \"value\":\"巧克力\"\n" +
            "                   },\n" +
            "                   \"keyword2\": {\n" +
            "                       \"value\":\"39.8元\"\n" +
            "                   },\n"+
            "                   }")

    @NotBlank(message = "模板需填充的值不能為空")
    private String data;
}

controller

Result 是自定義的返回類,換成自己的即可

 /**
     * 微信公眾號(hào)消息推送--需選用戶openId發(fā)送
     *
     * @return
     */
    @Operation(summary = "微信公眾號(hào)消息推送--需選用戶openId發(fā)送")
    @PostMapping("/wxMsgPush")
    public Result wxMsgPush(@RequestBody @Valid WxMagPushReq wxMagPushReq) {
        return messageService.wxMsgPush(wxMagPushReq);
    }

service

    Result wxMsgPush(WxMagPushReq wxMagPushReq);

serviceImpl

因?yàn)槲凑J(rèn)證的微信群發(fā)接口無法請(qǐng)求,采用循環(huán)發(fā)送的方式

@Value("${weixin.msg.secret}")
    private String secret;
    @Value("${weixin.msg.appid}")
    private String appid;
    private static WxToken wxToken = new WxToken();
    
 	@Override
    public Result wxMsgPush(WxMagPushReq wxMagPushReq) {
        //1、拿到請(qǐng)求路徑
        String url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + getTokenString();
        if (wxMagPushReq == null || wxMagPushReq.getOpenIdList().size() == 0 || StringUtils.isEmpty(wxMagPushReq.getData()) || StringUtils.isEmpty(wxMagPushReq.getTemplateId())) {
            throw ServiceException.error(ErrorCode.PARAM_EXCEPTION, "參數(shù)為空");
        }
        //裝推送失敗的openId
        List<String> list = new LinkedList<>();
        //傳入的openId去重
        List<String> collect = wxMagPushReq.getOpenIdList().stream().distinct().collect(Collectors.toList());
        for (String openId : collect) {
            //2、請(qǐng)求參數(shù)
            String params = "{\n" +
                    "           \"touser\":\"" + openId + "\",\n" +
                    "           \"template_id\":\"" + wxMagPushReq.getTemplateId() + "\",\n" +
                    "            \"data\":" + wxMagPushReq.getData() +
//                    "           \"data\":{\n" +
//                    "                   \"tel\":{\n" +
//                    "                       \"value\":\"18700000000\"\n" +
//                    "                   }\n" +
//                        "           }\n" +
                    "       }";
            HttpRequest request = HttpUtil.createPost(url);
            request.body(params);
            String str = request.execute().body();
            JSONObject json = JSONObject.parseObject(str);
            Integer errcode = json.getInteger("errcode");
            if (0 != errcode) {
                list.add(openId);
            }
        }
        return Result.ok(list);
    }
    
    //用于生成認(rèn)證token    
    private String getToken() {
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret;
        //2、基于doGet方法,調(diào)用地址獲取Token
        HttpRequest request = HttpUtil.createGet(url);
        String resultJSON = request.execute().body();
        JSONObject jsonObject = JSONObject.parseObject(resultJSON);
        String accessToken = jsonObject.getString("access_token");
        Long expiresIn = jsonObject.getLong("expires_in");
        //3、存儲(chǔ)到WxToken對(duì)象里
        wxToken.setAccessToken(accessToken);
        wxToken.setExpire(expiresIn);
        //4、返回Token
        return wxToken.getAccessToken();
    }

    public String getTokenString() {
        // 從對(duì)象中獲取accessToken
        String accessToken = wxToken.getAccessToken();
        // 獲取的accessToken為null,可能之前沒獲取,可能過期了
        if (accessToken == null) {
            // 加鎖
            synchronized (wxToken) {
                // 再次判斷
                if (wxToken.getAccessToken() == null) {
                    getToken();
                }
            }
        }
        return wxToken.getAccessToken();
    }

代碼中注釋掉的tel就是模板中對(duì)應(yīng)的參數(shù)名稱。

啟動(dòng)項(xiàng)目就可以測(cè)試了,請(qǐng)求成功,所關(guān)注的公眾號(hào)會(huì)發(fā)一條推送的信息過來。

二、圖文推送

把圖片/視頻稱為素材,帶素材推送步驟。上傳素材到臨時(shí)/永久庫(kù)->上傳圖文消息->消息推送。之前看社區(qū)說永久的素材庫(kù)不能使用,下面的示例采用的是臨時(shí)庫(kù)

注:上傳素材的時(shí)候會(huì)返回media_id這個(gè)ID在上傳圖文消息的時(shí)候需要用到,上傳圖文消息的時(shí)候也會(huì)返回media_id,這個(gè)ID在消息推送的時(shí)候也會(huì)用到。

WxMagPushAllReq

@Data
@Schema(description = "微信消息推送全部用戶實(shí)體")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class WxMagPushAllReq {

    @Schema(description = "1-文本,2圖文,當(dāng)發(fā)送圖文消息時(shí),mediaId不能為空")
    private String type;
//    @NotBlank(message = "消息內(nèi)容不能為空")
    @Schema(description = "圖文mediaId")
    private String mediaId;
//    @NotBlank(message = "消息內(nèi)容不能為空")
    @Schema(description = "消息內(nèi)容")
    private String content;

}

WxTuwen

@Data
public class WxTuwen {
    //圖片media_id
    @Schema(description = "圖片media_id")
    private String thumb_media_id;
    @Schema(description = "圖文消息的作者")
    //圖文消息的作者
    private String author;
    @Schema(description = "標(biāo)題")
    //標(biāo)題
    private String title;
    @Schema(description = "在圖文消息頁(yè)面點(diǎn)擊“閱讀原文”后的頁(yè)面,受安全限制,如需跳轉(zhuǎn)Appstore,可以使用itun.es或appsto.re的短鏈服務(wù),并在短鏈后增加 #wechat_redirect 后綴")
    //在圖文消息頁(yè)面點(diǎn)擊“閱讀原文”后的頁(yè)面,受安全限制,如需跳轉(zhuǎn)Appstore,可以使用itun.es或appsto.re的短鏈服務(wù),并在短鏈后增加 #wechat_redirect 后綴。
    private String content_source_url;
    @Schema(description = "圖文消息頁(yè)面的內(nèi)容")
    //圖文消息頁(yè)面的內(nèi)容,支持HTML標(biāo)簽。
    private String content;
    @Schema(description = "圖文消息的描述")
    //圖文消息的描述,如本字段為空
    private String digest;
    @Schema(description = "是否顯示封面,1為顯示,0為不顯示")
    //是否顯示封面,1為顯示,0為不顯示
    private Integer show_cover_pic;
}

controller

    @Operation(summary = "微信公眾號(hào)消息推送--推送全部用戶")
    @PostMapping("/wxMsgPushAll")
    public Result wxMsgPushAll(@RequestBody @Valid WxMagPushAllReq wxMagPushAllReq) {
        return messageService.wxMsgPushAll(wxMagPushAllReq);
    }
    
    @Operation(summary = "微信公眾號(hào)消息推送--上傳臨時(shí)素材")
    @PostMapping("/addMaterial")
    public Result addMaterial(@RequestParam("media") MultipartFile media, @RequestParam("type") String type) {
        return messageService.addMaterial(media,type);
    }

    @Operation(summary = "微信公眾號(hào)消息推送--上傳圖文消息素材")
    @PostMapping("/uploadnews")
    public Result uploadnews(@RequestBody @Valid WxTuwen wxTuwen) {
        return messageService.uploadnews(wxTuwen);
    }

serveice

    Result wxMsgPushAll(WxMagPushAllReq wxMagPushAllReq);
    Result addMaterial(MultipartFile media, String type);
    Result uploadnews(WxTuwen wxTuwen);

serviceImpl

	@Value("${weixin.msg.secret}")
    private String secret;
    @Value("${weixin.msg.appid}")
    private String appid;
    private static WxToken wxToken = new WxToken();
   
    @Override
    public Result wxMsgPushAll(WxMagPushAllReq wxMagPushAllReq) {
        String list = getWxUserOpenid(getTokenString(), "", "");
        if (StringUtils.isEmpty(list)) {
            return Result.ok();
        }
        String url = "https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token=" + getTokenString();
        //預(yù)覽接口,可以看推送的效果
//        String url = " https://api.weixin.qq.com/cgi-bin/message/mass/preview?access_token=" + getTokenString();
        String params = "";
        if ("1".equals(wxMagPushAllReq.getType())) {
        //自定義推送內(nèi)容
            params = "{\n" +
                    "           \"touser\":[" + list.substring(0, list.length() - 1) + "],\n" +
                    "           \"msgtype\": \"text\",\n" +
                    "           \"text\": { \"content\": \"" + wxMagPushAllReq.getContent() + "\"}" +
                    "       }";
        } else {
        //帶圖文推送消息
            params = "{\n" +            
                 "   \"touser\":[" + list.substring(0, list.length() - 1) + "],\n" +
                    "   \"mpnews\":{\n" +
                    "      \"media_id\":\"" + wxMagPushAllReq.getMediaId() + "\"\n" +
                    "   },\n" +
                    "    \"msgtype\":\"mpnews\",\n" +
                    "    \"send_ignore_reprint\":0\n" +
                    "}";
        }
        HttpRequest request = HttpUtil.createPost(url);
        request.body(params);
        String str = request.execute().body();
        System.out.println(str);
        return Result.ok(str);
    }
    
 	@Override
    public Result addMaterial(MultipartFile media, String type) {
        try {
            String mediaId = uploadFile(transferToFile(media), getTokenString(), type);
            return Result.ok(mediaId);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Result uploadnews(WxTuwen wxTuwen) {
    	//如需處理多個(gè)圖文,修改為循環(huán)處理
        String url = "https://api.weixin.qq.com/cgi-bin/media/uploadnews?access_token=" + getTokenString();
        String str = JSONObject.toJSONString(wxTuwen);
        str = "{" + "\"articles\":[" + str + "]" + "}";
        HttpRequest request = HttpUtil.createPost(url);
        request.body(str);
        String body = request.execute().body();
        JSONObject jsonObject = JSONObject.parseObject(body);
        return Result.ok(jsonObject.getString("media_id"));
    }

    //將類型MultipartFile轉(zhuǎn)為file類型
    public File transferToFile(MultipartFile file) {
        try {
            File convFile = new File(file.getOriginalFilename());
            convFile.createNewFile();
            InputStream in = file.getInputStream();
            OutputStream out = new FileOutputStream(convFile);
            byte[] bytes = new byte[1024];
            int read;
            while ((read = in.read(bytes)) != -1) {
                out.write(bytes, 0, read);
            }
            return convFile;
        } catch (Exception e) {
            throw new RuntimeException();
        }
    }
    //上傳到臨時(shí)庫(kù),返回一個(gè)ID
     public String uploadFile(File file, String accessToken, String type) throws Exception {
        //臨時(shí)素材地址
        String url1 = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=" + accessToken + "&type=" + type;
        //永久素材的地址
//        String url1 = "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=" + accessToken + "&type=" + type;
        if (!file.exists() || !file.isFile()) {
            throw new IOException("文件不存在!");
        }
        URL urlObj = new URL(url1);
        //連接
        HttpURLConnection conn = (HttpURLConnection) urlObj.openConnection();

        conn.setRequestMethod("POST");
        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setUseCaches(false);

        //請(qǐng)求頭
        conn.setRequestProperty("Connection", "Keep-Alive");
        conn.setRequestProperty("Charset", "UTF-8");
        //conn.setRequestProperty("Content-Type","multipart/form-data;");

        //設(shè)置邊界
        String BOUNDARY = "----------" + System.currentTimeMillis();
        conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + BOUNDARY);

        StringBuilder sb = new StringBuilder();
        sb.append("--");
        sb.append(BOUNDARY);
        sb.append("\r\n");
        sb.append("Content-Disposition:form-data;name=\"file\";filename=\"" + file.getName() + "\"\r\n");
        sb.append("Content-Type:application/octet-stream\r\n\r\n");
        System.out.println(sb);
        byte[] head = sb.toString().getBytes("UTF-8");

        //輸出流
        OutputStream out = new DataOutputStream(conn.getOutputStream());

        out.write(head);

        //文件正文部分
        DataInputStream in = new DataInputStream(new FileInputStream(file));
        int bytes = 0;
        byte[] bufferOut = new byte[1024];
        while ((bytes = in.read(bufferOut)) != -1) {
            out.write(bufferOut, 0, bytes);
        }
        in.close();

        //結(jié)尾
        byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");
        out.write(foot);
        out.flush();
        out.close();

        //獲取響應(yīng)
        StringBuffer buffer = new StringBuffer();
        BufferedReader reader = null;
        String result = null;

        reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        String line = null;
        while ((line = reader.readLine()) != null) {
            buffer.append(line);
        }
        if (result == null) {
            result = buffer.toString();
        }
        reader.close();

        //需要添加json-lib  jar包
        JSONObject json = JSONObject.parseObject(result);
        System.out.println(json);
        String mediaId = json.getString("thumb_media_id");
        return result;
    }

//根據(jù)appid和secretaccess_token
     private String getToken() {
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret;
        //2、基于doGet方法,調(diào)用地址獲取Token
        HttpRequest request = HttpUtil.createGet(url);
        String resultJSON = request.execute().body();
        JSONObject jsonObject = JSONObject.parseObject(resultJSON);
        String accessToken = jsonObject.getString("access_token");
        Long expiresIn = jsonObject.getLong("expires_in");
        //3、存儲(chǔ)到WxToken對(duì)象里
        wxToken.setAccessToken(accessToken);
        wxToken.setExpire(expiresIn);
        //4、返回Token
        return wxToken.getAccessToken();
    }

    public String getTokenString() {
        // 從對(duì)象中獲取accessToken
        String accessToken = wxToken.getAccessToken();
        // 獲取的accessToken為null,可能之前沒獲取,可能過期了
        if (accessToken == null) {
            // 加鎖
            synchronized (wxToken) {
                // 再次判斷
                if (wxToken.getAccessToken() == null) {
                    getToken();
                }
            }
        }
        return wxToken.getAccessToken();
    }

總結(jié) 

到此這篇關(guān)于SpringBoot(JAVA)整合微信公眾號(hào)消息推送的文章就介紹到這了,更多相關(guān)SpringBoot整合微信公眾號(hào)消息推送內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java用split分割含一個(gè)或多個(gè)空格的字符串案例

    Java用split分割含一個(gè)或多個(gè)空格的字符串案例

    這篇文章主要介紹了Java用split分割含一個(gè)或多個(gè)空格的字符串案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來過來看看吧
    2020-09-09
  • SpringBoot2.x配置多數(shù)據(jù)源方式

    SpringBoot2.x配置多數(shù)據(jù)源方式

    這篇文章主要介紹了SpringBoot2.x配置多數(shù)據(jù)源方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • Tomcat集群和Session復(fù)制應(yīng)用介紹

    Tomcat集群和Session復(fù)制應(yīng)用介紹

    本文將詳細(xì)介紹Tomcat集群和Session復(fù)制應(yīng)用,需要了解的朋友可以參考下
    2012-11-11
  • Java代理深入講解之靜態(tài)代理

    Java代理深入講解之靜態(tài)代理

    這篇文章主要給大家介紹了關(guān)于Java靜態(tài)代理的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • HashMap和Hashtable的詳細(xì)比較

    HashMap和Hashtable的詳細(xì)比較

    這篇文章主要介紹了HashMap和Hashtable的詳細(xì)比較的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • JAVA面試題之緩存擊穿、緩存穿透、緩存雪崩的三者區(qū)別

    JAVA面試題之緩存擊穿、緩存穿透、緩存雪崩的三者區(qū)別

    當(dāng)服務(wù)器QPS比較高,并且對(duì)數(shù)據(jù)的實(shí)時(shí)性要求不高時(shí),往往會(huì)接入緩存以達(dá)到快速Response、降低數(shù)據(jù)庫(kù)壓力的作用,常用來做緩存的中間件如Redis等。本文主要介紹了JAVA面試時(shí)??嫉木彺鎿舸⒋┩?、雪崩場(chǎng)景三者區(qū)別,有興趣的小伙伴可以看一下
    2021-11-11
  • java實(shí)現(xiàn)簡(jiǎn)易點(diǎn)菜器

    java實(shí)現(xiàn)簡(jiǎn)易點(diǎn)菜器

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)易點(diǎn)菜器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • 一篇文章帶你了解常用的Maven命令

    一篇文章帶你了解常用的Maven命令

    這篇文章主要為大家介紹了常用的Maven命令 ,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-01-01
  • java命令執(zhí)行jar包的多種方法(四種方法)

    java命令執(zhí)行jar包的多種方法(四種方法)

    本文通過四種方法給大家介紹java命令執(zhí)行jar包的方式,每種方法通過實(shí)例代碼給大家詳解,需要的朋友參考下吧
    2019-11-11
  • SpringBoot中@Conditional注解的使用

    SpringBoot中@Conditional注解的使用

    這篇文章主要介紹了SpringBoot中@Conditional注解的使用,@Conditional注解是一個(gè)條件裝配注解,主要用于限制@Bean注解在什么時(shí)候才生效,以指定的條件形式控制bean的創(chuàng)建,需要的朋友可以參考下
    2024-01-01

最新評(píng)論

永康市| 安达市| 怀宁县| 锡林郭勒盟| 汉川市| 临猗县| 苏州市| 进贤县| 林甸县| 防城港市| 建德市| 神池县| 灵武市| 贵港市| 横峰县| 巴彦淖尔市| 新津县| 宁海县| 张家港市| 田东县| 盐池县| 盐池县| 卓尼县| 康平县| 昌乐县| 盖州市| 辉县市| 色达县| 贡觉县| 于田县| 石嘴山市| 吴忠市| 栖霞市| 津南区| 哈巴河县| 墨玉县| 安溪县| 永嘉县| 大邑县| 苏尼特右旗| 台安县|