国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Java微信公眾號發(fā)送消息-保姆級教程附源碼

這篇具有很好參考價值的文章主要介紹了Java微信公眾號發(fā)送消息-保姆級教程附源碼。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

目錄

1. 概念說明:

2. 開發(fā)準備:

3. 測試demo(更改配置信息即可使用)

3.1.?服務(wù)器配置

?3.1.1.配置填寫說明

3.1.2.校驗服務(wù)器有效性:

3.1.3.URL后端接口代碼和校驗代碼(servlet)

?3.1.4.配置內(nèi)網(wǎng)穿透,完成本地調(diào)試

?3.1.5. 可能存在的問題

3.2 模板消息

3.2.1. 搞定?template_id?即模板消息id:

3.2.2. 搞定?touser 即openid

3.2.3.?從獲取openid的請求中我們發(fā)現(xiàn)需要access_token:

3.2.4. 發(fā)送模板消息的url參數(shù)

3.2.5. topcolor

3.2.5. data

3.3. 源碼

3.3.1?模板消息DTO

3.3.2.?模板消息內(nèi)容DTO

3.3.3. access_token緩存類:

3.3.4.http請求工具類:

3.3.5.?最終的Servlet(controller自行轉(zhuǎn)換)(為方便觀看所有邏輯都寫在這里了,自行優(yōu)化):

3.4.測試

官方文檔:

微信公眾平臺開發(fā)概述 | 微信開放文檔

全局返回碼文檔 :微信開放文檔

1. 概念說明:

  • access_token:是公眾號的全局唯一接口調(diào)用憑據(jù),公眾號調(diào)用各接口的必要參數(shù)(2小時內(nèi)有效,過期需要重新獲取,但1天內(nèi)獲取次數(shù)有限,需自行存儲)

  • OpenID :為了識別用戶每個公眾號針對,每個用戶會產(chǎn)生一個OpenID(用戶id:對用戶的操作需要用到)

  • UnionID: 同一開放平臺賬號下不同公眾號或應(yīng)用下用戶的共同id(這里不需要用到)

  • 消息會話(這里用到模板消息)

    • 公眾號是以微信用戶的一個聯(lián)系人形式存在的,消息會話是公眾號與用戶交互的基礎(chǔ)。

    • 公眾號內(nèi)主要有這樣幾類消息服務(wù)的類型,分別用于不同的場景:

      • 群發(fā)消息:訂閱號為每天1次,服務(wù)號為每月4次

      • 被動回復(fù)消息:在用戶給公眾號發(fā)消息后,公眾號可以回復(fù)一個消息

      • 客服消息:用戶在公眾號內(nèi)發(fā)消息/觸發(fā)特定行為后,公眾號可以給用戶發(fā)消息

      • 模板消息:在需要對用戶發(fā)送服務(wù)通知(如刷卡提醒、服務(wù)預(yù)約成功通知等)時,公眾號可以用特定內(nèi)容模板,主動向用戶發(fā)送消息。

2. 開發(fā)準備:

  1. 開發(fā)者在公眾平臺網(wǎng)站中創(chuàng)建服務(wù)號、獲取接口權(quán)限后方可開始

    https://kf.qq.com/faq/120911VrYVrA150918fMZ77R.html?scene_id=kf3386

  2. 個人研究測試:通過手機微信掃描二維碼獲得測試號

    https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login

3. 測試demo(更改配置信息即可使用)

3.1.?服務(wù)器配置

這里坑比較多,服務(wù)器配置不是隨便填一個url就完事了,需要后端接口配合校驗。

界面:java微信公眾號開發(fā)源碼,微信

?測試號界面:java微信公眾號開發(fā)源碼,微信

?3.1.1.配置填寫說明

  • URL:服務(wù)器地址--是開發(fā)者用來接收微信消息和事件的接口URL (在提交配置修改時微信會向該URL接口發(fā)送請求驗證服務(wù)器地址的有效性)

  • Token:任意填寫,用作生成簽名(微信向上述URL接口發(fā)送的請求是攜帶token的,需要在接口中校驗token一致以確保安全性)這個token與上述的access_token不是一回事。這個token只用于驗證開發(fā)者服務(wù)器。

  • EncodingAESKey: 由開發(fā)者手動填寫或隨機生成,將用作消息體加解密密鑰

  • 消息加解密方式 :明文模式、兼容模式和安全模式

