WhiteHole开发随笔(在线多用户消息发送)

136 阅读5分钟

前言

很不容易哈,最近事情比较多,也是终于抽到空,水那么一两篇博文了。那么咱们速战速决,要源码的朋友得等等,因为还在开发当中。不过这块的话我会准备两个版本,一个就是很随意的版本,也就是现在写的版本,这个方便理解里面的功能实现。还有一个版本就是优化版本,代码会看起来更舒服,一开始我是想好好写的,但是一方面时间问题断断续续的,还有一方面也是懒,不想去整理,毕竟直接cv比造一些小轮子要快。

效果

首先我们可以看到这里有一个用户,叫做Huterox03 在这里插入图片描述 之后是我们的第二个用户Huterox

在这里插入图片描述

Test社区是Huterox03用户创建的社区,当这个用户点击,选择加入自己的社区的时候会提示不行。 在这里插入图片描述

WhiteHole社区是用户Huterox创建的社区,此时Huterox03用户点击加入WhiteHole社区 在这里插入图片描述

这个时候,在Huterox用户的消息页面当中,就会出现这个消息,以及对应的消息提示 在这里插入图片描述 点击消息的头部,还可以查看到对方用户的用户信息页面,然后这个信息页面的关注按钮变成了这个同意按钮(我是打算重新设计一个页面的,但是这个还是以后再说吧) 在这里插入图片描述

之后当Huterox作为管理员,同意之后的话,Huterox03会受到消息,然后可以查看到消息,还可以看到对应的由nutty消息服务器传过来的消息。 在这里插入图片描述

可以看到此时接收到的消息的列表。 在这里插入图片描述 效果大概就是这样的。

流程

技术难度的话,几乎没有,说白了还是CURD那一套,只是中间调用了一些其他的服务来完成业务罢了,写这个烦的只是接口调试罢了。 在这里插入图片描述 此外这里值得一提的是,这里对与社区的创建者是保密的,不会在用户的界面展示,但是后台还是可以查看的,主要是出于对创建者的保护(好吧是我忘了写展示页面了)

搞清楚了这个那么接下来就简单了。

这里前端代码我就不给了,无非是socket网络连接,然后接受罢了。而且代码先前也是给过的。

所以的话,我们来聊聊这个服务之间的一个推送。

请求服务

判断当前用户

首先是我们需要对当前的用户进行一个判断。 是不是社区的创建者,然后前端提交的这个userid到底是不是存在的。虽然咱们这个一开始会先进行一个校验,但是为了安全嘛,理论上来说,通过了token校验,用户是存在的。但是这种事情保险一点总没错。

        String userid = joinQ.getUserid();
        Long communityid = joinQ.getCommunityid();
        String backMessage = "已经通知社区管理员请等待哟~";

        if(redisUtils.hasKey(RedisTransKey.getRedisJoinCommunity(userid+"_"+communityid))){
            return R.error(BizCodeEnum.OVER_REQUEST.getCode(), BizCodeEnum.OVER_REQUEST.getMsg());
        }

        //分别对社区,对用户进行校验
        CommunityEntity comm = communityService.getById(communityid);
        if(comm==null){
            return R.error(BizCodeEnum.NO_SUCHCOMMUNITY.getCode(),BizCodeEnum.NO_SUCHCOMMUNITY.getMsg());
        }

        //此时查看当前是不是自己加入自己的社区
        if(comm.getUserid().equals(userid)){
            backMessage="看来您对您自己的社区很满意哇~";
            return R.ok(backMessage);
        }

        R info = feignUserService.info(userid);
        String userString = FastJsonUtils.toJson(info.get("user"));
        UserEntity user = FastJsonUtils.fromJson(userString, UserEntity.class);
        if(user==null){
            return R.error(BizCodeEnum.NO_SUCHUSER.getCode(),BizCodeEnum.NO_SUCHUSER.getMsg());
        }
        //都通过之后的话,我们开始发送消息给服务,这个是审核消息,直接发送即可

消息转发

