一套简朴的web即时通讯——第二版

2019年7月1日12:57:19一套简朴的web即时通讯——第二版已关闭评论 210

  媒介

  接上一版,这一版的页面与功用都有所优化,详细以下:

  1、优化登录阻拦

  2、登录后猎取一切挚友并辨别显现在线、离线挚友,挚友上线、下线都有符号

  3、将前后端交互的值改成用户id、显现值改成昵称nickName

  4、谈天音讯存储,点击挚友谈天,先追加谈天记录

  5、登录后猎取一切未读音讯并以小圆点的情势展现

  6、搜刮挚友、增加挚友

 

  优化细节

    1、登录阻拦由之前的经由过程途径中猎取账号,推断WebSocketServer.loginList中是不是存在key改成登录的时刻设置cookie,登录阻拦从cookie中取值

  登录、登出的时刻设置、删除cookie,

一套简朴的web即时通讯——第二版

    /**
     * 登录
     */
    @PostMapping("login")
    public Result<ImsUserVo> login(ImsUserVo userVo, HttpServletResponse response) {
        //加密后再去对照密文
        userVo.setPassword(MD5Util.getMD5(userVo.getPassword()));
        Result<List<ImsUserVo>> result = list(userVo);
        if (result.isFlag() && result.getData().size() > 0) {
            ImsUserVo imsUserVo = result.getData().get(0);
            //置空隐私信息
            imsUserVo.setPassword(null);

            //add WebSocketServer.loginList
            WebSocketServer.loginList.put(imsUserVo.getUserName(), imsUserVo);

            //设置cookie
            Cookie cookie = new Cookie("imsLoginToken", imsUserVo.getUserName());
            cookie.setMaxAge(60 * 30);
            //设置域
//          cookie.setDomain("huanzi.cn");
            //设置接见途径
            cookie.setPath("/");
            response.addCookie(cookie);

            return Result.of(imsUserVo);
        } else {
            return Result.of(null, false, "账号或暗码毛病!");
        }
    }

    /**
     * 登出
     */
    @RequestMapping("logout/{username}")
    public ModelAndView loginOut(HttpServletResponse response, @PathVariable String username) {
        new WebSocketServer().deleteUserByUsername(username,response);
        return new ModelAndView("login.html");
    }

ImsUserController.java

  改成封闭websocket时不做操纵,仅减减socket衔接数

一套简朴的web即时通讯——第二版

    /**
     * 衔接封闭挪用的要领
     */
    @OnClose
    public void onClose(Session session) {
        //下线用户名
        String logoutUserName = "";

        //从webSocketMap删除下线用户
        for (Entry<String, Session> entry : sessionMap.entrySet()) {
            if (entry.getValue() == session) {
                sessionMap.remove(entry.getKey());
                logoutUserName = entry.getKey();
                break;
            }
        }
        deleteUserByUsername(logoutUserName,null);
    }

    /**
        用户下线
     */
    public void deleteUserByUsername(String username, HttpServletResponse response){
        //在线人数减减
        WebSocketServer.onlineCount--;
        if(WebSocketServer.onlineCount <= 0){
            WebSocketServer.onlineCount = 0;
        }

        if(StringUtils.isEmpty(response)){
            return;
        }

        //用户鸠合delete
        WebSocketServer.loginList.remove(username);

        //删除cookie 思绪就是替代本来的cookie,并设置它的生计时候为0
        //设置cookie
        Cookie cookie = new Cookie("imsLoginToken", username);
        cookie.setMaxAge(0);
        //设置域
//      cookie.setDomain("huanzi.cn");
        //设置接见途径
        cookie.setPath("/");
        response.addCookie(cookie);

        //关照除本身以外的一切人
        sendOnlineCount(username, "{'type':'onlineCount','onlineCount':" + WebSocketServer.onlineCount + ",username:'" + username + "'}");
    }

WebSocketServer.java

  在登录阻拦器中从cookie取用户账户

一套简朴的web即时通讯——第二版

        //其实存的是用户账号
        String imsLoginToken = "";
        Cookie[] cookies = request.getCookies();
        if (null != cookies) {
            for (Cookie cookie : cookies) {
                if ("imsLoginToken".equals(cookie.getName())) {
                    imsLoginToken = cookie.getValue();
                }
            }
        }

        if(WebSocketServer.loginList.containsKey(imsLoginToken)){
            //一般处置惩罚要求
            filterChain.doFilter(servletRequest, servletResponse);
        }else{
            //重定向登录页面
            response.sendRedirect("/imsUser/loginPage.html");
        }

