15. 实现业务功能--帖子操作

news2024/10/7 16:16:30

1. 集成编译器

editor.md 支持 MarkDown 语法编辑,在需要用户输⼊内容的页面按以下代码嵌入编辑器

1.1 编写 HTML

<!-- 引⼊编辑器的CSS -->
<link rel="stylesheet" href="./dist/editor.md/css/editormd.min.css">
<!-- 引⼊编辑器JS -->
<script src="./dist/editor.md/editormd.min.js"></script>
<script src="./dist/editor.md/lib/marked.min.js"></script>
<script src="./dist/editor.md/lib/prettify.min.js"></script>
<script src="./dist/libs/tinymce/tinymce.min.js" defer></script>
<!-- 需要初始化编辑器的DIV -->
<div id="edit-article">
 <!-- textarea也是⼀个表单控件,当在editor.md中编辑好的内容会关联这个⽂本域上 -->
 <textarea id="article_post_content" style="display: none;"></textarea>
</div>

1.2 编写 JS

var editor = editormd("edit-article", {
 width: "100%",
 height: "100%",
 // theme : "dark",
 // previewTheme : "dark",
 // editorTheme : "pastel-on-dark",
 codeFold: true,
 //syncScrolling : false,
 saveHTMLToTextarea: true, // 保存 HTML 到 Textarea
 searchReplace: true,
 watch : true, // 关闭实时预览
 htmlDecode: "style,script,iframe|on*", // 开启 HTML 标签解析,为了安
全性,默认不开启 
 // toolbar : false, //关闭⼯具栏
 // previewCodeHighlight : false, // 关闭预览 HTML 的代码块⾼亮,默认开启
 emoji: true,
 taskList: true,
 tocm: true, // Using [TOCM]
 tex: true, // 开启科学公式TeX语⾔⽀持,默认关闭
 // flowChart: true, // 开启流程图⽀持,默认关闭
 // sequenceDiagram: true, // 开启时序/序列图⽀持,默认关闭,
 placeholder: '开始创作...', // 占位符
 path: "./dist/editor.md/lib/"
});

2. 发布帖子

2.1 实现逻辑

1. 用户点击发布新帖按钮,进入发贴页面

2. 选择版块,填入标题、正文后提交服务器

 

3. 服务器校验信息,并写入数据库

4. 更新用户发帖数与版块贴子数

5. 返回结果 

要对帖子表、用户表、板块表同时进行操作,就需要通过事务进行管理。 

2.2 参数要求

参数名描述类型默认值条件
boardId版块 Idlong必须
title文章标题String必须
content帖子内容String必须

作者 Id 需要从 Session 中获取(即当前的登录用户)。

2.3 在 UserExtMapper.xml 中编写 SQL 语句

<!-- 更新用户的发帖数 -->
  <update id="updateArticleCount" parameterType="java.lang.Long">
    update t_user set articleCount = articleCount + 1,updateTime = now() where id = #{id,jdbcType=BIGINT}
  </update>

2.4 创建 Service 接口

在 IUserService 定义方法:
    /**
     * 贴子数增加1
     * @param id
     * @return
     */
   void addOneArticleCountById(Long id);
在 IBoardService 定义方法:
    /**
     * 贴子数增加1
     * @param id
     * @return
     */
   void addOneArticleCountById(Long id);

在 IArticleService 定义方法:

使用事务管理,加入 @Transactional 注解

 

    /**
     * 发布帖⼦
     * @param article 帖⼦信息
     */
    // 事务管理
    @Transactional
    void create(Article article);

在这个方法中,需要对三个表进行更新操作,因此需要通过事务进行管理。如果在执行过程中抛出异常,那么事务将会被自动回滚。

2.5 实现 Service 接口