之后的话就是咱们的消息的转发。

        HoleAduitMsgQ holeAduitMsgQ = new HoleAduitMsgQ();
        holeAduitMsgQ.setMsgtitle("加入社区申请");
        holeAduitMsgQ.setMsg(user.getNickname()+"申请加入:"+comm.getCommunityTitle()+"社区");
        //消息是转发给管理员的
        holeAduitMsgQ.setUserid(comm.getUserid());
        holeAduitMsgQ.setLinkid(userid);
        holeAduitMsgQ.setLinkid2(String.valueOf(communityid));
//        1-文章,2-提问,3-回答,4-pushAc,5-Merge,6-社区成员申请,7-成员请求成功
        holeAduitMsgQ.setType(6);
        feignHoleAduitMsgService.holeAduitMsg(holeAduitMsgQ);

那么这里的话调用到了一个远程的nutty接口,这个接口是这样的:

@Service
public class HoleAduitMsgServiceImpl implements HoleAduitMsgService {

    @Autowired
    HoleAuditService auditService;

    @Override
    public R holeaduitMsg(HoleAduitMsgQ holeAduitMsgQ) {
        //1.对消息进行存储,只要用户在线的话,我们就直接先给他签收一下
        String userid = holeAduitMsgQ.getUserid();
        Channel channel = UserConnectPool.getChannelFromMap(userid);
        HoleAuditEntity holeAuditEntity = new HoleAuditEntity();
        BeanUtils.copyProperties(holeAduitMsgQ,holeAuditEntity);
        holeAuditEntity.setCreateTime(DateUtils.getCurrentTime());

        if(channel!=null){
            //这边只是保证存在,双层保险,这个时候的话就是在线
            Channel realChannel = UserConnectPool.getChannelGroup().find(channel.id());
            if(realChannel!=null){
                holeAuditEntity.setStatus(1);
                //我们这边直接转发消息就好了,不需要再额外处理
                realChannel.writeAndFlush(
                        new TextWebSocketFrame(
                                JsonUtils.objectToJson(
                                        Objects.requireNonNull(R.ok().put("data", holeAuditEntity))
                                                .put("type", MessageActionEnum.HOLEADUITMSG.type)
                                )
                        )
                );
            }else {
                //状态为2表示当前用户可能由于什么原因没有和我们的消息服务器连接
                holeAuditEntity.setStatus(2);
            }
        }else {
            holeAuditEntity.setStatus(2);
        }

        //这里进行消息的存储
        auditService.save(holeAuditEntity);
        return R.ok();
    }

}

完整代码

