投诉消息撤回 配置上架所需测试账号

master
15004070936 5 days ago
parent 9ca0321317
commit 5dd7ee034e

@ -7,11 +7,13 @@ import com.ruoyi.RestResponse;
import com.ruoyi.basic.service.YjAppUserService; import com.ruoyi.basic.service.YjAppUserService;
import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.entity.AppUser; import com.ruoyi.common.core.domain.entity.AppUser;
import com.ruoyi.common.im.enums.MessageType;
import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.course.domain.req.ReqSearchClaTime; import com.ruoyi.course.domain.req.ReqSearchClaTime;
import com.ruoyi.course.domain.time.RespBusinessClaTimeCalendar; import com.ruoyi.course.domain.time.RespBusinessClaTimeCalendar;
import com.ruoyi.course.service.ScClaTimeService; import com.ruoyi.course.service.ScClaTimeService;
import com.ruoyi.im.service.FileService; import com.ruoyi.im.service.FileService;
import com.ruoyi.im.util.SensitiveFilterUtil;
import com.sun.org.apache.regexp.internal.RE; import com.sun.org.apache.regexp.internal.RE;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -34,6 +36,9 @@ public class MyController extends BaseController {
@Autowired @Autowired
private FileService fileService; private FileService fileService;
@Autowired
private SensitiveFilterUtil sensitiveFilterUtil;
@GetMapping("/myInformation") @GetMapping("/myInformation")
public RestResponse myInformation(){ public RestResponse myInformation(){
AppUser user= appUserService.getById(SecurityUtils.getAppLoginUser().getAppUserId()); AppUser user= appUserService.getById(SecurityUtils.getAppLoginUser().getAppUserId());
@ -54,15 +59,16 @@ public class MyController extends BaseController {
modifyUser.setId(dbUser.getId()); modifyUser.setId(dbUser.getId());
if (StrUtil.isNotEmpty(user.getPassword()) if (StrUtil.isNotEmpty(user.getPassword())
&&SecurityUtils.matchesPassword(user.getPassword(),dbUser.getPassword())){ &&SecurityUtils.matchesPassword(user.getPassword(),dbUser.getPassword())){
modifyUser.setPassword(SecurityUtils.encryptPassword(user.getNewPassword())); dbUser.setPassword(SecurityUtils.encryptPassword(user.getNewPassword()));
return new RestResponse().setSuccess(appUserService.updateById(modifyUser)); return new RestResponse().setSuccess(appUserService.updateById(dbUser));
} }
modifyUser.setSex(user.getSex()); dbUser.setSex(user.getSex());
modifyUser.setAvatar(user.getAvatar()); dbUser.setAvatar(user.getAvatar());
modifyUser.setNickName(user.getNickName()); // 过滤内容中的敏感词
modifyUser.setSignature(user.getSignature()); dbUser.setNickName(sensitiveFilterUtil.filter(user.getNickName()));
appUserService.updateById(modifyUser); dbUser.setSignature(sensitiveFilterUtil.filter(user.getSignature()));
return new RestResponse().setSuccess(true).setData(modifyUser); appUserService.updateById(dbUser);
return new RestResponse().setSuccess(true).setData(dbUser);
} }
/** /**

@ -2,8 +2,8 @@ package com.ruoyi.web.controller.im;
import com.ruoyi.im.domain.vo.UploadImageVO; import com.ruoyi.im.domain.vo.UploadImageVO;
import com.ruoyi.im.service.FileService; import com.ruoyi.im.service.FileService;
import com.ruoyi.web.controller.im.result.Result; import com.ruoyi.im.domain.result.Result;
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.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;

@ -9,8 +9,8 @@ import com.ruoyi.im.domain.vo.FriendVO;
import com.ruoyi.im.domain.vo.OnlineTerminalVO; import com.ruoyi.im.domain.vo.OnlineTerminalVO;
import com.ruoyi.im.domain.vo.UserVO; import com.ruoyi.im.domain.vo.UserVO;
import com.ruoyi.im.service.FriendService; import com.ruoyi.im.service.FriendService;
import com.ruoyi.web.controller.im.result.Result; import com.ruoyi.im.domain.result.Result;
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.Operation;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -75,4 +75,6 @@ public class FriendController {
public Result<List<OnlineTerminalVO>> getOnlineTerminal(@NotNull @RequestParam("userIds") String userIds) { public Result<List<OnlineTerminalVO>> getOnlineTerminal(@NotNull @RequestParam("userIds") String userIds) {
return ResultUtils.success(friendService.getOnlineTerminals(userIds)); return ResultUtils.success(friendService.getOnlineTerminals(userIds));
} }
} }

@ -4,8 +4,8 @@ import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.im.domain.vo.GroupMemberVO; import com.ruoyi.im.domain.vo.GroupMemberVO;
import com.ruoyi.im.domain.vo.GroupVO; import com.ruoyi.im.domain.vo.GroupVO;
import com.ruoyi.im.service.GroupService; import com.ruoyi.im.service.GroupService;
import com.ruoyi.web.controller.im.result.Result; import com.ruoyi.im.domain.result.Result;
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.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;

@ -4,8 +4,8 @@ import com.ruoyi.im.domain.dto.GroupMessageDTO;
import com.ruoyi.im.domain.vo.GroupMessageVO; import com.ruoyi.im.domain.vo.GroupMessageVO;
import com.ruoyi.im.service.GroupMessageService; import com.ruoyi.im.service.GroupMessageService;
import com.ruoyi.web.controller.im.result.Result; import com.ruoyi.im.domain.result.Result;
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.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -25,8 +25,8 @@ public class GroupMessageController {
@PostMapping("/send") @PostMapping("/send")
@Operation(summary = "发送群聊消息", description = "发送群聊消息") @Operation(summary = "发送群聊消息", description = "发送群聊消息")
public Result<GroupMessageVO> sendMessage(@Valid @RequestBody GroupMessageDTO vo) { public Result sendMessage(@Valid @RequestBody GroupMessageDTO vo) {
return ResultUtils.success(groupMessageService.sendMessage(vo)); return groupMessageService.sendMessage(vo);
} }
@GetMapping("/maxReadedId") @GetMapping("/maxReadedId")

@ -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();
}
}

@ -3,29 +3,20 @@ package com.ruoyi.web.controller.im;
import com.ruoyi.im.domain.Friend; import com.ruoyi.im.domain.Friend;
import com.ruoyi.im.domain.dto.PrivateMessageDTO; 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.domain.vo.PrivateMessageVO;
import com.ruoyi.im.service.FriendService;
import com.ruoyi.im.service.PrivateMessageService; 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.ProductService;
import com.ruoyi.mall.service.impl.OrderItemService; import com.ruoyi.mall.service.impl.OrderItemService;
import com.ruoyi.mall.service.impl.OrderService; import com.ruoyi.mall.service.impl.OrderService;
import com.ruoyi.web.controller.im.result.Result; import com.ruoyi.im.domain.result.Result;
import com.ruoyi.web.controller.im.result.ResultUtils; import com.ruoyi.im.domain.result.ResultUtils;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor; 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.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import javax.validation.Valid; import javax.validation.Valid;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -44,8 +35,8 @@ public class PrivateMessageController {
@PostMapping("/send") @PostMapping("/send")
@Operation(summary = "发送消息", description = "发送私聊消息") @Operation(summary = "发送消息", description = "发送私聊消息")
public Result<PrivateMessageVO> sendMessage(@Valid @RequestBody PrivateMessageDTO vo) { public Result sendMessage(@Valid @RequestBody PrivateMessageDTO vo) {
return ResultUtils.success(privateMessageService.sendMessage(vo)); return privateMessageService.sendMessage(vo);
} }
/** /**

@ -3,14 +3,14 @@ package com.ruoyi.web.controller.im;
import com.ruoyi.common.config.WebrtcConfig; import com.ruoyi.common.config.WebrtcConfig;
import com.ruoyi.im.domain.vo.SystemConfigVO; 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.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.web.controller.im.result.Result; import com.ruoyi.im.domain.result.Result;
@Tag(name = "系统相关") @Tag(name = "系统相关")
@RestController @RestController

@ -1,12 +1,12 @@
package com.ruoyi.web.controller.im; package com.ruoyi.web.controller.im;
import com.ruoyi.im.service.WebrtcPrivateService; 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.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import com.ruoyi.web.controller.im.result.Result; import com.ruoyi.im.domain.result.Result;
@Tag(name = "单人通话") @Tag(name = "单人通话")
@RestController @RestController

@ -74,6 +74,7 @@ public class CaptchaController
@PostMapping("/sms/sendCode") @PostMapping("/sms/sendCode")
public AjaxResult sendSmsCode(@RequestBody Map<String,String> map ) { public AjaxResult sendSmsCode(@RequestBody Map<String,String> map ) {
String phone=map.get("phone"); String phone=map.get("phone");
// 1. 验证手机号格式(可交由前端或参数校验) // 1. 验证手机号格式(可交由前端或参数校验)
if (!phone.matches("^1[3-9]\\d{9}$")) { if (!phone.matches("^1[3-9]\\d{9}$")) {
return AjaxResult.error("手机号格式不正确"); return AjaxResult.error("手机号格式不正确");
@ -100,6 +101,10 @@ public class CaptchaController
String codeKey = CacheConstants.SMS_CODE_KEY + phone; String codeKey = CacheConstants.SMS_CODE_KEY + phone;
redisCache.setCacheObject(codeKey, code, 1, TimeUnit.MINUTES); redisCache.setCacheObject(codeKey, code, 1, TimeUnit.MINUTES);
// redisTemplate.opsForValue().set(codeKey, code, Duration.ofMinutes(1)); // redisTemplate.opsForValue().set(codeKey, code, Duration.ofMinutes(1));
if(phone.equals("15011112222")){
return new AjaxResult(201,"验证码发送成功",code);
}
// 3. 发送短信 // 3. 发送短信
try { try {
smsService.sendSmsCode(phone, code); smsService.sendSmsCode(phone, code);

@ -115,4 +115,14 @@ public class AppUser{
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date cancelTime; private Date cancelTime;
//聊天状态 0正常 1禁言
private Integer isMute;
//禁言到期时间
private Date muteExpireTime;
public Boolean permissionToTalk(){
return this.isMute.equals(Integer.valueOf(0));
}
} }

@ -20,7 +20,12 @@ public enum MessageStatus {
/** /**
* *
*/ */
READED(3, "已读"); READED(3, "已读"),
/**
*
*/
BLOCKED(4, "屏蔽");
private final Integer code; private final Integer code;

@ -26,6 +26,7 @@ public enum MessageType {
VIDEO(4, "视频消息"), VIDEO(4, "视频消息"),
ORDER(5, "订单消息"), ORDER(5, "订单消息"),
PRODUCT(6, "商品消息"), PRODUCT(6, "商品消息"),
BLOCKED(7, "该消息因违规已被屏蔽"),
RECALL(10, "撤回"), RECALL(10, "撤回"),
READED(11, "已读"), READED(11, "已读"),
RECEIPT(12, "消息已读回执"), RECEIPT(12, "消息已读回执"),

@ -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<String, String> 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<Long> 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<String> 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;
}
}
}