LoginFilter.java

  

  2、登录以后的用户列表不再是显现websocket衔接的用户,而是登录用户的挚友,同时要辨别显现挚友的在线与离线,以是新增一个猎取在线挚友的接口

一套简朴的web即时通讯——第二版

    /**
     * 猎取在线挚友
     */
    @PostMapping("getOnlineList")
    private Result<List<ImsUserVo>> getOnlineList(ImsFriendVo imsFriendVo) {
        return imsFriendService.getOnlineList(imsFriendVo);
    }


   /**
     * 猎取在线挚友
     */
    @Override
    public Result<List<ImsUserVo>> getOnlineList(ImsFriendVo imsFriendVo) {
        //挚友列表
        List<ImsFriendVo> friendList = list(imsFriendVo).getData();

        //在线挚友列表
        ArrayList<ImsUserVo> onlineFriendList = new ArrayList<>();

        //遍历friendList
        for(ImsFriendVo imsFriendVo1 : friendList){
            ImsUserVo imsUserVo = imsFriendVo1.getUser();
            if (!StringUtils.isEmpty(WebSocketServer.getSessionMap().get(imsUserVo.getId().toString()))) {
                onlineFriendList.add(imsUserVo);
            }
        }
        return Result.of(onlineFriendList);
    }

ImsFriend
一套简朴的web即时通讯——第二版

//衔接胜利竖立的回调要领
websocket.onopen = function () {
    //猎取挚友列表
    // $.post(ctx + "/imsFriend/list",{userId: username},function (data) {
    //     console.log(data)
    // });
    $.ajax({
        type: 'post',
        url: ctx + "/imsFriend/list",
        contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
        dataType: 'json',
        data: {userId: user.id},
        success: function (data) {
            if (data.flag) {
                //列表
                let friends = data.data;
                for (let i = 0; i < friends.length; i++) {
                    let friend = friends[i].user;
                    let $friendGroupList = $("<div class=\"hz-group-list\">" +
                                    "<img class='left' style='width: 23px;' src='https://avatars3.githubusercontent.com/u/31408183?s=40&v=4'/>" +
                                    "<span class='hz-group-list-username'>" + friend.nickName + "</span><span id=\"" + friend.id + "-status\" style='color: #9c0c0c;;'>[离线]</span>" +
                                    "<div id=\"hz-badge-" + friend.id + "\" class='hz-badge'>0</div>" +
                                  "</div>");
                    $friendGroupList.user = friend;
                    $("#hz-group-body").append($friendGroupList);
                }

                //挚友人数
                $("#friendCount").text(friends.length);

                getOnlineList(user.id);
            }
        },
        error: function (xhr, status, error) {
            console.log("ajax毛病!");
        }
    });
};

/**
 * 猎取在线挚友
 */
function getOnlineList(userId){
    $.ajax({
        type: 'post',
        url: ctx + "/imsFriend/getOnlineList",
        contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
        dataType: 'json',
        data: {userId: userId},
        success: function (data) {
            if (data.flag) {
                //列表
                let onlineFriends = data.data;
                for (let i = 0; i < onlineFriends.length; i++) {
                    let friend = onlineFriends[i];
                    $("#" + friend.id + "-status").text("[在线]");
                    $("#" + friend.id + "-status").css("color", "#497b0f");
                }
                //挚友人数
                $("#onlineCount").text(onlineFriends.length);
            }
        },
        error: function (xhr, status, error) {
            console.log("ajax毛病!");
        }
    });
}

socketChart.js

一套简朴的web即时通讯——第二版

 

  3、将之前前后端通报用户账户username改成用户id,同时,显现的是nickName昵称,修正的处所比较多,我就不贴代码了

一套简朴的web即时通讯——第二版

 

   4、音讯存储 

   后端存储症结代码