那么这里的话,就是完成了咱们的一个处理

 public R JoinUser(JoinQ joinQ) {
        /**
         * 这里负责用户社区的加入
         * 这个userid是谁要加入我们这个社区
         * 1. 判断用户是不是加入了
         * 2. 通知社区对应的管理员,让管理员进行审核
         * 3. 管理员审核通过后,完成用户的加入
         * 4. 这个接口限制1分钟一次
         * */
        String userid = joinQ.getUserid();
        Long communityid = joinQ.getCommunityid();
        String backMessage = "已经通知社区管理员请等待哟~";

        if(redisUtils.hasKey(RedisTransKey.getRedisJoinCommunity(userid+"_"+communityid))){
            return R.error(BizCodeEnum.OVER_REQUEST.getCode(), BizCodeEnum.OVER_REQUEST.getMsg());
        }

        //分别对社区,对用户进行校验
        CommunityEntity comm = communityService.getById(communityid);
        if(comm==null){
            return R.error(BizCodeEnum.NO_SUCHCOMMUNITY.getCode(),BizCodeEnum.NO_SUCHCOMMUNITY.getMsg());
        }

        //此时查看当前是不是自己加入自己的社区
        if(comm.getUserid().equals(userid)){
            backMessage="看来您对您自己的社区很满意哇~";
            return R.ok(backMessage);
        }

        R info = feignUserService.info(userid);
        String userString = FastJsonUtils.toJson(info.get("user"));
        UserEntity user = FastJsonUtils.fromJson(userString, UserEntity.class);
        if(user==null){
            return R.error(BizCodeEnum.NO_SUCHUSER.getCode(),BizCodeEnum.NO_SUCHUSER.getMsg());
        }
        //都通过之后的话,我们开始发送消息给服务,这个是审核消息,直接发送即可

        //查看当前的这个成员是不是已经加入了
        Map<String, Object> params = new HashMap<>();
        params.put("userid",user.getUserid());
        params.put("communityid",communityid);
        R r = feignCommunityisInService.communityisIn(params);
        String in = FastJsonUtils.toJson(r.get("in"));
        CommunityJoinEntity isJoin = FastJsonUtils.fromJson(in, CommunityJoinEntity.class);
        //此时已经存在了
        if(isJoin !=null){
            backMessage = "您已经加入该社区了";
            redisUtils.set(RedisTransKey.setJoinCommunityKey(userid)
                    ,1,1, TimeUnit.MINUTES
            );
            return R.ok(backMessage);
        }

        HoleAduitMsgQ holeAduitMsgQ = new HoleAduitMsgQ();
        holeAduitMsgQ.setMsgtitle("加入社区申请");
        holeAduitMsgQ.setMsg(user.getNickname()+"申请加入:"+comm.getCommunityTitle()+"社区");
        //消息是转发给管理员的
        holeAduitMsgQ.setUserid(comm.getUserid());
        holeAduitMsgQ.setLinkid(userid);
        holeAduitMsgQ.setLinkid2(String.valueOf(communityid));
//        1-文章,2-提问,3-回答,4-pushAc,5-Merge,6-社区成员申请,7-成员请求成功
        holeAduitMsgQ.setType(6);
        feignHoleAduitMsgService.holeAduitMsg(holeAduitMsgQ);
        //存储成功设置标志
        redisUtils.set(RedisTransKey.setJoinCommunityKey(userid+"_"+communityid)
                ,1,10, TimeUnit.MINUTES
        );
        return R.ok(backMessage);
    }

审核服务

之后的话,是咱的审核服务,这个的话其实也是,首先消息的服务是共用一个,但是的话,咱们的这个的话,对与数据的校验什么的稍微复杂一点儿。

