【SpringBoot】论坛项目中如何进行实现发布文章,以及更新对应数据库的数据更新

前言

🌟🌟本期讲解关于websocket的相关知识介绍~~~

🌈感兴趣的小伙伴看一看小编主页:GGBondlctrl-CSDN博客

🔥 你的点赞就是小编不断更新的最大动力

🎆那么废话不多说直接开整吧~~

目录

📚️1.数据库设计

🚀1.1数据库

🚀1.2板块数据库SQL语句编写

1.2.1用户表更新数据

1.2.2板块表更新数据

1.2.3文章表发布数据

📚️2.Dao层的设计

📚️3.Service层的设计

🚀3.1用户service层

🚀3.2板块service层

🚀3.3文章service层

📚️4.Controller层的设计

📚️5.测试

📚️6.总结

📚️1.数据库设计

🚀1.1数据库

小编使用的是navicat,具体的数据库如下所示,由于发表文章设计三个数据库:

文章数据库,板块数据库,作者数据库(这里指的就是用户数据库)

文章数据库:

包含了文章id,文章属于那个板块,所以板块id,谁发表的就是用户id,以及文章题目,内容,以及点赞数,回复数,浏览量等等,可以看看表的英文解释;

用户数据库:

这里就包含了用户id(与文章里的对应),以及username,password,包含比较重要的一些用户数据;

板块数据库:

这里就是每个板块的信息,板块名字,板块内发布的文章的数量,先后顺序等等.....

🚀1.2板块数据库SQL语句编写

分析:

我们要发布一篇文章,那么发布文章后,对应发布文章的作者对应的发布数量要增加,以及文章属于那个板块,那么板块包含的数量也要增加,所以这里涉及到三个数据库的操作;

1.2.1用户表更新数据

这里很明显是动态更新,具体的SQL语句如下所示:

sql 复制代码
<update id="updateByPrimaryKeySelective" parameterType="com.example.forum.model.User">
    update t_user
    <set>
      <if test="username != null">
        username = #{username,jdbcType=VARCHAR},
      </if>
      <if test="password != null">
        password = #{password,jdbcType=VARCHAR},
      </if>
      <if test="nickname != null">
        nickname = #{nickname,jdbcType=VARCHAR},
      </if>
      <if test="phoneNum != null">
        phoneNum = #{phoneNum,jdbcType=VARCHAR},
      </if>
      <if test="email != null">
        email = #{email,jdbcType=VARCHAR},
      </if>
      <if test="gender != null">
        gender = #{gender,jdbcType=TINYINT},
      </if>
      <if test="salt != null">
        salt = #{salt,jdbcType=VARCHAR},
      </if>
      <if test="avatarUrl != null">
        avatarUrl = #{avatarUrl,jdbcType=VARCHAR},
      </if>
      <if test="articleCount != null">
        articleCount = #{articleCount,jdbcType=INTEGER},
      </if>
      <if test="isAdmin != null">
        isAdmin = #{isAdmin,jdbcType=TINYINT},
      </if>
      <if test="remark != null">
        remark = #{remark,jdbcType=VARCHAR},
      </if>
      <if test="state != null">
        state = #{state,jdbcType=TINYINT},
      </if>
      <if test="deleteState != null">
        deleteState = #{deleteState,jdbcType=TINYINT},
      </if>
      <if test="createTime != null">
        createTime = #{createTime,jdbcType=TIMESTAMP},
      </if>
      <if test="updateTime != null">
        updateTime = #{updateTime,jdbcType=TIMESTAMP},
      </if>
    </set>
    where id = #{id,jdbcType=BIGINT}
  </update>
1.2.2板块表更新数据

很明显这里肯定也是动态更新的过程:

sql 复制代码
 <update id="updateByPrimaryKeySelective" parameterType="com.example.forum.model.Board">
    update t_board
    <set>
      <if test="name != null">
        name = #{name,jdbcType=VARCHAR},
      </if>
      <if test="articleCount != null">
        articleCount = #{articleCount,jdbcType=INTEGER},
      </if>
      <if test="sort != null">
        sort = #{sort,jdbcType=INTEGER},
      </if>
      <if test="state != null">
        state = #{state,jdbcType=TINYINT},
      </if>
      <if test="deleteState != null">
        deleteState = #{deleteState,jdbcType=TINYINT},
      </if>
      <if test="createTime != null">
        createTime = #{createTime,jdbcType=TIMESTAMP},
      </if>
      <if test="updateTime != null">
        updateTime = #{updateTime,jdbcType=TIMESTAMP},
      </if>
    </set>
    where id = #{id,jdbcType=BIGINT}
  </update>
1.2.3文章表发布数据

这里发布,那么就是往数据库中插入数据:

sql 复制代码
<insert id="insertSelective" parameterType="com.example.forum.model.Article">
    insert into t_article
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="id != null">
        id,
      </if>
      <if test="boardId != null">
        boardId,
      </if>
      <if test="userId != null">
        userId,
      </if>
      <if test="title != null">
        title,
      </if>
      <if test="visitCount != null">
        visitCount,
      </if>
      <if test="replyCount != null">
        replyCount,
      </if>
      <if test="likeCount != null">
        likeCount,
      </if>
      <if test="state != null">
        state,
      </if>
      <if test="deleteState != null">
        deleteState,
      </if>
      <if test="createTime != null">
        createTime,
      </if>
      <if test="updateTime != null">
        updateTime,
      </if>
      <if test="content != null">
        content,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="id != null">
        #{id,jdbcType=BIGINT},
      </if>
      <if test="boardId != null">
        #{boardId,jdbcType=BIGINT},
      </if>
      <if test="userId != null">
        #{userId,jdbcType=BIGINT},
      </if>
      <if test="title != null">
        #{title,jdbcType=VARCHAR},
      </if>
      <if test="visitCount != null">
        #{visitCount,jdbcType=INTEGER},
      </if>
      <if test="replyCount != null">
        #{replyCount,jdbcType=INTEGER},
      </if>
      <if test="likeCount != null">
        #{likeCount,jdbcType=INTEGER},
      </if>
      <if test="state != null">
        #{state,jdbcType=TINYINT},
      </if>
      <if test="deleteState != null">
        #{deleteState,jdbcType=TINYINT},
      </if>
      <if test="createTime != null">
        #{createTime,jdbcType=TIMESTAMP},
      </if>
      <if test="updateTime != null">
        #{updateTime,jdbcType=TIMESTAMP},
      </if>
      <if test="content != null">
        #{content,jdbcType=LONGVARCHAR},
      </if>
    </trim>
  </insert>

📚️2.Dao层的设计

这里很简单就是设计接口与数据库进行连接,种类小编将三种接口的设计一起写入到下方:

java 复制代码
//板块数据的动态更新
int updateByPrimaryKeySelective(Board record);

//用户数据的动态更新
 int updateByPrimaryKeySelective(User record);

//文章的发布(插入)
int insertSelective(Article record);

注意:每个方法的名字要和上述SQL在xml中的id要保持一致,不然会出现无法找到我们所需要的SQL语句来操作数据库;

📚️3.Service层的设计

🚀3.1用户service层

这里先规定service接口,在使用实现类进行实现

java 复制代码
  /**
     * 用户发布帖子后进行帖子数量的增加
     * @param id
     */
    void addOneArticleCountById(Long id);

对应的实现类的代码如下所示:

java 复制代码
@Override
    public void addOneArticleCountById(Long id) {
        //校验参数
        if(id == null || id <= 0){
            log.warn(ResultCode.FAILED_BOARD_ARTICLE_COUNT.toString());
            throw new ApplicationException(AppResult.fail(ResultCode.FAILED_BOARD_ARTICLE_COUNT));
        }

        //进行获取对象
        User user = userMapper.selectByPrimaryKey(id);

        //校验这里的对象是否存在
        if(user == null){
            log.warn(ResultCode.ERROR_IS_NULL.toString() + ", user id = " + id);
            // 抛出异常
            throw new ApplicationException(AppResult.fail(ResultCode.ERROR_IS_NULL));
        }

        //然后通过更新这里的文章数量
        User updataUser = new User();
        updataUser.setId(user.getId());
        updataUser.setArticleCount(user.getArticleCount() + 1);

        //更新
        int result = userMapper.updateByPrimaryKeySelective(updataUser);
        if(result != 1){
            log.warn(ResultCode.FAILED.toString());
            throw new ApplicationException(AppResult.fail(ResultCode.FAILED));
        }
    }

大体的步骤就是:对于id进行参数的校验,然后通过id拿到这里的用户的对象;再次进行非空的校验,最后就是设修改的对象,传入用户要修改的信息即可;那么最后一步就是判断这里的修改行数是否是1即可;

🚀3.2板块service层

大致和用户差不多,service实现类如下所示:

java 复制代码
 @Override
    public void addOneArticleCountById(Long id) {
        //首先判断id参数的合法性
        if(id == null || id <= 0){
            log.warn("没有找到对应的板块,id:" + id);
            throw new ApplicationException(AppResult.fail(ResultCode.FAILED_BOARD_ARTICLE_COUNT));
        }
        //根据id查询对应的板块
        Board board = boardMapper.selectByPrimaryKey(id);
        //校验是否正确
        if(board == null){
            //此时板块为空
            log.warn(ResultCode.ERROR_IS_NULL.toString());
            throw new ApplicationException(AppResult.fail(ResultCode.ERROR_IS_NULL));
        }

        //更新这里的文章的数量
        Board updataBoard = new Board();
        updataBoard.setId(board.getId());
        updataBoard.setArticleCount(board.getArticleCount() + 1);

        int result = boardMapper.updateByPrimaryKeySelective(updataBoard);

        //判断这里的更新是否出现了的错误
        if(result != 1){
            log.warn(ResultCode.FAILED.toString());
            throw new ApplicationException(AppResult.fail(ResultCode.FAILED));
        }
    }

和用户板块差不多,那么这里抛出异常主要是为了事务进行准备;

🚀3.3文章service层

在接口中由于这里涉及三个表的设计,所以为了保证安全性,这里使用事务,保证三个数据库更改一起成功或者一起失败:

java 复制代码
  @Transactional
    void create(Article article);

那么至于service层代码来说:

java 复制代码
 public void create(Article article) {
        //进行参数的校验
        if(article == null || article.getUserId() == null
        || article.getBoardId() == null
        || !StringUtils.hasLength(article.getContent())
        || !StringUtils.hasLength(article.getTitle())){
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            throw new ApplicationException(AppResult.fail(ResultCode.FAILED_PARAMS_VALIDATE));
        }

        //设置默认值
        article.setVisitCount(0); // 访问数
        article.setReplyCount(0); // 回复数
        article.setLikeCount(0); // 点赞数
        article.setDeleteState((byte) 0);
        article.setState((byte) 0);
        Date date = new Date();
        article.setCreateTime(date);
        article.setUpdateTime(date);

        //进行创建文章的操作
        int result = articleMapper.insertSelective(article);
        if(result != 1){
            throw new ApplicationException(AppResult.fail(ResultCode.FAILED_CREATE));
        }

        //更新这里的用户表数据以及板块表数据
        //这里要进行校验的操作,利用事务进行轮滚或者是提交
        User user = userServiceImp.selectById(article.getUserId());
        if(user == null){
            
            throw new ApplicationException(AppResult.fail(ResultCode.FAILED_CREATE));
        }

        userServiceImp.addOneArticleCountById(user.getId());

        Board board = boardServiceImp.selectById(article.getBoardId());
        if(board == null){
          
            throw new ApplicationException(AppResult.fail(ResultCode.FAILED_CREATE));
        }

        boardServiceImp.addOneArticleCountById(board.getId());

    }

