Web的点赞功能和收藏功能的设计思路
文章目录
- 点赞功能的设计
- 实体类
- 数据库设计
- 整体流程
- 业务逻辑处理
- 收藏功能的设计
- 实体类
- 数据库设计
- 整体流程
- 业务逻辑处理
点赞功能的设计
实体类
package com.example.entity;
/*
点赞实体类
*/
public class Likes {
private Integer id;
/**
* 关联id
*/
private Integer fid;
/**
* 点赞人id
*/
private Integer userId;
/**
* 模块
*/
private String module;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getFid() {
return fid;
}
public void setFid(Integer fid) {
this.fid = fid;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getModule() {
return module;
}
public void setModule(String module) {
this.module = module;
}
}
数据库设计
我们首先设计一个点赞表
CREATE TABLE `likes` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`fid` int(11) DEFAULT NULL COMMENT '关联ID',
`user_id` int(11) DEFAULT NULL COMMENT '点赞人ID',
`module` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '模块',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='点赞';
我解释一下,我为什么这么设计这个数据表
fid: 这是一个外键,用于关联被点赞的对象。在不同的场景下,它可能代表不同的实体ID。例如,如果点赞的对象是博客文章,fid就存储博客文章的ID;如果是活动,就存储活动的ID。DEFAULT NULL表示这个字段可以为空,这在某些情况下可能是必要的,比如在实现“未明确点赞特定对象”的点赞时。
user_id: 表示执行点赞操作的用户ID。这个字段用于记录是谁进行了点赞操作。它也是一个外键,关联到用户表。
module: 这是一个字符串字段,用于指定点赞发生的模块或上下文。例如,它可以是’post’表示博客文章,’event’表示活动,或者其他任何您系统中可能的点赞对象类型。这增加了表的灵活性,使其不仅限于一种类型的实体。
整体流程
我先说一下整体流程:
用户发起点赞请求,Controller 接收请求并传递给 Service,Service 根据当前用户信息和点赞对象信息判断是点赞还是取消点赞,然后通过 Mapper 层操作数据库实现相应的功能。
业务逻辑处理
Controller
接收前端的HTTP请求,调用服务层的方法,并返回响应结果。
@RestController
@RequestMapping("/likes")
public class LikesController {
@Resource
LikesService likesService;
// 点赞和取消
@PostMapping("/set")
public Result set(@RequestBody Likes likes) {
likesService.set(likes);
return Result.success();
}
}
Service
点赞功能的业务逻辑。
@Service
public class LikesService {
@Resource
LikesMapper likesMapper;
public void set(Likes likes) {
Account currentUser = TokenUtils.getCurrentUser();
likes.setUserId(currentUser.getId());
Likes dblLikes = likesMapper.selectUserLikes(likes);
if (dblLikes == null) {
likesMapper.insert(likes);
} else {
likesMapper.deleteById(dblLikes.getId());
}
}
/**
* 查询当前用户是否点过赞
*/
public Likes selectUserLikes(Integer fid, String module) {
Account currentUser = TokenUtils.getCurrentUser();
Likes likes = new Likes();
likes.setUserId(currentUser.getId());
likes.setFid(fid);
likes.setModule(module);
return likesMapper.selectUserLikes(likes);
}
public int selectByFidAndModule(Integer fid, String module) {
return likesMapper.selectByFidAndModule(fid, module);
}
}
获取当前用户
首先,通过TokenUtils.getCurrentUser()方法获取当前登录的用户信息。这是通过解析用户的认证令牌(通常是JWT或其他形式的token)来实现的,确保了只有认证用户能进行点赞操作。设置用户ID
将当前用户的ID设置到Likes对象中。这是为了确保点赞信息与特定用户相关联,即知道是哪个用户进行了点赞或取消点赞操作。查询已存在的点赞记录
通过调用likesMapper.selectUserLikes(likes),查询数据库中是否已存在相同的点赞记录。这个查询基于传入的Likes对象,特别是依据用户ID、功能ID (fid) 和模块(module)。查询结果dblLikes将决定接下来的操作步骤。处理点赞或取消点赞
根据查询结果,业务逻辑分为两种情况:
如果dblLikes为空:表示当前用户尚未对该fid和module点赞。因此,执行likesMapper.insert(likes),在数据库中插入一条新的点赞记录。这代表用户现在对该项目点赞。
如果dblLikes不为空:表示已存在点赞记录,用户此次操作意在取消点赞。因此,执行likesMapper.deleteById(dblLikes.getId()),根据点赞记录的ID从数据库中删除这条记录。这代表用户取消了对该项目的点赞。
通过上述步骤,set方法有效地管理了点赞状态的切换,即从未点赞到点赞,或从已点赞到取消点赞。这种设计既简洁又高效,能够确保每个用户对每个fid和module的点赞状态唯一,且在用户决定改变心意时可以轻松地进行状态切换。
mapper
public interface LikesMapper {
void insert(Likes likes);
Likes selectUserLikes(Likes likes);
void deleteById(Integer id);
int selectByFidAndModule(@Param("fid") Integer fid, @Param("module") String module);
}
xml文件
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.LikesMapper">
<insert id="insert">
insert into likes (fid, user_id, module) values (#{fid}, #{userId}, #{module})
</insert>
<delete id="deleteById">
delete from likes where id = #{id}
</delete>
<select id="selectUserLikes" resultType="com.example.entity.Likes">
select * from likes where fid = #{fid} and user_id = #{userId} and module = #{module}
</select>
<select id="selectByFidAndModule" resultType="java.lang.Integer">
select count(*) from likes where fid = #{fid} and module = #{module}
</select>
</mapper>
收藏功能的设计
收藏功能跟点赞功能一样的思路。
实体类
package com.example.entity;
/*
点赞实体类
*/
public class Collect {
private Integer id;
private Integer fid;
private Integer userId;
private String module;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getFid() {
return fid;
}
public void setFid(Integer fid) {
this.fid = fid;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getModule() {
return module;
}
public void setModule(String module) {
this.module = module;
}
}
数据库设计
CREATE TABLE `collect` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`fid` int(11) DEFAULT NULL COMMENT '关联ID',
`user_id` int(11) DEFAULT NULL COMMENT '点赞人ID',
`module` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '模块',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='收藏';
整体流程
用户发起收藏请求,Controller 接收请求并传递给 Service,Service 根据当前用户信息和收藏对象信息判断是收藏还是取消收藏,然后通过 Mapper 层操作数据库实现相应的功能。
业务逻辑处理
controller
@RestController
@RequestMapping("/collect")
public class CollectController {
@Resource
CollectService collectService;
// 收藏和取消
@PostMapping("/set")
public Result set(@RequestBody Collect collect) {
collectService.set(collect);
return Result.success();
}
}
service
@Service
public class CollectService {
@Resource
CollectMapper collectMapper;
public void set(Collect collect) {
Account currentUser = TokenUtils.getCurrentUser();
collect.setUserId(currentUser.getId());
Collect dblCollect = collectMapper.selectUserCollect(collect);
if (dblCollect == null) {
collectMapper.insert(collect);
} else {
collectMapper.deleteById(dblCollect.getId());
}
}
/**
* 查询当前用户是否收藏过
*/
public Collect selectUserCollect(Integer fid, String module) {
Account currentUser = TokenUtils.getCurrentUser();
Collect collect = new Collect();
collect.setUserId(currentUser.getId());
collect.setFid(fid);
collect.setModule(module);
return collectMapper.selectUserCollect(collect);
}
public int selectByFidAndModule(Integer fid, String module) {
return collectMapper.selectByFidAndModule(fid, module);
}
}
mapper
public interface CollectMapper {
void insert(Collect collect);
Collect selectUserCollect(Collect collect);
void deleteById(Integer id);
int selectByFidAndModule(@Param("fid") Integer fid, @Param("module") String module);
}
xml文件
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.CollectMapper">
<insert id="insert">
insert into collect (fid, user_id, module) values (#{fid}, #{userId}, #{module})
</insert>
<delete id="deleteById">
delete from collect where id = #{id}
</delete>
<select id="selectUserCollect" resultType="com.example.entity.Collect">
select * from collect where fid = #{fid} and user_id = #{userId} and module = #{module}
</select>
<select id="selectByFidAndModule" resultType="java.lang.Integer">
select count(*) from collect where fid = #{fid} and module = #{module}
</select>
</mapper>