一套简朴的web即时通讯——第二版

    /**
     * 服务器接收到客户端音讯时挪用的要领
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        try {
            //JSON字符串转 HashMap
            HashMap hashMap = new ObjectMapper().readValue(message, HashMap.class);

            //音讯范例
            String type = (String) hashMap.get("type");

            //泉源用户
            Map srcUser = (Map) hashMap.get("srcUser");

            //目的用户
            Map tarUser = (Map) hashMap.get("tarUser");

            //若是点击的是本身,那就是群聊
            if (srcUser.get("userId").equals(tarUser.get("userId"))) {
                //群聊
                groupChat(session,hashMap);
            } else {
                //私聊
                privateChat(session, tarUser, hashMap);
            }

            //后期要做音讯耐久化
            ImsFriendMessageVo imsFriendMessageVo = new ImsFriendMessageVo();
            imsFriendMessageVo.setToUserId((Integer) tarUser.get("userId"));
            imsFriendMessageVo.setFromUserId((Integer) srcUser.get("userId"));
            //谈天内容
            imsFriendMessageVo.setContent(hashMap.get("message").toString());
            try {
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                imsFriendMessageVo.setCreatedTime(simpleDateFormat.parse(hashMap.get("date").toString()));
                imsFriendMessageVo.setUpdataTime(simpleDateFormat.parse(hashMap.get("date").toString()));
            } catch (ParseException e) {
                e.printStackTrace();
            }
            imsFriendMessageService.save(imsFriendMessageVo);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

WebSocketServer.java

  前端点击挚友时,猎取谈天记录症结代码

一套简朴的web即时通讯——第二版

    //读取谈天记录
    $.post(ctx + "/imsFriendMessage/getChattingRecords", {
        fromUserId: userId,
        toUserId: toUserId
    }, function (data) {
        if (data.flag) {
            for (let i = 0; i < data.data.length; i++) {
                let msgObj = data.data[i];

                //当谈天窗口与msgUserName的人雷同,笔墨在左侧(对方/其他人),否则在右侧(本身)
                if (msgObj.fromUserId === userId) {
                    //追加谈天数据
                    setMessageInnerHTML({
                        id: msgObj.id,
                        isRead: msgObj.isRead,
                        toUserId: msgObj.toUserId,
                        fromUserId: msgObj.fromUserId,
                        message: msgObj.content,
                        date: msgObj.createdTime
                    });
                } else {
                    //追加谈天数据
                    setMessageInnerHTML({
                        id: msgObj.id,
                        isRead: msgObj.isRead,
                        toUserId: msgObj.fromUserId,
                        message: msgObj.content,
                        date: msgObj.createdTime
                    });
                }
            }
        }
    });

socketChart.js
一套简朴的web即时通讯——第二版

    /**
     * 猎取A-B的谈天记录
     */
    @RequestMapping("getChattingRecords")
    public Result<List<ImsFriendMessageVo>> getChattingRecords(ImsFriendMessageVo imsFriendMessageVo){
        return imsFriendMessageService.getChattingRecords(imsFriendMessageVo);
    }

    @Override
    public Result<List<ImsFriendMessageVo>> getChattingRecords(ImsFriendMessageVo imsFriendMessageVo) {
        //A对B的谈天记录
        List<ImsFriendMessageVo> allList = new ArrayList<>(super.list(imsFriendMessageVo).getData());
        Integer fromUserId = imsFriendMessageVo.getFromUserId();
        imsFriendMessageVo.setFromUserId(imsFriendMessageVo.getToUserId());
        imsFriendMessageVo.setToUserId(fromUserId);
        //B对A的谈天记录
        allList.addAll(super.list(imsFriendMessageVo).getData());
        //默许按时候排序
        allList.sort(Comparator.comparingLong(vo -> vo.getCreatedTime().getTime()));
        return Result.of(allList);
    }

ImsFriendMessage

一套简朴的web即时通讯——第二版 一套简朴的web即时通讯——第二版

 

  5、登录后猎取一切未读音讯并以小圆点的情势展现

  登录胜利后猎取与挚友的未读音讯症结代码,在猎取挚友列表以后挪用

一套简朴的web即时通讯——第二版

                //猎取未读音讯
                $.post(ctx + "/imsFriendMessage/list",{toUserId:userId,isRead:0},function(data){
                    if(data.flag){
                        let friends = {};

                        //将fromUser兼并
                        for (let i = 0; i < data.data.length; i++) {
                            let fromUser = data.data[i];

                            if(!friends[fromUser.fromUserId]){
                                friends[fromUser.fromUserId] = {};
                                friends[fromUser.fromUserId].count = 1;
                            }else{
                                friends[fromUser.fromUserId].count = friends[fromUser.fromUserId].count + 1;
                            }
                        }

                        for (let key in friends) {
                            let fromUser = friends[key];
                            //小圆点++
                            $("#hz-badge-" + key).text(fromUser.count);
                            $("#hz-badge-" + key).css("opacity", "1");
                        }
                    }
                });

