diff --git a/MallChat b/MallChat
new file mode 160000
index 0000000..c47b487
--- /dev/null
+++ b/MallChat
@@ -0,0 +1 @@
+Subproject commit c47b48760dd1eaaed6cf1c62930c65032ed66752
diff --git a/README.md b/README.md
index b642c57..b4572a8 100644
--- a/README.md
+++ b/README.md
@@ -13,13 +13,22 @@
-
- [](https://github.com/Evansy/MallChatWeb/actions/workflows/deploy.yml)
+
+
+
+
-
+
-
[](https://github.com/zongzibinbin/MallChat/blob/master/LICENSE)
- [](https://github.com/zongzibinbin/MallChat/stargazers)
+
+
+
+
+
+
+
+
+
## 项目导航
@@ -130,7 +139,7 @@
虚拟列表 |
- | 后端 |
+ 后端 |
|
@@ -145,6 +154,18 @@
Ac自动机敏感词检测 |
+
+
+
+ |
+ 限流编程式 |
+
+
+
+
+ |
+ 握手认证 |
+
diff --git a/docs/mallchat.sql b/docs/mallchat.sql
index 9a94090..f2db654 100644
--- a/docs/mallchat.sql
+++ b/docs/mallchat.sql
@@ -190,4 +190,16 @@ CREATE TABLE `sensitive_word` (
`word` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '敏感词'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='敏感词库';
INSERT INTO `sensitive_word` (`word`) VALUES ('TMD');
-INSERT INTO `sensitive_word` (`word`) VALUES ('tmd');
\ No newline at end of file
+INSERT INTO `sensitive_word` (`word`) VALUES ('tmd');
+
+DROP TABLE IF EXISTS `user_emoji`;
+CREATE TABLE `user_emoji` (
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
+ `uid` bigint(20) NOT NULL COMMENT '用户表ID',
+ `expression_url` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '表情地址',
+ `delete_status` int(1) NOT NULL DEFAULT '0' COMMENT '逻辑删除(0-正常,1-删除)',
+ `create_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
+ `update_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '修改时间',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `IDX_USER_EMOJIS_UID` (`uid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='用户表情包';
\ No newline at end of file
diff --git a/docs/version/2023-07-09.sql b/docs/version/2023-07-09.sql
new file mode 100644
index 0000000..22ea074
--- /dev/null
+++ b/docs/version/2023-07-09.sql
@@ -0,0 +1,10 @@
+CREATE TABLE `user_emoji` (
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
+ `uid` bigint(20) NOT NULL COMMENT '用户表ID',
+ `expression_url` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '表情地址',
+ `delete_status` int(1) NOT NULL DEFAULT '0' COMMENT '逻辑删除(0-正常,1-删除)',
+ `create_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
+ `update_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '修改时间',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `IDX_USER_EMOJIS_UID` (`uid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='用户表情包';
\ No newline at end of file
diff --git a/mallchat-common/pom.xml b/mallchat-common/pom.xml
index 0a33126..f20da8b 100644
--- a/mallchat-common/pom.xml
+++ b/mallchat-common/pom.xml
@@ -123,6 +123,16 @@
com.alibaba
fastjson
+
+ org.springframework
+ spring-test
+ 5.3.19
+ test
+
+
+ org.springframework.boot
+ spring-boot-test
+
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/msg/EmojisMsgDTO.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/msg/EmojisMsgDTO.java
new file mode 100644
index 0000000..d8aaa2c
--- /dev/null
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/msg/EmojisMsgDTO.java
@@ -0,0 +1,29 @@
+package com.abin.mallchat.common.chat.domain.entity.msg;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotBlank;
+import java.io.Serializable;
+
+/**
+ * Description: 表情图片消息入参
+ * Author: abin
+ * Date: 2023-06-04
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class EmojisMsgDTO implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty("下载地址")
+ @NotBlank
+ private String url;
+}
+
+
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/msg/MessageExtra.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/msg/MessageExtra.java
index 9a68c74..fa085b9 100644
--- a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/msg/MessageExtra.java
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/msg/MessageExtra.java
@@ -1,5 +1,6 @@
package com.abin.mallchat.common.chat.domain.entity.msg;
+import com.abin.mallchat.common.common.utils.discover.domain.UrlInfo;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -23,7 +24,7 @@ import java.util.Map;
public class MessageExtra implements Serializable {
private static final long serialVersionUID = 1L;
//url跳转链接
- private Map urlTitleMap;
+ private Map urlContentMap;
//消息撤回详情
private MsgRecall recall;
//艾特的uid
@@ -36,4 +37,9 @@ public class MessageExtra implements Serializable {
private SoundMsgDTO soundMsgDTO;
//文件消息
private VideoMsgDTO videoMsgDTO;
+
+ /**
+ * 表情图片信息
+ */
+ private EmojisMsgDTO emojisMsgDTO;
}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/enums/MessageTypeEnum.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/enums/MessageTypeEnum.java
index cc262a9..73d7b97 100644
--- a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/enums/MessageTypeEnum.java
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/enums/MessageTypeEnum.java
@@ -22,6 +22,7 @@ public enum MessageTypeEnum {
FILE(4, "文件"),
SOUND(5, "语音"),
VIDEO(6, "视频"),
+ EMOJI(7, "表情"),
;
private final Integer type;
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/aspect/FrequencyControlAspect.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/aspect/FrequencyControlAspect.java
index 25418a6..f0290ab 100644
--- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/aspect/FrequencyControlAspect.java
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/aspect/FrequencyControlAspect.java
@@ -2,9 +2,8 @@ package com.abin.mallchat.common.common.aspect;
import cn.hutool.core.util.StrUtil;
import com.abin.mallchat.common.common.annotation.FrequencyControl;
-import com.abin.mallchat.common.common.exception.BusinessException;
-import com.abin.mallchat.common.common.exception.CommonErrorEnum;
-import com.abin.mallchat.common.common.utils.RedisUtils;
+import com.abin.mallchat.common.common.domain.dto.FrequencyControlDTO;
+import com.abin.mallchat.common.common.service.frequencycontrol.FrequencyControlUtil;
import com.abin.mallchat.common.common.utils.RequestHolder;
import com.abin.mallchat.common.common.utils.SpElUtils;
import lombok.extern.slf4j.Slf4j;
@@ -15,7 +14,12 @@ import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
-import java.util.*;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static com.abin.mallchat.common.common.service.frequencycontrol.FrequencyControlStrategyFactory.TOTAL_COUNT_WITH_IN_FIX_TIME_FREQUENCY_CONTROLLER;
/**
* Description: 频控实现
@@ -48,25 +52,25 @@ public class FrequencyControlAspect {
}
keyMap.put(prefix + ":" + key, frequencyControl);
}
- //批量获取redis统计的值
- ArrayList keyList = new ArrayList<>(keyMap.keySet());
- List countList = RedisUtils.mget(keyList, Integer.class);
- for (int i = 0; i < keyList.size(); i++) {
- String key = keyList.get(i);
- Integer count = countList.get(i);
- FrequencyControl frequencyControl = keyMap.get(key);
- if (Objects.nonNull(count) && count >= frequencyControl.count()) {//频率超过了
- log.warn("frequencyControl limit key:{},count:{}", key, count);
- throw new BusinessException(CommonErrorEnum.FREQUENCY_LIMIT);
- }
- }
- try {
- return joinPoint.proceed();
- } finally {
- //不管成功还是失败,都增加次数
- keyMap.forEach((k, v) -> {
- RedisUtils.inc(k, v.time(), v.unit());
- });
- }
+ // 将注解的参数转换为编程式调用需要的参数
+ List frequencyControlDTOS = keyMap.entrySet().stream().map(entrySet -> buildFrequencyControlDTO(entrySet.getKey(), entrySet.getValue())).collect(Collectors.toList());
+ // 调用编程式注解
+ return FrequencyControlUtil.executeWithFrequencyControlList(TOTAL_COUNT_WITH_IN_FIX_TIME_FREQUENCY_CONTROLLER, frequencyControlDTOS, joinPoint::proceed);
+ }
+
+ /**
+ * 将注解参数转换为编程式调用所需要的参数
+ *
+ * @param key 频率控制Key
+ * @param frequencyControl 注解
+ * @return 编程式调用所需要的参数-FrequencyControlDTO
+ */
+ private FrequencyControlDTO buildFrequencyControlDTO(String key, FrequencyControl frequencyControl) {
+ FrequencyControlDTO frequencyControlDTO = new FrequencyControlDTO();
+ frequencyControlDTO.setCount(frequencyControl.count());
+ frequencyControlDTO.setTime(frequencyControl.time());
+ frequencyControlDTO.setUnit(frequencyControl.unit());
+ frequencyControlDTO.setKey(key);
+ return frequencyControlDTO;
}
}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/config/SensitiveWordConfig.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/config/SensitiveWordConfig.java
new file mode 100644
index 0000000..6220d51
--- /dev/null
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/config/SensitiveWordConfig.java
@@ -0,0 +1,30 @@
+package com.abin.mallchat.common.common.config;
+
+import com.abin.mallchat.common.common.utils.sensitiveWord.DFAFilter;
+import com.abin.mallchat.common.common.utils.sensitiveWord.SensitiveWordBs;
+import com.abin.mallchat.common.sensitive.MyWordDeny;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class SensitiveWordConfig {
+
+ @Autowired
+ private MyWordDeny myWordDeny;
+
+ /**
+ * 初始化引导类
+ *
+ * @return 初始化引导类
+ * @since 1.0.0
+ */
+ @Bean
+ public SensitiveWordBs sensitiveWordBs() {
+ return SensitiveWordBs.newInstance()
+ .filterStrategy(DFAFilter.getInstance())
+ .sensitiveWord(myWordDeny)
+ .init();
+ }
+
+}
\ No newline at end of file
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/domain/dto/FrequencyControlDTO.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/domain/dto/FrequencyControlDTO.java
new file mode 100644
index 0000000..3399773
--- /dev/null
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/domain/dto/FrequencyControlDTO.java
@@ -0,0 +1,42 @@
+package com.abin.mallchat.common.common.domain.dto;
+
+import lombok.*;
+
+import java.util.concurrent.TimeUnit;
+
+@Data
+@ToString
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+/** 限流策略定义
+ * @author linzhihan
+ * @date 2023/07/03
+ *
+ */
+public class FrequencyControlDTO {
+ /**
+ * 代表频控的Key 如果target为Key的话 这里要传值用于构建redis的Key target为Ip或者UID的话会从上下文取值 Key字段无需传值
+ */
+ private String key;
+ /**
+ * 频控时间范围,默认单位秒
+ *
+ * @return 时间范围
+ */
+ private Integer time;
+
+ /**
+ * 频控时间单位,默认秒
+ *
+ * @return 单位
+ */
+ private TimeUnit unit;
+
+ /**
+ * 单位时间内最大访问次数
+ *
+ * @return 次数
+ */
+ private Integer count;
+}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/domain/vo/request/IdReqVO.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/domain/vo/request/IdReqVO.java
new file mode 100644
index 0000000..9c0f417
--- /dev/null
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/domain/vo/request/IdReqVO.java
@@ -0,0 +1,20 @@
+package com.abin.mallchat.common.common.domain.vo.request;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author zhongzb create on 2021/05/31
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class IdReqVO {
+ @ApiModelProperty("id")
+ @NotNull
+ private long id;
+}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/exception/CommonErrorEnum.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/exception/CommonErrorEnum.java
index edcd880..b1b7ec8 100644
--- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/exception/CommonErrorEnum.java
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/exception/CommonErrorEnum.java
@@ -13,7 +13,7 @@ import lombok.Getter;
public enum CommonErrorEnum implements ErrorEnum {
SYSTEM_ERROR(-1, "系统出小差了,请稍后再试哦~~"),
- PARAM_VALID(-2, "参数校验失败"),
+ PARAM_VALID(-2, "参数校验失败{0}"),
FREQUENCY_LIMIT(-3, "请求太频繁了,请稍后再试哦~~"),
LOCK_LIMIT(-4, "请求太频繁了,请稍后再试哦~~"),
;
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/exception/FrequencyControlException.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/exception/FrequencyControlException.java
new file mode 100644
index 0000000..fbcaff7
--- /dev/null
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/exception/FrequencyControlException.java
@@ -0,0 +1,39 @@
+package com.abin.mallchat.common.common.exception;
+
+import lombok.Data;
+
+/**
+ * 自定义限流异常
+ *
+ * @author linzhihan
+ * @date 2023/07/034
+ */
+@Data
+public class FrequencyControlException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 错误码
+ */
+ protected Integer errorCode;
+
+ /**
+ * 错误信息
+ */
+ protected String errorMsg;
+
+ public FrequencyControlException() {
+ super();
+ }
+
+ public FrequencyControlException(String errorMsg) {
+ super(errorMsg);
+ this.errorMsg = errorMsg;
+ }
+
+ public FrequencyControlException(ErrorEnum error) {
+ super(error.getErrorMsg());
+ this.errorCode = error.getErrorCode();
+ this.errorMsg = error.getErrorMsg();
+ }
+}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/exception/GlobalExceptionHandler.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/exception/GlobalExceptionHandler.java
index 3a986e1..066e210 100644
--- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/exception/GlobalExceptionHandler.java
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/exception/GlobalExceptionHandler.java
@@ -42,7 +42,7 @@ public class GlobalExceptionHandler {
*/
@ExceptionHandler(value = NullPointerException.class)
public ApiResult exceptionHandler(NullPointerException e) {
- log.error("null point exception!The reason is:{}", e.getMessage(), e);
+ log.error("null point exception!The reason is: ", e);
return ApiResult.fail(CommonErrorEnum.SYSTEM_ERROR);
}
@@ -73,4 +73,12 @@ public class GlobalExceptionHandler {
return ApiResult.fail(-1, String.format("不支持'%s'请求", e.getMethod()));
}
+ /**
+ * 限流异常
+ */
+ @ExceptionHandler(value = FrequencyControlException.class)
+ public ApiResult frequencyControlExceptionHandler(FrequencyControlException e) {
+ log.info("frequencyControl exception!The reason is:{}", e.getMessage(), e);
+ return ApiResult.fail(e.getErrorCode(), e.getMessage());
+ }
}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/handler/GlobalUncaughtExceptionHandler.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/handler/GlobalUncaughtExceptionHandler.java
index b3229e6..4dc9775 100644
--- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/handler/GlobalUncaughtExceptionHandler.java
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/handler/GlobalUncaughtExceptionHandler.java
@@ -9,7 +9,6 @@ public class GlobalUncaughtExceptionHandler implements Thread.UncaughtException
@Override
public void uncaughtException(Thread t, Throwable e) {
log.error("Exception in thread {} ", t.getName(), e);
- e.printStackTrace();
}
}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/service/frequencycontrol/AbstractFrequencyControlService.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/service/frequencycontrol/AbstractFrequencyControlService.java
new file mode 100644
index 0000000..211f9f8
--- /dev/null
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/service/frequencycontrol/AbstractFrequencyControlService.java
@@ -0,0 +1,124 @@
+package com.abin.mallchat.common.common.service.frequencycontrol;
+
+import com.abin.mallchat.common.common.domain.dto.FrequencyControlDTO;
+import com.abin.mallchat.common.common.exception.CommonErrorEnum;
+import com.abin.mallchat.common.common.exception.FrequencyControlException;
+import com.abin.mallchat.common.common.utils.AssertUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+
+import javax.annotation.PostConstruct;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 抽象类频控服务 其他类如果要实现限流服务 直接注入使用通用限流类
+ * 后期会通过继承此类实现令牌桶等算法
+ *
+ * @author linzhihan
+ * @date 2023/07/03
+ * @see TotalCountWithInFixTimeFrequencyController 通用限流类
+ */
+@Slf4j
+public abstract class AbstractFrequencyControlService {
+
+ @PostConstruct
+ protected void registerMyselfToFactory() {
+ FrequencyControlStrategyFactory.registerFrequencyController(getStrategyName(), this);
+ }
+
+ /**
+ * @param frequencyControlMap 定义的注解频控 Map中的Key-对应redis的单个频控的Key Map中的Value-对应redis的单个频控的Key限制的Value
+ * @param supplier 函数式入参-代表每个频控方法执行的不同的业务逻辑
+ * @return 业务方法执行的返回值
+ * @throws Throwable
+ */
+ private T executeWithFrequencyControlMap(Map frequencyControlMap, SupplierThrowWithoutParam supplier) throws Throwable {
+ if (reachRateLimit(frequencyControlMap)) {
+ throw new FrequencyControlException(CommonErrorEnum.FREQUENCY_LIMIT);
+ }
+ try {
+ return supplier.get();
+ } finally {
+ //不管成功还是失败,都增加次数
+ addFrequencyControlStatisticsCount(frequencyControlMap);
+ }
+ }
+
+
+ /**
+ * 多限流策略的编程式调用方法 无参的调用方法
+ *
+ * @param frequencyControlList 频控列表 包含每一个频率控制的定义以及顺序
+ * @param supplier 函数式入参-代表每个频控方法执行的不同的业务逻辑
+ * @return 业务方法执行的返回值
+ * @throws Throwable 被限流或者限流策略定义错误
+ */
+ @SuppressWarnings("unchecked")
+ public T executeWithFrequencyControlList(List frequencyControlList, SupplierThrowWithoutParam supplier) throws Throwable {
+ boolean existsFrequencyControlHasNullKey = frequencyControlList.stream().anyMatch(frequencyControl -> ObjectUtils.isEmpty(frequencyControl.getKey()));
+ AssertUtil.isFalse(existsFrequencyControlHasNullKey, "限流策略的Key字段不允许出现空值");
+ Map frequencyControlDTOMap = frequencyControlList.stream().collect(Collectors.groupingBy(FrequencyControlDTO::getKey, Collectors.collectingAndThen(Collectors.toList(), list -> list.get(0))));
+ return executeWithFrequencyControlMap((Map) frequencyControlDTOMap, supplier);
+ }
+
+ /**
+ * 单限流策略的调用方法-编程式调用
+ *
+ * @param frequencyControl 单个频控对象
+ * @param supplier 服务提供着
+ * @return 业务方法执行结果
+ * @throws Throwable
+ */
+ public T executeWithFrequencyControl(K frequencyControl, SupplierThrowWithoutParam supplier) throws Throwable {
+ return executeWithFrequencyControlList(Collections.singletonList(frequencyControl), supplier);
+ }
+
+
+ @FunctionalInterface
+ public interface SupplierThrowWithoutParam {
+
+ /**
+ * Gets a result.
+ *
+ * @return a result
+ */
+ T get() throws Throwable;
+ }
+
+ @FunctionalInterface
+ public interface Executor {
+
+ /**
+ * Gets a result.
+ *
+ * @return a result
+ */
+ void execute() throws Throwable;
+ }
+
+ /**
+ * 是否达到限流阈值 子类实现 每个子类都可以自定义自己的限流逻辑判断
+ *
+ * @param frequencyControlMap 定义的注解频控 Map中的Key-对应redis的单个频控的Key Map中的Value-对应redis的单个频控的Key限制的Value
+ * @return true-方法被限流 false-方法没有被限流
+ */
+ protected abstract boolean reachRateLimit(Map frequencyControlMap);
+
+ /**
+ * 增加限流统计次数 子类实现 每个子类都可以自定义自己的限流统计信息增加的逻辑
+ *
+ * @param frequencyControlMap 定义的注解频控 Map中的Key-对应redis的单个频控的Key Map中的Value-对应redis的单个频控的Key限制的Value
+ */
+ protected abstract void addFrequencyControlStatisticsCount(Map frequencyControlMap);
+
+ /**
+ * 获取策略名称
+ *
+ * @return 策略名称
+ */
+ protected abstract String getStrategyName();
+
+}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/service/frequencycontrol/FrequencyControlStrategyFactory.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/service/frequencycontrol/FrequencyControlStrategyFactory.java
new file mode 100644
index 0000000..ec211a8
--- /dev/null
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/service/frequencycontrol/FrequencyControlStrategyFactory.java
@@ -0,0 +1,51 @@
+package com.abin.mallchat.common.common.service.frequencycontrol;
+
+import com.abin.mallchat.common.common.domain.dto.FrequencyControlDTO;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 限流策略工厂
+ *
+ * @author linzhihan
+ * @date 2023/07/03
+ */
+public class FrequencyControlStrategyFactory {
+ /**
+ * 指定时间内总次数限流
+ */
+ public static final String TOTAL_COUNT_WITH_IN_FIX_TIME_FREQUENCY_CONTROLLER = "TotalCountWithInFixTime";
+ /**
+ * 限流策略集合
+ */
+ static Map> frequencyControlServiceStrategyMap = new ConcurrentHashMap<>(8);
+
+ /**
+ * 将策略类放入工厂
+ *
+ * @param strategyName 策略名称
+ * @param abstractFrequencyControlService 策略类
+ */
+ public static void registerFrequencyController(String strategyName, AbstractFrequencyControlService abstractFrequencyControlService) {
+ frequencyControlServiceStrategyMap.put(strategyName, abstractFrequencyControlService);
+ }
+
+ /**
+ * 根据名称获取策略类
+ *
+ * @param strategyName 策略名称
+ * @return 对应的限流策略类
+ */
+ @SuppressWarnings("unchecked")
+ public static AbstractFrequencyControlService getFrequencyControllerByName(String strategyName) {
+ return (AbstractFrequencyControlService) frequencyControlServiceStrategyMap.get(strategyName);
+ }
+
+ /**
+ * 构造器私有
+ */
+ private FrequencyControlStrategyFactory() {
+
+ }
+}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/service/frequencycontrol/FrequencyControlUtil.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/service/frequencycontrol/FrequencyControlUtil.java
new file mode 100644
index 0000000..0e94041
--- /dev/null
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/service/frequencycontrol/FrequencyControlUtil.java
@@ -0,0 +1,63 @@
+package com.abin.mallchat.common.common.service.frequencycontrol;
+
+import com.abin.mallchat.common.common.domain.dto.FrequencyControlDTO;
+import com.abin.mallchat.common.common.utils.AssertUtil;
+import org.apache.commons.lang3.ObjectUtils;
+
+import java.util.List;
+
+/**
+ * 限流工具类 提供编程式的限流调用方法
+ *
+ * @author linzhihan
+ * @date 2023/07/03
+ */
+public class FrequencyControlUtil {
+
+ /**
+ * 单限流策略的调用方法-编程式调用
+ *
+ * @param strategyName 策略名称
+ * @param frequencyControl 单个频控对象
+ * @param supplier 服务提供着
+ * @return 业务方法执行结果
+ * @throws Throwable
+ */
+ public static T executeWithFrequencyControl(String strategyName, K frequencyControl, AbstractFrequencyControlService.SupplierThrowWithoutParam supplier) throws Throwable {
+ AbstractFrequencyControlService frequencyController = FrequencyControlStrategyFactory.getFrequencyControllerByName(strategyName);
+ return frequencyController.executeWithFrequencyControl(frequencyControl, supplier);
+ }
+
+ public static void executeWithFrequencyControl(String strategyName, K frequencyControl, AbstractFrequencyControlService.Executor executor) throws Throwable {
+ AbstractFrequencyControlService frequencyController = FrequencyControlStrategyFactory.getFrequencyControllerByName(strategyName);
+ frequencyController.executeWithFrequencyControl(frequencyControl, () -> {
+ executor.execute();
+ return null;
+ });
+ }
+
+
+ /**
+ * 多限流策略的编程式调用方法调用方法
+ *
+ * @param strategyName 策略名称
+ * @param frequencyControlList 频控列表 包含每一个频率控制的定义以及顺序
+ * @param supplier 函数式入参-代表每个频控方法执行的不同的业务逻辑
+ * @return 业务方法执行的返回值
+ * @throws Throwable 被限流或者限流策略定义错误
+ */
+ public static T executeWithFrequencyControlList(String strategyName, List frequencyControlList, AbstractFrequencyControlService.SupplierThrowWithoutParam supplier) throws Throwable {
+ boolean existsFrequencyControlHasNullKey = frequencyControlList.stream().anyMatch(frequencyControl -> ObjectUtils.isEmpty(frequencyControl.getKey()));
+ AssertUtil.isFalse(existsFrequencyControlHasNullKey, "限流策略的Key字段不允许出现空值");
+ AbstractFrequencyControlService frequencyController = FrequencyControlStrategyFactory.getFrequencyControllerByName(strategyName);
+ return frequencyController.executeWithFrequencyControlList(frequencyControlList, supplier);
+ }
+
+ /**
+ * 构造器私有
+ */
+ private FrequencyControlUtil() {
+
+ }
+
+}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/service/frequencycontrol/TotalCountWithInFixTimeFrequencyController.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/service/frequencycontrol/TotalCountWithInFixTimeFrequencyController.java
new file mode 100644
index 0000000..531e36c
--- /dev/null
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/service/frequencycontrol/TotalCountWithInFixTimeFrequencyController.java
@@ -0,0 +1,64 @@
+package com.abin.mallchat.common.common.service.frequencycontrol;
+
+import com.abin.mallchat.common.common.domain.dto.FrequencyControlDTO;
+import com.abin.mallchat.common.common.utils.RedisUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import static com.abin.mallchat.common.common.service.frequencycontrol.FrequencyControlStrategyFactory.TOTAL_COUNT_WITH_IN_FIX_TIME_FREQUENCY_CONTROLLER;
+
+/**
+ * 抽象类频控服务 -使用redis实现 固定时间内不超过固定次数的限流类
+ *
+ * @author linzhihan
+ * @date 2023/07/03
+ */
+@Slf4j
+@Service
+public class TotalCountWithInFixTimeFrequencyController extends AbstractFrequencyControlService {
+
+
+ /**
+ * 是否达到限流阈值 子类实现 每个子类都可以自定义自己的限流逻辑判断
+ *
+ * @param frequencyControlMap 定义的注解频控 Map中的Key-对应redis的单个频控的Key Map中的Value-对应redis的单个频控的Key限制的Value
+ * @return true-方法被限流 false-方法没有被限流
+ */
+ @Override
+ protected boolean reachRateLimit(Map frequencyControlMap) {
+ //批量获取redis统计的值
+ List frequencyKeys = new ArrayList<>(frequencyControlMap.keySet());
+ List countList = RedisUtils.mget(frequencyKeys, Integer.class);
+ for (int i = 0; i < frequencyKeys.size(); i++) {
+ String key = frequencyKeys.get(i);
+ Integer count = countList.get(i);
+ int frequencyControlCount = frequencyControlMap.get(key).getCount();
+ if (Objects.nonNull(count) && count >= frequencyControlCount) {
+ //频率超过了
+ log.warn("frequencyControl limit key:{},count:{}", key, count);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 增加限流统计次数 子类实现 每个子类都可以自定义自己的限流统计信息增加的逻辑
+ *
+ * @param frequencyControlMap 定义的注解频控 Map中的Key-对应redis的单个频控的Key Map中的Value-对应redis的单个频控的Key限制的Value
+ */
+ @Override
+ protected void addFrequencyControlStatisticsCount(Map frequencyControlMap) {
+ frequencyControlMap.forEach((k, v) -> RedisUtils.inc(k, v.getTime(), v.getUnit()));
+ }
+
+ @Override
+ protected String getStrategyName() {
+ return TOTAL_COUNT_WITH_IN_FIX_TIME_FREQUENCY_CONTROLLER;
+ }
+}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/JwtUtils.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/JwtUtils.java
index fe2a97e..f9ce4d5 100644
--- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/JwtUtils.java
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/JwtUtils.java
@@ -67,7 +67,7 @@ public class JwtUtils {
DecodedJWT jwt = verifier.verify(token);
return jwt.getClaims();
} catch (Exception e) {
- log.info("decode error,token:{}", token, e);
+ log.error("decode error,token:{}", token, e);
}
return null;
}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/AbstractUrlTitleDiscover.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/AbstractUrlDiscover.java
similarity index 64%
rename from mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/AbstractUrlTitleDiscover.java
rename to mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/AbstractUrlDiscover.java
index 79cbefe..4da24e9 100644
--- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/AbstractUrlTitleDiscover.java
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/AbstractUrlDiscover.java
@@ -3,14 +3,14 @@ package com.abin.mallchat.common.common.utils.discover;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.abin.mallchat.common.common.utils.FutureUtils;
+import com.abin.mallchat.common.common.utils.discover.domain.UrlInfo;
import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.Nullable;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.springframework.data.util.Pair;
-import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -20,46 +20,55 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
- * Description: urlTitle查询抽象类
- * Author: abin
- * Date: 2023-05-27
+ * @author zhaoqichao
+ * @date 2023/7/3 16:38
*/
@Slf4j
-public abstract class AbstractUrlTitleDiscover implements UrlTitleDiscover {
+public abstract class AbstractUrlDiscover implements UrlDiscover {
//链接识别的正则
private static final Pattern PATTERN = Pattern.compile("((http|https)://)?(www.)?([\\w_-]+(?:(?:\\.[\\w_-]+)+))([\\w.,@?^=%&:/~+#-]*[\\w@?^=%&/~+#-])?");
+
@Nullable
@Override
- public Map getContentTitleMap(String content) {
+ public Map getUrlContentMap(String content) {
+
if (StrUtil.isBlank(content)) {
return new HashMap<>();
}
List matchList = ReUtil.findAll(PATTERN, content, 0);
+
//并行请求
- List>> futures = matchList.stream().map(match -> CompletableFuture.supplyAsync(() -> {
- String title = getUrlTitle(match);
- return StringUtils.isNotEmpty(title) ? Pair.of(match, title) : null;
+ List>> futures = matchList.stream().map(match -> CompletableFuture.supplyAsync(() -> {
+ UrlInfo urlInfo = getContent(match);
+ return Objects.isNull(urlInfo) ? null : Pair.of(match, urlInfo);
})).collect(Collectors.toList());
- CompletableFuture>> future = FutureUtils.sequenceNonNull(futures);
+ CompletableFuture>> future = FutureUtils.sequenceNonNull(futures);
//结果组装
return future.join().stream().collect(Collectors.toMap(Pair::getFirst, Pair::getSecond, (a, b) -> a));
}
@Nullable
@Override
- public String getUrlTitle(String url) {
+ public UrlInfo getContent(String url) {
Document document = getUrlDocument(assemble(url));
if (Objects.isNull(document)) {
return null;
}
- return getDocTitle(document);
+
+ return UrlInfo.builder()
+ .title(getTitle(document))
+ .description(getDescription(document))
+ .image(getImage(assemble(url),document)).build();
}
+
private String assemble(String url) {
+
if (!StrUtil.startWith(url, "http")) {
return "http://" + url;
}
+
return url;
}
@@ -69,8 +78,9 @@ public abstract class AbstractUrlTitleDiscover implements UrlTitleDiscover {
connect.timeout(2000);
return connect.get();
} catch (Exception e) {
- log.error("find title error:url:{}", matchUrl, e);
+ log.error("find error:url:{}", matchUrl, e);
}
return null;
}
+
}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/CommonUrlDiscover.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/CommonUrlDiscover.java
new file mode 100644
index 0000000..2f3b842
--- /dev/null
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/CommonUrlDiscover.java
@@ -0,0 +1,52 @@
+package com.abin.mallchat.common.common.utils.discover;
+
+import cn.hutool.core.util.StrUtil;
+import io.jsonwebtoken.lang.Objects;
+import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.Nullable;
+import org.jsoup.nodes.Document;
+import org.jsoup.select.Elements;
+
+/**
+ * @author zhaoqichao
+ * @date 2023/7/3 16:54
+ */
+public class CommonUrlDiscover extends AbstractUrlDiscover {
+ @Nullable
+ @Override
+ public String getTitle(Document document) {
+ return document.title();
+ }
+
+ @Nullable
+ @Override
+ public String getDescription(Document document) {
+ String description = document.head().select("meta[name=description]").attr("content");
+ String keywords = document.head().select("meta[name=keywords]").attr("content");
+ String content = StrUtil.isNotBlank(description) ? description : keywords;
+ //只保留一句话的描述
+ return StrUtil.isNotBlank(content) ? content.substring(0, content.indexOf("。")) : content;
+ }
+
+ @Nullable
+ @Override
+ public String getImage(String url, Document document) {
+ String image = document.select("link[type=image/x-icon]").attr("href");
+ //如果没有去匹配含有icon属性的logo
+ String href = StrUtil.isEmpty(image) ? document.select("link[rel$=icon]").attr("href") : image;
+ //如果icon中已经包含了url部分域名
+ if (StrUtil.isNotBlank(StrUtil.removeAny(StrUtil.removeAny(href, "/"), "favicon.ico")) &&
+ StrUtil.containsAny(StrUtil.removePrefix(url, "http://"), StrUtil.removeAny(StrUtil.removeAny(href, "/"), "favicon.ico"))) {
+ return "http://" + StrUtil.removePrefix(href, "/");
+ }
+ //如果url已经包含了logo
+ if (StrUtil.containsAny(url, "favicon")) {
+ return url;
+ }
+ //如果logo中有url
+ if (StrUtil.containsAny(href, "http") || StrUtil.containsAny(href, "https")) {
+ return href;
+ }
+ return StrUtil.format("{}/{}", url, StrUtil.removePrefix(href, "/"));
+ }
+}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/CommonUrlTitleDiscover.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/CommonUrlTitleDiscover.java
deleted file mode 100644
index 6471610..0000000
--- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/CommonUrlTitleDiscover.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.abin.mallchat.common.common.utils.discover;
-
-import org.jsoup.nodes.Document;
-
-/**
- * Description: 通用的标题解析类
- * Author: abin
- * Date: 2023-05-27
- */
-public class CommonUrlTitleDiscover extends AbstractUrlTitleDiscover {
- @Override
- public String getDocTitle(Document document) {
- return document.title();
- }
-}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/PrioritizedUrlDiscover.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/PrioritizedUrlDiscover.java
new file mode 100644
index 0000000..eef3c11
--- /dev/null
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/PrioritizedUrlDiscover.java
@@ -0,0 +1,60 @@
+package com.abin.mallchat.common.common.utils.discover;
+
+import cn.hutool.core.util.StrUtil;
+import org.jetbrains.annotations.Nullable;
+import org.jsoup.nodes.Document;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Description: 具有优先级的title查询器
+ * Author: abin
+ * Date: 2023-05-27
+ */
+public class PrioritizedUrlDiscover extends AbstractUrlDiscover {
+
+ private final List urlDiscovers = new ArrayList<>(2);
+
+ public PrioritizedUrlDiscover() {
+ urlDiscovers.add(new WxUrlDiscover());
+ urlDiscovers.add(new CommonUrlDiscover());
+ }
+
+
+ @Nullable
+ @Override
+ public String getTitle(Document document) {
+ for (UrlDiscover urlDiscover : urlDiscovers) {
+ String urlTitle = urlDiscover.getTitle(document);
+ if (StrUtil.isNotBlank(urlTitle)) {
+ return urlTitle;
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String getDescription(Document document) {
+ for (UrlDiscover urlDiscover : urlDiscovers) {
+ String urlDescription = urlDiscover.getDescription(document);
+ if (StrUtil.isNotBlank(urlDescription)) {
+ return urlDescription;
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String getImage(String url, Document document) {
+ for (UrlDiscover urlDiscover : urlDiscovers) {
+ String urlImage = urlDiscover.getImage(url,document);
+ if (StrUtil.isNotBlank(urlImage)) {
+ return urlImage;
+ }
+ }
+ return null;
+ }
+}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/PrioritizedUrlTitleDiscover.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/PrioritizedUrlTitleDiscover.java
deleted file mode 100644
index 8c7fb4d..0000000
--- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/PrioritizedUrlTitleDiscover.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.abin.mallchat.common.common.utils.discover;
-
-import cn.hutool.core.util.StrUtil;
-import org.jsoup.nodes.Document;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Description: 具有优先级的title查询器
- * Author: abin
- * Date: 2023-05-27
- */
-public class PrioritizedUrlTitleDiscover extends AbstractUrlTitleDiscover {
-
- private final List urlTitleDiscovers = new ArrayList<>(2);
-
- public PrioritizedUrlTitleDiscover() {
- urlTitleDiscovers.add(new CommonUrlTitleDiscover());
- urlTitleDiscovers.add(new WxUrlTitleDiscover());
- }
-
- @Override
- public String getDocTitle(Document document) {
- for (UrlTitleDiscover urlTitleDiscover : urlTitleDiscovers) {
- String urlTitle = urlTitleDiscover.getDocTitle(document);
- if (StrUtil.isNotBlank(urlTitle)) {
- return urlTitle;
- }
- }
- return null;
- }
-}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/UrlDiscover.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/UrlDiscover.java
new file mode 100644
index 0000000..3515c28
--- /dev/null
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/UrlDiscover.java
@@ -0,0 +1,46 @@
+package com.abin.mallchat.common.common.utils.discover;
+
+import cn.hutool.core.date.StopWatch;
+import cn.hutool.core.util.StrUtil;
+import com.abin.mallchat.common.common.utils.discover.domain.UrlInfo;
+import org.jsoup.nodes.Document;
+
+import javax.annotation.Nullable;
+import java.util.Map;
+
+/**
+ * @author zhaoqichao
+ * @date 2023/7/3 16:34
+ */
+public interface UrlDiscover {
+
+
+ @Nullable
+ Map getUrlContentMap(String content);
+
+ @Nullable
+ UrlInfo getContent(String url);
+
+ @Nullable
+ String getTitle(Document document);
+
+ @Nullable
+ String getDescription(Document document);
+
+ @Nullable
+ String getImage(String url, Document document);
+
+ public static void main(String[] args) {
+ StopWatch stopWatch = new StopWatch();
+ stopWatch.start();
+ String longStr = "其中包含一个URL www.baidu.com,一个带有端口号的URL http://www.jd.com:80, 一个带有路径的URL http://mallchat.cn, 还有美团技术文章https://mp.weixin.qq.com/s/hwTf4bDck9_tlFpgVDeIKg ";
+// String longStr = "一个带有端口号的URL http://www.jd.com:80,";
+// String longStr = "一个带有路径的URL http://mallchat.cn";
+ PrioritizedUrlDiscover discover = new PrioritizedUrlDiscover();
+ final Map map = discover.getUrlContentMap(longStr);
+ System.out.println(map);
+ stopWatch.stop();
+ long cost = stopWatch.getTotalTimeMillis();
+ System.out.println(cost);
+ }
+}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/UrlTitleDiscover.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/UrlTitleDiscover.java
deleted file mode 100644
index e2fac68..0000000
--- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/UrlTitleDiscover.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.abin.mallchat.common.common.utils.discover;
-
-import cn.hutool.core.date.StopWatch;
-import org.jsoup.nodes.Document;
-
-import javax.annotation.Nullable;
-import java.util.Map;
-
-public interface UrlTitleDiscover {
-
-
- @Nullable
- Map getContentTitleMap(String content);
-
-
- @Nullable
- String getUrlTitle(String url);
-
- @Nullable
- String getDocTitle(Document document);
-
- public static void main(String[] args) {//用异步多任务查询并合并 974 //串行访问的速度1349 1291 1283 1559
- StopWatch stopWatch = new StopWatch();
- stopWatch.start();
- String longStr = "这是一个很长的字符串再来 www.github.com,其中包含一个URL www.baidu.com,, 一个带有端口号的URL http://www.jd.com:80, 一个带有路径的URL http://mallchat.cn, 还有美团技术文章https://mp.weixin.qq.com/s/hwTf4bDck9_tlFpgVDeIKg ";
- PrioritizedUrlTitleDiscover discover = new PrioritizedUrlTitleDiscover();
- Map contentTitleMap = discover.getContentTitleMap(longStr);
- System.out.println(contentTitleMap);
-//
-// Jsoup.connect("http:// www.github.com");
- stopWatch.stop();
- long cost = stopWatch.getTotalTimeMillis();
- System.out.println(cost);
- }//{http://mallchat.cn=MallChat, www.baidu.com=百度一下,你就知道, https://mp.weixin.qq.com/s/hwTf4bDck9_tlFpgVDeIKg=超大规模数据库集群保稳系列之二:数据库攻防演练建设实践, http://www.jd.com:80=京东(JD.COM)-正品低价、品质保障、配送及时、轻松购物!}
-}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/WxUrlDiscover.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/WxUrlDiscover.java
new file mode 100644
index 0000000..a5bb330
--- /dev/null
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/WxUrlDiscover.java
@@ -0,0 +1,30 @@
+package com.abin.mallchat.common.common.utils.discover;
+
+import org.jetbrains.annotations.Nullable;
+import org.jsoup.nodes.Document;
+
+/**
+ * Description: 针对微信公众号文章的标题获取类
+ * Author: abin
+ * Date: 2023-05-27
+ */
+public class WxUrlDiscover extends AbstractUrlDiscover {
+
+ @Nullable
+ @Override
+ public String getTitle(Document document) {
+ return document.getElementsByAttributeValue("property", "og:title").attr("content");
+ }
+
+ @Nullable
+ @Override
+ public String getDescription(Document document) {
+ return document.getElementsByAttributeValue("property", "og:description").attr("content");
+ }
+
+ @Nullable
+ @Override
+ public String getImage(String url, Document document) {
+ return document.getElementsByAttributeValue("property", "og:image").attr("content");
+ }
+}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/WxUrlTitleDiscover.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/WxUrlTitleDiscover.java
deleted file mode 100644
index 29b1172..0000000
--- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/WxUrlTitleDiscover.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.abin.mallchat.common.common.utils.discover;
-
-import org.jsoup.nodes.Document;
-
-/**
- * Description: 针对微信公众号文章的标题获取类
- * Author: abin
- * Date: 2023-05-27
- */
-public class WxUrlTitleDiscover extends AbstractUrlTitleDiscover {
- @Override
- public String getDocTitle(Document document) {
- return document.getElementsByAttributeValue("property", "og:title").attr("content");
- }
-}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/domain/UrlInfo.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/domain/UrlInfo.java
new file mode 100644
index 0000000..8f02b7c
--- /dev/null
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/discover/domain/UrlInfo.java
@@ -0,0 +1,32 @@
+package com.abin.mallchat.common.common.utils.discover.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author zhaoqichao
+ * @date 2023/7/3 16:12
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class UrlInfo {
+ /**
+ * 标题
+ **/
+ String title;
+
+ /**
+ * 描述
+ **/
+ String description;
+
+ /**
+ * 网站LOGO
+ **/
+ String image;
+
+}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/oss/MinIOTemplate.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/oss/MinIOTemplate.java
index f49a5fa..99e6e6a 100644
--- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/oss/MinIOTemplate.java
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/oss/MinIOTemplate.java
@@ -136,8 +136,8 @@ public class MinIOTemplate {
String uid = Optional.ofNullable(req.getUid()).map(String::valueOf).orElse("000000");
cn.hutool.core.lang.UUID uuid = cn.hutool.core.lang.UUID.fastUUID();
String suffix = FileNameUtil.getSuffix(req.getFileName());
- String year = DateUtil.format(new Date(), DatePattern.NORM_YEAR_PATTERN);
- return req.getFilePath() + StrUtil.SLASH + year + StrUtil.SLASH + uid + StrUtil.SLASH + uuid + StrUtil.DOT + suffix;
+ String yearAndMonth = DateUtil.format(new Date(), DatePattern.NORM_MONTH_PATTERN);
+ return req.getFilePath() + StrUtil.SLASH + yearAndMonth + StrUtil.SLASH + uid + StrUtil.SLASH + uuid + StrUtil.DOT + suffix;
}
/**
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/SensitiveWordUtils0.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/sensitiveWord/ACFilter.java
similarity index 88%
rename from mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/SensitiveWordUtils0.java
rename to mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/sensitiveWord/ACFilter.java
index f67c694..618908f 100644
--- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/SensitiveWordUtils0.java
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/sensitiveWord/ACFilter.java
@@ -1,4 +1,4 @@
-package com.abin.mallchat.common.common.utils;
+package com.abin.mallchat.common.common.utils.sensitiveWord;
import com.abin.mallchat.common.common.algorithm.ac.ACTrie;
import com.abin.mallchat.common.common.algorithm.ac.MatchResult;
@@ -15,7 +15,7 @@ import java.util.Objects;
*
* Created by berg on 2023/6/18.
*/
-public class SensitiveWordUtils0 {
+public class ACFilter implements SensitiveWordFilter {
private final static char mask_char = '*'; // 替代字符
@@ -27,7 +27,7 @@ public class SensitiveWordUtils0 {
* @param text 文本
* @return boolean
*/
- public static boolean hasSensitiveWord(String text) {
+ public boolean hasSensitiveWord(String text) {
if (StringUtils.isBlank(text)) return false;
return !Objects.equals(filter(text), text);
}
@@ -38,7 +38,7 @@ public class SensitiveWordUtils0 {
* @param text 待替换文本
* @return 替换后的文本
*/
- public static String filter(String text) {
+ public String filter(String text) {
if (StringUtils.isBlank(text)) return text;
List matchResults = ac_trie.matches(text);
StringBuffer result = new StringBuffer(text);
@@ -62,7 +62,7 @@ public class SensitiveWordUtils0 {
*
* @param words 敏感词数组
*/
- public static void loadWord(List words) {
+ public void loadWord(List words) {
if (words == null) return;
ac_trie = new ACTrie(words);
}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/SensitiveWordUtils.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/sensitiveWord/DFAFilter.java
similarity index 87%
rename from mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/SensitiveWordUtils.java
rename to mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/sensitiveWord/DFAFilter.java
index 298f876..e766e2e 100644
--- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/SensitiveWordUtils.java
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/sensitiveWord/DFAFilter.java
@@ -1,4 +1,4 @@
-package com.abin.mallchat.common.common.utils;
+package com.abin.mallchat.common.common.utils.sensitiveWord;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
@@ -18,7 +18,10 @@ import java.util.*;
* @author zhaoyuhang
* @date 2023/06/19
*/
-public final class SensitiveWordUtils {
+public final class DFAFilter implements SensitiveWordFilter {
+
+ private DFAFilter() {
+ }
private static Word root = new Word(' '); // 敏感词字典的根节点
private final static char replace = '*'; // 替代字符
private final static String skipChars = " !*-+_=,,.@;:;:。、??()()【】[]《》<>“”\"‘’"; // 遇到这些字符就会跳过
@@ -30,6 +33,10 @@ public final class SensitiveWordUtils {
}
}
+ public static DFAFilter getInstance() {
+ return new DFAFilter();
+ }
+
/**
* 判断文本中是否存在敏感词
@@ -37,7 +44,7 @@ public final class SensitiveWordUtils {
* @param text 文本
* @return true: 存在敏感词, false: 不存在敏感词
*/
- public static boolean hasSensitiveWord(String text) {
+ public boolean hasSensitiveWord(String text) {
if (StringUtils.isBlank(text)) return false;
return !Objects.equals(filter(text), text);
}
@@ -48,7 +55,7 @@ public final class SensitiveWordUtils {
* @param text 待替换文本
* @return 替换后的文本
*/
- public static String filter(String text) {
+ public String filter(String text) {
StringBuilder result = new StringBuilder(text);
int index = 0;
while (index < result.length()) {
@@ -93,7 +100,7 @@ public final class SensitiveWordUtils {
*
* @param words 敏感词数组
*/
- public static void loadWord(List words) {
+ public void loadWord(List words) {
if (!CollectionUtils.isEmpty(words)) {
Word newRoot = new Word(' ');
words.forEach(word -> loadWord(word, newRoot));
@@ -106,7 +113,7 @@ public final class SensitiveWordUtils {
*
* @param word 词
*/
- public static void loadWord(String word, Word root) {
+ public void loadWord(String word, Word root) {
if (StringUtils.isBlank(word)) {
return;
}
@@ -136,7 +143,7 @@ public final class SensitiveWordUtils {
*
* @param path 文本文件的绝对路径
*/
- public static void loadWordFromFile(String path) {
+ public void loadWordFromFile(String path) {
try (InputStream inputStream = Files.newInputStream(Paths.get(path))) {
loadWord(inputStream);
} catch (IOException e) {
@@ -150,7 +157,7 @@ public final class SensitiveWordUtils {
* @param inputStream 文本文件输入流
* @throws IOException IO异常
*/
- public static void loadWord(InputStream inputStream) throws IOException {
+ public void loadWord(InputStream inputStream) throws IOException {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
String line;
ArrayList list = new ArrayList<>();
@@ -167,7 +174,7 @@ public final class SensitiveWordUtils {
* @param c 待检测字符
* @return true: 需要跳过, false: 不需要跳过
*/
- private static boolean skip(char c) {
+ private boolean skip(char c) {
return skipSet.contains(c);
}
@@ -186,17 +193,7 @@ public final class SensitiveWordUtils {
public Word(char c) {
this.c = c;
- this.end = false;
this.next = new HashMap<>();
}
}
-
- public static void main(String[] args) {
- String text = "白日,梦";
- String filter = filter(text);
- System.out.println(filter);
-
-
- }
-
}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/sensitiveWord/IWordDeny.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/sensitiveWord/IWordDeny.java
new file mode 100644
index 0000000..4259c91
--- /dev/null
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/sensitiveWord/IWordDeny.java
@@ -0,0 +1,18 @@
+package com.abin.mallchat.common.common.utils.sensitiveWord;
+
+import java.util.List;
+
+/**
+ * 敏感词
+ *
+ * @author zhaoyuhang
+ * @date 2023/07/09
+ */
+public interface IWordDeny {
+ /**
+ * 获取结果
+ * @return 结果
+ * @since 0.0.13
+ */
+ List deny();
+}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/sensitiveWord/SensitiveWordBs.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/sensitiveWord/SensitiveWordBs.java
new file mode 100644
index 0000000..006fd2f
--- /dev/null
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/sensitiveWord/SensitiveWordBs.java
@@ -0,0 +1,102 @@
+package com.abin.mallchat.common.common.utils.sensitiveWord;
+
+import java.util.List;
+
+/**
+ * 敏感词引导类
+ *
+ * @author zhaoyuhang
+ * @date 2023/07/08
+ */
+public class SensitiveWordBs {
+
+ /**
+ * 私有化构造器
+ */
+ private SensitiveWordBs() {
+ }
+
+ /**
+ * 脱敏策略
+ */
+ private SensitiveWordFilter sensitiveWordFilter = DFAFilter.getInstance();
+
+ /**
+ * 敏感词列表
+ */
+ private IWordDeny wordDeny;
+
+ public static SensitiveWordBs newInstance() {
+ return new SensitiveWordBs();
+ }
+
+ /**
+ * 初始化
+ *
+ * 1. 根据配置,初始化对应的 map。比较消耗性能。
+ * @since 0.0.13
+ * @return this
+ */
+ public SensitiveWordBs init() {
+
+ List words = wordDeny.deny();
+ loadWord(words);
+ return this;
+ }
+
+ /**
+ * 过滤策略
+ *
+ * @param filter 过滤器
+ * @return 结果
+ * @since 0.7.0
+ */
+ public SensitiveWordBs filterStrategy(SensitiveWordFilter filter) {
+ if (filter == null) {
+ throw new IllegalArgumentException("filter can not be null");
+ }
+ this.sensitiveWordFilter = filter;
+ return this;
+ }
+
+ public SensitiveWordBs sensitiveWord(IWordDeny wordDeny) {
+ if (wordDeny == null) {
+ throw new IllegalArgumentException("wordDeny can not be null");
+ }
+ this.wordDeny = wordDeny;
+ return this;
+ }
+
+
+
+
+ /**
+ * 有敏感词
+ *
+ * @param text 文本
+ * @return boolean
+ */
+ public boolean hasSensitiveWord(String text) {
+ return sensitiveWordFilter.hasSensitiveWord(text);
+ }
+
+ /**
+ * 过滤
+ *
+ * @param text 文本
+ * @return {@link String}
+ */
+ public String filter(String text) {
+ return sensitiveWordFilter.filter(text);
+ }
+
+ /**
+ * 加载敏感词列表
+ *
+ * @param words 敏感词数组
+ */
+ private void loadWord(List words) {
+ sensitiveWordFilter.loadWord(words);
+ }
+
+}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/sensitiveWord/SensitiveWordFilter.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/sensitiveWord/SensitiveWordFilter.java
new file mode 100644
index 0000000..afe2533
--- /dev/null
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/sensitiveWord/SensitiveWordFilter.java
@@ -0,0 +1,37 @@
+package com.abin.mallchat.common.common.utils.sensitiveWord;
+
+
+import java.util.List;
+
+/**
+ * 敏感词过滤
+ *
+ * @author zhaoyuhang
+ * @date 2023/07/08
+ */
+public interface SensitiveWordFilter {
+ /**
+ * 有敏感词
+ *
+ * @param text 文本
+ * @return boolean
+ */
+ boolean hasSensitiveWord(String text);
+
+ /**
+ * 过滤
+ *
+ * @param text 文本
+ * @return {@link String}
+ */
+ String filter(String text);
+
+ /**
+ * 加载敏感词列表
+ *
+ * @param words 敏感词数组
+ */
+ void loadWord(List words);
+
+
+}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/sensitive/MyWordDeny.java b/mallchat-common/src/main/java/com/abin/mallchat/common/sensitive/MyWordDeny.java
new file mode 100644
index 0000000..a47d623
--- /dev/null
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/sensitive/MyWordDeny.java
@@ -0,0 +1,24 @@
+package com.abin.mallchat.common.sensitive;
+
+import com.abin.mallchat.common.common.utils.sensitiveWord.IWordDeny;
+import com.abin.mallchat.common.sensitive.dao.SensitiveWordDao;
+import com.abin.mallchat.common.sensitive.domain.SensitiveWord;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Component
+public class MyWordDeny implements IWordDeny {
+ @Autowired
+ private SensitiveWordDao sensitiveWordDao;
+
+ @Override
+ public List deny() {
+ return sensitiveWordDao.list()
+ .stream()
+ .map(SensitiveWord::getWord)
+ .collect(Collectors.toList());
+ }
+}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/sensitive/service/ISensitiveWordService.java b/mallchat-common/src/main/java/com/abin/mallchat/common/sensitive/service/ISensitiveWordService.java
deleted file mode 100644
index f62783a..0000000
--- a/mallchat-common/src/main/java/com/abin/mallchat/common/sensitive/service/ISensitiveWordService.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.abin.mallchat.common.sensitive.service;
-
-public interface ISensitiveWordService {
-
-}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/sensitive/service/impl/SensitiveWordServiceImpl.java b/mallchat-common/src/main/java/com/abin/mallchat/common/sensitive/service/impl/SensitiveWordServiceImpl.java
deleted file mode 100644
index d7fd50f..0000000
--- a/mallchat-common/src/main/java/com/abin/mallchat/common/sensitive/service/impl/SensitiveWordServiceImpl.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.abin.mallchat.common.sensitive.service.impl;
-
-import com.abin.mallchat.common.common.utils.SensitiveWordUtils;
-import com.abin.mallchat.common.sensitive.dao.SensitiveWordDao;
-import com.abin.mallchat.common.sensitive.domain.SensitiveWord;
-import com.abin.mallchat.common.sensitive.service.ISensitiveWordService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
-import org.springframework.stereotype.Service;
-import org.springframework.util.CollectionUtils;
-
-import javax.annotation.PostConstruct;
-import java.util.List;
-import java.util.stream.Collectors;
-
-@Service
-@Slf4j
-public class SensitiveWordServiceImpl implements ISensitiveWordService {
- @Autowired
- private SensitiveWordDao sensitiveWordDao;
- @Autowired
- private ThreadPoolTaskExecutor threadPoolTaskExecutor;
-
- @PostConstruct
- public void initSensitiveWord() {
- threadPoolTaskExecutor.execute(() -> {
- log.info("[initSensitiveWord] start");
- List list = sensitiveWordDao.list();
- if (!CollectionUtils.isEmpty(list)) {
- List wordList = list.stream()
- .map(SensitiveWord::getWord)
- .collect(Collectors.toList());
- SensitiveWordUtils.loadWord(wordList);
- }
- log.info("[initSensitiveWord] end; loading sensitiveWords num:{}", list.size());
- });
- }
-}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/user/dao/UserEmojiDao.java b/mallchat-common/src/main/java/com/abin/mallchat/common/user/dao/UserEmojiDao.java
new file mode 100644
index 0000000..8b8b2ad
--- /dev/null
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/user/dao/UserEmojiDao.java
@@ -0,0 +1,28 @@
+package com.abin.mallchat.common.user.dao;
+
+import com.abin.mallchat.common.user.domain.entity.UserEmoji;
+import com.abin.mallchat.common.user.mapper.UserEmojiMapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ *
+ * 用户表情包 服务实现类
+ *
+ *
+ * @author abin
+ * @since 2023-07-09
+ */
+@Service
+public class UserEmojiDao extends ServiceImpl {
+
+ public List listByUid(Long uid) {
+ return lambdaQuery().eq(UserEmoji::getUid, uid).list();
+ }
+
+ public int countByUid(Long uid) {
+ return lambdaQuery().eq(UserEmoji::getUid, uid).count();
+ }
+}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/user/domain/entity/UserEmoji.java b/mallchat-common/src/main/java/com/abin/mallchat/common/user/domain/entity/UserEmoji.java
new file mode 100644
index 0000000..4a9f2dd
--- /dev/null
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/user/domain/entity/UserEmoji.java
@@ -0,0 +1,65 @@
+package com.abin.mallchat.common.user.domain.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.*;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ *
+ * 用户表情包
+ *
+ *
+ * @author abin
+ * @since 2023-07-09
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = false)
+@TableName("user_emoji")
+public class UserEmoji implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * id
+ */
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ /**
+ * 用户表ID
+ */
+ @TableField("uid")
+ private Long uid;
+
+ /**
+ * 表情地址
+ */
+ @TableField("expression_url")
+ private String expressionUrl;
+
+ /**
+ * 逻辑删除(0-正常,1-删除)
+ */
+ @TableField("delete_status")
+ @TableLogic(value = "0", delval = "1")
+ private Integer deleteStatus;
+
+ /**
+ * 创建时间
+ */
+ @TableField("create_time")
+ private Date createTime;
+
+ /**
+ * 修改时间
+ */
+ @TableField("update_time")
+ private Date updateTime;
+
+
+}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/user/mapper/UserEmojiMapper.java b/mallchat-common/src/main/java/com/abin/mallchat/common/user/mapper/UserEmojiMapper.java
new file mode 100644
index 0000000..cc36c9c
--- /dev/null
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/user/mapper/UserEmojiMapper.java
@@ -0,0 +1,16 @@
+package com.abin.mallchat.common.user.mapper;
+
+import com.abin.mallchat.common.user.domain.entity.UserEmoji;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * 用户表情包 Mapper 接口
+ *
+ *
+ * @author abin
+ * @since 2023-07-09
+ */
+public interface UserEmojiMapper extends BaseMapper {
+
+}
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/user/mapper/UserEmojisMapper.java b/mallchat-common/src/main/java/com/abin/mallchat/common/user/mapper/UserEmojisMapper.java
new file mode 100644
index 0000000..2f1fbd2
--- /dev/null
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/user/mapper/UserEmojisMapper.java
@@ -0,0 +1,13 @@
+package com.abin.mallchat.common.user.mapper;
+
+import com.abin.mallchat.common.user.domain.entity.UserEmoji;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * 用户表情包 Mapper
+ *
+ * @author: WuShiJie
+ * @createTime: 2023/7/3 14:24
+ */
+public interface UserEmojisMapper extends BaseMapper {
+}
diff --git a/mallchat-common/src/main/resources/mapper/user/UserEmojiMapper.xml b/mallchat-common/src/main/resources/mapper/user/UserEmojiMapper.xml
new file mode 100644
index 0000000..eea5b91
--- /dev/null
+++ b/mallchat-common/src/main/resources/mapper/user/UserEmojiMapper.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/mallchat-custom-server/pom.xml b/mallchat-custom-server/pom.xml
index 6436bcb..f47902c 100644
--- a/mallchat-custom-server/pom.xml
+++ b/mallchat-custom-server/pom.xml
@@ -16,6 +16,19 @@
com.abin.mallchat
mallchat-common
+
+
+ junit
+ junit
+ ${junit.version}
+ test
+
+
+ org.springframework
+ spring-test
+ 5.3.19
+ test
+
com.knuddels
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/controller/ChatController.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/controller/ChatController.java
index a74ed2b..10bbbd6 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/controller/ChatController.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/controller/ChatController.java
@@ -84,7 +84,7 @@ public class ChatController {
@GetMapping("/public/msg/page")
@ApiOperation("消息列表")
@FrequencyControl(time = 120, count = 20, target = FrequencyControl.Target.IP)
- public ApiResult> getMsgPage1(@Valid ChatMessagePageReq request) {
+ public ApiResult> getMsgPage(@Valid ChatMessagePageReq request) {
// black(request);
CursorPageBaseResp msgPage = chatService.getMsgPage(request, RequestHolder.get().getUid());
filterBlackMsg(msgPage);
@@ -94,7 +94,6 @@ public class ChatController {
private void filterBlackMsg(CursorPageBaseResp memberPage) {
Set blackMembers = getBlackUidSet();
memberPage.getList().removeIf(a -> blackMembers.contains(a.getFromUser().getUid().toString()));
- System.out.println(1);
}
@PostMapping("/msg")
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/ChatMessageReq.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/ChatMessageReq.java
index 2fd2040..b255a34 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/ChatMessageReq.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/ChatMessageReq.java
@@ -1,6 +1,5 @@
package com.abin.mallchat.custom.chat.domain.vo.request;
-import com.abin.mallchat.common.chat.domain.enums.MessageTypeEnum;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -30,7 +29,7 @@ public class ChatMessageReq {
@ApiModelProperty("消息类型")
@NotNull
- private Integer msgType = MessageTypeEnum.TEXT.getType();
+ private Integer msgType;
@ApiModelProperty("消息内容,类型不同传值不同,见https://www.yuque.com/snab/mallcaht/rkb2uz5k1qqdmcmd")
@NotNull
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/ChatMessageResp.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/ChatMessageResp.java
index 968aae9..096eaf7 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/ChatMessageResp.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/ChatMessageResp.java
@@ -7,7 +7,6 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
-import java.util.Map;
/**
* Description: 消息
@@ -27,16 +26,8 @@ public class ChatMessageResp {
@Data
public static class UserInfo {
- @ApiModelProperty("用户名称")
- private String username;
@ApiModelProperty("用户id")
private Long uid;
- @ApiModelProperty("头像")
- private String avatar;
- @ApiModelProperty("归属地")
- private String locPlace;
- @ApiModelProperty("徽章标识,如果没有展示null")
- private Badge badge;
}
@Data
@@ -45,36 +36,12 @@ public class ChatMessageResp {
private Long id;
@ApiModelProperty("消息发送时间")
private Date sendTime;
- @ApiModelProperty("消息内容-废弃")
- @Deprecated
- private String content;
- @ApiModelProperty("消息链接映射-废弃")
- @Deprecated
- private Map urlTitleMap;
@ApiModelProperty("消息类型 1正常文本 2.撤回消息")
private Integer type;
@ApiModelProperty("消息内容不同的消息类型,内容体不同,见https://www.yuque.com/snab/mallcaht/rkb2uz5k1qqdmcmd")
private Object body;
@ApiModelProperty("消息标记")
private MessageMark messageMark;
- @ApiModelProperty("父消息,如果没有父消息,返回的是null")
- private ReplyMsg reply;
-
- }
-
- @Data
- @Deprecated
- public static class ReplyMsg {
- @ApiModelProperty("消息id")
- private Long id;
- @ApiModelProperty("用户名称")
- private String username;
- @ApiModelProperty("消息内容")
- private String content;
- @ApiModelProperty("是否可消息跳转 0否 1是")
- private Integer canCallback;
- @ApiModelProperty("跳转间隔的消息条数")
- private Integer gapCount;
}
@Data
@@ -88,12 +55,4 @@ public class ChatMessageResp {
@ApiModelProperty("该用户是否已经举报 0否 1是")
private Integer userDislike;
}
-
- @Data
- public static class Badge {
- @ApiModelProperty("徽章图像")
- private String img;
- @ApiModelProperty("徽章说明")
- private String describe;
- }
}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/msg/TextMsgResp.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/msg/TextMsgResp.java
index 34db6c5..17a7b48 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/msg/TextMsgResp.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/msg/TextMsgResp.java
@@ -1,5 +1,6 @@
package com.abin.mallchat.custom.chat.domain.vo.response.msg;
+import com.abin.mallchat.common.common.utils.discover.domain.UrlInfo;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -22,7 +23,7 @@ public class TextMsgResp {
@ApiModelProperty("消息内容")
private String content;
@ApiModelProperty("消息链接映射")
- private Map urlTitleMap;
+ private Map urlContentMap;
@ApiModelProperty("艾特的uid")
private List atUidList;
@ApiModelProperty("父消息,如果没有父消息,返回的是null")
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/WeChatMsgOperationService.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/WeChatMsgOperationService.java
new file mode 100644
index 0000000..1e08b4a
--- /dev/null
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/WeChatMsgOperationService.java
@@ -0,0 +1,14 @@
+package com.abin.mallchat.custom.chat.service;
+
+import java.util.List;
+
+public interface WeChatMsgOperationService {
+ /**
+ * 向被at的用户微信推送群聊消息
+ *
+ * @param senderUid senderUid
+ * @param receiverUidList receiverUidList
+ * @param msg msg
+ */
+ void publishChatMsgToWeChatUser(long senderUid, List receiverUidList, String msg);
+}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/adapter/MessageAdapter.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/adapter/MessageAdapter.java
index 53e10fa..38f0a3c 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/adapter/MessageAdapter.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/adapter/MessageAdapter.java
@@ -3,14 +3,9 @@ package com.abin.mallchat.custom.chat.service.adapter;
import cn.hutool.core.bean.BeanUtil;
import com.abin.mallchat.common.chat.domain.entity.Message;
import com.abin.mallchat.common.chat.domain.entity.MessageMark;
-import com.abin.mallchat.common.chat.domain.entity.msg.MessageExtra;
import com.abin.mallchat.common.chat.domain.enums.MessageMarkTypeEnum;
import com.abin.mallchat.common.chat.domain.enums.MessageStatusEnum;
import com.abin.mallchat.common.common.domain.enums.YesOrNoEnum;
-import com.abin.mallchat.common.user.domain.entity.IpDetail;
-import com.abin.mallchat.common.user.domain.entity.IpInfo;
-import com.abin.mallchat.common.user.domain.entity.ItemConfig;
-import com.abin.mallchat.common.user.domain.entity.User;
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageReq;
import com.abin.mallchat.custom.chat.domain.vo.response.ChatMessageResp;
import com.abin.mallchat.custom.chat.service.strategy.msg.AbstractMsgHandler;
@@ -38,37 +33,25 @@ public class MessageAdapter {
}
- public static List buildMsgResp(List messages, Map replyMap, Map userMap, List msgMark, Long receiveUid, Map itemMap) {
+ public static List buildMsgResp(List messages, Map replyMap, List msgMark, Long receiveUid) {
Map> markMap = msgMark.stream().collect(Collectors.groupingBy(MessageMark::getMsgId));
return messages.stream().map(a -> {
ChatMessageResp resp = new ChatMessageResp();
- resp.setFromUser(buildFromUser(userMap.get(a.getFromUid()), itemMap));
- resp.setMessage(buildMessage(a, replyMap, userMap, markMap.getOrDefault(a.getId(), new ArrayList<>()), receiveUid));
+ resp.setFromUser(buildFromUser(a.getFromUid()));
+ resp.setMessage(buildMessage(a, replyMap, markMap.getOrDefault(a.getId(), new ArrayList<>()), receiveUid));
return resp;
})
.sorted(Comparator.comparing(a -> a.getMessage().getSendTime()))//帮前端排好序,更方便它展示
.collect(Collectors.toList());
}
- private static ChatMessageResp.Message buildMessage(Message message, Map replyMap, Map userMap, List marks, Long receiveUid) {
+ private static ChatMessageResp.Message buildMessage(Message message, Map replyMap, List marks, Long receiveUid) {
ChatMessageResp.Message messageVO = new ChatMessageResp.Message();
BeanUtil.copyProperties(message, messageVO);
messageVO.setSendTime(message.getCreateTime());
AbstractMsgHandler msgHandler = MsgHandlerFactory.getStrategyNoNull(message.getType());
- messageVO.setBody(msgHandler.showMsg(message));
- messageVO.setUrlTitleMap(Optional.ofNullable(message.getExtra()).map(MessageExtra::getUrlTitleMap).orElse(null));
- Message replyMessage = replyMap.get(message.getReplyMsgId());
-
- //回复消息
- if (Objects.nonNull(replyMessage)) {
- ChatMessageResp.ReplyMsg replyMsgVO = new ChatMessageResp.ReplyMsg();
- replyMsgVO.setId(replyMessage.getId());
- replyMsgVO.setContent(replyMessage.getContent());
- User replyUser = userMap.get(replyMessage.getFromUid());
- replyMsgVO.setUsername(replyUser.getName());
- replyMsgVO.setCanCallback(YesOrNoEnum.toStatus(Objects.nonNull(message.getGapCount()) && message.getGapCount() <= CAN_CALLBACK_GAP_COUNT));
- replyMsgVO.setGapCount(message.getGapCount());
- messageVO.setReply(replyMsgVO);
+ if (Objects.nonNull(msgHandler)) {
+ messageVO.setBody(msgHandler.showMsg(message));
}
//消息标记
messageVO.setMessageMark(buildMsgMark(marks, receiveUid));
@@ -87,19 +70,9 @@ public class MessageAdapter {
return mark;
}
- private static ChatMessageResp.UserInfo buildFromUser(User fromUser, Map itemMap) {
+ private static ChatMessageResp.UserInfo buildFromUser(Long fromUid) {
ChatMessageResp.UserInfo userInfo = new ChatMessageResp.UserInfo();
- userInfo.setUsername(fromUser.getName());
- userInfo.setAvatar(fromUser.getAvatar());
- userInfo.setLocPlace(Optional.ofNullable(fromUser.getIpInfo()).map(IpInfo::getUpdateIpDetail).map(IpDetail::getCity).orElse(null));
- userInfo.setUid(fromUser.getId());
- if (Objects.nonNull(fromUser.getItemId())) {
- ChatMessageResp.Badge badge = new ChatMessageResp.Badge();
- ItemConfig itemConfig = itemMap.get(fromUser.getItemId());
- badge.setImg(itemConfig.getImg());
- badge.setDescribe(itemConfig.getDescribe());
- userInfo.setBadge(badge);
- }
+ userInfo.setUid(fromUid);
return userInfo;
}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/impl/ChatServiceImpl.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/impl/ChatServiceImpl.java
index adbb1d3..03ab62f 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/impl/ChatServiceImpl.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/impl/ChatServiceImpl.java
@@ -19,8 +19,6 @@ import com.abin.mallchat.common.common.domain.vo.response.CursorPageBaseResp;
import com.abin.mallchat.common.common.event.MessageSendEvent;
import com.abin.mallchat.common.common.utils.AssertUtil;
import com.abin.mallchat.common.user.dao.UserDao;
-import com.abin.mallchat.common.user.domain.entity.ItemConfig;
-import com.abin.mallchat.common.user.domain.entity.User;
import com.abin.mallchat.common.user.domain.enums.ChatActiveStatusEnum;
import com.abin.mallchat.common.user.domain.enums.RoleEnum;
import com.abin.mallchat.common.user.service.IRoleService;
@@ -49,7 +47,6 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
/**
* Description: 消息处理类
@@ -226,21 +223,14 @@ public class ChatServiceImpl implements ChatService {
return new ArrayList<>();
}
Map replyMap = new HashMap<>();
- Map userMap;
- Map itemMap;
//批量查出回复的消息
List replyIds = messages.stream().map(Message::getReplyMsgId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
if (CollectionUtil.isNotEmpty(replyIds)) {
replyMap = messageDao.listByIds(replyIds).stream().collect(Collectors.toMap(Message::getId, Function.identity()));
}
- //批量查询消息关联用户
- Set uidSet = Stream.concat(replyMap.values().stream().map(Message::getFromUid), messages.stream().map(Message::getFromUid)).collect(Collectors.toSet());
- userMap = userCache.getUserInfoBatch(uidSet);
- //批量查询item信息
- itemMap = userMap.values().stream().map(User::getItemId).distinct().filter(Objects::nonNull).map(itemCache::getById).collect(Collectors.toMap(ItemConfig::getId, Function.identity()));
//查询消息标志
List msgMark = messageMarkDao.getValidMarkByMsgIdBatch(messages.stream().map(Message::getId).collect(Collectors.toList()));
- return MessageAdapter.buildMsgResp(messages, replyMap, userMap, msgMark, receiveUid, itemMap);
+ return MessageAdapter.buildMsgResp(messages, replyMap, msgMark, receiveUid);
}
}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/impl/WeChatMsgOperationServiceImpl.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/impl/WeChatMsgOperationServiceImpl.java
new file mode 100644
index 0000000..429068c
--- /dev/null
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/impl/WeChatMsgOperationServiceImpl.java
@@ -0,0 +1,115 @@
+package com.abin.mallchat.custom.chat.service.impl;
+
+import cn.hutool.core.thread.NamedThreadFactory;
+import com.abin.mallchat.common.common.domain.dto.FrequencyControlDTO;
+import com.abin.mallchat.common.common.exception.FrequencyControlException;
+import com.abin.mallchat.common.common.handler.GlobalUncaughtExceptionHandler;
+import com.abin.mallchat.common.common.service.frequencycontrol.FrequencyControlUtil;
+import com.abin.mallchat.common.user.domain.entity.User;
+import com.abin.mallchat.common.user.service.cache.UserCache;
+import com.abin.mallchat.custom.chat.service.WeChatMsgOperationService;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
+import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import static com.abin.mallchat.common.common.service.frequencycontrol.FrequencyControlStrategyFactory.TOTAL_COUNT_WITH_IN_FIX_TIME_FREQUENCY_CONTROLLER;
+
+@Slf4j
+@Component
+public class WeChatMsgOperationServiceImpl implements WeChatMsgOperationService {
+
+ private static final ExecutorService executor = new ThreadPoolExecutor(1, 10, 3000L,
+ TimeUnit.MILLISECONDS,
+ new LinkedBlockingQueue(20),
+ new NamedThreadFactory("wechat-operation-thread", null, false,
+ new GlobalUncaughtExceptionHandler()));
+
+ // at消息的微信推送模板id
+ private final String atMsgPublishTemplateId = "Xd7sWPZsuWa0UmpvLaZPvaJVjNj1KjEa0zLOm5_Z7IU";
+
+ private final String WE_CHAT_MSG_COLOR = "#A349A4";
+
+ @Autowired
+ private UserCache userCache;
+
+ @Autowired
+ WxMpService wxMpService;
+
+ @Override
+ public void publishChatMsgToWeChatUser(long senderUid, List receiverUidList, String msg) {
+ User sender = userCache.getUserInfo(senderUid);
+ Set uidSet = new HashSet();
+ uidSet.addAll(receiverUidList);
+ Map userMap = userCache.getUserInfoBatch(uidSet);
+ userMap.values().forEach(user -> {
+ if (Objects.nonNull(user.getOpenId())) {
+ executor.execute(() -> {
+ WxMpTemplateMessage msgTemplate = getAtMsgTemplate(sender, user.getOpenId(), msg);
+ publishTemplateMsgCheckLimit(msgTemplate);
+ });
+ }
+ });
+ }
+
+ private void publishTemplateMsgCheckLimit(WxMpTemplateMessage msgTemplate) {
+ try {
+ FrequencyControlDTO frequencyControlDTO = new FrequencyControlDTO();
+ frequencyControlDTO.setKey("TemplateMsg:" + msgTemplate.getToUser());
+ frequencyControlDTO.setUnit(TimeUnit.HOURS);
+ frequencyControlDTO.setCount(1);
+ frequencyControlDTO.setTime(1);
+ FrequencyControlUtil.executeWithFrequencyControl(TOTAL_COUNT_WITH_IN_FIX_TIME_FREQUENCY_CONTROLLER, frequencyControlDTO,
+ () -> publishTemplateMsg(msgTemplate));
+ } catch (FrequencyControlException e) {
+ log.info("wx push limit openid:{}", msgTemplate.getToUser());
+ } catch (Throwable e) {
+ log.error("wx push error openid:{}", msgTemplate.getToUser());
+ }
+ }
+
+ /*
+ * 构造微信模板消息
+ */
+ private WxMpTemplateMessage getAtMsgTemplate(User sender, String openId, String msg) {
+ return WxMpTemplateMessage.builder()
+ .toUser(openId)
+ .templateId(atMsgPublishTemplateId)
+ .data(generateAtMsgData(sender, msg))
+ .build();
+ }
+
+ /*
+ * 构造微信消息模板的数据
+ */
+ private List generateAtMsgData(User sender, String msg) {
+ List dataList = new ArrayList();
+// todo: 没有消息模板,暂不实现
+ dataList.add(new WxMpTemplateData("name", sender.getName(), WE_CHAT_MSG_COLOR));
+ dataList.add(new WxMpTemplateData("content", msg, WE_CHAT_MSG_COLOR));
+ return dataList;
+ }
+
+ /**
+ * 推送微信模板消息
+ *
+ * @param templateMsg 微信模板消息
+ */
+ protected void publishTemplateMsg(WxMpTemplateMessage templateMsg) {
+// WxMpTemplateMsgService wxMpTemplateMsgService = wxMpService.getTemplateMsgService();todo 等审核通过
+// try {
+// wxMpTemplateMsgService.sendTemplateMsg(templateMsg);
+// } catch (WxErrorException e) {
+// log.error("publish we chat msg failed! open id is {}, msg is {}.",
+// templateMsg.getToUser(), JsonUtils.toStr(templateMsg.getData()));
+// }
+ }
+}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/msg/EmojisMsgHandler.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/msg/EmojisMsgHandler.java
new file mode 100644
index 0000000..d7f93a5
--- /dev/null
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/msg/EmojisMsgHandler.java
@@ -0,0 +1,57 @@
+package com.abin.mallchat.custom.chat.service.strategy.msg;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.abin.mallchat.common.chat.dao.MessageDao;
+import com.abin.mallchat.common.chat.domain.entity.Message;
+import com.abin.mallchat.common.chat.domain.entity.msg.EmojisMsgDTO;
+import com.abin.mallchat.common.chat.domain.entity.msg.MessageExtra;
+import com.abin.mallchat.common.chat.domain.enums.MessageTypeEnum;
+import com.abin.mallchat.common.common.utils.AssertUtil;
+import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageReq;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Optional;
+
+/**
+ * Description:表情消息
+ * Author: abin
+ * Date: 2023-06-04
+ */
+@Component
+public class EmojisMsgHandler extends AbstractMsgHandler {
+ @Autowired
+ private MessageDao messageDao;
+
+ @Override
+ MessageTypeEnum getMsgTypeEnum() {
+ return MessageTypeEnum.EMOJI;
+ }
+
+ @Override
+ public void checkMsg(ChatMessageReq request, Long uid) {
+ EmojisMsgDTO body = BeanUtil.toBean(request.getBody(), EmojisMsgDTO.class);
+ AssertUtil.allCheckValidateThrow(body);
+ }
+
+ @Override
+ public void saveMsg(Message msg, ChatMessageReq request) {
+ EmojisMsgDTO body = BeanUtil.toBean(request.getBody(), EmojisMsgDTO.class);
+ MessageExtra extra = Optional.ofNullable(msg.getExtra()).orElse(new MessageExtra());
+ Message update = new Message();
+ update.setId(msg.getId());
+ update.setExtra(extra);
+ extra.setEmojisMsgDTO(body);
+ messageDao.updateById(update);
+ }
+
+ @Override
+ public Object showMsg(Message msg) {
+ return msg.getExtra().getEmojisMsgDTO();
+ }
+
+ @Override
+ public Object showReplyMsg(Message msg) {
+ return "表情";
+ }
+}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/msg/TextMsgHandler.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/msg/TextMsgHandler.java
index d8e347a..5ec867a 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/msg/TextMsgHandler.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/msg/TextMsgHandler.java
@@ -10,8 +10,9 @@ import com.abin.mallchat.common.chat.domain.enums.MessageTypeEnum;
import com.abin.mallchat.common.chat.service.cache.MsgCache;
import com.abin.mallchat.common.common.domain.enums.YesOrNoEnum;
import com.abin.mallchat.common.common.utils.AssertUtil;
-import com.abin.mallchat.common.common.utils.SensitiveWordUtils;
-import com.abin.mallchat.common.common.utils.discover.PrioritizedUrlTitleDiscover;
+import com.abin.mallchat.common.common.utils.discover.PrioritizedUrlDiscover;
+import com.abin.mallchat.common.common.utils.discover.domain.UrlInfo;
+import com.abin.mallchat.common.common.utils.sensitiveWord.SensitiveWordBs;
import com.abin.mallchat.common.user.domain.entity.User;
import com.abin.mallchat.common.user.domain.enums.RoleEnum;
import com.abin.mallchat.common.user.service.IRoleService;
@@ -46,8 +47,10 @@ public class TextMsgHandler extends AbstractMsgHandler {
private UserInfoCache userInfoCache;
@Autowired
private IRoleService iRoleService;
-
- private static final PrioritizedUrlTitleDiscover URL_TITLE_DISCOVER = new PrioritizedUrlTitleDiscover();
+ @Autowired
+ private SensitiveWordBs sensitiveWordBs;
+
+ private static final PrioritizedUrlDiscover URL_TITLE_DISCOVER = new PrioritizedUrlDiscover();
@Override
MessageTypeEnum getMsgTypeEnum() {
@@ -81,7 +84,7 @@ public class TextMsgHandler extends AbstractMsgHandler {
MessageExtra extra = Optional.ofNullable(msg.getExtra()).orElse(new MessageExtra());
Message update = new Message();
update.setId(msg.getId());
- update.setContent(SensitiveWordUtils.filter(body.getContent()));
+ update.setContent(sensitiveWordBs.filter(body.getContent()));
update.setExtra(extra);
//如果有回复消息
if (Objects.nonNull(body.getReplyMsgId())) {
@@ -91,8 +94,8 @@ public class TextMsgHandler extends AbstractMsgHandler {
}
//判断消息url跳转
- Map urlTitleMap = URL_TITLE_DISCOVER.getContentTitleMap(body.getContent());
- extra.setUrlTitleMap(urlTitleMap);
+ Map urlContentMap = URL_TITLE_DISCOVER.getUrlContentMap(body.getContent());
+ extra.setUrlContentMap(urlContentMap);
//艾特功能
if (CollectionUtil.isNotEmpty(body.getAtUidList())) {
extra.setAtUidList(body.getAtUidList());
@@ -106,7 +109,7 @@ public class TextMsgHandler extends AbstractMsgHandler {
public Object showMsg(Message msg) {
TextMsgResp resp = new TextMsgResp();
resp.setContent(msg.getContent());
- resp.setUrlTitleMap(Optional.ofNullable(msg.getExtra()).map(MessageExtra::getUrlTitleMap).orElse(null));
+ resp.setUrlContentMap(Optional.ofNullable(msg.getExtra()).map(MessageExtra::getUrlContentMap).orElse(null));
resp.setAtUidList(Optional.ofNullable(msg.getExtra()).map(MessageExtra::getAtUidList).orElse(null));
//回复消息
Optional reply = Optional.ofNullable(msg.getReplyMsgId())
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/dto/GPTRequestDTO.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/dto/GPTRequestDTO.java
new file mode 100644
index 0000000..cb72432
--- /dev/null
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/dto/GPTRequestDTO.java
@@ -0,0 +1,21 @@
+package com.abin.mallchat.custom.chatai.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class GPTRequestDTO {
+ /**
+ * 聊天内容
+ */
+ private String content;
+ /**
+ * 用户Id
+ */
+ private Long uid;
+}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/ChatGLM2Handler.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/ChatGLM2Handler.java
index 0f7ff1b..83f665a 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/ChatGLM2Handler.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/ChatGLM2Handler.java
@@ -4,12 +4,17 @@ import cn.hutool.http.HttpResponse;
import com.abin.mallchat.common.chat.domain.entity.Message;
import com.abin.mallchat.common.chat.domain.entity.msg.MessageExtra;
import com.abin.mallchat.common.common.constant.RedisKey;
+import com.abin.mallchat.common.common.domain.dto.FrequencyControlDTO;
+import com.abin.mallchat.common.common.exception.FrequencyControlException;
+import com.abin.mallchat.common.common.service.frequencycontrol.FrequencyControlUtil;
import com.abin.mallchat.common.common.utils.RedisUtils;
+import com.abin.mallchat.custom.chatai.dto.GPTRequestDTO;
import com.abin.mallchat.custom.chatai.properties.ChatGLM2Properties;
import com.abin.mallchat.custom.chatai.utils.ChatGLM2Utils;
import com.abin.mallchat.custom.user.domain.vo.response.user.UserInfoResp;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
@@ -21,10 +26,15 @@ import java.util.Random;
import java.util.concurrent.TimeUnit;
import static com.abin.mallchat.common.common.constant.RedisKey.USER_GLM2_TIME_LAST;
+import static com.abin.mallchat.common.common.service.frequencycontrol.FrequencyControlStrategyFactory.TOTAL_COUNT_WITH_IN_FIX_TIME_FREQUENCY_CONTROLLER;
@Slf4j
@Component
public class ChatGLM2Handler extends AbstractChatAIHandler {
+ /**
+ * ChatGLM2Handler限流前缀
+ */
+ private static final String CHAT_GLM2_FREQUENCY_PREFIX = "ChatGLM2Handler";
private static final List ERROR_MSG = Arrays.asList(
"还摸鱼呢?你不下班我还要下班呢。。。。",
@@ -74,27 +84,42 @@ public class ChatGLM2Handler extends AbstractChatAIHandler {
protected String doChat(Message message) {
String content = message.getContent().replace("@" + AI_NAME, "").trim();
Long uid = message.getFromUid();
- Long minute;
+ try {
+ FrequencyControlDTO frequencyControlDTO = new FrequencyControlDTO();
+ frequencyControlDTO.setKey(CHAT_GLM2_FREQUENCY_PREFIX + ":" + uid);
+ frequencyControlDTO.setUnit(TimeUnit.MINUTES);
+ frequencyControlDTO.setCount(1);
+ frequencyControlDTO.setTime(glm2Properties.getMinute().intValue());
+ return FrequencyControlUtil.executeWithFrequencyControl(TOTAL_COUNT_WITH_IN_FIX_TIME_FREQUENCY_CONTROLLER, frequencyControlDTO, () -> sendRequestToGPT(new GPTRequestDTO(content, uid)));
+ } catch (FrequencyControlException e) {
+ return "你太快了亲爱的~过一会再来找人家~";
+ } catch (Throwable e) {
+ return "系统开小差啦~~";
+ }
+ }
+
+ /**
+ * TODO
+ *
+ * @param gptRequestDTO
+ * @return
+ */
+ @Nullable
+ private String sendRequestToGPT(GPTRequestDTO gptRequestDTO) {
+ String content = gptRequestDTO.getContent();
String text;
- if ((minute = userMinutesLater(uid)) > 0) {
- text = "你太快了 " + minute + "分钟后重试";
- } else {
- HttpResponse response = null;
- try {
- response = ChatGLM2Utils
- .create()
- .url(glm2Properties.getUrl())
- .prompt(content)
- .timeout(glm2Properties.getTimeout())
- .send();
- text = ChatGLM2Utils.parseText(response);
- } catch (Exception e) {
- log.warn("glm2 doChat warn:", e);
- return getErrorText();
- }
- if (StringUtils.isNotBlank(text)) {
- RedisUtils.set(RedisKey.getKey(USER_GLM2_TIME_LAST, uid), new Date(), glm2Properties.getMinute(), TimeUnit.MINUTES);
- }
+ HttpResponse response = null;
+ try {
+ response = ChatGLM2Utils
+ .create()
+ .url(glm2Properties.getUrl())
+ .prompt(content)
+ .timeout(glm2Properties.getTimeout())
+ .send();
+ text = ChatGLM2Utils.parseText(response);
+ } catch (Exception e) {
+ log.warn("glm2 doChat warn:", e);
+ return getErrorText();
}
return text;
}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/GPTChatAIHandler.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/GPTChatAIHandler.java
index 1fd85ea..d4b5b55 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/GPTChatAIHandler.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/GPTChatAIHandler.java
@@ -9,6 +9,10 @@ import com.abin.mallchat.custom.chatai.domain.ChatGPTContext;
import com.abin.mallchat.custom.chatai.domain.ChatGPTMsg;
import com.abin.mallchat.custom.chatai.domain.builder.ChatGPTContextBuilder;
import com.abin.mallchat.custom.chatai.domain.builder.ChatGPTMsgBuilder;
+import com.abin.mallchat.common.common.domain.dto.FrequencyControlDTO;
+import com.abin.mallchat.common.common.exception.FrequencyControlException;
+import com.abin.mallchat.common.common.service.frequencycontrol.FrequencyControlUtil;
+import com.abin.mallchat.custom.chatai.dto.GPTRequestDTO;
import com.abin.mallchat.custom.chatai.properties.ChatGPTProperties;
import com.abin.mallchat.custom.chatai.utils.ChatGPTUtils;
import com.abin.mallchat.custom.user.domain.vo.response.user.UserInfoResp;
@@ -24,9 +28,15 @@ import java.util.concurrent.TimeUnit;
import static com.abin.mallchat.common.common.constant.RedisKey.USER_CHAT_CONTEXT;
+import static com.abin.mallchat.common.common.service.frequencycontrol.FrequencyControlStrategyFactory.TOTAL_COUNT_WITH_IN_FIX_TIME_FREQUENCY_CONTROLLER;
+
@Slf4j
@Component
public class GPTChatAIHandler extends AbstractChatAIHandler {
+ /**
+ * GPTChatAIHandler限流前缀
+ */
+ private static final String CHAT_FREQUENCY_PREFIX = "GPTChatAIHandler";
@Autowired
private ChatGPTProperties chatGPTProperties;
@@ -36,16 +46,18 @@ public class GPTChatAIHandler extends AbstractChatAIHandler {
@Override
protected void init() {
super.init();
- UserInfoResp userInfo = userService.getUserInfo(chatGPTProperties.getAIUserId());
- if (userInfo == null) {
- log.error("根据AIUserId:{} 找不到用户信息", chatGPTProperties.getAIUserId());
- throw new RuntimeException("根据AIUserId: " + chatGPTProperties.getAIUserId() + " 找不到用户信息");
+ if (isUse()) {
+ UserInfoResp userInfo = userService.getUserInfo(chatGPTProperties.getAIUserId());
+ if (userInfo == null) {
+ log.error("根据AIUserId:{} 找不到用户信息", chatGPTProperties.getAIUserId());
+ throw new RuntimeException("根据AIUserId: " + chatGPTProperties.getAIUserId() + " 找不到用户信息");
+ }
+ if (StringUtils.isBlank(userInfo.getName())) {
+ log.warn("根据AIUserId:{} 找到的用户信息没有name", chatGPTProperties.getAIUserId());
+ throw new RuntimeException("根据AIUserId: " + chatGPTProperties.getAIUserId() + " 找到的用户没有名字");
+ }
+ AI_NAME = userInfo.getName();
}
- if (StringUtils.isBlank(userInfo.getName())) {
- log.warn("根据AIUserId:{} 找到的用户信息没有name", chatGPTProperties.getAIUserId());
- throw new RuntimeException("根据AIUserId: " + chatGPTProperties.getAIUserId() + " 找到的用户没有名字");
- }
- AI_NAME = userInfo.getName();
}
@Override
@@ -58,37 +70,41 @@ public class GPTChatAIHandler extends AbstractChatAIHandler {
return chatGPTProperties.getAIUserId();
}
-
@Override
protected String doChat(Message message) {
- String prompt = message.getContent().replace("@" + AI_NAME, "").trim();
+ String content = message.getContent().replace("@" + AI_NAME, "").trim();
Long uid = message.getFromUid();
+ try {
+ FrequencyControlDTO frequencyControlDTO = new FrequencyControlDTO();
+ frequencyControlDTO.setKey(CHAT_FREQUENCY_PREFIX + ":" + uid);
+ frequencyControlDTO.setUnit(TimeUnit.HOURS);
+ frequencyControlDTO.setCount(chatGPTProperties.getLimit());
+ frequencyControlDTO.setTime(24);
+ return FrequencyControlUtil.executeWithFrequencyControl(TOTAL_COUNT_WITH_IN_FIX_TIME_FREQUENCY_CONTROLLER, frequencyControlDTO, () -> sendRequestToGPT(new GPTRequestDTO(content, uid)));
+ } catch (FrequencyControlException e) {
+ return "亲爱的,你今天找我聊了" + chatGPTProperties.getLimit() + "次了~人家累了~明天见";
+ } catch (Throwable e) {
+ return "系统开小差啦~~";
+ }
+ }
+
+ private String sendRequestToGPT(GPTRequestDTO gptRequestDTO) {
+ String content = gptRequestDTO.getContent();
Long roomId = message.getRoomId();
Long chatNum;
String text;
- if ((chatNum = getUserChatNum(uid)) > chatGPTProperties.getLimit()) {
- text = "你今天已经和我聊了" + chatNum + "次了,我累了,明天再聊吧";
- } else {
- try {
- ChatGPTContext context = buildContext(message, prompt);// 构建上下文
- context = tailorContext(context);// 裁剪上下文
- log.info("prompt = {}" , prompt);
- Response response = ChatGPTUtils.create(chatGPTProperties.getKey())
- .proxyUrl(chatGPTProperties.getProxyUrl())
- .model(chatGPTProperties.getModelName())
- .timeout(chatGPTProperties.getTimeout())
- .maxTokens(chatGPTProperties.getMaxTokens())
- .message(context.getMsg())
- .send();
- text = ChatGPTUtils.parseText(response);
- ChatGPTMsg chatGPTMsg = ChatGPTMsgBuilder.assistantMsg(text);
- context.addMsg(chatGPTMsg);
- RedisUtils.set(RedisKey.getKey(USER_CHAT_CONTEXT, uid, roomId), context, 1L, TimeUnit.HOURS);
- userChatNumInrc(uid);
- } catch (Exception e) {
- log.warn("gpt doChat warn:", e);
- text = "我累了,明天再聊吧";
- }
+ HttpResponse response = null;
+ try {
+ response = ChatGPTUtils.create(chatGPTProperties.getKey())
+ .proxyUrl(chatGPTProperties.getProxyUrl())
+ .model(chatGPTProperties.getModelName())
+ .timeout(chatGPTProperties.getTimeout())
+ .prompt(content)
+ .send();
+ text = ChatGPTUtils.parseText(response);
+ } catch (Exception e) {
+ log.warn("gpt doChat warn:", e);
+ text = "我累了,明天再聊吧";
}
return text;
}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/common/event/listener/MessageSendListener.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/common/event/listener/MessageSendListener.java
index ba8bcf0..e87bc0a 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/common/event/listener/MessageSendListener.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/common/event/listener/MessageSendListener.java
@@ -5,6 +5,8 @@ import com.abin.mallchat.common.chat.domain.entity.Message;
import com.abin.mallchat.common.common.event.MessageSendEvent;
import com.abin.mallchat.custom.chat.domain.vo.response.ChatMessageResp;
import com.abin.mallchat.custom.chat.service.ChatService;
+import com.abin.mallchat.custom.chat.service.WeChatMsgOperationService;
+import com.abin.mallchat.custom.chat.service.impl.WeChatMsgOperationServiceImpl;
import com.abin.mallchat.custom.chatai.service.IChatAIService;
import com.abin.mallchat.custom.user.service.WebSocketService;
import com.abin.mallchat.custom.user.service.adapter.WSAdapter;
@@ -15,6 +17,8 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionalEventListener;
+import java.util.Objects;
+
/**
* 消息发送监听器
*
@@ -32,6 +36,9 @@ public class MessageSendListener {
@Autowired
private IChatAIService openAIService;
+ @Autowired
+ WeChatMsgOperationService weChatMsgOperationService;
+
@Async
@TransactionalEventListener(classes = MessageSendEvent.class, fallbackExecution = true)
public void notifyAllOnline(MessageSendEvent event) {
@@ -46,4 +53,12 @@ public class MessageSendListener {
openAIService.chat(message);
}
+ @TransactionalEventListener(classes = MessageSendEvent.class, fallbackExecution = true)
+ public void publishChatToWechat(@NotNull MessageSendEvent event) {
+ Message message = messageDao.getById(event.getMsgId());
+ if (Objects.nonNull(message.getExtra().getAtUidList())) {
+ weChatMsgOperationService.publishChatMsgToWeChatUser(message.getFromUid(), message.getExtra().getAtUidList(),
+ message.getContent());
+ }
+ }
}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/common/intecepter/TokenInterceptor.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/common/intecepter/TokenInterceptor.java
index 719fb0d..814297b 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/common/intecepter/TokenInterceptor.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/common/intecepter/TokenInterceptor.java
@@ -45,6 +45,11 @@ public class TokenInterceptor implements HandlerInterceptor {
return true;
}
+ @Override
+ public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
+ MDC.remove(MDCKey.UID);
+ }
+
/**
* 判断是不是公共方法,可以未登录访问的
*
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/controller/UserEmojiController.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/controller/UserEmojiController.java
new file mode 100644
index 0000000..9692359
--- /dev/null
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/controller/UserEmojiController.java
@@ -0,0 +1,77 @@
+package com.abin.mallchat.custom.user.controller;
+
+import com.abin.mallchat.common.common.domain.vo.request.IdReqVO;
+import com.abin.mallchat.common.common.domain.vo.response.ApiResult;
+import com.abin.mallchat.common.common.domain.vo.response.IdRespVO;
+import com.abin.mallchat.common.common.utils.RequestHolder;
+import com.abin.mallchat.custom.user.domain.vo.request.user.UserEmojiReq;
+import com.abin.mallchat.custom.user.domain.vo.response.user.UserEmojiResp;
+import com.abin.mallchat.custom.user.service.UserEmojiService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * 用户表情包
+ *
+ * @author: WuShiJie
+ * @createTime: 2023/7/3 14:21
+ */
+@RestController
+@RequestMapping("/capi/user/emoji")
+@Api(tags = "用户表情包管理相关接口")
+public class UserEmojiController {
+
+ /**
+ * 用户表情包 Service
+ */
+ @Resource
+ private UserEmojiService emojiService;
+
+
+ /**
+ * 表情包列表
+ *
+ * @return 表情包列表
+ * @author WuShiJie
+ * @createTime 2023/7/3 14:46
+ **/
+ @GetMapping("/list")
+ @ApiOperation("表情包列表")
+ public ApiResult> getEmojisPage() {
+ return ApiResult.success(emojiService.list(RequestHolder.get().getUid()));
+ }
+
+
+ /**
+ * 新增表情包
+ *
+ * @param req 用户表情包
+ * @return 表情包
+ * @author WuShiJie
+ * @createTime 2023/7/3 14:46
+ **/
+ @PostMapping()
+ @ApiOperation("新增表情包")
+ public ApiResult insertEmojis(@Valid @RequestBody UserEmojiReq req) {
+ return emojiService.insert(req, RequestHolder.get().getUid());
+ }
+
+ /**
+ * 删除表情包
+ *
+ * @return 删除结果
+ * @author WuShiJie
+ * @createTime 2023/7/3 14:46
+ **/
+ @DeleteMapping()
+ @ApiOperation("删除表情包")
+ public ApiResult deleteEmojis(@Valid @RequestBody IdReqVO reqVO) {
+ emojiService.remove(reqVO.getId(), RequestHolder.get().getUid());
+ return ApiResult.success();
+ }
+}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/enums/OssSceneEnum.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/enums/OssSceneEnum.java
index ce7c7ac..67a5214 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/enums/OssSceneEnum.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/enums/OssSceneEnum.java
@@ -17,6 +17,7 @@ import java.util.stream.Collectors;
@Getter
public enum OssSceneEnum {
CHAT(1, "聊天", "/chat"),
+ EMOJI(2, "表情包", "/emoji"),
;
private final Integer type;
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/request/oss/UploadUrlReq.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/request/oss/UploadUrlReq.java
index d0b0028..df1f473 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/request/oss/UploadUrlReq.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/request/oss/UploadUrlReq.java
@@ -23,7 +23,7 @@ public class UploadUrlReq {
@ApiModelProperty(value = "文件名(带后缀)")
@NotBlank
private String fileName;
- @ApiModelProperty(value = "上传场景1.聊天室")
+ @ApiModelProperty(value = "上传场景1.聊天室,2.表情包")
@NotNull
private Integer scene;
}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/request/user/EmojisPageReq.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/request/user/EmojisPageReq.java
new file mode 100644
index 0000000..9dfe00f
--- /dev/null
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/request/user/EmojisPageReq.java
@@ -0,0 +1,14 @@
+package com.abin.mallchat.custom.user.domain.vo.request.user;
+
+import com.abin.mallchat.common.common.domain.vo.request.CursorPageBaseReq;
+import lombok.Data;
+
+/**
+ * 描述此类的作用
+ *
+ * @author: WuShiJie
+ * @createTime: 2023/7/3 14:52
+ */
+@Data
+public class EmojisPageReq extends CursorPageBaseReq {
+}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/request/user/UserEmojiReq.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/request/user/UserEmojiReq.java
new file mode 100644
index 0000000..5a31343
--- /dev/null
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/request/user/UserEmojiReq.java
@@ -0,0 +1,26 @@
+package com.abin.mallchat.custom.user.domain.vo.request.user;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+
+/**
+ * Description: 表情包反参
+ * Author: abin
+ * Date: 2023-07-09
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class UserEmojiReq {
+ /**
+ * 表情地址
+ */
+ @ApiModelProperty(value = "新增的表情url")
+ private String expressionUrl;
+
+}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/user/UserEmojiResp.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/user/UserEmojiResp.java
new file mode 100644
index 0000000..696393d
--- /dev/null
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/user/UserEmojiResp.java
@@ -0,0 +1,32 @@
+package com.abin.mallchat.custom.user.domain.vo.response.user;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+
+/**
+ * Description: 表情包反参
+ * Author: abin
+ * Date: 2023-07-09
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class UserEmojiResp {
+ /**
+ * id
+ */
+ @ApiModelProperty(value = "id")
+ private Long id;
+
+ /**
+ * 表情地址
+ */
+ @ApiModelProperty(value = "表情url")
+ private String expressionUrl;
+
+}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/LoginService.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/LoginService.java
index ed28384..3f57542 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/LoginService.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/LoginService.java
@@ -38,4 +38,5 @@ public interface LoginService {
* @return
*/
Long getValidUid(String token);
+
}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/UserEmojiService.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/UserEmojiService.java
new file mode 100644
index 0000000..302a58b
--- /dev/null
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/UserEmojiService.java
@@ -0,0 +1,45 @@
+package com.abin.mallchat.custom.user.service;
+
+import com.abin.mallchat.common.common.domain.vo.response.ApiResult;
+import com.abin.mallchat.common.common.domain.vo.response.IdRespVO;
+import com.abin.mallchat.custom.user.domain.vo.request.user.UserEmojiReq;
+import com.abin.mallchat.custom.user.domain.vo.response.user.UserEmojiResp;
+
+import java.util.List;
+
+/**
+ * 用户表情包 Service
+ *
+ * @author: WuShiJie
+ * @createTime: 2023/7/3 14:22
+ */
+public interface UserEmojiService {
+
+ /**
+ * 表情包列表
+ *
+ * @return 表情包列表
+ * @author WuShiJie
+ * @createTime 2023/7/3 14:46
+ **/
+ List list(Long uid);
+
+ /**
+ * 新增表情包
+ *
+ * @param emojis 用户表情包
+ * @param uid 用户ID
+ * @return 表情包
+ * @author WuShiJie
+ * @createTime 2023/7/3 14:46
+ **/
+ ApiResult insert(UserEmojiReq emojis, Long uid);
+
+ /**
+ * 删除表情包
+ *
+ * @param id
+ * @param uid
+ */
+ void remove(Long id, Long uid);
+}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/OssServiceImpl.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/OssServiceImpl.java
index 08bf513..fa533e8 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/OssServiceImpl.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/OssServiceImpl.java
@@ -17,7 +17,6 @@ import org.springframework.stereotype.Service;
*/
@Service
public class OssServiceImpl implements OssService {
- private static final String BUCKET_NAME = "mallchat";
@Autowired
private MinIOTemplate minIOTemplate;
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/UserEmojiServiceImpl.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/UserEmojiServiceImpl.java
new file mode 100644
index 0000000..3a0b882
--- /dev/null
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/UserEmojiServiceImpl.java
@@ -0,0 +1,75 @@
+package com.abin.mallchat.custom.user.service.impl;
+
+import com.abin.mallchat.common.common.annotation.RedissonLock;
+import com.abin.mallchat.common.common.domain.vo.response.ApiResult;
+import com.abin.mallchat.common.common.domain.vo.response.IdRespVO;
+import com.abin.mallchat.common.common.utils.AssertUtil;
+import com.abin.mallchat.common.user.dao.UserEmojiDao;
+import com.abin.mallchat.common.user.domain.entity.UserEmoji;
+import com.abin.mallchat.custom.user.domain.vo.request.user.UserEmojiReq;
+import com.abin.mallchat.custom.user.domain.vo.response.user.UserEmojiResp;
+import com.abin.mallchat.custom.user.service.UserEmojiService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 用户表情包 ServiceImpl
+ *
+ * @author: WuShiJie
+ * @createTime: 2023/7/3 14:23
+ */
+@Service
+@Slf4j
+public class UserEmojiServiceImpl implements UserEmojiService {
+
+ @Autowired
+ private UserEmojiDao userEmojiDao;
+
+ @Override
+ public List list(Long uid) {
+ return userEmojiDao.listByUid(uid).
+ stream()
+ .map(a -> UserEmojiResp.builder()
+ .id(a.getId())
+ .expressionUrl(a.getExpressionUrl())
+ .build())
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * 新增表情包
+ *
+ * @param uid 用户ID
+ * @return 表情包
+ * @author WuShiJie
+ * @createTime 2023/7/3 14:46
+ **/
+ @Override
+ @RedissonLock(key = "#uid")
+ public ApiResult insert(UserEmojiReq req, Long uid) {
+ //校验表情数量是否超过30
+ int count = userEmojiDao.countByUid(uid);
+ AssertUtil.isFalse(count > 30, "最多只能添加30个表情哦~~");
+ //校验表情是否存在
+ Integer existsCount = userEmojiDao.lambdaQuery()
+ .eq(UserEmoji::getExpressionUrl, req.getExpressionUrl())
+ .eq(UserEmoji::getUid, uid)
+ .count();
+ AssertUtil.isFalse(existsCount > 0, "当前表情已存在哦~~");
+ UserEmoji insert = UserEmoji.builder().uid(uid).expressionUrl(req.getExpressionUrl()).build();
+ userEmojiDao.save(insert);
+ return ApiResult.success(IdRespVO.id(insert.getId()));
+ }
+
+ @Override
+ public void remove(Long id, Long uid) {
+ UserEmoji userEmoji = userEmojiDao.getById(id);
+ AssertUtil.isNotEmpty(userEmoji, "表情不能为空");
+ AssertUtil.equal(userEmoji.getUid(), uid, "小黑子,别人表情不是你能删的");
+ userEmojiDao.removeById(id);
+ }
+}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/UserServiceImpl.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/UserServiceImpl.java
index dc63558..e8e5d62 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/UserServiceImpl.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/UserServiceImpl.java
@@ -4,7 +4,7 @@ import cn.hutool.core.util.StrUtil;
import com.abin.mallchat.common.common.event.UserBlackEvent;
import com.abin.mallchat.common.common.event.UserRegisterEvent;
import com.abin.mallchat.common.common.utils.AssertUtil;
-import com.abin.mallchat.common.common.utils.SensitiveWordUtils;
+import com.abin.mallchat.common.common.utils.sensitiveWord.SensitiveWordBs;
import com.abin.mallchat.common.user.dao.BlackDao;
import com.abin.mallchat.common.user.dao.ItemConfigDao;
import com.abin.mallchat.common.user.dao.UserBackpackDao;
@@ -63,6 +63,8 @@ public class UserServiceImpl implements UserService {
private BlackDao blackDao;
@Autowired
private UserSummaryCache userSummaryCache;
+ @Autowired
+ private SensitiveWordBs sensitiveWordBs;
@Override
public UserInfoResp getUserInfo(Long uid) {
@@ -76,7 +78,7 @@ public class UserServiceImpl implements UserService {
public void modifyName(Long uid, ModifyNameReq req) {
//判断名字是不是重复
String newName = req.getName();
- AssertUtil.isFalse(SensitiveWordUtils.hasSensitiveWord(newName), "名字中包含敏感词,请重新输入"); // 判断名字中有没有敏感词
+ AssertUtil.isFalse(sensitiveWordBs.hasSensitiveWord(newName), "名字中包含敏感词,请重新输入"); // 判断名字中有没有敏感词
User oldUser = userDao.getByName(newName);
AssertUtil.isEmpty(oldUser, "名字已经被抢占了,请换一个哦~~");
//判断改名卡够不够
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/WebSocketServiceImpl.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/WebSocketServiceImpl.java
index 7282473..04efa6d 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/WebSocketServiceImpl.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/WebSocketServiceImpl.java
@@ -2,7 +2,6 @@ package com.abin.mallchat.custom.user.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.abin.mallchat.common.common.annotation.FrequencyControl;
import com.abin.mallchat.common.common.config.ThreadPoolConfig;
@@ -20,6 +19,8 @@ import com.abin.mallchat.custom.user.service.LoginService;
import com.abin.mallchat.custom.user.service.WebSocketService;
import com.abin.mallchat.custom.user.service.adapter.WSAdapter;
import com.abin.mallchat.custom.user.websocket.NettyUtil;
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import lombok.SneakyThrows;
@@ -32,9 +33,13 @@ import org.springframework.context.ApplicationEventPublisher;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
+
+import java.time.Duration;
import java.util.*;
+
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
@@ -47,12 +52,18 @@ import java.util.concurrent.locks.ReentrantLock;
@Slf4j
public class WebSocketServiceImpl implements WebSocketService {
+ private static final Duration EXPIRE_TIME = Duration.ofHours(1);
+ private static final Long MAX_MUM_SIZE = 10000L;
+
+ private static final AtomicInteger CODE = new AtomicInteger();
/**
* 所有请求登录的code与channel关系
- * todo 有可能有人请求了二维码,就是不登录,留个坑,之后处理
*/
- private static final ConcurrentHashMap WAIT_LOGIN_MAP = new ConcurrentHashMap<>();
+ private static final Cache WAIT_LOGIN_MAP = Caffeine.newBuilder()
+ .expireAfterWrite(EXPIRE_TIME)
+ .maximumSize(MAX_MUM_SIZE)
+ .build();
/**
* 所有已连接的websocket连接列表和一些额外参数
*/
@@ -66,7 +77,6 @@ public class WebSocketServiceImpl implements WebSocketService {
return ONLINE_WS_MAP;
}
- public static final int EXPIRE_SECONDS = 60 * 60;
@Autowired
private WxMpService wxMpService;
@Autowired
@@ -95,7 +105,7 @@ public class WebSocketServiceImpl implements WebSocketService {
//生成随机不重复的登录码
Integer code = generateLoginCode(channel);
//请求微信接口,获取登录码地址
- WxMpQrCodeTicket wxMpQrCodeTicket = wxMpService.getQrcodeService().qrCodeCreateTmpTicket(code, EXPIRE_SECONDS);
+ WxMpQrCodeTicket wxMpQrCodeTicket = wxMpService.getQrcodeService().qrCodeCreateTmpTicket(code, (int) EXPIRE_TIME.getSeconds());
//返回给前端
sendMsg(channel, WSAdapter.buildLoginResp(wxMpQrCodeTicket));
}
@@ -107,12 +117,11 @@ public class WebSocketServiceImpl implements WebSocketService {
* @return
*/
private Integer generateLoginCode(Channel channel) {
- int code;
do {
- code = RandomUtil.randomInt(Integer.MAX_VALUE);
- } while (WAIT_LOGIN_MAP.contains(code)
- || Objects.nonNull(WAIT_LOGIN_MAP.putIfAbsent(code, channel)));
- return code;
+ CODE.getAndIncrement();
+ } while (WAIT_LOGIN_MAP.asMap().containsKey(CODE.get())
+ || Objects.isNull(WAIT_LOGIN_MAP.get(CODE.get(), c -> channel)));
+ return CODE.get();
}
/**
@@ -199,12 +208,12 @@ public class WebSocketServiceImpl implements WebSocketService {
@Override
public Boolean scanLoginSuccess(Integer loginCode, User user, String token) {
//发送消息
- Channel channel = WAIT_LOGIN_MAP.get(loginCode);
+ Channel channel = WAIT_LOGIN_MAP.getIfPresent(loginCode);
if (Objects.isNull(channel)) {
return Boolean.FALSE;
}
//移除code
- WAIT_LOGIN_MAP.remove(loginCode);
+ WAIT_LOGIN_MAP.invalidate(loginCode);
//用户登录
loginSuccess(channel, user, token);
return true;
@@ -212,7 +221,7 @@ public class WebSocketServiceImpl implements WebSocketService {
@Override
public Boolean scanSuccess(Integer loginCode) {
- Channel channel = WAIT_LOGIN_MAP.get(loginCode);
+ Channel channel = WAIT_LOGIN_MAP.getIfPresent(loginCode);
if (Objects.isNull(channel)) {
return Boolean.FALSE;
}
@@ -287,4 +296,6 @@ public class WebSocketServiceImpl implements WebSocketService {
reentrantLock.unlock();
Thread.sleep(1000);
}
+
+
}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/websocket/HttpHeadersHandler.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/websocket/HttpHeadersHandler.java
index 30f6cdd..6752060 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/websocket/HttpHeadersHandler.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/websocket/HttpHeadersHandler.java
@@ -1,5 +1,6 @@
package com.abin.mallchat.custom.user.websocket;
+import cn.hutool.core.net.url.UrlBuilder;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.FullHttpRequest;
@@ -7,13 +8,23 @@ import io.netty.handler.codec.http.HttpHeaders;
import org.apache.commons.lang3.StringUtils;
import java.net.InetSocketAddress;
+import java.util.Optional;
public class HttpHeadersHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof FullHttpRequest) {
- HttpHeaders headers = ((FullHttpRequest) msg).headers();
+ FullHttpRequest request = (FullHttpRequest) msg;
+ UrlBuilder urlBuilder = UrlBuilder.ofHttp(request.uri());
+
+ // 获取token参数
+ String token = Optional.ofNullable(urlBuilder.getQuery()).map(k->k.get("token")).map(CharSequence::toString).orElse("");
+ NettyUtil.setAttr(ctx.channel(), NettyUtil.TOKEN, token);
+
+ // 获取请求路径
+ request.setUri(urlBuilder.getPath().toString());
+ HttpHeaders headers = request.headers();
String ip = headers.get("X-Real-IP");
if (StringUtils.isEmpty(ip)) {//如果没经过nginx,就直接获取远端地址
InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
@@ -21,7 +32,10 @@ public class HttpHeadersHandler extends ChannelInboundHandlerAdapter {
}
NettyUtil.setAttr(ctx.channel(), NettyUtil.IP, ip);
ctx.pipeline().remove(this);
+ ctx.fireChannelRead(request);
+ }else
+ {
+ ctx.fireChannelRead(msg);
}
- ctx.fireChannelRead(msg);
}
}
\ No newline at end of file
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/websocket/NettyUtil.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/websocket/NettyUtil.java
index 79daafa..bcc5b05 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/websocket/NettyUtil.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/websocket/NettyUtil.java
@@ -1,6 +1,7 @@
package com.abin.mallchat.custom.user.websocket;
import io.netty.channel.Channel;
+import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
@@ -15,6 +16,7 @@ public class NettyUtil {
public static AttributeKey TOKEN = AttributeKey.valueOf("token");
public static AttributeKey IP = AttributeKey.valueOf("ip");
public static AttributeKey UID = AttributeKey.valueOf("uid");
+ public static AttributeKey HANDSHAKER_ATTR_KEY = AttributeKey.valueOf(WebSocketServerHandshaker.class, "HANDSHAKER");
public static void setAttr(Channel channel, AttributeKey attributeKey, T data) {
Attribute attr = channel.attr(attributeKey);
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/websocket/NettyWebSocketServer.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/websocket/NettyWebSocketServer.java
index b70b867..4ebf470 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/websocket/NettyWebSocketServer.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/websocket/NettyWebSocketServer.java
@@ -10,6 +10,7 @@ import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
+import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
@@ -88,7 +89,7 @@ public class NettyWebSocketServer {
* 4. WebSocketServerProtocolHandler 核心功能是把 http协议升级为 ws 协议,保持长连接;
* 是通过一个状态码 101 来切换的
*/
- pipeline.addLast(new WebSocketHandshakeHandler());
+ pipeline.addLast(new WebSocketServerProtocolHandler("/"));
// 自定义handler ,处理业务逻辑
pipeline.addLast(new NettyWebSocketServerHandler());
}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/websocket/NettyWebSocketServerHandler.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/websocket/NettyWebSocketServerHandler.java
index 3d75069..fe8a92a 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/websocket/NettyWebSocketServerHandler.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/websocket/NettyWebSocketServerHandler.java
@@ -19,10 +19,12 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
public class NettyWebSocketServerHandler extends SimpleChannelInboundHandler {
+ private WebSocketService webSocketService;
+
// 当web客户端连接后,触发该方法
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
-// getService().connect(ctx.channel());
+ this.webSocketService = getService();
}
// 客户端离线
@@ -45,7 +47,7 @@ public class NettyWebSocketServerHandler extends SimpleChannelInboundHandlerabin
+ * Date: 2023-07-06
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class WXTemplate {
+
+ @Autowired
+ private WeChatMsgOperationService chatMsgOperationService;
+ @Autowired
+ private ChatServiceImpl chatService;
+
+ @Test
+ public void test() {
+ chatMsgOperationService.publishChatMsgToWeChatUser(1L, Collections.singletonList(10008L), "你家规下去");
+ }
+}