理兔chat开发日记

0.公共部分

0.1aop切面拦截请求判断登录

首先我们的aop本质上就是一个普通类,只是我们加上了@Aspect(啊丝悲的)注解表示为aop切面类和@Component交给spring来管理

然后我们提到切面就一定会有切点,而我们的切点就是我们自己声明的注解类,那切点又有事件的通知类型,有前置通知、后置通知、返回通知、异常通知和环绕通知五种

所以对于我们的拦截器我们用前置通知是最合适的,我们使用@Before就是定义前置通知,在里面加上我们自己定义注解的位置后这个就是切点了

我们通过切面point获得我们声明的切点注解,在判断是否需要判断登录或管理员

1登录注册

1.1.注册

注册跟以前的差不多,我们将我们的验证码放在redis下,我们在注册的时候先判断我们输入的验证码是否正确

验证码成功后在我们的实现类中,我们先判断邮箱是否重复,不重复我们就继续注册

我们拥有靓号注册的功能,就是我们可以通过靓号添加好友,所以我们判断是否有靓号并且未使用,有就将该用户的userid设为靓号的id

我们在封装如用户名、邮箱等数据到数据库,如果我们注册有用到靓号我们将该靓号的状态修改为已使用

而后我们要创建机器人好友,我们现从redis中获取我们保存的机器人设置,我们要用户注册登录后发送消息,所以我们将增加机器人为好友平且增加会话信息,也就是主界面的聊天框

然后我们将该机器人添加到会话人消息中和添加聊天消息中,这样我们在将数据传给前端我们在登录后就可以看到机器人的消息了

2.登录(有存联系人到redis)

在登陆中我们先判断用户数据是否有误,如密码错误或邮箱不存在等

无误的话我们就将数据填入token类中

然后我们将该用户下的联系人(好友和群)添加到redis中,但我们要先将该用户的联系人清空,防止有错误,添加到redis方便我们用ws给联系人发送消息

创建我们用户的唯一登录token后将token保存到redis中

最后封装返回到前端

2.群组相关

2.1创建群组

我们先用HttpServletRequest中的getHeader方法获取我们表头里的token来跟我们创建群组的用户的数据,也就是当前登录用户登录的数据

然后我们将用户名、群id等数据添加到GroupInfo类中,也就是我们的java和数据库之间的对应类

在我们的实现类中我们先判断groupId是否存在,不存在就是新增,反之为修改,然后我们判断该用户创建了多少个群,如果超过了我们的设定值就不让他创建

然后补全我们的数据,如当前时间和创建一个11位随机数的groupId等,后把它们添加到数据库中

然后将群组添加为联系人,也就是将创建的群添加到联系人列表中

而后我们要创建会话,也就是主页面的聊天框,跟添加联系人里的差不多,也是创建会话用户,但只创建自己,不是双向创建,因为群不需要添加好友,只用添加人加就行了,可以降低数据库压力

接下来就创建消息和发送消息就行了

再修改中,我们要先判断登录用户id和修改群的群组id是否一致,因为有可能有人跳过前端修改不是他的群,最后调用update修改

最后实现图片上传

2.2查看当前用户下的群组

获取登录数据将当前登录用户的id作为群主id查数据库

2.3查看群的详细页

通过群主id查数据库就可以获取当前查看群的详细页

2.4获取聊天会话群聊详情

我们先获取群组的基本信息,然后,创建一个UserContactQuery对象并设置其属性,用于查询与群组相关的用户联系人信息,设置了联系人ID为群组ID、查询用户信息、按创建时间升序排序,并且只查询状态为“好友”的联系人,然后根据查询条件获取用户联系人列表,最后创建一个GroupInfoVO对象,用于封装群组信息和用户联系人列表,然后将这些信息设置到GroupInfoVO对象中

3.搜索相关

3.1搜索

我们在实现类中先获取搜索的前缀,判断是用户还是群组,然后调用数据库查数据

最后我们填充数据和判断查找的是否是好友就行了

3.2申请添加好友

我们首先判断添加的这个ID是否存在,毕竟你已经提交了添加请求,如果这ID不存在,表示你根本就没走前端,直接给他报错就行了

