From 6112c7f6398221b78624cde0129ecf23fe5c94ab Mon Sep 17 00:00:00 2001
From: 15004070936 <1097449274@qq.com>
Date: Fri, 17 Jul 2026 14:06:31 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
ruoyi-admin/ruoyi-admin.iml | 57 +-
.../basic/AppreciateController.java | 2 +-
.../controller/basic/HealthyController.java | 2 +-
.../controller/basic/InheritController.java | 2 +-
.../web/controller/basic/MyController.java | 2 +-
.../basic/PracticeMomentsController.java | 2 +-
.../web/controller/basic/SenseController.java | 2 +-
.../controller/course/CourseController.java | 2 +-
.../web/controller/im/FriendController.java | 14 +-
.../web/controller/im/GroupController.java | 8 +-
.../controller/im/GroupMessageController.java | 12 +-
.../im/PrivateMessageController.java | 12 +-
.../controller/login/AppLoginController.java | 18 +-
.../controller/login/CaptchaController.java | 26 +-
.../src/main/resources/application.yml | 1 +
ruoyi-common/pom.xml | 13 +-
.../common/core/domain/entity/AppUser.java | 7 +-
.../core/domain/model/AppUserLoginBody.java | 5 +
.../ruoyi/common/db/SshContextListener.java | 4 +-
.../common/im/model/IMPrivateMessage.java | 3 +
.../com/ruoyi/common/im/model/IMUserInfo.java | 8 +-
.../ruoyi/common/utils/JpushClientUtil.java | 794 ++++++------------
.../service/AppUserDetailsServiceImpl.java | 2 +
.../com/ruoyi/imclient/sender/IMSender.java | 5 +-
.../com/ruoyi/imclient/sender/IMSender.class | Bin 13107 -> 13107 bytes
.../processor/GroupMessageProcessor.java | 4 +-
.../processor/PrivateMessageProcessor.java | 6 +-
.../imserver/util/LongToStringConverter.java | 45 +
.../src/main/resources/application-druid.yml | 2 +-
.../domain/question/QuestionAnswerSheet.java | 4 +-
.../question/QuestionConstitutionScore.java | 2 +-
.../question/QuestionConstitutionType.java | 8 +-
.../domain/question/QuestionQuestion.java | 4 +-
.../impl/QuestionnaireServiceImpl.java | 20 +-
.../com/ruoyi/course/domain/res/RespBook.java | 2 +-
.../ruoyi/course/domain/res/RespStuBook.java | 3 +-
.../course/domain/time/ClaTimeBookItem.java | 1 +
.../course/domain/time/StudentOrderItem.java | 8 +
.../service/impl/ScClaTimeServiceImpl.java | 63 +-
.../com/ruoyi/im/domain/GroupMessage.java | 5 +
.../com/ruoyi/im/domain/PrivateMessage.java | 5 +
.../ruoyi/im/domain/dto/GroupMessageDTO.java | 2 +-
.../java/com/ruoyi/im/domain/vo/FriendVO.java | 6 +
.../ruoyi/im/domain/vo/GroupMessageVO.java | 7 +
.../ruoyi/im/domain/vo/OnlineTerminalVO.java | 19 +
.../ruoyi/im/domain/vo/PrivateMessageVO.java | 4 +
.../com/ruoyi/im/mapper/FriendMapper.java | 5 +-
.../com/ruoyi/im/service/FriendService.java | 9 +-
.../com/ruoyi/im/service/GroupService.java | 9 +-
.../im/service/impl/FriendServiceImpl.java | 33 +-
.../service/impl/GroupMessageServiceImpl.java | 67 +-
.../im/service/impl/GroupServiceImpl.java | 19 +
.../impl/PrivateMessageServiceImpl.java | 48 +-
.../mapper/cource/ScBookCourseMapper.xml | 3 +-
.../mapper/cource/ScClaTimeMapper.xml | 20 +-
.../main/resources/mapper/im/FriendMapper.xml | 20 +-
56 files changed, 728 insertions(+), 728 deletions(-)
create mode 100644 ruoyi-im-server/src/main/java/com/ruoyi/imserver/util/LongToStringConverter.java
create mode 100644 ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/OnlineTerminalVO.java
diff --git a/ruoyi-admin/ruoyi-admin.iml b/ruoyi-admin/ruoyi-admin.iml
index 37e8d48..6a2d24e 100644
--- a/ruoyi-admin/ruoyi-admin.iml
+++ b/ruoyi-admin/ruoyi-admin.iml
@@ -4,7 +4,10 @@
-
+
+
+
+
@@ -15,13 +18,13 @@
-
-
+
+
-
-
+
+
@@ -99,6 +102,9 @@
+
+
+
@@ -119,40 +125,13 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/AppreciateController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/AppreciateController.java
index 2afb0ba..f66acee 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/AppreciateController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/AppreciateController.java
@@ -37,7 +37,7 @@ public class AppreciateController {
public RestResponse getList(@RequestBody Map map){
Long visitStore=Long.parseLong(map.get("visitStore").toString());
List list= service.list(new QueryWrapper()
- .select("id,title,image,read_num,start_time")
+ .select("id,title,image,read_num,start_time,modify_time")
.eq("dept_id",visitStore)
.eq("status",true)
.orderByDesc("modify_time"));
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/HealthyController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/HealthyController.java
index 6ec6cc3..add59da 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/HealthyController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/HealthyController.java
@@ -38,7 +38,7 @@ public class HealthyController {
public RestResponse getList(@RequestBody Map map){
Long visitStore=Long.parseLong(map.get("visitStore").toString());
List list= service.list(new QueryWrapper()
- .select("id,title,image,read_num,start_time")
+ .select("id,title,image,read_num,start_time,modify_time")
.eq("dept_id",visitStore)
.eq("status",true)
.orderByDesc("modify_time"));
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/InheritController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/InheritController.java
index 4efc24c..165ed66 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/InheritController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/InheritController.java
@@ -37,7 +37,7 @@ public class InheritController {
public RestResponse getList(@RequestBody Map map){
Long visitStore=Long.parseLong(map.get("visitStore").toString());
List list= inheritService.list(new QueryWrapper()
- .select("id,title,image,read_num,start_time")
+ .select("id,title,image,read_num,start_time,modify_time")
.eq("dept_id",visitStore)
.eq("status",true)
.orderByDesc("modify_time"));
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/MyController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/MyController.java
index 428cade..159fc95 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/MyController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/MyController.java
@@ -140,7 +140,7 @@ public class MyController extends BaseController {
*/
@PostMapping("/confirmClass")
public RestResponse confirmClass(@RequestBody Map map){
- Long courseTimeId=(Long)map.get("courseTimeId");
+ Long courseTimeId=Long.parseLong(map.get("courseTimeId").toString());
String startTime=map.get("startTime").toString();//HH:mm:ss
String endTime=map.get("endTime").toString();//HH:mm:ss
if (StrUtil.hasEmpty(startTime,endTime)){
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/PracticeMomentsController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/PracticeMomentsController.java
index 9f1da6d..b45521e 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/PracticeMomentsController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/PracticeMomentsController.java
@@ -38,7 +38,7 @@ public class PracticeMomentsController {
public RestResponse getList(@RequestBody Map map){
Long visitStore=Long.parseLong(map.get("visitStore").toString());
List list=momentsService.list(new QueryWrapper()
- .select("id,title,image,read_num,start_time")
+ .select("id,title,image,read_num,start_time,modify_time")
.eq("dept_id",visitStore)
.eq("status",true)
.orderByDesc("modify_time"));
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/SenseController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/SenseController.java
index b53d167..01b300e 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/SenseController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/SenseController.java
@@ -36,7 +36,7 @@ public class SenseController {
public RestResponse getList(@RequestBody Map map){
Long visitStore=Long.parseLong(map.get("visitStore").toString());
List list= service.list(new QueryWrapper()
- .select("id,title,image,read_num,start_time")
+ .select("id,title,image,read_num,start_time,modify_time")
.eq("dept_id",visitStore)
.eq("status",true)
.orderByDesc("modify_time"));
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/course/CourseController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/course/CourseController.java
index d7a8a8f..60c547a 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/course/CourseController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/course/CourseController.java
@@ -92,7 +92,7 @@ public class CourseController extends BaseController {
*/
@PostMapping("/cancelCourse")
public RestResponse cancelCourse(@RequestBody Map map){
- Long courseTimeId =(Long)map.get("courseTimeId");
+ Long courseTimeId =Long.parseLong(map.get("courseTimeId").toString());
return scClaTimeService.cancelCourse(courseTimeId);
}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/FriendController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/FriendController.java
index 84d2549..8996f87 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/FriendController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/FriendController.java
@@ -6,6 +6,7 @@ import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.core.domain.entity.AppUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.im.domain.vo.FriendVO;
+import com.ruoyi.im.domain.vo.OnlineTerminalVO;
import com.ruoyi.im.domain.vo.UserVO;
import com.ruoyi.im.service.FriendService;
import com.ruoyi.web.controller.im.result.Result;
@@ -53,12 +54,13 @@ public class FriendController {
@GetMapping("/find/{friendId}")
@Operation(summary = "查找好友信息", description = "查找好友信息")
- public Result findFriend(@NotNull(message = "好友id不可为空") @PathVariable Long friendId) {
+ public Result findFriend(@NotNull(message = "好友id不可为空") @PathVariable String friendId) {
Long userId= SecurityUtils.getAppLoginUser().getAppUser().getId();
- if (friendId.equals(userId)) {
+ Long fId=Long.valueOf(friendId);
+ if (fId.equals(userId)) {
return null;
}
- return ResultUtils.success(friendService.findFriend(userId,friendId));
+ return ResultUtils.success(friendService.findFriend(userId,fId));
}
@@ -68,5 +70,9 @@ public class FriendController {
friendService.delFriend(friendId);
return ResultUtils.success();
}
-
+ @GetMapping("/terminal/online")
+ @Operation(summary = "判断用户哪个终端在线", description = "返回在线的用户id的终端集合")
+ public Result> getOnlineTerminal(@NotNull @RequestParam("userIds") String userIds) {
+ return ResultUtils.success(friendService.getOnlineTerminals(userIds));
+ }
}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/GroupController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/GroupController.java
index cc45975..26c2e76 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/GroupController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/GroupController.java
@@ -1,6 +1,7 @@
package com.ruoyi.web.controller.im;
import com.ruoyi.common.annotation.RepeatSubmit;
+import com.ruoyi.im.domain.vo.GroupMemberVO;
import com.ruoyi.im.domain.vo.GroupVO;
import com.ruoyi.im.service.GroupService;
import com.ruoyi.web.controller.im.result.Result;
@@ -42,6 +43,11 @@ public class GroupController {
return ResultUtils.success(groupService.findGroups());
}
-
+ @Operation(summary = "查询群聊成员", description = "查询群聊成员")
+ @GetMapping("/members/{groupId}")
+ public Result> findGroupMembers(
+ @NotNull(message = "群聊id不能为空") @PathVariable Long groupId) {
+ return ResultUtils.success(groupService.findGroupMembers(groupId));
+ }
}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/GroupMessageController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/GroupMessageController.java
index bb28ee3..bb4c255 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/GroupMessageController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/GroupMessageController.java
@@ -31,21 +31,21 @@ public class GroupMessageController {
@GetMapping("/maxReadedId")
@Operation(summary = "获取最大已读消息的id", description = "获取某个会话中已读消息的最大id")
- public Result getMaxReadedId(@RequestParam Long groupId) {
- return ResultUtils.success(groupMessageService.getMaxReadedId(groupId),"成功");
+ public Result getMaxReadedId(@RequestParam String groupId) {
+ return ResultUtils.success(groupMessageService.getMaxReadedId(Long.parseLong(groupId.toString())),"成功");
}
@GetMapping("/pullOfflineMessage")
@Operation(summary = "拉取离线消息", description = "拉取离线消息,消息将通过webscoket异步推送")
- public Result pullOfflineMessage(@RequestParam Long minId) {
- groupMessageService.pullOfflineMessage(minId);
+ public Result pullOfflineMessage(@RequestParam String minId) {
+ groupMessageService.pullOfflineMessage(Long.parseLong(minId.toString()));
return ResultUtils.success();
}
@PutMapping("/readed")
@Operation(summary = "消息已读", description = "将群聊中的消息状态置为已读")
- public Result readedMessage(@RequestParam Long groupId) {
- groupMessageService.readedMessage(groupId);
+ public Result readedMessage(@RequestParam String groupId) {
+ groupMessageService.readedMessage(Long.parseLong(groupId.toString()));
return ResultUtils.success();
}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/PrivateMessageController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/PrivateMessageController.java
index d9fdb9b..62b7291 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/PrivateMessageController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/PrivateMessageController.java
@@ -55,23 +55,23 @@ public class PrivateMessageController {
*/
@GetMapping("/pullOfflineMessage")
@Operation(summary = "拉取离线消息", description = "拉取离线消息,消息将通过webscoket异步推送")
- public Result pullOfflineMessage(@RequestParam Long minId) {
- privateMessageService.pullOfflineMessage(minId);
+ public Result pullOfflineMessage(@RequestParam String minId) {
+ privateMessageService.pullOfflineMessage(Long.parseLong(minId.toString()));
return ResultUtils.success();
}
@PutMapping("/readed")
@Operation(summary = "消息已读", description = "将会话中接收的消息状态置为已读")
- public Result readedMessage(@RequestParam Long friendId) {
- privateMessageService.readedMessage(friendId);
+ public Result readedMessage(@RequestParam String friendId) {
+ privateMessageService.readedMessage(Long.parseLong(friendId.toString()));
return ResultUtils.success();
}
@GetMapping("/maxReadedId")
@Operation(summary = "获取最大已读消息的id", description = "获取某个会话中已读消息的最大id")
- public Result getMaxReadedId(@RequestParam Long friendId) {
- return ResultUtils.success(privateMessageService.getMaxReadedId(friendId));
+ public Result getMaxReadedId(@RequestParam String friendId) {
+ return ResultUtils.success(privateMessageService.getMaxReadedId(Long.parseLong(friendId.toString())));
}
// @GetMapping("/history")
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/login/AppLoginController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/login/AppLoginController.java
index 21ba4d1..b746354 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/login/AppLoginController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/login/AppLoginController.java
@@ -1,6 +1,8 @@
package com.ruoyi.web.controller.login;
import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.im.util.BeanUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@@ -12,6 +14,7 @@ import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.AppUser;
import com.ruoyi.common.core.domain.model.AppLoginUser;
import com.ruoyi.common.core.domain.model.AppUserLoginBody;
+import com.ruoyi.common.utils.JpushClientUtil;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.framework.web.service.AppLoginService;
import com.ruoyi.basic.domain.YjStore;
@@ -65,6 +68,7 @@ public class AppLoginController {
}
AppUser appUser=new AppUser();
appUser.setPhoneNumber(loginBody.getPhonenumber());
+ appUser.setNickName(loginBody.getPhonenumber());
appUser.setPassword(SecurityUtils.encryptPassword(loginBody.getPassword()));
appUser.setStatus(1);
appUserService.save(appUser);
@@ -83,6 +87,17 @@ public class AppLoginController {
AjaxResult ajax = AjaxResult.success();
String token=appLoginService.login(loginBody.getPhonenumber(),loginBody.getPassword(),loginBody.getCode(),loginBody.getUuid(),loginBody.getRegisterId(),loginBody.getMiniAppCode());
ajax.put(Constants.TOKEN, token);
+
+ // 保存设备id绑定别名,便于推送消息
+ if (StrUtil.isNotEmpty(loginBody.getRegisterId())){
+ appUserService.update(new UpdateWrapper().eq("phone_number",loginBody.getPhonenumber())
+ .set("register_id",loginBody.getRegisterId())
+ .set(StrUtil.isNotEmpty(loginBody.getLoginSysPlatform()),"login_sys_platform",loginBody.getLoginSysPlatform())
+ );
+ // 极光推送注册设备id绑定别名,便于推送消息
+ JpushClientUtil.bindAlias(loginBody.getRegisterId(),loginBody.getPhonenumber());
+ }
+
return ajax;
}
@@ -103,7 +118,8 @@ public class AppLoginController {
appUser.setPhonenumber(user.getAppUser().getPhoneNumber());
// 角色集合
appUser.setRoleId(user.getRoles());
- //管理人员(教练、店长、顾问)默认访问门店
+ //管理人员(教练、店长、顾问)默认访问门店.
+
// if (ObjectUtil.isNotEmpty(user.getManageAccountId())&&ObjectUtil.isNotEmpty(appUser.getVisitStore())){
// Long deptId= userService.selectUserById(user.getManageAccountId()).getDeptId();
// appUser.setVisitStore(deptId);
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/login/CaptchaController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/login/CaptchaController.java
index b003898..f92b63c 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/login/CaptchaController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/login/CaptchaController.java
@@ -8,6 +8,7 @@ import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.redis.RedisCache;
+import com.ruoyi.common.utils.JpushClientUtil;
import com.ruoyi.common.utils.sign.Base64;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.system.service.ISysConfigService;
@@ -20,8 +21,7 @@ import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
import java.util.concurrent.TimeUnit;
/**
@@ -92,11 +92,31 @@ public class CaptchaController
{
return AjaxResult.error(e.getMessage());
}
-
+ testBindAlias();
ajax.put("uuid", uuid);
ajax.put("img", Base64.encode(os.toByteArray()));
return ajax;
}
+ public void testBindAlias() {
+
+
+// JpushClientUtil.bindAlias("reg_123", "user_888");
+// JpushClientUtil.pushToAll("瑜伽汇","这是java广播消息",null);
+// JpushClientUtil.pushByRegistrationId(Arrays.asList("170976fa8bac0ade1e0"),"瑜伽汇","这是RegistrationId广播消息",null);
+// JpushClientUtil.bindAlias("160a3797c9280401a82","15004070936");
+// JpushClientUtil.pushToUser("15004070936","瑜伽汇","这是Alias消息",null);
+// JpushClientUtil.pushToUsers(Arrays.asList("15004070936","mumu"),"瑜伽汇","瑜伽汇群组推送",null);
+
+// String msg = String.format(
+// "%s:%s",
+// "普拉提", "课程预约成功!"
+// );
+// Map extras=new HashMap<>();
+// extras.put("type","bookCourses");//type推送类型:bookCourses 预约课程 groupMessage群聊消息 privateMessage私信消息
+// extras.put("pagePath","/pages/book/book");//pagePath跳转页面
+// extras.put("bookId","123456789");//bookId预约id
+// JpushClientUtil.pushByRegistrationId(Arrays.asList("160a3797c9280401a82"),"瑜伽汇",msg,extras);
+ }
}
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index 193ea05..6ab1d8d 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -146,3 +146,4 @@ xss:
wechat:
token: runpeng
+
diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml
index fe0a1c8..f382f65 100644
--- a/ruoyi-common/pom.xml
+++ b/ruoyi-common/pom.xml
@@ -159,16 +159,15 @@
- cn.jpush.api
- jiguang-common
- 1.1.7
+ io.github.jpush
+ jiguang-sdk
+ 5.3.0
- cn.jpush.api
- jpush-client
- 3.4.3
+ com.google.code.gson
+ gson
+ 2.8.9
-
io.springfox
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/AppUser.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/AppUser.java
index 8869588..097b6f0 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/AppUser.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/AppUser.java
@@ -94,7 +94,12 @@ public class AppUser{
@TableField(exist = false)
private String newPassword;
-
+ //安卓:android;
+ //iOS:ios ;
+ //鸿蒙:harmonyos ;
+ //微信小程序:weixin;
+ @TableField("login_sys_platform")
+ private String loginSysPlatform;
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/AppUserLoginBody.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/AppUserLoginBody.java
index 7f164b2..0abe9a8 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/AppUserLoginBody.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/AppUserLoginBody.java
@@ -1,5 +1,6 @@
package com.ruoyi.common.core.domain.model;
+import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@@ -66,4 +67,8 @@ public class AppUserLoginBody
*/
private String visitStoreId;
+ private String loginSysPlatform;
+
+
+
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/db/SshContextListener.java b/ruoyi-common/src/main/java/com/ruoyi/common/db/SshContextListener.java
index 860d1e1..a71c384 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/db/SshContextListener.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/db/SshContextListener.java
@@ -7,8 +7,8 @@ import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
-@Component//尽量加上这个
-@WebListener//声明为监听器 implements ServletContextListener
+//@Component//尽量加上这个
+//@WebListener//声明为监听器 implements ServletContextListener
public class SshContextListener implements ServletContextListener{
private SshTunnelConfig sshConnectionConfig;
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/im/model/IMPrivateMessage.java b/ruoyi-common/src/main/java/com/ruoyi/common/im/model/IMPrivateMessage.java
index 9800e46..fa32745 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/im/model/IMPrivateMessage.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/im/model/IMPrivateMessage.java
@@ -1,6 +1,8 @@
package com.ruoyi.common.im.model;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.ruoyi.common.im.enums.IMTerminalType;
import lombok.Data;
@@ -17,6 +19,7 @@ public class IMPrivateMessage {
/**
* 接收者id
*/
+ @JsonSerialize(using = ToStringSerializer.class)
private Long recvId;
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/im/model/IMUserInfo.java b/ruoyi-common/src/main/java/com/ruoyi/common/im/model/IMUserInfo.java
index a999afc..3079369 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/im/model/IMUserInfo.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/im/model/IMUserInfo.java
@@ -1,14 +1,11 @@
package com.ruoyi.common.im.model;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
-/**
- * @author: Blue
- * @date: 2023-09-24 09:23:11
- * @version: 1.0
- */
@Data
@NoArgsConstructor
@AllArgsConstructor
@@ -17,6 +14,7 @@ public class IMUserInfo {
/**
* 用户id
*/
+ @JsonSerialize(using = ToStringSerializer.class)
private Long id;
/**
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/JpushClientUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/JpushClientUtil.java
index 9e3d355..d0a83db 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/JpushClientUtil.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/JpushClientUtil.java
@@ -1,592 +1,294 @@
package com.ruoyi.common.utils;
-import cn.jiguang.common.resp.APIConnectionException;
-import cn.jiguang.common.resp.APIRequestException;
-import cn.jiguang.common.resp.BooleanResult;
-import cn.jiguang.common.resp.DefaultResult;
-import cn.jpush.api.JPushClient;
-import cn.jpush.api.device.TagAliasResult;
-import cn.jpush.api.push.PushResult;
-import cn.jpush.api.push.model.Message;
-import cn.jpush.api.push.model.Options;
-import cn.jpush.api.push.model.Platform;
-import cn.jpush.api.push.model.PushPayload;
-import cn.jpush.api.push.model.audience.Audience;
-import cn.jpush.api.push.model.notification.AndroidNotification;
-import cn.jpush.api.push.model.notification.IosNotification;
-import cn.jpush.api.push.model.notification.Notification;
-import cn.jpush.api.schedule.ScheduleResult;
+import cn.hutool.core.bean.BeanUtil;
+import cn.jiguang.sdk.api.DeviceApi;
+import cn.jiguang.sdk.api.PushApi;
+import cn.jiguang.sdk.bean.push.PushSendParam;
+import cn.jiguang.sdk.bean.push.PushSendParam;
+import cn.jiguang.sdk.bean.push.PushSendResult;
+import cn.jiguang.sdk.exception.ApiErrorException;
+import com.google.gson.Gson;
+import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
-import java.util.ArrayList;
-import java.util.List;
+import javax.annotation.PostConstruct;
+import java.io.IOException;
+import java.util.*;
/**
- * 极光推送工具类
+ * 极光推送工具类 (适配 SDK 5.3.0)
+ * 用于 IM 系统的离线消息推送
*/
+@Component
public class JpushClientUtil {
- private static Logger logger = LoggerFactory.getLogger(JpushClientUtil.class);
+
+ private static final Logger log = LoggerFactory.getLogger(JpushClientUtil.class);
+ private static final Gson gson = new Gson();
+ private static final String DEVICE_API_URL = "https://device.jpush.cn/v3/devices/";
+ private static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8");
+
+ // 静态变量,由 Spring 初始化
+ private static String appKey;
+ private static String masterSecret;
+ private static boolean apnsProduction;
+ private static PushApi pushApi;
+
+ private static OkHttpClient httpClient;
+
+ // 注入的属性
+// @Value("${jpush.appKey}")
+// private String injectedAppKey;
+//
+// @Value("${jpush.masterSecret}")
+// private String injectedMasterSecret;
+// private final static String injectedAppKey = "e75debc0daaed0a2a888d2f3";
+// private final static String injectedMasterSecret = "e8728877c098e641cc6c51e5";
+ private final static String injectedAppKey = "d5edb270e4b1cc29616e1dd5";
+ private final static String injectedMasterSecret = "a49a9fd3df40747fb6e0d180";
+
+// private final static String customAction = "com.test.java.sdk.";
+// private final static String targetPackage = "com.test.java.sdk";
+// private final static String targetActivity = "Activity 组件路径;";
+// private final static String extrasParam = "S.key1=value;i.key2=3;";
+// @Value("${jpush.apnsProduction:true}")
+ private final static boolean injectedApnsProduction = true;
+
+
+ @PostConstruct
+ public void init() {
+ // 将注入的值赋给静态变量
+ appKey = injectedAppKey;
+ masterSecret = injectedMasterSecret;
+ apnsProduction = injectedApnsProduction;
+
+ // 初始化 PushApi
+ pushApi = new PushApi.Builder()
+ .setAppKey(appKey)
+ .setMasterSecret(masterSecret)
+ .build();
+
+ // 初始化 OkHttpClient
+ httpClient = new OkHttpClient.Builder()
+ .connectTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
+ .readTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
+ .writeTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
+ .build();
+
+ log.info("极光推送工具类初始化完成");
+ }
+
+// ==================== 别名绑定方法 ====================
+
/**
- * 设置好账号的app_key和masterSecret是必须的
+ * 服务端直接绑定别名,将 registrationId 与 alias 关联。
+ * 调用时机:用户登录成功后,客户端上报 registrationId 即可调用。
+ *
+ * @param registrationId 客户端上报的设备唯一标识
+ * @param alias 别名,如用户ID或手机号
*/
- private final static String APPKER = "c2e673cd0e77c762ffe1a857";
- private final static String MASTERSECRET = "34aace4d60d847468ab96097";
+ public static void bindAlias(String registrationId, String alias) {
+ if (registrationId == null || registrationId.isEmpty() || alias == null || alias.isEmpty()) {
+ log.warn("绑定别名失败: registrationId 或 alias 为空");
+ return;
+ }
+
+ // 构建请求体
+ Map bodyMap = new HashMap<>();
+ bodyMap.put("alias", alias);
+ String jsonBody = gson.toJson(bodyMap);
+
+ // Basic 认证
+ String auth = Base64.getEncoder().encodeToString((appKey + ":" + masterSecret).getBytes());
+
+ RequestBody requestBody = RequestBody.create(JSON_MEDIA_TYPE,jsonBody);
+ Request request = new Request.Builder()
+ .url(DEVICE_API_URL + registrationId)
+ .addHeader("Authorization", "Basic " + auth)
+ .post(requestBody)
+ .build();
+
+ try (Response response = httpClient.newCall(request).execute()) {
+ if (response.isSuccessful()) {
+ log.info("别名绑定成功 | registrationId: {}, alias: {}", registrationId, alias);
+ } else {
+ // 极光 API 有时返回 404 但仍视为成功
+ String respBody = response.body() != null ? response.body().string() : "";
+ log.warn("别名绑定响应非成功,可能已成功 | registrationId: {}, alias: {}, code: {}, body: {}",
+ registrationId, alias, response.code(), respBody);
+ }
+ } catch (IOException e) {
+ log.error("别名绑定请求异常 | registrationId: {}, alias: {}, error: {}",
+ registrationId, alias, e.getMessage(), e);
+ }
+ }
+
+
+ // ==================== 单聊推送:按别名 ====================
+
+
/**
- * ApnsProduction
- * 此字段的值是用来指定本推送要推送的apns环境,false表示开发,true表示生产;对android和自定义消息无意义
- * 上线之后要改为 true
+ * 推送到单个用户 (别名,即 userId)
+ * @param alias 用户别名
+ * @param title 通知标题
+ * @param content 通知内容
+ * @param extras 额外参数 (如会话类型、消息类型等)
*/
- private final static Boolean ApnsProduction = false;
-
- private static JPushClient jPushClient = new JPushClient(MASTERSECRET,APPKER);
-
- private JpushClientUtil() {
+ public static void pushToUser(String alias, String title, String content, Map extras) {
+ PushSendParam param = buildPushParamWithAlias(alias, title, content, extras);
+ sendPush(param, "user", alias);
+ }
- throw new AssertionError("不能产生该对象");
+ // ==================== 群聊推送:按别名批量 ====================
+
+ /**
+ * 推送到多个用户 (别名批量,适合群聊离线推送)
+ * @param aliases 用户别名集合
+ * @param title 通知标题
+ * @param content 通知内容
+ * @param extras 额外参数
+ */
+ public static void pushToUsers(List aliases, String title, String content, Map extras) {
+ if (aliases == null || aliases.isEmpty()) return;
+ PushSendParam param = buildPushParamWithAliases(aliases, title, content, extras);
+ sendPush(param, "group-users", aliases.size() + " users");
}
- /**
- * 绑定电话
- */
- public static void testBindMobile() {
- try {
- DefaultResult result = jPushClient.bindMobile("100d855909a0c6d0655", "15004070936");
- System.out.println("Got result " + result);
- } catch (APIConnectionException e) {
- logger.error("Connection error. Should retry later. ", e);
- } catch (APIRequestException e) {
- logger.error("Error response from JPush server. Should review and fix it. ", e);
- logger.info("HTTP Status: " + e.getStatus());
- logger.info("Error Code: " + e.getErrorCode());
- logger.info("Error Message: " + e.getErrorMessage());
- }
- }
- /**
- *
- * @param
- * @return
- *生成别名
- */
- public static boolean bindAlias(String registerId,String phoneNumber) {
- try {
- DefaultResult defaultResult = jPushClient.updateDeviceTagAlias(registerId, phoneNumber, null,
- null);
- logger.info("Got result"+defaultResult);
- } catch (APIConnectionException e) {
- logger.error("Connection error. Should retry later. ", e);
- e.printStackTrace();
- } catch (APIRequestException e) {
- logger.error("Error response from JPush server. Should review and fix it. ", e);
- e.printStackTrace();
- }finally {
- jPushClient.close();
- }
- return false;
- }
-
- public static BooleanResult hasMobile() {
- BooleanResult deviceInTag = null;
- try {
- deviceInTag = jPushClient.isDeviceInTag(
- String.valueOf(jPushClient.getDeviceTagAlias("100d855909a0c6d0655").alias), "100d855909a0c6d0655");
- logger.info("Got result" + deviceInTag);
- return deviceInTag ;
- } catch (APIConnectionException e) {
- e.printStackTrace();
- } catch (APIRequestException e) {
- e.printStackTrace();
- }finally {
- jPushClient.close();
- }
- return deviceInTag ;
- }
-
- public static void testGetDeviceTagAlias() {
- try {
- TagAliasResult result = jPushClient.getDeviceTagAlias("100d855909a0c6d0655");
-
- logger.info(result.alias);
- logger.info(result.tags.toString());
-
- } catch (APIConnectionException e) {
- logger.error("Connection error. Should retry later. ", e);
-
- } catch (APIRequestException e) {
- logger.error("Error response from JPush server. Should review and fix it. ", e);
- logger.info("HTTP Status: " + e.getStatus());
- logger.info("Error Code: " + e.getErrorCode());
- logger.info("Error Message: " + e.getErrorMessage());
- }
- }
+ // ==================== 全量推送 (谨慎使用) ====================
/**
- * 推送给设备标识(别名)参数的用户
- * @param alias 设备标识(别名)
- * @param notification_title 通知内容标题
- * @param msg_title 消息内容标题
- * @param msg_content 消息内容
- * @param extrasparam 扩展字段(通常传跳转的链接)
- * @return 0推送失败,1推送成功
+ * 推送给所有设备
*/
- public static int sendToAlias( List alias,String notification_title, String msg_title,
- String msg_content, String extrasparam) {
- JPushClient jPushClient = new JPushClient(MASTERSECRET,APPKER);
- int result = 0;
- try {
- PushPayload pushPayload= JpushClientUtil.buildPushObject_all_alias_alertWithTitle(
- alias,notification_title,msg_title,msg_content,extrasparam);
- PushResult pushResult = jPushClient.sendPush(pushPayload);
- if(pushResult.getResponseCode()==200){
- result = 1;
- }
- logger.info("[极光推送]PushResult result is " + pushResult);
- } catch (APIConnectionException e) {
- logger.error("[极光推送]Connection error. Should retry later. ", e);
- } catch (APIRequestException e) {
- logger.error("[极光推送]Error response from JPush server. Should review and fix it. ", e);
- logger.info("[极光推送]HTTP Status: " + e.getStatus());
- logger.info("[极光推送]Error Code: " + e.getErrorCode());
- logger.info("[极光推送]Error Message: " + e.getErrorMessage());
- }
- return result;
+ public static void pushToAll(String title, String content, Map extras) {
+ PushSendParam param = buildPushParamWithAll(title, content, extras);
+ sendPush(param, "all", null);
}
-
+ // ==================== 根据 Registration ID 推送 (备用) ====================
+
/**
- * 推送给设备标识(别名)参数的用户(定时)
- * @param alias 设备标识(别名)
- * @param notification_title 通知内容标题
- * @param msg_title 消息内容标题
- * @param msg_content 消息内容
- * @param extrasparam 扩展字段
- * @param time 格式:yyyy-MM-dd HH:mm:ss
- * @return 0推送失败,1推送成功
+ * 按 Registration ID 推送 (适用于未绑定别名的场景)
*/
- public static int sendToAlias2( List alias,String notification_title, String msg_title, String msg_content, String extrasparam, String time) {
- JPushClient jPushClient = new JPushClient(MASTERSECRET,APPKER);
- int result = 0;
- try {
- PushPayload pushPayload= JpushClientUtil.buildPushObject_all_alias_alertWithTitle(alias,notification_title,msg_title,msg_content,extrasparam);
- ScheduleResult scheduleResult=jPushClient.createSingleSchedule("点呗生活", time, pushPayload);
- if(scheduleResult.getResponseCode()==200){
- result=1;
- }
- logger.info("[极光推送]ScheduleResult result is " + scheduleResult);
- } catch (APIConnectionException e) {
- logger.error("[极光推送]Connection error. Should retry later. ", e);
- } catch (APIRequestException e) {
- logger.error("[极光推送]Error response from JPush server. Should review and fix it. ", e);
- logger.info("[极光推送]HTTP Status: " + e.getStatus());
- logger.info("[极光推送]Error Code: " + e.getErrorCode());
- logger.info("[极光推送]Error Message: " + e.getErrorMessage());
- }
- return result;
+ public static void pushByRegistrationId(List regId, String title, String content, Map extras) {
+ PushSendParam param = buildPushParamWithRegistrationId(regId, title, content, extras);
+ sendPush(param, "regId", regId.size()+ " users");
}
-
+
+ // ==================== 内部构建方法 (核心适配) ====================
+
/**
- * 推送给设备RegistrationIds参数的用户
- * @param registrationIdList 设备注册ID
- * @param notification_title 通知内容标题
- * @param msg_title 消息内容标题
- * @param msg_content 消息内容
- * @param extrasparam 扩展字段
- * @return 0推送失败,1推送成功
+ * 构建单个别名的推送参数
*/
- public static int sendToRegistrationIds( List registrationIdList,String notification_title, String msg_title, String msg_content, String extrasparam) {
- JPushClient jPushClient = new JPushClient(MASTERSECRET,APPKER);
- int result = 0;
- try {
- PushPayload pushPayload= JpushClientUtil.buildPushObject_all_registrationIds_alertWithTitle(registrationIdList,notification_title,msg_title,msg_content,extrasparam);
- PushResult pushResult=jPushClient.sendPush(pushPayload);
- if(pushResult.getResponseCode()==200){
- result=1;
- }
- logger.info("[极光推送]PushResult result is " + pushResult);
- } catch (APIConnectionException e) {
- logger.error("[极光推送]Connection error. Should retry later. ", e);
- } catch (APIRequestException e) {
- logger.error("[极光推送]Error response from JPush server. Should review and fix it. ", e);
- logger.info("[极光推送]HTTP Status: " + e.getStatus());
- logger.info("[极光推送]Error Code: " + e.getErrorCode());
- logger.info("[极光推送]Error Message: " + e.getErrorMessage());
- }
- return result;
+ private static PushSendParam buildPushParamWithAlias(String alias, String title, String content, Map extras) {
+ Map pushBody = buildCommonPushBody(title, content, extras);
+ Map map= new HashMap<>();
+ map.put("alias", Arrays.asList(alias));
+ pushBody.put("audience", map);
+ PushSendParam param = BeanUtil.toBean(pushBody, PushSendParam.class);
+ return param;
}
-// public static void main(String[] agrs){
-//
-// List strings=new ArrayList<>();
-// strings.add("13065ffa4ee0d41a70c");
-// String notification_title="通知内容标题";//通知内容标题
-// String msg_title="消息内容标题";//消息内容标题
-// String msg_content="消息内容";//消息内容
-// String extrasparam="扩展字段";//扩展字段
-// int i=sendToRegistrationIds(strings,notification_title,msg_title,msg_content,extrasparam);
-// System.out.println(i==0?"0推送失败":"1推送成功");
-// }
+ /**
+ * 构建多个别名的推送参数
+ */
+ private static PushSendParam buildPushParamWithAliases(List aliases, String title, String content, Map extras) {
+ Map pushBody = buildCommonPushBody(title, content, extras);
+ Map map= new HashMap<>();
+ map.put("alias", aliases);
+ pushBody.put("audience", map);
+ return BeanUtil.toBean(pushBody, PushSendParam.class);
+ }
/**
- * 发送给所有安卓用户
- * @param notification_title 通知内容标题
- * @param msg_title 消息内容标题
- * @param msg_content 消息内容
- * @param extrasparam 扩展字段
- * @return 0推送失败,1推送成功
+ * 构建全量推送的参数
*/
- public static int sendToAllAndroid( String notification_title, String msg_title, String msg_content, String extrasparam) {
- int result = 0;
- try {
- PushPayload pushPayload= JpushClientUtil.buildPushObject_android_all_alertWithTitle(notification_title,msg_title,msg_content,extrasparam);
- PushResult pushResult=jPushClient.sendPush(pushPayload);
- if(pushResult.getResponseCode()==200){
- result=1;
- }
- logger.info("[极光推送]PushResult result is " + pushResult);
- } catch (APIConnectionException e) {
- logger.error("[极光推送]Connection error. Should retry later. ", e);
- } catch (APIRequestException e) {
- logger.error("[极光推送]Error response from JPush server. Should review and fix it. ", e);
- logger.info("[极光推送]HTTP Status: " + e.getStatus());
- logger.info("[极光推送]Error Code: " + e.getErrorCode());
- logger.info("[极光推送]Error Message: " + e.getErrorMessage());
- }
- return result;
+ private static PushSendParam buildPushParamWithAll(String title, String content, Map extras) {
+ Map pushBody = buildCommonPushBody(title, content, extras);
+ pushBody.put("audience", "all");
+ return BeanUtil.toBean(pushBody, PushSendParam.class);
}
-
+
/**
- * 发送给所有IOS用户
- * @param notification_title 通知内容标题
- * @param msg_title 消息内容标题
- * @param msg_content 消息内容
- * @param extrasparam 扩展字段
- * @return 0推送失败,1推送成功
+ * 构建 Registration ID 推送的参数
*/
- public static int sendToAllIos(String notification_title, String msg_title, String msg_content, String extrasparam) {
- int result = 0;
- try {
- PushPayload pushPayload= JpushClientUtil.buildPushObject_ios_all_alertWithTitle(notification_title,msg_title,msg_content,extrasparam);
- PushResult pushResult=jPushClient.sendPush(pushPayload);
- if(pushResult.getResponseCode()==200){
- result=1;
- }
- logger.info("[极光推送]PushResult result is " + pushResult);
- } catch (APIConnectionException e) {
- logger.error("[极光推送]Connection error. Should retry later. ", e);
- } catch (APIRequestException e) {
- logger.error("[极光推送]Error response from JPush server. Should review and fix it. ", e);
- logger.info("[极光推送]HTTP Status: " + e.getStatus());
- logger.info("[极光推送]Error Code: " + e.getErrorCode());
- logger.info("[极光推送]Error Message: " + e.getErrorMessage());
- }
- return result;
+ private static PushSendParam buildPushParamWithRegistrationId(List regId, String title, String content, Map extras) {
+ Map pushBody = buildCommonPushBody(title, content, extras);
+ Map map= new HashMap<>();
+ map.put("registration_id", regId);
+ pushBody.put("audience", map);
+ return BeanUtil.toBean(pushBody, PushSendParam.class);
}
-
+
+
/**
- * 发送给所有用户
- * @param notification_title 通知内容标题
- * @param msg_title 消息内容标题
- * @param msg_content 消息内容
- * @param extrasparam 扩展字段
- * @return 0推送失败,1推送成功
+ * 构建通用的推送 body (包含通知和公共参数)
*/
- public static int sendToAll( String notification_title, String msg_title, String msg_content, String extrasparam) {
- int result = 0;
- try {
- PushPayload pushPayload= JpushClientUtil.buildPushObject_android_and_ios(notification_title,msg_title,msg_content,extrasparam);
- PushResult pushResult=jPushClient.sendPush(pushPayload);
- if(pushResult.getResponseCode()==200){
- result=1;
- }
- logger.info("[极光推送]PushResult result is " + pushResult);
- } catch (APIConnectionException e) {
- logger.error("[极光推送]Connection error. Should retry later. ", e);
- } catch (APIRequestException e) {
- logger.error("[极光推送]Error response from JPush server. Should review and fix it. ", e);
- logger.info("[极光推送]HTTP Status: " + e.getStatus());
- logger.info("[极光推送]Error Code: " + e.getErrorCode());
- logger.info("[极光推送]Error Message: " + e.getErrorMessage());
+ private static Map buildCommonPushBody(String title, String content, Map extras) {
+ Map pushBody = new HashMap<>();
+ pushBody.put("platform", "all"); // 全平台
+
+ // 构建通知体
+ Map notification = new HashMap<>();
+ notification.put("alert", content);
+
+ // Android 通知
+ Map android = new HashMap<>();
+ android.put("alert", content);
+ android.put("title", title);
+// //点击消息跳转至
+// Map intent= new HashMap<>();
+// String intentUrl = String.format(
+// "intent:#Intent;action=%s;component=%s/%s;S.userId=%s;end",
+// customAction, targetPackage, targetActivity, extrasParam
+// );
+// intent.put("url",intentUrl);
+// android.put("intent",intent);
+ if (extras != null) {
+ android.put("extras", extras);
}
- return result;
+ notification.put("android", android);
+
+ // iOS 通知
+ Map ios = new HashMap<>();
+ ios.put("alert", title);
+ ios.put("sound", "default");
+ ios.put("badge", "+1");
+ if (extras != null) {
+ ios.put("extras", extras);
+ }
+ notification.put("ios", ios);
+
+ pushBody.put("notification", notification);
+
+ // 选项
+ Map options = new HashMap<>();
+ options.put("time_to_live", 86400);
+ options.put("apns_production", apnsProduction);
+ pushBody.put("options", options);
+
+ return pushBody;
}
-
+
/**
- * 发送给所有用户(定时推送)
- * @param notification_title 通知内容标题
- * @param msg_title 消息内容标题
- * @param msg_content 消息内容
- * @param extrasparam 扩展字段
- * @param time 格式:yyyy-MM-dd HH:mm:ss
- * @return 0推送失败,1推送成功
+ * 统一发送和异常处理
*/
- public static int sendToAll2( String notification_title, String msg_title, String msg_content, String extrasparam, String time) {
- int result = 0;
+ private static void sendPush(PushSendParam param, String type, String target) {
try {
- PushPayload pushPayload= JpushClientUtil.buildPushObject_android_and_ios(notification_title,msg_title,msg_content,extrasparam);
- ScheduleResult scheduleResult=jPushClient.createSingleSchedule("测试", time, pushPayload);
- if(scheduleResult.getResponseCode()==200){
- result=1;
- }
- logger.info("[极光推送]scheduleResult result is " + scheduleResult);
- } catch (APIConnectionException e) {
- logger.error("[极光推送]Connection error. Should retry later. ", e);
- } catch (APIRequestException e) {
- logger.error("[极光推送]Error response from JPush server. Should review and fix it. ", e);
- logger.info("[极光推送]HTTP Status: " + e.getStatus());
- logger.info("[极光推送]Error Code: " + e.getErrorCode());
- logger.info("[极光推送]Error Message: " + e.getErrorMessage());
+ // 调用 PushApi 的 send 方法进行推送
+ PushSendResult result = pushApi.send(param);
+ log.info("极光推送成功 | type: {} | target: {} | msgId: {}", type, target, result.getMessageId());
+ } catch (ApiErrorException e) {
+ // 处理 API 错误,可获取错误码、HTTP状态码和限流信息
+ int httpStatus = e.getStats();
+ int errorCode = e.getApiError().getError().getCode();
+ String errorMessage = e.getApiError().getError().getMessage();
+ log.error("极光推送失败 | type: {} | target: {} | httpStatus: {} | errorCode: {} | error: {}",
+ type, target, httpStatus, errorCode, errorMessage, e);
+ // 此处可接入重试机制或报警
}
- return result;
- }
-
-
- public static PushPayload buildPushObject_android_and_ios(String notification_title, String msg_title, String msg_content, String extrasparam) {
- return PushPayload.newBuilder()
- .setPlatform(Platform.android_ios())
- .setAudience(Audience.all())
- .setNotification(Notification.newBuilder()
- .setAlert(msg_content)
- .addPlatformNotification(AndroidNotification.newBuilder()
- .setAlert(msg_content)
- .setTitle(notification_title)
- //此字段为透传字段,不会显示在通知栏。用户可以通过此字段来做一些定制需求,如特定的key传要指定跳转的页面(value)
- .addExtra("url",extrasparam)
- .build()
- )
- .addPlatformNotification(IosNotification.newBuilder()
- //传一个IosAlert对象,指定apns title、title、subtitle等
- .setAlert(msg_content)
- //直接传alert
- //此项是指定此推送的badge自动加1
- .incrBadge(1)
- //此字段的值default表示系统默认声音;传sound.caf表示此推送以项目里面打包的sound.caf声音来提醒,
- // 如果系统没有此音频则以系统默认声音提醒;此字段如果传空字符串,iOS9及以上的系统是无声音提醒,以下的系统是默认声音
- .setSound("sound.caf")
- //此字段为透传字段,不会显示在通知栏。用户可以通过此字段来做一些定制需求,如特定的key传要指定跳转的页面(value)
- .addExtra("url",extrasparam)
- //此项说明此推送是一个background推送,想了解background看:http://docs.jpush.io/client/ios_tutorials/#ios-7-background-remote-notification
- // .setContentAvailable(true)
- .build()
- )
- .build()
- )
- //Platform指定了哪些平台就会像指定平台中符合推送条件的设备进行推送。 jpush的自定义消息,
- // sdk默认不做任何处理,不会有通知提示。建议看文档http://docs.jpush.io/guideline/faq/的
- // [通知与自定义消息有什么区别?]了解通知和自定义消息的区别
- .setMessage(Message.newBuilder()
- .setMsgContent(msg_content)
- .setTitle(msg_title)
- .addExtra("url",extrasparam)
- .build())
- .setOptions(Options.newBuilder()
- //此字段的值是用来指定本推送要推送的apns环境,false表示开发,true表示生产;对android和自定义消息无意义
- .setApnsProduction(ApnsProduction)
- //此字段是给开发者自己给推送编号,方便推送者分辨推送记录
- .setSendno(1)
- //此字段的值是用来指定本推送的离线保存时长,如果不传此字段则默认保存一天,最多指定保留十天,单位为秒
- .setTimeToLive(86400)
- .build()
- )
- .build();
- }
-
- private static PushPayload buildPushObject_all_alias_alertWithTitle(List alias,String notification_title, String msg_title, String msg_content, String extrasparam) {
- //创建一个IosAlert对象,可指定APNs的alert、title等字段
- //IosAlert iosAlert = IosAlert.newBuilder().setTitleAndBody("title", "alert body").build();
- return PushPayload.newBuilder()
- //指定要推送的平台,all代表当前应用配置了的所有平台,也可以传android等具体平台
- .setPlatform(Platform.all())
- //指定推送的接收对象,all代表所有人,也可以指定已经设置成功的tag或alias或该应应用客户端调用接口获取到的registration id
- .setAudience(Audience.alias(alias))
- //.setAudience(Audience.registrationId(registrationId))
- //jpush的通知,android的由jpush直接下发,iOS的由apns服务器下发,Winphone的由mpns下发
- .setNotification(Notification.newBuilder()
- //指定当前推送的android通知
- .addPlatformNotification(AndroidNotification.newBuilder()
- .setAlert(msg_content)
- .setTitle(notification_title)
- //此字段为透传字段,不会显示在通知栏。用户可以通过此字段来做一些定制需求,如特定的key传要指定跳转的页面(value)
- .addExtra("url",extrasparam)
- .build())
- //指定当前推送的iOS通知
- .addPlatformNotification(IosNotification.newBuilder()
- //传一个IosAlert对象,指定apns title、title、subtitle等
- .setAlert(msg_content)
- //直接传alert
- //此项是指定此推送的badge自动加1
- .incrBadge(1)
- //此字段的值default表示系统默认声音;传sound.caf表示此推送以项目里面打包的sound.caf声音来提醒,
- // 如果系统没有此音频则以系统默认声音提醒;此字段如果传空字符串,iOS9及以上的系统是无声音提醒,以下的系统是默认声音
- .setSound("sound.caf")
- //此字段为透传字段,不会显示在通知栏。用户可以通过此字段来做一些定制需求,如特定的key传要指定跳转的页面(value)
- .addExtra("url",extrasparam)
- //此项说明此推送是一个background推送,想了解background看:http://docs.jpush.io/client/ios_tutorials/#ios-7-background-remote-notification
- //取消此注释,消息推送时ios将无法在锁屏情况接收
- // .setContentAvailable(true)
- .build())
- .build())
- //Platform指定了哪些平台就会像指定平台中符合推送条件的设备进行推送。 jpush的自定义消息,
- // sdk默认不做任何处理,不会有通知提示。建议看文档http://docs.jpush.io/guideline/faq/的
- // [通知与自定义消息有什么区别?]了解通知和自定义消息的区别
- .setMessage(Message.newBuilder()
- .setMsgContent(msg_content)
- .setTitle(msg_title)
- .addExtra("url",extrasparam)
- .build())
- .setOptions(Options.newBuilder()
- //此字段的值是用来指定本推送要推送的apns环境,false表示开发,true表示生产;对android和自定义消息无意义
- .setApnsProduction(ApnsProduction)
- //此字段是给开发者自己给推送编号,方便推送者分辨推送记录
- .setSendno(1)
- //此字段的值是用来指定本推送的离线保存时长,如果不传此字段则默认保存一天,最多指定保留十天;
- .setTimeToLive(86400)
- .build())
- .build();
}
-
- private static PushPayload buildPushObject_all_registrationIds_alertWithTitle(List registrationIds,String notification_title, String msg_title, String msg_content, String extrasparam) {
- //创建一个IosAlert对象,可指定APNs的alert、title等字段
- //IosAlert iosAlert = IosAlert.newBuilder().setTitleAndBody("title", "alert body").build();
- return PushPayload.newBuilder()
- //指定要推送的平台,all代表当前应用配置了的所有平台,也可以传android等具体平台
- .setPlatform(Platform.all())
- //指定推送的接收对象,all代表所有人,也可以指定已经设置成功的tag或alias或该应应用客户端调用接口获取到的registration id
- .setAudience(Audience.registrationId(registrationIds))
- //jpush的通知,android的由jpush直接下发,iOS的由apns服务器下发,Winphone的由mpns下发
- .setNotification(Notification.newBuilder()
- //指定当前推送的android通知
- .addPlatformNotification(AndroidNotification.newBuilder()
- .setAlert(msg_content)
- .setTitle(notification_title)
- //此字段为透传字段,不会显示在通知栏。用户可以通过此字段来做一些定制需求,如特定的key传要指定跳转的页面(value)
- .addExtra("url",extrasparam)
- .build())
- //指定当前推送的iOS通知
- .addPlatformNotification(IosNotification.newBuilder()
- //传一个IosAlert对象,指定apns title、title、subtitle等
- .setAlert(msg_content)
- //直接传alert
- //此项是指定此推送的badge自动加1
- .incrBadge(1)
- //此字段的值default表示系统默认声音;传sound.caf表示此推送以项目里面打包的sound.caf声音来提醒,
- // 如果系统没有此音频则以系统默认声音提醒;此字段如果传空字符串,iOS9及以上的系统是无声音提醒,以下的系统是默认声音
- .setSound("sound.caf")
- //此字段为透传字段,不会显示在通知栏。用户可以通过此字段来做一些定制需求,如特定的key传要指定跳转的页面(value)
- .addExtra("url",extrasparam)
- //此项说明此推送是一个background推送,想了解background看:http://docs.jpush.io/client/ios_tutorials/#ios-7-background-remote-notification
- //取消此注释,消息推送时ios将无法在锁屏情况接收
- // .setContentAvailable(true)
- .build())
- .build())
- //Platform指定了哪些平台就会像指定平台中符合推送条件的设备进行推送。 jpush的自定义消息,
- // sdk默认不做任何处理,不会有通知提示。建议看文档http://docs.jpush.io/guideline/faq/的
- // [通知与自定义消息有什么区别?]了解通知和自定义消息的区别
- .setMessage(Message.newBuilder()
- .setMsgContent(msg_content)
- .setTitle(msg_title)
- .addExtra("url",extrasparam)
- .build())
- .setOptions(Options.newBuilder()
- //此字段的值是用来指定本推送要推送的apns环境,false表示开发,true表示生产;对android和自定义消息无意义
- .setApnsProduction(ApnsProduction)
- //此字段是给开发者自己给推送编号,方便推送者分辨推送记录
- .setSendno(1)
- //此字段的值是用来指定本推送的离线保存时长,如果不传此字段则默认保存一天,最多指定保留十天;
- .setTimeToLive(86400)
- .build())
- .build();
- }
-
- private static PushPayload buildPushObject_android_all_alertWithTitle(String notification_title, String msg_title, String msg_content, String extrasparam) {
- List rids=new ArrayList<>();
- return PushPayload.newBuilder()
- //指定要推送的平台,all代表当前应用配置了的所有平台,也可以传android等具体平台
- .setPlatform(Platform.android())
- //指定推送的接收对象,all代表所有人,也可以指定已经设置成功的tag或alias或该应应用客户端调用接口获取到的registration id
- .setAudience(Audience.all())
- //jpush的通知,android的由jpush直接下发,iOS的由apns服务器下发,Winphone的由mpns下发
- .setNotification(Notification.newBuilder()
- //指定当前推送的android通知
- .addPlatformNotification(AndroidNotification.newBuilder()
- .setAlert(msg_content)
- .setTitle(notification_title)
- //此字段为透传字段,不会显示在通知栏。用户可以通过此字段来做一些定制需求,如特定的key传要指定跳转的页面(value)
- .addExtra("url",extrasparam)
- .build())
- .build()
- )
- //Platform指定了哪些平台就会像指定平台中符合推送条件的设备进行推送。 jpush的自定义消息,
- // sdk默认不做任何处理,不会有通知提示。建议看文档http://docs.jpush.io/guideline/faq/的
- // [通知与自定义消息有什么区别?]了解通知和自定义消息的区别
- .setMessage(Message.newBuilder()
- .setMsgContent(msg_content)
- .setTitle(msg_title)
- .addExtra("url",extrasparam)
- .build())
- .setOptions(Options.newBuilder()
- //此字段的值是用来指定本推送要推送的apns环境,false表示开发,true表示生产;对android和自定义消息无意义
- .setApnsProduction(ApnsProduction)
- //此字段是给开发者自己给推送编号,方便推送者分辨推送记录
- .setSendno(1)
- //此字段的值是用来指定本推送的离线保存时长,如果不传此字段则默认保存一天,最多指定保留十天,单位为秒
- .setTimeToLive(86400)
- .build())
- .build();
- }
-
- private static PushPayload buildPushObject_ios_all_alertWithTitle( String notification_title, String msg_title, String msg_content, String extrasparam) {
- return PushPayload.newBuilder()
- //指定要推送的平台,all代表当前应用配置了的所有平台,也可以传android等具体平台
- .setPlatform(Platform.ios())
- //指定推送的接收对象,all代表所有人,也可以指定已经设置成功的tag或alias或该应应用客户端调用接口获取到的registration id
- .setAudience(Audience.all())
- //jpush的通知,android的由jpush直接下发,iOS的由apns服务器下发,Winphone的由mpns下发
- .setNotification(Notification.newBuilder()
- //指定当前推送的android通知
- .addPlatformNotification(IosNotification.newBuilder()
- //传一个IosAlert对象,指定apns title、title、subtitle等
- .setAlert(msg_content)
- //直接传alert
- //此项是指定此推送的badge自动加1
- .incrBadge(1)
- //此字段的值default表示系统默认声音;传sound.caf表示此推送以项目里面打包的sound.caf声音来提醒,
- // 如果系统没有此音频则以系统默认声音提醒;此字段如果传空字符串,iOS9及以上的系统是无声音提醒,以下的系统是默认声音
- .setSound("sound.caf")
- //此字段为透传字段,不会显示在通知栏。用户可以通过此字段来做一些定制需求,如特定的key传要指定跳转的页面(value)
- .addExtra("url",extrasparam)
- //此项说明此推送是一个background推送,想了解background看:http://docs.jpush.io/client/ios_tutorials/#ios-7-background-remote-notification
- // .setContentAvailable(true)
- .build())
- .build()
- )
- //Platform指定了哪些平台就会像指定平台中符合推送条件的设备进行推送。 jpush的自定义消息,
- // sdk默认不做任何处理,不会有通知提示。建议看文档http://docs.jpush.io/guideline/faq/的
- // [通知与自定义消息有什么区别?]了解通知和自定义消息的区别
- .setMessage(Message.newBuilder()
- .setMsgContent(msg_content)
- .setTitle(msg_title)
- .addExtra("url",extrasparam)
- .build())
- .setOptions(Options.newBuilder()
- //此字段的值是用来指定本推送要推送的apns环境,false表示开发,true表示生产;对android和自定义消息无意义
- .setApnsProduction(ApnsProduction)
- //此字段是给开发者自己给推送编号,方便推送者分辨推送记录
- .setSendno(1)
- //此字段的值是用来指定本推送的离线保存时长,如果不传此字段则默认保存一天,最多指定保留十天,单位为秒
- .setTimeToLive(86400)
- .build())
- .build();
- }
-
- public static Boolean sendMessage(String phone,String notification_title,String msg_content){
- List strings=new ArrayList<>();
- strings.add(phone);
- String msg_title="";//消息内容标题
- String extrasparam="";//扩展字段
- int i= sendToAlias(strings,notification_title,msg_title,msg_content,extrasparam);
- System.out.println(i==0?"0推送失败":"1推送成功");
- return i==0?false:true;
- }
-}
\ No newline at end of file
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/AppUserDetailsServiceImpl.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/AppUserDetailsServiceImpl.java
index d47a7dc..4015133 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/AppUserDetailsServiceImpl.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/AppUserDetailsServiceImpl.java
@@ -8,6 +8,7 @@ import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.AppLoginUser;
import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.JpushClientUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.course.service.IScStudentService;
import com.ruoyi.system.service.SysTeacherService;
@@ -84,6 +85,7 @@ public class AppUserDetailsServiceImpl implements UserDetailsService
SysUser user1=new SysUser();
user1.setPassword(user.getPassword());
passwordService.validate(user1);
+
return createLoginUser(user,roles.toArray(new Long[roles.size()]) ,studentId);
}
diff --git a/ruoyi-im-client/src/main/java/com/ruoyi/imclient/sender/IMSender.java b/ruoyi-im-client/src/main/java/com/ruoyi/imclient/sender/IMSender.java
index 97b291a..0d546c2 100644
--- a/ruoyi-im-client/src/main/java/com/ruoyi/imclient/sender/IMSender.java
+++ b/ruoyi-im-client/src/main/java/com/ruoyi/imclient/sender/IMSender.java
@@ -11,6 +11,7 @@ import com.ruoyi.common.im.enums.IMSendCode;
import com.ruoyi.common.im.enums.IMTerminalType;
import com.ruoyi.common.im.model.*;
import com.ruoyi.common.im.mq.RedisMQTemplate;
+import com.ruoyi.common.utils.JpushClientUtil;
import com.ruoyi.imclient.listener.MessageListenerMulticaster;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
@@ -83,7 +84,7 @@ public class IMSender {
}
}
-
+
public void sendPrivateMessage(IMPrivateMessage message) {
List results = new LinkedList<>();
if(!Objects.isNull(message.getRecvId())){
@@ -257,7 +258,7 @@ public class IMSender {
public Boolean isOnline(Long userId) {
String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, userId.toString(), "*");
- return !Objects.requireNonNull(redisMQTemplate.keys(key)).isEmpty();
+ return !Objects.requireNonNull(redisMQTemplate.keys(key)).isEmpty();//null.isEmpty()->ture->!->false->! ->ture ->不在线
}
public List getOnlineUser(List userIds){
diff --git a/ruoyi-im-client/target/classes/com/ruoyi/imclient/sender/IMSender.class b/ruoyi-im-client/target/classes/com/ruoyi/imclient/sender/IMSender.class
index a46cce50e7070feaacce1be80cd3b76bb62e68f8..afdc80549ca220012c827a091ceb0f78f10f408e 100644
GIT binary patch
delta 710
zcmWNPdrZw?7{@=)ORK2OYHc>mTy{d%&Pie>xh+EFGB#Ps?PyjVHGfE(L#^a)`wh9o
zhPf<}9hI!)HZ{2wZ7C&Wi^(^7xc|A^#vow2z+lCLp*cihk#xsRb
zVzILf2P+9*rpsTnPlQLTM6N
zOcLuzW&^9pQL5dn;Sg&%sp)x~Twy);Na3+II!NUWX?!4^@3_R9jS@hH3?WlSvq^&4
zEDo|HjxEZUEy-+EHn$YAU5dz&GIHgHjXbF(UmDq=Yz6X-ozllHKPO8IG>hQEWJfpN{)!{jHctLNAspKMclu*xQT9mvEkNUeR
z11OUq%GFJ)5sFrQqkX&xbUT&+yJ5t46si9Un6R4A)+?RjU8y_B+
zKpvW*JTl=tF_AQwXc|otPmPNvlS#A5=egNWi@8Lrso;gVNt>yq-8Ayjw9;YT^2&7a
z+Vt?&lMvEvV!H6=9Rt;9Al>>yJ`%?#wfk9j@kM9*N&!6_Q`;x_p_3{MziH+Vo%HJ2
zr?dSPf5CGgG*!I%Geo>Bv8Rcz<+87n!B&$!MtZH`jwmU%Ryv%%M;WHig>u|_2LsEmPEHwdP06oC;08FU7DVCd;AJ%xF>$<RkSUbw%}S=xzzmuQ2Lm<4j3g;LBSDI-j3+z6Kj7E22e(nh3wWQpBnREhQceyr9GvmGqK2ysQrM)nNgpT&0F<)NzAXYP6MG>d!8N
zxGf$OslQ_NSEByzNC>48&Rt37o}^JG`>2pZJWz*~a*u~nPL*^-Q7u1tB>mJHC+dtl
zkIgWi7=P+bAkRz)4Q3^cCYdI)g%>81W^;s>M%SAXT1*A6O*O5ikv7x98}pua)5%-Y
zLx(-er^|$XU?80g<`eE})t4^9_(Bq2^)0?>x9?=pO)fp!yq7EdpjLlHGr#GePv?(z
z`zNmS+mHGt$N&dC#nC2~L~*huTjFG>?YSjX`fMYtK~i9gvBo=}VmPODQLgQ&HCh5R
X^RNZ`ML3Vse7xopG`HC5{MP>mog~4K
diff --git a/ruoyi-im-server/src/main/java/com/ruoyi/imserver/netty/processor/GroupMessageProcessor.java b/ruoyi-im-server/src/main/java/com/ruoyi/imserver/netty/processor/GroupMessageProcessor.java
index 2bb6c3d..c7a2380 100644
--- a/ruoyi-im-server/src/main/java/com/ruoyi/imserver/netty/processor/GroupMessageProcessor.java
+++ b/ruoyi-im-server/src/main/java/com/ruoyi/imserver/netty/processor/GroupMessageProcessor.java
@@ -10,6 +10,7 @@ import com.ruoyi.common.im.model.IMSendResult;
import com.ruoyi.common.im.model.IMUserInfo;
import com.ruoyi.common.im.mq.RedisMQTemplate;
import com.ruoyi.imserver.netty.UserChannelCtxMap;
+import com.ruoyi.imserver.util.LongToStringConverter;
import io.netty.channel.ChannelHandlerContext;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -37,7 +38,7 @@ public class GroupMessageProcessor extends AbstractMessageProcessor
// 推送消息到用户
IMSendInfo