mirror of
https://github.com/zongzibinbin/MallChat.git
synced 2025-12-26 04:47:53 +08:00
fix:解决冲突
This commit is contained in:
commit
bc7b6e3650
@ -7,7 +7,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@ -63,13 +63,13 @@ public class MessageMark implements Serializable {
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField("create_time")
|
||||
private LocalDateTime createTime;
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 修改时间
|
||||
*/
|
||||
@TableField("update_time")
|
||||
private LocalDateTime updateTime;
|
||||
private Date updateTime;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -25,4 +26,6 @@ public class MessageExtra implements Serializable {
|
||||
private Map<String, String> urlTitleMap;
|
||||
//消息撤回详情
|
||||
private MsgRecall recall;
|
||||
//艾特的uid
|
||||
private List<Long> atUidList;
|
||||
}
|
||||
|
||||
@ -15,7 +15,8 @@ import java.util.Objects;
|
||||
|
||||
@Configuration
|
||||
public class RedisConfig {
|
||||
@Bean
|
||||
|
||||
@Bean("myRedisTemplate")
|
||||
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
|
||||
// 创建模板
|
||||
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
|
||||
@ -30,10 +31,11 @@ public class RedisConfig {
|
||||
// value和 hashValue采用 JSON序列化
|
||||
redisTemplate.setValueSerializer(jsonRedisSerializer);
|
||||
redisTemplate.setHashValueSerializer(jsonRedisSerializer);
|
||||
redisTemplate.afterPropertiesSet();
|
||||
return redisTemplate;
|
||||
}
|
||||
|
||||
public class MyRedisSerializerCustomized extends GenericJackson2JsonRedisSerializer {
|
||||
private static class MyRedisSerializerCustomized extends GenericJackson2JsonRedisSerializer {
|
||||
@Override
|
||||
public byte[] serialize(Object source) throws SerializationException {
|
||||
if (Objects.nonNull(source)) {
|
||||
|
||||
@ -26,6 +26,16 @@ public class RedisKey {
|
||||
*/
|
||||
public static final String USER_TOKEN_STRING = "userToken:uid_%d";
|
||||
|
||||
/**
|
||||
* 用户的信息更新时间
|
||||
*/
|
||||
public static final String USER_MODIFY_STRING = "userModify:uid_%d";
|
||||
|
||||
/**
|
||||
* 用户的信息汇总
|
||||
*/
|
||||
public static final String USER_SUMMARY_STRING = "userSummary:uid_%d";
|
||||
|
||||
public static String getKey(String key, Object... objects) {
|
||||
return BASE_KEY + String.format(key, objects);
|
||||
}
|
||||
|
||||
@ -6,10 +6,12 @@ import org.springframework.context.ApplicationEvent;
|
||||
|
||||
@Getter
|
||||
public class MessageMarkEvent extends ApplicationEvent {
|
||||
private ChatMessageMarkDTO dto;
|
||||
|
||||
private final ChatMessageMarkDTO dto;
|
||||
|
||||
public MessageMarkEvent(Object source, ChatMessageMarkDTO dto) {
|
||||
super(source);
|
||||
this.dto = dto;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -6,10 +6,12 @@ import org.springframework.context.ApplicationEvent;
|
||||
|
||||
@Getter
|
||||
public class MessageRecallEvent extends ApplicationEvent {
|
||||
private ChatMsgRecallDTO recallDTO;
|
||||
|
||||
private final ChatMsgRecallDTO recallDTO;
|
||||
|
||||
public MessageRecallEvent(Object source, ChatMsgRecallDTO recallDTO) {
|
||||
super(source);
|
||||
this.recallDTO = recallDTO;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package com.abin.mallchat.common.common.exception;
|
||||
import com.abin.mallchat.common.common.domain.vo.response.ApiResult;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
@ -62,4 +63,14 @@ public class GlobalExceptionHandler {
|
||||
log.info("business exception!The reason is:{}", e.getMessage(), e);
|
||||
return ApiResult.fail(e.getErrorCode(), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* http请求方式不支持
|
||||
*/
|
||||
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
|
||||
public ApiResult<Void> handleException(HttpRequestMethodNotSupportedException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return ApiResult.fail(-1, String.format("不支持'%s'请求", e.getMethod()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,66 @@
|
||||
package com.abin.mallchat.common.common.service.cache;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.abin.mallchat.common.common.utils.RedisUtils;
|
||||
import org.springframework.data.util.Pair;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Description: redis string类型的批量缓存框架
|
||||
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||
* Date: 2023-06-10
|
||||
*/
|
||||
public abstract class AbstractRedisStringCache<IN, OUT> implements BatchCache<IN, OUT> {
|
||||
|
||||
private Class<OUT> outClass;
|
||||
|
||||
protected AbstractRedisStringCache() {
|
||||
ParameterizedType genericSuperclass = (ParameterizedType) this.getClass().getGenericSuperclass();
|
||||
this.outClass = (Class<OUT>) genericSuperclass.getActualTypeArguments()[1];
|
||||
}
|
||||
|
||||
protected abstract String getKey(IN req);
|
||||
|
||||
protected abstract Long getExpireSeconds();
|
||||
|
||||
protected abstract Map<IN, OUT> load(List<IN> req);
|
||||
|
||||
@Override
|
||||
public OUT get(IN req) {
|
||||
return getBatch(Collections.singletonList(req)).get(req);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<IN, OUT> getBatch(List<IN> req) {
|
||||
List<String> keys = req.stream().map(this::getKey).collect(Collectors.toList());
|
||||
List<OUT> valueList = RedisUtils.mget(keys, outClass);
|
||||
List<IN> loadReqs = new ArrayList<>();
|
||||
for (int i = 0; i < valueList.size(); i++) {
|
||||
if (Objects.isNull(valueList.get(i))) {
|
||||
loadReqs.add(req.get(i));
|
||||
}
|
||||
}
|
||||
Map<IN, OUT> load = new HashMap<>();
|
||||
//不足的重新加载进redis
|
||||
if (CollectionUtil.isNotEmpty(loadReqs)) {
|
||||
load = load(loadReqs);
|
||||
Map<String, OUT> loadMap = load.entrySet().stream()
|
||||
.map(a -> Pair.of(getKey(a.getKey()), a.getValue()))
|
||||
.collect(Collectors.toMap(Pair::getFirst, Pair::getSecond));
|
||||
RedisUtils.mset(loadMap, getExpireSeconds());
|
||||
}
|
||||
|
||||
//组装最后的结果
|
||||
Map<IN, OUT> resultMap = new HashMap<>();
|
||||
for (int i = 0; i < req.size(); i++) {
|
||||
IN in = req.get(i);
|
||||
OUT out = Optional.ofNullable(valueList.get(i))
|
||||
.orElse(load.get(in));
|
||||
resultMap.put(in, out);
|
||||
}
|
||||
return resultMap;
|
||||
}
|
||||
}
|
||||
16
mallchat-common/src/main/java/com/abin/mallchat/common/common/service/cache/BatchCache.java
vendored
Normal file
16
mallchat-common/src/main/java/com/abin/mallchat/common/common/service/cache/BatchCache.java
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
package com.abin.mallchat.common.common.service.cache;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface BatchCache<IN, OUT> {
|
||||
/**
|
||||
* 获取单个
|
||||
*/
|
||||
OUT get(IN req);
|
||||
|
||||
/**
|
||||
* 获取批量
|
||||
*/
|
||||
Map<IN, OUT> getBatch(List<IN> req);
|
||||
}
|
||||
@ -44,7 +44,7 @@ public class CursorUtils {
|
||||
.map(String::valueOf)
|
||||
.orElse(null);
|
||||
Boolean isLast = result.size() != cursorPageBaseReq.getPageSize();
|
||||
return new CursorPageBaseResp(cursor, isLast, result);
|
||||
return new CursorPageBaseResp<>(cursor, isLast, result);
|
||||
}
|
||||
|
||||
public <T> CursorPageBaseResp<T> getCursorPageByMysql(IService<T> mapper, CursorPageBaseReq request, Consumer<LambdaQueryWrapper<T>> initWrapper, SFunction<T, ?> cursorColumn) {
|
||||
@ -60,7 +60,7 @@ public class CursorUtils {
|
||||
.map(String::valueOf)
|
||||
.orElse(null);
|
||||
Boolean isLast = page.getRecords().size() != request.getPageSize();
|
||||
return new CursorPageBaseResp(cursor, isLast, page.getRecords());
|
||||
return new CursorPageBaseResp<>(cursor, isLast, page.getRecords());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -8,23 +8,17 @@ import org.springframework.data.redis.core.*;
|
||||
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;
|
||||
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||||
import org.springframework.data.redis.core.script.RedisScript;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class RedisUtils {
|
||||
public RedisTemplate redisTemplate;
|
||||
|
||||
private static StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
static {
|
||||
RedisUtils.stringRedisTemplate = SpringUtil.getBean(StringRedisTemplate.class);
|
||||
}
|
||||
|
||||
@ -49,7 +43,7 @@ public class RedisUtils {
|
||||
* @param key 键
|
||||
* @param time 时间(秒)
|
||||
*/
|
||||
public static boolean expire(String key, long time) {
|
||||
public static Boolean expire(String key, long time) {
|
||||
try {
|
||||
if (time > 0) {
|
||||
stringRedisTemplate.expire(key, time, TimeUnit.SECONDS);
|
||||
@ -68,10 +62,10 @@ public class RedisUtils {
|
||||
* @param time 时间(秒)
|
||||
* @param timeUnit 单位
|
||||
*/
|
||||
public boolean expire(String key, long time, TimeUnit timeUnit) {
|
||||
public static Boolean expire(String key, long time, TimeUnit timeUnit) {
|
||||
try {
|
||||
if (time > 0) {
|
||||
redisTemplate.expire(key, time, timeUnit);
|
||||
stringRedisTemplate.expire(key, time, timeUnit);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
@ -86,7 +80,7 @@ public class RedisUtils {
|
||||
* @param key 键 不能为null
|
||||
* @return 时间(秒) 返回0代表为永久有效
|
||||
*/
|
||||
public static long getExpire(String key) {
|
||||
public static Long getExpire(String key) {
|
||||
return stringRedisTemplate.getExpire(key, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@ -96,7 +90,7 @@ public class RedisUtils {
|
||||
* @param key 键 不能为null
|
||||
* @return 时间(秒) 返回0代表为永久有效
|
||||
*/
|
||||
public static long getExpire(String key, TimeUnit timeUnit) {
|
||||
public static Long getExpire(String key, TimeUnit timeUnit) {
|
||||
return stringRedisTemplate.getExpire(key, timeUnit);
|
||||
}
|
||||
|
||||
@ -106,9 +100,9 @@ public class RedisUtils {
|
||||
* @param pattern key
|
||||
* @return /
|
||||
*/
|
||||
public List<String> scan(String pattern) {
|
||||
public static List<String> scan(String pattern) {
|
||||
ScanOptions options = ScanOptions.scanOptions().match(pattern).build();
|
||||
RedisConnectionFactory factory = redisTemplate.getConnectionFactory();
|
||||
RedisConnectionFactory factory = stringRedisTemplate.getConnectionFactory();
|
||||
RedisConnection rc = Objects.requireNonNull(factory).getConnection();
|
||||
Cursor<byte[]> cursor = rc.scan(options);
|
||||
List<String> result = new ArrayList<>();
|
||||
@ -131,9 +125,9 @@ public class RedisUtils {
|
||||
* @param size 每页数目
|
||||
* @return /
|
||||
*/
|
||||
public List<String> findKeysForPage(String patternKey, int page, int size) {
|
||||
public static List<String> findKeysForPage(String patternKey, int page, int size) {
|
||||
ScanOptions options = ScanOptions.scanOptions().match(patternKey).build();
|
||||
RedisConnectionFactory factory = redisTemplate.getConnectionFactory();
|
||||
RedisConnectionFactory factory = stringRedisTemplate.getConnectionFactory();
|
||||
RedisConnection rc = Objects.requireNonNull(factory).getConnection();
|
||||
Cursor<byte[]> cursor = rc.scan(options);
|
||||
List<String> result = new ArrayList<>(size);
|
||||
@ -167,9 +161,9 @@ public class RedisUtils {
|
||||
* @param key 键
|
||||
* @return true 存在 false不存在
|
||||
*/
|
||||
public boolean hasKey(String key) {
|
||||
public static Boolean hasKey(String key) {
|
||||
try {
|
||||
return redisTemplate.hasKey(key);
|
||||
return stringRedisTemplate.hasKey(key);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return false;
|
||||
@ -185,21 +179,23 @@ public class RedisUtils {
|
||||
public static void del(String... keys) {
|
||||
if (keys != null && keys.length > 0) {
|
||||
if (keys.length == 1) {
|
||||
boolean result = stringRedisTemplate.delete(keys[0]);
|
||||
log.debug("--------------------------------------------");
|
||||
log.debug(new StringBuilder("删除缓存:").append(keys[0]).append(",结果:").append(result).toString());
|
||||
Boolean result = stringRedisTemplate.delete(keys[0]);
|
||||
log.debug("--------------------------------------------");
|
||||
log.debug("删除缓存:" + keys[0] + ",结果:" + result);
|
||||
} else {
|
||||
Set<String> keySet = new HashSet<>();
|
||||
for (String key : keys) {
|
||||
keySet.addAll(stringRedisTemplate.keys(key));
|
||||
Set<String> stringSet = stringRedisTemplate.keys(key);
|
||||
if (Objects.nonNull(stringSet) && !stringSet.isEmpty()) {
|
||||
keySet.addAll(stringSet);
|
||||
}
|
||||
}
|
||||
long count = stringRedisTemplate.delete(keySet);
|
||||
Long count = stringRedisTemplate.delete(keySet);
|
||||
log.debug("--------------------------------------------");
|
||||
log.debug("成功删除缓存:" + keySet.toString());
|
||||
log.debug("成功删除缓存:" + keySet);
|
||||
log.debug("缓存删除数量:" + count + "个");
|
||||
log.debug("--------------------------------------------");
|
||||
}
|
||||
log.debug("--------------------------------------------");
|
||||
}
|
||||
}
|
||||
|
||||
@ -222,7 +218,7 @@ public class RedisUtils {
|
||||
* @param value 值
|
||||
* @return true成功 false失败
|
||||
*/
|
||||
public static boolean set(String key, Object value) {
|
||||
public static Boolean set(String key, Object value) {
|
||||
try {
|
||||
stringRedisTemplate.opsForValue().set(key, objToStr(value));
|
||||
return true;
|
||||
@ -243,7 +239,10 @@ public class RedisUtils {
|
||||
|
||||
public static <T> List<T> mget(Collection<String> keys, Class<T> tClass) {
|
||||
List<String> list = stringRedisTemplate.opsForValue().multiGet(keys);
|
||||
return (List<T>) list.stream().map(o -> toBeanOrNull(o, tClass)).collect(Collectors.toList());
|
||||
if (Objects.isNull(list)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return list.stream().map(o -> toBeanOrNull(o, tClass)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static <T> T toBeanOrNull(String json, Class<T> tClass) {
|
||||
@ -271,10 +270,10 @@ public class RedisUtils {
|
||||
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
|
||||
* @return true成功 false 失败
|
||||
*/
|
||||
public boolean set(String key, Object value, long time) {
|
||||
public static Boolean set(String key, Object value, long time) {
|
||||
try {
|
||||
if (time > 0) {
|
||||
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
|
||||
stringRedisTemplate.opsForValue().set(key, objToStr(value), time, TimeUnit.SECONDS);
|
||||
} else {
|
||||
set(key, value);
|
||||
}
|
||||
@ -294,7 +293,7 @@ public class RedisUtils {
|
||||
* @param timeUnit 类型
|
||||
* @return true成功 false 失败
|
||||
*/
|
||||
public static boolean set(String key, Object value, long time, TimeUnit timeUnit) {
|
||||
public static Boolean set(String key, Object value, long time, TimeUnit timeUnit) {
|
||||
try {
|
||||
if (time > 0) {
|
||||
stringRedisTemplate.opsForValue().set(key, objToStr(value), time, timeUnit);
|
||||
@ -317,8 +316,8 @@ public class RedisUtils {
|
||||
* @param item 项 不能为null
|
||||
* @return 值
|
||||
*/
|
||||
public Object hget(String key, String item) {
|
||||
return redisTemplate.opsForHash().get(key, item);
|
||||
public static Object hget(String key, String item) {
|
||||
return stringRedisTemplate.opsForHash().get(key, item);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -327,8 +326,8 @@ public class RedisUtils {
|
||||
* @param key 键
|
||||
* @return 对应的多个键值
|
||||
*/
|
||||
public Map<Object, Object> hmget(String key) {
|
||||
return redisTemplate.opsForHash().entries(key);
|
||||
public static Map<Object, Object> hmget(String key) {
|
||||
return stringRedisTemplate.opsForHash().entries(key);
|
||||
|
||||
}
|
||||
|
||||
@ -339,9 +338,9 @@ public class RedisUtils {
|
||||
* @param map 对应多个键值
|
||||
* @return true 成功 false 失败
|
||||
*/
|
||||
public boolean hmset(String key, Map<String, Object> map) {
|
||||
public static Boolean hmset(String key, Map<String, Object> map) {
|
||||
try {
|
||||
redisTemplate.opsForHash().putAll(key, map);
|
||||
stringRedisTemplate.opsForHash().putAll(key, map);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
@ -357,9 +356,9 @@ public class RedisUtils {
|
||||
* @param time 时间(秒)
|
||||
* @return true成功 false失败
|
||||
*/
|
||||
public boolean hmset(String key, Map<String, Object> map, long time) {
|
||||
public static Boolean hmset(String key, Map<String, Object> map, long time) {
|
||||
try {
|
||||
redisTemplate.opsForHash().putAll(key, map);
|
||||
stringRedisTemplate.opsForHash().putAll(key, map);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
@ -378,9 +377,9 @@ public class RedisUtils {
|
||||
* @param value 值
|
||||
* @return true 成功 false失败
|
||||
*/
|
||||
public boolean hset(String key, String item, Object value) {
|
||||
public static Boolean hset(String key, String item, Object value) {
|
||||
try {
|
||||
redisTemplate.opsForHash().put(key, item, value);
|
||||
stringRedisTemplate.opsForHash().put(key, item, value);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
@ -397,9 +396,9 @@ public class RedisUtils {
|
||||
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
|
||||
* @return true 成功 false失败
|
||||
*/
|
||||
public boolean hset(String key, String item, Object value, long time) {
|
||||
public static Boolean hset(String key, String item, Object value, long time) {
|
||||
try {
|
||||
redisTemplate.opsForHash().put(key, item, value);
|
||||
stringRedisTemplate.opsForHash().put(key, item, value);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
@ -416,8 +415,8 @@ public class RedisUtils {
|
||||
* @param key 键 不能为null
|
||||
* @param item 项 可以使多个 不能为null
|
||||
*/
|
||||
public void hdel(String key, Object... item) {
|
||||
redisTemplate.opsForHash().delete(key, item);
|
||||
public static void hdel(String key, Object... item) {
|
||||
stringRedisTemplate.opsForHash().delete(key, item);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -427,8 +426,8 @@ public class RedisUtils {
|
||||
* @param item 项 不能为null
|
||||
* @return true 存在 false不存在
|
||||
*/
|
||||
public boolean hHasKey(String key, String item) {
|
||||
return redisTemplate.opsForHash().hasKey(key, item);
|
||||
public static Boolean hHasKey(String key, String item) {
|
||||
return stringRedisTemplate.opsForHash().hasKey(key, item);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -439,8 +438,8 @@ public class RedisUtils {
|
||||
* @param by 要增加几(大于0)
|
||||
* @return
|
||||
*/
|
||||
public double hincr(String key, String item, double by) {
|
||||
return redisTemplate.opsForHash().increment(key, item, by);
|
||||
public static Double hincr(String key, String item, double by) {
|
||||
return stringRedisTemplate.opsForHash().increment(key, item, by);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -451,8 +450,8 @@ public class RedisUtils {
|
||||
* @param by 要减少记(小于0)
|
||||
* @return
|
||||
*/
|
||||
public double hdecr(String key, String item, double by) {
|
||||
return redisTemplate.opsForHash().increment(key, item, -by);
|
||||
public static Double hdecr(String key, String item, double by) {
|
||||
return stringRedisTemplate.opsForHash().increment(key, item, -by);
|
||||
}
|
||||
|
||||
// ============================set=============================
|
||||
@ -463,9 +462,9 @@ public class RedisUtils {
|
||||
* @param key 键
|
||||
* @return
|
||||
*/
|
||||
public Set<Object> sGet(String key) {
|
||||
public static Set<String> sGet(String key) {
|
||||
try {
|
||||
return redisTemplate.opsForSet().members(key);
|
||||
return stringRedisTemplate.opsForSet().members(key);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return null;
|
||||
@ -479,9 +478,9 @@ public class RedisUtils {
|
||||
* @param value 值
|
||||
* @return true 存在 false不存在
|
||||
*/
|
||||
public boolean sHasKey(String key, Object value) {
|
||||
public static Boolean sHasKey(String key, Object value) {
|
||||
try {
|
||||
return redisTemplate.opsForSet().isMember(key, value);
|
||||
return stringRedisTemplate.opsForSet().isMember(key, value);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return false;
|
||||
@ -495,12 +494,16 @@ public class RedisUtils {
|
||||
* @param values 值 可以是多个
|
||||
* @return 成功个数
|
||||
*/
|
||||
public long sSet(String key, Object... values) {
|
||||
public static Long sSet(String key, Object... values) {
|
||||
try {
|
||||
return redisTemplate.opsForSet().add(key, values);
|
||||
String[] s = new String[values.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
s[i] = objToStr(values[i]);
|
||||
}
|
||||
return stringRedisTemplate.opsForSet().add(key, s);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return 0;
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
|
||||
@ -512,16 +515,20 @@ public class RedisUtils {
|
||||
* @param values 值 可以是多个
|
||||
* @return 成功个数
|
||||
*/
|
||||
public long sSetAndTime(String key, long time, Object... values) {
|
||||
public static Long sSetAndTime(String key, long time, Object... values) {
|
||||
try {
|
||||
Long count = redisTemplate.opsForSet().add(key, values);
|
||||
String[] s = new String[values.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
s[i] = objToStr(values[i]);
|
||||
}
|
||||
Long count = stringRedisTemplate.opsForSet().add(key, s);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return count;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return 0;
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
|
||||
@ -531,12 +538,12 @@ public class RedisUtils {
|
||||
* @param key 键
|
||||
* @return
|
||||
*/
|
||||
public long sGetSetSize(String key) {
|
||||
public static Long sGetSetSize(String key) {
|
||||
try {
|
||||
return redisTemplate.opsForSet().size(key);
|
||||
return stringRedisTemplate.opsForSet().size(key);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return 0;
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
|
||||
@ -547,13 +554,12 @@ public class RedisUtils {
|
||||
* @param values 值 可以是多个
|
||||
* @return 移除的个数
|
||||
*/
|
||||
public long setRemove(String key, Object... values) {
|
||||
public static Long setRemove(String key, Object... values) {
|
||||
try {
|
||||
Long count = redisTemplate.opsForSet().remove(key, values);
|
||||
return count;
|
||||
return stringRedisTemplate.opsForSet().remove(key, values);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return 0;
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
|
||||
@ -567,9 +573,9 @@ public class RedisUtils {
|
||||
* @param end 结束 0 到 -1代表所有值
|
||||
* @return
|
||||
*/
|
||||
public List<Object> lGet(String key, long start, long end) {
|
||||
public static List<String> lGet(String key, long start, long end) {
|
||||
try {
|
||||
return redisTemplate.opsForList().range(key, start, end);
|
||||
return stringRedisTemplate.opsForList().range(key, start, end);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return null;
|
||||
@ -582,12 +588,12 @@ public class RedisUtils {
|
||||
* @param key 键
|
||||
* @return
|
||||
*/
|
||||
public long lGetListSize(String key) {
|
||||
public static Long lGetListSize(String key) {
|
||||
try {
|
||||
return redisTemplate.opsForList().size(key);
|
||||
return stringRedisTemplate.opsForList().size(key);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return 0;
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
|
||||
@ -598,9 +604,9 @@ public class RedisUtils {
|
||||
* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
|
||||
* @return
|
||||
*/
|
||||
public Object lGetIndex(String key, long index) {
|
||||
public static String lGetIndex(String key, long index) {
|
||||
try {
|
||||
return redisTemplate.opsForList().index(key, index);
|
||||
return stringRedisTemplate.opsForList().index(key, index);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return null;
|
||||
@ -614,9 +620,9 @@ public class RedisUtils {
|
||||
* @param value 值
|
||||
* @return
|
||||
*/
|
||||
public boolean lSet(String key, Object value) {
|
||||
public static Boolean lSet(String key, Object value) {
|
||||
try {
|
||||
redisTemplate.opsForList().rightPush(key, value);
|
||||
stringRedisTemplate.opsForList().rightPush(key, objToStr(value));
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
@ -632,9 +638,9 @@ public class RedisUtils {
|
||||
* @param time 时间(秒)
|
||||
* @return
|
||||
*/
|
||||
public boolean lSet(String key, Object value, long time) {
|
||||
public static Boolean lSet(String key, Object value, long time) {
|
||||
try {
|
||||
redisTemplate.opsForList().rightPush(key, value);
|
||||
stringRedisTemplate.opsForList().rightPush(key, objToStr(value));
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
@ -652,9 +658,13 @@ public class RedisUtils {
|
||||
* @param value 值
|
||||
* @return
|
||||
*/
|
||||
public boolean lSet(String key, List<Object> value) {
|
||||
public static Boolean lSet(String key, List<Object> value) {
|
||||
try {
|
||||
redisTemplate.opsForList().rightPushAll(key, value);
|
||||
List<String> list = new ArrayList<>();
|
||||
for (Object item : value) {
|
||||
list.add(objToStr(item));
|
||||
}
|
||||
stringRedisTemplate.opsForList().rightPushAll(key, list);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
@ -670,9 +680,13 @@ public class RedisUtils {
|
||||
* @param time 时间(秒)
|
||||
* @return
|
||||
*/
|
||||
public boolean lSet(String key, List<Object> value, long time) {
|
||||
public static Boolean lSet(String key, List<Object> value, long time) {
|
||||
try {
|
||||
redisTemplate.opsForList().rightPushAll(key, value);
|
||||
List<String> list = new ArrayList<>();
|
||||
for (Object item : value) {
|
||||
list.add(objToStr(item));
|
||||
}
|
||||
stringRedisTemplate.opsForList().rightPushAll(key, list);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
@ -691,9 +705,9 @@ public class RedisUtils {
|
||||
* @param value 值
|
||||
* @return /
|
||||
*/
|
||||
public boolean lUpdateIndex(String key, long index, Object value) {
|
||||
public static Boolean lUpdateIndex(String key, long index, Object value) {
|
||||
try {
|
||||
redisTemplate.opsForList().set(key, index, value);
|
||||
stringRedisTemplate.opsForList().set(key, index, objToStr(value));
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
@ -709,12 +723,12 @@ public class RedisUtils {
|
||||
* @param value 值
|
||||
* @return 移除的个数
|
||||
*/
|
||||
public long lRemove(String key, long count, Object value) {
|
||||
public static Long lRemove(String key, long count, Object value) {
|
||||
try {
|
||||
return redisTemplate.opsForList().remove(key, count, value);
|
||||
return stringRedisTemplate.opsForList().remove(key, count, value);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return 0;
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
|
||||
@ -723,11 +737,14 @@ public class RedisUtils {
|
||||
* @param ids id
|
||||
*/
|
||||
public void delByKeys(String prefix, Set<Long> ids) {
|
||||
Set<Object> keys = new HashSet<>();
|
||||
Set<String> keys = new HashSet<>();
|
||||
for (Long id : ids) {
|
||||
keys.addAll(redisTemplate.keys(new StringBuffer(prefix).append(id).toString()));
|
||||
Set<String> stringSet = stringRedisTemplate.keys(prefix + id);
|
||||
if (Objects.nonNull(stringSet) && !stringSet.isEmpty()) {
|
||||
keys.addAll(stringSet);
|
||||
}
|
||||
}
|
||||
long count = redisTemplate.delete(keys);
|
||||
Long count = stringRedisTemplate.delete(keys);
|
||||
// 此处提示可自行删除
|
||||
log.debug("--------------------------------------------");
|
||||
log.debug("成功删除缓存:" + keys.toString());
|
||||
@ -762,7 +779,7 @@ public class RedisUtils {
|
||||
* @return
|
||||
*/
|
||||
public Long zAdd(String key, Set<TypedTuple<String>> values) {
|
||||
return redisTemplate.opsForZSet().add(key, values);
|
||||
return stringRedisTemplate.opsForZSet().add(key, values);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -770,8 +787,8 @@ public class RedisUtils {
|
||||
* @param values
|
||||
* @return
|
||||
*/
|
||||
public Long zRemove(String key, Object... values) {
|
||||
return redisTemplate.opsForZSet().remove(key, values);
|
||||
public static Long zRemove(String key, Object... values) {
|
||||
return stringRedisTemplate.opsForZSet().remove(key, values);
|
||||
}
|
||||
|
||||
public static Long zRemove(String key, Object value) {
|
||||
@ -790,8 +807,8 @@ public class RedisUtils {
|
||||
* @param delta
|
||||
* @return
|
||||
*/
|
||||
public Double zIncrementScore(String key, String value, double delta) {
|
||||
return redisTemplate.opsForZSet().incrementScore(key, value, delta);
|
||||
public static Double zIncrementScore(String key, String value, double delta) {
|
||||
return stringRedisTemplate.opsForZSet().incrementScore(key, value, delta);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -801,8 +818,8 @@ public class RedisUtils {
|
||||
* @param value
|
||||
* @return 0表示第一位
|
||||
*/
|
||||
public Long zRank(String key, Object value) {
|
||||
return redisTemplate.opsForZSet().rank(key, value);
|
||||
public static Long zRank(String key, Object value) {
|
||||
return stringRedisTemplate.opsForZSet().rank(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -812,8 +829,8 @@ public class RedisUtils {
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public Long zReverseRank(String key, Object value) {
|
||||
return redisTemplate.opsForZSet().reverseRank(key, value);
|
||||
public static Long zReverseRank(String key, Object value) {
|
||||
return stringRedisTemplate.opsForZSet().reverseRank(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -824,8 +841,8 @@ public class RedisUtils {
|
||||
* @param end 结束位置, -1查询所有
|
||||
* @return
|
||||
*/
|
||||
public Set<String> zRange(String key, long start, long end) {
|
||||
return redisTemplate.opsForZSet().range(key, start, end);
|
||||
public static Set<String> zRange(String key, long start, long end) {
|
||||
return stringRedisTemplate.opsForZSet().range(key, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -836,9 +853,9 @@ public class RedisUtils {
|
||||
* @param end
|
||||
* @return
|
||||
*/
|
||||
public Set<ZSetOperations.TypedTuple<String>> zRangeWithScores(String key, long start,
|
||||
long end) {
|
||||
return redisTemplate.opsForZSet().rangeWithScores(key, start, end);
|
||||
public static Set<ZSetOperations.TypedTuple<String>> zRangeWithScores(String key, long start,
|
||||
long end) {
|
||||
return stringRedisTemplate.opsForZSet().rangeWithScores(key, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -849,8 +866,8 @@ public class RedisUtils {
|
||||
* @param max 最大值
|
||||
* @return
|
||||
*/
|
||||
public Set<String> zRangeByScore(String key, double min, double max) {
|
||||
return redisTemplate.opsForZSet().rangeByScore(key, min, max);
|
||||
public static Set<String> zRangeByScore(String key, double min, double max) {
|
||||
return stringRedisTemplate.opsForZSet().rangeByScore(key, min, max);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -863,7 +880,7 @@ public class RedisUtils {
|
||||
*/
|
||||
public Set<TypedTuple<String>> zRangeByScoreWithScores(String key,
|
||||
double min, double max) {
|
||||
return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max);
|
||||
return stringRedisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -874,9 +891,9 @@ public class RedisUtils {
|
||||
* @param end
|
||||
* @return
|
||||
*/
|
||||
public Set<TypedTuple<String>> zRangeByScoreWithScores(String key,
|
||||
double min, double max, long start, long end) {
|
||||
return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max,
|
||||
public static Set<TypedTuple<String>> zRangeByScoreWithScores(String key,
|
||||
double min, double max, long start, long end) {
|
||||
return stringRedisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max,
|
||||
start, end);
|
||||
}
|
||||
|
||||
@ -888,8 +905,8 @@ public class RedisUtils {
|
||||
* @param end
|
||||
* @return
|
||||
*/
|
||||
public Set<String> zReverseRange(String key, long start, long end) {
|
||||
return redisTemplate.opsForZSet().reverseRange(key, start, end);
|
||||
public static Set<String> zReverseRange(String key, long start, long end) {
|
||||
return stringRedisTemplate.opsForZSet().reverseRange(key, start, end);
|
||||
}
|
||||
|
||||
// /**
|
||||
@ -967,8 +984,8 @@ public class RedisUtils {
|
||||
* @param max
|
||||
* @return
|
||||
*/
|
||||
public Long zCount(String key, double min, double max) {
|
||||
return redisTemplate.opsForZSet().count(key, min, max);
|
||||
public static Long zCount(String key, double min, double max) {
|
||||
return stringRedisTemplate.opsForZSet().count(key, min, max);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -977,8 +994,8 @@ public class RedisUtils {
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public Long zSize(String key) {
|
||||
return redisTemplate.opsForZSet().size(key);
|
||||
public static Long zSize(String key) {
|
||||
return stringRedisTemplate.opsForZSet().size(key);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -998,8 +1015,8 @@ public class RedisUtils {
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public Double zScore(String key, Object value) {
|
||||
return redisTemplate.opsForZSet().score(key, value);
|
||||
public static Double zScore(String key, Object value) {
|
||||
return stringRedisTemplate.opsForZSet().score(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1010,8 +1027,8 @@ public class RedisUtils {
|
||||
* @param end
|
||||
* @return
|
||||
*/
|
||||
public Long zRemoveRange(String key, long start, long end) {
|
||||
return redisTemplate.opsForZSet().removeRange(key, start, end);
|
||||
public static Long zRemoveRange(String key, long start, long end) {
|
||||
return stringRedisTemplate.opsForZSet().removeRange(key, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1022,8 +1039,8 @@ public class RedisUtils {
|
||||
* @param max
|
||||
* @return
|
||||
*/
|
||||
public Long zRemoveRangeByScore(String key, double min, double max) {
|
||||
return redisTemplate.opsForZSet().removeRangeByScore(key, min, max);
|
||||
public static Long zRemoveRangeByScore(String key, double min, double max) {
|
||||
return stringRedisTemplate.opsForZSet().removeRangeByScore(key, min, max);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1034,8 +1051,8 @@ public class RedisUtils {
|
||||
* @param destKey
|
||||
* @return
|
||||
*/
|
||||
public Long zUnionAndStore(String key, String otherKey, String destKey) {
|
||||
return redisTemplate.opsForZSet().unionAndStore(key, otherKey, destKey);
|
||||
public static Long zUnionAndStore(String key, String otherKey, String destKey) {
|
||||
return stringRedisTemplate.opsForZSet().unionAndStore(key, otherKey, destKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1044,9 +1061,9 @@ public class RedisUtils {
|
||||
* @param destKey
|
||||
* @return
|
||||
*/
|
||||
public Long zUnionAndStore(String key, Collection<String> otherKeys,
|
||||
String destKey) {
|
||||
return redisTemplate.opsForZSet()
|
||||
public static Long zUnionAndStore(String key, Collection<String> otherKeys,
|
||||
String destKey) {
|
||||
return stringRedisTemplate.opsForZSet()
|
||||
.unionAndStore(key, otherKeys, destKey);
|
||||
}
|
||||
|
||||
@ -1058,9 +1075,9 @@ public class RedisUtils {
|
||||
* @param destKey
|
||||
* @return
|
||||
*/
|
||||
public Long zIntersectAndStore(String key, String otherKey,
|
||||
String destKey) {
|
||||
return redisTemplate.opsForZSet().intersectAndStore(key, otherKey,
|
||||
public static Long zIntersectAndStore(String key, String otherKey,
|
||||
String destKey) {
|
||||
return stringRedisTemplate.opsForZSet().intersectAndStore(key, otherKey,
|
||||
destKey);
|
||||
}
|
||||
|
||||
@ -1072,9 +1089,9 @@ public class RedisUtils {
|
||||
* @param destKey
|
||||
* @return
|
||||
*/
|
||||
public Long zIntersectAndStore(String key, Collection<String> otherKeys,
|
||||
String destKey) {
|
||||
return redisTemplate.opsForZSet().intersectAndStore(key, otherKeys,
|
||||
public static Long zIntersectAndStore(String key, Collection<String> otherKeys,
|
||||
String destKey) {
|
||||
return stringRedisTemplate.opsForZSet().intersectAndStore(key, otherKeys,
|
||||
destKey);
|
||||
}
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Description: spring el表达式解析
|
||||
@ -19,7 +20,7 @@ public class SpElUtils {
|
||||
private static final DefaultParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
|
||||
|
||||
public static String parseSpEl(Method method, Object[] args, String spEl) {
|
||||
String[] params = parameterNameDiscoverer.getParameterNames(method);//解析参数名
|
||||
String[] params = Optional.ofNullable(parameterNameDiscoverer.getParameterNames(method)).orElse(new String[]{});//解析参数名
|
||||
EvaluationContext context = new StandardEvaluationContext();//el解析需要的上下文对象
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
context.setVariable(params[i], args[i]);//所有参数都作为原材料扔进去
|
||||
|
||||
@ -66,7 +66,7 @@ public abstract class AbstractUrlTitleDiscover implements UrlTitleDiscover {
|
||||
protected Document getUrlDocument(String matchUrl) {
|
||||
try {
|
||||
Connection connect = Jsoup.connect(matchUrl);
|
||||
connect.timeout(1000);
|
||||
connect.timeout(2000);
|
||||
return connect.get();
|
||||
} catch (Exception e) {
|
||||
log.error("find title error:url:{}", matchUrl, e);
|
||||
|
||||
@ -51,6 +51,13 @@ public class UserBackpackDao extends ServiceImpl<UserBackpackMapper, UserBackpac
|
||||
.list();
|
||||
}
|
||||
|
||||
public List<UserBackpack> getByItemIds(List<Long> uids, List<Long> itemIds) {
|
||||
return lambdaQuery().in(UserBackpack::getUid, uids)
|
||||
.in(UserBackpack::getItemId, itemIds)
|
||||
.eq(UserBackpack::getStatus, YesOrNoEnum.NO.getStatus())
|
||||
.list();
|
||||
}
|
||||
|
||||
public UserBackpack getByIdp(String idempotent) {
|
||||
return lambdaQuery().eq(UserBackpack::getIdempotent, idempotent).one();
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.abin.mallchat.common.user.dao;
|
||||
|
||||
import com.abin.mallchat.common.common.domain.enums.NormalOrNoEnum;
|
||||
import com.abin.mallchat.common.user.domain.entity.User;
|
||||
import com.abin.mallchat.common.user.mapper.UserMapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
@ -7,6 +8,8 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户表 服务实现类
|
||||
@ -40,4 +43,14 @@ public class UserDao extends ServiceImpl<UserMapper, User> {
|
||||
public User getByName(String name) {
|
||||
return lambdaQuery().eq(User::getName, name).one();
|
||||
}
|
||||
|
||||
public List<User> getMemberList() {
|
||||
return lambdaQuery()
|
||||
.eq(User::getStatus, NormalOrNoEnum.NORMAL.getStatus())
|
||||
.orderByDesc(User::getUpdateTime)//最近活跃的1000个人,可以用lastOptTime字段,但是该字段没索引,updateTime可平替
|
||||
.last("limit 1000")//毕竟是大群聊,人数需要做个限制
|
||||
.select(User::getId, User::getName, User::getAvatar)
|
||||
.list();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
package com.abin.mallchat.common.user.domain.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
|
||||
/**
|
||||
* Description: 修改用户名
|
||||
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||
* Date: 2023-03-23
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ItemInfoDTO {
|
||||
@ApiModelProperty(value = "徽章id")
|
||||
private Long itemId;
|
||||
@ApiModelProperty("徽章图像")
|
||||
private String img;
|
||||
@ApiModelProperty("徽章说明")
|
||||
private String describe;
|
||||
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package com.abin.mallchat.common.user.domain.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* Description: 修改用户名
|
||||
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||
* Date: 2023-03-23
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class SummeryInfoDTO {
|
||||
@ApiModelProperty(value = "用户id")
|
||||
private Long uid;
|
||||
@ApiModelProperty(value = "用户昵称")
|
||||
private String name;
|
||||
@ApiModelProperty(value = "用户头像")
|
||||
private String avatar;
|
||||
@ApiModelProperty(value = "归属地")
|
||||
private String locPlace;
|
||||
@ApiModelProperty("佩戴的徽章id")
|
||||
private Long wearingItemId;
|
||||
@ApiModelProperty(value = "用户拥有的徽章id列表")
|
||||
List<Long> itemIds;
|
||||
|
||||
}
|
||||
@ -8,7 +8,7 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@ -49,13 +49,13 @@ public class Black implements Serializable {
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField("create_time")
|
||||
private LocalDateTime createTime;
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 修改时间
|
||||
*/
|
||||
@TableField("update_time")
|
||||
private LocalDateTime updateTime;
|
||||
private Date updateTime;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@ -52,13 +52,13 @@ public class ItemConfig implements Serializable {
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField("create_time")
|
||||
private LocalDateTime createTime;
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 修改时间
|
||||
*/
|
||||
@TableField("update_time")
|
||||
private LocalDateTime updateTime;
|
||||
private Date updateTime;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@ -41,13 +41,13 @@ public class Role implements Serializable {
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField("create_time")
|
||||
private LocalDateTime createTime;
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 修改时间
|
||||
*/
|
||||
@TableField("update_time")
|
||||
private LocalDateTime updateTime;
|
||||
private Date updateTime;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@ -61,13 +61,13 @@ public class UserBackpack implements Serializable {
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField("create_time")
|
||||
private LocalDateTime createTime;
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 修改时间
|
||||
*/
|
||||
@TableField("update_time")
|
||||
private LocalDateTime updateTime;
|
||||
private Date updateTime;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ public enum ItemEnum {
|
||||
cache = Arrays.stream(ItemEnum.values()).collect(Collectors.toMap(ItemEnum::getId, Function.identity()));
|
||||
}
|
||||
|
||||
public static ItemEnum of(Integer type) {
|
||||
public static ItemEnum of(Long type) {
|
||||
return cache.get(type);
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ public enum RoleEnum {
|
||||
cache = Arrays.stream(RoleEnum.values()).collect(Collectors.toMap(RoleEnum::getId, Function.identity()));
|
||||
}
|
||||
|
||||
public static RoleEnum of(Integer type) {
|
||||
public static RoleEnum of(Long type) {
|
||||
return cache.get(type);
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,6 +95,16 @@ public class UserCache {
|
||||
return cursorUtils.getCursorPageByRedis(pageBaseReq, RedisKey.getKey(RedisKey.OFFLINE_UID_ZET), Long::parseLong);
|
||||
}
|
||||
|
||||
public List<Long> getUserModifyTime(List<Long> uidList) {
|
||||
List<String> keys = uidList.stream().map(uid -> RedisKey.getKey(RedisKey.USER_MODIFY_STRING, uid)).collect(Collectors.toList());
|
||||
return RedisUtils.mget(keys, Long.class);
|
||||
}
|
||||
|
||||
public void refreshUserModifyTime(Long uid) {
|
||||
String key = RedisKey.getKey(RedisKey.USER_MODIFY_STRING, uid);
|
||||
RedisUtils.set(key, new Date().getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息,盘路缓存模式
|
||||
*/
|
||||
@ -120,6 +130,11 @@ public class UserCache {
|
||||
return map;
|
||||
}
|
||||
|
||||
public void userInfoChange(Long uid) {
|
||||
delUserInfo(uid);
|
||||
refreshUserModifyTime(uid);
|
||||
}
|
||||
|
||||
public void delUserInfo(Long uid) {
|
||||
String key = RedisKey.getKey(RedisKey.USER_INFO_STRING, uid);
|
||||
RedisUtils.del(key);
|
||||
|
||||
40
mallchat-common/src/main/java/com/abin/mallchat/common/user/service/cache/UserInfoCache.java
vendored
Normal file
40
mallchat-common/src/main/java/com/abin/mallchat/common/user/service/cache/UserInfoCache.java
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
package com.abin.mallchat.common.user.service.cache;
|
||||
|
||||
import com.abin.mallchat.common.common.constant.RedisKey;
|
||||
import com.abin.mallchat.common.common.service.cache.AbstractRedisStringCache;
|
||||
import com.abin.mallchat.common.user.dao.UserDao;
|
||||
import com.abin.mallchat.common.user.domain.entity.User;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Description: 用户基本信息的缓存
|
||||
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||
* Date: 2023-06-10
|
||||
*/
|
||||
@Component
|
||||
public class UserInfoCache extends AbstractRedisStringCache<Long, User> {
|
||||
@Autowired
|
||||
private UserDao userDao;
|
||||
|
||||
@Override
|
||||
protected String getKey(Long uid) {
|
||||
return RedisKey.getKey(RedisKey.USER_INFO_STRING, uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Long getExpireSeconds() {
|
||||
return 5 * 60L;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Long, User> load(List<Long> uidList) {
|
||||
List<User> needLoadUserList = userDao.listByIds(uidList);
|
||||
return needLoadUserList.stream().collect(Collectors.toMap(User::getId, Function.identity()));
|
||||
}
|
||||
}
|
||||
68
mallchat-common/src/main/java/com/abin/mallchat/common/user/service/cache/UserSummaryCache.java
vendored
Normal file
68
mallchat-common/src/main/java/com/abin/mallchat/common/user/service/cache/UserSummaryCache.java
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
package com.abin.mallchat.common.user.service.cache;
|
||||
|
||||
import com.abin.mallchat.common.common.constant.RedisKey;
|
||||
import com.abin.mallchat.common.common.service.cache.AbstractRedisStringCache;
|
||||
import com.abin.mallchat.common.user.dao.UserBackpackDao;
|
||||
import com.abin.mallchat.common.user.domain.dto.SummeryInfoDTO;
|
||||
import com.abin.mallchat.common.user.domain.entity.*;
|
||||
import com.abin.mallchat.common.user.domain.enums.ItemTypeEnum;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Description: 用户所有信息的缓存
|
||||
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||
* Date: 2023-06-10
|
||||
*/
|
||||
@Component
|
||||
public class UserSummaryCache extends AbstractRedisStringCache<Long, SummeryInfoDTO> {
|
||||
@Autowired
|
||||
private UserInfoCache userInfoCache;
|
||||
@Autowired
|
||||
private UserBackpackDao userBackpackDao;
|
||||
@Autowired
|
||||
private ItemCache itemCache;
|
||||
|
||||
@Override
|
||||
protected String getKey(Long uid) {
|
||||
return RedisKey.getKey(RedisKey.USER_SUMMARY_STRING, uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Long getExpireSeconds() {
|
||||
return 10 * 60L;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Long, SummeryInfoDTO> load(List<Long> uidList) {//后续可优化徽章信息也异步加载
|
||||
//用户基本信息
|
||||
Map<Long, User> userMap = userInfoCache.getBatch(uidList);
|
||||
//用户徽章信息
|
||||
List<ItemConfig> itemConfigs = itemCache.getByType(ItemTypeEnum.BADGE.getType());
|
||||
List<Long> itemIds = itemConfigs.stream().map(ItemConfig::getId).collect(Collectors.toList());
|
||||
List<UserBackpack> backpacks = userBackpackDao.getByItemIds(uidList, itemIds);
|
||||
Map<Long, List<UserBackpack>> userBadgeMap = backpacks.stream().collect(Collectors.groupingBy(UserBackpack::getUid));
|
||||
//用户最后一次更新时间
|
||||
return uidList.stream().map(uid -> {
|
||||
SummeryInfoDTO summeryInfoDTO = new SummeryInfoDTO();
|
||||
User user = userMap.get(uid);
|
||||
if (Objects.isNull(user)) {
|
||||
return null;
|
||||
}
|
||||
List<UserBackpack> userBackpacks = userBadgeMap.getOrDefault(user.getId(), new ArrayList<>());
|
||||
summeryInfoDTO.setUid(user.getId());
|
||||
summeryInfoDTO.setName(user.getName());
|
||||
summeryInfoDTO.setAvatar(user.getAvatar());
|
||||
summeryInfoDTO.setLocPlace(Optional.ofNullable(user.getIpInfo()).map(IpInfo::getUpdateIpDetail).map(IpDetail::getCity).orElse(null));
|
||||
summeryInfoDTO.setWearingItemId(user.getItemId());
|
||||
summeryInfoDTO.setItemIds(userBackpacks.stream().map(UserBackpack::getItemId).collect(Collectors.toList()));
|
||||
return summeryInfoDTO;
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toMap(SummeryInfoDTO::getUid, Function.identity()));
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
package com.abin.mallchat.common.user.service.impl;
|
||||
|
||||
import cn.hutool.core.lang.TypeReference;
|
||||
|
||||
import cn.hutool.core.thread.NamedThreadFactory;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
@ -13,7 +12,7 @@ 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.User;
|
||||
import com.abin.mallchat.common.user.service.IpService;
|
||||
import jodd.util.concurrent.ThreadFactoryBuilder;
|
||||
import com.abin.mallchat.common.user.service.cache.UserCache;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -21,7 +20,10 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Description: ip
|
||||
@ -31,21 +33,21 @@ import java.util.concurrent.*;
|
||||
@Service
|
||||
@Slf4j
|
||||
public class IpServiceImpl implements IpService, DisposableBean {
|
||||
private static ExecutorService executor = new ThreadPoolExecutor(1, 1,
|
||||
private static final ExecutorService EXECUTOR = new ThreadPoolExecutor(1, 1,
|
||||
0L, TimeUnit.MILLISECONDS,
|
||||
new LinkedBlockingQueue<Runnable>(500),
|
||||
new NamedThreadFactory("refresh-ipDetail", (ThreadGroup)null,false,
|
||||
new LinkedBlockingQueue<>(500),
|
||||
new NamedThreadFactory("refresh-ipDetail", null, false,
|
||||
new GlobalUncaughtExceptionHandler()));
|
||||
|
||||
@Autowired
|
||||
private UserDao userDao;
|
||||
|
||||
|
||||
@Autowired
|
||||
private UserCache userCache;
|
||||
|
||||
|
||||
@Override
|
||||
public void refreshIpDetailAsync(Long uid) {
|
||||
executor.execute(() -> {
|
||||
EXECUTOR.execute(() -> {
|
||||
User user = userDao.getById(uid);
|
||||
IpInfo ipInfo = user.getIpInfo();
|
||||
if (Objects.isNull(ipInfo)) {
|
||||
@ -62,6 +64,7 @@ public class IpServiceImpl implements IpService, DisposableBean {
|
||||
update.setId(uid);
|
||||
update.setIpInfo(ipInfo);
|
||||
userDao.updateById(update);
|
||||
userCache.userInfoChange(uid);
|
||||
} else {
|
||||
log.error("get ip detail fail ip:{},uid:{}", ip, uid);
|
||||
}
|
||||
@ -103,7 +106,7 @@ public class IpServiceImpl implements IpService, DisposableBean {
|
||||
Date begin = new Date();
|
||||
for (int i = 0; i < 100; i++) {
|
||||
int finalI = i;
|
||||
executor.execute(() -> {
|
||||
EXECUTOR.execute(() -> {
|
||||
IpDetail ipDetail = TryGetIpDetailOrNullTreeTimes("113.90.36.126");
|
||||
if (Objects.nonNull(ipDetail)) {
|
||||
Date date = new Date();
|
||||
@ -115,13 +118,12 @@ public class IpServiceImpl implements IpService, DisposableBean {
|
||||
|
||||
@Override
|
||||
public void destroy() throws InterruptedException {
|
||||
executor.shutdown();
|
||||
if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {//最多等30秒,处理不完就拉倒
|
||||
EXECUTOR.shutdown();
|
||||
if (!EXECUTOR.awaitTermination(30, TimeUnit.SECONDS)) {//最多等30秒,处理不完就拉倒
|
||||
if (log.isErrorEnabled()) {
|
||||
log.error("Timed out while waiting for executor [{}] to terminate", executor);
|
||||
log.error("Timed out while waiting for executor [{}] to terminate", EXECUTOR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -8,24 +8,19 @@ import com.abin.mallchat.common.common.domain.vo.response.CursorPageBaseResp;
|
||||
import com.abin.mallchat.common.common.utils.RequestHolder;
|
||||
import com.abin.mallchat.common.user.domain.enums.BlackTypeEnum;
|
||||
import com.abin.mallchat.common.user.service.cache.UserCache;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageBaseReq;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageMarkReq;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessagePageReq;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageReq;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.request.msg.TextMsgReq;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.response.ChatMemberResp;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.response.ChatMemberStatisticResp;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.response.ChatMessageResp;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.response.ChatRoomResp;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.request.*;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.response.*;
|
||||
import com.abin.mallchat.custom.chat.service.ChatService;
|
||||
import com.abin.mallchat.custom.user.service.impl.UserServiceImpl;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@ -39,6 +34,7 @@ import java.util.Set;
|
||||
@RestController
|
||||
@RequestMapping("/capi/chat")
|
||||
@Api(tags = "聊天室相关接口")
|
||||
@Slf4j
|
||||
public class ChatController {
|
||||
@Autowired
|
||||
private ChatService chatService;
|
||||
@ -53,12 +49,20 @@ public class ChatController {
|
||||
|
||||
@GetMapping("/public/member/page")
|
||||
@ApiOperation("群成员列表")
|
||||
@FrequencyControl(time = 120, count = 20, target = FrequencyControl.Target.IP)
|
||||
public ApiResult<CursorPageBaseResp<ChatMemberResp>> getMemberPage(@Valid CursorPageBaseReq request) {
|
||||
// black(request);
|
||||
CursorPageBaseResp<ChatMemberResp> memberPage = chatService.getMemberPage(request);
|
||||
filterBlackMember(memberPage);
|
||||
return ApiResult.success(memberPage);
|
||||
}
|
||||
|
||||
@GetMapping("/member/list")
|
||||
@ApiOperation("房间内的所有群成员列表-@专用")
|
||||
public ApiResult<List<ChatMemberListResp>> getMemberList(@Valid ChatMessageMemberReq chatMessageMemberReq) {
|
||||
return ApiResult.success(chatService.getMemberList(chatMessageMemberReq));
|
||||
}
|
||||
|
||||
private void filterBlackMember(CursorPageBaseResp<ChatMemberResp> memberPage) {
|
||||
Set<String> blackMembers = getBlackUidSet();
|
||||
memberPage.getList().removeIf(a -> blackMembers.contains(a.getUid().toString()));
|
||||
@ -74,14 +78,28 @@ public class ChatController {
|
||||
return ApiResult.success(chatService.getMemberStatistic());
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private UserServiceImpl userService;
|
||||
|
||||
@GetMapping("/public/msg/page")
|
||||
@ApiOperation("消息列表")
|
||||
@FrequencyControl(time = 120, count = 20, target = FrequencyControl.Target.IP)
|
||||
public ApiResult<CursorPageBaseResp<ChatMessageResp>> getMsgPage(@Valid ChatMessagePageReq request) {
|
||||
// black(request);
|
||||
CursorPageBaseResp<ChatMessageResp> msgPage = chatService.getMsgPage(request, RequestHolder.get().getUid());
|
||||
filterBlackMsg(msgPage);
|
||||
return ApiResult.success(msgPage);
|
||||
}
|
||||
|
||||
private void black(CursorPageBaseReq baseReq) {
|
||||
if (baseReq.getPageSize() > 50) {
|
||||
log.info("limit request:{}", baseReq);
|
||||
baseReq.setPageSize(10);
|
||||
userService.blackIp(RequestHolder.get().getIp());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void filterBlackMsg(CursorPageBaseResp<ChatMessageResp> memberPage) {
|
||||
Set<String> blackMembers = getBlackUidSet();
|
||||
memberPage.getList().removeIf(a -> blackMembers.contains(a.getFromUser().getUid().toString()));
|
||||
@ -94,10 +112,6 @@ public class ChatController {
|
||||
@FrequencyControl(time = 30, count = 5, target = FrequencyControl.Target.UID)
|
||||
@FrequencyControl(time = 60, count = 10, target = FrequencyControl.Target.UID)
|
||||
public ApiResult<ChatMessageResp> sendMsg(@Valid @RequestBody ChatMessageReq request) {
|
||||
if (Objects.isNull(request.getBody())) {
|
||||
TextMsgReq req = new TextMsgReq(request.getContent(), request.getReplyMsgId());//todo 消息兼容之后删了
|
||||
request.setBody(req);
|
||||
}
|
||||
Long msgId = chatService.sendMsg(request, RequestHolder.get().getUid());
|
||||
//返回完整消息格式,方便前端展示
|
||||
return ApiResult.success(chatService.getMsgResp(msgId, RequestHolder.get().getUid()));
|
||||
@ -105,7 +119,7 @@ public class ChatController {
|
||||
|
||||
@PutMapping("/msg/mark")
|
||||
@ApiOperation("消息标记")
|
||||
@FrequencyControl(time = 20, count = 3, target = FrequencyControl.Target.UID)
|
||||
@FrequencyControl(time = 10, count = 5, target = FrequencyControl.Target.UID)
|
||||
public ApiResult<Void> setMsgMark(@Valid @RequestBody ChatMessageMarkReq request) {
|
||||
chatService.setMsgMark(RequestHolder.get().getUid(), request);
|
||||
return ApiResult.success();
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
package com.abin.mallchat.custom.chat.domain.vo.request;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* Description: 消息列表请求
|
||||
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||
* Date: 2023-03-29
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ChatMessageMemberReq {
|
||||
@NotNull
|
||||
@ApiModelProperty("会话id")
|
||||
private Long roomId;
|
||||
}
|
||||
@ -30,11 +30,4 @@ public class ChatMessageReq {
|
||||
@ApiModelProperty("消息内容,类型不同传值不同,见https://www.yuque.com/snab/mallcaht/rkb2uz5k1qqdmcmd")
|
||||
private Object body;
|
||||
|
||||
@ApiModelProperty("消息内容")
|
||||
@Deprecated
|
||||
private String content;
|
||||
|
||||
@ApiModelProperty("回复的消息id,如果没有别传就好")
|
||||
@Deprecated
|
||||
private Long replyMsgId;
|
||||
}
|
||||
|
||||
@ -6,6 +6,8 @@ import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Description: 文本消息入参
|
||||
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||
@ -22,4 +24,7 @@ public class TextMsgReq {
|
||||
|
||||
@ApiModelProperty("回复的消息id,如果没有别传就好")
|
||||
private Long replyMsgId;
|
||||
|
||||
@ApiModelProperty("艾特的uid")
|
||||
private List<Long> atUidList;
|
||||
}
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
package com.abin.mallchat.custom.chat.domain.vo.response;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Description: 群成员列表的成员信息
|
||||
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||
* Date: 2023-03-23
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ChatMemberListResp {
|
||||
@ApiModelProperty("uid")
|
||||
private Long uid;
|
||||
@ApiModelProperty("用户名称")
|
||||
private String name;
|
||||
@ApiModelProperty("头像")
|
||||
private String avatar;
|
||||
}
|
||||
@ -6,6 +6,7 @@ import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -22,6 +23,8 @@ public class TextMsgResp {
|
||||
private String content;
|
||||
@ApiModelProperty("消息链接映射")
|
||||
private Map<String, String> urlTitleMap;
|
||||
@ApiModelProperty("艾特的uid")
|
||||
private List<Long> atUidList;
|
||||
@ApiModelProperty("父消息,如果没有父消息,返回的是null")
|
||||
private TextMsgResp.ReplyMsg reply;
|
||||
|
||||
|
||||
@ -3,16 +3,11 @@ package com.abin.mallchat.custom.chat.service;
|
||||
import com.abin.mallchat.common.chat.domain.entity.Message;
|
||||
import com.abin.mallchat.common.common.domain.vo.request.CursorPageBaseReq;
|
||||
import com.abin.mallchat.common.common.domain.vo.response.CursorPageBaseResp;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageBaseReq;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageMarkReq;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessagePageReq;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageReq;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.response.ChatMemberResp;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.response.ChatMemberStatisticResp;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.response.ChatMessageResp;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.response.ChatRoomResp;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.request.*;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.response.*;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Description: 消息处理类
|
||||
@ -76,4 +71,6 @@ public interface ChatService {
|
||||
void setMsgMark(Long uid, ChatMessageMarkReq request);
|
||||
|
||||
void recallMsg(Long uid, ChatMessageBaseReq request);
|
||||
|
||||
List<ChatMemberListResp> getMemberList(ChatMessageMemberReq chatMessageMemberReq);
|
||||
}
|
||||
|
||||
@ -7,7 +7,6 @@ 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.common.utils.discover.PrioritizedUrlTitleDiscover;
|
||||
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;
|
||||
@ -27,7 +26,6 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
public class MessageAdapter {
|
||||
public static final int CAN_CALLBACK_GAP_COUNT = 100;
|
||||
private static final PrioritizedUrlTitleDiscover URL_TITLE_DISCOVER = new PrioritizedUrlTitleDiscover();
|
||||
|
||||
public static Message buildMsgSave(ChatMessageReq request, Long uid) {
|
||||
|
||||
@ -35,16 +33,10 @@ public class MessageAdapter {
|
||||
.fromUid(uid)
|
||||
.roomId(request.getRoomId())
|
||||
.status(MessageStatusEnum.NORMAL.getStatus())
|
||||
.extra(buildExtra(request))
|
||||
.build();
|
||||
|
||||
}
|
||||
|
||||
private static MessageExtra buildExtra(ChatMessageReq request) {
|
||||
Map<String, String> contentTitleMap = URL_TITLE_DISCOVER.getContentTitleMap(request.getContent());
|
||||
return MessageExtra.builder().urlTitleMap(contentTitleMap).build();
|
||||
}
|
||||
|
||||
public static List<ChatMessageResp> buildMsgResp(List<Message> messages, Map<Long, Message> replyMap, Map<Long, User> userMap, List<MessageMark> msgMark, Long receiveUid, Map<Long, ItemConfig> itemMap) {
|
||||
Map<Long, List<MessageMark>> markMap = msgMark.stream().collect(Collectors.groupingBy(MessageMark::getMsgId));
|
||||
return messages.stream().map(a -> {
|
||||
|
||||
@ -26,14 +26,8 @@ import com.abin.mallchat.common.user.domain.enums.RoleEnum;
|
||||
import com.abin.mallchat.common.user.service.IRoleService;
|
||||
import com.abin.mallchat.common.user.service.cache.ItemCache;
|
||||
import com.abin.mallchat.common.user.service.cache.UserCache;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageBaseReq;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageMarkReq;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessagePageReq;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageReq;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.response.ChatMemberResp;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.response.ChatMemberStatisticResp;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.response.ChatMessageResp;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.response.ChatRoomResp;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.request.*;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.response.*;
|
||||
import com.abin.mallchat.custom.chat.service.ChatService;
|
||||
import com.abin.mallchat.custom.chat.service.adapter.MemberAdapter;
|
||||
import com.abin.mallchat.custom.chat.service.adapter.MessageAdapter;
|
||||
@ -45,7 +39,9 @@ import com.abin.mallchat.custom.chat.service.strategy.msg.AbstractMsgHandler;
|
||||
import com.abin.mallchat.custom.chat.service.strategy.msg.MsgHandlerFactory;
|
||||
import com.abin.mallchat.custom.chat.service.strategy.msg.RecallMsgHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@ -92,7 +88,7 @@ public class ChatServiceImpl implements ChatService {
|
||||
@Transactional
|
||||
public Long sendMsg(ChatMessageReq request, Long uid) {
|
||||
AbstractMsgHandler msgHandler = MsgHandlerFactory.getStrategyNoNull(request.getMsgType());//todo 这里先不扩展,后续再改
|
||||
msgHandler.checkMsg(request);
|
||||
msgHandler.checkMsg(request, uid);
|
||||
//同步获取消息的跳转链接标题
|
||||
Message insert = MessageAdapter.buildMsgSave(request, uid);
|
||||
messageDao.save(insert);
|
||||
@ -196,6 +192,22 @@ public class ChatServiceImpl implements ChatService {
|
||||
recallMsgHandler.recall(uid, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(cacheNames = "member", key = "'memberList.'+#req.roomId")
|
||||
public List<ChatMemberListResp> getMemberList(ChatMessageMemberReq req) {
|
||||
if (Objects.equals(1L, req.getRoomId())) {//大群聊可看见所有人
|
||||
return userDao.getMemberList()
|
||||
.stream()
|
||||
.map(a -> {
|
||||
ChatMemberListResp resp = new ChatMemberListResp();
|
||||
BeanUtils.copyProperties(a, resp);
|
||||
resp.setUid(a.getId());
|
||||
return resp;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void checkRecall(Long uid, Message message) {
|
||||
AssertUtil.isNotEmpty(message, "消息有误");
|
||||
AssertUtil.notEqual(message.getType(), MessageTypeEnum.RECALL, "消息无法撤回");
|
||||
|
||||
@ -20,7 +20,7 @@ public abstract class AbstractMsgHandler {
|
||||
|
||||
abstract MessageTypeEnum getMsgTypeEnum();
|
||||
|
||||
public abstract void checkMsg(ChatMessageReq req);
|
||||
public abstract void checkMsg(ChatMessageReq req, Long uid);
|
||||
|
||||
public abstract void saveMsg(Message msg, ChatMessageReq req);
|
||||
|
||||
|
||||
@ -40,7 +40,7 @@ public class RecallMsgHandler extends AbstractMsgHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkMsg(ChatMessageReq request) {
|
||||
public void checkMsg(ChatMessageReq request, Long uid) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@ -9,15 +9,22 @@ 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.discover.PrioritizedUrlTitleDiscover;
|
||||
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;
|
||||
import com.abin.mallchat.common.user.service.cache.UserCache;
|
||||
import com.abin.mallchat.common.user.service.cache.UserInfoCache;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageReq;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.request.msg.TextMsgReq;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.response.msg.TextMsgResp;
|
||||
import com.abin.mallchat.custom.chat.service.adapter.MessageAdapter;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
@ -34,6 +41,12 @@ public class TextMsgHandler extends AbstractMsgHandler {
|
||||
private MsgCache msgCache;
|
||||
@Autowired
|
||||
private UserCache userCache;
|
||||
@Autowired
|
||||
private UserInfoCache userInfoCache;
|
||||
@Autowired
|
||||
private IRoleService iRoleService;
|
||||
@Autowired
|
||||
private static final PrioritizedUrlTitleDiscover URL_TITLE_DISCOVER = new PrioritizedUrlTitleDiscover();
|
||||
|
||||
@Override
|
||||
MessageTypeEnum getMsgTypeEnum() {
|
||||
@ -41,7 +54,7 @@ public class TextMsgHandler extends AbstractMsgHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkMsg(ChatMessageReq request) {
|
||||
public void checkMsg(ChatMessageReq request, Long uid) {
|
||||
TextMsgReq body = BeanUtil.toBean(request.getBody(), TextMsgReq.class);
|
||||
AssertUtil.isNotEmpty(body.getContent(), "内容不能为空");
|
||||
AssertUtil.isTrue(body.getContent().length() < 500, "消息内容过长,服务器扛不住啊,兄dei");
|
||||
@ -51,14 +64,26 @@ public class TextMsgHandler extends AbstractMsgHandler {
|
||||
AssertUtil.isNotEmpty(replyMsg, "回复消息不存在");
|
||||
AssertUtil.equal(replyMsg.getRoomId(), request.getRoomId(), "只能回复相同会话内的消息");
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(body.getAtUidList())) {
|
||||
AssertUtil.isTrue(body.getAtUidList().size() > 10, "一次别艾特这么多人");
|
||||
List<Long> atUidList = body.getAtUidList();
|
||||
Map<Long, User> batch = userInfoCache.getBatch(atUidList);
|
||||
AssertUtil.equal(atUidList.size(), batch.values().size(), "@用户不存在");
|
||||
boolean atAll = body.getAtUidList().contains(0L);
|
||||
if (atAll) {
|
||||
AssertUtil.isTrue(iRoleService.hasPower(uid, RoleEnum.CHAT_MANAGER), "没有权限");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveMsg(Message msg, ChatMessageReq request) {//插入文本内容
|
||||
TextMsgReq body = BeanUtil.toBean(request.getBody(), TextMsgReq.class);
|
||||
MessageExtra extra = Optional.ofNullable(msg.getExtra()).orElse(new MessageExtra());
|
||||
Message update = new Message();
|
||||
update.setId(msg.getId());
|
||||
update.setContent(body.getContent());
|
||||
update.setExtra(extra);
|
||||
//如果有回复消息
|
||||
if (Objects.nonNull(body.getReplyMsgId())) {
|
||||
Integer gapCount = messageDao.getGapCount(request.getRoomId(), body.getReplyMsgId(), msg.getId());
|
||||
@ -66,6 +91,15 @@ public class TextMsgHandler extends AbstractMsgHandler {
|
||||
update.setReplyMsgId(body.getReplyMsgId());
|
||||
|
||||
}
|
||||
//判断消息url跳转
|
||||
Map<String, String> urlTitleMap = URL_TITLE_DISCOVER.getContentTitleMap(body.getContent());
|
||||
extra.setUrlTitleMap(urlTitleMap);
|
||||
//艾特功能
|
||||
if (CollectionUtils.isNotEmpty(body.getAtUidList())) {
|
||||
extra.setAtUidList(body.getAtUidList());
|
||||
|
||||
}
|
||||
|
||||
messageDao.updateById(update);
|
||||
}
|
||||
|
||||
@ -74,6 +108,7 @@ public class TextMsgHandler extends AbstractMsgHandler {
|
||||
TextMsgResp resp = new TextMsgResp();
|
||||
resp.setContent(msg.getContent());
|
||||
resp.setUrlTitleMap(Optional.ofNullable(msg.getExtra()).map(MessageExtra::getUrlTitleMap).orElse(null));
|
||||
resp.setAtUidList(Optional.ofNullable(msg.getExtra()).map(MessageExtra::getAtUidList).orElse(null));
|
||||
//回复消息
|
||||
Optional<Message> reply = Optional.ofNullable(msg.getReplyMsgId())
|
||||
.map(msgCache::getMsg)
|
||||
|
||||
@ -45,7 +45,7 @@ public class ItemReceiveListener {
|
||||
User user = userDao.getById(userBackpack.getUid());
|
||||
if (Objects.isNull(user.getItemId())) {
|
||||
userDao.wearingBadge(userBackpack.getUid(), userBackpack.getItemId());
|
||||
userCache.delUserInfo(userBackpack.getUid());
|
||||
userCache.userInfoChange(userBackpack.getUid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,11 +4,11 @@ package com.abin.mallchat.custom.user.controller;
|
||||
import com.abin.mallchat.common.common.domain.vo.response.ApiResult;
|
||||
import com.abin.mallchat.common.common.utils.AssertUtil;
|
||||
import com.abin.mallchat.common.common.utils.RequestHolder;
|
||||
import com.abin.mallchat.common.user.domain.dto.ItemInfoDTO;
|
||||
import com.abin.mallchat.common.user.domain.dto.SummeryInfoDTO;
|
||||
import com.abin.mallchat.common.user.domain.enums.RoleEnum;
|
||||
import com.abin.mallchat.common.user.service.IRoleService;
|
||||
import com.abin.mallchat.custom.user.domain.vo.request.user.BlackReq;
|
||||
import com.abin.mallchat.custom.user.domain.vo.request.user.ModifyNameReq;
|
||||
import com.abin.mallchat.custom.user.domain.vo.request.user.WearingBadgeReq;
|
||||
import com.abin.mallchat.custom.user.domain.vo.request.user.*;
|
||||
import com.abin.mallchat.custom.user.domain.vo.response.user.BadgeResp;
|
||||
import com.abin.mallchat.custom.user.domain.vo.response.user.UserInfoResp;
|
||||
import com.abin.mallchat.custom.user.service.UserService;
|
||||
@ -43,6 +43,18 @@ public class UserController {
|
||||
return ApiResult.success(userService.getUserInfo(RequestHolder.get().getUid()));
|
||||
}
|
||||
|
||||
@PostMapping("/public/summary/userInfo/batch")
|
||||
@ApiOperation("用户聚合信息-返回的代表需要刷新的")
|
||||
public ApiResult<List<SummeryInfoDTO>> getSummeryUserInfo(@Valid @RequestBody SummeryInfoReq req) {
|
||||
return ApiResult.success(userService.getSummeryUserInfo(req));
|
||||
}
|
||||
|
||||
@PostMapping("/public/badges/batch")
|
||||
@ApiOperation("徽章聚合信息-返回的代表需要刷新的")
|
||||
public ApiResult<List<ItemInfoDTO>> getItemInfo(@Valid @RequestBody ItemInfoReq req) {
|
||||
return ApiResult.success(userService.getItemInfo(req));
|
||||
}
|
||||
|
||||
@PutMapping("/name")
|
||||
@ApiOperation("修改用户名")
|
||||
public ApiResult<Void> modifyName(@Valid @RequestBody ModifyNameReq req) {
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
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;
|
||||
|
||||
import javax.validation.constraints.Size;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* Description: 批量查询徽章详情
|
||||
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||
* Date: 2023-03-23
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ItemInfoReq {
|
||||
@ApiModelProperty(value = "徽章信息入参")
|
||||
@Size(max = 50)
|
||||
private List<infoReq> reqList;
|
||||
|
||||
@Data
|
||||
public static class infoReq {
|
||||
@ApiModelProperty(value = "徽章id")
|
||||
private Long itemId;
|
||||
@ApiModelProperty(value = "最近一次更新徽章信息时间")
|
||||
private Long lastModifyTime;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
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;
|
||||
|
||||
import javax.validation.constraints.Size;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* Description: 批量查询用户汇总详情
|
||||
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||
* Date: 2023-03-23
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class SummeryInfoReq {
|
||||
@ApiModelProperty(value = "用户信息入参")
|
||||
@Size(max = 50)
|
||||
private List<infoReq> reqList;
|
||||
|
||||
@Data
|
||||
public static class infoReq {
|
||||
@ApiModelProperty(value = "uid")
|
||||
private Long uid;
|
||||
@ApiModelProperty(value = "最近一次更新用户信息时间")
|
||||
private Long lastModifyTime;
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
package com.abin.mallchat.custom.user.service;
|
||||
|
||||
import com.abin.mallchat.custom.user.domain.vo.request.user.BlackReq;
|
||||
import com.abin.mallchat.custom.user.domain.vo.request.user.ModifyNameReq;
|
||||
import com.abin.mallchat.custom.user.domain.vo.request.user.WearingBadgeReq;
|
||||
import com.abin.mallchat.common.user.domain.dto.ItemInfoDTO;
|
||||
import com.abin.mallchat.common.user.domain.dto.SummeryInfoDTO;
|
||||
import com.abin.mallchat.custom.user.domain.vo.request.user.*;
|
||||
import com.abin.mallchat.custom.user.domain.vo.response.user.BadgeResp;
|
||||
import com.abin.mallchat.custom.user.domain.vo.response.user.UserInfoResp;
|
||||
|
||||
@ -57,4 +57,14 @@ public interface UserService {
|
||||
void register(String openId);
|
||||
|
||||
void black(BlackReq req);
|
||||
|
||||
/**
|
||||
* 获取用户汇总信息
|
||||
*
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
List<SummeryInfoDTO> getSummeryUserInfo(SummeryInfoReq req);
|
||||
|
||||
List<ItemInfoDTO> getItemInfo(ItemInfoReq req);
|
||||
}
|
||||
|
||||
@ -24,8 +24,6 @@ public class LoginServiceImpl implements LoginService {
|
||||
|
||||
@Autowired
|
||||
private JwtUtils jwtUtils;
|
||||
@Autowired
|
||||
private RedisUtils redisUtils;
|
||||
//token过期时间
|
||||
private static final Integer TOKEN_EXPIRE_DAYS = 5;
|
||||
//token续期时间
|
||||
@ -37,6 +35,7 @@ public class LoginServiceImpl implements LoginService {
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean verify(String token) {
|
||||
Long uid = jwtUtils.getUidOrNull(token);
|
||||
if (Objects.isNull(uid)) {
|
||||
@ -48,25 +47,26 @@ public class LoginServiceImpl implements LoginService {
|
||||
}
|
||||
|
||||
@Async
|
||||
@Override
|
||||
public void renewalTokenIfNecessary(String token) {
|
||||
Long uid = jwtUtils.getUidOrNull(token);
|
||||
if (Objects.isNull(uid)) {
|
||||
return;
|
||||
}
|
||||
String key = RedisKey.getKey(RedisKey.USER_TOKEN_STRING, uid);
|
||||
long expireDays = redisUtils.getExpire(key, TimeUnit.DAYS);
|
||||
long expireDays = RedisUtils.getExpire(key, TimeUnit.DAYS);
|
||||
if (expireDays == -2) {//不存在的key
|
||||
return;
|
||||
}
|
||||
if (expireDays < TOKEN_RENEWAL_DAYS) {//小于一天的token帮忙续期
|
||||
redisUtils.expire(key, TOKEN_EXPIRE_DAYS, TimeUnit.DAYS);
|
||||
RedisUtils.expire(key, TOKEN_EXPIRE_DAYS, TimeUnit.DAYS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String login(Long uid) {
|
||||
String key = RedisKey.getKey(RedisKey.USER_TOKEN_STRING, uid);
|
||||
String token = redisUtils.getStr(key);
|
||||
String token = RedisUtils.getStr(key);
|
||||
if (StrUtil.isNotBlank(token)) {
|
||||
return token;
|
||||
}
|
||||
|
||||
@ -8,6 +8,8 @@ import com.abin.mallchat.common.user.dao.BlackDao;
|
||||
import com.abin.mallchat.common.user.dao.ItemConfigDao;
|
||||
import com.abin.mallchat.common.user.dao.UserBackpackDao;
|
||||
import com.abin.mallchat.common.user.dao.UserDao;
|
||||
import com.abin.mallchat.common.user.domain.dto.ItemInfoDTO;
|
||||
import com.abin.mallchat.common.user.domain.dto.SummeryInfoDTO;
|
||||
import com.abin.mallchat.common.user.domain.entity.Black;
|
||||
import com.abin.mallchat.common.user.domain.entity.ItemConfig;
|
||||
import com.abin.mallchat.common.user.domain.entity.User;
|
||||
@ -17,9 +19,8 @@ import com.abin.mallchat.common.user.domain.enums.ItemEnum;
|
||||
import com.abin.mallchat.common.user.domain.enums.ItemTypeEnum;
|
||||
import com.abin.mallchat.common.user.service.cache.ItemCache;
|
||||
import com.abin.mallchat.common.user.service.cache.UserCache;
|
||||
import com.abin.mallchat.custom.user.domain.vo.request.user.BlackReq;
|
||||
import com.abin.mallchat.custom.user.domain.vo.request.user.ModifyNameReq;
|
||||
import com.abin.mallchat.custom.user.domain.vo.request.user.WearingBadgeReq;
|
||||
import com.abin.mallchat.common.user.service.cache.UserSummaryCache;
|
||||
import com.abin.mallchat.custom.user.domain.vo.request.user.*;
|
||||
import com.abin.mallchat.custom.user.domain.vo.response.user.BadgeResp;
|
||||
import com.abin.mallchat.custom.user.domain.vo.response.user.UserInfoResp;
|
||||
import com.abin.mallchat.custom.user.service.UserService;
|
||||
@ -30,7 +31,10 @@ import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@ -56,6 +60,8 @@ public class UserServiceImpl implements UserService {
|
||||
private ItemCache itemCache;
|
||||
@Autowired
|
||||
private BlackDao blackDao;
|
||||
@Autowired
|
||||
private UserSummaryCache userSummaryCache;
|
||||
|
||||
@Override
|
||||
public UserInfoResp getUserInfo(Long uid) {
|
||||
@ -79,7 +85,7 @@ public class UserServiceImpl implements UserService {
|
||||
//改名
|
||||
userDao.modifyName(uid, req.getName());
|
||||
//删除缓存
|
||||
userCache.delUserInfo(uid);
|
||||
userCache.userInfoChange(uid);
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,7 +111,7 @@ public class UserServiceImpl implements UserService {
|
||||
//佩戴徽章
|
||||
userDao.wearingBadge(uid, req.getBadgeId());
|
||||
//删除用户缓存
|
||||
userCache.delUserInfo(uid);
|
||||
userCache.userInfoChange(uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -128,7 +134,44 @@ public class UserServiceImpl implements UserService {
|
||||
applicationEventPublisher.publishEvent(new UserBlackEvent(this, byId));
|
||||
}
|
||||
|
||||
private void blackIp(String ip) {
|
||||
@Override
|
||||
public List<SummeryInfoDTO> getSummeryUserInfo(SummeryInfoReq req) {
|
||||
//需要前端同步的uid
|
||||
List<Long> uidList = getNeedSyncUidList(req.getReqList());
|
||||
//加载用户信息
|
||||
Map<Long, SummeryInfoDTO> batch = userSummaryCache.getBatch(uidList);
|
||||
return new ArrayList<>(batch.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ItemInfoDTO> getItemInfo(ItemInfoReq req) {//简单做,更新时间可判断被修改
|
||||
return req.getReqList().stream().map(a -> {
|
||||
ItemConfig itemConfig = itemCache.getById(a.getItemId());
|
||||
if (Objects.nonNull(a.getLastModifyTime()) && a.getLastModifyTime() >= itemConfig.getUpdateTime().getTime()) {
|
||||
return null;
|
||||
}
|
||||
ItemInfoDTO dto = new ItemInfoDTO();
|
||||
dto.setItemId(itemConfig.getId());
|
||||
dto.setImg(itemConfig.getImg());
|
||||
dto.setDescribe(itemConfig.getDescribe());
|
||||
return dto;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<Long> getNeedSyncUidList(List<SummeryInfoReq.infoReq> reqList) {
|
||||
List<Long> result = new ArrayList<>();
|
||||
List<Long> userModifyTime = userCache.getUserModifyTime(reqList.stream().map(SummeryInfoReq.infoReq::getUid).collect(Collectors.toList()));
|
||||
for (int i = 0; i < reqList.size(); i++) {
|
||||
SummeryInfoReq.infoReq infoReq = reqList.get(i);
|
||||
Long modifyTime = userModifyTime.get(i);
|
||||
if (Objects.isNull(infoReq.getLastModifyTime()) || (Objects.nonNull(modifyTime) && modifyTime > infoReq.getLastModifyTime())) {
|
||||
result.add(infoReq.getUid());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void blackIp(String ip) {
|
||||
if (StrUtil.isBlank(ip)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ 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;
|
||||
import com.abin.mallchat.common.common.event.UserOfflineEvent;
|
||||
import com.abin.mallchat.common.common.event.UserOnlineEvent;
|
||||
@ -89,6 +90,8 @@ public class WebSocketServiceImpl implements WebSocketService {
|
||||
*/
|
||||
@SneakyThrows
|
||||
@Override
|
||||
@FrequencyControl(time = 10, count = 2, spEl = "T(com.abin.mallchat.common.common.utils.RequestHolder).get().getIp()")
|
||||
@FrequencyControl(time = 100, count = 5, spEl = "T(com.abin.mallchat.common.common.utils.RequestHolder).get().getIp()")
|
||||
public void handleLoginReq(Channel channel) {
|
||||
//生成随机不重复的登录码
|
||||
Integer code = generateLoginCode(channel);
|
||||
@ -119,6 +122,7 @@ public class WebSocketServiceImpl implements WebSocketService {
|
||||
* @param channel
|
||||
*/
|
||||
@Override
|
||||
@FrequencyControl(time = 10, count = 5, spEl = "T(com.abin.mallchat.common.common.utils.RequestHolder).get().getIp()")
|
||||
public void connect(Channel channel) {
|
||||
ONLINE_WS_MAP.put(channel, new WSChannelExtraDTO());
|
||||
}
|
||||
@ -174,6 +178,7 @@ public class WebSocketServiceImpl implements WebSocketService {
|
||||
getOrInitChannelExt(channel).setUid(uid);
|
||||
ONLINE_UID_MAP.putIfAbsent(uid, new CopyOnWriteArrayList<>());
|
||||
ONLINE_UID_MAP.get(uid).add(channel);
|
||||
NettyUtil.setAttr(channel, NettyUtil.UID, uid);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
package com.abin.mallchat.custom.user.websocket;
|
||||
|
||||
import com.abin.mallchat.common.common.constant.MDCKey;
|
||||
import com.abin.mallchat.common.common.domain.dto.RequestInfo;
|
||||
import com.abin.mallchat.common.common.utils.RequestHolder;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.MDC;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
@Slf4j
|
||||
public class NettyCollectorHandler extends ChannelInboundHandlerAdapter {
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
String tid = UUID.randomUUID().toString();
|
||||
MDC.put(MDCKey.TID, tid);
|
||||
RequestInfo info = new RequestInfo();
|
||||
info.setUid(NettyUtil.getAttr(ctx.channel(), NettyUtil.UID));
|
||||
info.setIp(NettyUtil.getAttr(ctx.channel(), NettyUtil.IP));
|
||||
RequestHolder.set(info);
|
||||
|
||||
ctx.fireChannelRead(msg);
|
||||
}
|
||||
}
|
||||
@ -13,6 +13,7 @@ import io.netty.util.AttributeKey;
|
||||
public class NettyUtil {
|
||||
|
||||
public static AttributeKey<String> IP = AttributeKey.valueOf("ip");
|
||||
public static AttributeKey<Long> UID = AttributeKey.valueOf("uid");
|
||||
|
||||
public static <T> void setAttr(Channel channel, AttributeKey<T> attributeKey, T data) {
|
||||
Attribute<T> attr = channel.attr(attributeKey);
|
||||
|
||||
@ -79,6 +79,7 @@ public class NettyWebSocketServer {
|
||||
pipeline.addLast(new HttpObjectAggregator(8192));
|
||||
//保存用户ip
|
||||
pipeline.addLast(new HttpHeadersHandler());
|
||||
pipeline.addLast(new NettyCollectorHandler());
|
||||
/**
|
||||
* 说明:
|
||||
* 1. 对于 WebSocket,它的数据是以帧frame 的形式传递的;
|
||||
|
||||
@ -9,6 +9,7 @@ import com.abin.mallchat.custom.user.service.WebSocketService;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
||||
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
|
||||
import io.netty.handler.timeout.IdleState;
|
||||
import io.netty.handler.timeout.IdleStateEvent;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -20,7 +21,7 @@ public class NettyWebSocketServerHandler extends SimpleChannelInboundHandler<Tex
|
||||
// 当web客户端连接后,触发该方法
|
||||
@Override
|
||||
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
|
||||
getService().connect(ctx.channel());
|
||||
// getService().connect(ctx.channel());
|
||||
}
|
||||
|
||||
// 客户端离线
|
||||
@ -63,6 +64,8 @@ public class NettyWebSocketServerHandler extends SimpleChannelInboundHandler<Tex
|
||||
// 关闭用户的连接
|
||||
userOffLine(ctx);
|
||||
}
|
||||
} else if (evt == WebSocketServerProtocolHandler.ServerHandshakeStateEvent.HANDSHAKE_COMPLETE) {
|
||||
getService().connect(ctx.channel());
|
||||
}
|
||||
super.userEventTriggered(ctx, evt);
|
||||
}
|
||||
@ -70,7 +73,7 @@ public class NettyWebSocketServerHandler extends SimpleChannelInboundHandler<Tex
|
||||
// 处理异常
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
log.warn("异常发生,异常消息 ={}", cause.getMessage());
|
||||
log.warn("异常发生,异常消息 ={}", cause);
|
||||
ctx.channel().close();
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user