day05问答系统

1.需求分析

经过几天学习,相信大家对于业务开发已经轻车熟路了,整体流程与以往一样:

  • 需求和原型图分析
  • 接口统计和设计
  • 数据结构设计
  • 接口的实现

1.1.产品原型

1.1.1.课程详情页

在用户已经登录的情况下,如果用户购买了课程,在课程详情页可以看到一个互动问答的选项卡:
问答选项卡如下:
在这里插入图片描述

  1. 问答列表
  • 问答列表可以选择全部问题还是我的问题,选择我的问题则只展示我提问的问题。默认是全部
  • 选择章节序号,根据章节号查看章节下对应问答。默认展示所有章节的问题
  • 对于我提问的问题,可以做删除、修改操作
  1. 跳转逻辑
  • 点击提问按钮,进入问题编辑页面
  • 点击问题标题,进入问题详情页
  • 点击问题下的回答,进入回答表单

点击提问或编辑按钮会进入问题编辑页面:

在这里插入图片描述

  1. 表单内容
  • 课程:问题一定关联提问时所在的课程,无需选择
  • 章节:可以选择提问知识点对应的章节,也可以不选
  • 问题标题:一个概括性描述
  • 问题详情:详细问题信息,富文本
  • 是否匿名:用户可以选择匿名提问,其它用户不可见提问者信息

点击某个问题,则会进入问题详情页面:
在这里插入图片描述

  1. 页面内容
  • 顶部展示问题相关详细信息
  • 任何人都可以对问题做回复,也可以对他人的回答再次回复,无限叠楼。
  • 也没渲染只分两层:
    • 对问题的一级回复,称为回答
    • 对回答的回复、对回复的回复,作为第二级,称为评论
  • 问题详情页下面展示问题下的所有回答
  • 点击回答下的详情才展示二级评论
  • 可以对评论、回答点赞
1.1.2.视频学习页

另外,在视频学习页面中同样可以看到互动问答功能:
在这里插入图片描述
这个页面与课程详情页功能类似,只不过是在观看视频的过程中操作。用户产生学习疑问是可以快速提问,不用退回到课程详情页,用户体验较好。

  1. 页面逻辑
  • 默认展示视频播放小节下的问答
  • 用户可以在这里提问问题,自动与当前课程、当前视频对应章节关联。其它参数与课程详情页的问题表单类似。
  • 问答列表默认只显示问题,点击后进入问题详情页才能查看具体答案
1.1.3.管理端问答管理页

除了用户端以外,管理端也可以管理互动问答,首先是一个列表页:
在这里插入图片描述

  1. 搜索
  • 管理员可以搜索用户提出的所有问题
  • 搜索结果可以基于页面过滤条件做过滤
    • 问题状态:已查看、未查看两种。标示是否已经被管理员查看过。每当学员在问题下评论,状态重置为未查看
    • 课程名称:由于问题是提问在课程下的,所以会跟课程关联。管理员输入课程名称,搜索该课程下的所有问题
    • 提问时间:提出问题的时间
  1. 页面列表
  • 默认按照提问时间倒序排列;点击回答数量时可以根据回答数量排序
  • 课程分类:需要展示问题所属课程的三级分类的名称的拼接
  • 课程所属章节:如果是在视频页面提问,则问题会与视频对应的章、节关联,则此处显示章名称、节名称。
  • 课程名称:提问是针对某个课程的,因此此处显示对应的课程名称
  • 回答数量:该问题下的一级回复,称为回答。此处显示问题下的回答的数量,其它评论不统计。
  • 用户端状态:隐藏/显示。表示是否在用户端展示,对于一些敏感话题,管理员可以直接隐藏问题。
  1. 操作
  • 点击查看:会将该问题标记为已查看状态,并且跳转到问题详情页
  • 点击隐藏或显示:控制该问题是否在用户端显示。隐藏问题,则问题下的所有回答和恢复都被隐藏

点击查看按钮,会进入一个问题详情页面:
在这里插入图片描述

  1. 问题详情
  • 页面顶部是问题详情,展示信息与问题列表页基本一致
  • 点击评论,老师可以回答问题
  • 点击隐藏/显示,可以隐藏或显示问题
  1. 回答列表
  • 分页展示问题下的回答(一级回复)
  • 可以对回答点赞、评论、隐藏
  • 点击查看,则进入回答详情页

