1.点赞收藏功能设计
1.示意图
2.描述
1.使用redis记录的数据
- **hash类型:**hashkey:subjectId:userId,hashval:存的是点赞的状态 1 是点赞 0 是不点赞。
- **string 类型:**key subjectId,val:我们的题目被点赞的数量
- **string 类型:**key subjectId.userId,val:"1"记录题目被谁点过赞
2.数据库的设计
create table subject_liked
(
id bigint auto_increment comment '主键'
primary key,
subject_id bigint null comment '题目id',
like_user_id varchar(32) null comment '点赞人id',
status int null comment '点赞状态 1点赞 0不点赞',
created_by varchar(32) charset utf8 null comment '创建人',
created_time datetime null comment '创建时间',
update_by varchar(32) charset utf8 null comment '修改人',
update_time datetime null comment '修改时间',
is_deleted int default 0 null,
constraint uniq_like
unique (subject_id, like_user_id) comment '点赞唯一索引'
)
comment '题目点赞表' collate = utf8mb4_bin;
3.功能设计
1.新增点赞
直接操作 redis,存 hash,存数量,存点赞的人与题目的 key
2.取消点赞
上面的反逻辑,数量会-1,hash 里面的状态会更新,点赞人与题目关联的 key 会被删除
3.查询当前题目被点赞的数量
直接与 redis 交互,读题目的被点赞数量的 key
4.查询当前题目被当前用户是否点过赞
直接查 redis 就可以了
5.我的点赞
直接查数据库做分页逻辑的展示
2.代码生成器的使用
1.找到代码生成器在磁盘的位置,直接复制到项目下
2.导入模块
1.打开项目结构,选择导入模块
2.从已存在的资源中导入
3.一直下一步即可
4.导入成功
5.右击pom.xml将其作为maven项目
6.发现刷新maven无法找到这个starter
7.将jc-club-common-starter模块也导入进来
3.gen.yml 进行配置
1.替换数据库连接信息及对应表
# 数据库连接信息
jdbc:
dbName: sun_club
tableName: subject_liked
url:
username:
password:
driver: com.mysql.cj.jdbc.Driver
2.使用的模板与生成文件映射给关系
mapperInfos: genCode/subjectLikedMapper.yml
3.全局参数
# 全局参数
params:
# 作者
author: sun
# 模块
module: subject
# controller 通用前缀
api: /subjectLiked
# 生成对象是否移除前缀
removePre: false
# 使用内置函数赋值给变量 FunctionUtils 中替换
genDate: now()
# win 需要补充模板具体目录
templateBasePath: D:/Intelij_IDEA_Project/sun-club/code-generate/src/main/resources/
3.点赞功能基本开发
1.sun-club-application-controller
1.SubjectLikedController.java 接受点赞题目id和点赞状态
/**
* 新增点赞
* @param subjectLikedDTO 点赞题目id、点赞状态0/1
* @return
*/
@RequestMapping("add")
public Result<Boolean> add(@RequestBody SubjectLikedDTO subjectLikedDTO) {
try {
if (log.isInfoEnabled()) {
log.info("SubjectLikedController.add.dto:{}", JSON.toJSONString(subjectLikedDTO));
}
Preconditions.checkNotNull(subjectLikedDTO.getSubjectId(), "题目id不能为空");
Preconditions.checkNotNull(subjectLikedDTO.getStatus(), "点赞状态不能为空");
// 获取点赞人的id
String loginId = LoginUtil.getLoginId();
subjectLikedDTO.setLikeUserId(loginId);
Preconditions.checkNotNull(subjectLikedDTO.getLikeUserId(), "点赞人不能为空");
SubjectLikedBO SubjectLikedBO = SubjectLikedDTOConverter.INSTANCE.convertDTOToBO(subjectLikedDTO);
subjectLikedDomainService.add(SubjectLikedBO);
return Result.ok(true);
} catch (Exception e) {
log.error("SubjectLikedController.register.error:{}", e.getMessage(), e);
return Result.fail("新增题目点赞表失败");
}
}
2.sun-club-common
1.SubjectLikedStatusEnum.java 题目点赞状态枚举
package com.sunxiansheng.subject.common.enums;
import lombok.Getter;
/**
* Description: 题目点赞枚举
* @Author sun
* @Create 2024/5/24 9:53
* @Version 1.0
*/
@Getter
public enum SubjectLikedStatusEnum {
LIKED(1, "点赞"),
UN_LIKED(0, "取消点赞"),
;
public int code;
public String desc;
SubjectLikedStatusEnum(int code, String desc) {
this.code = code;
this.desc = desc;
}
/**
* 根据code获取枚举
* @param code
* @return
*/
public static SubjectLikedStatusEnum getByCode(int code) {
for (SubjectLikedStatusEnum value : values()) {
if (value.code == code) {
return value;
}
}
return null;
}
}
3.sun-club-domain
1.SubjectLikedDomainService.java
/**
* 添加 题目点赞表 信息
*/
void add(SubjectLikedBO subjectLikedBO);
2.SubjectLikedDomainServiceImpl.java
/*
与redis交互
*/
@Resource
private RedisUtil redisUtil;
/*
点赞 hash结构:大key
*/
public static final String SUBJECT_LIKE_KEY = "subject.liked";
/*
题目点赞计数 string结构:key
*/
public static final String SUBJECT_LIKE_COUNT_KEY = "subject.liked.count";
/*
题目被谁点过赞 string结构:key
*/
public static final String SUBJECT_LIKE_DETAIL_KEY = "subject.liked.detail";
/**
* 构建新增点赞时redis中的hashKey(小key)
* @param subjectId
* @param userId
* @return
*/
private String buildSubjectLikedKey(String subjectId, String userId) {
return subjectId + ":" + userId;
}
@Override
public void add(SubjectLikedBO subjectLikedBO) {
// 获取信息
Long subjectId = subjectLikedBO.getSubjectId();
String likeUserId = subjectLikedBO.getLikeUserId();
Integer status = subjectLikedBO.getStatus();
// 构建hashKey
String hashKey = buildSubjectLikedKey(String.valueOf(subjectId), likeUserId);
// 存储点赞信息
redisUtil.putHash(SUBJECT_LIKE_KEY, hashKey, status);
// 题目点赞计数
String countKey = SUBJECT_LIKE_COUNT_KEY + "." + subjectId;
// 题目被谁点过赞
String detailKey = SUBJECT_LIKE_DETAIL_KEY + "." + subjectId + "." + likeUserId;
// 如果是点赞,则增加一
if (SubjectLikedStatusEnum.LIKED.getCode() == status) {
// 记录该题目被谁点过赞
redisUtil.set(detailKey, "1");
redisUtil.increment(countKey, 1);
} else {
// 如果说是取消点赞,则要判断是否已经是0了
Integer count = redisUtil.getInt(countKey);
// 如果是0,就直接返回,不是0则减一
if (Objects.isNull(count) || count <= 0) {
return;
}
redisUtil.increment(countKey, -1);
// 取消点赞,也要删除点赞细节
redisUtil.del(detailKey);
}
}
3.RedisUtil.java 新增hash结构api
/**
* 向Redis中的hash结构存储数据
* @param key 一个hash结构的key
* @param hashKey hash中的小key
* @param hashVal hash中的小value
*/
public void putHash(String key, String hashKey, Object hashVal) {
redisTemplate.opsForHash().put(key, hashKey, hashVal);
}
/**
* Redis中的String类型,获取value时将其转换为int类型
* @param key
* @return
*/
public Integer getInt(String key) {
return (Integer) redisTemplate.opsForValue().get(key);
}
/**
* Redis中的String类型,将value增加一
* @param key
* @param count
* @return
*/
public void increment(String key, Integer count) {
redisTemplate.opsForValue().increment(key, count);
}
4.测试
1.点赞
2.Redis
3.题目详情增加点赞数据
1.sun-club-application-controller
1.SubjectInfoDTO.java 新增字段
/**
* 是否被当前用户点赞
*/
private Boolean liked;
/**
* 当前题目点赞的数量
*/
private Integer likedCount;
2.sun-club-domain
1.SubjectInfoBO.java 新增字段
/**
* 是否被当前用户点赞
*/
private Boolean liked;
/**
* 当前题目点赞的数量
*/
private Integer likedCount;
2.SubjectLikedDomainService.java
/**
* 获取当前是否被点赞过
*/
Boolean isLiked(String subjectId, String userId);
/**
* 获取点赞数量
*/
Integer getLikedCount(Long subjectId);
3.SubjectLikedDomainServiceImpl.java
@Override
public Boolean isLiked(String subjectId, String userId) {
String detailKey = SUBJECT_LIKE_DETAIL_KEY + "." + subjectId + "." + userId;
// 如果存在这个key,就说明该题目被这个用户点过赞了
return redisUtil.exist(detailKey);
}
@Override
public Integer getLikedCount(Long subjectId) {
String countKey = SUBJECT_LIKE_COUNT_KEY + "." + subjectId;
Integer count = redisUtil.getInt(countKey);
// 如果为空或0,直接返回0
if (Objects.isNull(count) || count <= 0) {
return 0;
}
return count;
}
4.SubjectInfoDomainServiceImpl.java 在查询题目信息时查询点赞信息
// ========== redis查询点赞信息 ==========
bo.setLiked(subjectLikedDomainService.isLiked(String.valueOf(subjectInfoBO.getId()), LoginUtil.getLoginId()));
bo.setLikedCount(subjectLikedDomainService.getLikedCount(subjectInfoBO.getId()));
// ========== redis查询点赞信息 ==========