Web端即时聊天项⽬实现(基于WebSocket)
Web端即时聊天项⽬实现
项⽬背景
其实这个项⽬算是我做过的花时间最长也投⼊⼼⾎最多的⼀个项⽬了,当时决定开始做这个的时候我⼏乎什么都不会,那时我个⼈的情况是:
JavaEE⽅⾯:
会jsp+servlet,也简单使⽤过Struts,Spring仅仅只是听说过。
前端⽅⾯:
html,css有⼀些基础,会使⽤Bootstrap前端⼯具开发集,js基本不了解。
数据库相关
那时还没有学习数据库这门课程,但是熟悉jdbc与数据库的连接,会基本的增删改查SQL语句,简单使⽤过Hibernate
⽹络编程相关:
通信相关的知识也仅限于计算机⽹络课程上学习的简单的Socket。
在那种情况下,我决定来做这个即时聊天的项⽬,先定下使⽤SpringMVC+Hibernate作为后端框架,然后⼀步⼀步查资料寻和学习通信和前端相关的知识和解决⽅案,最终花了⼏个⽉时间完成了这样的⼀个项⽬,基本达到了预期的功能。但是更重要的是在这个过程中,我学会了很多东西,⽐如遇到问题应该怎么解决,常⽤开发借助哪些⼯具之类的,学会了使⽤SpringMVC框架来快速进⾏开发,学会了js原⽣的语法等等。尽管在没⼈指导⾃⼰瞎摸的情况下完成这个项⽬真的花了很多的时间和精⼒,但是最后的成果和学到的东西让我感觉这些都是值得的。
web端登录 废话这么多的原因⼀个⽅⾯是想让以后的⾃⼰记得当时完成这个项⽬的⼼情,另⼀⽅⾯也是想告诉可能看到这篇博客的⼈,或许你也想做⼀个Web端即时聊天的项⽬,在漫⽆边际的搜索中从某⼀个旮沓⾓落⾥发现了这篇默默⽆闻的博客,你要相信尽管现在可能你会的很少,但是只要花时间踏实地去学习去研究,最终⼀定能够做出来⾃⼰想要做的项⽬,也能从这个过程中学习到很多东西,站在这个项⽬的基础上以后快速的开发出更多的更优秀的项⽬,学习更多的技术~
前⾯我会把演⽰⽅式和代码放出来,之后我会把⾃⼰在学习和查阅资料的记录⼀⼀整理⼀下写出来,可能没有什么条理,很多地⽅可能会有错误和幼稚的想法,请见谅也欢迎指正。
项⽬演⽰
演⽰地址:
演⽰说明: 请在浏览器中两个标签页中打开这个⽹址,⾃⾏注册两个账号,然后搜索添加彼此为好友,即可进⾏聊天。(同⼀个浏览器不同标签页可以登录不同的账号不会发⽣冲突)
Bug反馈: 左边QQ加反馈或者发送邮件⾄:guoxiaofeng_2015@163。
源码
(欢迎follow,star提issue~)
项⽬功能
项⽬最开始,需要明确⾃⼰想要做是什么东西,想要完成什么功能。
这⾥啰嗦⼏句,其实这个项⽬最开始的设想的功能列表并不是这样的,这些是最后实际实现的功能,但是因为和最初设想地也差不多,这⾥就直接放出来了:
Web端:
注册、登录功能
查看所有好友、组
查好友、添加好友(可以附带验证消息)
⼀对⼀聊天
创建组、查看组成员、邀请好友进
聊
Android端:
注册、登陆功能
查看所有好友、组
⼀对⼀聊天
聊
注意: 这篇博客中完成的项⽬不⽀持⾼并发甚⾄可以说是并发性很差,⾮常差,我测试过我的⼩菜鸡服务器200个连接的时候就会出现⽆法建⽴连接的情况,300个以上时绝⼤多数连接都会⽆法建⽴。这⾥的项⽬只是完成了基本的聊天功能,如果想要考虑⾼并发的话请去查阅更多资料。我最近也在重构项⽬,想要尽量提⾼并发性,⽐如使⽤Netty作为聊天服务器,使⽤Nginx来进⾏负载均衡,使⽤Redis辅助缓存,来提⾼数据库访问速度,使⽤protobuf代替json来节约流量,优化转发,查询的逻辑等等~ 有这⽅⾯需求的可以深⼊研究⼀下互相交流交流~我也正在研究中。。
模块划分
根据⾃⼰对JavaEE项⽬的认知,先把项⽬分为⼏个模块,弄清楚各个模块的依赖关系,然后弄清楚从哪⾥⼊⼿开始做,⼀点⼀点来完成。
本项⽬主要分为以下⼏个模块:
数据库:
数据库设计与创建
服务器:
数据库访问(DAO)
业务逻辑处理(Service)
请求控制(Controller)
通信服务器端(WebSocket Server)
Web端:
前端UI
逻辑处理(js)
通信客户端(WebSocket Client)
Android端:
界⾯UI
逻辑
通信客户端(WebSocket Client)
模块⼤致分这些应该没什么⼤问题,因为我是⾃⼰做的,也不知道真正标准的流程到底是什么,但是我的话是从数据库开始设计的,当然最初版本的数据库是不完善的,后⾯根据实际需要进⾏了很多次的修改。所以设计数据库的时候要尽量考虑周全,考虑完善⼀些,可以减少返⼯的次数和时间。不过很多数据库技巧需要有项⽬经验才能积累出来的,如果刚开始学习的话尽量参考别⼈的数据库设计并且多思考思考,回头修改是难以避免的事情,也不⽤最开始就太追求完美。
⾄于这⾥为什么就决定使⽤WebScoket了,WebSocket是什么,这⾥可以先不⽤在意,我最开始也是不知道WebSocket的存在的,做项⽬的过程才慢慢知道了解的,看后⾯我杂乱的记录就知道了。
项⽬所⽤框架和⼯具
下⾯所说的⼯具也是我慢慢摸索最后所采⽤的,如果不了解的话真的建议去了解⼀下,可以少踩很多我当时踩过的坑。
开发⼯具
开始使⽤MyEclipse,后来转Intellij IDEA
前端写html,css基本样式使⽤Sublime Text 3(修改反馈速度较快),写js并且与后端调试是使⽤Intellij IDEA
/* 个⼈建议:直接使⽤Intellij IDEA,尽管没⽤过可能刚开始觉得不顺⼿,可是熟悉以后你就会发现IDEA的强⼤之处。前端的话如果⾃⼰没有前端⼯程的基础(Node.js,Vue,React等),以后也不想向前端发展的话,不是很建议专门去学习这些,简单的html 和js使⽤Bootstrap⾜矣完成本项⽬。JSP是否使⽤可以看个⼈,直接使⽤HTML跨域也不是不⾏。
*/
依赖管理和版本管理
依赖管理
Maven
/* 个⼈建议,千万不要因为没学过觉得⿇烦就不⽤Maven了,否则你浪费在不必要的寻各种jar包下载和解决各种奇奇怪怪的版本错误上浪费的时间要远远多于你学习Maven的时间,⽽且解决那些问题浪费的时间是真正的浪费,即便最终解决了也不会给⾃⼰的能⼒带来有效的提升。 */
数据库
MySQL
/*
数据库个⼈感觉其实都可以,可以为了学习换⽤MongoDB也⾏,只是建表(数据集合)就要⾃⼰改了。同时也可以考虑添加Redis作为辅助数据库,最近我在重构这个项⽬,就在考虑这⽅⾯的事情。
*/
后端框架
Spring MVC + Hibernate
/* 有基础建议使⽤Spring Boot,开发更为快速简洁⼀些,我那个时候为了学习SpringMVC⽽且也没听说过Spring Boot才使⽤的这个,WithMe重构版本就换⽤了Spring Boot,但是现在还在开发中,并不会放出来 */
通信协议
WebScoket
/* 这个可以去www.52im看⼀些相关的资料,WebSocket和SSE都是⽐较不错的选择,WebSocket与Socket的不同⾥⾯也有介绍 */
第三⽅jar包
Java-WebScoekt
Github主页:
/* 这个⼯具当时可以说是解决了我的燃眉之急,WithMe1.0中没有使⽤这个jar包,使⽤的是JavaEE 7.0⾃带的
WebSocket,结果Android端建⽴连接⼀直出错(可能是我不太会⽤),2.0中使⽤的是这个jar包,如我之前所说,如果你考虑地更多想做地更好的话,你有更好的选择,,Netty,Mina等等 */
前后端数据交互格式
json
/* 这个真的不⽤说,Web开发必备知识之⼀,必须学习 */
前端框架和⼯具
Bootstrap 这是⼀个⾮常流⾏的前端⼯具开发集,可以借助这套⼯具进⾏快速得前端开发,官⽹主页:
Layer.js ⼀个基于Jquery的弹出层解决⽅案,可以说我这个项⽬的前端基本就是依靠这个插件建⽴起来的,官⽹主页:
(注意区分LayerUI和Layer.js,前者是类似于Bootstrap的前端开发⼯具集,后者只是⼀个插件,⽽且后者是开源的,本项⽬中只是⽤了后者。)
原⽣javascript语法
Android端⽐较简陋,到时候可以⾃⾏参考代码。
下⾯开始是我在完成项⽬中所作的⼀些记录,可能会有些杂乱,我基本是想到哪⾥记到那⾥,希望能对做这个项⽬的⼈起到⼀些参考作⽤。⼀年前的⾃⼰,可能有很多不成熟的想法和错误的认知,重要的错误认知我会简单添加说明,但是依然可能存在错误:因为我现在依然在学习的路上,也不能说我现在知道的就是对的。如果看到错误⼤家能够指正,我也⾮常愿意修改。
数据库
所⽤到基础知识:SQL建表语句等
关于具体数据库实现:
user_main,user_detail两个表表⽰⽤户。
⽽对于具体的好友关系的实现,经过查资料和思考,⽬前有⼏种可以考虑的实现⽅式:
1. 建⽴⼀个friend表,当两个⽤户建⽴联系时就向表中插⼊⼀条数据,每次⽤户登录就查询这个表,建⽴好友列表。
优点: 建表,好友关系插⼊、删除都⽐较简单
缺点: 当⽤户⽐较多时,每次登陆会对⽤户数据库造成⽐较⼤的压⼒,当⽤户海量时每次登陆会消耗⼤量时间才能列出好友列表。2. 在user_detail表中加⼀项friend,存放好友的list,每次添加好友时,取出改list修改之后存⼊数据库,每次登陆时取出该list。
优点: 列出好友列表快捷。
缺点: 对于数据库如何设置list类型虽然有解决⽅法,但是⽐较繁琐(如序列化,Json转String等等),所以解决⽅案为不建⽴list,仅仅将好友的id(或者user_name存下来),根据资料。MySQL的varchar长度最长为65535个字节,5000以内好友的存储应该没有太⼤问题,⾜以满⾜需求。这样可以在取出数据库信息后经过⼀个⽅法将其转换为list,实现“伪list存储”。但是这种⽅案产⽣的结果就是:好友关系不太明确,添加审核⽆法实现,查询好友关系也不容易实现。
3. 另⼀种替代⽅案是动态创建⼀张好友表,每注册⼀个⽤户就为其新建⼀个好友表,⽤来存储好友关系。
优点: 同2,列表简单,查询也简单。
缺点: 每添加⼀个⽤户就多出⼀张好友表,开销较⼤。
4. 因此经过考虑,我提出了第四种⽅案,仍旧采⽤将好友id存储为String放在user_detail表的⽅法,但是同时也建⽴⼀张好友关系表。
user_detail表中的好友字段作为缓存好友表,设置⼀个标志位,当⽤户没有添加好友的操作标志位为0,直接读取user_detail表中好友id创建好友列表,当⽤户有过添加好友的操作时,标志位改为1,此时从好友关系表中查询此⼈的好友关系,并且对user_detail表中的好友id进⾏更新,同时将标志位置0.
优点: 建⽴好友表不是很⿇烦。(因为添加好友操作不是频繁性操作),查询好友关系简单(直接查询好友关系表)。可以实现,添加好友审核好友的功能。
缺点: 开销虽然没有动态创建表⼤,但是依旧较⼤。
2017/1/22
今天对建表数据库进⾏重构,做了以下调查⼯作:
遇到的问题为:
⽤户的唯⼀标识时拿⼀个逻辑主键呢,还是⽤⼀个业务主键。在项⽬中,具体表现为:是以⽤户名为唯⼀标识,id也为唯⼀标识,通过⽤户名确定⽤户(建⽴索引),另⼀个是直接以⽤户名为唯⼀标识同时也作为主键。
⽽且在具体问题中,当采⽤id标识并且采取⾃增也会出现⼀些问题。⽽我之前的建表语句则会出现更⼤的问题:因为两个表都采⽤⾃增,不能互相修改,也就是说⼀旦有⼀个出错那么在其之后注册的账户统统会错误,user_main和user_detail会全部对应错误。同时,在之后功能的实现中,我发现了⼀个问题,因为User类(即对应user_main)⾥⾯含有密码信息,⽽在实际登录、添加好友、聊天的过程中,需要经常把User类传来传去,以⾄于当我查好友的时候当获取他的user_id和user_name的时候,带着user_password也⼀起传过来了,虽然实际上可能没什么感觉,不输出或者使⽤user_password这个值就好了,但是很显然在理论上存在重⼤的安全问题,这是⽆法接受的。基于以上两个问题,因此有必要对这两个表进⾏重构。⾸先,现在有两种选择:
⼀、使⽤uuid代替⾃增,⽤String类型的id作为主键,同时设置user_name为索引。
⼆、仍旧使⽤int id⾃增作为主键,同时设置user_name为索引。但是对之前的插⼊模式做⼀些修改,避免问题⼀的出现。
前者性能不如后者,但是在分表分库的情况下⽅便(因为⽣成的uuid是时间空间上唯⼀的),⽽后者虽然之前当前表唯⼀,但是性能优于前者。
综合起来,选⽤第⼆种办法,同时对user_main表作出修改。
在重构过程中我在user_detail⾥⾯添加了⼿机、邮箱等信息,避免以后使⽤到这些信息是再次重构数据库。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论