MixedCode

안녕하세요.  믹스드코드입니다.

이번 시간에는 웹채팅 기능 구현하기 두번째 시간으로 채팅 참여자 목록을 보여주고 특정 사용자를 강퇴처리하는 로직을 구현해볼 예정입니다.
그리고 사용자들이 채팅서비스에 최초 연결되었을때 브라우저를 닫고 나가거나 직접 퇴장하기 버튼을 클릭했을때 등의 이벤트 기반에서 정보를 처리하는 방법들을 알아 보겠습니다.

1.  메뉴 헤더 바 영역를  표시합니다.
- 메뉴 헤더바 영역에는 좌측에 채팅 접속자 수를 표기하고 해당 숫자를 클릭하면 좌측영역에서 채팅사용자 목록 및 강퇴기능 제공 레이어가 나타납니다.
- 우측 영역에는 환경설정 버튼 과 채팅 나가기 버튼이 제공됩니다.
- 메뉴 헤더바 하단에는 채팅방 명을 표기하는 영역이 나타납니다.



2.  페이지가 로드 될때 메뉴헤더영역이 보이게  관련코드를  추가합니다.
-메뉴 헤더 보이기 영역코드를 추가하고 상태관리용 TM오브젝트를 추가합니다.

    var TM = new Object();

        $(function () {

            //채팅방 입장 레이어 가운데 정렬 및 보이기처리
            $('#tmPopWrap').css({ position: 'absolute' }).css({ left: ($(window).width() - $('.tmBody').outerWidth()) / 2, top: 100 });
            $("#tmPopWrap").show();
            $("#tmInputName").focus();
            $("#tmInputName").val(chatNickName);

            //메뉴 헤더 보이기
            $("#tmBtnCloseChat").show();
            $("#tmInfoBar, #tmNotification").show().css("top", "-50px").animate({ top: 0 }, 500);
            $("#tmMessageList .tmInner").css("margin-top", "70px");



3. TalkHub 클래스파일에  그룹채팅방 입장 기능을 추가합니다.

- 채팅방 그룹명 과 채팅아이디를 파라메터를 전달받습니다.
- 채팅 사용자 관련 각종 데이터 모델 클래스를 생성합니다.



1) 채팅그룹(방)  입장처리 및 입장완료 메시지 발송

        private static List<ChatUserModel> _chatUserList = new List<ChatUserModel>();

        /// <summary>
        /// 채팅방 입장
        /// </summary>
        /// <param name="groupName">채팅방명</param>
        /// <param name="userName">닉네임</param>
        public Task EntryGroup(string groupName,string userName)
        {
            Task ts = Groups.Add(Context.ConnectionId, groupName);

            string userIPAddress = Context.Request.GetHttpContext().Request.ServerVariables["Remote_ADDR"].ToString();

            ChatUserModel user = new ChatUserModel();
            user.ConnectionID = Context.ConnectionId;
            user.ChatRoomName = groupName;
            user.NickName = userName;
            user.ConnectedDate = DateTime.Now;
            user.IPAddress = userIPAddress;

            _chatUserList.Add(user);

            int userCnt = _chatUserList.Where(c => c.ChatRoomName == groupName).Count();

            string entryMsg = string.Format("{0}님이 입장하셨습니다.", userName);

            Clients.Group(groupName).EntryGroupMessage(entryMsg,userCnt);

            return ts;
        }



2) 채팅 사용자 관련 데이터 모델 정의 Models 폴더 하위에 생성

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace WebChatSolution2017.Models
{

    /// <summary>
    /// 채팅 사용자 데이터 모델
    /// </summary>
    public class ChatUserModel
    {
        /// <summary>
        /// 채팅방명
        /// </summary>
        public string ChatRoomName { get; set; }


        /// <summary>
        /// 커넥션아이디
        /// </summary>
        public string ConnectionID { get; set; }


        /// <summary>
        /// 대화명
        /// </summary>
        public string NickName { get; set; }


        /// <summary>
        /// 접속IP주소
        /// </summary>
        public string IPAddress { get; set; }


        /// <summary>
        /// 연결일시
        /// </summary>
        public DateTime ConnectedDate { get; set; }


    }


    /// <summary>
    /// 채팅 블로킹 정보 모델
    /// </summary>
    public class ChatBlockingInfo
    {
        public string RoomName { get; set; }
        public List<BlockingUserInfo> NickNames { get; set; }
    }

    //채팅 블로킹 사용자정보 모델
    public class BlockingUserInfo
    {
        public string RoomName { get; set; }
        public string NickName { get; set; }
        public string BlockingType { get; set; }

    }
}