3.1.2.校驗服務(wù)器有效性:

這是重點:點擊完提交修改后,微信會向url發(fā)起一個請求并將token攜帶過去,這個請求要能正確被你的后端服務(wù)器所響應(yīng)并返回正確的結(jié)果,服務(wù)器配置才算修改成功

校驗請求說明:

  • 開發(fā)者提交信息后,微信服務(wù)器將發(fā)送GET請求到填寫的服務(wù)器地址URL上,GET請求攜帶參數(shù)如下表所示:
    • signature:微信加密簽名,signature結(jié)合了開發(fā)者填寫的token參數(shù)和請求中的timestamp參數(shù)、nonce參數(shù)。

    • timestamp:時間戳

    • nonce :隨機數(shù)

    • echostr:隨機字符串

  • 開發(fā)者通過檢驗signature對請求進行校驗(下面有校驗方式)。若確認此次GET請求來自微信服務(wù)器,請原樣返回echostr參數(shù)內(nèi)容,則接入生效,成為開發(fā)者成功,否則接入失敗。

3.1.3.URL后端接口代碼和校驗代碼(servlet)


@WebServlet(urlPatterns = {
		"/wx"})
public class WxServlet extends HttpServlet {
	
    // 服務(wù)器配置填寫的token
    private static final String wxToken = "888888";

    @Override
	protected void doGET(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
        doGetWx(request, response);
 }
/**
	 * @Description 校驗配置URL服務(wù)器的合法性
	 * @date 2023年5月29日下午4:17:40
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	public void doGetWx(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		String signature = request.getParameter("signature");
		String timestamp = request.getParameter("timestamp");
		String nonce = request.getParameter("nonce");
		String echostr = request.getParameter("echostr");

		// 將微信echostr返回給微信服務(wù)器
		try (OutputStream os = response.getOutputStream()) {
			String sha1 = getSHA1(wxToken, timestamp, nonce, "");

			// 和signature進行對比
			if (sha1.equals(signature)) {
				// 返回echostr給微信
				os.write(URLEncoder.encode(echostr, "UTF-8").getBytes());
				os.flush();

			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 用SHA1算法生成安全簽名
	 *
	 * @param token     票據(jù)
	 * @param timestamp 時間戳
	 * @param nonce     隨機字符串
	 * @param encrypt   密文
	 * @return 安全簽名
	 * @throws Exception
	 */
	public static String getSHA1(String token, String timestamp, String nonce, String encrypt) throws Exception {
		try {
			String[] array = new String[] { token, timestamp, nonce, encrypt };
			StringBuffer sb = new StringBuffer();
			// 字符串排序
			Arrays.sort(array);
			for (int i = 0; i < 4; i++) {
				sb.append(array[i]);
			}
			String str = sb.toString();
			// SHA1簽名生成
			MessageDigest md = MessageDigest.getInstance("SHA-1");
			md.update(str.getBytes());
			byte[] digest = md.digest();
			StringBuffer hexstr = new StringBuffer();
			String shaHex = "";
			for (int i = 0; i < digest.length; i++) {
				shaHex = Integer.toHexString(digest[i] & 0xFF);
				if (shaHex.length() < 2) {
					hexstr.append(0);
				}
				hexstr.append(shaHex);
			}
			return hexstr.toString();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "";
	}
    
}

項目路徑是/xjsrm,因此服務(wù)器url地址就是:http://localhost:8080/xjsrm/wx

直接將http://localhost:8080/xjsrm/wx地址填到服務(wù)配置的url可以嗎?答案是不可以!

java微信公眾號開發(fā)源碼,微信

?3.1.4.配置內(nèi)網(wǎng)穿透,完成本地調(diào)試

?3.1.4.1. 內(nèi)網(wǎng)穿透的必要性:

  • 微信需要檢驗服務(wù)器有效性,因此這個url必須是公網(wǎng)資源,就是外網(wǎng)能訪問的,不支持本地127.0.0.1/localhost ,而且這樣調(diào)試起來非常的不方便。
  • 因此這里使用內(nèi)網(wǎng)穿透將本地資源映射到公網(wǎng)。(直接部署到服務(wù)器上調(diào)試的可以跳過)

?3.1.4.2. 用到的工具cpolar:

  • ?也可以使用花生殼、natapp、ngrok等;但不建議使用natapp、ngrok,這兩個工具都不能直接訪問到服務(wù)資源,中間會多一層手動校驗(提示用戶是否要訪問該網(wǎng)站),會造成不必要的麻煩。

?3.1.4.3. cpolar配置內(nèi)網(wǎng)穿透的教程

  • 參考大佬的博文 從 2.內(nèi)網(wǎng)穿透開始看到3.測試公網(wǎng)訪問 即可微信公眾號本地開發(fā)調(diào)試 - 無公網(wǎng)IP,內(nèi)網(wǎng)穿透_微信公眾號服務(wù)器調(diào)試_熱愛編程的小K的博客-CSDN博客微信公眾號本地開發(fā)調(diào)試 - 無公網(wǎng)IP,內(nèi)網(wǎng)穿透https://blog.csdn.net/qq_72157449/article/details/130237603

?3.1.4.4. 獲取本地項目的公網(wǎng)路徑

? ? ? ? 配置完cpolar后在在線隧道列表中找到本地項目的地址,我項目是localhost:8080,因此公網(wǎng)地址對應(yīng)(最好用https協(xié)議)https://22717eef.r6.vip.cpolar.cn 、

????????因此完整的服務(wù)器Url就是: https://22717eef.r6.vip.cpolar.cn/xjsrm/wx

????????瀏覽器訪問該url,看后端是否接受到了請求,如果接收到說明接口沒問題,此時將URL填到對應(yīng)的配置欄中點擊提交即可。java微信公眾號開發(fā)源碼,微信

?3.1.5. 可能存在的問題

????????如果你在使用點擊修改配置的提交發(fā)現(xiàn)微信發(fā)送的請求根本就沒有進到后端的項目中

????????此時查看sandboxinfo這個包。如果出現(xiàn) errorcode=-1多半是內(nèi)網(wǎng)穿透工具的問題。

????????出現(xiàn)其他錯誤代碼可以去錯誤大全中根據(jù)信息排查

? ? ? ? ?ngrok錯誤排查示例:? ? ? ? ?java微信公眾號開發(fā)源碼,微信

3.2 模板消息

?模板消息的官方文檔:微信公眾平臺 (qq.com)

從官方給出的請求示例入手,看需要準備的接口和數(shù)據(jù):

POST請求

https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN
請求包為一個json:

{
    "template_id":"ngqIpbwh8bUfcSsECmogfXcV14J0tQlEpBO27izEYtY",
    "touser":"OPENID",
	"url":"http://weixin.qq.com/download",
    "topcolor":"#FF0000",
    "data":{
            "User": {
                "value":"黃先生",
                "color":"#173177"
            },
            "Date":{
                "value":"06月07日 19時24分",
                "color":"#173177"
            },
            "CardNumber": {
                "value":"0426",
                "color":"#173177"
            },
            "Type":{
                "value":"消費",
                "color":"#173177"
            },
            "Money":{
                "value":"人民幣260.00元",
                "color":"#173177"
            },
            "DeadTime":{
                "value":"06月07日19時24分",
                "color":"#173177"
            },
            "Left":{
                "value":"6504.09",
                "color":"#173177"
            }
    }
}

3.2.1. 搞定?template_id?即模板消息id:

新增模板消息(以測試號為例)

模板內(nèi)容可設(shè)置參數(shù)(模板標題不可),供接口調(diào)用時使用,參數(shù)需以{{開頭,以.DATA}}結(jié)尾(具體傳參看后續(xù)代碼)

java微信公眾號開發(fā)源碼,微信

3.2.2. 搞定?touser 即openid

查看用戶管理的官方文檔;微信開放文檔 (qq.com),通過官方接口獲取

因為我們是公眾號,所以選用獲取用戶列表的接口:微信開放文檔 (qq.com)

http請求方式: GET(請使用https協(xié)議)
https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID

參數(shù)	是否必須	說明
access_token	是	調(diào)用接口憑證
next_openid	是	第一個拉取的OPENID,不填默認從頭開始拉取

返回說明
正確時返回JSON數(shù)據(jù)包:

{
    "total":2,
    "count":2,
    "data":{
    "openid":["OPENID1","OPENID2"]},
    "next_openid":"NEXT_OPENID"
}

3.2.3.?從獲取openid的請求中我們發(fā)現(xiàn)需要access_token

獲取access_token官方文檔:微信開放文檔 (qq.com)

https請求方式: GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

參數(shù)說明

參數(shù)	是否必須	說明
grant_type	是	獲取access_token填寫client_credential
appid	是	第三方用戶唯一憑證
secret	是	第三方用戶唯一憑證密鑰,即appsecret
返回說明

正常情況下,微信會返回下述JSON數(shù)據(jù)包給公眾號:
{"access_token":"ACCESS_TOKEN","expires_in":7200}

3.2.4. 發(fā)送模板消息的url參數(shù)

? ? ? ? 這個是發(fā)送消息后用戶點擊卡片跳轉(zhuǎn)的地址(自定義)可以不填

3.2.5. topcolor

? ? ? ?消息卡片的頂部顏色(自定義)

3.2.5. data

? ? ? ?消息的內(nèi)容(了解結(jié)構(gòu)即可,后續(xù)代碼中會體現(xiàn))

3.3. 源碼

拷貝完再理解

3.3.1?模板消息DTO

import java.util.Map;


/**
* @Description 微信公眾號模板消息請求對象
* @author isymi
* @version
* @date 2023年5月29日下午4:28:09
*
 */
public class TemplateMessage {
	