继续点击查看更多按钮,可以进入回答详情页:
[图片]

  1. 回答详情
  • 页面顶部是回答详情,展示信息与回答列表页基本一致
  • 点击我来评论,老师可以评论该回答
  • 点击隐藏/显示,可以隐藏或显示该回答,该回答下的所有评论也都会被隐藏或显示
  1. 评论列表
  • 分页展示回答下的评论
  • 可以对评论点赞、回复、隐藏
1.1.4.流程总结

整体来说,流程是这样的:

  • 学员在学习的过程中可以随时提问问题
  • 老师、其他学员都可以回答问题
  • 老师、学员也都可以对回答多次回复
  • 老师、学员也都可以对评论多次回复
  • 老师可以在管理端管理问题、回答、评论的状态

业务流程并不复杂。

1.2.接口统计

理论上我们应该先设计所有接口,再继续设计接口对应的表结构。不过由于接口较多,这里我们先对接口做简单统计。然后直接设计数据库,最后边设计接口,边实现接口。

1.2.1.问题的CRUD

首先第一个页面,列表展示页:
在这里插入图片描述
结合原型设计图我们可以看到这里包含4个接口:

  • 带条件过滤的分页查询
  • 新增提问
  • 修改提问
  • 删除提问
    这些都是基本的CRUD,应该不难。
1.2.2.问题的回答和评论

进入问答详情页再看:
在这里插入图片描述
可以看到页面中包含5个接口:

  • 根据id查询问题详情
  • 分页查询问题下的所有回答
  • 分页查询回答下的评论
  • 点赞/取消点赞某个回答或评论
  • 回答某个提问、评论他人回答

除了点赞功能外,其它接口也都是基本的增删改查,并不复杂。

1.2.3.管理端接口

刚才分析的都是用户端的相关接口,这些接口部分可以与管理端共用,但管理端也有自己的特有需求。
管理端也可以分页查询问题列表,而且过滤条件、查询结果会有很大不同:

在这里插入图片描述
比较明显的有两个接口:

  • 管理端分页查询问题列表:与用户端分页查询不通用,功能更复杂,查询条件更多
  • 隐藏或显示指定问题

除此以外,这里有一个问题状态字段,表示管理员是否查看了该问题以及问题中的回答。默认是未查看状态;当管理员点击查看后,状态会变化为已查看;当学员再次回答或评论,状态会再次变为未查看。
因此,需要注意的是:

  • 每当用户点击查看按钮,需要根据根据id查询问题详情,此时应标记问题状态为已查看
  • 每当学员回答或评论时,需要将问题标记为未查看

管理端也会有回答列表、评论列表。另外,回答和评论同样有隐藏功能。
问题详情和回答列表:

在这里插入图片描述
还有评论列表:
在这里插入图片描述

总结一下,回答和评论包含的接口有:

  • 管理端根据id查询问题详情
  • 分页查询问题下的回答
  • 分页查询回答下的评论
  • 点赞/取消点赞某个回答或评论
  • 隐藏/显示指定回答或评论
  • 回答某个提问、评论他人回答、评论(与用户端共用)
1.2.4.总结 接口

综上,与问答系统有关的接口有:
在这里插入图片描述

2.数据结构

从原型图不难看出,这部分功能主要涉及两个实体:

  • 问题
  • 回答/评论:回答、评论可以看做一类实体
    因此核心要设计的就是这两张表。

2.1.ER图

2.1.1.问题

首先是问题,通过新增提问的表单可以看出问题包含的属性:
在这里插入图片描述

2.1.2.回答、评论

回答和评论的属性基本一致,差别就是:

  • 回答的对象是问题
  • 评论的对象是其它回答或评论
    在这里插入图片描述
    在这里插入图片描述
    ER图:
    在这里插入图片描述

2.2.数据库表

结合ER图,表结构就非常清楚了,会包含两张表:

  • 问题表
  • 回复表:回答和评论都是回复,在一张表
2.2.1.问题表

首先是问题表:

CREATE TABLE IF NOT EXISTS `interaction_question` (
  `id` bigint NOT NULL COMMENT '主键,互动问题的id',
  `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '互动问题的标题',
  `description` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '问题描述信息',
  `course_id` bigint NOT NULL COMMENT '所属课程id',
  `chapter_id` bigint NOT NULL COMMENT '所属课程章id',
  `section_id` bigint NOT NULL COMMENT '所属课程节id',
  `user_id` bigint NOT NULL COMMENT '提问学员id',
  `latest_answer_id` bigint DEFAULT NULL COMMENT '最新的一个回答的id',
  `answer_times` int unsigned NOT NULL DEFAULT '0' COMMENT '问题下的回答数量',
  `anonymity` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否匿名,默认false',
  `hidden` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否被隐藏,默认false',
  `status` tinyint DEFAULT '0' COMMENT '管理端问题状态:0-未查看,1-已查看',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '提问时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_course_id` (`course_id`) USING BTREE,
  KEY `section_id` (`section_id`),
  KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='互动提问的问题表';

2.2.3.回答或评论

回答和评论合为一张表,称为评论表:

CREATE TABLE IF NOT EXISTS `interaction_reply` (
  `id` bigint NOT NULL COMMENT '互动问题的回答id',
  `question_id` bigint NOT NULL COMMENT '互动问题问题id',
  `answer_id` bigint DEFAULT '0' COMMENT '回复的上级回答id',
  `user_id` bigint NOT NULL COMMENT '回答者id',
  `content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '回答内容',
  `target_user_id` bigint DEFAULT '0' COMMENT '回复的目标用户id',
  `target_reply_id` bigint DEFAULT '0' COMMENT '回复的目标回复id',
  `reply_times` int NOT NULL DEFAULT '0' COMMENT '评论数量',
  `liked_times` int NOT NULL DEFAULT '0' COMMENT '点赞数量',
  `hidden` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否被隐藏,默认false',
  `anonymity` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否匿名,默认false',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_question_id` (`question_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='互动问题的回答或评论';

3.问题相关接口

问题相关接口在管理端和用户端存在一些差异,在设计接口时一定要留意。另外,此处只带大家实现其中的部分接口:

  • 新增互动问题
  • 用户端分页查询问题
  • 根据id查询问题详情
  • 管理端分页查询问题

3.1.新增问题

3.1.1.接口分析

首先还是看原型图,新增的表单如下:
在这里插入图片描述
通过新增的问题的表单即可分析出接口的请求参数信息了,然后按照Restful的风格设计即可:
在这里插入图片描述

3.1.2.实体类

新增业务中无返回值,只需要设计出入参对应的DTO即可

3.1.3.代码实现

首先是tj-learning中的InteractionQuestionController:

@RestController
@RequestMapping("/questions")
@RequiredArgsConstructor
public class InteractionQuestionController {

    private final IInteractionQuestionService questionService;

    @ApiOperation("新增提问")
    @PostMapping
    public void saveQuestion(@Valid @RequestBody QuestionFormDTO questionDTO){
        questionService.saveQuestion(questionDTO);
    }
}

然后是tj-learning中的IInteractionQuestionService接口:

public interface IInteractionQuestionService extends IService<InteractionQuestion> {
    void saveQuestion(QuestionFormDTO questionDTO);
}

最后是tj-learning中的InteractionQuestionServiceImpl实现类:

@Service
@RequiredArgsConstructor
public class InteractionQuestionServiceImpl extends ServiceImpl<InteractionQuestionMapper, InteractionQuestion> implements IInteractionQuestionService {
    
    private final IInteractionQuestionDetailService detailService;

    @Override
    @Transactional
    public void saveQuestion(QuestionFormDTO questionDTO) {
        // 1.获取登录用户
        Long userId = UserContext.getUser();
        // 2.数据转换 - DTO转po
        InteractionQuestion question = BeanUtils.toBean(questionDTO, InteractionQuestion.class);
        // 3.补充数据(因为前端传来的DTO数据 不包含po所需要的全部数据 需要自己实现代码额外添加)
        question.setUserId(userId);
        // 4.保存问题
        save(question);

        // 5.问题详情
        InteractionQuestionDetail detail = new InteractionQuestionDetail();
        detail.setId(question.getId());
        detail.setDescription(questionDTO.getDescription());
        detailService.save(detail);
    }
}

分页查询如何做的

在这里插入图片描述

用lambdaQuery()的链式编程,后面是拼条件,如果是in(是否在集合内)就用in(),如果是等于查询就用eq(),区间用between()。
.page()才是做分页,page方法中参数传的是MP的一个page对象:设置页码、每页大小、升序降序、排序字段。

在这里插入图片描述

 @ApiModelProperty(value = "页码", example = "1")
    @Min(value = 1, message = "页码不能小于1")
    private Integer pageNo = DEFAULT_PAGE_NUM;

    @ApiModelProperty(value = "每页大小", example = "5")
    @Min(value = 1, message = "每页查询数量不能小于1")
    private Integer pageSize = DEFAULT_PAGE_SIZE;

    @ApiModelProperty(value = "是否升序", example = "true")
    private Boolean isAsc = true;

    @ApiModelProperty(value = "排序字段", example = "id")
    private String sortBy;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值