大致就是在进行数据校验的判断后,设置要传递的对象实现数据修改,并进行是否成功的判断,然后对于两个板块和用户对象来说,这里还需要进行对应的service层方法的调用实现对应数据库的数据更改;(前提也是进行获得的对象的非空的校验);

这里上述三个service层来说一但抛出异常后,那么事务就会回滚,而不会提交 ,保证了数据的准确性以及正确性;

📚️4.Controller层的设计

这里是发表文章,牵连到三个数据库的设计,所以只需要设计发表文章的控制类即可

具体的代码如下所示:

java 复制代码
 @RequestMapping(value = "/create" ,method = RequestMethod.POST)
    public AppResult create(HttpServletRequest request,
                            @RequestParam("boardId") @NonNull Long boardId,
                            @RequestParam("title") @NonNull String title,
                            @RequestParam("content") @NonNull String content){
        //判断用户是否禁言,用户对象从session中进行获取
        HttpSession session = request.getSession(false);

        User user =(User) session.getAttribute(ContentConfig.USER_SESSION);
        if(user.getState() == 1){
            //说明此时用户处于禁言的状态
            return AppResult.fail(ResultCode.FAILED_USER_BANNED);
        }
        //设置传递参数
        Article article = new Article();
        article.setUserId(user.getId());
        article.setBoardId(boardId);
        article.setContent(content);
        article.setTitle(title);

        articleServiceImp.create(article);

        return AppResult.success("发表文章成功");
    }

解释:首先设置路由,以及需要的方法,然后设置的三个参数来说,直接是使用lombok中的NunNull进行非空的校验,然后从session中获取用户对象,设置这里传递的对象,最后调用service层的代码即可;

📚️5.测试

最后我们使用pastman进行测试这里的代码,是否能成功修改我们的数据库:

注意:由于要使用这里的session来获取对象,那么我们首先进行登录,然后再进行测试:

那么此时我们检查一下我们navicat中的数据库:

很明显这里输入的2指的就是板块2,这里的文章数量很明显进行了加一的操作;

然后这里的文章板块也进行了对应的发布操作;

对应的用户发布的文章也进行了加一的操作;

📚️6.总结

本期主要讲解了关于发布文章,牵连的三个数据库表的设计操作,从SQL的编写到Dao层,Service层,Controller层的程序设计;以及最后的结果展示;

🌅🌅🌅~~~~最后希望与诸君共勉,共同进步!!!


💪💪💪以上就是本期内容了, 感兴趣的话,就关注小编吧。

😊😊 期待你的关注~~~

相关推荐
技术宝哥26 分钟前
Redis(2):Redis + Lua为什么可以实现原子性
数据库·redis·lua
学地理的小胖砸2 小时前
【Python 操作 MySQL 数据库】
数据库·python·mysql
dddaidai1232 小时前
Redis解析
数据库·redis·缓存
数据库幼崽2 小时前
MySQL 8.0 OCP 1Z0-908 121-130题
数据库·mysql·ocp
Amctwd3 小时前
【SQL】如何在 SQL 中统计结构化字符串的特征频率
数据库·sql
betazhou3 小时前
基于Linux环境实现Oracle goldengate远程抽取MySQL同步数据到MySQL
linux·数据库·mysql·oracle·ogg
lyrhhhhhhhh3 小时前
Spring 框架 JDBC 模板技术详解
java·数据库·spring
喝醉的小喵5 小时前
【mysql】并发 Insert 的死锁问题 第二弹
数据库·后端·mysql·死锁
付出不多5 小时前
Linux——mysql主从复制与读写分离
数据库·mysql
初次见面我叫泰隆5 小时前
MySQL——1、数据库基础
数据库·adb