		/**
		 * 發(fā)送消息用戶的openid
		 */
	  	private String touser;
	  	/*
	  	 * 模板消息id
	  	 */
	    private String template_id;
	    /**
	     * 點擊模板信息跳轉(zhuǎn)地址;置空:則在發(fā)送后,點擊模板消息會進入一個空白頁面(ios),或無法點擊(android)
	     */
	    private String url;
	    /**
	     * 卡片頂部顏色
	     */
	    private String topcolor;
	    
	    /**
	     * key為模板中參數(shù)內(nèi)容"xx.DATA"的xx,value為參數(shù)對應(yīng)具體的值和顏色 
	     */
	    private Map<String, WeChatTemplateMsg> data;
	   // private String data;

		public TemplateMessage() {
		}

	    public TemplateMessage(String touser, String template_id, String url, String topcolor, Map<String, WeChatTemplateMsg> data) {
	        this.touser = touser;
	        this.template_id = template_id;
	        this.url = url;
	        this.topcolor = topcolor;
	        this.data = data;
	    }

		public String getTouser() {
			return touser;
		}

		public void setTouser(String touser) {
			this.touser = touser;
		}

		public String gettemplate_id() {
			return template_id;
		}

		public void settemplate_id(String template_id) {
			this.template_id = template_id;
		}

		public String getUrl() {
			return url;
		}

		public void setUrl(String url) {
			this.url = url;
		}

		public String getTopcolor() {
			return topcolor;
		}

		public void setTopcolor(String topcolor) {
			this.topcolor = topcolor;
		}

		public Map<String, WeChatTemplateMsg> getData() {
			return data;
		}

		public void setData(Map<String, WeChatTemplateMsg> data) {
			this.data = data;
		}

		@Override
		public String toString() {
			return "TemplateMessage [touser=" + touser + ", template_id=" + template_id + ", url=" + url + ", topcolor="
					+ topcolor + ", data=" + data + "]";
		}

}

3.3.2.?模板消息內(nèi)容DTO


import java.io.Serializable;

/**
* @Description 模板消息內(nèi)容類
* @author isymi
* @version
* @date 2023年5月29日下午4:33:27
*
 */
public class WeChatTemplateMsg implements Serializable{

	/**
     * 消息實參
     */
    private String value;
    /**
     * 消息顏色
     */
    private String color;
 
 
    public WeChatTemplateMsg(String value) {
        this.value = value;
        this.color = "#173177";
    }
 
    public WeChatTemplateMsg(String value, String color) {
        this.value = value;
        this.color = color;
    }

	@Override
	public String toString() {
		return "WeChatTemplateMsg [value=" + value + ", color=" + color + "]";
	}

	public String getValue() {
		return value;
	}

	public void setValue(String value) {
		this.value = value;
	}

	public String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}


}

3.3.3. access_token緩存類:


/**
* @Description access_token緩存類
* @author 
* @version
* @date 2023年5月30日上午10:40:08
*
 */
public class AccessToken {
	