socketChart.js

一套简朴的web即时通讯——第二版

 

  6、搜刮挚友、增加挚友

  可依照账号、昵称举行搜刮,个中账号是等值查询,昵称是隐约查询

  症结代码

一套简朴的web即时通讯——第二版

//搜刮挚友
function findUserByUserNameOrNickName() {
    let userNameOrNickName = $("#userNameOrNickName").val();
    if (!userNameOrNickName) {
        tip.msg("账号/昵称不能为空");
        return;
    }

    $.post(ctx + "/imsUser/findUserByUserNameOrNickName", {
        userName: userNameOrNickName,
        nickName: userNameOrNickName,
    }, function (data) {
        if (data.flag) {
            $("#friendList").empty();
            for (let i = 0; i < data.data.length; i++) {
                let user = data.data[i];
                let $userDiv = $("<div>" +
                    "<img style='width: 23px;margin: 0 5px 0 0;' src='" + user.avatar + "'/>" +
                    "<span>" + user.nickName + "(" + user.userName + ")</span>" +
                    "<button onclick='tipUserInfo($(this).parent()[0].user)'>用户概况</button>" +
                    "<button onclick=''>加挚友</button>" +
                    "</div>");
                $userDiv[0].user = user;
                $("#friendList").append($userDiv);
            }
        }
    });
}

socketChart.js
一套简朴的web即时通讯——第二版

    /**
     * 依据账号或昵称(隐约查询)查询
     */
    @PostMapping("findUserByUserNameOrNickName")
    public Result<List<ImsUserVo>> findUserByUserNameOrNickName(ImsUserVo userVo) {
        return imsUserService.findUserByUserNameOrNickName(userVo);
    }


    @Override
    public Result<List<ImsUserVo>> findUserByUserNameOrNickName(ImsUserVo userVo) {
        return Result.of(CopyUtil.copyList(imsUserRepository.findUserByUserNameOrNickName(userVo.getUserName(), userVo.getNickName()), ImsUserVo.class));
    }


    @Query(value = "select * from ims_user where user_name = :userName or nick_name like %:nickName%",nativeQuery = true)
    List<ImsUser> findUserByUserNameOrNickName(@Param("userName") String userName,@Param("nickName") String nickName);

ImsUser

一套简朴的web即时通讯——第二版

   增加挚友

  首先要修正ims_friend构造,SQL以下,增加了一个字段is_agree,是不是已赞同挚友请求 0已请求但未赞同 1赞同 -1谢绝,之前查询挚友列表的post要求则须要新增参数isAgree=1

一套简朴的web即时通讯——第二版