然后获取申请人用与我们写默认的一个申请句,我们再判断一下这个好友是否已经添加过了,或者是否已经被拉黑了,如果被拉黑了,就给他提示已经被拉黑了无法添加

然后我们通过获取开头字母判断添加的是群还是用户,是用户就获取被添加用户的添加类型,是直接加入还是要通过,直接加入的话我们就调用添加联系人方法

在判断是否有过申请记录,没有就创建,有就修改之前的状态,本质上就是给数据库中添加我们的申请数据,填充如申请用户ID、接收用户ID、联系ID、添加类型等数据,而后提交到数据库中

最后我们给被添加用户发送消息,这样我们的页面就可以实时提示新的申请

3.3获取好友申请列表

通过当前用户的userId去查申请表user_contact_apply,然后我们要实现如果是添加用户就显示用户的名称,如果是群组就显示群组的名称

3.4处理申请

我们在实现类中先判断用户处理的申请是否走了前端,如id是否存在、状态是否正常等

而后我们创建一个新的UserContactApply实例updateInfo,并设置其状态为枚举实例获取到的状态值,同时设置最后申请时间为当前系统时间,接着创建一个UserContactApplyQuery实例applyQuery,并设置其申请ID为applyId,状态为初始状态。这个查询条件用于后续更新操作中定位需要更新的记录。

如果申请后被拉黑我们就不让用户在提交申请

3.4.1添加联系人

我们判断是否拉黑后我们就要实现添加联系人的方法了,因为我们申请中有直接通过的功能,所以我们要先判断申请的是用户还是群组,是群组的话我们要先判断当前群人数是否已满,我们通过将申请群的id通过数据库查出在数据库下有多少条记录,这个结果就是我们当前群的人数,我们再通过redis获取设置的最大人数,如果超过了我们就提示成员已满

然后我们就准备添加好友了,我们先将申请人的数据放到一个集合中,后面我们也会放接受人或群的数据放到集合,方便我们统一提交数据到数据库

接下来我们要判断是添加好友还是添加群如果是申请好友,接收人添加申请人,群组不用添加申请人好友,是好友的话我们再获取接收人的数据添加到集合中后批量插入和添加到redis中

我们同意后就要创建会话了,也就是新建一个聊天框然后通知双方,也是先判断添加的是用户还是群,是用户我们添加会话用户信息

然后我们为申请人和接受人记录他们在该会话中的角色(通过userIdcontactId区分)和会话ID,从用户信息表中查询并设置对方的昵称(contactName),将这些会话用户信息批量保存到数据库中

创建一个ChatMessage对象,用于记录这次添加好友的请求,包括会话ID、消息类型(添加好友请求)、消息内容、发送人信息、发送时间、联系人ID和联系人类型。将这条消息保存到数据库中。

ChatMessage对象的信息复制到MessageSendDto对象中,以便于发送。使用消息发送服务(messageHandler)发送消息给接受人,通知他们收到了一个添加好友的请求。修改消息发送对象(MessageSendDto)中的消息类型和联系人ID,以及可能的扩展数据(如接受人的用户信息),然后发送给申请人,通知他们已发送添加好友的请求。

如果是添加群我们也是先将添加人添加到会话用户中

而后我们获取用户信息来提示群里有新用户和添加会话消息

然后将群组添加到联系人和将联系人通道添加到群组通道中(广播),最后获取群员数量后发送群广播

3.5获取联系人

我们获取联系人要判断获取用户还是群,所以我们先判断前端传的数据类型是否为空先,为空就不是走的前端

从token中获取登录数据后判断要获取用户还是群

然后我们设置我们状态查询条件,只有好友、被删除和被拉黑可以查到,其他的都查不到,最后把数据返回给前端

3.6获取联系人小框的详情

我们获取联系人详情通过前端传过来的contactId查数据库,将数据封装一下就好了

3.7获取联系人的详情

跟上上面那个没有太大的差别,上面是用户可以看不是好友的,也就是我们后面看群组成员的时候方便,下面是必须是好友

3.8删除或拉黑好友

