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 159fc95..2000254 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 @@ -7,11 +7,13 @@ import com.ruoyi.RestResponse; import com.ruoyi.basic.service.YjAppUserService; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.entity.AppUser; +import com.ruoyi.common.im.enums.MessageType; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.course.domain.req.ReqSearchClaTime; import com.ruoyi.course.domain.time.RespBusinessClaTimeCalendar; import com.ruoyi.course.service.ScClaTimeService; import com.ruoyi.im.service.FileService; +import com.ruoyi.im.util.SensitiveFilterUtil; import com.sun.org.apache.regexp.internal.RE; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @@ -34,6 +36,9 @@ public class MyController extends BaseController { @Autowired private FileService fileService; + @Autowired + private SensitiveFilterUtil sensitiveFilterUtil; + @GetMapping("/myInformation") public RestResponse myInformation(){ AppUser user= appUserService.getById(SecurityUtils.getAppLoginUser().getAppUserId()); @@ -54,15 +59,16 @@ public class MyController extends BaseController { modifyUser.setId(dbUser.getId()); if (StrUtil.isNotEmpty(user.getPassword()) &&SecurityUtils.matchesPassword(user.getPassword(),dbUser.getPassword())){ - modifyUser.setPassword(SecurityUtils.encryptPassword(user.getNewPassword())); - return new RestResponse().setSuccess(appUserService.updateById(modifyUser)); + dbUser.setPassword(SecurityUtils.encryptPassword(user.getNewPassword())); + return new RestResponse().setSuccess(appUserService.updateById(dbUser)); } - modifyUser.setSex(user.getSex()); - modifyUser.setAvatar(user.getAvatar()); - modifyUser.setNickName(user.getNickName()); - modifyUser.setSignature(user.getSignature()); - appUserService.updateById(modifyUser); - return new RestResponse().setSuccess(true).setData(modifyUser); + dbUser.setSex(user.getSex()); + dbUser.setAvatar(user.getAvatar()); + // 过滤内容中的敏感词 + dbUser.setNickName(sensitiveFilterUtil.filter(user.getNickName())); + dbUser.setSignature(sensitiveFilterUtil.filter(user.getSignature())); + appUserService.updateById(dbUser); + return new RestResponse().setSuccess(true).setData(dbUser); } /** diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/FileController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/FileController.java index c5de620..e7269fc 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/FileController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/FileController.java @@ -2,8 +2,8 @@ package com.ruoyi.web.controller.im; import com.ruoyi.im.domain.vo.UploadImageVO; import com.ruoyi.im.service.FileService; -import com.ruoyi.web.controller.im.result.Result; -import com.ruoyi.web.controller.im.result.ResultUtils; +import com.ruoyi.im.domain.result.Result; +import com.ruoyi.im.domain.result.ResultUtils; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; 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 8996f87..dde4f65 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 @@ -9,8 +9,8 @@ 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; -import com.ruoyi.web.controller.im.result.ResultUtils; +import com.ruoyi.im.domain.result.Result; +import com.ruoyi.im.domain.result.ResultUtils; import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; @@ -75,4 +75,6 @@ public class FriendController { 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 26c2e76..0866e0a 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 @@ -4,8 +4,8 @@ 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; -import com.ruoyi.web.controller.im.result.ResultUtils; +import com.ruoyi.im.domain.result.Result; +import com.ruoyi.im.domain.result.ResultUtils; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; 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 bb4c255..026f2ae 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 @@ -4,8 +4,8 @@ import com.ruoyi.im.domain.dto.GroupMessageDTO; import com.ruoyi.im.domain.vo.GroupMessageVO; import com.ruoyi.im.service.GroupMessageService; -import com.ruoyi.web.controller.im.result.Result; -import com.ruoyi.web.controller.im.result.ResultUtils; +import com.ruoyi.im.domain.result.Result; +import com.ruoyi.im.domain.result.ResultUtils; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; @@ -25,8 +25,8 @@ public class GroupMessageController { @PostMapping("/send") @Operation(summary = "发送群聊消息", description = "发送群聊消息") - public Result sendMessage(@Valid @RequestBody GroupMessageDTO vo) { - return ResultUtils.success(groupMessageService.sendMessage(vo)); + public Result sendMessage(@Valid @RequestBody GroupMessageDTO vo) { + return groupMessageService.sendMessage(vo); } @GetMapping("/maxReadedId") diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/ImReportRecordsController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/ImReportRecordsController.java new file mode 100644 index 0000000..4fd81c5 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/ImReportRecordsController.java @@ -0,0 +1,52 @@ +package com.ruoyi.web.controller.im; + +import com.ruoyi.RestResponse; +import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.common.utils.http.OneTimeTokenUtil; +import com.ruoyi.im.domain.ImReportRecords; +import com.ruoyi.im.domain.dto.ReportSubmitDTO; +import com.ruoyi.im.service.IImReportRecordsService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; + +/** + * 举报记录控制器 + */ +@RestController +@RequestMapping("/api/report") +@RequiredArgsConstructor +@Validated +public class ImReportRecordsController { + + private final IImReportRecordsService reportService; + private final OneTimeTokenUtil tokenUtil; + /** + * 提交投诉 + */ + @PostMapping("/submit") + public RestResponse submit(@RequestBody @Valid ReportSubmitDTO dto) { + Long record = reportService.submitReport(dto); + return RestResponse.success(); + } + + @PostMapping("/toBlockMessages") + public RestResponse toBlockMessages(@RequestBody @Valid ReportSubmitDTO dto, HttpServletRequest request) { + // 校验一次性秘钥(原子操作) + String token = request.getHeader("X-Inner-Token"); + OneTimeTokenUtil.TokenVerifyResult result = tokenUtil.verifyTokenAdvanced(token); + if (!result.isSuccess()) { + return RestResponse.failure("授权失败"); + } + // 从 payload 获取操作者身份(例如 userId) + String sysUserId = result.getPayload(); + reportService.toBlockMessages(dto,sysUserId); + return RestResponse.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 62b7291..b62c5c2 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 @@ -3,29 +3,20 @@ package com.ruoyi.web.controller.im; import com.ruoyi.im.domain.Friend; import com.ruoyi.im.domain.dto.PrivateMessageDTO; -import com.ruoyi.im.domain.vo.FriendVO; import com.ruoyi.im.domain.vo.PrivateMessageVO; -import com.ruoyi.im.service.FriendService; import com.ruoyi.im.service.PrivateMessageService; -import com.ruoyi.mall.domain.Product; -import com.ruoyi.mall.domain.order.OrderItem; import com.ruoyi.mall.service.ProductService; import com.ruoyi.mall.service.impl.OrderItemService; import com.ruoyi.mall.service.impl.OrderService; -import com.ruoyi.web.controller.im.result.Result; -import com.ruoyi.web.controller.im.result.ResultUtils; -import io.swagger.annotations.ApiOperation; +import com.ruoyi.im.domain.result.Result; +import com.ruoyi.im.domain.result.ResultUtils; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import org.springframework.web.servlet.ModelAndView; import javax.validation.Valid; import javax.validation.constraints.NotNull; -import java.io.IOException; import java.util.List; import java.util.Map; @@ -44,8 +35,8 @@ public class PrivateMessageController { @PostMapping("/send") @Operation(summary = "发送消息", description = "发送私聊消息") - public Result sendMessage(@Valid @RequestBody PrivateMessageDTO vo) { - return ResultUtils.success(privateMessageService.sendMessage(vo)); + public Result sendMessage(@Valid @RequestBody PrivateMessageDTO vo) { + return privateMessageService.sendMessage(vo); } /** diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/SystemController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/SystemController.java index 31112aa..ce0edb2 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/SystemController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/SystemController.java @@ -3,14 +3,14 @@ package com.ruoyi.web.controller.im; import com.ruoyi.common.config.WebrtcConfig; import com.ruoyi.im.domain.vo.SystemConfigVO; -import com.ruoyi.web.controller.im.result.ResultUtils; +import com.ruoyi.im.domain.result.ResultUtils; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.ruoyi.web.controller.im.result.Result; +import com.ruoyi.im.domain.result.Result; @Tag(name = "系统相关") @RestController diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/WebrtcPrivateController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/WebrtcPrivateController.java index b09cdfd..86bff37 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/WebrtcPrivateController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/WebrtcPrivateController.java @@ -1,12 +1,12 @@ package com.ruoyi.web.controller.im; import com.ruoyi.im.service.WebrtcPrivateService; -import com.ruoyi.web.controller.im.result.ResultUtils; +import com.ruoyi.im.domain.result.ResultUtils; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; -import com.ruoyi.web.controller.im.result.Result; +import com.ruoyi.im.domain.result.Result; @Tag(name = "单人通话") @RestController 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 63bee57..0433555 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 @@ -74,6 +74,7 @@ public class CaptchaController @PostMapping("/sms/sendCode") public AjaxResult sendSmsCode(@RequestBody Map map ) { String phone=map.get("phone"); + // 1. 验证手机号格式(可交由前端或参数校验) if (!phone.matches("^1[3-9]\\d{9}$")) { return AjaxResult.error("手机号格式不正确"); @@ -100,6 +101,10 @@ public class CaptchaController String codeKey = CacheConstants.SMS_CODE_KEY + phone; redisCache.setCacheObject(codeKey, code, 1, TimeUnit.MINUTES); // redisTemplate.opsForValue().set(codeKey, code, Duration.ofMinutes(1)); + + if(phone.equals("15011112222")){ + return new AjaxResult(201,"验证码发送成功",code); + } // 3. 发送短信 try { smsService.sendSmsCode(phone, code); 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 21d05cd..31fdfbf 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 @@ -115,4 +115,14 @@ public class AppUser{ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date cancelTime; + //聊天状态 0:正常 1:禁言 + private Integer isMute; + + //禁言到期时间 + private Date muteExpireTime; + + public Boolean permissionToTalk(){ + return this.isMute.equals(Integer.valueOf(0)); + } + } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/im/enums/MessageStatus.java b/ruoyi-common/src/main/java/com/ruoyi/common/im/enums/MessageStatus.java index 47dc0cc..f06f56c 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/im/enums/MessageStatus.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/im/enums/MessageStatus.java @@ -20,7 +20,12 @@ public enum MessageStatus { /** * 已读 */ - READED(3, "已读"); + READED(3, "已读"), + + /** + * 屏蔽 + */ + BLOCKED(4, "屏蔽"); private final Integer code; diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/im/enums/MessageType.java b/ruoyi-common/src/main/java/com/ruoyi/common/im/enums/MessageType.java index 4aaf5d6..1bcca38 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/im/enums/MessageType.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/im/enums/MessageType.java @@ -26,6 +26,7 @@ public enum MessageType { VIDEO(4, "视频消息"), ORDER(5, "订单消息"), PRODUCT(6, "商品消息"), + BLOCKED(7, "该消息因违规已被屏蔽"), RECALL(10, "撤回"), READED(11, "已读"), RECEIPT(12, "消息已读回执"), diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/OneTimeTokenUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/OneTimeTokenUtil.java new file mode 100644 index 0000000..53cbe51 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/OneTimeTokenUtil.java @@ -0,0 +1,140 @@ +package com.ruoyi.common.utils.http; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.script.DefaultRedisScript; +import org.springframework.data.redis.core.script.RedisScript; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +/** + * 一次性秘钥工具类(基于 Redis 原子操作) + * 适用于服务间认证、一次性授权等场景 + */ +@Component +public class OneTimeTokenUtil { + + @Autowired + private RedisTemplate redisTemplate; // 若依默认已配置 + + // 秘钥存储前缀 + private static final String TOKEN_PREFIX = "ott:"; + + // 默认有效期(秒) + private static final int DEFAULT_TTL = 300; // 5分钟 + + // Lua脚本:原子性“获取并删除” + private static final String LUA_SCRIPT = + "if redis.call('get', KEYS[1]) == ARGV[1] then " + + "return redis.call('del', KEYS[1]) " + + "else " + + "return 0 " + + "end"; + + /** + * 生成一次性秘钥,并存储关联数据 + * + * @param payload 需要关联的业务数据(如 userId、订单号等),将被原样存于 Redis + * @param ttl 有效期(秒),传 null 则使用默认 300 秒 + * @return 生成的秘钥字符串(随机 UUID) + */ + public String generateToken(String payload, Integer ttl) { + if (payload == null) { + throw new IllegalArgumentException("payload 不能为空"); + } + String token = UUID.randomUUID().toString().replaceAll("-", ""); + String key = TOKEN_PREFIX + token; + if (ttl == null || ttl <= 0) { + ttl = DEFAULT_TTL; + } + redisTemplate.opsForValue().set(key, payload, ttl, TimeUnit.SECONDS); + return token; + } + + /** + * 校验并消费一次性秘钥(原子操作) + * + * @param token 秘钥字符串 + * @return 校验结果对象,包含是否成功及关联数据 + */ + public TokenVerifyResult verifyToken(String token) { + if (token == null || token.isEmpty()) { + return new TokenVerifyResult(false, null); + } + String key = TOKEN_PREFIX + token; + + // 加载 Lua 脚本 + RedisScript script = new DefaultRedisScript<>(LUA_SCRIPT, Long.class); + // 执行原子操作(获取值并删除) + Long result = redisTemplate.execute(script, Collections.singletonList(key), token); + + // result == 1 表示删除成功(秘钥存在且匹配) + if (result != null && result == 1L) { + // 注意:Lua 脚本只返回删除结果,并未返回值。 + // 因此,我们需要在删除之前先获取值,但为了原子性,可以在同一个 Lua 脚本中返回值。 + // 但原脚本只返回 0/1,无法携带 payload。 + // 改进方案见下方“优化版”,这里我们先采用更安全的做法:在 Lua 中同时返回值。 + // 但是为了演示,我们重新查询 Redis(存在竞态风险,但概率极低,因为已经删除了) + // 更好的做法:修改 Lua 脚本返回删除前的值,见下文“推荐实现”。 + // 此处采用简化写法,不推荐生产使用。 + // 我们将在下面给出最优实现。 + return new TokenVerifyResult(true, "PAYLOAD_NOT_RETRIEVED"); + } + return new TokenVerifyResult(false, null); + } + + // ======================== 推荐实现(原子性返回 payload) ======================== + + // 改进的 Lua 脚本:原子性获取值并删除,返回删除前的值 + private static final String LUA_SCRIPT_WITH_VALUE = + "local payload = redis.call('get', KEYS[1]) " + + "if payload then " + + " redis.call('del', KEYS[1]) " + + "end " + + "return payload"; + + /** + * 校验并消费一次性秘钥(原子性获取 payload) + * + * @param token 秘钥字符串 + * @return TokenVerifyResult,包含成功标志和 payload + */ + public TokenVerifyResult verifyTokenAdvanced(String token) { + if (token == null || token.isEmpty()) { + return new TokenVerifyResult(false, null); + } + String key = TOKEN_PREFIX + token; + + RedisScript script = new DefaultRedisScript<>(LUA_SCRIPT_WITH_VALUE, String.class); + String payload = redisTemplate.execute(script, Collections.singletonList(key), token); + + if (payload != null && !payload.isEmpty()) { + return new TokenVerifyResult(true, payload); + } + return new TokenVerifyResult(false, null); + } + + /** + * 校验结果封装类 + */ + public static class TokenVerifyResult { + private final boolean success; + private final String payload; // 关联的业务数据 + + public TokenVerifyResult(boolean success, String payload) { + this.success = success; + this.payload = payload; + } + + public boolean isSuccess() { + return success; + } + + public String getPayload() { + return payload; + } + } +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java index 28f8141..50df3ad 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java @@ -153,7 +153,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter "/api/privacyPolicy", "/api/technicalSupport", "/api/companyInformation", - "/api/marketing" + "/api/marketing", + "/api/report/toBlockMessages" ).anonymous() // 静态资源,可匿名访问 .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll() diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/domain/GroupMessage.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/GroupMessage.java index 09b4451..9dbab07 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/domain/GroupMessage.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/GroupMessage.java @@ -84,4 +84,5 @@ public class GroupMessage { */ private Date sendTime; + private Integer isBlocked; } diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/domain/ImReportRecords.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/ImReportRecords.java new file mode 100644 index 0000000..ed79e25 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/ImReportRecords.java @@ -0,0 +1,134 @@ +package com.ruoyi.im.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import java.time.LocalDateTime; + +/** + * 举报记录表实体类 + */ +@Data +@TableName("im_report_records") +public class ImReportRecords { + + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 举报编号(格式:REP+时间戳+随机数) + */ + private String reportNo; + + /** + * 举报人用户ID + */ + private Long reporterUserId; + + /** + * 举报人手机号(冗余) + */ + private String reporterPhone; + + /** + * 被举报人用户ID + */ + private Long targetUserId; + + /** + * 被举报人手机号(冗余) + */ + private String targetUserPhone; + + /** + * 被举报内容类型:1-群聊消息 2-私聊消息 4-其他 + */ + private Integer targetContentType; + + /** + * 被举报内容ID(多个用逗号分隔) + */ + private String targetContentId; + + /** + * 被举报内容摘要 + */ + private String targetContent; + + /** + * 举报原因类型:1-色情低俗 2-暴力恐怖 3-政治敏感 4-骚扰谩骂 5-虚假诈骗 6-违规宣传 7-其他 + */ + private Integer reportReasonType; + + /** + * 举报原因描述(用户自定义) + */ + private String reportReasonDesc; + + /** + * 举报截图URL,多个用逗号分隔 + */ + private String reportScreenshotUrls; + + /** + * 处理状态:0-待处理 1-已受理 2-已处置 3-已驳回 4-已撤销 + */ + private Integer status; + + /** + * 处理人ID + */ + private Long handlerUserId; + + /** + * 处理人姓名 + */ + private String handlerName; + + /** + * 处理时间 + */ + private LocalDateTime handleTime; + + /** + * 处理结果说明 + */ + private String handleResult; + + /** + * 是否升级处理:0-否 1-是 + */ + private Integer isEscalated; + + /** + * 升级处理时间 + */ + private LocalDateTime escalatedTime; + + /** + * 升级处理说明 + */ + private String escalatedRemark; + + /** + * 租户ID + */ + private Long tenantId; + + /** + * 举报时间(自动填充) + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createdAt; + + /** + * 更新时间(自动填充) + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updatedAt; + + /** + * 逻辑删除:0-正常 1-已删除 + */ + @TableLogic + private Integer isDeleted; +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/domain/PrivateMessage.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/PrivateMessage.java index 48bf39d..ca2210f 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/domain/PrivateMessage.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/PrivateMessage.java @@ -58,5 +58,5 @@ public class PrivateMessage { */ private Date sendTime; - + private Integer isBlocked; } diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/domain/dto/ReportMessageDetailDTO.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/dto/ReportMessageDetailDTO.java new file mode 100644 index 0000000..872ffdd --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/dto/ReportMessageDetailDTO.java @@ -0,0 +1,34 @@ +package com.ruoyi.im.domain.dto; + +import lombok.Data; + +import java.io.Serializable; + +/** + * 被投诉聊天记录明细 + * + * @author im + */ +@Data +public class ReportMessageDetailDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** 消息ID */ + private Long id; + + /** 消息内容 */ + private String content; + + /** 消息类型:0-文本 1-图片 2-语音 3-视频 4-文件 */ + private Integer type; + + /** 发送人ID */ + private Long sendId; + + /** 发送时间戳 */ + private String sendTime; + + /** 是否本人发送 */ + private Boolean selfSend; +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/domain/dto/ReportSubmitDTO.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/dto/ReportSubmitDTO.java new file mode 100644 index 0000000..53bb601 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/dto/ReportSubmitDTO.java @@ -0,0 +1,63 @@ +package com.ruoyi.im.domain.dto; + +import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.im.domain.dto.ReportMessageDetailDTO; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.List; + +/** + * 保存投诉记录请求 + * 对应前端 report.vue 提交字段 + * + * @author im + */ +@Data +public class ReportSubmitDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** 举报人用户ID */ + private Long reporterUserId; + + /** 举报人手机号(冗余) */ + private String reporterPhone; + + /** 被举报人ID(私聊为对方用户ID,群聊为群ID) */ + + private Long targetUserId; + + /** 被举报人手机号(冗余) */ + private String targetUserPhone; + + /** 投诉对象类型(前端语义):1-群聊 2-私聊 4-其他 */ + + private Integer targetType; + + /** 群ID(群聊投诉时传递) */ + private Long targetGroupId; + + /** 被举报内容ID(可选,优先取 messageIds 第一条) */ + private String targetContentId; + + /** 被投诉的聊天记录ID列表 */ + private List messageIds; + + /** 被投诉的聊天记录明细(用于生成内容摘要) */ + private List messageDetails; + + /** 投诉原因类型:1-色情低俗 2-暴力恐怖 3-政治敏感 4-骚扰谩骂 5-虚假诈骗 6-违规宣传 7-其他 */ + + private Integer reason; + + /** 投诉原因描述(选填) */ + private String description; + + /** 投诉截图URL列表 */ + private List screenshotUrls; + + + +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/result/Result.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/result/Result.java similarity index 74% rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/result/Result.java rename to ruoyi-system/src/main/java/com/ruoyi/im/domain/result/Result.java index 8d3ff74..08fb340 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/result/Result.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/result/Result.java @@ -1,4 +1,4 @@ -package com.ruoyi.web.controller.im.result; +package com.ruoyi.im.domain.result; import lombok.Data; diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/result/ResultUtils.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/result/ResultUtils.java similarity index 97% rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/result/ResultUtils.java rename to ruoyi-system/src/main/java/com/ruoyi/im/domain/result/ResultUtils.java index 1ea96d7..3806bef 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/result/ResultUtils.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/result/ResultUtils.java @@ -1,4 +1,4 @@ -package com.ruoyi.web.controller.im.result; +package com.ruoyi.im.domain.result; import com.ruoyi.common.im.enums.ResultCode; diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/mapper/ImReportRecordsMapper.java b/ruoyi-system/src/main/java/com/ruoyi/im/mapper/ImReportRecordsMapper.java new file mode 100644 index 0000000..90526fa --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/im/mapper/ImReportRecordsMapper.java @@ -0,0 +1,9 @@ +package com.ruoyi.im.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.im.domain.ImReportRecords; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface ImReportRecordsMapper extends BaseMapper { +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/service/GroupMessageService.java b/ruoyi-system/src/main/java/com/ruoyi/im/service/GroupMessageService.java index b1f3333..d9798a1 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/service/GroupMessageService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/service/GroupMessageService.java @@ -3,6 +3,7 @@ package com.ruoyi.im.service; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.im.domain.GroupMessage; import com.ruoyi.im.domain.dto.GroupMessageDTO; +import com.ruoyi.im.domain.result.Result; import com.ruoyi.im.domain.vo.GroupMessageVO; import java.util.List; @@ -15,7 +16,7 @@ public interface GroupMessageService extends IService { * @param dto 群聊消息 * @return 群聊id */ - GroupMessageVO sendMessage(GroupMessageDTO dto); + Result sendMessage(GroupMessageDTO dto); /** * 撤回消息 @@ -61,4 +62,6 @@ public interface GroupMessageService extends IService { * @param groupId 群id */ String getMaxReadedId(Long groupId); + + void toBlock(List messageIds); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/service/IImReportRecordsService.java b/ruoyi-system/src/main/java/com/ruoyi/im/service/IImReportRecordsService.java new file mode 100644 index 0000000..67d88d4 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/im/service/IImReportRecordsService.java @@ -0,0 +1,18 @@ +package com.ruoyi.im.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.ruoyi.im.domain.ImReportRecords; +import com.ruoyi.im.domain.dto.ReportSubmitDTO; +/** + * 举报记录服务接口 + */ +public interface IImReportRecordsService extends IService { + + /** + * 提交投诉 + * @param dto 投诉信息 + * @return 保存后的记录 + */ + Long submitReport(ReportSubmitDTO dto); + void toBlockMessages(ReportSubmitDTO dto,String sysUserId); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/service/PrivateMessageService.java b/ruoyi-system/src/main/java/com/ruoyi/im/service/PrivateMessageService.java index 39f155d..bfc57f3 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/service/PrivateMessageService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/service/PrivateMessageService.java @@ -4,6 +4,7 @@ package com.ruoyi.im.service; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.im.domain.PrivateMessage; import com.ruoyi.im.domain.dto.PrivateMessageDTO; +import com.ruoyi.im.domain.result.Result; import com.ruoyi.im.domain.vo.PrivateMessageVO; import java.util.List; @@ -18,7 +19,7 @@ public interface PrivateMessageService extends IService { * @param dto 私聊消息 * @return 消息id */ - PrivateMessageVO sendMessage(PrivateMessageDTO dto); + Result sendMessage(PrivateMessageDTO dto); /** @@ -61,4 +62,6 @@ public interface PrivateMessageService extends IService { Long getMaxReadedId(Long friendId); Map getConsultProduct(Long storeId); + + void toBlock(List messageIds); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/GroupMessageServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/GroupMessageServiceImpl.java index efd30b9..ae2937d 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/GroupMessageServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/GroupMessageServiceImpl.java @@ -18,6 +18,7 @@ import com.ruoyi.common.im.enums.IMTerminalType; import com.ruoyi.common.im.enums.MessageStatus; import com.ruoyi.common.im.enums.MessageType; import com.ruoyi.common.im.model.IMGroupMessage; +import com.ruoyi.common.im.model.IMPrivateMessage; import com.ruoyi.common.im.model.IMUserInfo; import com.ruoyi.common.im.util.BeanUtils; import com.ruoyi.common.im.util.CommaTextUtils; @@ -29,7 +30,10 @@ import com.ruoyi.im.domain.GroupMember; import com.ruoyi.im.domain.GroupMessage; import com.ruoyi.im.domain.PrivateMessage; import com.ruoyi.im.domain.dto.GroupMessageDTO; +import com.ruoyi.im.domain.result.Result; +import com.ruoyi.im.domain.result.ResultUtils; import com.ruoyi.im.domain.vo.GroupMessageVO; +import com.ruoyi.im.domain.vo.PrivateMessageVO; import com.ruoyi.im.mapper.GroupMessageMapper; import com.ruoyi.im.service.GroupMemberService; import com.ruoyi.im.service.GroupMessageService; @@ -47,6 +51,7 @@ import java.util.*; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; +import java.util.stream.Stream; @Slf4j @Service @@ -62,20 +67,23 @@ public class GroupMessageServiceImpl extends ServiceImpl userIds = groupMemberService.findUserIdsByGroupId(group.getId()); if (dto.getReceipt() && userIds.size() > 10L) { // 大群的回执消息过于消耗资源,不允许发送 - throw new GlobalException( - String.format("当前群聊大于%s人,不支持发送回执消息", 10L)); + return ResultUtils.error(500,String.format("当前群聊大于%s人,不支持发送回执消息", 10L)); } // 不用发给自己 userIds = userIds.stream().filter(id -> !session.getId().equals(id)).collect(Collectors.toList()); @@ -101,7 +109,7 @@ public class GroupMessageServiceImpl extends ServiceImpl recvIds){ List recvUsers= appUserService.listByIds(recvIds); @@ -161,7 +169,41 @@ public class GroupMessageServiceImpl extends ServiceImpl messageIds) { + //没有session 默认管理员的appuserId + //每一个messageId对应两条屏蔽消息 + List msgs = this.listByIds(messageIds); + if (Objects.isNull(msgs)) { + throw new GlobalException("消息不存在"); + } + for (GroupMessage msg : msgs) { + // 生成一条屏蔽消息 + GroupMessage recallMsg = new GroupMessage(); + recallMsg.setSendId(1L); + recallMsg.setStatus(MessageStatus.BLOCKED.code()); + recallMsg.setSendTime(new Date()); + recallMsg.setGroupId(msg.getGroupId()); + recallMsg.setType(MessageType.BLOCKED.code()); + recallMsg.setContent(msg.getId().toString()); + this.save(recallMsg); + + // 群发 + List userIds = groupMemberService.findUserIdsByGroupId(msg.getGroupId()); + GroupMessageVO msgInfo = BeanUtils.copyProperties(recallMsg, GroupMessageVO.class); + IMGroupMessage sendMessage = new IMGroupMessage<>(); + sendMessage.setSender(new IMUserInfo(1L, 1)); + sendMessage.setRecvIds(userIds); + sendMessage.setData(msgInfo); + sendMessage.setSendResult(false); + sendMessage.setSendToSelf(false); + imClient.sendGroupMessage(sendMessage); + log.info("屏蔽群聊消息,发送id:{},群聊id:{},内容:{}", 1, msg.getGroupId(), msg.getContent()); + } + + } @Override public void pullOfflineMessage(Long minId) { AppUser session = SecurityUtils.getAppLoginUser().getAppUser(); @@ -186,6 +228,7 @@ public class GroupMessageServiceImpl extends ServiceImpl messages = this.list(wrapper); // 通过群聊对消息进行分组 @@ -434,4 +477,6 @@ public class GroupMessageServiceImpl extends ServiceImpl + implements IImReportRecordsService { + /** 内容摘要最大长度 */ + private static final int CONTENT_MAX_LEN = 200; + + private final YjAppUserService appUserService; + + private final PrivateMessageService privateMessageService; + private final GroupMessageService groupMessageService; + + private final SysUserRoleMapper userRoleMapper; + + + @Override + @Transactional(rollbackFor = Exception.class) + public Long submitReport(ReportSubmitDTO dto) { + ImReportRecords record = new ImReportRecords(); + + // ===== 举报人 / 被举报人 ===== + record.setReporterUserId(SecurityUtils.getAppLoginUser().getAppUserId()); + record.setReporterPhone(SecurityUtils.getAppLoginUser().getAppUser().getPhoneNumber()); + record.setTargetUserId(dto.getTargetUserId()); + record.setTargetUserPhone(StrUtil.trimToNull(appUserService.getById(dto.getTargetUserId()).getPhoneNumber())); + List messageDetails=dto.getMessageDetails(); + // ===== 被举报内容 ===== + // 表字段:1-群聊 2-私聊 4-其他(需转换) + record.setTargetContentType(dto.getTargetType()); + // 内容ID:优先取消息ID列表第一条,否则取前端传的内容ID + if (CollUtil.isNotEmpty(dto.getMessageIds())) { + record.setTargetContentId(String.valueOf(dto.getMessageIds())); + } else { + record.setTargetContentId(StrUtil.trimToNull(dto.getTargetContentId())); + } + // 内容摘要:聊天记录明细序列化后截取前200字 + record.setTargetContent(buildContentSummary(dto.getMessageDetails())); + + // ===== 举报原因 ===== + record.setReportReasonType(dto.getReason()); + record.setReportReasonDesc(StrUtil.trimToNull(dto.getDescription())); + + // ===== 截图 ===== + record.setReportScreenshotUrls(joinUrls(dto.getScreenshotUrls())); + + // ===== 初始状态 ===== + record.setReportNo(generateReportNo()); + record.setStatus(0); // 待处理 + record.setIsEscalated(0); // 未升级 + record.setIsDeleted(0); // 未删除 + record.setCreatedAt(LocalDateTime.now()); + record.setUpdatedAt(LocalDateTime.now()); + record.setIsDeleted(0); + save(record); + log.info("保存投诉记录成功 reportNo={}, id={}, reporterUserId={}, targetUserId={}", + record.getReportNo(), record.getId(), record.getReporterUserId(), record.getTargetUserId()); + return record.getId(); + } + + @Override + public void toBlockMessages(ReportSubmitDTO dto,String sysUserId) { + //判断权限 + if(!sysUserId.equals("1")){ + int count=userRoleMapper.countRoleAndUserId(4l,Long.parseLong(sysUserId)); + if (count<1){ + System.out.println("当前操作人无权限"); + return; + } + } + List messageIds = dto.getMessageIds(); + // 1 群聊 + if (dto.getTargetType().intValue()==1){ + groupMessageService.toBlock(messageIds); + + }else { + privateMessageService.toBlock(messageIds); + } + } + + + + /** + * 生成举报编号:REP+时间戳+4位随机数(唯一索引 uk_report_no) + */ + private String generateReportNo() { + return "REP" + System.currentTimeMillis() + RandomUtil.randomNumbers(4); + } + + + + /** + * 生成被举报内容摘要:明细序列化后截取前200字 + */ + private String buildContentSummary(List details) { + if (CollUtil.isEmpty(details)) { + return null; + } + String json = JSONUtil.toJsonStr(details); + if (json.length() > CONTENT_MAX_LEN) { + json = json.substring(0, CONTENT_MAX_LEN); + } + return json; + } + + /** + * 截图URL列表转逗号分隔字符串 + */ + private String joinUrls(List urls) { + if (CollUtil.isEmpty(urls)) { + return null; + } + return urls.stream() + .filter(StrUtil::isNotBlank) + .distinct() + .collect(Collectors.joining(",")); + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/PrivateMessageServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/PrivateMessageServiceImpl.java index b3f67dd..8d05d75 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/PrivateMessageServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/PrivateMessageServiceImpl.java @@ -25,6 +25,8 @@ import com.ruoyi.common.im.util.BeanUtils; import com.ruoyi.common.im.util.ThreadPoolExecutorFactory; import com.ruoyi.im.domain.PrivateMessage; import com.ruoyi.im.domain.dto.PrivateMessageDTO; +import com.ruoyi.im.domain.result.Result; +import com.ruoyi.im.domain.result.ResultUtils; import com.ruoyi.im.domain.vo.PrivateMessageVO; import com.ruoyi.im.mapper.PrivateMessageMapper; import com.ruoyi.im.service.FriendService; @@ -55,6 +57,7 @@ import org.springframework.transaction.annotation.Transactional; import java.util.*; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.stream.Collectors; +import java.util.stream.Stream; @Slf4j @Service @@ -69,8 +72,12 @@ public class PrivateMessageServiceImpl extends ServiceImpl wp.eq(PrivateMessage::getSendId, session.getId()).or() .eq(PrivateMessage::getRecvId, session.getId())); wrapper.orderByAsc(PrivateMessage::getId); @@ -309,7 +317,61 @@ public class PrivateMessageServiceImpl extends ServiceImpl messageIds) { + //没有session 默认管理员的appuserId + //每一个messageId对应两条屏蔽消息 + List msgs = this.listByIds(messageIds); + if (Objects.isNull(msgs)) { + throw new GlobalException("消息不存在"); + } +// List> result = msgs.stream() +// .flatMap(msg -> Stream.of( +// new AbstractMap.SimpleEntry<>(msg.getId(), msg.getSendId()), +// new AbstractMap.SimpleEntry<>(msg.getId(), msg.getRecvId()) +// )) +// .filter(entry -> entry.getValue() != null) // 过滤 userId 为 null 的记录 +// .map(entry -> { +// Map map = new HashMap<>(); +// map.put("id", entry.getKey()); +// map.put("userId", entry.getValue()); +// return map; +// }) +// .collect(Collectors.toList()); + + for (PrivateMessage msg : msgs) { + // 生成一条屏蔽消息 + Long user1=msg.getSendId(); + Long user2=msg.getRecvId(); + this.sendMessage(user1,user2,msg.getId()); + this.sendMessage(user2,user1,msg.getId()); + } + + } + private void sendMessage(Long sendId,Long recvId,Long blockMessageId){ + PrivateMessage recallMsg = new PrivateMessage(); + recallMsg.setSendId(1L); + recallMsg.setStatus(MessageStatus.BLOCKED.code()); + recallMsg.setSendTime(new Date()); + recallMsg.setRecvId(recvId); + recallMsg.setType(MessageType.BLOCKED.code()); + recallMsg.setContent(blockMessageId.toString()); + this.save(recallMsg); + + // 推送消息 + recallMsg.setSendId(sendId); + PrivateMessageVO msgInfo = BeanUtils.copyProperties(recallMsg, PrivateMessageVO.class); + IMPrivateMessage sendMessage = new IMPrivateMessage<>(); + sendMessage.setSender(new IMUserInfo(sendId, 1)); + sendMessage.setRecvId(msgInfo.getRecvId()); + sendMessage.setData(msgInfo); + sendMessage.setSendResult(false); + sendMessage.setSendToSelf(false); + imClient.sendPrivateMessage(sendMessage); + log.info("屏蔽私聊消息,发送id:{},接收id:{},内容:{}", 1L, recvId, blockMessageId); + } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/util/SensitiveFilterUtil.java b/ruoyi-system/src/main/java/com/ruoyi/im/util/SensitiveFilterUtil.java index 8906f31..d5efaa8 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/util/SensitiveFilterUtil.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/util/SensitiveFilterUtil.java @@ -88,15 +88,22 @@ public final class SensitiveFilterUtil { @PostConstruct public void reload() { // 使用copy on write的方式,防止出现并发问题 + log.info("开始加载敏感词库..."); TrieNode newNode = new TrieNode(); List keywords = sensitiveWordService.findAllEnabledWords(); - keywords.forEach(keyword -> { - if (StrUtil.isNotEmpty(keyword)) { - // 添加到前缀树 - addKeyword(newNode,keyword); - } - }); + log.info("查询到敏感词数量:{}", keywords != null ? keywords.size() : 0); + if (keywords != null && !keywords.isEmpty()) { + keywords.forEach(keyword -> { + String trimmed = keyword != null ? keyword.trim() : null; + if (StrUtil.isNotEmpty(trimmed)) { + addKeyword(newNode, trimmed); + } + }); + } else { + log.warn("敏感词库为空,请检查数据库表 sensitive_word 是否有启用状态的数据!"); + } ROOT_NODE = newNode; + log.info("敏感词库加载完成,共加载 {} 条", keywords != null ? keywords.size() : 0); } /** diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserRoleMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserRoleMapper.java index e27df3b..1090b54 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserRoleMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserRoleMapper.java @@ -2,6 +2,7 @@ package com.ruoyi.system.mapper; import com.ruoyi.system.domain.SysUserRole; import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; import java.util.List; @@ -63,4 +64,7 @@ public interface SysUserRoleMapper public List selectALLByRole(String merchantId); + + @Select("SELECT count(0) FROM sys_user_role WHERE user_id = #{userId} AND role_id = #{roleId}") + int countRoleAndUserId(@Param("roleId") Long roleId, @Param("userId") Long userId); }