	private String accessToken;
    //過期時間 當(dāng)前系統(tǒng)時間+微信傳來的過期時間
    private Long expiresTime;

    public AccessToken(String accessToken, String expiresIn) {
        this.accessToken = accessToken;
        this.expiresTime = System.currentTimeMillis()+Integer.parseInt(expiresIn)*1000;
    }

    /**
     * 判斷token是否過期
     * @return
     */
    public boolean isExpired(){
        return System.currentTimeMillis()>expiresTime;
    }

	public String getAccessToken() {
		return accessToken;
	}

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

	public Long getExpiresTime() {
		return expiresTime;
	}

	public void setExpiresTime(Long expiresTime) {
		this.expiresTime = expiresTime;
	}

	public AccessToken(String accessToken, Long expiresTime) {
		this.accessToken = accessToken;
		this.expiresTime = expiresTime;
	}

	public AccessToken() {
	}

}

3.3.4.http請求工具類:

import java.io.BufferedReader;

import java.net.*;
import java.nio.charset.StandardCharsets;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xx.xx.pojo.TemplateMessage;


/**
* @Description 微信公眾號http請求工具類
* @author isymi
* @version
* @date 2023年5月29日下午4:07:39
*
 */
public class WXPublicAccountHttpUtil {
	
	
	/**
	* @Description 根據(jù)請求獲取返回結(jié)果字符串(根據(jù)請求獲取accessToken)
	* @date 2023年5月29日下午4:04:21
	* @param url
	* @return
	* @throws IOException
	 */
	public static String get(String url) throws IOException {
        HttpURLConnection connection = null;
        BufferedReader reader = null;

        try {
            URL requestUrl = new URL(url);
            connection = (HttpURLConnection) requestUrl.openConnection();
            connection.setRequestMethod("GET");

            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                StringBuilder response = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    response.append(line);
                }
                return response.toString();
            } else {
                // Handle error response
                System.out.println("HTTP GET request failed with response code: " + responseCode);
                return null;
            }
        } finally {
            if (reader != null) {
                reader.close();
            }
            if (connection != null) {
                connection.disconnect();
            }
        }
    }
	
	/**
	* @Description 根據(jù)URl獲取JSONObject:根據(jù)請求獲取關(guān)注用戶列表數(shù)據(jù)
	* @date 2023年5月29日下午4:02:16
	* @param url
	* @return
	* @throws IOException
	 */
	public static JSONObject getJsonObject(String url) throws IOException {
        HttpURLConnection connection = null;
        BufferedReader reader = null;

        try {
            URL urlObj = new URL(url);
            connection = (HttpURLConnection) urlObj.openConnection();
            connection.setRequestMethod("GET");

            StringBuilder response = new StringBuilder();
            reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            
            /*
             * 	正確返回的格式
             *      {
    					"total":2,
    					"count":2,
    					"data":{
    						"openid":["OPENID1","OPENID2"]},
    					"next_openid":"NEXT_OPENID"
					}
             */
            return JSON.parseObject(response.toString());
        } finally {
            if (reader != null) {
                reader.close();
            }
            if (connection != null) {
                connection.disconnect();
            }
        }
    }

	/**
	* @Description 獲取關(guān)注用戶的 openid 集合
	* @date 2023年5月29日下午4:04:02
	* @param url
	* @return
	* @throws IOException
	 */
    public static  List<String> getOpenidList(String url) throws IOException {
    	// 獲取關(guān)注用戶列表數(shù)據(jù)
        JSONObject jsonObject = getJsonObject(url);
        System.out.println(jsonObject);
        
        // 錯誤情況
        if (jsonObject.containsKey("errcode")) {
            int errcode = jsonObject.getIntValue("errcode");
            String errmsg = jsonObject.getString("errmsg");
            throw new RuntimeException("Failed to get openid list. errcode: " + errcode + ", errmsg: " + errmsg);
        }
 
        int total = jsonObject.getIntValue("total");
       // 無用戶關(guān)注 {"total":0,"count":0,"next_openid":""}
        if (total == 0) {
            throw new RuntimeException("No openid found. Total is 0.");
        }
        // 有用戶關(guān)注:
        /**
         * {"total":1,
         * 	"data":{
         * 		"openid":["o-tgG5-VaQfsgdjerHA-z2PeZFls"]},
         * 		"count":1,
         * 		"next_openid":"o-tgG5-VaQfsgdjerHA-z2PeZFls"}
         */
        JSONObject dataObject = jsonObject.getJSONObject("data");
        
        int count = dataObject.getIntValue("count");
        System.out.println("關(guān)注總?cè)藬?shù):"+count);
        JSONArray openidArray = dataObject.getJSONArray("openid");
        
        // 將 openid 數(shù)組封裝為 List 集合
        List<String> openidList = new ArrayList<>();
        for (int i = 0; i < openidArray.size(); i++) {
            String openid = openidArray.getString(i);
            openidList.add(openid);
        }
        
        return openidList;
    }
    
    /**
    * @Description 發(fā)送消息
    * @date 2023年5月29日下午4:58:02
    * @param accessToken
    * @param templateMessage
    * @return
    * @throws IOException
     */
    public static String sendMessage( String accessToken, TemplateMessage templateMessage) throws IOException {
        String requestUrl ="https://api.weixin.qq.com/cgi-bin/message/template/send" + "?access_token=" + accessToken;

        URL urlObject = new URL(requestUrl);
        HttpURLConnection connection = (HttpURLConnection) urlObject.openConnection();
        connection.setRequestMethod("POST");
        connection.setDoOutput(true);
        connection.setRequestProperty("Content-Type", "application/json");

        String requestBody = JSON.toJSONString(templateMessage);
        byte[] requestBodyBytes = requestBody.getBytes(StandardCharsets.UTF_8);
        connection.setRequestProperty("Content-Length", String.valueOf(requestBodyBytes.length));

        OutputStream outputStream = connection.getOutputStream();
        outputStream.write(requestBodyBytes);
        outputStream.close();

        int responseCode = connection.getResponseCode();
        BufferedReader reader;
        if (responseCode >= 200 && responseCode <= 299) {
            reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
        } else {
            reader = new BufferedReader(new InputStreamReader(connection.getErrorStream()));
        }

        StringBuilder response = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            response.append(line);
        }
        reader.close();

        connection.disconnect();

        System.out.println("Response Code: " + responseCode);
        System.out.println("Response Body: " + response.toString());

        return response.toString();
    }

}