4. 채팅 그룹방 입장  처리 및  입장완료 메시지 수신 처리기를 등록합니다.
- 채팅 아이디 입력 후 버튼을 클릭하면 채팅 그룹방으로 접속하고 접속결과를  수신합니다.




             //채팅 그룹방 입장 메시지처리
            chat.client.entryGroupMessage = function (message, userCnt) {

                var html = '';
                html += '<p class="tmSystemMsg">';
                html += '<span class="tmMsg"><strong>' + message + '</strong></span>';
                html += '</p>';

                $("#tmMessageList .tmInner").append(html);
                $("#tmChatTotalCnt").html(userCnt);
            };


            //채팅방 입장처리
            $("#tmBtnConfirmName").click(function () {
 
                var userName = $("#tmInputName").val();

                if (userName == "") {
                    alert("대화명을 입력해주세요.");
                    $("#tmInputName").focus();
                    return false;
                }

                chatNickName = userName;

                $.connection.hub.start().done(function () {

                    //사용자 대화방 입장정보 전송
                    //chat.server.entry(chatNickName);
                    //$("#tmPopWrap").hide();


                    //사용자 채팅그룹방 입장정보 전송
                    chat.server.entryGroup(groupName,chatNickName);
                    $("#tmPopWrap").hide();
                });
            });


5.  채팅 그룹방에 접속한 사용자 목록을  좌측 레이어 영역에 표기하고 본인을 제외한 다른 사용자를 선택하고 강퇴처리하는 기능을 구현합니다.




6. 좌측 접속자 사용자수 아이콘을 클릭하면 좌측에  채팅 접속자 목록을 조회하고 해당 영역에 표시합니다.


Client - Talk.cshtml

            // 채팅사용자목록 조회결과 바인딩
            chat.client.getUserList = function (users) {
                fn_ChatUserListBind(users);
            };

            // 채팅: 참여자목록 보기버튼 클릭 이벤트
            $("#tmBtnMemberList").click(function () {
                chat.server.checkUserList(groupName);

                TM.isLogin = true;
                $("#chkUserList").removeClass("tmNotLogin");
                $("#adminBlocking").show();
                fn_formCheckBox();
            });


            // 채팅: 참여자목록 닫기버튼 클릭 이벤트
            $("#tmLayerMemberList .tmBtnCloseLayer").click(function () {
                fn_closeMemberListLayer();
            });



       // 채팅사용자 목록조회 바인딩
        function fn_ChatUserListBind(users) {
            $("#chkUserList").html("");

            var disableText = "";

            $.each(users, function (index, user) {
                // console.log(user.NickName);
                disableText = "";
                if (chatNickName == user.NickName) {
                    disableText = "disabled";
                }
                $("#chkUserList").append("<li class='" + disableText + "'><a href='javascript:;'>" + user.NickName + "</a><input type='checkbox' name='chkUser' id='chkUser" + index.toString() + "' value='" + user.NickName + "' " + disableText + " /></li>");
            });


            // 목록 레이어 보여주기
            fn_openMemberListLayer();
        }


         // 채팅 참여자 목록 레이어 보기
        function fn_openMemberListLayer() {
            var duration = 300;
            var distance = $("#tmLayerMemberList").outerWidth();

            $("#tmLayerMemberList").animate({ left: 0 }, duration, function () {
                TM.isOpenMemberList = true;
            });
            $("#tmLayerChat").css("right", "auto").animate({ left: distance }, duration);
            $("#tmLayerMask").hide().fadeIn(duration);
        }


        // 채팅 참여자 목록 레이어 닫기
        function fn_closeMemberListLayer() {
            var duration = 300;
            var distance = -$("#tmLayerMemberList").outerWidth();


            $("#tmLayerMemberList").animate({ left: distance }, duration, function () {
                TM.isOpenMemberList = false;
            });
            $("#tmLayerChat").animate({ left: 0 }, duration);
            $("#tmLayerMask").fadeOut(duration);
        }


        // 체크박스 상태체크 및 이벤트처리
        function fn_formCheckBox() {

            $(".tmFormCheckbox").on("click", "a", function (event) {
                var _this = $(this);
                var realCheckbox = _this.siblings("input[type=checkbox]");
                var isChecked = realCheckbox.prop("checked") == true ? true : false;
                var isDisabled = realCheckbox.attr("disabled") == "disabled" ? true : false;
                var isNotLogin = $(this).parents(".tmFormCheckbox").hasClass(".tmNotLogin");

                if (isNotLogin) return false;

                if (isDisabled) return false;

                if (isChecked) {
                    realCheckbox.prop("checked", false);
                }
                else {
                    realCheckbox.prop("checked", true);
                }

                realCheckbox.change();

                event.preventDefault();
            });


            // 체크박스 체인지 이벤트
            $(".tmFormCheckbox").on("change", "input[type=checkbox]", function () {
                var _this = $(this);
                var isChecked = _this.prop("checked") == true ? true : false;

                if (isChecked) {
                    _this.parent().addClass("active");
                }
                else {
                    _this.parent().removeClass("active");
                }
            });


            // 셀렉트박스: 데이타 바인딩 후 실행시켜주어야함.
            $(".tmFormCheckbox").find("input[type=checkbox]").change();
        }