/*
 Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 50528
 Source Host           : localhost:3306
 Source Schema         : test

 Target Server Type    : MySQL
 Target Server Version : 50528
 File Encoding         : 65001

 Date: 14/05/2019 17:25:35
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for ims_friend
-- ----------------------------
DROP TABLE IF EXISTS `ims_friend`;
CREATE TABLE `ims_friend`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键',
  `user_id` int(11) NULL DEFAULT NULL COMMENT '用户id',
  `friend_id` int(11) NULL DEFAULT NULL COMMENT '挚友id',
  `friend_type` int(11) NULL DEFAULT NULL COMMENT '挚友分组id',
  `friend_remark` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '挚友备注',
  `is_agree` int(1) NULL DEFAULT NULL COMMENT '是不是已赞同挚友请求 0已请求但未赞同 1赞同 -1谢绝',
  `created_time` datetime NULL DEFAULT NULL COMMENT '建立时候',
  `updata_time` datetime NULL DEFAULT NULL COMMENT '更新时候',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '挚友表' ROW_FORMAT = Compact;

SET FOREIGN_KEY_CHECKS = 1;

View Code

  在工具栏新加一个体系音讯,贴出对应症结代码

一套简朴的web即时通讯——第二版

//监听单击体系音讯,弹出窗口
$("body").on("click", "#sysNotification", function () {
    //此处为单击事宜要实行的代码
    if ($(".sysNotification").length <= 0) {
        tip.dialog({
            title: "体系音讯",
            class: "sysNotification",
            content: "<div></div>",
            shade: 0
        });
    } else {
        $(".sysNotification").click();
    }
    $("#sysNotification").find(".hz-badge").css("opacity",0);
    $("#sysNotification").find(".hz-badge").text(0);

    //已谢绝

    //请求挚友
    $.post(ctx + "/imsFriend/list", {
        friendId: userId,
        isAgree: 0,
    }, function (data) {
        if (data.flag) {
            for (let i = 0; i < data.data.length; i++) {
                let user = data.data[i].user;
                let $userDiv = $("<div>" +
                    "<img style='width: 23px;margin: 0 5px 0 0;' src='" + user.avatar + "'/>" +
                    "<span>" + user.nickName + "(" + user.userName + ")</span> 请求增加挚友<br/>" +
                    "<button onclick='tipUserInfo($(this).parent()[0].user)'>用户概况</button>" +
                    "<button onclick='agreeAddFriend(" + data.data[i].id + ")'>赞同</button>" +
                    "</div>");
                $userDiv[0].user = user;
                $(".sysNotification .tip-content").append($userDiv);
            }
        }
    });
});

//请求增加挚友
function applyToAddFriend(friendUserId) {
    let nowTime = commonUtil.getNowTime();
    $.post(ctx + "/imsFriend/save", {
        userId: userId,
        friendId: friendUserId,
        friendType: 1,
        friendRemark: "",
        isAgree: 0,
        createdTime: nowTime,
        updataTime: nowTime,
    }, function (data) {
        if (data.flag) {
            tip.msg({text:"已为你递交挚友请求,对方赞同好便可成为挚友!",time:3000});
        }
    });
}

//赞同挚友增加
function agreeAddFriend(id){
    let nowTime = commonUtil.getNowTime();
    $.post(ctx + "/imsFriend/save", {
        id:id,
        isAgree: 1,
        updataTime: nowTime,
    }, function (data) {
        if (data.flag) {
            $.post(ctx + "/imsFriend/save", {
                userId: data.data.friendId,
                friendId: data.data.userId,
                friendType: 1,
                friendRemark: "",
                isAgree: 1,
                createdTime: nowTime,
                updataTime: nowTime,
            }, function (data) {
                if (data.flag) {
                    tip.msg({text:"你们已是挚友了,能够最先谈天!",time:2000});
                }
            });
        }
    });
}

//猎取我的请求挚友,并做小圆点提醒
function getApplyFriend(userId){
    $.post(ctx + "/imsFriend/list", {
        friendId: userId,
        isAgree: 0,
    }, function (data) {
        if (data.flag && data.data.length > 0) {
            $("#sysNotification").find(".hz-badge").css("opacity",1);
            $("#sysNotification").find(".hz-badge").text(data.data.length);
        }
    });
}

socketChart.js

一套简朴的web即时通讯——第二版

  在线、离线提醒出来小bug...

  

  2019-05-17更新

  题目找到了,是因为我们将联系关系的挚友对象属性名改成了

    @OneToOne
    @JoinColumn(name = "friendId",referencedColumnName = "id", insertable = false, updatable = false)
    @NotFound(action= NotFoundAction.IGNORE)
    private ImsUser friendUser;//挚友

  但在猎取在线挚友那边照样,getUser();,致使数据紊乱,bug修正:改成getFriendUser();便可

/**
     * 猎取在线挚友
     */
    @Override
    public Result<List<ImsUserVo>> getOnlineList(ImsFriendVo imsFriendVo) {
        imsFriendVo.setIsAgree(1);
        //挚友列表
        List<ImsFriendVo> friendList = list(imsFriendVo).getData();

        //在线挚友列表
        ArrayList<ImsUserVo> onlineFriendList = new ArrayList<>();

        //遍历friendList
        for(ImsFriendVo imsFriendVo1 : friendList){
            ImsUserVo imsUserVo = imsFriendVo1.getUser();
            if (!StringUtils.isEmpty(WebSocketServer.getSessionMap().get(imsUserVo.getId().toString()))) {
                onlineFriendList.add(imsUserVo);
            }
        }
        return Result.of(onlineFriendList);
    }

 

 

  跋文

  第二版临时记录到这,第三版延续更新中...

avatar