Rekord
文章33
标签23
分类4
Let’s chatting on web

Let’s chatting on web

项目萌芽

干这行的都知道,程序员开发一定少不了浏览器,或许现在还少不了ChatGPT?

总之我是尽量用各种软件的web端,除非web端没有或者烂到不能用的。

我的电脑上没有安装微信,现在没有,以后也不想有。(QQ倒是装了一个,至少Windows上的QQ还是蛮好用的

但是现在我事实上用的最多的两款社交软件(QQ、微信)都没有Web端。

另外我也经常使用QQ作为跨端文件传输工具,但是手机QQ本地文件存储的位置我一直没能找到,并且其自带的文件过期机制,使得明明是自己传输的文件却做不到收放自如。

基于以上两个痛点,我开始萌发做一款Web聊天软件的想法。

开始动手

最初的动手是在2022年9月-10月。促使动手的原因很简单,需要做一个项目应付软件实训。当时看了市面上大部分的Web聊天系统,基本上都是基于 Vue + Express + socket.io。而我的技术栈是Java后端,前端属于原生级别。不过所幸还是找到了一款相当合适的。

这个就是当时看中的一款:https://github.com/Kanarienvogels/Chatroom

clone到本地,花了好几天将前后端代码都看完了,然后在原来的基础上做了一些规范化操作,并提交了一条PR,奈何原作者已经不玩GitHub了,故最终还是将这条pr关了,如果当时原作者能够响应,或许又是另一个故事了。

于是我索性基于这个项目单开一个项目,取名为 chatting 。然后接下来就是不断地重构、重构。第一次比较大的重构主要是从Spring到SpringBoot,后面的重构主要包括前后端各种地方的代码重写,总之就是在没有添加明显功能的前提下,不断地提高代码的质量和可扩展性。

当代码终于稳定下来后,我发现如果我需要添加新功能居然寸步难行。其中最大的问题在于前端,原因是因为最初的前端就是原生js + jQuery + Bootstrap样式。虽然我改动了不少js代码,但是对于Bootstrap样式我并不熟悉,而且由于大量使用了jQuery,所以js代码和样式以及结构耦合十分严重,经典的改一行出现五行新的报错。

而且当时项目检查的时间也快到了,我就索性开摆拿另一个功能更多的项目顶了上去,此后,项目被搁置了几个月。

前端重写,后端重构

转眼间,毕设就要求选题了,于是我又再次拾起了这个项目。但是这时我是知道这个项目的问题在哪的,于是我花了一周时间学习了Vue框架(说实话中文项目上手还是很快的)。最初使用vue并不十分顺手,因为它和曾经前端的直来直去编写方式有所差异,很多时候完成一项功能需要绕个弯。但是当你写了几千行代码后,这些问题就渐渐不是问题而是习惯了。

前端页面编写的难点倒是不多,但是需要考虑功能的全面性,防止以后又要再加功能改结构和样式,那将是代码灾难。整个页面的设计和编码花的时间不算多,大概一周就写完了,最终的成品和现在的也差不了多少。

接下来主要就是改后端,其实此时完全没必要用上以前的后端,因为除了Netty相关其他部分基本上都被重写了,不过为了情怀嘛,整个项目的后端还是在以前的基础上进行的开发。

中间经历了不少联调适配,反正前后端代码都是在不断地修修补补,最终形成了现在的效果。

demo

更多的话

整个项目开发过程大概就是这样,不过接下来我还想说一些我认为值得一提的过程与结果。

  • 前端的编码设计一直在重构,真真正正的使用到了Vue的各种特性,如store、plugin、mixin、router、services等,也真正的体会到了为什么Vue有这些特性,为什么Vue需要这些特性。
  • 后端的代码也一直在重构,组件也尽量在升级,最近的升级主要是从Mybatis到Mybatis-plus,规范程度向jar包靠拢。
  • 需求和bug采用issue管理,pr分情况使用rebase或者merge。
  • 欢迎合作

项目总结

  • 前端架构

    ├─.github 
    │ ├─dependabot.yml 
    │ └─workflows 
    │   ├─ci.yml 
    │   └─tagged-release.yml 
    ├─.gitignore 
    ├─babel.config.js 
    ├─jenkins 
    │ └─Jenkinsfile 
    ├─jsconfig.json 
    ├─package-lock.json 
    ├─package.json 
    ├─public 
    │ ├─avatar 
    │ │ ├─default_group_avatar.jpg 
    │ │ ├─default_user_avatar.jpg 
    │ │ └─openai.png 
    │ ├─favicon.ico 
    │ ├─img 
    │ │ ├─loading.gif 
    │ │ ├─login_bg.jpg 
    │ │ └─sign-weixin.png 
    │ ├─index.html 
    │ └─upload 
    ├─README.md 
    ├─src 
    │ ├─App.vue 
    │ ├─assets 
    │ │ └─emoji.json 
    │ ├─components 
    │ │ ├─MessageArea 
    │ │ │ ├─MessageArea.vue 
    │ │ │ ├─MessageBottomInputArea.vue 
    │ │ │ └─MessageTopTitle.vue 
    │ │ ├─NavigationZone 
    │ │ │ ├─ApplicationList.vue 
    │ │ │ ├─NavigationApplication.vue 
    │ │ │ ├─NavigationContact.vue 
    │ │ │ ├─NavigationTopSearchBar.vue 
    │ │ │ ├─NavigationZone.vue 
    │ │ │ └─RelationList.vue 
    │ │ ├─SearchArea 
    │ │ │ ├─SearchArea.vue 
    │ │ │ └─SearchAreaBody.vue 
    │ │ └─ToolBar 
    │ │   ├─ToolBar.vue 
    │ │   ├─ToolBarBottom.vue 
    │ │   └─ToolBarTop.vue 
    │ ├─config 
    │ │ ├─api.js 
    │ │ └─openai.js 
    │ ├─main.js 
    │ ├─mixins 
    │ │ └─socketMixin.js 
    │ ├─pages 
    │ │ ├─ChattingPage.vue 
    │ │ └─LoginPage.vue 
    │ ├─plugins 
    │ │ └─apiPlugin.js 
    │ ├─router 
    │ │ └─index.js 
    │ ├─services 
    │ │ ├─api 
    │ │ │ ├─api.js 
    │ │ │ └─index.js 
    │ │ └─request.js 
    │ ├─store 
    │ │ ├─actions.js 
    │ │ ├─index.js 
    │ │ └─mutations.js 
    │ ├─styles 
    │ │ └─common.css 
    │ └─utils 
    │   ├─common.js 
    │   ├─date.js 
    │   └─socket.js 
    └─vue.config.js
    
  • 后端架构

    ├─.github 
    │ └─workflows 
    │   └─ci.yml 
    ├─.gitignore 
    ├─docker-compose.yml 
    ├─Dockerfile 
    ├─Jenkinsfile 
    ├─Makefile 
    ├─pom.xml 
    ├─README.md 
    ├─scripts 
    │ └─local-deploy.bat 
    └─src 
      ├─main 
      │ ├─java 
      │ │ └─com 
      │ │   └─sxrekord 
      │ │     └─chatting 
      │ │       ├─ChattingApplication.java 
      │ │       ├─common 
      │ │       │ ├─Constant.java 
      │ │       │ ├─MessageType.java 
      │ │       │ └─WSType.java 
      │ │       ├─config 
      │ │       │ ├─UriConfig.java 
      │ │       │ └─WebMvcConfig.java 
      │ │       ├─context 
      │ │       │ └─AppContext.java 
      │ │       ├─controller 
      │ │       │ ├─AdminController.java 
      │ │       │ ├─FileController.java 
      │ │       │ ├─GroupController.java 
      │ │       │ ├─MessageController.java 
      │ │       │ ├─RelationController.java 
      │ │       │ └─UserController.java 
      │ │       ├─dao 
      │ │       │ ├─FileContentDao.java 
      │ │       │ ├─FileDao.java 
      │ │       │ ├─GroupDao.java 
      │ │       │ ├─ImageContentDao.java 
      │ │       │ ├─MessageDao.java 
      │ │       │ ├─RelationDao.java 
      │ │       │ ├─TextContentDao.java 
      │ │       │ └─UserDao.java 
      │ │       ├─exception 
      │ │       │ └─GlobalExceptionHandler.java 
      │ │       ├─interceptor 
      │ │       │ └─UserAuthInterceptor.java 
      │ │       ├─model 
      │ │       │ ├─po 
      │ │       │ │ ├─File.java 
      │ │       │ │ ├─FileContent.java 
      │ │       │ │ ├─Group.java 
      │ │       │ │ ├─ImageContent.java 
      │ │       │ │ ├─Message.java 
      │ │       │ │ ├─Relation.java 
      │ │       │ │ ├─TextContent.java 
      │ │       │ │ └─User.java 
      │ │       │ └─vo 
      │ │       │   └─ResponseJson.java 
      │ │       ├─service 
      │ │       │ ├─ChatService.java 
      │ │       │ ├─FileService.java 
      │ │       │ ├─GroupService.java 
      │ │       │ ├─impl 
      │ │       │ │ ├─ChatServiceImpl.java 
      │ │       │ │ ├─FileServiceImpl.java 
      │ │       │ │ ├─GroupServiceImpl.java 
      │ │       │ │ ├─MessageServiceImpl.java 
      │ │       │ │ ├─RelationServiceImpl.java 
      │ │       │ │ └─UserServiceImpl.java 
      │ │       │ ├─MessageService.java 
      │ │       │ ├─RelationService.java 
      │ │       │ └─UserService.java 
      │ │       ├─task 
      │ │       │ └─FileTask.java 
      │ │       ├─util 
      │ │       │ ├─FileUtils.java 
      │ │       │ ├─HeaderUtils.java 
      │ │       │ ├─JsonMsgHelper.java 
      │ │       │ ├─JwtTokenUtils.java 
      │ │       │ ├─RedisUtils.java 
      │ │       │ └─WrapEntity.java 
      │ │       └─websocket 
      │ │         ├─HttpRequestHandler.java 
      │ │         ├─WebSocketChildChannelHandler.java 
      │ │         ├─WebSocketServer.java 
      │ │         └─WebSocketServerHandler.java 
      │ └─resources 
      │   ├─application.yml 
      │   ├─banner.txt 
      │   ├─mapper 
      │   │ ├─file-mapper.xml 
      │   │ ├─filecontent-mapper.xml 
      │   │ ├─group-mapper.xml 
      │   │ ├─imagecontent-mapper.xml 
      │   │ ├─message_mapper.xml 
      │   │ ├─relation-mapper.xml 
      │   │ ├─textcontent-mapper.xml 
      │   │ └─user-mapper.xml 
      │   └─sql 
      │     ├─data.sql 
      │     └─schema.sql 
      └─test 
        └─java 
          └─com 
            └─sxrekord 
              └─chatting 
                ├─config 
                │ ├─DruidTest.java 
                │ └─FastAutoGeneratorTest.java 
                ├─dao 
                │ ├─GroupDaoTest.java 
                │ ├─MessageDaoTest.java 
                │ └─RelationDaoTest.java 
                ├─model 
                │ └─vo 
                │   └─ResponseJsonTest.java 
                ├─service 
                │ ├─FileServiceTest.java 
                │ ├─GroupServiceTest.java 
                │ ├─MessageServiceTest.java 
                │ ├─RelationServiceTest.java 
                │ └─UserServiceTest.java 
                └─util 
                  ├─FileUtilsTest.java 
                  ├─JwtTokenUtilTest.java 
                  └─RedisUtilsTest.java
    
  • 功能特色

    • 实现群组和好友的完全管理
    • 支持多种消息格式
    • 消息记录持久化与懒加载
    • 使用JWT作为token,安全性更高
    • 前端会在用户无感知的前提下自动鉴权
    • 文件管理十分精巧,不误删、不滥存

最后

希望自己不忘初心,能坚持更新维护吧!

本文作者:Rekord
本文链接:https://sxrekord.com/chatting/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可
×