1.收藏表的设计
收藏表最主要包含有以下几个字段:
- 主键id
- 收藏帖子的主键
- 收藏者的id
- 收藏时间
DROP TABLE IF EXISTS `tb_post_collect_record`;
CREATE TABLE `tb_post_collect_record` (
`record_id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键id',
`post_id` bigint NOT NULL DEFAULT '0' COMMENT '收藏帖子主键',
`user_id` bigint NOT NULL DEFAULT '0' COMMENT '收藏者id',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '收藏时间',
PRIMARY KEY (`record_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
2. 实现收藏模块
2.1 收藏实体类
BBSPostCollect
public class BBSPostCollect {
private Long recordId;
private Long postId;
private Long userId;
private Date createTime;
public Long getRecordId() {
return recordId;
}
public void setRecordId(Long recordId) {
this.recordId = recordId;
}
public Long getPostId() {
return postId;
}
public void setPostId(Long postId) {
this.postId = postId;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getClass().getSimpleName());
sb.append(" [");
sb.append("Hash = ").append(hashCode());
sb.append(", recordId=").append(recordId);
sb.append(", postId=").append(postId);
sb.append(", userId=").append(userId);
sb.append(", createTime=").append(createTime);
sb.append("]");
return sb.toString();
}
}
2.2 收藏模块展示
在BBSPostController控制类的postDetail()方法中添加收藏帖子功能。
// todo 是否收藏了本贴
BBSUser currentUser = (BBSUser) request.getSession().getAttribute(Constants.USER_SESSION_KEY);
request.setAttribute("currentUserCollectFlag", bbsPostCollectService.validUserCollect(currentUser.getUserId(), postId));
BBSPostCollectService
public interface BBSPostCollectService {
/**
* 验证用户是否收藏了帖子
*
* @param userId
* @param postId
* @return
*/
Boolean validUserCollect(Long userId, Long postId);
}
@Service
public class BBSPostCollectServiceImpl implements BBSPostCollectService {
@Autowired
private BBSPostCollectMapper bbsPostCollectMapper;
@Autowired
private BBSPostMapper bbsPostMapper;
@Autowired
private BBSUserMapper bbsUserMapper;
@Override
public Boolean validUserCollect(Long userId, Long postId) {
BBSPostCollect bbsPostCollect = bbsPostCollectMapper.selectByUserIdAndPostId(userId, postId);
if (bbsPostCollect == null) {
return false;
}
return true;
}
}
BBSPostCollectMapper
public interface BBSPostCollectMapper {
BBSPostCollect selectByUserIdAndPostId(@Param("userId") Long userId, @Param("postId") Long postId);
}
<?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="top.picacho.bbs.dao.BBSPostCollectMapper">
<resultMap id="BaseResultMap" type="top.picacho.bbs.entity.BBSPostCollect">
<id column="record_id" jdbcType="BIGINT" property="recordId" />
<result column="post_id" jdbcType="BIGINT" property="postId" />
<result column="user_id" jdbcType="BIGINT" property="userId" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
</resultMap>
<sql id="Base_Column_List">
record_id, post_id, user_id, create_time
</sql>
<select id="selectByUserIdAndPostId" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from tb_post_collect_record
where post_id = #{postId,jdbcType=BIGINT} and user_id = #{userId,jdbcType=BIGINT} limit 1
</select>
</mapper>
2.3 前端页面
<div style="text-align: center;">
<th:block th:unless="${currentUserCollectFlag}">
<a href="##" th:onclick="'collect('+${bbsPost.postId}+')'">
<span style="color: red;">
<i class="iconfont icon-zan"></i>
收藏 (<th:block th:text="${bbsPost.postCollects}"></th:block>)
</span>
</a>
</th:block>
<th:block th:if="${currentUserCollectFlag}">
<a href="##" th:onclick="'delCollect('+${bbsPost.postId}+')'">
<span style="color: grey;">
<i class="iconfont icon-zan"></i>
取消收藏 (<th:block th:text="${bbsPost.postCollects}"></th:block>)
</span>
</a>
</th:block>
</div>
2.4 测试效果
2.5 添加收藏的接口
BBSPostCollectController
@Controller
public class BBSPostCollectController {
@Resource
private BBSPostCollectService bbsPostCollectService;
@PostMapping("/addCollect/{postId}")
@ResponseBody
public Result addCollect(@PathVariable("postId") Long postId,
HttpSession httpSession) {
if (null == postId || postId < 0) {
return ResultGenerator.genFailResult("postId参数错误");
}
BBSUser bbsUser = (BBSUser) httpSession.getAttribute(Constants.USER_SESSION_KEY);
if (bbsPostCollectService.addCollectRecord(bbsUser.getUserId(), postId)) {
return ResultGenerator.genSuccessResult();
} else {
return ResultGenerator.genFailResult("请求失败,请检查参数及账号是否有操作权限");
}
}
}
BBSPostCollectService
public interface BBSPostCollectService {
/**
* 收藏帖子
*
* @param userId
* @param postId
* @return
*/
Boolean addCollectRecord(Long userId, Long postId);
}
@Service
public class BBSPostCollectServiceImpl implements BBSPostCollectService {
@Autowired
private BBSPostCollectMapper bbsPostCollectMapper;
@Autowired
private BBSPostMapper bbsPostMapper;
@Autowired
private BBSUserMapper bbsUserMapper;
@Override
@Transactional
public Boolean addCollectRecord(Long userId, Long postId) {
BBSPostCollect bbsPostCollect = bbsPostCollectMapper.selectByUserIdAndPostId(userId, postId);
BBSUser bbsUser = bbsUserMapper.selectByPrimaryKey(userId);
if (bbsUser == null || bbsUser.getUserStatus().intValue() == 1) {
//账号已被封禁
return false;
}
if (bbsPostCollect != null) {
return true;
} else {
bbsPostCollect = new BBSPostCollect();
bbsPostCollect.setPostId(postId);
bbsPostCollect.setUserId(userId);
//收藏数量加1
BBSPost bbsPost = bbsPostMapper.selectByPrimaryKey(postId);
bbsPost.setPostCollects(bbsPost.getPostCollects() + 1);
if (bbsPostCollectMapper.insertSelective(bbsPostCollect) > 0 && bbsPostMapper.updateByPrimaryKey(bbsPost) > 0) {
return true;
}
}
return false;
}
}
这里首先通过帖子id和用户id查询出收藏实体,如果存在说明已经已经收藏了直接返回;如果不存在说明没有收藏过,那么按正常的添加收藏实体,并且更新帖子的收藏数。
BBSPostCollectMapper
public interface BBSPostCollectMapper {
BBSPostCollect selectByUserIdAndPostId(@Param("userId") Long userId, @Param("postId") Long postId);
int insertSelective(BBSPostCollect record);
}
<?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="top.picacho.bbs.dao.BBSPostCollectMapper">
<resultMap id="BaseResultMap" type="top.picacho.bbs.entity.BBSPostCollect">
<id column="record_id" jdbcType="BIGINT" property="recordId" />
<result column="post_id" jdbcType="BIGINT" property="postId" />
<result column="user_id" jdbcType="BIGINT" property="userId" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
</resultMap>
<sql id="Base_Column_List">
record_id, post_id, user_id, create_time
</sql>
<select id="selectByUserIdAndPostId" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from tb_post_collect_record
where post_id = #{postId,jdbcType=BIGINT} and user_id = #{userId,jdbcType=BIGINT} limit 1
</select>
<insert id="insertSelective" parameterType="top.picacho.bbs.entity.BBSPostCollect">
insert into tb_post_collect_record
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="recordId != null">
record_id,
</if>
<if test="postId != null">
post_id,
</if>
<if test="userId != null">
user_id,
</if>
<if test="createTime != null">
create_time,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="recordId != null">
#{recordId,jdbcType=BIGINT},
</if>
<if test="postId != null">
#{postId,jdbcType=BIGINT},
</if>
<if test="userId != null">
#{userId,jdbcType=BIGINT},
</if>
<if test="createTime != null">
#{createTime,jdbcType=TIMESTAMP},
</if>
</trim>
</insert>
</mapper>
BBSPostMapper
int updateByPrimaryKey(BBSPost record);
<update id="updateByPrimaryKey" parameterType="top.picacho.bbs.entity.BBSPost">
update tb_bbs_post
set publish_user_id = #{publishUserId,jdbcType=BIGINT},
post_title = #{postTitle,jdbcType=VARCHAR},
post_category_id = #{postCategoryId,jdbcType=INTEGER},
post_category_name = #{postCategoryName,jdbcType=VARCHAR},
post_status = #{postStatus,jdbcType=TINYINT},
post_views = #{postViews,jdbcType=BIGINT},
post_comments = #{postComments,jdbcType=BIGINT},
post_collects = #{postCollects,jdbcType=BIGINT},
last_update_time = #{lastUpdateTime,jdbcType=TIMESTAMP},
create_time = #{createTime,jdbcType=TIMESTAMP}
where post_id = #{postId,jdbcType=BIGINT}
</update>
2.6 前端逻辑
在detail.html页面添加收藏板块。
//收藏
window.collect = function (postId) {
var $ = layui.$;
$.ajax({
type: 'POST',//方法类型
url: '/addCollect/' + postId,
success: function (result) {
if (result.resultCode == 200) {
layer.confirm('收藏成功!将刷新本页面...', {
icon: 3,
skin: 'layui-layer-molv',
title: '提示'
}, function (index) {
layer.close(index);
window.location.reload();
});
} else {
layer.msg(result.message);
}
;
},
error: function () {
layer.alert('操作失败!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
}
});
}
2.7 测试效果
2.8 取消收藏的接口
BBSPostCollectController
@PostMapping("/delCollect/{postId}")
@ResponseBody
public Result delCollect(@PathVariable("postId") Long postId,
HttpSession httpSession) {
if (null == postId || postId < 0) {
return ResultGenerator.genFailResult("postId参数错误");
}
BBSUser bbsUser = (BBSUser) httpSession.getAttribute(Constants.USER_SESSION_KEY);
if (bbsPostCollectService.deleteCollectRecord(bbsUser.getUserId(), postId)) {
return ResultGenerator.genSuccessResult();
} else {
return ResultGenerator.genFailResult("请求失败,请检查参数及账号是否有操作权限");
}
}
BBSPostCollectService
/**
* 取消收藏帖子
*
* @param userId
* @param postId
* @return
*/
Boolean deleteCollectRecord(Long userId, Long postId);
@Override
@Transactional
public Boolean deleteCollectRecord(Long userId, Long postId) {
BBSPostCollect bbsPostCollect = bbsPostCollectMapper.selectByUserIdAndPostId(userId, postId);
BBSUser bbsUser = bbsUserMapper.selectByPrimaryKey(userId);
if (bbsUser == null || bbsUser.getUserStatus().intValue() == 1) {
//账号已被封禁
return false;
}
if (bbsPostCollect == null) {
return true;
} else {
//收藏数量减1
BBSPost bbsPost = bbsPostMapper.selectByPrimaryKey(postId);
Long collectCount = bbsPost.getPostCollects() - 1;
if (collectCount >= 0) {
bbsPost.setPostCollects(collectCount);
}
if (bbsPostCollectMapper.deleteByPrimaryKey(bbsPostCollect.getRecordId()) > 0 && bbsPostMapper.updateByPrimaryKey(bbsPost) > 0) {
return true;
}
}
return false;
}
BBSPostCollectMapper
int deleteByPrimaryKey(Long recordId);
<delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
delete from tb_post_collect_record
where record_id = #{recordId,jdbcType=BIGINT}
</delete>
2.9 前端逻辑
<th:block th:if="${currentUserCollectFlag}">
<a href="##" th:onclick="'delCollect('+${bbsPost.postId}+')'">
<span style="color: grey;">
<i class="iconfont icon-zan"></i>
取消收藏 (<th:block th:text="${bbsPost.postCollects}"></th:block>)
</span>
</a>
</th:block>
//取消收藏
window.delCollect = function (postId) {
var $ = layui.$;
$.ajax({
type: 'POST',//方法类型
url: '/delCollect/' + postId,
success: function (result) {
if (result.resultCode == 200) {
layer.confirm('取消收藏成功!将刷新本页面...', {
icon: 3,
skin: 'layui-layer-molv',
title: '提示'
}, function (index) {
layer.close(index);
window.location.reload();
});
} else {
layer.msg(result.message);
}
;
},
error: function () {
layer.alert('操作失败!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
}
});
}
2.10 测试效果
项目源码地址下载:源码下载