3.3.5.?最終的Servlet(controller自行轉(zhuǎn)換)(為方便觀看所有邏輯都寫在這里了,自行優(yōu)化):

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xx.srm.pojo.AccessToken;
import com.xx.xx.pojo.TemplateMessage;
import com.xx.xx.pojo.WeChatTemplateMsg;
import com.xx.xx.utils.WXPublicAccountHttpUtil;

@WebServlet(urlPatterns = {
		"/wx", 
		"/wx/message" })
public class WxServlet extends HttpServlet {

    // 必須替換
	private static final String wxToken = "xxxxxm8";
    // 必須替換
	public static final String APPID = "wx3xxxxxx1795fa";
    // 必須替換
	public static final String SECRET = "57b96fxxxxxxxxeab62bfe3";
    // 必須替換
	public static final String MESSAGE_TEMPLATE_ID = "N6MyyAF0Ucxxxxxxxxxxxxxxxxp-OGsWnQut_niUAaY";

	/**
	 * 全局AccessToken
	 */
	private static AccessToken at;

	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		if ("/wx".equals(request.getServletPath())) {
			doGetWx(request, response);
		} else if ("/wx/message".equals(request.getServletPath())) {
			doSendMessage(request, response);
		}

	}
	
	/**
	 * @Description 校驗配置URL服務(wù)器的合法性
	 * @date 2023年5月29日下午4:17:40
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	public void doGetWx(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		String signature = request.getParameter("signature");
		String timestamp = request.getParameter("timestamp");
		String nonce = request.getParameter("nonce");
		String echostr = request.getParameter("echostr");

		// 將微信echostr返回給微信服務(wù)器
		try (OutputStream os = response.getOutputStream()) {
			String sha1 = getSHA1(wxToken, timestamp, nonce, "");

			// 和signature進行對比
			if (sha1.equals(signature)) {
				// 返回echostr給微信
				os.write(URLEncoder.encode(echostr, "UTF-8").getBytes());
				os.flush();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	
	/**
	* @Description 發(fā)送模板消息
	* @date 2023年5月30日上午10:57:45
	* @param request
	* @param response
	* @throws IOException
	 */
	private void doSendMessage(HttpServletRequest request, HttpServletResponse response) throws IOException {
		
		String token = getToken();
		String url = "https://api.weixin.qq.com/cgi-bin/user/get?" + "access_token=" + token;
		// 獲取 openid 數(shù)組
		List<String> userOpenids = WXPublicAccountHttpUtil.getOpenidList(url);
		
		
		// 主要的業(yè)務(wù)邏輯:
		for (String openId : userOpenids) {
			TemplateMessage templateMessage = new TemplateMessage();
			templateMessage.setTouser(openId);
			templateMessage.settemplate_id(MESSAGE_TEMPLATE_ID);
			templateMessage.setTopcolor("#FF0000");

			// key對應(yīng)創(chuàng)建模板內(nèi)容中的形參
			//{{title.DATA}} {{username.DATA}} {{quote.DATA}} {{date.DATA}} 
			// WeChatTemplateMsg對應(yīng)實參和字體顏色
			Map<String, WeChatTemplateMsg> data = new HashMap<String, WeChatTemplateMsg>();
			data.put("title", new WeChatTemplateMsg("你有一條新的消息", "#173177"));
			data.put("username", new WeChatTemplateMsg("黃先生", "#173177"));
			data.put("date", new WeChatTemplateMsg("2023年05月29日 16時24分", "#173177"));
			data.put("quote", new WeChatTemplateMsg("你好", "#173177"));
			

			templateMessage.setData(data);
			
			System.out.println(templateMessage);
			
			WXPublicAccountHttpUtil.sendMessage(getToken(), templateMessage);
			
		}

	}

	/**
	 * @Description 獲取token,本地緩存有就直接返回,沒有就發(fā)送請求獲?。╳x官方api獲取token每天有限制,因此需做緩存)
	 * @date 2023年5月29日下午4:13:17
	 * @return
	 */
	public static String getToken() {
		if (at == null || at.isExpired()) {
			getAccessToken();
		}
		return at.getAccessToken();
	}

	/**
	 * 給AccessToken賦值
	 */
	private static void getAccessToken() {

		// 發(fā)送請求獲取token
		String token = null;
		try {
			String url ="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential"+ "&appid=" + APPID + "&secret=" + SECRET;
			token = WXPublicAccountHttpUtil.get(url);
		} catch (Exception e) {
			e.printStackTrace();
		}
		JSONObject jsonObject = JSONObject.parseObject(token);
		String accessToken = (String) jsonObject.get("access_token");
		Integer expiresIn = (Integer) jsonObject.get("expires_in");
		// 創(chuàng)建token對象,并存儲
		at = new AccessToken(accessToken, String.valueOf(expiresIn));
		System.out.println(token);

	}





	/**
	 * 用SHA1算法生成安全簽名
	 *
	 * @param token     票據(jù)
	 * @param timestamp 時間戳
	 * @param nonce     隨機字符串
	 * @param encrypt   密文
	 * @return 安全簽名
	 * @throws Exception
	 */
	public static String getSHA1(String token, String timestamp, String nonce, String encrypt) throws Exception {
		try {
			String[] array = new String[] { token, timestamp, nonce, encrypt };
			StringBuffer sb = new StringBuffer();
			// 字符串排序
			Arrays.sort(array);
			for (int i = 0; i < 4; i++) {
				sb.append(array[i]);
			}
			String str = sb.toString();
			// SHA1簽名生成
			MessageDigest md = MessageDigest.getInstance("SHA-1");
			md.update(str.getBytes());
			byte[] digest = md.digest();
			StringBuffer hexstr = new StringBuffer();
			String shaHex = "";
			for (int i = 0; i < digest.length; i++) {
				shaHex = Integer.toHexString(digest[i] & 0xFF);
				if (shaHex.length() < 2) {
					hexstr.append(0);
				}
				hexstr.append(shaHex);
			}
			return hexstr.toString();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "";
	}

}

3.4.測試

關(guān)注公眾號

瀏覽器訪問?http://22717eef.r6.vip.cpolar.cn/xjsrm/wx/message(替換為自己的)

查看微信消息文章來源地址http://www.zghlxwxcb.cn/news/detail-555795.html

到了這里,關(guān)于Java微信公眾號發(fā)送消息-保姆級教程附源碼的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包