匿名发帖/匿名论坛功能设计与实现(编辑发帖部分)
前言
还是之前的音乐系统,首页一直是没想好写些什么,想写一个基于数据分析筛选的歌曲推荐功能,但是目前技术选型没太有考究等以后再实现吧,昨天突然想到可以把首页设计成前40%页面是歌曲推荐后面接下来就是一段匿名论坛功能,说干就干,直接构思,设计,实现。
sql设计
sql经过了数个功能的设计实现之后,现在的sql结构已经基本成熟,对此业务目前我使用了5个表,post(核心帖子表),post_data(帖子数据表),post_draft(帖子草稿表),post_images(帖子图片关联表),post_topics(话题表)
post表
post_data表
post_draft表
post_images
post_topics
这是这5个表的sql结构,然后下面是设计的UI:
接口实现
主要是设计了4个接口功能
发帖接口
使用Optional进行校验参数,大致发帖封为两种方式,一个是前端已经有了草稿,草稿里储存了一个随机的postId,储存帖子信息的时候直接使用这个postId即可,如果为null,则再后端再创建一下uuid即可,分为实名和匿名,匿名就捏造姓名和头像,其他的就是简单的写DB的操作
@Override
public Result postPost(Optional<PostPostDto> optional) {
if (!optional.isPresent()) {
return Result.error("传入空参数");
}
PostPostDto postPostDto = optional.get();
String content = postPostDto.getContent();
String remark = postPostDto.getRemark();
String account = postPostDto.getAccount();
Integer topicId = postPostDto.getTopicId();
Integer wordNum = postPostDto.getWordNum();
List<String> picList = postPostDto.getPicList();
Boolean isNameless = postPostDto.getIsNameless();
Post post = BeanUtil.toBean(postPostDto, Post.class);
if (post.getId() == null) {
// 说明是没有草稿直接发布的,就直接uuid一个即可
post.setId(RandomUtil.randomInt());
}
PostData postData = BeanUtil.toBean(postPostDto, PostData.class);
if (isNameless) {
// 是匿名
Faker faker = new Faker(new Locale("zh-CN"));
String adjective = faker.name().fullName();
String name = faker.animal().name();
String nickname = adjective + "的" + name;
post.setNickname(nickname);
post.setAvatar(NAMELESS_AVATAR_URL);
} else {
// 实名的话就直接去查account的信息
UserCommentPo userInfo = infoMapper.getInfoByAccount(Long.valueOf(account));
post.setAvatar(userInfo.getAvatar());
post.setNickname(userInfo.getUsername());
}
save(post);
// 设置postImages的值
ArrayList<PostImages> postImagesList = new ArrayList<>();
picList.forEach((pic) -> {
PostImages tempPostImages = new PostImages();
tempPostImages.setPostId(post.getId());
tempPostImages.setImageUrl(pic);
postImagesList.add(tempPostImages);
});
postImagesMapper.insert(postImagesList);
// 设置postData的值
postData.setPostId(post.getId());
postDataMapper.insert(postData);
return Result.ok("操作正确");
}
查询话题
这个太简单就是查一下数据库,用了mp的语法
@Override
public Result getTopics() {
LambdaQueryWrapper<PostTopics> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.select(PostTopics::getId, PostTopics::getTitle).eq(PostTopics::getIsDie, false);
List<PostTopics> postTopics = postTopicsMapper.selectList(queryWrapper);
return Result.ok(postTopics);
}
查询帖子的历史草稿
这个主要是数据库设计上的思维巧妙,其实业务上并无难度,就是没难度的查询
@Override
public Result listDraftsByTimes(Integer postId) {
// 构建查询条件
LambdaQueryWrapper<PostDraft> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(PostDraft::getPostId, postId)
.eq(PostDraft::getIsDie, false)
.orderByDesc(PostDraft::getUpdateTime);
// 查询草稿列表
List<PostDraft> drafts = postDraftMapper.selectList(queryWrapper);
return Result.ok(drafts);
}
保存草稿
这段代码没啥难度,也和发帖差不多,就是判断现在有没有postId,没有的话,我就设置一个,主要是sql设计上的难度,炸一想,我也想不出来,根据业务推出来的业务结构,业务就是历史草稿功能。
@Override
public Result saveDraft(PostDraft draft) {
// 设置更新时间
draft.setUpdateTime(LocalDateTime.now());
draft.setIsDie(false);
// 如果第一次生成草稿就先创建一个新的postId
if (draft.getPostId() == null) {
draft.setPostId(Math.abs(RandomUtil.randomInt()));
}
postDraftMapper.insert(draft);
return Result.ok(draft.getPostId());
}
前端的函数
前端的实现同样精彩,只说几点主要的逻辑,防抖限流就不讲了
编辑部分使用wangeditor实现,编辑html格式实现富文本,搞了一个定时器每一秒,统计一次字数。返回顶部和发布设置 按钮,使用Element-plus里的scroll组件里的监听事件实现,发图片使用的是Element-plus的upload组件,然后接入aliyun-oss的sdk。另外就是草稿恢复等功能,其实没什么逻辑难度有点无关紧要,就是查询历史草稿,然后点击恢复就把item传到编辑器里。
待完成实现
草稿箱接口
帖子展示接口
帖子的管理接口
帖子举报接口
帖子数据可视化管理接口