我们删除和拉黑不是用的同一接口,但用的是同一实现类,删除和拉黑我们都先移除好友,但我们不是物理删除数据库,而是更改他的状态,然后判断是删除还是拉黑后更改对方的自己状态,总而言之就是修改双方的状态        

4.用户相关

4.1获取用户信息

从token中获取当前登录数据后用userId查数据库就可以了

4.2修改用户信息

我们通过前端传的数据是没有密码和状态之类的,但有人可能不走前端修改我们的数据,所以我们要把传过来的数据删除掉我们不要的


判断是否上传头像,通过yml文件中获取的存放地址后用IO来上传头像,然后我们查出要修改的用户id,再调用数据库修改数据

4.3修改密码

修改密码就是将密码覆盖后强制退出就行了

4.4退出登录

5.管理后台

5.1管理后台获取用户列表

判断是管理员后倒叙查就行了

5.2禁用启用用户

判断传入是否正确后调用数据库覆盖status的值就行了

5.3将用户强制下线

5.4获取靓号列表

通过id倒序查数据库

5.5新增靓号

我们再新增的时候要判断很多条件,有判断靓号是否被使用、新增或修改时邮箱是否存在、靓号是否存在、靓号id或靓号邮箱是否已经被使用等

最后我们通过id是否存在判断是新增还是修改

5.6删除靓号

通过id直接删除数据库中的数据

5.7管理后台获取所有群组

判断是管理员后倒叙查就行了

5.8解散群组

我们要获取获取群主信息,解散时用作对比,防止其他用户跳过前端去删除群

在实现类中通过群组ID查询群组信息,然后判断和删除的群主是否是同一个人,然后修改数据库中群的状态,将他逻辑删除,然后指定要更新的联系人信息,将他们下的该群的好友状态改为删除

5.9获取系统设置

5.10保存系统设置

我们先检查机器人头像是否上传,没有就跳过,然后从数据库中获取文件存放位置后判断文件夹受否存在,而后上传新的头像到文件夹,最后调用redis保存新的数据

5.11获取更新列表(灰度发布)

我们的更新斑斑要实现灰度发布,灰度发布就是先给一部分用户更新,通过这一部分用户的测试无误后我们再全网发布,对于获取更新列表,我们直接查数据库就行了

5.12更新版本

我们先将前端传过来的数据封装到AppUdate类中

而后再实现类中,我们先判断时什么上传类型

然后我们要保证新的版本一定要比旧版本大,我们通过判断可以保证新的版本一定要比旧版本大,我们是通过倒序查数据并取第一条,也就是最新一条,这样我们就获取了获取最新一条版本号,然后将字符串切割成数字用于比较,这样我们就能保证当前版本号不存在且版本号大于历史版本

通过判断id是否存在,不存在就是新增,给他创建一个当前时间和状态,存在就是修改,直接把封装的AppUpdate对象传进去修改就行了

5.13删除版本

5.14发布版本

通过AppUpdateStatusEnum.getByStatus(status)方法根据传入的status获取对应的枚举实例statusEnum。如果statusEnumnull,说明传入的status没有对应的枚举值,此时抛出异常。如果当前状态是灰度发布,并且灰度用户ID为空或无效同样抛出异常。如果当前状态不是灰度发布,则将灰度用户ID置为空字符串,表示全网发布时不涉及特定的灰度用户。创建一个AppUpdate对象,设置其状态为传入的status和更新后的灰度用户ID,然后根据id更新数据库中的记录。

5.15前台检测更新

我们每次登录都会检测更新,但不是每次都有新版本或数据不报错,所以有报错我们也只是不处理

然后我们要判断给用户是否有新版本,我们通过ID倒序排除第一条数据,就是我们最新的版本,在sql语句中我们首先要查当前版本和最新版本是否是同一条,免得我们更新之后一直给我们弹还要重新更新,然后我们要判断用户是否有权限更新,比如我们最新版本是全网发布,或者该用户他是我们灰度发布下面允许的用户

我们通过sql查后如果该用户没有新版本我们就跳过更新

我们将据copy到返回前端的vo类中,然后判断是外链上传还是本地上传,是本地上传就获取文件大小,获取需要更新的用户后提示用户更新

