diff --git a/pom.xml b/pom.xml
index 8e39fb4..2a66cba 100644
--- a/pom.xml
+++ b/pom.xml
@@ -305,6 +305,11 @@
spring-boot-starter-thymeleaf
${spring-boot.version}
+
+ org.json
+ json
+ 20090211
+
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index 289bace..473c65e 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -68,7 +68,7 @@ spring:
# redis 配置
redis:
# 地址
- host: 127.0.0.1
+ host: 192.168.31.55
# 端口,默认为6379
port: 6379
# 数据库索引
@@ -142,6 +142,5 @@ ali:
umApp:
appAliKey: 204918113
appAliSecret: v4UrIhhLZlo0adpmevyCfvThGFbrRer0
- androidKey: 687b2df479267e0210b79b6f
- IOSKey: 687b2e1679267e0210b79b70
-
+ androidKey: 68a9988ce563686f4288e26d
+ IOSKey: 68a99a66ec2b5b6f8825b8b1
diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml
index 827315c..1c4a9f8 100644
--- a/ruoyi-common/pom.xml
+++ b/ruoyi-common/pom.xml
@@ -193,7 +193,10 @@
org.springframework.boot
spring-boot-starter-thymeleaf
-
+
+
+ org.json
+ json
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/config/UmengConfig.java b/ruoyi-system/src/main/java/com/ruoyi/system/config/UmengConfig.java
index 93154c5..c13aa93 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/config/UmengConfig.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/config/UmengConfig.java
@@ -6,6 +6,9 @@ import com.ruoyi.common.constant.AliKeyConfig;
import com.ruoyi.common.core.domain.UmResp;
import com.ruoyi.common.enums.DeviceTypeEnum;
import com.ruoyi.common.utils.uuid.UUID;
+import com.ruoyi.system.config.push.AndroidNotification;
+import com.ruoyi.system.config.push.PushClient;
+import com.ruoyi.system.config.push.android.AndroidCustomizedcast;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.Header;
@@ -34,6 +37,8 @@ public class UmengConfig {
private static final Logger log = LoggerFactory.getLogger(UmengConfig.class);
+ private PushClient client = new PushClient();
+
public UmResp send(String token,String deviceTypeUp){
String umAppkey = null;
if (deviceTypeUp.equals(DeviceTypeEnum.ANDROID.name())){
@@ -108,6 +113,25 @@ public class UmengConfig {
}
+ public void sendAndroidCustomizedcast() throws Exception {
+ AndroidCustomizedcast customizedcast = new AndroidCustomizedcast(AliKeyConfig.UMApp_AliKey,AliKeyConfig.UMApp_AliSecret);
+ // TODO Set your alias here, and use comma to split them if there are multiple alias.
+ // And if you have many alias, you can also upload a file containing these alias, then
+ // use file_id to send customized notification.
+ customizedcast.setAlias("alias", "alias_type");
+ customizedcast.setTicker( "Android customizedcast ticker");
+ customizedcast.setTitle( "中文的title");
+ customizedcast.setText( "Android customizedcast text");
+ customizedcast.goAppAfterOpen();
+ customizedcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
+ // TODO Set 'production_mode' to 'false' if it's a test device.
+ // For how to register a test device, please see the developer doc.
+ customizedcast.setProductionMode();
+ //厂商通道相关参数
+ customizedcast.setChannelActivity("your channel activity");
+ customizedcast.setChannelProperties("abc");
+ client.send(customizedcast);
+ }
public static void main(String[] args) {
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/config/push/AndroidNotification.java b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/AndroidNotification.java
new file mode 100644
index 0000000..d3ca5fe
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/AndroidNotification.java
@@ -0,0 +1,198 @@
+package com.ruoyi.system.config.push;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import org.json.JSONObject;
+
+public abstract class AndroidNotification extends UmengNotification {
+ // Keys can be set in the payload level
+ protected static final HashSet PAYLOAD_KEYS = new HashSet(Arrays.asList(new String[]{
+ "display_type"}));
+
+ // Keys can be set in the body level
+ protected static final HashSet BODY_KEYS = new HashSet(Arrays.asList(new String[]{
+ "ticker", "title", "text", "builder_id", "icon", "largeIcon", "img", "play_vibrate", "play_lights", "play_sound",
+ "sound", "after_open", "url", "activity", "custom"}));
+
+ public enum DisplayType{
+ NOTIFICATION{public String getValue(){return "notification";}},///通知:消息送达到用户设备后,由友盟SDK接管处理并在通知栏上显示通知内容。
+ MESSAGE{public String getValue(){return "message";}};///消息:消息送达到用户设备后,消息内容透传给应用自身进行解析处理。
+ public abstract String getValue();
+ }
+ public enum AfterOpenAction{
+ go_app,//打开应用
+ go_url,//跳转到URL
+ go_activity,//打开特定的activity
+ go_custom//用户自定义内容。
+ }
+ // Set key/value in the rootJson, for the keys can be set please see ROOT_KEYS, PAYLOAD_KEYS,
+ // BODY_KEYS and POLICY_KEYS.
+ @Override
+ public boolean setPredefinedKeyValue(String key, Object value) throws Exception {
+ if (ROOT_KEYS.contains(key)) {
+ // This key should be in the root level
+ rootJson.put(key, value);
+ } else if (PAYLOAD_KEYS.contains(key)) {
+ // This key should be in the payload level
+ JSONObject payloadJson = null;
+ if (rootJson.has("payload")) {
+ payloadJson = rootJson.getJSONObject("payload");
+ } else {
+ payloadJson = new JSONObject();
+ rootJson.put("payload", payloadJson);
+ }
+ payloadJson.put(key, value);
+ } else if (BODY_KEYS.contains(key)) {
+ // This key should be in the body level
+ JSONObject bodyJson = null;
+ JSONObject payloadJson = null;
+ // 'body' is under 'payload', so build a payload if it doesn't exist
+ if (rootJson.has("payload")) {
+ payloadJson = rootJson.getJSONObject("payload");
+ } else {
+ payloadJson = new JSONObject();
+ rootJson.put("payload", payloadJson);
+ }
+ // Get body JSONObject, generate one if not existed
+ if (payloadJson.has("body")) {
+ bodyJson = payloadJson.getJSONObject("body");
+ } else {
+ bodyJson = new JSONObject();
+ payloadJson.put("body", bodyJson);
+ }
+ bodyJson.put(key, value);
+ } else if (POLICY_KEYS.contains(key)) {
+ // This key should be in the body level
+ JSONObject policyJson = null;
+ if (rootJson.has("policy")) {
+ policyJson = rootJson.getJSONObject("policy");
+ } else {
+ policyJson = new JSONObject();
+ rootJson.put("policy", policyJson);
+ }
+ policyJson.put(key, value);
+ } else {
+ if (key == "payload" || key == "body" || key == "policy" || key == "extra") {
+ throw new Exception("You don't need to set value for " + key + " , just set values for the sub keys in it.");
+ } else {
+ throw new Exception("Unknown key: " + key);
+ }
+ }
+ return true;
+ }
+
+ // Set extra key/value for Android notification
+ public boolean setExtraField(String key, String value) throws Exception {
+ JSONObject payloadJson = null;
+ JSONObject extraJson = null;
+ if (rootJson.has("payload")) {
+ payloadJson = rootJson.getJSONObject("payload");
+ } else {
+ payloadJson = new JSONObject();
+ rootJson.put("payload", payloadJson);
+ }
+
+ if (payloadJson.has("extra")) {
+ extraJson = payloadJson.getJSONObject("extra");
+ } else {
+ extraJson = new JSONObject();
+ payloadJson.put("extra", extraJson);
+ }
+ extraJson.put(key, value);
+ return true;
+ }
+
+ //
+ public void setDisplayType(DisplayType d) throws Exception {
+ setPredefinedKeyValue("display_type", d.getValue());
+ }
+ ///通知栏提示文字
+ public void setTicker(String ticker) throws Exception {
+ setPredefinedKeyValue("ticker", ticker);
+ }
+ ///通知标题
+ public void setTitle(String title) throws Exception {
+ setPredefinedKeyValue("title", title);
+ }
+ ///通知文字描述
+ public void setText(String text) throws Exception {
+ setPredefinedKeyValue("text", text);
+ }
+ ///用于标识该通知采用的样式。使用该参数时, 必须在SDK里面实现自定义通知栏样式。
+ public void setBuilderId(Integer builder_id) throws Exception {
+ setPredefinedKeyValue("builder_id", builder_id);
+ }
+ ///状态栏图标ID, R.drawable.[smallIcon],如果没有, 默认使用应用图标。
+ public void setIcon(String icon) throws Exception {
+ setPredefinedKeyValue("icon", icon);
+ }
+ ///通知栏拉开后左侧图标ID
+ public void setLargeIcon(String largeIcon) throws Exception {
+ setPredefinedKeyValue("largeIcon", largeIcon);
+ }
+ ///通知栏大图标的URL链接。该字段的优先级大于largeIcon。该字段要求以http或者https开头。
+ public void setImg(String img) throws Exception {
+ setPredefinedKeyValue("img", img);
+ }
+ ///收到通知是否震动,默认为"true"
+ public void setPlayVibrate(Boolean play_vibrate) throws Exception {
+ setPredefinedKeyValue("play_vibrate", play_vibrate.toString());
+ }
+ ///收到通知是否闪灯,默认为"true"
+ public void setPlayLights(Boolean play_lights) throws Exception {
+ setPredefinedKeyValue("play_lights", play_lights.toString());
+ }
+ ///收到通知是否发出声音,默认为"true"
+ public void setPlaySound(Boolean play_sound) throws Exception {
+ setPredefinedKeyValue("play_sound", play_sound.toString());
+ }
+ ///通知声音,R.raw.[sound]. 如果该字段为空,采用SDK默认的声音
+ public void setSound(String sound) throws Exception {
+ setPredefinedKeyValue("sound", sound);
+ }
+ ///收到通知后播放指定的声音文件
+ public void setPlaySound(String sound) throws Exception {
+ setPlaySound(true);
+ setSound(sound);
+ }
+
+ ///点击"通知"的后续行为,默认为打开app。
+ public void goAppAfterOpen() throws Exception {
+ setAfterOpenAction(AfterOpenAction.go_app);
+ }
+ public void goUrlAfterOpen(String url) throws Exception {
+ setAfterOpenAction(AfterOpenAction.go_url);
+ setUrl(url);
+ }
+ public void goActivityAfterOpen(String activity) throws Exception {
+ setAfterOpenAction(AfterOpenAction.go_activity);
+ setActivity(activity);
+ }
+ public void goCustomAfterOpen(String custom) throws Exception {
+ setAfterOpenAction(AfterOpenAction.go_custom);
+ setCustomField(custom);
+ }
+ public void goCustomAfterOpen(JSONObject custom) throws Exception {
+ setAfterOpenAction(AfterOpenAction.go_custom);
+ setCustomField(custom);
+ }
+
+ ///点击"通知"的后续行为,默认为打开app。原始接口
+ public void setAfterOpenAction(AfterOpenAction action) throws Exception {
+ setPredefinedKeyValue("after_open", action.toString());
+ }
+ public void setUrl(String url) throws Exception {
+ setPredefinedKeyValue("url", url);
+ }
+ public void setActivity(String activity) throws Exception {
+ setPredefinedKeyValue("activity", activity);
+ }
+ ///can be a string of json
+ public void setCustomField(String custom) throws Exception {
+ setPredefinedKeyValue("custom", custom);
+ }
+ public void setCustomField(JSONObject custom) throws Exception {
+ setPredefinedKeyValue("custom", custom);
+ }
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/config/push/App.java b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/App.java
new file mode 100644
index 0000000..d9781a5
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/App.java
@@ -0,0 +1,6 @@
+package com.ruoyi.system.config.push;
+
+
+public class App {
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/config/push/Demo.java b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/Demo.java
new file mode 100644
index 0000000..9a8de1b
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/Demo.java
@@ -0,0 +1,283 @@
+package com.ruoyi.system.config.push;
+
+
+import com.ruoyi.system.config.push.android.*;
+import com.ruoyi.system.config.push.ios.*;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+public class Demo {
+ private String appkey = null;
+ private String appMasterSecret = null;
+ private String timestamp = null;
+ private PushClient client = new PushClient();
+
+ public Demo(String key, String secret) {
+ try {
+ appkey = key;
+ appMasterSecret = secret;
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ public void sendAndroidBroadcast() throws Exception {
+ AndroidBroadcast broadcast = new AndroidBroadcast(appkey,appMasterSecret);
+ broadcast.setTicker( "Android broadcast ticker");
+ broadcast.setTitle( "中文的title");
+ broadcast.setText( "Android broadcast text");
+ broadcast.goAppAfterOpen();
+ broadcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
+ // TODO Set 'production_mode' to 'false' if it's a test device.
+ // For how to register a test device, please see the developer doc.
+ broadcast.setProductionMode();
+ // Set customized fields
+ broadcast.setExtraField("test", "helloworld");
+ //厂商通道相关参数
+ broadcast.setChannelActivity("your channel activity");
+ broadcast.setChannelProperties("abc");
+ client.send(broadcast);
+ }
+
+ public void sendAndroidUnicast() throws Exception {
+ AndroidUnicast unicast = new AndroidUnicast(appkey,appMasterSecret);
+ // TODO Set your device token
+ unicast.setDeviceToken( "your device_token");
+ unicast.setTicker( "Android unicast ticker");
+ unicast.setTitle( "中文的title");
+ unicast.setText( "Android unicast text");
+ unicast.goAppAfterOpen();
+ unicast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
+ // TODO Set 'production_mode' to 'false' if it's a test device.
+ // For how to register a test device, please see the developer doc.
+ unicast.setProductionMode();
+ // Set customized fields
+ unicast.setExtraField("test", "helloworld");
+ unicast.setChannelActivity("your channel activity");
+ unicast.setChannelProperties("abc");
+ client.send(unicast);
+ }
+
+ public void sendAndroidGroupcast() throws Exception {
+ AndroidGroupcast groupcast = new AndroidGroupcast(appkey,appMasterSecret);
+ /* TODO
+ * Construct the filter condition:
+ * "where":
+ * {
+ * "and":
+ * [
+ * {"tag":"test"},
+ * {"tag":"Test"}
+ * ]
+ * }
+ */
+ JSONObject filterJson = new JSONObject();
+ JSONObject whereJson = new JSONObject();
+ JSONArray tagArray = new JSONArray();
+ JSONObject testTag = new JSONObject();
+ JSONObject TestTag = new JSONObject();
+ testTag.put("tag", "test");
+ TestTag.put("tag", "Test");
+ tagArray.put(testTag);
+ tagArray.put(TestTag);
+ whereJson.put("and", tagArray);
+ filterJson.put("where", whereJson);
+
+ groupcast.setFilter(filterJson);
+ groupcast.setTicker( "Android groupcast ticker");
+ groupcast.setTitle( "中文的title");
+ groupcast.setText( "Android groupcast text");
+ groupcast.goAppAfterOpen();
+ groupcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
+ groupcast.setChannelActivity("your channel activity");
+ // TODO Set 'production_mode' to 'false' if it's a test device.
+ // For how to register a test device, please see the developer doc.
+ groupcast.setProductionMode();
+ //厂商通道相关参数
+ groupcast.setChannelActivity("your channel activity");
+ groupcast.setChannelProperties("abc");
+ client.send(groupcast);
+ }
+
+// public void sendAndroidCustomizedcast() throws Exception {
+// AndroidCustomizedcast customizedcast = new AndroidCustomizedcast(appkey,appMasterSecret);
+// // TODO Set your alias here, and use comma to split them if there are multiple alias.
+// // And if you have many alias, you can also upload a file containing these alias, then
+// // use file_id to send customized notification.
+// customizedcast.setAlias("alias", "alias_type");
+// customizedcast.setTicker( "Android customizedcast ticker");
+// customizedcast.setTitle( "中文的title");
+// customizedcast.setText( "Android customizedcast text");
+// customizedcast.goAppAfterOpen();
+// customizedcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
+// // TODO Set 'production_mode' to 'false' if it's a test device.
+// // For how to register a test device, please see the developer doc.
+// customizedcast.setProductionMode();
+// //厂商通道相关参数
+// customizedcast.setChannelActivity("your channel activity");
+// customizedcast.setChannelProperties("abc");
+// client.send(customizedcast);
+// }
+
+ public void sendAndroidCustomizedcastFile() throws Exception {
+ AndroidCustomizedcast customizedcast = new AndroidCustomizedcast(appkey,appMasterSecret);
+ // TODO Set your alias here, and use comma to split them if there are multiple alias.
+ // And if you have many alias, you can also upload a file containing these alias, then
+ // use file_id to send customized notification.
+ String fileId = client.uploadContents(appkey,appMasterSecret,"aa"+"\n"+"bb"+"\n"+"alias");
+ customizedcast.setFileId(fileId, "alias_type");
+ customizedcast.setTicker( "Android customizedcast ticker");
+ customizedcast.setTitle( "中文的title");
+ customizedcast.setText( "Android customizedcast text");
+ customizedcast.goAppAfterOpen();
+ customizedcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
+ // TODO Set 'production_mode' to 'false' if it's a test device.
+ // For how to register a test device, please see the developer doc.
+ customizedcast.setProductionMode();
+ //厂商通道相关参数
+ customizedcast.setChannelActivity("your channel activity");
+ customizedcast.setChannelProperties("abc");
+ client.send(customizedcast);
+ }
+
+ public void sendAndroidFilecast() throws Exception {
+ AndroidFilecast filecast = new AndroidFilecast(appkey,appMasterSecret);
+ // TODO upload your device tokens, and use '\n' to split them if there are multiple tokens
+ String fileId = client.uploadContents(appkey,appMasterSecret,"aa"+"\n"+"bb");
+ filecast.setFileId( fileId);
+ filecast.setTicker( "Android filecast ticker");
+ filecast.setTitle( "中文的title");
+ filecast.setText( "Android filecast text");
+ filecast.goAppAfterOpen();
+ filecast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
+ //厂商通道相关参数
+ filecast.setChannelActivity("your channel activity");
+ filecast.setChannelProperties("abc");
+ client.send(filecast);
+ }
+
+ public void sendIOSBroadcast() throws Exception {
+ IOSBroadcast broadcast = new IOSBroadcast(appkey,appMasterSecret);
+ //alert值设置为字符串
+ //broadcast.setAlert("IOS 广播测试");
+ //alert的值设置为字典
+ broadcast.setAlert("今日天气" , "" , "今日可能下雨🌂");
+ broadcast.setBadge( 0);
+ broadcast.setSound( "default");
+ // TODO set 'production_mode' to 'true' if your app is under production mode
+ broadcast.setTestMode();
+ // Set customized fields
+ broadcast.setCustomizedField("test", "helloworld");
+ client.send(broadcast);
+ }
+
+ public void sendIOSUnicast() throws Exception {
+ IOSUnicast unicast = new IOSUnicast(appkey,appMasterSecret);
+ // TODO Set your device token
+ unicast.setDeviceToken( "your device_token");
+ //alert值设置为字符串
+ //unicast.setAlert("IOS 单播测试");
+ //alert的值设置为字典
+ unicast.setAlert("今日天气" , "" , "今日可能下雨🌂");
+ unicast.setBadge( 0);
+ unicast.setSound( "default");
+ // TODO set 'production_mode' to 'true' if your app is under production mode
+ unicast.setTestMode();
+ // Set customized fields
+ unicast.setCustomizedField("test", "helloworld");
+ client.send(unicast);
+ }
+
+
+ public void sendIOSGroupcast() throws Exception {
+ IOSGroupcast groupcast = new IOSGroupcast(appkey,appMasterSecret);
+ /* TODO
+ * Construct the filter condition:
+ * "where":
+ * {
+ * "and":
+ * [
+ * {"tag":"iostest"}
+ * ]
+ * }
+ */
+ JSONObject filterJson = new JSONObject();
+ JSONObject whereJson = new JSONObject();
+ JSONArray tagArray = new JSONArray();
+ JSONObject testTag = new JSONObject();
+ testTag.put("tag", "iostest");
+ tagArray.put(testTag);
+ whereJson.put("and", tagArray);
+ filterJson.put("where", whereJson);
+ System.out.println(filterJson.toString());
+
+ // Set filter condition into rootJson
+ groupcast.setFilter(filterJson);
+ //groupcast.setAlert("IOS 组播测试");
+ //alert的值设置为字典
+ groupcast.setAlert("今日天气" , "subtitle" , "今日可能下雨🌂");
+ groupcast.setBadge( 0);
+ groupcast.setSound( "default");
+ // TODO set 'production_mode' to 'true' if your app is under production mode
+ groupcast.setTestMode();
+ client.send(groupcast);
+ }
+
+ public void sendIOSCustomizedcast() throws Exception {
+ IOSCustomizedcast customizedcast = new IOSCustomizedcast(appkey,appMasterSecret);
+ // TODO Set your alias and alias_type here, and use comma to split them if there are multiple alias.
+ // And if you have many alias, you can also upload a file containing these alias, then
+ // use file_id to send customized notification.
+ customizedcast.setAlias("alias", "alias_type");
+ //customizedcast.setAlert("IOS 个性化测试");
+ //alert的值设置为字典
+ customizedcast.setAlert("今日天气" , "" , "今日可能下雨🌂");
+ customizedcast.setBadge( 0);
+ customizedcast.setSound( "default");
+ // TODO set 'production_mode' to 'true' if your app is under production mode
+ customizedcast.setTestMode();
+ client.send(customizedcast);
+ }
+
+ public void sendIOSFilecast() throws Exception {
+ IOSFilecast filecast = new IOSFilecast(appkey,appMasterSecret);
+ // TODO upload your device tokens, and use '\n' to split them if there are multiple tokens
+ String fileId = client.uploadContents(appkey,appMasterSecret,"aa"+"\n"+"bb");
+ filecast.setFileId( fileId);
+ //filecast.setAlert("IOS 文件播测试");
+ //alert的值设置为字典
+ filecast.setAlert("今日天气" , "" , "今日可能下雨🌂");
+ filecast.setBadge( 0);
+ filecast.setSound( "default");
+ // TODO set 'production_mode' to 'true' if your app is under production mode
+ filecast.setTestMode();
+ client.send(filecast);
+ }
+
+ public static void main(String[] args) {
+ // TODO set your appkey and master secret here
+ Demo demo = new Demo("your appkey", "your master secret");
+ try {
+ demo.sendAndroidUnicast();
+ //demo.sendIOSUnicast();
+ /* TODO these methods are all available, just fill in some fields and do the test
+ * demo.sendAndroidCustomizedcastFile();
+ * demo.sendAndroidBroadcast();
+ * demo.sendAndroidGroupcast();
+ * demo.sendAndroidCustomizedcast();
+ * demo.sendAndroidFilecast();
+ *
+ * demo.sendIOSBroadcast();
+ * demo.sendIOSUnicast();
+ * demo.sendIOSGroupcast();
+ * demo.sendIOSCustomizedcast();
+ * demo.sendIOSFilecast();
+ */
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/config/push/IOSNotification.java b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/IOSNotification.java
new file mode 100644
index 0000000..814a800
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/IOSNotification.java
@@ -0,0 +1,93 @@
+package com.ruoyi.system.config.push;
+
+import java.util.Arrays;
+import java.util.HashSet;
+
+import org.json.JSONObject;
+
+public abstract class IOSNotification extends UmengNotification {
+
+ // Keys can be set in the aps level
+ protected static final HashSet APS_KEYS = new HashSet(Arrays.asList(new String[]{
+ "alert", "badge", "sound", "content-available"
+ }));
+
+ @Override
+ public boolean setPredefinedKeyValue(String key, Object value) throws Exception {
+ if (ROOT_KEYS.contains(key)) {
+ // This key should be in the root level
+ rootJson.put(key, value);
+ } else if (APS_KEYS.contains(key)) {
+ // This key should be in the aps level
+ JSONObject apsJson = null;
+ JSONObject payloadJson = null;
+ if (rootJson.has("payload")) {
+ payloadJson = rootJson.getJSONObject("payload");
+ } else {
+ payloadJson = new JSONObject();
+ rootJson.put("payload", payloadJson);
+ }
+ if (payloadJson.has("aps")) {
+ apsJson = payloadJson.getJSONObject("aps");
+ } else {
+ apsJson = new JSONObject();
+ payloadJson.put("aps", apsJson);
+ }
+ apsJson.put(key, value);
+ } else if (POLICY_KEYS.contains(key)) {
+ // This key should be in the body level
+ JSONObject policyJson = null;
+ if (rootJson.has("policy")) {
+ policyJson = rootJson.getJSONObject("policy");
+ } else {
+ policyJson = new JSONObject();
+ rootJson.put("policy", policyJson);
+ }
+ policyJson.put(key, value);
+ } else {
+ if (key == "payload" || key == "aps" || key == "policy") {
+ throw new Exception("You don't need to set value for " + key + " , just set values for the sub keys in it.");
+ } else {
+ throw new Exception("Unknownd key: " + key);
+ }
+ }
+
+ return true;
+ }
+ // Set customized key/value for IOS notification
+ public boolean setCustomizedField(String key, String value) throws Exception {
+ //rootJson.put(key, value);
+ JSONObject payloadJson = null;
+ if (rootJson.has("payload")) {
+ payloadJson = rootJson.getJSONObject("payload");
+ } else {
+ payloadJson = new JSONObject();
+ rootJson.put("payload", payloadJson);
+ }
+ payloadJson.put(key, value);
+ return true;
+ }
+
+ public void setAlert(String token) throws Exception {
+ setPredefinedKeyValue("alert", token);
+ }
+
+ public void setAlert(String title ,String subtitle , String body) throws Exception{
+ JSONObject object = new JSONObject();
+ object.put("title" , title);
+ object.put("subtitle" , subtitle);
+ object.put("body" , body);
+ setPredefinedKeyValue("alert",object );
+ }
+ public void setBadge(Integer badge) throws Exception {
+ setPredefinedKeyValue("badge", badge);
+ }
+
+ public void setSound(String sound) throws Exception {
+ setPredefinedKeyValue("sound", sound);
+ }
+
+ public void setContentAvailable(Integer contentAvailable) throws Exception {
+ setPredefinedKeyValue("content-available", contentAvailable);
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/config/push/PushClient.java b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/PushClient.java
new file mode 100644
index 0000000..3625b92
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/PushClient.java
@@ -0,0 +1,100 @@
+package com.ruoyi.system.config.push;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+import com.alibaba.fastjson2.JSONObject;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+public class PushClient {
+
+ // The user agent
+ protected final String USER_AGENT = "Mozilla/5.0";
+
+ // This object is used for sending the post request to Umeng
+ protected HttpClient client = new DefaultHttpClient();
+
+ // The host
+ protected static final String host = "http://msg.umeng.com";
+
+ // The upload path
+ protected static final String uploadPath = "/upload";
+
+ // The post path
+ protected static final String postPath = "/api/send";
+
+ public boolean send(UmengNotification msg) throws Exception {
+ String timestamp = Integer.toString((int)(System.currentTimeMillis() / 1000));
+ msg.setPredefinedKeyValue("timestamp", timestamp);
+ String url = host + postPath;
+ String postBody = msg.getPostBody();
+ String sign = DigestUtils.md5Hex(("POST" + url + postBody + msg.getAppMasterSecret()).getBytes("utf8"));
+ url = url + "?sign=" + sign;
+ HttpPost post = new HttpPost(url);
+ post.setHeader("User-Agent", USER_AGENT);
+ StringEntity se = new StringEntity(postBody, "UTF-8");
+ post.setEntity(se);
+ // Send the post request and get the response
+ HttpResponse response = client.execute(post);
+ int status = response.getStatusLine().getStatusCode();
+ System.out.println("Response Code : " + status);
+ BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
+ StringBuffer result = new StringBuffer();
+ String line = "";
+ while ((line = rd.readLine()) != null) {
+ result.append(line);
+ }
+ System.out.println(result);
+ if (status == 200) {
+ System.out.println("Notification sent successfully.");
+ } else {
+ System.out.println("Failed to send the notification!");
+ }
+ return true;
+ }
+
+ // Upload file with device_tokens to Umeng
+ public String uploadContents(String appkey,String appMasterSecret,String contents) throws Exception {
+ // Construct the json string
+ JSONObject uploadJson = new JSONObject();
+ uploadJson.put("appkey", appkey);
+ String timestamp = Integer.toString((int)(System.currentTimeMillis() / 1000));
+ uploadJson.put("timestamp", timestamp);
+ uploadJson.put("content", contents);
+ // Construct the request
+ String url = host + uploadPath;
+ String postBody = uploadJson.toString();
+ String sign = DigestUtils.md5Hex(("POST" + url + postBody + appMasterSecret).getBytes("utf8"));
+ url = url + "?sign=" + sign;
+ HttpPost post = new HttpPost(url);
+ post.setHeader("User-Agent", USER_AGENT);
+ StringEntity se = new StringEntity(postBody, "UTF-8");
+ post.setEntity(se);
+ // Send the post request and get the response
+ HttpResponse response = client.execute(post);
+ System.out.println("Response Code : " + response.getStatusLine().getStatusCode());
+ BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
+ StringBuffer result = new StringBuffer();
+ String line = "";
+ while ((line = rd.readLine()) != null) {
+ result.append(line);
+ }
+ System.out.println(result.toString());
+ // Decode response string and get file_id from it
+ JSONObject respJson = JSONObject.parseObject(result.toString());
+ String ret = respJson.getString("ret");
+ if (!ret.equals("SUCCESS")) {
+ throw new Exception("Failed to upload file");
+ }
+ JSONObject data = respJson.getJSONObject("data");
+ String fileId = data.getString("file_id");
+ // Set file_id into rootJson using setPredefinedKeyValue
+
+ return fileId;
+ }
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/config/push/UmengNotification.java b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/UmengNotification.java
new file mode 100644
index 0000000..34c02fc
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/UmengNotification.java
@@ -0,0 +1,87 @@
+package com.ruoyi.system.config.push;
+
+
+import org.json.JSONObject;
+
+import java.util.Arrays;
+import java.util.HashSet;
+
+public abstract class UmengNotification {
+ // This JSONObject is used for constructing the whole request string.
+ protected final JSONObject rootJson = new JSONObject();
+
+
+ // The app master secret
+ protected String appMasterSecret;
+
+ // Keys can be set in the root level
+ protected static final HashSet ROOT_KEYS = new HashSet(Arrays.asList(new String[]{
+ "appkey", "timestamp", "type", "device_tokens", "alias", "alias_type", "file_id",
+ "filter", "production_mode", "feedback", "description", "thirdparty_id" , "mipush" , "mi_activity" , "channel_properties"}));
+
+ // Keys can be set in the policy level
+ protected static final HashSet POLICY_KEYS = new HashSet(Arrays.asList(new String[]{
+ "start_time", "expire_time", "max_send_num"
+ }));
+
+ // Set predefined keys in the rootJson, for extra keys(Android) or customized keys(IOS) please
+ // refer to corresponding methods in the subclass.
+ public abstract boolean setPredefinedKeyValue(String key, Object value) throws Exception;
+ public void setAppMasterSecret(String secret) {
+ appMasterSecret = secret;
+ }
+
+ public String getPostBody(){
+ return rootJson.toString();
+ }
+
+ protected final String getAppMasterSecret(){
+ return appMasterSecret;
+ }
+
+ protected void setProductionMode(Boolean prod) throws Exception {
+ setPredefinedKeyValue("production_mode", prod.toString());
+ }
+
+ ///正式模式
+ public void setProductionMode() throws Exception {
+ setProductionMode(true);
+ }
+
+ ///测试模式
+ public void setTestMode() throws Exception {
+ setProductionMode(false);
+ }
+
+ ///发送消息描述,建议填写。
+ public void setDescription(String description) throws Exception {
+ setPredefinedKeyValue("description", description);
+ }
+
+ ///定时发送时间,若不填写表示立即发送。格式: "YYYY-MM-DD hh:mm:ss"。
+ public void setStartTime(String startTime) throws Exception {
+ setPredefinedKeyValue("start_time", startTime);
+ }
+ ///消息过期时间,格式: "YYYY-MM-DD hh:mm:ss"。
+ public void setExpireTime(String expireTime) throws Exception {
+ setPredefinedKeyValue("expire_time", expireTime);
+ }
+ ///发送限速,每秒发送的最大条数。
+ public void setMaxSendNum(Integer num) throws Exception {
+ setPredefinedKeyValue("max_send_num", num);
+ }
+
+ //厂商弹窗activity
+ public void setChannelActivity(String activity) throws Exception{
+ setPredefinedKeyValue("mipush", "true");
+ setPredefinedKeyValue("mi_activity",activity );
+ }
+
+ //厂商属性配置
+ public void setChannelProperties(String xiaoMiChannelId) throws Exception{
+ JSONObject object = new JSONObject();
+ object.put("xiaomi_channel_id" , xiaoMiChannelId);
+ setPredefinedKeyValue("channel_properties", object);
+ }
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/config/push/android/AndroidBroadcast.java b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/android/AndroidBroadcast.java
new file mode 100644
index 0000000..98fa1f9
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/android/AndroidBroadcast.java
@@ -0,0 +1,11 @@
+package com.ruoyi.system.config.push.android;
+
+import com.ruoyi.system.config.push.AndroidNotification;
+
+public class AndroidBroadcast extends AndroidNotification {
+ public AndroidBroadcast(String appkey,String appMasterSecret) throws Exception {
+ setAppMasterSecret(appMasterSecret);
+ setPredefinedKeyValue("appkey", appkey);
+ this.setPredefinedKeyValue("type", "broadcast");
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/config/push/android/AndroidCustomizedcast.java b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/android/AndroidCustomizedcast.java
new file mode 100644
index 0000000..b5fc7f4
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/android/AndroidCustomizedcast.java
@@ -0,0 +1,22 @@
+package com.ruoyi.system.config.push.android;
+
+import com.ruoyi.system.config.push.AndroidNotification;
+
+public class AndroidCustomizedcast extends AndroidNotification {
+ public AndroidCustomizedcast(String appkey,String appMasterSecret) throws Exception {
+ setAppMasterSecret(appMasterSecret);
+ setPredefinedKeyValue("appkey", appkey);
+ this.setPredefinedKeyValue("type", "customizedcast");
+ }
+
+ public void setAlias(String alias,String aliasType) throws Exception {
+ setPredefinedKeyValue("alias", alias);
+ setPredefinedKeyValue("alias_type", aliasType);
+ }
+
+ public void setFileId(String fileId,String aliasType) throws Exception {
+ setPredefinedKeyValue("file_id", fileId);
+ setPredefinedKeyValue("alias_type", aliasType);
+ }
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/config/push/android/AndroidFilecast.java b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/android/AndroidFilecast.java
new file mode 100644
index 0000000..cd4ea4d
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/android/AndroidFilecast.java
@@ -0,0 +1,15 @@
+package com.ruoyi.system.config.push.android;
+
+import com.ruoyi.system.config.push.AndroidNotification;
+
+public class AndroidFilecast extends AndroidNotification {
+ public AndroidFilecast(String appkey,String appMasterSecret) throws Exception {
+ setAppMasterSecret(appMasterSecret);
+ setPredefinedKeyValue("appkey", appkey);
+ this.setPredefinedKeyValue("type", "filecast");
+ }
+
+ public void setFileId(String fileId) throws Exception {
+ setPredefinedKeyValue("file_id", fileId);
+ }
+}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/config/push/android/AndroidGroupcast.java b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/android/AndroidGroupcast.java
new file mode 100644
index 0000000..1f0300f
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/android/AndroidGroupcast.java
@@ -0,0 +1,16 @@
+package com.ruoyi.system.config.push.android;
+
+import com.ruoyi.system.config.push.AndroidNotification;
+import org.json.JSONObject;
+
+public class AndroidGroupcast extends AndroidNotification {
+ public AndroidGroupcast(String appkey,String appMasterSecret) throws Exception {
+ setAppMasterSecret(appMasterSecret);
+ setPredefinedKeyValue("appkey", appkey);
+ this.setPredefinedKeyValue("type", "groupcast");
+ }
+
+ public void setFilter(JSONObject filter) throws Exception {
+ setPredefinedKeyValue("filter", filter);
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/config/push/android/AndroidUnicast.java b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/android/AndroidUnicast.java
new file mode 100644
index 0000000..ffee49f
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/android/AndroidUnicast.java
@@ -0,0 +1,16 @@
+package com.ruoyi.system.config.push.android;
+
+import com.ruoyi.system.config.push.AndroidNotification;
+
+public class AndroidUnicast extends AndroidNotification {
+ public AndroidUnicast(String appkey,String appMasterSecret) throws Exception {
+ setAppMasterSecret(appMasterSecret);
+ setPredefinedKeyValue("appkey", appkey);
+ this.setPredefinedKeyValue("type", "unicast");
+ }
+
+ public void setDeviceToken(String token) throws Exception {
+ setPredefinedKeyValue("device_tokens", token);
+ }
+
+}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/config/push/ios/IOSBroadcast.java b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/ios/IOSBroadcast.java
new file mode 100644
index 0000000..54bf6ec
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/ios/IOSBroadcast.java
@@ -0,0 +1,12 @@
+package com.ruoyi.system.config.push.ios;
+
+import com.ruoyi.system.config.push.IOSNotification;
+
+public class IOSBroadcast extends IOSNotification {
+ public IOSBroadcast(String appkey,String appMasterSecret) throws Exception {
+ setAppMasterSecret(appMasterSecret);
+ setPredefinedKeyValue("appkey", appkey);
+ this.setPredefinedKeyValue("type", "broadcast");
+
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/config/push/ios/IOSCustomizedcast.java b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/ios/IOSCustomizedcast.java
new file mode 100644
index 0000000..b9ba2bf
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/ios/IOSCustomizedcast.java
@@ -0,0 +1,22 @@
+package com.ruoyi.system.config.push.ios;
+
+import com.ruoyi.system.config.push.IOSNotification;
+
+public class IOSCustomizedcast extends IOSNotification {
+ public IOSCustomizedcast(String appkey,String appMasterSecret) throws Exception {
+ setAppMasterSecret(appMasterSecret);
+ setPredefinedKeyValue("appkey", appkey);
+ this.setPredefinedKeyValue("type", "customizedcast");
+ }
+
+ public void setAlias(String alias,String aliasType) throws Exception {
+ setPredefinedKeyValue("alias", alias);
+ setPredefinedKeyValue("alias_type", aliasType);
+ }
+
+ public void setFileId(String fileId, String aliasType) throws Exception {
+ setPredefinedKeyValue("file_id", fileId);
+ setPredefinedKeyValue("alias_type", aliasType);
+ }
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/config/push/ios/IOSFilecast.java b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/ios/IOSFilecast.java
new file mode 100644
index 0000000..aeecff8
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/ios/IOSFilecast.java
@@ -0,0 +1,15 @@
+package com.ruoyi.system.config.push.ios;
+
+import com.ruoyi.system.config.push.IOSNotification;
+
+public class IOSFilecast extends IOSNotification {
+ public IOSFilecast(String appkey,String appMasterSecret) throws Exception {
+ setAppMasterSecret(appMasterSecret);
+ setPredefinedKeyValue("appkey", appkey);
+ this.setPredefinedKeyValue("type", "filecast");
+ }
+
+ public void setFileId(String fileId) throws Exception {
+ setPredefinedKeyValue("file_id", fileId);
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/config/push/ios/IOSGroupcast.java b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/ios/IOSGroupcast.java
new file mode 100644
index 0000000..3b99ace
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/ios/IOSGroupcast.java
@@ -0,0 +1,16 @@
+package com.ruoyi.system.config.push.ios;
+
+import com.ruoyi.system.config.push.IOSNotification;
+import org.json.JSONObject;
+
+public class IOSGroupcast extends IOSNotification {
+ public IOSGroupcast(String appkey,String appMasterSecret) throws Exception {
+ setAppMasterSecret(appMasterSecret);
+ setPredefinedKeyValue("appkey", appkey);
+ this.setPredefinedKeyValue("type", "groupcast");
+ }
+
+ public void setFilter(JSONObject filter) throws Exception {
+ setPredefinedKeyValue("filter", filter);
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/config/push/ios/IOSUnicast.java b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/ios/IOSUnicast.java
new file mode 100644
index 0000000..37f8d2f
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/config/push/ios/IOSUnicast.java
@@ -0,0 +1,15 @@
+package com.ruoyi.system.config.push.ios;
+
+import com.ruoyi.system.config.push.IOSNotification;
+
+public class IOSUnicast extends IOSNotification {
+ public IOSUnicast(String appkey,String appMasterSecret) throws Exception{
+ setAppMasterSecret(appMasterSecret);
+ setPredefinedKeyValue("appkey", appkey);
+ this.setPredefinedKeyValue("type", "unicast");
+ }
+
+ public void setDeviceToken(String token) throws Exception {
+ setPredefinedKeyValue("device_tokens", token);
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/NotificationsServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/NotificationsServiceImpl.java
index da4b5ab..9224997 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/NotificationsServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/NotificationsServiceImpl.java
@@ -142,11 +142,11 @@ public class NotificationsServiceImpl implements INotificationsService
for (NotificationRecords record : records)
{
// 如果记录已经发送过,则不再创建新记录,只更新状态
+ boolean sendResult = sendNotificationToThirdParty(notification, record);
if ("sent".equals(record.getStatus()))
{
// 调用第三方接口发送通知
- boolean sendResult = sendNotificationToThirdParty(notification, record);
-
+
if (sendResult)
{
successCount++;
@@ -162,8 +162,7 @@ public class NotificationsServiceImpl implements INotificationsService
else
{
// 调用第三方接口发送通知
- boolean sendResult = sendNotificationToThirdParty(notification, record);
-
+
if (sendResult)
{
// 更新记录状态为已发送