@ -153,7 +153,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
"/api/privacyPolicy", "/api/privacyPolicy",
"/api/technicalSupport", "/api/technicalSupport",
"/api/companyInformation", "/api/companyInformation",
"/api/marketing" "/api/marketing",
"/api/report/toBlockMessages"
).anonymous() ).anonymous()
// 静态资源,可匿名访问 // 静态资源,可匿名访问
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll() .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()

@ -84,4 +84,5 @@ public class GroupMessage {
*/ */
private Date sendTime; private Date sendTime;
private Integer isBlocked;
} }

@ -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;
}

@ -58,5 +58,5 @@ public class PrivateMessage {
*/ */
private Date sendTime; private Date sendTime;
private Integer isBlocked;
} }

@ -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;
}

@ -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<Long> messageIds;
/** 被投诉的聊天记录明细(用于生成内容摘要) */
private List<ReportMessageDetailDTO> messageDetails;
/** 投诉原因类型1-色情低俗 2-暴力恐怖 3-政治敏感 4-骚扰谩骂 5-虚假诈骗 6-违规宣传 7-其他 */
private Integer reason;
/** 投诉原因描述(选填) */
private String description;
/** 投诉截图URL列表 */
private List<String> screenshotUrls;
}

@ -1,4 +1,4 @@
package com.ruoyi.web.controller.im.result; package com.ruoyi.im.domain.result;
import lombok.Data; import lombok.Data;