6.使用netty实现聊天功能

6.1初始化netty打通ws连接

我们要先创建一个类名为NettyWebSocketStarter用于我们实现初始化netty打通ws,我创建一个ServerBootstrap的实例用于设置服务器的辅助启动器,设置两个EventLoopGroup用于我们异步实现io操作,bossGroup用于接收客户端的连接 workGroup用于处理网络IO操作,如读取数据和发送数据

而后指定使用Nio的ServerSocketChannel作为服务器的通道实现和设置日志等级

而后我们为每个客户端连接提供了初始化,如对http协议的支持使用http的编码器和解码器、聚合解码保证接收的http请求的完整性、读写心跳超时判断、将http协议升级为ws协议,对websocket的支持和自定义的WebSocket处理器等重要的处理器

这是我们通过在yml绑定的ws连接的端口中异步启动等待连接成功,异步是防止程序一直等待连接导致我们正常的功能也受到影响

6.2ws连接和用户基础信息

在我们上面的ServerBootstrap等待我们的连接成功后我们就要判断是否能让该用户发消息了,在我们上面提到的自定义的WebSocket处理器中,我们继承了SimpleChannelInboundHandler类下的功能,当中有userEventTriggered方法,我们在该方法下判断传入的事件类型是否是WebSocketServerProtocolHandler.HandshakeComplete,这个是WebSocket握手完成后触发的特定事件类型,是我们就获取连接的路径和token,而后判断是否取到token和token的数据是否与数据库中的一致,通过后我们的握手协议就通过了,而后我们调用我们自己写的addContext方法将该次连接的唯一id存在缓存中和获取联系人等操作后用户就可以发送信息了

我们的获取token是通过将路径传入的token参数切割出值

在我们addContext方法中发送消息后判断id是否存在缓存中,没有就存,并且我们也将该用户的心跳过期时间存到redis中,使用时获取一下id就可以判断是哪个用户了,最后更新最后登录时间

并且我们从从redis中取出该用户的联系人,一个一个判断是群还是好友

而后我们通过上面的方法得到该用户下的群组后在缓存中通过群组id获取群的信息,没有就创建将群组添加到缓存中,而后将该用户添加群组缓存中,这样我们发送消息时从缓存中将在该群id下的用户也发消息,就实现了接收群消息的功能

6.3查询聊天消息

然后我们的主界面的新数据我们只查7天内的,我们连接成功后就修改最后更新时间,然后通过id获取最后离开时间,如果之间超过了7天我们就查7天的数据,如果没超我们只查差的天数,防止数据重复

然后我们查询会话信息,可以保证我们的程序在更换新设备后还有聊天消息,就是我们登录后的主页面有聊天信息

而后我们要查询给用户的联系人发的聊天消息,我们要有区分,因为我们的聊天消息会有很多,我们不能像好友申请表一样给消息发送方和接收方都写一条数据,是群的话一个人写一条,群里有200人就会有201条数据,这样我们的数据库压力会过大,所以我们存哪个用户发的消息,我们有接受方字段,我们查询如过是群我们就判断给用户是否在群里,查询是用户的话我们正常差就行了

我们多集群部署后如果用户1连接我们的服务器1向用户2发送消息,这时我们无法保证用户2也链接在服务器1上,所以我们将用户发达消息先统一送到redisson中,由redis下发到所有的服务器上

6.4好友聊天

我们先把用户发送的消息获取下来,主要是判断用户发的是普通消息还是媒体消息

我们在方法中先判断是不是给机器人发的消息,如果不是我们在redis下查发送人有没有接受人或群的好友,没有就提示已被删除

然后获取发送者ID和接收者ID,因为可能是用户或群组,所以我们根据接收者类型生成会话ID,记录当前时间作为消息的发送时间,检查消息类型是否为系统允许的,不是就报错

判断是普通消息就已发送,媒体消息就发送中,清理消息内容中的HTML标签,确保内容安全

然后更新我们的会话和消息表,让我们主页面上有新的内容

如果我们是向机器人发的消息,我们就可以调用我们的ai来对话,在最后发送消息就行了,这样我们就实现了发送消息的功能

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值