该篇文章主要讲的是后台如何对小程序登录的用户进行通知。

ps:由于开发时间和写文章时间间隔过久,细节上的可能不是很详细,但是会把整体功能,以及代码实现贴上来。

通知效果:

微信小程序推送消息java开发 小程序发送推送_微信小程序推送消息java开发


解释: 简单的说就是用户登陆过小程序那便可以,将自己想要推送的内容发送到用户的微信当中,微信当中有一个叫服务通知的东西,推送的内容会在上面显示。

上面这种消息模板是在微信公众平台–>功能–>模板消息下面配置的,具体模板显示内容可以调整。1. 推送必须的东西

微信小程序推送消息java开发 小程序发送推送_推送_02


首先呢这两个一个叫小程序Id一个叫小程序密钥这两个是可以在微信公众平台查到的。

接下来有三个url这个是发送推送消息必不可少的,第一个url是获取小程序全局唯一后台接口调用凭据;第二个接口是微信小程序推送接口,第三个接口是简单讲就是获取openId。然后微信开发者公众平台开发接口目录如下:微信公众平台开放接口

//获取access_token
private final static String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&";
//推送url
private final static String PUSH_URL = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=";
//根据code换取openId
//本接口应在后端服务器调用
private final static String CODE_URL = "https://api.weixin.qq.com/sns/jscode2session?appid=";

以上这5个算是准备工作吧,然后接下来就是正式进入推送了。

2. 首先我们创建一个获取openId的工具类
根据官方文档和摸索一下,这个获取openId还是很简单的。
官方上的解释是: 登录凭证校验。通过 wx.login() 接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程。
也就是说上面说的第三个接口,通过把code传递到后台,然后通过后台调用第三个接口,便可以获取我们想得到接口,具体代码如下:

//获取小程序codeid换取openid
	public static String getOpenId(String codeId) {
		String url = CODE_URL + APP_ID + "&secret=" + SECRET + "&js_code=" + codeId + "&grant_type=authorization_code";
		PrintWriter out = null;
		BufferedReader in = null;
		String line;
		StringBuffer sb = new StringBuffer();
		try {
			URL realUrl = new URL(url);
			// 打开和URL之间的连接
			URLConnection conn = realUrl.openConnection();

			// 设置通用的请求属性 设置请求格式
			//设置返回类型
			conn.setRequestProperty("contentType", "text/plain");
			//设置请求类型
			conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
			//设置超时时间
			conn.setConnectTimeout(1000);
			conn.setReadTimeout(1000);
			conn.setDoOutput(true);
			conn.connect();
			// 获取URLConnection对象对应的输出流
			out = new PrintWriter(conn.getOutputStream());
			// flush输出流的缓冲
			out.flush();
			// 定义BufferedReader输入流来读取URL的响应    设置接收格式
			in = new BufferedReader(
					new InputStreamReader(conn.getInputStream(), "UTF-8"));
			while ((line = in.readLine()) != null) {
				sb.append(line);
			}
			JSONObject jsonObject = JSONObject.parseObject(sb.toString());
			return jsonObject.get("openid").toString();
		} catch (Exception e) {
			e.printStackTrace();
		}
		//使用finally块来关闭输出流、输入流
		finally {
			try {
				if (out != null) {
					out.close();
				}
				if (in != null) {
					in.close();
				}
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}
		return null;
	}

这样我们就换取用户的唯一标识 openId,具体上面的代码可以直接复用也比较简单就不多啰嗦了。

3. 接下来呢我们就要获取access_token(本接口应在后端服务器调用)

关于access_token的官方解释: 获取小程序全局唯一后台接口调用凭据(access_token)。调用各后台接口时都需使用 access_token,开发者需要进行妥善保存。

看官方的解释我们不难理解,access_token是调用微信后台接口比不可少的东西。注意事项官方也很明确的写出来了如下:

微信小程序推送消息java开发 小程序发送推送_微信小程序推送消息java开发_03


获取access_token工具类如下:

public static JSONObject getAccessToken() {
		String url = ACCESS_TOKEN_URL + "appid=" + APP_ID + "&secret=" + SECRET;
		PrintWriter out = null;
		BufferedReader in = null;
		String line;
		StringBuffer sb = new StringBuffer();
		try {
			URL realUrl = new URL(url);
			// 打开和URL之间的连接
			URLConnection conn = realUrl.openConnection();

			// 设置通用的请求属性 设置请求格式
			//设置返回类型
			conn.setRequestProperty("contentType", "text/plain");
			//设置请求类型
			conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
			//设置超时时间
			conn.setConnectTimeout(1000);
			conn.setReadTimeout(1000);
			conn.setDoOutput(true);
			conn.connect();
			// 获取URLConnection对象对应的输出流
			out = new PrintWriter(conn.getOutputStream());
			// flush输出流的缓冲
			out.flush();
			// 定义BufferedReader输入流来读取URL的响应    设置接收格式
			in = new BufferedReader(
					new InputStreamReader(conn.getInputStream(), "UTF-8"));
			while ((line = in.readLine()) != null) {
				sb.append(line);
			}
			// 将获得的String对象转为JSON格式
			JSONObject jsonObject = JSONObject.parseObject(sb.toString());
			return jsonObject;
		} catch (Exception e) {
			e.printStackTrace();
		}
		//使用finally块来关闭输出流、输入流
		finally {
			try {
				if (out != null) {
					out.close();
				}
				if (in != null) {
					in.close();
				}
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}
		return null;
	}

解释已经很详细了,最后再说一些细节的操作先把工具类放出来。

4.推送工具类 (本接口应在后端服务器调用)
推送的具体实现具体的参数啊,还是查看官方文档再次不多赘述了。模板消息推送官方解释代码如下:

/**
 * 推送工具类
 * @author 柚子
 * @date 2018/12/25
 * @param params 推送消息内容
 * @param accessToken 
 * @return boolean
 */
public static boolean setPush(String params, String accessToken) {
		boolean flag = false;
		String url = PUSH_URL + accessToken;
		OutputStream outputStream = null;
		InputStreamReader inputStreamReader = null;
		InputStream inputStream = null;
		BufferedReader bufferedReader = null;
		HttpsURLConnection connection = null;
		try {
			// 创建URL对象
			URL realUrl = new URL(url);
			// 打开连接 获取连接对象
			connection = (HttpsURLConnection) realUrl.openConnection();
			// 设置请求编码
			connection.addRequestProperty("encoding", "UTF-8");
			// 设置允许输入
			connection.setDoInput(true);
			// 设置允许输出
			connection.setDoOutput(true);
			connection.setRequestMethod("POST");
			connection.setRequestProperty("content-type", "application/x-www-form-urlencoded");
			// 当outputStr不为null时向输出流写数据
			if (null != params) {
				outputStream = connection.getOutputStream();
				// 注意编码格式
				outputStream.write(params.getBytes("UTF-8"));
				outputStream.close();
			}
			// 从输入流读取返回内容
			inputStream = connection.getInputStream();
			inputStreamReader = new InputStreamReader(inputStream, "utf-8");
			bufferedReader = new BufferedReader(inputStreamReader);
			String str = null;
			StringBuffer buffer = new StringBuffer();
			while ((str = bufferedReader.readLine()) != null) {
				buffer.append(str);
			}
			JSONObject jsonObject = JSONObject.parseObject(buffer.toString());
			int errorCode = jsonObject.getInteger("errcode");
			String errorMessage = jsonObject.getString("errmsg");
			if (errorCode == 0) {
				flag = true;
			} else {
				logger.info("模板消息发送失败:" + errorCode + "," + errorMessage);
				flag = false;
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			// 依次关闭打开的输入流
			try {
				connection.disconnect();
				bufferedReader.close();
				inputStreamReader.close();
				inputStream.close();
				// 依次关闭打开的输出流
				outputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return flag;
	}

请求数据的示例在官网当中是有的,json形式的数据也就是对应params参数,accessToken参数我们是通过传递进来的当然也可以写死。
5.最后的实现描述
关于推送的实现的描述:
代码如下所示:

/**
	 * 功能描述
	 *
	 * @param openId     小程序openId
	 * @param formId     小程序formId
	 * @param title      通知标题
	 * @param content    通知内容
	 * @return boolean
	 * @author youzi
	 * @date 2018/12/14
	 */
	private boolean pushNoticeUtil(String openId, String formId, String title,String content) {
		logger.info("pushNoticeUtil方法开始");
		//缓存access_token
		if (redisUtils.get("access_token") == null || redisUtils.get("access_token").toString() == "") {
			JSONObject jsonObject = getAccessToken();
			if (jsonObject.get("expires_in") != null && jsonObject.get("expires_in").toString() != ""
					&& Integer.parseInt(jsonObject.get("expires_in").toString()) == 7200) {
				redisUtils.set("access_token", jsonObject.get("access_token"), 2 * 60 * 60L);
			}
		}
		JSONObject jsonObject1 = new JSONObject();
		jsonObject1.put("touser", openId);
		// DINING_TEMPLATE 模板Id  微信公众平台添加模板时生成的ID
		jsonObject1.put("template_id", DINING_TEMPLATE);
		jsonObject1.put("form_id", formId);
		JSONObject jsonObject2 = new JSONObject();
		JSONObject jsonObject3 = new JSONObject();
		jsonObject3.put("value", title);
		jsonObject2.put("keyword1", jsonObject3);
		jsonObject3 = new JSONObject();
		jsonObject3.put("value", content);
		jsonObject2.put("keyword2", jsonObject3);
		jsonObject1.put("data", jsonObject2);
		boolean pushResult = setPush(jsonObject1.toString(), redisUtils.get("access_token"));
		logger.info("pushNoticeUtil方法结束:推送结果" + pushResult);
		return pushResult;
	}

疑问: formId是什么? 简单的将就是小程序发送请求传递的一个东西,作用是用户发送消息模板消息,具体的获取官方文档如下:获取formId 只是简单的解释一下可能不是很清楚,但是只要知道想要推送消息,那就必须要formId。
整体流程:
首先微信小程序登录,登录我们会获取到openId,将其和自己后台登录绑定到一起这样我们就可以保存下来openId用来推送,然后我们在小程序登录的时候模拟发送请求获取多个formId,将获取到的formId和openId保存到数据库表中,但是要注意formId是有时效性的如果时效了,推送也会推送不到用户。
然后我们便可以准备推送了,推送时我们可以先获取accessToken,将accessToken 放进redis里面设置过期时间,如果过期了我们重新获取,否则不需要重新获取,官方的建议也是如此。然后组装我们的推送数据,具体的组装数据需要根据模板确定,但是形式上是一样,然后调用推送此时便可以发现推送成功了。
最后: 如果还有疑问的话大家可以联系我,一起探讨一下,谢谢。