@ -1,4 +1,4 @@
package com.ruoyi.web.controller.im.result; package com.ruoyi.im.domain.result;
import com.ruoyi.common.im.enums.ResultCode; import com.ruoyi.common.im.enums.ResultCode;

@ -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<ImReportRecords> {
}

@ -3,6 +3,7 @@ package com.ruoyi.im.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.im.domain.GroupMessage; import com.ruoyi.im.domain.GroupMessage;
import com.ruoyi.im.domain.dto.GroupMessageDTO; import com.ruoyi.im.domain.dto.GroupMessageDTO;
import com.ruoyi.im.domain.result.Result;
import com.ruoyi.im.domain.vo.GroupMessageVO; import com.ruoyi.im.domain.vo.GroupMessageVO;
import java.util.List; import java.util.List;
@ -15,7 +16,7 @@ public interface GroupMessageService extends IService<GroupMessage> {
* @param dto * @param dto
* @return id * @return id
*/ */
GroupMessageVO sendMessage(GroupMessageDTO dto); Result sendMessage(GroupMessageDTO dto);
/** /**
* *
@ -61,4 +62,6 @@ public interface GroupMessageService extends IService<GroupMessage> {
* @param groupId id * @param groupId id
*/ */
String getMaxReadedId(Long groupId); String getMaxReadedId(Long groupId);
void toBlock(List<Long> messageIds);
} }

