生成收藏模块代码.

This commit is contained in:
lijiahang
2023-09-01 17:17:35 +08:00
parent 72b219cf95
commit a4875154df
19 changed files with 731 additions and 5 deletions

View File

@@ -2,6 +2,7 @@ package com.orion.ops.framework.redis.core.utils;
import com.alibaba.fastjson.JSON;
import com.orion.lang.define.cache.CacheKeyDefine;
import com.orion.lang.utils.Strings;
import com.orion.lang.utils.io.Streams;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
@@ -26,6 +27,19 @@ public class RedisUtils {
private RedisUtils() {
}
/**
* 扫描 key
*
* @param match 匹配值
* @return keys
*/
public static Set<String> scanKeys(String match) {
// TODO TEST
return scanKeys(ScanOptions.scanOptions()
.match(match)
.build());
}
/**
* 扫描 key
*
@@ -92,6 +106,28 @@ public class RedisUtils {
setJson(key, define, cache);
}
/**
* 设置 json
*
* @param key key
* @param define define
* @param value value
*/
public static void set(String key, CacheKeyDefine define, Object value) {
if (value == null) {
value = Strings.EMPTY;
}
if (define.getTimeout() == 0) {
// 不过期
redisTemplate.opsForValue().set(key, value.toString());
} else {
// 过期
redisTemplate.opsForValue().set(key, value.toString(),
define.getTimeout(),
define.getUnit());
}
}
/**
* 设置 json
*

View File

@@ -0,0 +1,63 @@
package com.orion.ops.module.infra.api;
import com.orion.ops.module.infra.enums.FavoriteTypeEnum;
import java.util.List;
import java.util.concurrent.Future;
/**
* 收藏 对外服务类
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023-9-1 10:30
*/
public interface FavoriteApi {
/**
* 添加收藏
*
* @param type type
* @param userId userId
* @param relId relId
*/
void addFavorite(FavoriteTypeEnum type, Long userId, Long relId);
/**
* 获取收藏 relId 列表 会有已删除的 id
*
* @param type type
* @param userId userId
* @return relIdList
*/
Future<List<Long>> getFavoriteRelIdList(FavoriteTypeEnum type, Long userId);
/**
* 通过 userId 删除收藏
*
* @param userId userId
*/
void deleteFavoriteByUserId(Long userId);
/**
* 通过 userId 删除收藏
*
* @param userIdList userId
*/
void deleteFavoriteByUserIdList(List<Long> userIdList);
/**
* 通过 relId 删除收藏
*
* @param relId relId
*/
void deleteFavoriteByRelId(Long relId);
/**
* 通过 relId 删除收藏
*
* @param relIdList relIdList
*/
void deleteFavoriteByRelIdList(List<Long> relIdList);
}

View File

@@ -0,0 +1,19 @@
package com.orion.ops.module.infra.enums;
/**
* 收藏类型 枚举
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/8/25 10:53
*/
public enum FavoriteTypeEnum {
/**
* 主机
*/
HOST,
;
}

View File

@@ -0,0 +1,132 @@
package com.orion.ops.module.infra.api.impl;
import com.orion.lang.utils.Strings;
import com.orion.lang.utils.collect.Lists;
import com.orion.ops.framework.common.constant.Const;
import com.orion.ops.framework.redis.core.utils.RedisUtils;
import com.orion.ops.module.infra.api.FavoriteApi;
import com.orion.ops.module.infra.define.FavoriteCacheKeyDefine;
import com.orion.ops.module.infra.entity.request.favorite.FavoriteCreateRequest;
import com.orion.ops.module.infra.entity.request.favorite.FavoriteQueryRequest;
import com.orion.ops.module.infra.enums.FavoriteTypeEnum;
import com.orion.ops.module.infra.service.FavoriteService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
/**
* 收藏 对外服务实现类
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023-9-1 10:30
*/
@Slf4j
@Service
public class FavoriteApiImpl implements FavoriteApi {
@Resource
private FavoriteService favoriteService;
@Resource
private RedisTemplate<String, String> redisTemplate;
@Override
@Async("asyncExecutor")
public void addFavorite(FavoriteTypeEnum type, Long userId, Long relId) {
// 插入数据库
String typeName = type.name();
FavoriteCreateRequest request = new FavoriteCreateRequest();
request.setUserId(userId);
request.setRelId(relId);
request.setType(typeName);
favoriteService.addFavorite(request);
// 获取缓存
String key = FavoriteCacheKeyDefine.FAVORITE.format(typeName, userId);
String cache = redisTemplate.opsForValue().get(key);
List<Long> relIdList;
if (Strings.isBlank(cache)) {
relIdList = Lists.newList();
} else {
relIdList = Arrays.stream(cache.split(Const.COMMA))
.map(Long::valueOf)
.collect(Collectors.toList());
}
// 插入缓存
relIdList.add(relId);
RedisUtils.set(key, FavoriteCacheKeyDefine.FAVORITE, Lists.join(relIdList));
}
@Override
@Async("asyncExecutor")
public Future<List<Long>> getFavoriteRelIdList(FavoriteTypeEnum type, Long userId) {
// 获取缓存
String typeName = type.name();
String key = FavoriteCacheKeyDefine.FAVORITE.format(typeName, userId);
String cache = redisTemplate.opsForValue().get(key);
List<Long> relIdList;
if (cache != null) {
// 不为 null 则获取缓存
relIdList = Arrays.stream(cache.split(Const.COMMA))
.map(Long::valueOf)
.collect(Collectors.toList());
} else {
// 为 null 从数据库获取
FavoriteQueryRequest request = new FavoriteQueryRequest();
request.setUserId(userId);
request.setType(typeName);
relIdList = favoriteService.getFavoriteRelIdList(request);
// 设置缓存
redisTemplate.opsForValue().set(key, Lists.join(relIdList));
}
return CompletableFuture.completedFuture(relIdList);
}
@Override
@Async("asyncExecutor")
public void deleteFavoriteByUserId(Long userId) {
List<String> favoriteKeyList = Arrays.stream(FavoriteTypeEnum.values())
.map(s -> FavoriteCacheKeyDefine.FAVORITE.format(s, userId))
.collect(Collectors.toList());
redisTemplate.delete(favoriteKeyList);
}
@Override
@Async("asyncExecutor")
public void deleteFavoriteByUserIdList(List<Long> userIdList) {
List<String> favoriteKeyList = new ArrayList<>();
for (Long userId : userIdList) {
Arrays.stream(FavoriteTypeEnum.values())
.map(s -> FavoriteCacheKeyDefine.FAVORITE.format(s, userId))
.forEach(favoriteKeyList::add);
}
redisTemplate.delete(favoriteKeyList);
}
@Override
@Async("asyncExecutor")
public void deleteFavoriteByRelId(Long relId) {
// 只删除数据库 redis 等自动失效
FavoriteQueryRequest request = new FavoriteQueryRequest();
request.setRelId(relId);
favoriteService.deleteFavorite(request);
}
@Override
public void deleteFavoriteByRelIdList(List<Long> relIdList) {
// 只删除数据库 redis 等自动失效
FavoriteQueryRequest request = new FavoriteQueryRequest();
request.setRelIdList(relIdList);
favoriteService.deleteFavorite(request);
}
}

View File

@@ -0,0 +1,28 @@
package com.orion.ops.module.infra.convert;
import com.orion.ops.module.infra.entity.domain.FavoriteDO;
import com.orion.ops.module.infra.entity.request.favorite.FavoriteCreateRequest;
import com.orion.ops.module.infra.entity.request.favorite.FavoriteQueryRequest;
import com.orion.ops.module.infra.entity.vo.FavoriteVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* 收藏 内部对象转换器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023-9-1 10:30
*/
@Mapper
public interface FavoriteConvert {
FavoriteConvert MAPPER = Mappers.getMapper(FavoriteConvert.class);
FavoriteDO to(FavoriteCreateRequest request);
FavoriteDO to(FavoriteQueryRequest request);
FavoriteVO to(FavoriteDO domain);
}

View File

@@ -0,0 +1,32 @@
package com.orion.ops.module.infra.dao;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.orion.ops.framework.mybatis.core.mapper.IMapper;
import com.orion.ops.module.infra.entity.domain.FavoriteDO;
import org.apache.ibatis.annotations.Mapper;
/**
* 收藏 Mapper 接口
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023-9-1 10:30
*/
@Mapper
public interface FavoriteDAO extends IMapper<FavoriteDO> {
/**
* 获取查询条件
*
* @param entity entity
* @return 查询条件
*/
default LambdaQueryWrapper<FavoriteDO> queryCondition(FavoriteDO entity) {
return this.wrapper()
.eq(FavoriteDO::getId, entity.getId())
.eq(FavoriteDO::getUserId, entity.getUserId())
.eq(FavoriteDO::getRelId, entity.getRelId())
.eq(FavoriteDO::getType, entity.getType());
}
}

View File

@@ -0,0 +1,24 @@
package com.orion.ops.module.infra.define;
import com.orion.lang.define.cache.CacheKeyBuilder;
import com.orion.lang.define.cache.CacheKeyDefine;
import java.util.concurrent.TimeUnit;
/**
* 收藏服务缓存 key
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/8/31 11:48
*/
public interface FavoriteCacheKeyDefine {
CacheKeyDefine FAVORITE = new CacheKeyBuilder()
.key("favorite:{}:{}")
.desc("收藏信息 ${type} ${userId}")
.type(Long.class)
.timeout(3, TimeUnit.DAYS)
.build();
}

View File

@@ -0,0 +1,45 @@
package com.orion.ops.module.infra.entity.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.orion.ops.framework.mybatis.core.domain.BaseDO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
/**
* 收藏 实体对象
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023-9-1 10:30
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@TableName(value = "favorite", autoResultMap = true)
@Schema(name = "FavoriteDO", description = "收藏 实体对象")
public class FavoriteDO extends BaseDO {
private static final long serialVersionUID = 1L;
@Schema(description = "id")
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@Schema(description = "用户id")
@TableField("user_id")
private Long userId;
@Schema(description = "引用id")
@TableField("rel_id")
private Long relId;
@Schema(description = "收藏类型")
@TableField("type")
private String type;
}

View File

@@ -0,0 +1,58 @@
package com.orion.ops.module.infra.entity.export;
import com.orion.lang.utils.time.Dates;
import com.orion.office.excel.annotation.ExportField;
import com.orion.office.excel.annotation.ExportSheet;
import com.orion.office.excel.annotation.ExportTitle;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.Date;
/**
* 系统角色导出
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/8/31 17:40
*/
@Data
@ExportTitle(title = SystemRoleExport.TITLE)
@ExportSheet(name = "系统角色", filterHeader = true, freezeHeader = true, indexToSort = true)
public class SystemRoleExport {
public static final String TITLE = "系统角色导出";
@ExportField(index = 0, header = "id", width = 16)
@Schema(description = "id")
private Long id;
@ExportField(index = 1, header = "角色名称", width = 16)
@Schema(description = "角色名称")
private String name;
@ExportField(index = 2, header = "角色编码", width = 16)
@Schema(description = "角色编码")
private String code;
@ExportField(index = 3, header = "状态", width = 16)
@Schema(description = "状态 0停用 1启用")
private Integer status;
@ExportField(index = 4, header = "创建时间", width = 16, format = Dates.YMD_HMS)
@Schema(description = "创建时间")
private Date createTime;
@ExportField(index = 5, header = "修改时间", width = 16, format = Dates.YMD_HMS)
@Schema(description = "修改时间")
private Date updateTime;
@ExportField(index = 6, header = "创建人", width = 16)
@Schema(description = "创建人")
private String creator;
@ExportField(index = 7, header = "修改人", width = 16)
@Schema(description = "修改人")
private String updater;
}

View File

@@ -0,0 +1,41 @@
package com.orion.ops.module.infra.entity.request.favorite;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.io.Serializable;
/**
* 收藏 创建请求对象
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023-9-1 10:30
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(name = "FavoriteCreateRequest", description = "收藏 创建请求对象")
public class FavoriteCreateRequest implements Serializable {
@NotNull
@Schema(description = "用户id")
private Long userId;
@NotNull
@Schema(description = "引用id")
private Long relId;
@NotBlank
@Size(max = 12)
@Schema(description = "收藏类型")
private String type;
}

View File

@@ -0,0 +1,44 @@
package com.orion.ops.module.infra.entity.request.favorite;
import com.orion.ops.framework.common.entity.PageRequest;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import javax.validation.constraints.Size;
import java.util.List;
/**
* 收藏 查询请求对象
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023-9-1 10:30
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Schema(name = "FavoriteQueryRequest", description = "收藏 查询请求对象")
public class FavoriteQueryRequest extends PageRequest {
@Schema(description = "id")
private Long id;
@Schema(description = "用户id")
private Long userId;
@Schema(description = "引用id")
private Long relId;
@Size(max = 12)
@Schema(description = "收藏类型")
private String type;
@Schema(description = "用户id")
private List<Long> userIdList;
@Schema(description = "引用id")
private List<Long> relIdList;
}

View File

@@ -0,0 +1,39 @@
package com.orion.ops.module.infra.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 收藏 视图响应对象
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023-9-1 10:30
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(name = "FavoriteVO", description = "收藏 视图响应对象")
public class FavoriteVO implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "id")
private Long id;
@Schema(description = "用户id")
private Long userId;
@Schema(description = "引用id")
private Long relId;
@Schema(description = "收藏类型")
private String type;
}

View File

@@ -0,0 +1,50 @@
package com.orion.ops.module.infra.service;
import com.orion.ops.module.infra.entity.request.favorite.FavoriteCreateRequest;
import com.orion.ops.module.infra.entity.request.favorite.FavoriteQueryRequest;
import com.orion.ops.module.infra.entity.vo.FavoriteVO;
import java.util.List;
/**
* 收藏 服务类
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023-9-1 10:30
*/
public interface FavoriteService {
/**
* 创建收藏
*
* @param request request
* @return id
*/
Long addFavorite(FavoriteCreateRequest request);
/**
* 查询收藏列表
*
* @param request request
* @return rows
*/
List<FavoriteVO> getFavoriteList(FavoriteQueryRequest request);
/**
* 查询收藏 relId 列表
*
* @param request request
* @return relIdList
*/
List<Long> getFavoriteRelIdList(FavoriteQueryRequest request);
/**
* 删除收藏
*
* @param request request
* @return effect
*/
Integer deleteFavorite(FavoriteQueryRequest request);
}

View File

@@ -291,7 +291,7 @@ public class AuthenticationServiceImpl implements AuthenticationService {
private void invalidOtherDeviceToken(Long id, long loginTime, String remoteAddr, String location) {
String loginKey = UserCacheKeyDefine.LOGIN_TOKEN.format(id, "*");
// 获取登陆信息
Set<String> loginKeyList = RedisUtils.scanKeys(loginKey, 100);
Set<String> loginKeyList = RedisUtils.scanKeys(loginKey);
if (!loginKeyList.isEmpty()) {
// 获取有效登陆信息
List<LoginTokenDTO> loginTokenInfoList = redisTemplate.opsForValue()
@@ -314,7 +314,7 @@ public class AuthenticationServiceImpl implements AuthenticationService {
// 删除续签信息
if (allowRefresh) {
String refreshKey = UserCacheKeyDefine.LOGIN_REFRESH.format(id, "*");
Set<String> refreshKeyList = RedisUtils.scanKeys(refreshKey, 100);
Set<String> refreshKeyList = RedisUtils.scanKeys(refreshKey);
if (!refreshKeyList.isEmpty()) {
redisTemplate.delete(refreshKeyList);
}

View File

@@ -0,0 +1,92 @@
package com.orion.ops.module.infra.service.impl;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.orion.ops.module.infra.convert.FavoriteConvert;
import com.orion.ops.module.infra.dao.FavoriteDAO;
import com.orion.ops.module.infra.entity.domain.FavoriteDO;
import com.orion.ops.module.infra.entity.request.favorite.FavoriteCreateRequest;
import com.orion.ops.module.infra.entity.request.favorite.FavoriteQueryRequest;
import com.orion.ops.module.infra.entity.vo.FavoriteVO;
import com.orion.ops.module.infra.service.FavoriteService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
/**
* 收藏 服务实现类
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023-9-1 10:30
*/
@Slf4j
@Service
public class FavoriteServiceImpl implements FavoriteService {
@Resource
private FavoriteDAO favoriteDAO;
@Override
public Long addFavorite(FavoriteCreateRequest request) {
// 转换
FavoriteDO record = FavoriteConvert.MAPPER.to(request);
record.setId(null);
// 插入
int effect = favoriteDAO.insert(record);
log.info("FavoriteService-addFavorite effect: {}, record: {}", effect, JSON.toJSONString(record));
return record.getId();
}
@Override
public List<FavoriteVO> getFavoriteList(FavoriteQueryRequest request) {
// 条件
LambdaQueryWrapper<FavoriteDO> wrapper = this.buildQueryWrapper(request);
// 查询
return favoriteDAO.of()
.wrapper(wrapper)
.list(FavoriteConvert.MAPPER::to);
}
@Override
public List<Long> getFavoriteRelIdList(FavoriteQueryRequest request) {
// 条件
LambdaQueryWrapper<FavoriteDO> wrapper = this.buildQueryWrapper(request);
// 查询
return favoriteDAO.of()
.wrapper(wrapper)
.stream()
.map(FavoriteDO::getRelId)
.distinct()
.collect(Collectors.toList());
}
@Override
public Integer deleteFavorite(FavoriteQueryRequest request) {
// 条件
LambdaQueryWrapper<FavoriteDO> wrapper = this.buildQueryWrapper(request);
// 删除
return favoriteDAO.delete(wrapper);
}
/**
* 构建查询 wrapper
*
* @param request request
* @return wrapper
*/
private LambdaQueryWrapper<FavoriteDO> buildQueryWrapper(FavoriteQueryRequest request) {
return favoriteDAO.wrapper()
.eq(FavoriteDO::getId, request.getId())
.eq(FavoriteDO::getUserId, request.getUserId())
.eq(FavoriteDO::getRelId, request.getRelId())
.eq(FavoriteDO::getType, request.getType())
.in(FavoriteDO::getUserId, request.getUserIdList())
.in(FavoriteDO::getRelId, request.getRelIdList());
}
}

View File

@@ -101,8 +101,8 @@ public class SystemUserRoleServiceImpl implements SystemUserRoleService {
return effect;
}
@Async("asyncExecutor")
@Override
@Async("asyncExecutor")
public void asyncDeleteUserCacheRole(String roleCode, List<Long> userIdList) {
for (Long userId : userIdList) {
RedisUtils.<LoginUser>processSetJson(UserCacheKeyDefine.USER_INFO, s -> {

View File

@@ -181,14 +181,14 @@ public class SystemUserServiceImpl implements SystemUserService {
redisTemplate.delete(UserCacheKeyDefine.LOGIN_FAILED_COUNT.format(record.getUsername()));
// 删除登陆缓存
String loginKey = UserCacheKeyDefine.LOGIN_TOKEN.format(id, "*");
Set<String> loginKeyList = RedisUtils.scanKeys(loginKey, 100);
Set<String> loginKeyList = RedisUtils.scanKeys(loginKey);
if (!loginKeyList.isEmpty()) {
redisTemplate.delete(loginKeyList);
}
// 删除续签信息
if (AuthenticationService.allowRefresh) {
String refreshKey = UserCacheKeyDefine.LOGIN_REFRESH.format(id, "*");
Set<String> refreshKeyList = RedisUtils.scanKeys(refreshKey, 100);
Set<String> refreshKeyList = RedisUtils.scanKeys(refreshKey);
if (!refreshKeyList.isEmpty()) {
redisTemplate.delete(refreshKeyList);
}

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.orion.ops.module.infra.dao.FavoriteDAO">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.orion.ops.module.infra.entity.domain.FavoriteDO">
<id column="id" property="id"/>
<result column="create_time" property="createTime"/>
<result column="update_time" property="updateTime"/>
<result column="creator" property="creator"/>
<result column="updater" property="updater"/>
<result column="deleted" property="deleted"/>
<result column="user_id" property="userId"/>
<result column="rel_id" property="relId"/>
<result column="type" property="type"/>
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, user_id, rel_id, type, create_time, update_time, creator, updater, deleted
</sql>
</mapper>