在 IBoradService.java 中实现以下方法:

 @Override
    public void addOneArticleCountById(Long id) {
        // 非空检验
        if(id == null || id <= 0){
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 查询现有的用户信息
        User user = selectById(id);
        // 校验用户是否存在
        if (user == null) {
            // 打印日志
            log.info(ResultCode.FAILED_USER_NOT_EXISTS.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        // 构造要更新的对象
        User updateUser = new User(); 
        updateUser.setId(user.getId()); // 用户Id
        updateUser.setArticleCount(user.getArticleCount() + 1); //帖子数量+1
        updateUser.setUpdateTime(new Date());// 更新时间
        
        // 调用 DAO
        int row = userMapper.updateByPrimaryKeySelective(updateUser);
        if(row != 1){
            // 打印日志
            log.warn(ResultCode.ERROR_SERVICES.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.ERROR_SERVICES));
        }
    }

在 BoardServiceImpl.java 中实现以下方法:

@Override
    public void addOneArticleCountById(Long id) {
        // 非空检验
        if(id == null || id <= 0){
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 查询板块信息
        Board board = selectById(id);
        // 检验版块是否存在
        if(board == null){
            // 打印日志
            log.warn(ResultCode.FAILED_BOARD_NOT_EXISTS.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_BOARD_NOT_EXISTS));
        }
        // 构造要更新的对象
        Board updateBoard = new Board();
        updateBoard.setId(board.getId()); // 版块Id
        updateBoard.setArticleCount(board.getArticleCount() + 1); //帖子数量
        updateBoard.setUpdateTime(new Date());// 更新时间

        // 调用 DAO
        int row = boardMapper.updateByPrimaryKeySelective(updateBoard);
    }

2.6 测试

在以上的实现方法写好后,编写测试代码:

在 UserServiceImplTest.java 文件中:

@Test
    @Transactional
    void addOneArticleCountById() {
        userService.addOneArticleCountById(1l);
        System.out.println("更新成功");

        userService.addOneArticleCountById(2l);
        System.out.println("更新成功");

    }

在 BoardServiceImplTest.java 中:

    @Test
    void addOneArticleCountById() {
        boradService.addOneArticleCountById(1l);
        System.out.println("更新成功");

        boradService.addOneArticleCountById(2l);
        System.out.println("更新成功");

        boradService.addOneArticleCountById(55l);
        System.out.println("更新成功");
    }

加了事务的注解后,测试的结果不在持久化到数据库,当测试通过后,写入的数据会被回滚。 

    @Test
    void create() {
        Article article = new Article();
        article.setBoardId(1l);
        article.setUserId(1l);
        article.setTitle("单元测试标题");
        article.setContent("单元测试内容");
        // 调用service
        articleService.create(article);
        System.out.println("写入成功");
    }

 测试成功:

2.7 实现 Controller

@ApiOperation("发布帖子")
    @PostMapping("/create")
    public AppResult create(HttpServletRequest request,
                            @ApiParam("版块Id") @RequestParam("boardId") @NonNull Long boardId,
                            @ApiParam("帖子标题") @RequestParam("title") @NonNull String title,
                            @ApiParam("帖子正文") @RequestParam("content") @NonNull String content){
        // 获取用户信息
        HttpSession session = request.getSession(false);
        User user =(User)session.getAttribute(AppConfig.SESSION_USER_KEY);
        // 校验用户状态
        if(user.getState() == 1){
            // 用户已禁言,返回提示
            return AppResult.failed(ResultCode.FAILED_USER_BANNED);
        }
        // 构造帖子对象
        Article article = new Article();
        article.setUserId(user.getId()); // 当前登录用户就是作者
        article.setBoardId(boardId); // 版块Id
        article.setTitle(title); // 帖子标题
        article.setContent(content); // 帖子正文
        // 调用 Service
        articleService.create(article);
        // 返回结果
        return AppResult.success("贴子发布成功");
    }

2.8 实现前端界面

// 构造帖子对象
      let postData = {
        boardId : boardIdEl.val(),
        title : titleEl.val(),
        content : contentEl.val()
      };
      

      // 提交, 成功后调用changeNavActive($('#nav_board_index'));回到首页并加载帖子列表
      // contentType: 'application/x-www-form-urlencoded'
      $.ajax({
        type : 'post',
        url : 'article/create',
        contentType : 'application/x-www-form-urlencoded',
        data : postData,
        // 成功回调
        success: function(respData){
          if(respData.code == 0){
            // 成功后跳转到首页
            changeNavActive($('#nav_board_index'));
          }else{
            // 失败
            $.toast({
                heading : '警告',
                text : respData.message,
                icon : 'Warning'
              }); 
            }
          },
          // 失败回调
          error: function(){
            $.toast({
                heading : '错误',
                text : '出错了,请联系管理员',
                icon : 'error'
              });
          }

3. 帖子详情

3.1 实现逻辑

1. 用户点击帖子,将帖子 Id 做为参数向服务器发送请求
2. 服务器查询帖子信息
3. 帖子访问次数加1
4. 返回查询结果

那么此时的操作有一个查询,一个更新需要用事务进行管理吗?

答:只对一条记录进行更新时,不需要事务。

在帖子详情中,必须包含帖子的全部信息。

3.2 创建扩展 Mapper.xml

在 ArticleExtMapper.xml 中添加SQL:
<?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="com.example.demo.dao.ArticleMapper">
  <!--  定义表关系的结果集映射  -->
  <resultMap id="AllInfoResultMap" type="com.example.demo.model.Article" extends="ResultMapWithBLOBs">
    <!--    关联User对象  -->
    <association property="user" resultMap="com.example.demo.dao.UserMapper.BaseResultMap" columnPrefix="u_"/>
    <!--    关联Board对象  -->
    <association property="board" resultMap="com.example.demo.dao.BoardMapper.BaseResultMap" columnPrefix="b_"/>
  </resultMap>
  <!--  查询所有的帖子集合  -->
  <select id="selectAll" resultMap="AllInfoResultMap">
    select
    u.id as u_id,
    u.nickname as u_nickname,
    u.gender as u_gender,
    u.avatarUrl as u_avatarUrl,
    a.id,
    a.boardId,
    a.userId,
    a.title,
    a.visitCount,
    a.replyCount,
    a.likeCount,
    a.state,
    a.deleteState,
    a.createTime,
    a.updateTime
    from t_article as a ,t_user as u
    where a.userId = u.id
    and a.deleteState = 0
    order by a.createTime desc
  </select>
  <!--  查询所有的帖子集合  -->
  <select id="selectByBoardId" resultMap="AllInfoResultMap">
    select
    u.id as u_id,
    u.nickname as u_nickname,
    u.gender as u_gender,
    u.avatarUrl as u_avatarUrl,
    a.id,
    a.boardId,
    a.userId,
    a.title,
    a.visitCount,
    a.replyCount,
    a.likeCount,
    a.state,
    a.deleteState,
    a.createTime,
    a.updateTime
    from t_article as a ,t_user as u
    where a.userId = u.id
    and a.deleteState = 0
    and a.boardId = #{boardId,jdbcType=BIGINT}
    order by a.createTime desc
  </select>
  
  <!--  根据帖子Id 查询帖子详情  -->
  <select id="selectById" resultMap="AllInfoResultMap" parameterType="java.lang.Long">
    select
    u.id as u_id,
    u.nickname as u_nickname,
    u.gender as u_gender,
    u.avatarUrl as u_avatarUrl,
    b.id as b_id,
    b.name as b_name,
    a.id,
    a.boardId,
    a.userId,
    a.title,
    a.visitCount,
    a.replyCount,
    a.likeCount,
    a.state,
    a.deleteState,
    a.createTime,
    a.updateTime
    from t_article as a ,t_user as u,t_board b
    where a.userId = u.id
    and a.boardId = b.id
    and a.id = #{id,jdbcType=BIGINT}
    and a.deleteState = 0
  </select>
</mapper>

3.3 修改 DAO

在 dao 包下的 ArticleMapper 中添加方法声明:
    /**
     * 根据帖子Id 查询帖子详情
     * @param id
     * @return
     */
    Article selectById(@Param("id") Long id);

3.4 创建 Service 接口

在 IArticleService 定义方法:
    /**
     * 根据帖子Id 查询帖子详情
     * @param id
     * @return
     */
    Article selectById(Long id);

3.5 实现 Service 接口

在 ArticleServiceImpl 中实现方法:
 @Override
    public Article selectById(Long id) {
        // 非空检验
        if(id == null || id <= 0){
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 调用 DAO
        Article article = articleMapper.selectById(id);
        // 返回结果
        return article;
    }

3.6 测试

@Test
    void selectById() throws JsonProcessingException {
        Article article = articleService.selectById(1l);
        System.out.println(objectMapper.writeValueAsString(article));

        article = articleService.selectById(8l);
        System.out.println(objectMapper.writeValueAsString(article));

        article = articleService.selectById(100l);
        System.out.println(objectMapper.writeValueAsString(article));
    }

测试结果:

3.7 实现 Controller

在 ArticleController 中提供对外的API接口:
@ApiOperation("根据Id查询帖⼦详情")
    @GetMapping("/getById")
    public AppResult<Article> getDetails(@ApiParam("帖⼦Id")
                                         @RequestParam("id") 
                                             @NonNull Long id) {
        // 调⽤Service层获取帖⼦详情
        Article article = articleService.selectById(id);
        // 校验
        if (article == null) {
            return AppResult.failed("帖子不存在");
        }
        // 返回成功信息
        return AppResult.success(article);
    }

 

3.8 实现前端界面

$.ajax({
      type : 'get',
      url : '/article/getById?id=' + currentArticle.id,
      // 成功回调
      success: function(respData){
          if(respData.code == 0){
            // 把查询到的数据设置到页面上
            initArticleDetails(respData.data);
          }else{
            // 失败
            $.toast({
                heading : '警告',
                text : respData.message,
                icon : 'Warning'
              }); 
            }
          },
          // 失败回调
          error: function(){
            $.toast({
                heading : '错误',
                text : '出错了,请联系管理员',
                icon : 'error'
              });
          }

    });

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/947040.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

学习pytorch6 torchvision中的数据集使用

torchvision中的数据集使用 1. torchvision中的数据集使用官网文档注意点1 totensor实例化不要忘记加括号注意点2 download可以一直保持为True代码执行结果 2. DataLoader的使用 1. torchvision中的数据集使用 官网文档 注意左上角的版本 https://pytorch.org/vision/0.9/ 注…

行业趋势和新兴领域分析:分析当前网络安全行业的发展趋势,如IoT安全、AI安全、区块链安全等。

第一章&#xff1a;引言 随着数字化时代的迅速发展&#xff0c;网络安全已经成为各行各业不可忽视的重要领域。恶意攻击、数据泄露以及黑客入侵等威胁逐渐增多&#xff0c;推动着网络安全行业不断创新与进步。本文将深入探讨当前网络安全领域的发展趋势&#xff0c;聚焦于新兴…

肿瘤科医师狂喜,15分RNA修饰数据挖掘文章

Biomamba荐语 与这个系列的前面一些论文类似&#xff0c;这次给大家推荐的是一篇纯生物信息学数据挖掘的文章&#xff0c;换句话说&#xff0c;这又是一篇不需要支出科研经费&#xff08;白嫖&#xff09;的论文(当然&#xff0c;生信分析用的服务器还是得掏点费用的)。一般来…

springboot第37集:kafka,mqtt,Netty,nginx,CentOS,Webpack

image.png binzookeeper-server-start.shconfigzookeeper.properties.png image.png image.png 消费 image.png image.png image.png image.png image.png image.png image.png image.png image.png Netty的优点有很多&#xff1a; API使用简单&#xff0c;学习成本低。功能强大…

【操作系统】聊聊文件传输的零拷贝、PageCache、异步IO机制

在目前主流的系统中&#xff0c;其实大多数都是数据密集型系统&#xff0c;所以设计数据密集型应用一书非常经典&#xff0c;推荐一读。而大多数遇到的问题都是存储问题。CPU、内存 因为本身的读写速度比较快&#xff0c;所以磁盘就成为了一个性能瓶颈。 针对磁盘优化的技术层…

对class文件进行base64编码

使用以下代码 package org.springframework.cloud.gateway.sample;import org.springframework.util.Base64Utils;import java.io.*; import java.nio.charset.StandardCharsets;public class EncodeShell {public static void main(String[] args){byte[] data null;try {In…

大数据之linux入门

一、linux是什么 linux操作系统 开发者是林纳斯-托瓦兹&#xff0c;出于个人爱好编写。linux是一个基于posix和unix的多用户、多任务、支持多线程和多CPU的操作系统。 Unix是20世纪70年代初出现的一个操作系统&#xff0c;除了作为网络操作系统之外&#xff0c;还可以作为单…

6路液体水位检测芯片VK36W6D SOP16 抗电源干扰及手机干扰特性好

产品品牌&#xff1a;永嘉微电/VINKA 产品型号&#xff1a;VK36W6D 封装形式&#xff1a;SOP16/QFN16L 详细资料&#xff1a;13.5/5.474/4.703 概述 VK36W6D具有6个触摸检测通道&#xff0c;可用来检测6个点的水位。该芯片具有较高的集成度&#xff0c;仅需极少的外部组件便…

vscode GDB 调试linux内核 head.S

遇到的问题 此前参考如下文章 https://zhuanlan.zhihu.com/p/510289859 已经完成了在ubuntu 虚拟机用vscode 调试linux 内核。但是美中不足的是&#xff0c;断点最早只能加在__primary_switched() 函数。无法停在更早的断点上&#xff0c;比如ENTRY(stext) 位置。参考《奔跑吧…

C语言_初识C语言指针

文章目录 前言一、指针 ... 一个内存单元多大比较合适&#xff1f;二、地址或者编号如何产生&#xff1f;三、指针变量的大小 前言 内存是电脑上特别重要的存储器&#xff0c;计算机中程序的运行都是在内存中进行的。 所以为了有效的使用内存&#xff0c;就把内存划分成一个个…

记1次前端性能优化之CPU使用率

碰到这样的一个问题&#xff0c;用户反馈页面的图表一直加载不出来&#xff0c;页面还卡死 打开链接页面&#xff0c;打开控制台 Network 看到有个请求一直pending&#xff0c;结合用户描述&#xff0c;页面一直loading,似乎验证了我的怀疑&#xff1a;后端迟迟没有相应。 但是…

【工作笔记-0038】mongodb mongorestore 命令行导入 bson.gz数据

1. 导出的集合文件格式如下&#xff08;也就是导出的表文件&#xff09;&#xff1a; 例如&#xff1a; D:\Files\xxxx集合名称.bson.gz 怎样导出&#xff0c;这里不做介绍&#xff0c;用 mongodb compass 或者 studio 3t 都可以 2. 下载命令行导入工具&#xff1a; 官方…

webpack(一)模块化

模块化演变过程 阶段一&#xff1a;基于文件的划分模块方式 概念&#xff1a;将每个功能和相关数据状态分别放在单独的文件里 约定每一个文件就是一个单独的模块&#xff0c;使用每个模块&#xff0c;直接调用这个模块的成员 缺点&#xff1a;所有的成员都可以在模块外被访问和…

Redis发布订阅

Redis发布订阅 Redis 发布订阅(pub/sub)是一种 消息通信模式&#xff1a;发送者(pub)发送消息&#xff0c;订阅者(sub)接收消息。 Redis 客户端可以订阅任意数量的频道。 订阅/发布消息图&#xff1a; 下图展示了频道 channel1 &#xff0c; 以及订阅这个频道的三个客户端 —…

时间范围选择时选中日期所使用的当日内具体时刻 如00:00:00= 23:59:59

<el-form-item label"审核时间&#xff1a;"><el-date-pickerv-model"auditTime"type"datetimerange"range-separator"至"value-format"yyyy-MM-dd HH:mm:ss"start-placeholder"开始日期"end-placeholde…

智慧园区方案:AI与视频融合技术如何助力园区监管智能化升级?

一、行业背景 随着科技的不断发展&#xff0c;人工智能&#xff08;AI&#xff09;技术正在各个领域迅速应用和推广。其中&#xff0c;智慧园区是一个重要的应用场景&#xff0c;它通过AI技术的支持&#xff0c;实现了园区的智能化管理和高效运营。 1、园区管理智慧化升级需求…

Centos7 安装Docker管理工具Portainer

0、前提条件 已安装Docker并且开启Docker&#xff0c;安装Docker可参见&#xff1a;Centos7 安装 Docker_瘦身小蚂蚁的博客-CSDN博客 1、 拉取portainer-ce镜像 docker pull portainer/portainer-ce:latest [rootlocalhost ~]# docker pull portainer/portainer-ce:latest la…

git视频教程Jenkins持续集成视频教程Git Gitlab Sonar教程

[TOC这里写自定义目录标题) https://edu.51cto.com/lesson/290903.html 欢迎使用Markdown编辑器 你好&#xff01; 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章&#xff0c;了解一下Markdown的基本语法知识。…

科技资讯|苹果Vision Pro头显申请游戏手柄专利和商标

苹果集虚拟现实和增强现实于一体的头戴式设备 Vision Pro 推出一个月后&#xff0c;美国专利局公布了两项苹果公司申请的游戏手柄专利&#xff0c;其中一项的专利图如下图所示。据 PatentlyApple 报道&#xff0c;虽然专利本身并不能保证苹果公司会推出游戏手柄&#xff0c;但是…

JVM 是怎么设计来保证new对象的线程安全

1、采用 CAS 分配重试的方式来保证更新操作的原子性 2、每个线程在 Java 堆中预先分配一小块内存&#xff0c;也就是本地线程分配缓冲&#xff08;Thread Local AllocationBuffer&#xff0c;TLAB&#xff09;&#xff0c;要分配内存的线程&#xff0c;先在本地缓冲区中分配&a…