完整代码长这样,很大一部分是在构建消息类,实体类,然后是对用户的行为进行一定的约束。

  public R AcJoinUser(AcJoinQ acJoinQ) {
        /**
         * 这里进行10秒限制
         * 1. 先进行疯狂校验
         * 2. 进行存储
         * 3. 通知用户
         * */
        String userid = acJoinQ.getUserid();
        String backMessage = "操作完成,已通知该成员";
        if(redisUtils.hasKey(RedisTransKey.getAcAuthority(userid))){
            return R.error(BizCodeEnum.TOO_FASTAUTHORITY.getCode(), BizCodeEnum.TOO_FASTAUTHORITY.getMsg());
        }

        Long communityid = acJoinQ.getCommunityid();
        String membersid = acJoinQ.getMembersid();

        //先对社区进行校验
        CommunityEntity comm = communityService.getById(communityid);
        if(comm==null){
            return R.error(BizCodeEnum.NO_SUCHCOMMUNITY.getCode(),BizCodeEnum.NO_SUCHCOMMUNITY.getMsg());
        }
        String manageID = comm.getUserid();
        if(!manageID.equals(userid)){
            //此时可以判断为非法越权操作,直接封杀2个小时
            redisUtils.set(RedisTransKey.setAcAuthority(userid)
                    ,1,120, TimeUnit.MINUTES
            );
            return R.error(BizCodeEnum.BAD_AUTHORITY.getCode(),BizCodeEnum.BAD_AUTHORITY.getMsg());
        }

        //对用户和成员进行校验
        R info = feignUserService.info(userid);
        String userString = FastJsonUtils.toJson(info.get("user"));
        UserEntity manager = FastJsonUtils.fromJson(userString, UserEntity.class);
        if(manager==null){
            return R.error(BizCodeEnum.NO_SUCHUSER.getCode(),BizCodeEnum.NO_SUCHUSER.getMsg());
        }
        info = feignUserService.info(membersid);
        userString = FastJsonUtils.toJson(info.get("user"));
        UserEntity members = FastJsonUtils.fromJson(userString, UserEntity.class);
        if(members==null){
            return R.error(BizCodeEnum.NO_SUCHUSER.getCode(),BizCodeEnum.NO_SUCHUSER.getMsg());
        }

        UsersEntity usersEntity = new UsersEntity();
        CommunityJoinEntity communityJoinEntity = new CommunityJoinEntity();

        //查看当前的这个成员是不是已经加入了
        Map<String, Object> params = new HashMap<>();
        params.put("userid",membersid);
        params.put("communityid",communityid);
        R r = feignCommunityisInService.communityisIn(params);
        String in = FastJsonUtils.toJson(r.get("in"));
        CommunityJoinEntity isJoin = FastJsonUtils.fromJson(in, CommunityJoinEntity.class);
        //此时已经存在了
        if(isJoin !=null){
            backMessage = "您已加入此社区";
            redisUtils.set(RedisTransKey.setAcAuthority(manageID)
                    ,1,10, TimeUnit.SECONDS
            );
            return R.ok(backMessage);
        }

        //查询成员的头像信息
        R RHeadImg = feignHeadimgService.headimg(membersid);
        String headImgString = FastJsonUtils.toJson(RHeadImg.get("headimg"));
        HeadimgEntity headimg_members = FastJsonUtils.fromJson(headImgString, HeadimgEntity.class);
        if(headimg_members!=null){
            usersEntity.setUserimg(headimg_members.getImgpath());
        }
        //查询管理员头像信息
        RHeadImg = feignHeadimgService.headimg(manageID);
        headImgString = FastJsonUtils.toJson(RHeadImg.get("headimg"));
        HeadimgEntity headimg_manage = FastJsonUtils.fromJson(headImgString, HeadimgEntity.class);
        if(headimg_manage!=null){
            communityJoinEntity.setCommunityImg(headimg_manage.getImgpath());
        }

        //此时进行存储
        usersEntity.setUserid(membersid);
        usersEntity.setUserNickname(members.getNickname());
        usersEntity.setCommunityid(communityid);
        usersEntity.setCommunityName(comm.getCommunityTitle());
        usersEntity.setCreateTime(DateUtils.getCurrentTime());
        usersService.save(usersEntity);

        //更新成员的一个社区加入的情况
        communityJoinEntity.setCommunityImg(comm.getCommunityImg());
        communityJoinEntity.setCommunityInfo(comm.getCommunityInfo());
        communityJoinEntity.setCommunityid(comm.getCommunityid());
        communityJoinEntity.setCommunityUserid(comm.getUserid());
        communityJoinEntity.setCommunityUserNickname(comm.getUserNickname());
        communityJoinEntity.setCommunityName(comm.getCommunityTitle());
        communityJoinEntity.setUserid(membersid);
        communityJoinEntity.setCommunityJoinTime(DateUtils.getCurrentTime());
        feignCommunityJoinService.save(communityJoinEntity);

        //此时向用户发送消息,告诉用户社区申请通过

        HoleAduitMsgQ holeAduitMsgQ = new HoleAduitMsgQ();
        holeAduitMsgQ.setMsgtitle("您的申请已经通过");
        holeAduitMsgQ.setMsg("Congratulations,成为"+comm.getCommunityTitle()+"的一员!");
        holeAduitMsgQ.setUserid(membersid);
        holeAduitMsgQ.setLinkid(String.valueOf(comm.getCommunityid()));
//        1-文章,2-提问,3-回答,4-pushAc,5-Merge,6-成员,7-成员请求成功
        holeAduitMsgQ.setType(7);
        feignHoleAduitMsgService.holeAduitMsg(holeAduitMsgQ);
        //存储成功设置标志
        redisUtils.set(RedisTransKey.setAcAuthority(manageID)
                ,1,10, TimeUnit.SECONDS
        );
        backMessage = "操作完成,已通知该成员";
        return R.ok(backMessage);
    }

总结

今天的话,就写了这两个功能,ok,接下来要去背单词了。