Server - TalkHub.cs

     /// <summary>
        /// 채팅방 접속자 목록 반환
        /// </summary>
        /// <param name="chatGroupName">채팅방명</param>
        public void CheckUserList(string groupName)
        {
            var users = _chatUserList.Where(c => c.ChatRoomName == groupName).ToList();
            Clients.Caller.getUserList(users);
        }






7.  아이피 차단 강퇴 처리 후  강퇴 사실을 공지하고 대상 사용자의 화면은  채팅 기능이 모두 비활성화 처리됩니다.
- 강퇴 대상 사용자 화면에서는 메시지 입력 /전송 등의 주요 기능이 비활성화 처리됩니다.



8. 1일차단/영구 차단 버튼을 클릭하면 하단 스크립트 함수가 호출되고  채팅서비스 ipBlocking 함수를 호출합니다.



Client - Talk.cshtml VIEW


        // 아이피 차단
        function fn_Blocking(blockingType) {

            if (confirm("강퇴처리 하시겠습니까?")) {
                var chkUser = $('input[name=chkUser]');
                var userList = null;

                $.each(chkUser, function (index, obj) {
                    var checked = this.checked;
                    if (checked == true) {
                        if (userList == null) {
                            userList = { "RoomName": groupName, "NickNames": [{ "RoomName": groupName, "NickName": this.value, "BlockingType": blockingType }] };
                        } else {
                            userList.NickNames.push({ "RoomName": groupName, "NickName": this.value, "BlockingType": blockingType });
                        }

                    }
                });

                // IP차단정보등록 및 강퇴처리
                chat.server.ipBlocking(JSON.stringify(userList));

            }
        }




Server - TalkHub.cs

        /// <summary>
        /// 아이피 블로킹 및 강퇴처리
        /// </summary>
        /// <param name="jsonUserList">블로킹대상json문자열</param>
        public void IpBlocking(string jsonUserList)
        {
            ChatBlockingInfo blocking = JsonConvert.DeserializeObject<ChatBlockingInfo>(jsonUserList);

            foreach (BlockingUserInfo u in blocking.NickNames)
            {
                //사용자 채팅 아웃처리
                UserConnectionOut(u.RoomName,u.NickName,"님이 강퇴처리 되었습니다.");
            }
        }


        /// <summary>
        /// 사용자 채팅 아웃
        /// </summary>
        /// <param name="roomName"></param>
        /// <param name="nickName"></param>
        private void UserConnectionOut(string roomName, string nickName,string msg)
        {
            ChatUserModel user = _chatUserList.Where(c => c.ChatRoomName == roomName && c.NickName == nickName).FirstOrDefault();

            if (user != null)
            {
                //사용자목록에서 삭제
                _chatUserList.Remove(user);

                //퇴장메시지 발송
                Clients.Group(user.ChatRoomName).goodByUser(user.NickName, msg, _chatUserList.Where(c => c.ChatRoomName == user.ChatRoomName).Count());

                //그룹에서 사용자 삭제
                Groups.Remove(user.ConnectionID, user.ChatRoomName);

            }
        }


        /// <summary>
        /// 퇴장하기
        /// </summary>
        public void ChatExit()
        {
            var user = _chatUserList.Where(c => c.ConnectionID == Context.ConnectionId).FirstOrDefault();
            UserConnectionOut(user.ChatRoomName, user.NickName, " 님이 퇴장하셨습니다.");
        }

9.  채팅 서비스 연결 과 끊김/재연결 이벤트 처리를 위해 주요 기능을 재정의합니다.



Server - TalkHub.cs


        /// <summary>
        /// 사용자 커넥션 발생시
        /// </summary>
        /// <returns></returns>
        public override Task OnConnected()
        {
            return base.OnConnected();
        }


        /// <summary>
        /// 사용자 연결이 끊어질때(브라우저 닫기/탭닫기)
        /// </summary>
        /// <returns></returns>
        public override Task OnDisconnected(bool stopCalled)
        {
            var user = _chatUserList.Where(c => c.ConnectionID == Context.ConnectionId).FirstOrDefault();
            UserConnectionOut(user.ChatRoomName, user.NickName, " 님이 퇴장하셨습니다.");

            return base.OnDisconnected(stopCalled);
        }


        /// <summary>
        /// 사용자 재연결 발생시
        /// </summary>
        /// <returns></returns>
        public override Task OnReconnected()
        {
            return base.OnReconnected();
        }


 지금까지 채팅의 주요 기능으로  채팅 그룹별 사용자 목록 및 강퇴처리/나가기 기능등을 구현해보았습니다.
수고 많으셨습니다.


*