@ -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<ImReportRecords> {
/**
*
* @param dto
* @return
*/
Long submitReport(ReportSubmitDTO dto);
void toBlockMessages(ReportSubmitDTO dto,String sysUserId);
}

@ -4,6 +4,7 @@ package com.ruoyi.im.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.im.domain.PrivateMessage; import com.ruoyi.im.domain.PrivateMessage;
import com.ruoyi.im.domain.dto.PrivateMessageDTO; import com.ruoyi.im.domain.dto.PrivateMessageDTO;
import com.ruoyi.im.domain.result.Result;
import com.ruoyi.im.domain.vo.PrivateMessageVO; import com.ruoyi.im.domain.vo.PrivateMessageVO;
import java.util.List; import java.util.List;
@ -18,7 +19,7 @@ public interface PrivateMessageService extends IService<PrivateMessage> {
* @param dto * @param dto
* @return id * @return id
*/ */
PrivateMessageVO sendMessage(PrivateMessageDTO dto); Result sendMessage(PrivateMessageDTO dto);
/** /**
@ -61,4 +62,6 @@ public interface PrivateMessageService extends IService<PrivateMessage> {
Long getMaxReadedId(Long friendId); Long getMaxReadedId(Long friendId);
Map getConsultProduct(Long storeId); Map getConsultProduct(Long storeId);
void toBlock(List<Long> messageIds);
} }

@ -18,6 +18,7 @@ import com.ruoyi.common.im.enums.IMTerminalType;
import com.ruoyi.common.im.enums.MessageStatus; import com.ruoyi.common.im.enums.MessageStatus;
import com.ruoyi.common.im.enums.MessageType; import com.ruoyi.common.im.enums.MessageType;
import com.ruoyi.common.im.model.IMGroupMessage; 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.model.IMUserInfo;
import com.ruoyi.common.im.util.BeanUtils; import com.ruoyi.common.im.util.BeanUtils;
import com.ruoyi.common.im.util.CommaTextUtils; 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.GroupMessage;
import com.ruoyi.im.domain.PrivateMessage; import com.ruoyi.im.domain.PrivateMessage;
import com.ruoyi.im.domain.dto.GroupMessageDTO; 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.GroupMessageVO;
import com.ruoyi.im.domain.vo.PrivateMessageVO;
import com.ruoyi.im.mapper.GroupMessageMapper; import com.ruoyi.im.mapper.GroupMessageMapper;
import com.ruoyi.im.service.GroupMemberService; import com.ruoyi.im.service.GroupMemberService;
import com.ruoyi.im.service.GroupMessageService; import com.ruoyi.im.service.GroupMessageService;
@ -47,6 +51,7 @@ import java.util.*;
import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
@Slf4j @Slf4j
@Service @Service
@ -62,20 +67,23 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
private static final ScheduledThreadPoolExecutor EXECUTOR = ThreadPoolExecutorFactory.getThreadPoolExecutor(); private static final ScheduledThreadPoolExecutor EXECUTOR = ThreadPoolExecutorFactory.getThreadPoolExecutor();
@Override @Override
public GroupMessageVO sendMessage(GroupMessageDTO dto) { public Result sendMessage(GroupMessageDTO dto) {
AppUser session = SecurityUtils.getAppLoginUser().getAppUser(); // AppUser session = SecurityUtils.getAppLoginUser().getAppUser();
AppUser session =appUserService.getById(SecurityUtils.getAppLoginUser().getAppUserId());
if (!session.permissionToTalk()){
return ResultUtils.error(500,"您已被禁言,无法发送消息");
}
Group group = groupService.getAndCheckById(dto.getGroupId()); Group group = groupService.getAndCheckById(dto.getGroupId());
// 是否在群聊里面 // 是否在群聊里面
GroupMember member = groupMemberService.findByGroupAndUserId(dto.getGroupId(), session.getId()); GroupMember member = groupMemberService.findByGroupAndUserId(dto.getGroupId(), session.getId());
if (Objects.isNull(member) || member.getQuit()) { if (Objects.isNull(member) || member.getQuit()) {
throw new GlobalException("您已不在群聊里面,无法发送消息"); return ResultUtils.error(500,"您已不在群聊里面,无法发送消息");
} }
// 群聊成员列表 // 群聊成员列表
List<Long> userIds = groupMemberService.findUserIdsByGroupId(group.getId()); List<Long> userIds = groupMemberService.findUserIdsByGroupId(group.getId());
if (dto.getReceipt() && userIds.size() > 10L) { if (dto.getReceipt() && userIds.size() > 10L) {
// 大群的回执消息过于消耗资源,不允许发送 // 大群的回执消息过于消耗资源,不允许发送
throw new GlobalException( return ResultUtils.error(500,String.format("当前群聊大于%s人,不支持发送回执消息", 10L));
String.format("当前群聊大于%s人,不支持发送回执消息", 10L));
} }
// 不用发给自己 // 不用发给自己
userIds = userIds.stream().filter(id -> !session.getId().equals(id)).collect(Collectors.toList()); userIds = userIds.stream().filter(id -> !session.getId().equals(id)).collect(Collectors.toList());
@ -101,7 +109,7 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
imClient.sendGroupMessage(sendMessage); imClient.sendGroupMessage(sendMessage);
jpush(group.getId(),group.getName(),msg.getContent(),userIds); jpush(group.getId(),group.getName(),msg.getContent(),userIds);
log.info("发送群聊消息发送id:{},群聊id:{},内容:{}", session.getId(), dto.getGroupId(), dto.getContent()); log.info("发送群聊消息发送id:{},群聊id:{},内容:{}", session.getId(), dto.getGroupId(), dto.getContent());
return msgInfo; return ResultUtils.success(msgInfo);
} }
public void jpush(Long groupId,String groupName,String contentd,List<Long> recvIds){ public void jpush(Long groupId,String groupName,String contentd,List<Long> recvIds){
List<AppUser> recvUsers= appUserService.listByIds(recvIds); List<AppUser> recvUsers= appUserService.listByIds(recvIds);
@ -161,7 +169,41 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
log.info("撤回群聊消息发送id:{},群聊id:{},内容:{}", session.getId(), msg.getGroupId(), msg.getContent()); log.info("撤回群聊消息发送id:{},群聊id:{},内容:{}", session.getId(), msg.getGroupId(), msg.getContent());
return msgInfo; return msgInfo;
} }
@Transactional
@Override
public void toBlock(List<Long> messageIds) {
//没有session 默认管理员的appuserId
//每一个messageId对应两条屏蔽消息
List<GroupMessage> 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<Long> userIds = groupMemberService.findUserIdsByGroupId(msg.getGroupId());
GroupMessageVO msgInfo = BeanUtils.copyProperties(recallMsg, GroupMessageVO.class);
IMGroupMessage<GroupMessageVO> 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 @Override
public void pullOfflineMessage(Long minId) { public void pullOfflineMessage(Long minId) {
AppUser session = SecurityUtils.getAppLoginUser().getAppUser(); AppUser session = SecurityUtils.getAppLoginUser().getAppUser();
@ -186,6 +228,7 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
wrapper.gt(GroupMessage::getId, minId) wrapper.gt(GroupMessage::getId, minId)
.gt(GroupMessage::getSendTime, minDate) .gt(GroupMessage::getSendTime, minDate)
.in(GroupMessage::getGroupId, groupIds) .in(GroupMessage::getGroupId, groupIds)
.eq(GroupMessage::getIsBlocked, 0)//屏蔽违规信息
.orderByAsc(GroupMessage::getId); .orderByAsc(GroupMessage::getId);
List<GroupMessage> messages = this.list(wrapper); List<GroupMessage> messages = this.list(wrapper);
// 通过群聊对消息进行分组 // 通过群聊对消息进行分组
@ -434,4 +477,6 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
// } // }
return maxReadedId.toString(); return maxReadedId.toString();
} }
} }

@ -0,0 +1,150 @@
package com.ruoyi.im.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.basic.service.YjAppUserService;
import com.ruoyi.common.core.domain.entity.SysUser;
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.ReportMessageDetailDTO;
import com.ruoyi.im.domain.dto.ReportSubmitDTO;
import com.ruoyi.im.mapper.ImReportRecordsMapper;
import com.ruoyi.im.service.GroupMessageService;
import com.ruoyi.im.service.IImReportRecordsService;
import com.ruoyi.im.service.PrivateMessageService;
import com.ruoyi.system.domain.SysUserRole;
import com.ruoyi.system.mapper.SysUserRoleMapper;
import com.ruoyi.system.service.ISysUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
@Service
@RequiredArgsConstructor
public class ImReportRecordsServiceImpl
extends ServiceImpl<ImReportRecordsMapper, ImReportRecords>
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<ReportMessageDetailDTO> 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<Long> 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<ReportMessageDetailDTO> 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<String> urls) {
if (CollUtil.isEmpty(urls)) {
return null;
}
return urls.stream()
.filter(StrUtil::isNotBlank)
.distinct()
.collect(Collectors.joining(","));
}
}

@ -25,6 +25,8 @@ import com.ruoyi.common.im.util.BeanUtils;
import com.ruoyi.common.im.util.ThreadPoolExecutorFactory; import com.ruoyi.common.im.util.ThreadPoolExecutorFactory;
import com.ruoyi.im.domain.PrivateMessage; import com.ruoyi.im.domain.PrivateMessage;
import com.ruoyi.im.domain.dto.PrivateMessageDTO; 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.domain.vo.PrivateMessageVO;
import com.ruoyi.im.mapper.PrivateMessageMapper; import com.ruoyi.im.mapper.PrivateMessageMapper;
import com.ruoyi.im.service.FriendService; import com.ruoyi.im.service.FriendService;
@ -55,6 +57,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.*; import java.util.*;
import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
@Slf4j @Slf4j
@Service @Service
@ -69,8 +72,12 @@ public class PrivateMessageServiceImpl extends ServiceImpl<PrivateMessageMapper,
private static final ScheduledThreadPoolExecutor EXECUTOR = ThreadPoolExecutorFactory.getThreadPoolExecutor(); private static final ScheduledThreadPoolExecutor EXECUTOR = ThreadPoolExecutorFactory.getThreadPoolExecutor();
@Override @Override
public PrivateMessageVO sendMessage(PrivateMessageDTO dto) { public Result sendMessage(PrivateMessageDTO dto) {
AppUser appUser= SecurityUtils.getAppLoginUser().getAppUser(); // AppUser appUser= SecurityUtils.getAppLoginUser().getAppUser();
AppUser appUser =appUserService.getById(SecurityUtils.getAppLoginUser().getAppUserId());
if (!appUser.permissionToTalk()){
return ResultUtils.error(500,"您已被禁言,无法发送消息");
}
//无需验证好友 //无需验证好友
Boolean isFriends = friendService.isFriend(appUser.getId(), dto.getRecvId()); Boolean isFriends = friendService.isFriend(appUser.getId(), dto.getRecvId());
if (Boolean.FALSE.equals(isFriends)) { if (Boolean.FALSE.equals(isFriends)) {
@ -98,7 +105,7 @@ public class PrivateMessageServiceImpl extends ServiceImpl<PrivateMessageMapper,
imClient.sendPrivateMessage(sendMessage); imClient.sendPrivateMessage(sendMessage);
jpush(appUser.getId(),appUser.getNickName(),msg.getContent(),dto.getRecvId()); jpush(appUser.getId(),appUser.getNickName(),msg.getContent(),dto.getRecvId());
log.info("发送私聊消息发送id:{},接收id:{},内容:{}", appUser.getId(), dto.getRecvId(), dto.getContent()); log.info("发送私聊消息发送id:{},接收id:{},内容:{}", appUser.getId(), dto.getRecvId(), dto.getContent());
return msgInfo; return ResultUtils.success(msgInfo);
} }
public void jpush(Long sendId,String senderName,String contentd,Long recvId){ public void jpush(Long sendId,String senderName,String contentd,Long recvId){
@ -166,6 +173,7 @@ public class PrivateMessageServiceImpl extends ServiceImpl<PrivateMessageMapper,
wrapper.gt(PrivateMessage::getId, minId); wrapper.gt(PrivateMessage::getId, minId);
wrapper.ge(PrivateMessage::getSendTime, minDate); wrapper.ge(PrivateMessage::getSendTime, minDate);
wrapper.eq(PrivateMessage::getStatus,MessageStatus.UNSEND.code()); wrapper.eq(PrivateMessage::getStatus,MessageStatus.UNSEND.code());
wrapper.eq(PrivateMessage::getIsBlocked,0);//屏蔽违规信息
wrapper.and(wp -> wp.eq(PrivateMessage::getSendId, session.getId()).or() wrapper.and(wp -> wp.eq(PrivateMessage::getSendId, session.getId()).or()
.eq(PrivateMessage::getRecvId, session.getId())); .eq(PrivateMessage::getRecvId, session.getId()));
wrapper.orderByAsc(PrivateMessage::getId); wrapper.orderByAsc(PrivateMessage::getId);
@ -309,7 +317,61 @@ public class PrivateMessageServiceImpl extends ServiceImpl<PrivateMessageMapper,
imClient.sendPrivateMessage(sendMessage); imClient.sendPrivateMessage(sendMessage);
} }
@Transactional
@Override
public void toBlock(List<Long> messageIds) {
//没有session 默认管理员的appuserId
//每一个messageId对应两条屏蔽消息
List<PrivateMessage> msgs = this.listByIds(messageIds);
if (Objects.isNull(msgs)) {
throw new GlobalException("消息不存在");
}
// List<Map<String, Long>> 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<String, Long> 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<PrivateMessageVO> 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);
}
} }

@ -88,15 +88,22 @@ public final class SensitiveFilterUtil {
@PostConstruct @PostConstruct
public void reload() { public void reload() {
// 使用copy on write的方式防止出现并发问题 // 使用copy on write的方式防止出现并发问题
log.info("开始加载敏感词库...");
TrieNode newNode = new TrieNode(); TrieNode newNode = new TrieNode();
List<String> keywords = sensitiveWordService.findAllEnabledWords(); List<String> keywords = sensitiveWordService.findAllEnabledWords();
log.info("查询到敏感词数量:{}", keywords != null ? keywords.size() : 0);
if (keywords != null && !keywords.isEmpty()) {
keywords.forEach(keyword -> { keywords.forEach(keyword -> {
if (StrUtil.isNotEmpty(keyword)) { String trimmed = keyword != null ? keyword.trim() : null;
// 添加到前缀树 if (StrUtil.isNotEmpty(trimmed)) {
addKeyword(newNode,keyword); addKeyword(newNode, trimmed);
} }
}); });
} else {
log.warn("敏感词库为空,请检查数据库表 sensitive_word 是否有启用状态的数据!");
}
ROOT_NODE = newNode; ROOT_NODE = newNode;
log.info("敏感词库加载完成,共加载 {} 条", keywords != null ? keywords.size() : 0);
} }
/** /**

@ -2,6 +2,7 @@ package com.ruoyi.system.mapper;
import com.ruoyi.system.domain.SysUserRole; import com.ruoyi.system.domain.SysUserRole;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List; import java.util.List;
@ -63,4 +64,7 @@ public interface SysUserRoleMapper
public List<SysUserRole> selectALLByRole(String merchantId); public List<SysUserRole> 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);
} }

Loading…
Cancel
Save