Spring Boot项目学习14之帖子收藏模块

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>
                            收藏&nbsp;&nbsp;(<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>
                            取消收藏&nbsp;&nbsp;(<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>
                            取消收藏&nbsp;&nbsp;(<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 测试效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

项目源码地址下载:源码下载

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
【资源说明】 1、基于Spring Boot的社区论坛项目源码+数据库+项目说明.zip 2、该资源包括项目的全部源码,下载可以直接使用! 3、本项目适合作为计算机、数学、电子信息等专业的课程设计、期末大作业和毕设项目,作为参考资料学习借鉴。 4、本资源作为“参考资料”如果需要实现其他功能,需要能看懂代码,并且热爱钻研,自行调试。 基于Spring Boot的社区论坛项目源码+数据库+项目说明.zip # WeCommunity > 微博、微信、微X......各种微,我们也跟上潮流叫微社区,英文名是 WeCommunity!是不是和微信(WeChat)很像? 微社区是一个用户交流平台,类似论坛,提供有:帖子管理、评论、关注、点赞、搜索、私信、数据统计等功能项目目前部署在阿里云1核2G云服务器上,所有的组件都是单机模式运行。 ### 依葫芦画瓢的项目架构图 ![项目架构设计图](https://i.loli.net/2020/07/01/umXATrRW2PCLhEI.png "项目架构设计图") ### 功能描述 1. 用户管理   用户可以注册、登陆、退出,修改头像,查看某个用户的主页,其包括某个用户的关注、粉丝、获得的点赞数、发布的帖子,用户自己能查看自己发表的评论。 2. 帖子管理   普通用户可以发布帖子、修改帖子,管理员可以删除帖子、恢复删除的帖子,版主可以将帖子置顶/取消置顶、加精华/取消加精华。 3. 关注   用户可以关注/取消关注某个用户,假如A关注了B,那么A的关注列表中就有了B,B的粉丝列表中就有了A。 4. 评论   用户可以对帖子进行评论,还可以对评论进行回复。 5. 点赞   用户可以对帖子、评论进行点赞。 6. 系统通知   某个用户评论、点赞了帖子,或者关注了某个用户,那么被评论、点赞、关注的用户会收到一条通知。目前系统中有3种通知:评论通知、点赞通知、被关注通知。 7. 数据统计   管理员可以查看网站指定日期范围的UV(独立访客)、DAU(日活跃用户)数据。 8. 私信   用户可以对网站内的其他用户发送私信,双方互发消息,只有他们自己能看到自己的私信。 9. 定时调度   每个帖子都有个权重分,影响帖子的展示排名,定时调度主要是定时更新帖子的权重。 10. 搜索   搜索系统使用Elasticsearch实现,支持对帖子标题、帖子内容的搜索。 ### 技术选型 - Spring Boot - SpringMVC - Spring - MyBatis3、通用mapper - Spring Security:安全框架 - Redis:缓存及数据存储 - Kafka:消息队列 - Elasticsearch-6.3.0:分布式搜索引擎 - Quartz:定时调度框架 - Nginx - Thymeleaf:模板引擎 - Caffeine:Java本地缓存库 - MySQL - 七牛云:第三方文件存储服务 ### 各个功能模块所对应的技术点 ![功能模块对应的技术点](https://i.loli.net/2020/07/01/u3DRnvrxfUNKhtc.jpg) ### 界面设计 ![主页](https://i.loli.net/2020/07/01/VbQYPd9wvWzxjy8.jpg "主页") ![帖子发布](https://i.loli.net/2020/07/01/ANeDU75GaMB36ZT.jpg "帖子发布") ![私信列表_私信详情](https://i.loli.net/2020/07/01/p6HQtoPlJXNGdwz.jpg "私信列表_私信详情") ![系统通知_](https://i.loli.net/2020/07/01/mbvtnlCgZyYWqLS.jpg "系统通知_") ### 文件说明 - wecommunity.sql:数据库文件 - wecommunity文件夹:Maven 项目源码 - static文件夹:前端静态资源,需独立部署 ### 本地开发运行部署 - 下载zip直接解压或安装git后执行克隆命令 `git clone https://github.com/AatroxC/WeCommunity.git` - 安装各组件并启动:Redis、ZooKee
当前课程中商城项目的实战源码是我发布在 GitHub 上的开源项目 newbee-mall (新蜂商城),目前已有 9900 多个 Star,本课程是一个 Spring Boot 技术栈的实战类课程,课程共分为 3 大部分,前面两个部分为基础环境准备和相关概念介绍,第三个部分是 Spring Boot 商城项目功能的讲解,让大家实际操作并实践上手一个大型的线上商城项目,并学习到一定的开发经验以及其中的开发技巧。商城项目所涉及的功能结构图整理如下: 作者寄语本课程录制于2019年,距今已有一段时间。期间,Spring Boot技术栈也有一些版本升级,比如Spring Boot 2.7.x发版、Spring Boot 3.x版本正式版本。对于这些情况,笔者会在本课程实战项目的开源仓库中创建不同的代码分支,保持实战项目的源码更新,保证读者朋友们不会学习过气的知识点。新蜂商城的优化和迭代工作不会停止,不仅仅是功能的优化,在技术栈上也会不断的增加,截止2023年,新蜂商城已经发布了 7 个重要的版本,版本记录及开发计划如下图所示。 课程特色 对新手开发者十分友好,无需复杂的操作步骤,仅需 2 秒就可以启动这个完整的商城项目最终的实战项目是一个企业级别的 Spring Boot 大型项目,对于各个阶段的 Java 开发者都是极佳的选择实践项目页面美观且实用,交互效果完美教程详细开发教程详细完整、文档资源齐全代码+讲解+演示网站全方位保证,向 Hello World 教程说拜拜技术栈新颖且知识点丰富,学习后可以提升大家对于知识的理解和掌握,可以进一步提升你的市场竞争力 课程预览 以下为商城项目的页面和功能展示,分别为:商城首页 1商城首页 2购物车订单结算订单列表支付页面后台管理系统登录页商品管理商品编辑
对于学习 Spring Boot项目学习路线,可以按照以下步骤进行: 1. 第一阶段:了解基础知识和概念。在此阶段,你可以开始学习 Spring Boot 的基础知识和核心概念,包括 Spring Framework、Spring Boot 的特点和优势等。可以参考中提供的学习路线,掌握基础知识和概念是深入学习 Spring Boot 的基础。 2. 第二阶段:学习 Spring Boot Starter。Spring Boot Starter 是 Spring Boot 的一个重要特性,它提供了一种快速集成常用框架和库的方式。在此阶段,你可以学习如何使用已有的 Starter,例如 Spring Data JPA、Thymeleaf 等,来快速集成这些常用框架和库。这将有助于你在实际项目中更快地构建应用程序。可以参考中提供的学习内容,深入理解 Spring Boot Starter 的概念和作用。 3. 第三阶段:深入学习 Spring Boot 特性和功能。在这个阶段,你可以进一步深入学习 Spring Boot 的各种特性和功能,例如自动配置、Actuator、Spring Boot DevTools、Spring Security 等。通过学习和实践,你将能够更好地理解和应用这些功能,进一步提升你的开发能力。可以参考中提供的学习路线,逐步掌握 Spring Boot 的核心概念和功能。 通过以上学习路线,你可以系统地学习和掌握 Spring Boot 的核心概念和功能。随着实践项目的进行和不断学习,你将能够应对更复杂的需求和场景,深入理解和运用 Spring Boot 的各种特性和功能。希望这个学习路线对你的学习有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

picacho_pkq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值