> 文档中心 > 两天开发的网站果然没人用,所以我决定优化一下

两天开发的网站果然没人用,所以我决定优化一下


  • J3 - 西行
  • 杂文(小夹子 # 开发)

上周末在家封闭了两天,就为了解个心结做个小夹子网站出来,最初的功能就是单纯的把我所看过的文章、资料保存起来,方便以后统计、回顾。

并且我也是紧接着出了一篇相关文章来说明这件事,大家有兴趣可以看我的这篇文章👉《两天开发个网站,不为别的就为存点小资源》。

那,网站开发出来之后呢,我也是自己使用了几天,因为圈子小只能自己当用户了,哈哈!在使用的过程中广场页面中的内容倒是可以正常的获取回显出来,但就是感觉怪怪的,内容总是刷的一下出现和刷的一下消失,这不行,页面交互体验太差了;网站的整体呢是以存储的内容为主的,而内容又是可以私有或共享,当用户把存储的内容共享出来也就意味着可以出现在广场页面上,但这就问题来了。每个内容在用户那都是有个夹子可以很好的分类,但到了广场这里的话,就谈不上分类这一说了,所以广场页面要改,或者说要新增一个内容分类或内容标签的功能;在我的页面中关于我的介绍这块区域我觉得没有必要再留了,它在首页也就是广场页面显示就行了,转换到我的页面时就可以把这块区域留出来放更有意义的内容比如站内公告、精选内容、随机内容等;用户的内容分类我觉得也有必要优化一下就是增加个统计功能,再每个分类的右上角回显该分类下存储的内容数,让用户更加清楚的知道自己存了多少东西。

上面我说了挺多优化的,那我稍微整理一下:

1、页面内容刷新,增加加载效果,提升使用体验。

2、内容新增分类功能,在广场首页做个分类导航,这块可能是个比较大的功能。

3、我的页面中关于我的介绍去掉,换成更有意义的内容显示如:公告内容、精选内容、站内随机内容。

4、优化夹子目录列表,在每个内容目录右上角增加目录内容总数。

《一》

下面就是无尽的优化之路了,先来看第一点分析:

加载效果,这玩意前端处理就行了,在用户点击内容查询或第一次查询内容的时候,让页面在没有出现内容之前显示一个正在加载的效果就行了,而且 Ant Design 框架是有可供响应组件的。

那这就快活了,不用自己干,拿来主义真香!在对着文档一顿查阅就有了如下代码:

登 录
// import request from '@/utils/request' export default { data() { return { // 数据中心 spinning: { loginLoad: false } } }, // 自定义方法 methods: { login() { // 发送 API 之前显示加载效果 this.spinning.loginLoad = true // 发送API 请求 // 在这里发送一个 API 请求 // 请求成功或失败之后,将加载状态置为 false this.spinning.loginLoad = false } } }

这只是一个简单的按钮增加一个旋转加载的效果,在小夹子网站的页面上是有很多个这种类似的按钮,这也意味着我要一个个的加上这些类似功能代码。我不知道大家前端加上加载效果是怎么样的,如果有更好或统一处理加载效果的可以评论区说说你们的处理方式哈!

效果如下:

在这里插入图片描述

《二》

下面就是个重点功能了,给内容做分类处理

我稍微分析了一下,这个功能是一个水平扩展,对现有功能不会有任何影响,并且在后续的内容推荐上是由异曲同工之处。

这个功能要重新设计一张内容类型表出来,并且还要有一张内容与分类进行关联的中间表,每个内容关联多个分类,所以是一对多的关系。这里所涉及的两张表SQL如下:

##内容类型表,类型名称做唯一键CREATE TABLE `small_clip_content_type` (  `id` bigint(20) NOT NULL AUTO_INCREMENT,  `name` varchar(20) COLLATE utf8mb4_croatian_ci DEFAULT NULL COMMENT '内容类型名称',  `sort` int(4) DEFAULT NULL COMMENT '排列权重',  `create_time` datetime DEFAULT NULL,  `update_time` datetime DEFAULT NULL,  `creator` varchar(50) COLLATE utf8mb4_croatian_ci DEFAULT NULL,  PRIMARY KEY (`id`),  UNIQUE KEY `un` (`name`)) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_croatian_ci##内容和类型的关联表,内容ID和类型ID关联为一个唯一键CREATE TABLE `small_clip_content_to_type` (  `id` bigint(20) NOT NULL AUTO_INCREMENT,  `content_id` bigint(20) DEFAULT NULL COMMENT '内容id',  `content_type_id` bigint(20) DEFAULT NULL COMMENT '内容分类id',  `create_time` datetime DEFAULT NULL,  `update_time` datetime DEFAULT NULL,  `creator` varchar(50) COLLATE utf8mb4_croatian_ci DEFAULT NULL,  PRIMARY KEY (`id`),  UNIQUE KEY `un` (`content_id`,`content_type_id`)) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_croatian_ci

接下来,要干的活就是code代码了,主要为下面三部分:

  1. 给分类表做个查询列表功能,暂不分页,直接一次全查。
  2. 修改内容保存功能,保存时添加内容类型字段。
  3. 查询内容时,添加内容分类条件,根据内容类型查询,如没有分类条件则查询全部。

对于第一部分,后端将会查询整个内容类型表,返回一个列表数据到前端,接着前端拿到数据列表再进行循环渲染数据。而前端用什么来显示这些分类呢!我参考了其他的网站功能,决定用 Menu 导航菜单 这个组件来实现页面渲染,效果如下。
在这里插入图片描述

这里,每点击一个分类标签所查询的内容就是关联表中该类型所对应的内容列表。

那这内容类型下的数据是哪里产生的呢!这就要再保存内容的时候做文章了。再用户添加内容时,我们要添加一个下拉框,让用户选择他们所创建的内容隶属于什么类型,如果不选,那么就不会再任何类型下出现对应的数据,只会再全部中显示。

用户添加内容时,效果如下:

在这里插入图片描述

这里会传一个类型 Id 数组到后端,接着我不知道大家有什么好的插入数据方法,我所实现的方法就是遍历 Id 数组,每次将类型 Id 和内容 Id 插入到中间表中,统一用一个事务进行包裹,部分代码如下:

// 事务transactionTemplate.execute(status -> {    // 插入内容    insertOrUpdate(clipContent);    // 插入到用户内容关联表    userClipService.insertOrUpdate(new UserClip().setClipId(clipContent.getId())     .setClipTypeId(form.getTypeId())     .setUserId(user.getId())     .setDelete(false)     .setCreator(user.getMail()));    if (ArrayUtil.isNotEmpty(form.getContentTypes())) { // 遍历插入到内容类型中间表 Arrays.stream(form.getContentTypes()).forEach(contentTypeId -> contentToTypeService.insertOrUpdate(  new ContentToType()   .setContentId(clipContent.getId())   .setContentTypeId(contentTypeId)   .setCreator(user.getMail()) ));    }    return Boolean.TRUE;});

这里我想你们可以看出一个内容插入,最多会有五次 insert 操作,对于保存操作这种实现不知道会不会有问题,所以大家有啥好的方法可以评论区说出来一起讨论讨论。

接下来就是查询优化了,根据对应的内容类型查询出对应的内容。这里主要是 SQL 的编写,先来分析一下我现在的情况:

  1. 有一张内容表、用户内容关联表、内容类型中间表
  2. 内容表有是否私有这一条件,用户内容关联表中有是否删除这一条件,内容类型中间表有内容所对应的类型 id 字段
  3. 广场数据只查非私有、非收藏、非删除的指定内容类型的数据

分析完毕,就出现了如下的 SQL:

SELECTa.*FROM `small_clip_clip_content` aLEFT JOIN `small_clip_user_clip` b ON a.id = b.clip_id AND a.creator = b.creator<if test="query.contentTypeId != null">RIGHT JOIN (  SELECT DISTINCT c.content_id FROM `small_clip_content_to_type` c WHERE 1 = 1    AND c.content_type_id = #{query.contentTypeId}) d ON d.content_id = a.id</if>WHERE a.is_privates = 0AND b.is_delete = 0ORDER BY a.create_time DESC

最后我发现有一个一对多的关系我没有查出来,就是内容对应的类型列表。上面的语句只是把要展示的内容数据查出来了,而每个类型数据对应的类型倒是没有查出来,通常碰到这个情况,最简单的做法就是挨个遍历内容,根据内容id去中间表把类型找出来。那这就又有个问题了,就是循环遍历操作数据库,肯定是不行的,所以我转换了一下思路,把第一步查出内容 id 全部拿出来,去中间表去重的获取内容对应的类型数据,然后再内存中将数据关系进行绑定。查询类型 SQL 如下:

select  b.*,  a.content_idfrom small_clip_content_to_type aleft join small_clip_content_type b on a.content_type_id = b.idwhere a.content_id in<foreach collection="list" index="index" item="id" open="(" separator="," close=")">  #{id}</foreach>order by b.sort asc

内存中,关系绑定代码如下:

@Overridepublic IPage<ClipContentDTO> publicList(Page<ClipContent> page, PublicClipContentQuery query) {    // 第一步获取内容    var dtoListPage = getBaseMapper().publicList(page, query).convert(converter::converter);    if (dtoListPage.getRecords().size() <= 0){ return dtoListPage;    }    // 映射内容id集合    Set<Long> contentIds = dtoListPage.getRecords().stream().map(ClipContent::getId).collect(Collectors.toSet());    // 操作数据库,查询出内容id集合所设计的分类数据    List<ContentTypeDTO> contentTypeList =  contentTypeService.getContentTypeByContentIds(contentIds);    // 内存中遍历内容列表,将类型数据和内容绑定    dtoListPage.getRecords().forEach(dto -> { List<ContentType> contentTypeList_ =  new ArrayList<>(); contentTypeList.forEach(contentTypeDTO -> {     if (dto.getId().equals(contentTypeDTO.getContentId())){  contentTypeList_.add(converter.converter(contentTypeDTO));     } }); // 关系绑定 dto.setContentTypeList(contentTypeList_);    });    // 返回    return dtoListPage;}

这样一来,就将原来的循环操作优化成了两次操作,还能接受,效果图如下:

在这里插入图片描述

现在网站的广场页面给我的感觉就是有那种专业的味道了,能分类查能标签标识每个内容所涉及的类别,个人感觉非常满意。后面还打算给首页加个搜索框,在站内进行资源搜索不过这个功能要后面再弄,先搁着。

《三》

最后就是我的页面优化了,先给目录列表加个汇总数据,汇总每个目录下的内容数。这也主要是一条 SQL 的事情,具体语句如下:

SELECT t.*, COUNT(c.clip_type_id) AS content_countFROM `small_clip_clip_type` tLEFT JOIN ( SELECT  a.clip_type_id FROM `small_clip_user_clip` a LEFT JOIN `small_clip_clip_content` b ON b.id = a.user_id WHERE 1=1   AND a.is_delete = 0   AND a.user_id = #{userId} ) c ON c.clip_type_id = t.idWHERE 1=1  AND t.user_id = #{userId}  GROUP BY t.id

达到的效果就是这样:

在这里插入图片描述

最后在侧边将关于我的内容改成了如下内容推荐:

在这里插入图片描述

效果的实现就是页面加载,同时发送三个请求,分别获取站内第一条公告信息、精选类别中随机的五条内容以及全部内容中的随机条内容回显到页面进行渲染。这样做的目的就是给用户推荐一下优质内容进行收藏,有助于用户获取更多有用的信息。

以上优化的操作整下了,再次访问小夹子时就感觉大不一样了。没有之间那种简陋的感觉,哈哈!反倒是有种微微高级感,当然我说了不算,大家还是自己感受一下👉小夹子。

这是我为小夹子写的第二篇文章,我不知道能为它写多少次这样的优化文章,但我希望我能坚持每一个的选择,直到尽头。

好了,今天的文章就到这里了,等我下次又有什么好点子再来和大家唠唠。

有任何问题,根据下面联系方式找到我:

QQ:1491989462

微信:13207920596


  • 由于博主才疏学浅,难免会有纰漏,假如你发现了错误或偏见的地方,还望留言给我指出来,我会对其加以修正。

  • 如果你觉得文章还不错,你的转发、分享、点赞、留言就是对我最大的鼓励。

  • 感谢您的阅读,十分欢迎并感谢您的关注。

唱吧电脑版