Skip to content

Commit f2b0548

Browse files
klausxiebinarywang
authored andcommitted
binarywang#436 添加一次性订阅消息接口
1 parent be50ea0 commit f2b0548

File tree

14 files changed

+336
-2
lines changed

14 files changed

+336
-2
lines changed

demo.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
1. 微信支付Demo:[码云](http://gitee.com/binary/weixin-java-pay-demo)[GitHub](http://github.com/binarywang/weixin-java-pay-demo)
66
1. 企业号/企业微信Demo:[码云](http://gitee.com/binary/weixin-java-cp-demo)[GitHub](http://github.com/binarywang/weixin-java-cp-demo)
77
1. 微信小程序Demo:[码云](http://gitee.com/binary/weixin-java-miniapp-demo)[GitHub](http://github.com/binarywang/weixin-java-miniapp-demo)
8-
1. 开放平台Demo:[码云](http://gitee.com/binary/weixin-java-open-demo)[GitHub](http://github.com/binarywang/weixin-java-open-demo)
8+
1. 开放平台Demo:[码云](http://gitee.com/binary/weixin-java-open-demo)[GitHub](http://github.com/Wechat-Group/weixin-java-open-demo)
99
1. 公众号Demo:
1010
- 使用Spring MVC实现的公众号Demo:[码云](http://gitee.com/binary/weixin-java-mp-demo)、[GitHub](http://github.com/binarywang/weixin-java-mp-demo)
1111
- 使用Spring Boot实现的公众号Demo:[码云](http://gitee.com/binary/weixin-java-mp-demo-springboot)、[GitHub](http://github.com/binarywang/weixin-java-mp-demo-springboot)

weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ public interface WxMpConfigStorage {
8585

8686
String getAesKey();
8787

88+
String getTemplateId();
89+
8890
long getExpiresTime();
8991

9092
String getOauth2redirectUri();

weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
1818
protected volatile String appId;
1919
protected volatile String secret;
2020
protected volatile String token;
21+
protected volatile String templateId;
2122
protected volatile String accessToken;
2223
protected volatile String aesKey;
2324
protected volatile long expiresTime;
@@ -173,6 +174,15 @@ public void setToken(String token) {
173174
this.token = token;
174175
}
175176

177+
@Override
178+
public String getTemplateId() {
179+
return this.templateId;
180+
}
181+
182+
public void setTemplateId(String templateId) {
183+
this.templateId = templateId;
184+
}
185+
176186
@Override
177187
public long getExpiresTime() {
178188
return this.expiresTime;

weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,13 @@ public interface WxMpService {
363363
*/
364364
WxMpTemplateMsgService getTemplateMsgService();
365365

366+
/**
367+
* 返回一次性订阅消息相关接口方法的实现类对象,以方便调用其各个接口
368+
*
369+
* @return WxMpSubscribeMsgService
370+
*/
371+
WxMpSubscribeMsgService getSubscribeMsgService();
372+
366373
/**
367374
* 返回硬件平台相关接口方法的实现类对象,以方便调用其各个接口
368375
*
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package me.chanjar.weixin.mp.api;
2+
3+
import me.chanjar.weixin.common.exception.WxErrorException;
4+
import me.chanjar.weixin.mp.bean.subscribe.WxMpSubscribeMessage;
5+
6+
/**
7+
* <pre>
8+
* 一次性订阅消息接口
9+
* https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1500374289_66bvB
10+
* </pre>
11+
*
12+
* @author Mklaus
13+
* @date 2018-01-22 上午11:07
14+
*/
15+
public interface WxMpSubscribeMsgService {
16+
17+
/**
18+
* <pre>
19+
* 构造用户订阅一条模板消息授权的url连接
20+
* 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1500374289_66bvB
21+
* </pre>
22+
*
23+
* @param redirectURI 用户授权完成后的重定向链接,无需urlencode, 方法内会进行encode
24+
* @param scene 重定向后会带上scene参数,开发者可以填0-10000的整形值,用来标识订阅场景值
25+
* @param reserved 用于保持请求和回调的状态,授权请后原样带回给第三方 (最多128字节,要求做urlencode)
26+
* @return url
27+
*/
28+
String subscribeMsgAuthorizationUrl(String redirectURI, int scene, String reserved);
29+
30+
/**
31+
* <pre>
32+
* 发送一次性订阅消息
33+
* 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1500374289_66bvB
34+
* </pre>
35+
*
36+
* @return 消息Id
37+
*/
38+
boolean sendSubscribeMessage(WxMpSubscribeMessage message) throws WxErrorException;
39+
40+
}

weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceAbstractImpl.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public abstract class WxMpServiceAbstractImpl<H, P> implements WxMpService, Requ
4040
private WxMpDataCubeService dataCubeService = new WxMpDataCubeServiceImpl(this);
4141
private WxMpUserBlacklistService blackListService = new WxMpUserBlacklistServiceImpl(this);
4242
private WxMpTemplateMsgService templateMsgService = new WxMpTemplateMsgServiceImpl(this);
43+
private WxMpSubscribeMsgService subscribeMsgService = new WxMpSubscribeMsgServiceImpl(this);
4344
private WxMpDeviceService deviceService = new WxMpDeviceServiceImpl(this);
4445
private WxMpShakeService shakeService = new WxMpShakeServiceImpl(this);
4546
private WxMpMemberCardService memberCardService = new WxMpMemberCardServiceImpl(this);
@@ -375,6 +376,11 @@ public WxMpTemplateMsgService getTemplateMsgService() {
375376
return this.templateMsgService;
376377
}
377378

379+
@Override
380+
public WxMpSubscribeMsgService getSubscribeMsgService() {
381+
return this.subscribeMsgService;
382+
}
383+
378384
@Override
379385
public WxMpDeviceService getDeviceService() {
380386
return this.deviceService;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package me.chanjar.weixin.mp.api.impl;
2+
3+
import me.chanjar.weixin.common.exception.WxErrorException;
4+
import me.chanjar.weixin.common.util.http.URIUtil;
5+
import me.chanjar.weixin.mp.api.WxMpConfigStorage;
6+
import me.chanjar.weixin.mp.api.WxMpService;
7+
import me.chanjar.weixin.mp.api.WxMpSubscribeMsgService;
8+
import me.chanjar.weixin.mp.bean.subscribe.WxMpSubscribeMessage;
9+
10+
/**
11+
* @author Mklaus
12+
* @date 2018-01-22 上午11:19
13+
*/
14+
public class WxMpSubscribeMsgServiceImpl implements WxMpSubscribeMsgService {
15+
private static final String SUBSCRIBE_MESSAGE_AUTHORIZE_URL =
16+
"https://mp.weixin.qq.com/mp/subscribemsg?action=get_confirm&appid=%s&scene=%d&template_id=%s&redirect_url=%s&reserved=%s#wechat_redirect";
17+
private static final String SEND_MESSAGE_URL = "https://api.weixin.qq.com/cgi-bin/message/template/subscribe";
18+
19+
20+
private WxMpService wxMpService;
21+
22+
public WxMpSubscribeMsgServiceImpl(WxMpService wxMpService) {
23+
this.wxMpService = wxMpService;
24+
}
25+
26+
@Override
27+
public String subscribeMsgAuthorizationUrl(String redirectURI, int scene, String reserved) {
28+
WxMpConfigStorage storage = this.wxMpService.getWxMpConfigStorage();
29+
return String.format(SUBSCRIBE_MESSAGE_AUTHORIZE_URL,
30+
storage.getAppId(), scene, storage.getTemplateId(), URIUtil.encodeURIComponent(redirectURI), reserved);
31+
}
32+
33+
@Override
34+
public boolean sendSubscribeMessage(WxMpSubscribeMessage message) throws WxErrorException {
35+
if (message.getTemplateId() == null) {
36+
message.setTemplateId(this.wxMpService.getWxMpConfigStorage().getTemplateId());
37+
}
38+
39+
String responseContent = this.wxMpService.post(SEND_MESSAGE_URL, message.toJson());
40+
return responseContent != null;
41+
}
42+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package me.chanjar.weixin.mp.bean.subscribe;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Builder;
5+
import lombok.Data;
6+
import lombok.NoArgsConstructor;
7+
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
8+
import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
9+
10+
/**
11+
* @author Mklaus
12+
* @date 2018-01-22 下午12:18
13+
*/
14+
@Data
15+
@NoArgsConstructor
16+
@Builder
17+
@AllArgsConstructor
18+
public class WxMpSubscribeMessage {
19+
20+
/**
21+
* 接收者openid.
22+
*/
23+
private String toUser;
24+
25+
/**
26+
* 模板ID.
27+
*/
28+
private String templateId;
29+
30+
/**
31+
* 模板跳转链接.
32+
* <pre>
33+
* url和miniprogram都是非必填字段,若都不传则模板无跳转;若都传,会优先跳转至小程序。
34+
* 开发者可根据实际需要选择其中一种跳转方式即可。当用户的微信客户端版本不支持跳小程序时,将会跳转至url。
35+
* </pre>
36+
*/
37+
private String url;
38+
39+
/**
40+
* 跳小程序所需数据,不需跳小程序可不用传该数据.
41+
*
42+
* @see #url
43+
*/
44+
private WxMpTemplateMessage.MiniProgram miniProgram;
45+
46+
/**
47+
* 订阅场景值
48+
*/
49+
private String scene;
50+
51+
/**
52+
* 消息标题 (15字以内)
53+
*/
54+
private String title;
55+
56+
/**
57+
* 消息内容文本 (200字以内)
58+
*/
59+
private String contentValue;
60+
61+
/**
62+
* 消息内容文本颜色
63+
*/
64+
private String contentColor;
65+
66+
67+
public String toJson() {
68+
return WxMpGsonBuilder.INSTANCE.create().toJson(this);
69+
}
70+
71+
72+
}

weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUserInfoResult;
1111
import me.chanjar.weixin.mp.bean.material.*;
1212
import me.chanjar.weixin.mp.bean.result.*;
13+
import me.chanjar.weixin.mp.bean.subscribe.WxMpSubscribeMessage;
1314
import me.chanjar.weixin.mp.bean.template.WxMpTemplateIndustry;
1415
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
1516

@@ -30,6 +31,7 @@ public class WxMpGsonBuilder {
3031
INSTANCE.registerTypeAdapter(WxMpMassUploadResult.class, new WxMpMassUploadResultAdapter());
3132
INSTANCE.registerTypeAdapter(WxMpQrCodeTicket.class, new WxQrCodeTicketAdapter());
3233
INSTANCE.registerTypeAdapter(WxMpTemplateMessage.class, new WxMpTemplateMessageGsonAdapter());
34+
INSTANCE.registerTypeAdapter(WxMpSubscribeMessage.class, new WxMpSubscribeMessageGsonAdapter());
3335
INSTANCE.registerTypeAdapter(WxMpSemanticQueryResult.class, new WxMpSemanticQueryResultAdapter());
3436
INSTANCE.registerTypeAdapter(WxMpOAuth2AccessToken.class, new WxMpOAuth2AccessTokenAdapter());
3537
INSTANCE.registerTypeAdapter(WxDataCubeUserSummary.class, new WxMpUserSummaryGsonAdapter());
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package me.chanjar.weixin.mp.util.json;
2+
3+
import com.google.gson.JsonElement;
4+
import com.google.gson.JsonObject;
5+
import com.google.gson.JsonSerializationContext;
6+
import com.google.gson.JsonSerializer;
7+
import me.chanjar.weixin.mp.bean.subscribe.WxMpSubscribeMessage;
8+
9+
import java.lang.reflect.Type;
10+
11+
/**
12+
* @author Mklaus
13+
* @date 2018-01-22 下午12:31
14+
*/
15+
public class WxMpSubscribeMessageGsonAdapter implements JsonSerializer<WxMpSubscribeMessage> {
16+
17+
@Override
18+
public JsonElement serialize(WxMpSubscribeMessage message, Type type, JsonSerializationContext jsonSerializationContext) {
19+
JsonObject messageJson = new JsonObject();
20+
messageJson.addProperty("touser", message.getToUser());
21+
messageJson.addProperty("template_id", message.getTemplateId());
22+
23+
if (message.getUrl() != null) {
24+
messageJson.addProperty("url", message.getUrl());
25+
}
26+
27+
if (message.getMiniProgram() != null) {
28+
JsonObject miniProgramJson = new JsonObject();
29+
miniProgramJson.addProperty("appid", message.getMiniProgram().getAppid());
30+
miniProgramJson.addProperty("pagepath", message.getMiniProgram().getPagePath());
31+
messageJson.add("miniprogram", miniProgramJson);
32+
}
33+
34+
messageJson.addProperty("scene", message.getScene());
35+
messageJson.addProperty("title", message.getTitle());
36+
37+
JsonObject data = new JsonObject();
38+
messageJson.add("data", data);
39+
40+
JsonObject content = new JsonObject();
41+
data.add("content", content);
42+
43+
if (message.getContentValue() != null) {
44+
content.addProperty("value", message.getContentValue());
45+
}
46+
47+
if (message.getContentColor() != null) {
48+
content.addProperty("color", message.getContentColor());
49+
}
50+
51+
return messageJson;
52+
53+
}
54+
}

0 commit comments

Comments
 (0)