1、你得有一个小程序,并且认证了,个人的也行
2、开通订阅消息
小程序后台->功能->订阅消息

3、公共模板库选择一个模板
选择的时候,选择你需要的字段,因为字段有限制

4、我的模板点击详情
详情内容,模板 id 都是需要提供个服务端开发人员的

小程序消息订阅,需要用户确认
1、首先小程序授权登陆获取 code
官网示例:https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html
wx.login({
success (res) {
if (res.code) {
//发起网络请求
wx.request({
url: 'https://example.com/onLogin',
data: {
code: res.code
}
})
} else {
console.log('登录失败!' + res.errMsg)
}
}
})
// 结果 {errMsg: "login:ok", code: "0a3kK4Ga10Gk3F0oBAHa1mGyRl3kK4Gd"}
uni-App 示例:https://uniapp.dcloud.net.cn/api/plugins/login.html#login
uni.login({
provider: 'weixin', //使用微信登录
success: function (loginRes) {
console.log(loginRes)
}
});
// 结果 {errMsg: "login:ok", code: "0a3kK4Ga10Gk3F0oBAHa1mGyRl3kK4Gd"}
2、将 code 传给服务端 获取用户唯一标识 openId
3、通过代码起小程序消息订阅界面、用户点击确定ok,小程序工作结束
tmplIds 填写模板 id 即可,最多三个
wx.requestSubscribeMessage({
tmplIds: [''],
success (res) {
console.log(res)
}
})
4、注意事项:
避免重复拉起用户订阅通知,可以通过微信提供的
getSetting判断用户是否订阅了,如果没有就拉起。注意下面是用
uniapp写的,方法前缀是uni如果你小程序代码记得修改wx以及提示组件到此小程序工作结束
getSetting() {
uni.getSetting({
withSubscriptions: true, // 获取用户订阅状态
success(res) {
// false 表示用户未订阅改消息
if (!res.subscriptionsSetting.mainSwitch) {
this.subscribeMessage();
} else {
uni.showToast({
title: '已订阅',
icon: 'none'
})
}
}
})
},
subscribeMessage() {
uni.requestSubscribeMessage({
tmplIds: ['模板id'],
success(res) {
if (res.errMsg === 'requestSubscribeMessage:ok') {
uni.showToast({
title: '订阅成功',
icon: 'none'
})
}
}
})
}
微信小程序的
appid和secret小程序后台->开发->开发管理->开发设置->开发者 ID
注意事项:
http 请求这里使用 apache 的工具类,你也可以使用别的thing 字段有长度限制20,超过会失败1、通过 code 获取用户 open id 官网文档
public String getOpenId(String code) throws IOException {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
Map<String, Object> params = new HashMap<>();
params.put("appid", Constants.APPLET_APP_ID);
params.put("secret", Constants.APPLET_SECRET);
params.put("js_code", code);
params.put("grant_type", "authorization_code");
String url = handleParams("https://api.weixin.qq.com/sns/jscode2session", params);
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity(); // 响应结果
return EntityUtils.toString(entity, CharSetType.UTF8.getType());
}
public static void main(String[] args) throws IOException {
HttpUtils httpUtils = new HttpUtils();
String token = httpUtils.getToken();
System.out.println(token);
}
响应结果:
{"access_token":"67_u22CQaWq22222222Q4griDE6kiT5hwg7jVxedn8J9te17Az1oWGGxPgB22222229Y4Wm6h_Yzci7-FSDjeH8YG6DsCOYrQXJCWsPXhT6nWbKIWCXfABACID","expires_in":7200}
2、通过 appid 和 secret 获取 token 超时 7200 秒 可 redis 缓存 官方文档
public String getToken() throws IOException {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
Map<String, Object> params = new HashMap<>();
params.put("appid", Constants.APPLET_APP_ID);
params.put("secret", Constants.APPLET_SECRET);
params.put("grant_type", "client_credential");
String url = handleParams("https://api.weixin.qq.com/cgi-bin/token", params);
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity(); // 响应结果
return EntityUtils.toString(entity, CharSetType.UTF8.getType());
}
3、指定用户推送消息结束 官方文档
public String pushMsg(String token) throws IOException {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
Map<String, Object> params = new HashMap<>();
// 处理微信推送数据结构
JSONObject mapData = new JSONObject();
Map<String, Object> map1 = new HashMap<>();
map1.put("value", "任务名称");
mapData.put("thing2", map1);
Map<String, Object> map2 = new HashMap<>();
map2.put("value", "2022-04-03 10:00:00");
mapData.put("time3", map2);
Map<String, Object> map3 = new HashMap<>();
map3.put("value", "描述信息");
mapData.put("thing4", map3);
Map<String, Object> map4 = new HashMap<>();
map4.put("value", "备注信息");
mapData.put("thing10", map4);
Map<String, Object> map5 = new HashMap<>();
map5.put("value", "任务来源");
mapData.put("thing11", map5);
params.put("template_id", "templateId");// 模板 id
params.put("touser", "openId"); // open id
params.put("data", mapData); // 数据
params.put("page", "page"); // 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转
params.put("miniprogram_state", "trial"); //developer为开发版;trial为体验版;formal为正式版;默认为正式版
params.put("lang", "zh_CN"); //
HttpPost httpPost = new HttpPost("https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + token);
httpPost.addHeader("ContentTyp", "application/json");
// 参数转 JSON 格式
String json = objToStr(params);
StringEntity stringEntity = new StringEntity(json, CharSetType.UTF8.getType());
stringEntity.setContentEncoding(CharSetType.UTF8.getType());
httpPost.setEntity(stringEntity);
CloseableHttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity(); // 响应结果
return EntityUtils.toString(entity, CharSetType.UTF8.getType());
}
4、完整代码
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.chenlijia1111.utils.core.enums.CharSetType;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.jeecg.modules.video.utitls.Constants;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @description:
* @author: Mr.Fang
* @create: 2023-04-03 17:06
**/
public class HttpUtils {
/**
* description: 获取token,返回结果为 JSON 自行转 map
* create by: Mr.Fang
*
* @return: java.lang.String
* @date: 2023/4/3 17:46
*/
public String getToken() throws IOException {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
Map<String, Object> params = new HashMap<>();
params.put("appid", Constants.APPLET_APP_ID);
params.put("secret", Constants.APPLET_SECRET);
params.put("grant_type", "client_credential");
String url = handleParams("https://api.weixin.qq.com/cgi-bin/token", params);
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity(); // 响应结果
return EntityUtils.toString(entity, CharSetType.UTF8.getType());
}
/**
* description: 获取 open id,返回结果为 JSON 自行转 map
* create by: Mr.Fang
*
* @param: [code]
* @return: java.lang.String
* @date: 2023/4/3 17:46
*/
public String getOpenId(String code) throws IOException {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
Map<String, Object> params = new HashMap<>();
params.put("appid", Constants.APPLET_APP_ID);
params.put("secret", Constants.APPLET_SECRET);
params.put("js_code", code);
params.put("grant_type", "authorization_code");
String url = handleParams("https://api.weixin.qq.com/sns/jscode2session", params);
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity(); // 响应结果
return EntityUtils.toString(entity, CharSetType.UTF8.getType());
}
/**
* description: 消息推送 返回结果为 JSON 自行转 map;token 调用 getToken获取
* create by: Mr.Fang
*
* @param: [token]
* @return: java.lang.String
* @date: 2023/4/3 17:46
*/
public String pushMsg(String token) throws IOException {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
Map<String, Object> params = new HashMap<>();
// 处理微信推送数据结构
JSONObject mapData = new JSONObject();
Map<String, Object> map1 = new HashMap<>();
map1.put("value", "任务名称");
mapData.put("thing2", map1);
Map<String, Object> map2 = new HashMap<>();
map2.put("value", "2023-04-03 12:00:00");
mapData.put("time3", map2);
Map<String, Object> map3 = new HashMap<>();
map3.put("value", "描述信息");
mapData.put("thing4", map3);
Map<String, Object> map4 = new HashMap<>();
map4.put("value", "备注系信息");
mapData.put("thing10", map4);
Map<String, Object> map5 = new HashMap<>();
map5.put("value", "抖音");
mapData.put("thing11", map5);
params.put("template_id", "templateId");// 模板 id
params.put("touser", "openId"); // open id
params.put("data", mapData); // 数据
params.put("page", "page"); // 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转
params.put("miniprogram_state", "trial"); //developer为开发版;trial为体验版;formal为正式版;默认为正式版
params.put("lang", "zh_CN"); //
HttpPost httpPost = new HttpPost("https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + token);
httpPost.addHeader("ContentTyp", "application/json");
// 参数转 JSON 格式
String json = objToStr(params);
StringEntity stringEntity = new StringEntity(json, CharSetType.UTF8.getType());
stringEntity.setContentEncoding(CharSetType.UTF8.getType());
httpPost.setEntity(stringEntity);
CloseableHttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity(); // 响应结果
return EntityUtils.toString(entity, CharSetType.UTF8.getType());
}
/**
* description: 对象转 字符串
* create by: Mr.Fang
*
* @param: [obj]
* @return: java.lang.String
* @date: 2023/4/3 17:45
*/
public static String objToStr(Object obj) {
ObjectMapper objectMapper = new ObjectMapper();
if (Objects.nonNull(obj)) {
try {
String jsonStr = objectMapper.writeValueAsString(obj);
return jsonStr;
} catch (JsonProcessingException var2) {
var2.printStackTrace();
}
}
return null;
}
/**
* description: map 转 URL 地址拼接
* create by: Mr.Fang
*
* @param: [url, params]
* @return: java.lang.String
* @date: 2023/4/3 17:45
*/
public String handleParams(String url, Map<String, Object> params) {
if (params.size() != 0) {
Set<Map.Entry<String, Object>> entries = params.entrySet();
String paramsString = entries.stream().map((e) -> {
try {
StringBuilder sb = new StringBuilder();
sb.append(URLEncoder.encode(e.getKey(), CharSetType.UTF8.getType()));
sb.append("=");
if (Objects.nonNull(e.getValue())) {
sb.append(URLEncoder.encode(e.getValue().toString(), CharSetType.UTF8.getType()));
}
return sb.toString();
} catch (UnsupportedEncodingException var2) {
var2.printStackTrace();
return null;
}
}).collect(Collectors.joining("&"));
return url + "?" + paramsString;
}
return url;
}
}
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm
我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c
我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI
这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub
我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我
什么是ruby的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht