[Spring] 웹 소켓으로 채팅구현

Posted by 신희준 on January 23, 2018


2018 - 01 - 23 (화)


웹 소켓


프로젝트에 웹소켓을 활용하여 쪽지, 채팅 기능을 구현할 필요성이 생기게되어 웹 소켓에대해서 공부해 보았다.

사실 학교다닐 적에 통신관련 수업시간에 소켓에 대해서 수업을 들은적이 있다. 기억하기로는 OSI 5계층 중 4계층인 전송계층(Transport layer) 와 5계층인 응용계층 (Application layer) 사이에 존재하여 전송계층에 의존하고 이 두계층 사이에서 게이트? 역활을 한다. 라고 기억하고 있습니다.

결국 .. COMPUTER NETWORKING A TOP-DOWN Approach 라는 (전공서적) 을 펼쳐서 소켓부분을 찾게되었다. 해당 책에서는 UDP / TCP 소켓 프로그래밍을 소개하는데 이를 파이썬으로 소개한다.


프로젝트에 TCP 소켓 프로그래밍을 해야하는 나는 TCP 부분을 중점적으로 보았다.

TCP는 UDP 와 달리 손실? 을 싫어한다.(데이터의 정확하고 안정적인 전달이 핵심) 기본적으로 TCP 는 3Way handshaking 을 통해 연결지향적인 통신을 한다. 이 때 클라이언트 소켓 (IP 주소 및 포트번호) 와 서버 소켓 (IP주소 및 포트번호) 에 연결을 시도한다.

1 . 클라이언트가 TCP 연결을 위해 서버로 요청 메시지를 보낸다. 이 메시지는 소켓을 거쳐 서버에 전달된다.

2 . 서버는 반대로 클라이언트 주소로 응답 메시지를 보내고 이는 출입문이라고 할 수 있는 소켓을 통해 전달된다.

3 . 승인하는 응답을 보낼 경우 핸드셰이킹이 이루어진다. 소켓을 연결하는 파이프를 통해 바이트를 송수신 할 수 있게 된다.

웹소켓은 TCP 접속에 양방향 통신 채널하는 프로토콜이며 웹소켓의 API 는 W3C 에의해 표준화 되어있다.


DB설계

1 .. 두개의 테이블을 생성해주었다. CHATROOM 테이블과 MESSAGE 테이블

Post Sample Image

Post Sample Image

실습


1 .. https://github.com/sockjs/sockjs-client 에서 dist 의 sockjs.js 를 내려받아 프로젝트의 resource/js 폴더에 추가한다.

2 .. pom.xml 에 라이브러리 추가 (프로젝트의 스프링 버전은 4.1.7이다.)

<!-- https://mvnrepository.com/artifact/org.springframework/spring-websocket -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-websocket</artifactId>
    <version>4.2.4.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-annotations</artifactId>
  <version>2.9.0</version>
</dependency>

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-core</artifactId>
  <version>2.8.9</version>
</dependency>

<!-- jackson-databind -->
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.8.4</version>
</dependency>

3 .. ws-config.xml 생성 (웹소켓 관련 xml)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:websocket="http://www.springframework.org/schema/websocket"
 xmlns:mvc="http://www.springframework.org/schema/mvc"
 xsi:schemaLocation="http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket-4.0.xsd
  http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 <bean id="chatHandler" class="com.almom.handler.ChatWebSocketHandler" />

 <websocket:handlers>


  <websocket:mapping handler="chatHandler" path="/chat" />
	  <websocket:handshake-interceptors>
         <bean class="org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor" />
      </websocket:handshake-interceptors>
  <websocket:sockjs />

 </websocket:handlers>

 <mvc:default-servlet-handler />
</beans>

4 .. jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>



<html>
<head>

<link rel="stylesheet" type="text/css"
	href="../../../resources/css/bootstrap-grid.css">
<link rel="stylesheet" type="text/css"
	href="../../../resources/css/bootstrap-reboot.css">
<link rel="stylesheet" type="text/css"
	href="../../../resources/css/bootstrap.css">
<link rel="stylesheet" type="text/css"
	href="../../../resources/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css"
	href="../../../resources/css/page.css">
<link rel="stylesheet"
	href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" type="text/css"
	href="../../../resources/css/style.css">
<script type="text/javascript"
	src="../../../resources/js/jquery-3.2.1.js"></script>
<script type="text/javascript"
	src="../../../resources/js/sockjs.min.js"></script>

<style>
</style>
</head>

<body>

<c:set var="profile" value='<%=session.getAttribute("login")%>' />



 	<div class="col-12 row justify-content-center align-items-center my-5 ">
		<a href=""><img src="../../../resources/image/AlmomLogo.png"
			alt="Almom Logo" width="180px" class="img-fluid" /></a>
	</div>
	<div class="col-12">
		<div class="col-2" style="float: left">
			<span> 목록 </span>
		</div>
		<div class="col-8" style="float: left; text-align: center;">
			${tutor_name } 님과 대화</div>
		<div class="col-2" style="float: right">
			<span> 닫기 </span>
		</div>



	</div>
	<div class="col-12" style="margin-top: 40px; clear: both;">
		<div class="col-10"
			style="margin: 20px auto; text-align: center; color: white; background-color: #01D1FE; border: 1px solid #01D1FE; padding: 10px 10px; border-radius: 8px;">
			수업 일정과 강의 내용에 대해 문의해보세요. <br>(연락처 문의 또는 직접 알려주는 것은 불가)
		</div>

	</div>
	<!-- 채팅 내용 -->
	<div class="col-12">
		<div class="col-11"
			style="margin: 0 auto; border: 1px solid #01D1FE; height: 400px; border-radius: 10px; overflow:scroll" id = "chatArea">

			<div id="chatMessageArea" style = "margin-top : 10px; margin-left:10px;"></div>




		</div>
	</div>

	<!-- 채팅 입력창 -->
	<div class="col-12" style="margin-top: 20px; margin-bottom: 15px;">
		<div class="col-12" style="float: left">
			<textarea class="form-control"
				style="border: 1px solid #01D1FE; height: 65px; float: left; width: 80%"
				placeholder="Enter ..." id = "message">


				</textarea>
			<span
				style="float: right; width: 18%; height: 65px; text-align: center; background-color: #01D1FE; border-radius: 5px;">
				<a
				style="margin-top: 30px; text-align: center; color: white; font-weight: bold;" id = "sendBtn"><br>전송</a>
			</span>
		</div>

	</div>


<img id="profileImg" class="img-fluid"
					src="/displayFile?fileName=${userImage}&directory=profile" style = "display:none">
<input type="text" id="nickname" value = "${user_name }" style = "display:none">
 <input type="button" id="enterBtn" value="입장" style = "display:none">
 <input type="button" id="exitBtn" value="나가기" style = "display:none">
<script type="text/javascript">
 connect();

 function connect() {
	    sock = new SockJS('/chat');
	    sock.onopen = function() {
	        console.log('open');
	    };
	    sock.onmessage = function(evt) {
    	 var data = evt.data;
    	   console.log(data)
  		   var obj = JSON.parse(data)  	   
    	   console.log(obj)
    	   appendMessage(obj.message_content);
	    };
	    sock.onclose = function() {
	    	 appendMessage("연결을 끊었습니다.");
	        console.log('close');
	    };
	}




 function send() {
  var msg = $("#message").val();
  if(msg != ""){
	  message = {};
	  message.message_content = $("#message").val()
  	  message.TUTOR_USER_user_id = '${TUTOR_USER_user_id}'
  	  message.USER_user_id = '${profile.user_id}'
  	  message.CLASS_class_id = '${class_id}'
  	  message.message_sender = '${profile.user_id}'
  }




  sock.send(JSON.stringify(message));
  $("#message").val("");
 }




 function getTimeStamp() {
   var d = new Date();
   var s =
     leadingZeros(d.getFullYear(), 4) + '-' +
     leadingZeros(d.getMonth() + 1, 2) + '-' +
     leadingZeros(d.getDate(), 2) + ' ' +

     leadingZeros(d.getHours(), 2) + ':' +
     leadingZeros(d.getMinutes(), 2) + ':' +
     leadingZeros(d.getSeconds(), 2);

   return s;
 }

 function leadingZeros(n, digits) {
   var zero = '';
   n = n.toString();

   if (n.length < digits) {
     for (i = 0; i < digits - n.length; i++)
       zero += '0';
   }
   return zero + n;
 }







 function appendMessage(msg) {

	 if(msg == ''){
		 return false;
	 }else{


	 var t = getTimeStamp();
	 $("#chatMessageArea").append("<div class='col-12 row' style = 'height : auto; margin-top : 5px;'><div class='col-2' style = 'float:left; padding-right:0px; padding-left : 0px;'><img id='profileImg' class='img-fluid' src='/displayFile?fileName=${userImage}&directory=profile' style = 'width:50px; height:50px; '><div style='font-size:9px; clear:both;'>${user_name}</div></div><div class = 'col-10' style = 'overflow : y ; margin-top : 7px; float:right;'><div class = 'col-12' style = ' background-color:#ACF3FF; padding : 10px 5px; float:left; border-radius:10px;'><span style = 'font-size : 12px;'>"+msg+"</span></div><div col-12 style = 'font-size:9px; text-align:right; float:right;'><span style ='float:right; font-size:9px; text-align:right;' >"+t+"</span></div></div></div>")		 

	  var chatAreaHeight = $("#chatArea").height();
	  var maxScroll = $("#chatMessageArea").height() - chatAreaHeight;
	  $("#chatArea").scrollTop(maxScroll);

	 }
 }
 $(document).ready(function() {
  $('#message').keypress(function(event){
   var keycode = (event.keyCode ? event.keyCode : event.which);
   if(keycode == '13'){
    send();
   }
   event.stopPropagation();
  });



  $('#sendBtn').click(function() { send(); });/*
  $('#enterBtn').click(function() { connect(); });
  $('#exitBtn').click(function() { disconnect(); }); */
 });
</script>

</body>
</html>

  • handler
package com.almom.handler;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import java.util.concurrent.ConcurrentHashMap;

import javax.inject.Inject;

import org.springframework.web.socket.CloseStatus;

import org.springframework.web.socket.TextMessage;

import org.springframework.web.socket.WebSocketSession;

import org.springframework.web.socket.handler.TextWebSocketHandler;

import com.almom.domain.ChatRoomVO;
import com.almom.domain.MessageVO;
import com.almom.domain.UserVO;
import com.almom.persistence.ChatDAO;
import com.google.gson.Gson;

public class ChatWebSocketHandler extends TextWebSocketHandler {

	@Inject
	private ChatDAO dao;

	private List<WebSocketSession> connectedUsers;

	public ChatWebSocketHandler() {
	      connectedUsers = new ArrayList<WebSocketSession>();
	   }

	private Map<String, WebSocketSession> users = new ConcurrentHashMap<String, WebSocketSession>();

	@Override

	public void afterConnectionEstablished(

			WebSocketSession session) throws Exception {

		log(session.getId() + " 연결 됨!!");

		users.put(session.getId(), session);
		connectedUsers.add(session);
	}

	@Override

	public void afterConnectionClosed(

			WebSocketSession session, CloseStatus status) throws Exception {

		log(session.getId() + " 연결 종료됨");
		connectedUsers.remove(session);
		users.remove(session.getId());

	}


	@Override
	   protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {


		System.out.println(message.getPayload());

		  Map<String, Object> map = null;

	      MessageVO messageVO = MessageVO.convertMessage(message.getPayload());

	      System.out.println("1 : " + messageVO.toString());


	      ChatRoomVO roomVO  = new ChatRoomVO();
	      roomVO.setCLASS_class_id(messageVO.getCLASS_class_id()); //클래스
	      roomVO.setTUTOR_USER_user_id(messageVO.getTUTOR_USER_user_id()); //튜터
	      roomVO.setUSER_user_id(messageVO.getUSER_user_id()); //유저

	      ChatRoomVO croom =null;
	      if(!messageVO.getUSER_user_id().equals(messageVO.getTUTOR_USER_user_id())) {
	    	  System.out.println("a");



	    	  if(dao.isRoom(roomVO) == null ) {
	    		  System.out.println("b");
	    		  dao.createRoom(roomVO);
	    		  System.out.println("d");
	    		  croom = dao.isRoom(roomVO);

	    	  }else {
	    		  System.out.println("C");
	    		  croom = dao.isRoom(roomVO);
	    	  }
	      }else {

    		  croom = dao.isRoom(roomVO);
    	  }

	      messageVO.setCHATROOM_chatroom_id(croom.getChatroom_id());
	      if(croom.getUSER_user_id().equals(messageVO.getMessage_sender())) {

	    	  messageVO.setMessage_receiver(roomVO.getTUTOR_USER_user_id());
	      }else {
	    	  messageVO.setMessage_receiver(roomVO.getUSER_user_id());
	      }




	      for (WebSocketSession websocketSession : connectedUsers) {
	         map = websocketSession.getAttributes();
	         UserVO login = (UserVO) map.get("login");

	         //받는사람
	         if (login.getUser_id().equals(messageVO.getMessage_sender())) {

	            Gson gson = new Gson();
	            String msgJson = gson.toJson(messageVO);
	            websocketSession.sendMessage(new TextMessage(msgJson));
	         }


	      }
	   }

	@Override

	public void handleTransportError(

			WebSocketSession session, Throwable exception) throws Exception {

		log(session.getId() + " 익셉션 발생: " + exception.getMessage());

	}

	private void log(String logmsg) {

		System.out.println(new Date() + " : " + logmsg);

	}

}

UserVO , MessageVO , ChatRoomVO, ChatDAO, ChatDAOImpl

package com.almom.domain;

import java.util.Date;

public class UserVO {
	private String user_id;
	private String user_email;
	private String user_name;
	private String user_password;
	private String user_profileImagePath;
	private int user_sex;
	private String user_birth;
	private String user_job;
	private String user_phoneNumber;
	private String user_authCode;
	private String user_authStatus;
	private String user_isTutor;
	private String user_status;
	private String pageNumber;
	private String rnum;
	private Date user_log;
	private int ages;
	private int age_count;
	private int user_isAdmin;
	private int unReadCount;
	
	
	
	public int getUnReadCount() {
		return unReadCount;
	}


	public void setUnReadCount(int unReadCount) {
		this.unReadCount = unReadCount;
	}


	public int getUser_isAdmin() {
		return user_isAdmin;
	}


	public void setUser_isAdmin(int user_isAdmin) {
		this.user_isAdmin = user_isAdmin;
	}


	public int getAges() {
		return ages;
	}


	public void setAges(int ages) {
		this.ages = ages;
	}


	public int getAge_count() {
		return age_count;
	}


	public void setAge_count(int age_count) {
		this.age_count = age_count;
	}


	public Date getUser_log() {
		return user_log;
	}


	public void setUser_log(Date user_log) {
		this.user_log = user_log;
	}


	public String getPageNumber() {
		return pageNumber;
	}


	public void setPageNumber(String pageNumber) {
		this.pageNumber = pageNumber;
	}


	public String getRnum() {
		return rnum;
	}


	public void setRnum(String rnum) {
		this.rnum = rnum;
	}


	public String getUser_status() {
		return user_status;
	}


	public void setUser_status(String user_status) {
		this.user_status = user_status;
	}


	public String getUser_isTutor() {
		return user_isTutor;
	}


	public void setUser_isTutor(String user_isTutor) {
		this.user_isTutor = user_isTutor;
	}


	public String getUser_authCode() {
		return user_authCode;
	}


	public void setUser_authCode(String user_authCode) {
		this.user_authCode = user_authCode;
	}


	public String getUser_authStatus() {
		return user_authStatus;
	}


	public void setUser_authStatus(String user_authStatus) {
		this.user_authStatus = user_authStatus;
	}


	public void setUser_birth(String user_birth) {
		this.user_birth = user_birth;
	}
	

	public String getUser_birth() {
		return user_birth;
	}


	private String user_snsId;
	
	
	public void setUser_snsId(String user_snsId) {
		this.user_snsId = user_snsId;
	}
	
	public String getUser_snsId() {
		return user_snsId;
	}

	public String getUser_id() {
		return user_id;
	}
	public void setUser_id(String user_id) {
		this.user_id = user_id;
	}
	public String getUser_email() {
		return user_email;
	}
	public void setUser_email(String user_email) {
		this.user_email = user_email;
	}
	public String getUser_name() {
		return user_name;
	}
	public void setUser_name(String user_name) {
		this.user_name = user_name;
	}
	public String getUser_password() {
		return user_password;
	}
	public void setUser_password(String user_password) {
		this.user_password = user_password;
	}
	public String getUser_profileImagePath() {
		return user_profileImagePath;
	}
	public void setUser_profileImagePath(String user_profileImagePath) {
		this.user_profileImagePath = user_profileImagePath;
	}
	public int getUser_sex() {
		return user_sex;
	}
	public void setUser_sex(int user_sex) {
		this.user_sex = user_sex;
	}
	
	public String getUser_job() {
		return user_job;
	}
	public void setUser_job(String user_job) {
		this.user_job = user_job;
	}
	public String getUser_phoneNumber() {
		return user_phoneNumber;
	}
	public void setUser_phoneNumber(String user_phoneNumber) {
		this.user_phoneNumber = user_phoneNumber;
	}


	@Override
	public String toString() {
		return "UserVO [user_id=" + user_id + ", user_email=" + user_email + ", user_name=" + user_name
				+ ", user_password=" + user_password + ", user_profileImagePath=" + user_profileImagePath
				+ ", user_sex=" + user_sex + ", user_birth=" + user_birth + ", user_job=" + user_job
				+ ", user_phoneNumber=" + user_phoneNumber + ", user_authCode=" + user_authCode + ", user_authStatus="
				+ user_authStatus + ", user_isTutor=" + user_isTutor + ", user_status=" + user_status + ", pageNumber="
				+ pageNumber + ", rnum=" + rnum + ", user_log=" + user_log + ", ages=" + ages + ", age_count="
				+ age_count + ", user_isAdmin=" + user_isAdmin + ", unReadCount=" + unReadCount + ", user_snsId="
				+ user_snsId + "]";
	}

}

package com.almom.domain;

import java.util.Date;

import com.google.gson.Gson;

public class MessageVO {
	
	private String message_id;
	private String message_sender;
	private String message_receiver;
	private String message_content;
	private Date message_sendTime;
	private Date message_readTime;
	private String CHATROOM_chatroom_id;
	private String USER_user_id;
	private String TUTOR_USER_user_id;
	private int CLASS_class_id;
	private String user_profileImagePath;
	private String receiver_user_profileImagePath;
	private String user_name;
	private String receiver_user_name;
	private String class_name;
	private int class_id;
	private String TUTOR_tutor_id;
	private String tutor_name;
	private String tuti_id;
	private int unReadCount;
	
	
	public int getUnReadCount() {
		return unReadCount;
	}
	public void setUnReadCount(int unReadCount) {
		this.unReadCount = unReadCount;
	}
	public String getTuti_id() {
		return tuti_id;
	}
	public void setTuti_id(String tuti_id) {
		this.tuti_id = tuti_id;
	}
	public String getTutor_name() {
		return tutor_name;
	}
	public void setTutor_name(String tutor_name) {
		this.tutor_name = tutor_name;
	}
	public int getClass_id() {
		return class_id;
	}
	public void setClass_id(int class_id) {
		this.class_id = class_id;
	}
	public String getTUTOR_tutor_id() {
		return TUTOR_tutor_id;
	}
	public void setTUTOR_tutor_id(String tUTOR_tutor_id) {
		TUTOR_tutor_id = tUTOR_tutor_id;
	}
	public String getClass_name() {
		return class_name;
	}
	public void setClass_name(String class_name) {
		this.class_name = class_name;
	}
	public String getReceiver_user_name() {
		return receiver_user_name;
	}
	public void setReceiver_user_name(String receiver_user_name) {
		this.receiver_user_name = receiver_user_name;
	}
	public String getUser_profileImagePath() {
		return user_profileImagePath;
	}
	public void setUser_profileImagePath(String user_profileImagePath) {
		this.user_profileImagePath = user_profileImagePath;
	}
	public String getUser_name() {
		return user_name;
	}
	public void setUser_name(String user_name) {
		this.user_name = user_name;
	}
	public String getReceiver_user_profileImagePath() {
		return receiver_user_profileImagePath;
	}
	public void setReceiver_user_profileImagePath(String receiver_user_profileImagePath) {
		this.receiver_user_profileImagePath = receiver_user_profileImagePath;
	}
	public Date getMessage_sendTime() {
		return message_sendTime;
	}
	public void setMessage_sendTime(Date message_sendTime) {
		this.message_sendTime = message_sendTime;
	}
	public Date getMessage_readTime() {
		return message_readTime;
	}
	public void setMessage_readTime(Date message_readTime) {
		this.message_readTime = message_readTime;
	}
	public String getMessage_id() {
		return message_id;
	}
	public void setMessage_id(String message_id) {
		this.message_id = message_id;
	}
	public String getMessage_sender() {
		return message_sender;
	}
	public void setMessage_sender(String message_sender) {
		this.message_sender = message_sender;
	}
	public String getMessage_receiver() {
		return message_receiver;
	}
	public void setMessage_receiver(String message_receiver) {
		this.message_receiver = message_receiver;
	}
	public String getMessage_content() {
		return message_content;
	}
	public void setMessage_content(String message_content) {
		this.message_content = message_content;
	}

	public String getCHATROOM_chatroom_id() {
		return CHATROOM_chatroom_id;
	}
	public void setCHATROOM_chatroom_id(String cHATROOM_chatroom_id) {
		CHATROOM_chatroom_id = cHATROOM_chatroom_id;
	}
	public String getUSER_user_id() {
		return USER_user_id;
	}
	public void setUSER_user_id(String uSER_user_id) {
		USER_user_id = uSER_user_id;
	}

	public int getCLASS_class_id() {
		return CLASS_class_id;
	}
	public void setCLASS_class_id(int cLASS_class_id) {
		CLASS_class_id = cLASS_class_id;
	}
	public String getTUTOR_USER_user_id() {
		return TUTOR_USER_user_id;
	}
	public void setTUTOR_USER_user_id(String tUTOR_USER_user_id) {
		TUTOR_USER_user_id = tUTOR_USER_user_id;
	}
	
	public static MessageVO convertMessage(String source) {
		MessageVO message = new MessageVO();
		Gson gson = new Gson();
		message = gson.fromJson(source,  MessageVO.class);
		return message;
	}
	@Override
	public String toString() {
		return "MessageVO [message_id=" + message_id + ", message_sender=" + message_sender + ", message_receiver="
				+ message_receiver + ", message_content=" + message_content + ", message_sendTime=" + message_sendTime
				+ ", message_readTime=" + message_readTime + ", CHATROOM_chatroom_id=" + CHATROOM_chatroom_id
				+ ", USER_user_id=" + USER_user_id + ", TUTOR_USER_user_id=" + TUTOR_USER_user_id + ", CLASS_class_id="
				+ CLASS_class_id + ", user_profileImagePath=" + user_profileImagePath
				+ ", receiver_user_profileImagePath=" + receiver_user_profileImagePath + ", user_name=" + user_name
				+ ", receiver_user_name=" + receiver_user_name + ", class_name=" + class_name + ", class_id=" + class_id
				+ ", TUTOR_tutor_id=" + TUTOR_tutor_id + ", tutor_name=" + tutor_name + ", tuti_id=" + tuti_id
				+ ", unReadCount=" + unReadCount + "]";
	}

	
}

package com.almom.domain;

public class ChatRoomVO {

	
	private String chatroom_id;
	private String USER_user_id;
	private String TUTOR_USER_user_id;
	private int CLASS_class_id;
	public String getChatroom_id() {
		return chatroom_id;
	}
	public void setChatroom_id(String chatroom_id) {
		this.chatroom_id = chatroom_id;
	}
	public String getUSER_user_id() {
		return USER_user_id;
	}
	public void setUSER_user_id(String uSER_user_id) {
		USER_user_id = uSER_user_id;
	}
	public String getTUTOR_USER_user_id() {
		return TUTOR_USER_user_id;
	}
	public void setTUTOR_USER_user_id(String tUTOR_USER_user_id) {
		TUTOR_USER_user_id = tUTOR_USER_user_id;
	}
	public int getCLASS_class_id() {
		return CLASS_class_id;
	}
	public void setCLASS_class_id(int cLASS_class_id) {
		CLASS_class_id = cLASS_class_id;
	}
	@Override
	public String toString() {
		return "ChatRoomVO [chatroom_id=" + chatroom_id + ", USER_user_id=" + USER_user_id + ", TUTOR_USER_user_id="
				+ TUTOR_USER_user_id + ", CLASS_class_id=" + CLASS_class_id + "]";
	}
	
	
	

	
	
}

package com.almom.persistence;

import java.util.List;

import com.almom.domain.ChatRoomVO;
import com.almom.domain.MessageVO;

public interface ChatDAO {

	public void createRoom(ChatRoomVO vo)throws Exception;
	public ChatRoomVO isRoom(ChatRoomVO vo)throws Exception;
	public void insertMessage(MessageVO vo)throws Exception;
	public String getPartner(ChatRoomVO vo)throws Exception;
	public String getProfile(String str)throws Exception;
	public String getName(String str)throws Exception;
	public List<MessageVO> getMessageList(String str)throws Exception;
	public List<ChatRoomVO> getRoomList(String str)throws Exception;
	public List<ChatRoomVO> getRoomList2(String str)throws Exception;
	public MessageVO getRecentMessage(String str)throws Exception;
	//public String isGetMessageList(String str)throws Exception;
	
	public String getTutorId(String str)throws Exception;
	public List<ChatRoomVO> getRoomListTutor(String str)throws Exception;
	public void updateReadTime(int class_id , String user_id , String TUTOR_USER_user_id)throws Exception;
	public void updateReadTimeTutor(int class_id , String user_id , String TUTOR_USER_user_id)throws Exception;
	
	public int getUnReadCount(String TUTOR_USER_user_id, int class_id, String user_id)throws Exception;
	public int getUnReadCountTutor(String TUTOR_USER_user_id, int class_id, String user_id)throws Exception;
	
	public int getAllCount(String str);
	
}
package com.almom.persistence;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

import javax.inject.Inject;

import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Repository;

import com.almom.domain.ChatRoomVO;
import com.almom.domain.MessageVO;

@Repository
public class ChatDAOImpl implements ChatDAO{
	
	@Inject
	private SqlSession session;

	private static String namespace = "com.almom.mapper.ChatMapper";

	
	
	@Override
	public void createRoom(ChatRoomVO vo) throws Exception {
		// TODO Auto-generated method stub
		System.out.println("ㅅㅂ");
		session.insert(namespace+".createRoom" , vo);
		System.out.println("시팔");
	}



	@Override
	public ChatRoomVO isRoom(ChatRoomVO vo) throws Exception {
		// TODO Auto-generated method stub
		
		ChatRoomVO roomvo = null;
		roomvo = session.selectOne(namespace+".isRoom", vo);
		System.out.println("ss");
		System.out.println(roomvo);
		
		return roomvo;
	}



	@Override
	public void insertMessage(MessageVO vo) throws Exception {
		// TODO Auto-generated method stub
		
		session.insert(namespace+".insertMessage" , vo);
	}



	@Override
	public String getPartner(ChatRoomVO vo) throws Exception {
		// TODO Auto-generated method stub
		
		List<MessageVO> mvo = session.selectList(namespace+".getPartner", vo);
		
		return mvo.get(0).getUSER_user_id();
	}



	@Override
	public String getProfile(String str) throws Exception {
		// TODO Auto-generated method stub
		return session.selectOne(namespace+".getProfile" , str);
	}



	@Override
	public String getName(String str) throws Exception {
		// TODO Auto-generated method stub
		return session.selectOne(namespace+".getName" , str);
	}



	@Override
	public List<MessageVO> getMessageList(String str) throws Exception {
		// TODO Auto-generated method stub

			return session.selectList(namespace+".getMessageList" , str);
		
		
	}



	@Override
	public List<ChatRoomVO> getRoomList(String str) throws Exception {
		// TODO Auto-generated method stub
		return session.selectList(namespace+".getRoomList",str);
	}



	@Override
	public List<ChatRoomVO> getRoomList2(String str) throws Exception {
		// TODO Auto-generated method stub
		return session.selectList(namespace+".getRoomList2" , str);
	}



	@Override
	public MessageVO getRecentMessage(String str) throws Exception {
		// TODO Auto-generated method stub
		return session.selectOne(namespace+".getRecentMessage" , str);
	}



	@Override
	public String getTutorId(String str) throws Exception {
		// TODO Auto-generated method stub
		return session.selectOne(namespace+".getTutorId" , str) ;
	}



	@Override
	public List<ChatRoomVO> getRoomListTutor(String str) throws Exception {
		// TODO Auto-generated method stub
		return session.selectList(namespace+".getRoomListTutor" , str);
	}



	@Override
	public void updateReadTime(int class_id, String user_id, String TUTOR_USER_user_id) throws Exception {
		// TODO Auto-generated method stub
		
		HashMap<String, Object> map = new HashMap<String, Object> ();
		
		map.put("TUTOR_USER_user_id", TUTOR_USER_user_id);
		map.put("USER_user_id", user_id);
		map.put("CLASS_class_id", class_id);
		session.update(namespace+".updateReadTime" , map);
	}



	@Override
	public int getUnReadCount(String TUTOR_USER_user_id, int class_id, String user_id) throws Exception {
		// TODO Auto-generated method stub
		HashMap<String, Object> map = new HashMap<String, Object> ();
		
		map.put("TUTOR_USER_user_id", TUTOR_USER_user_id);
		map.put("USER_user_id", user_id);
		map.put("CLASS_class_id", class_id);
		
		
		return session.selectOne(namespace+".getUnReadCount" , map);
	}



	@Override
	public int getAllCount(String str) {
		// TODO Auto-generated method stub
		HashMap<String, Object> map = new HashMap<String, Object> ();
		
		map.put("USER_user_id", str);
		map.put("TUTOR_USER_user_id", str);
		if(session.selectOne(namespace+".getAllCount" ,map) ==null) {
			return 0;
		}else {
			
			return session.selectOne(namespace+".getAllCount" ,map);
		}
		
	}



	@Override
	public void updateReadTimeTutor(int class_id , String user_id , String TUTOR_USER_user_id) throws Exception {
		// TODO Auto-generated method stub
		HashMap<String, Object> map = new HashMap<String, Object> ();
		
		map.put("TUTOR_USER_user_id", TUTOR_USER_user_id);
		map.put("USER_user_id", user_id);
		map.put("CLASS_class_id", class_id);
		session.update(namespace+".updateReadTimeTutor" , map);
	}



	@Override
	public int getUnReadCountTutor(String TUTOR_USER_user_id, int class_id, String user_id) throws Exception {
		// TODO Auto-generated method stub
		HashMap<String, Object> map = new HashMap<String, Object> ();
		
		map.put("TUTOR_USER_user_id", TUTOR_USER_user_id);
		map.put("USER_user_id", user_id);
		map.put("CLASS_class_id", class_id);
		
		
		return session.selectOne(namespace+".getUnReadCountTutor" , map);
	}




	
}

SQL(ChatMapper.xml)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.almom.mapper.ChatMapper">

<insert id = "createRoom">
insert into CHATROOM (USER_user_id , TUTOR_USER_user_id, CLASS_class_id) 
values(#{USER_user_id}, #{TUTOR_USER_user_id} , #{CLASS_class_id} )


</insert>


<select id ="isRoom" resultType = "ChatRoomVO">

select * from CHATROOM WHERE USER_user_id = #{USER_user_id} and TUTOR_USER_user_id = #{TUTOR_USER_user_id} 
and CLASS_class_id = #{CLASS_class_id} 
</select>

<insert id = "insertMessage">
insert into MESSAGE (message_sender , message_receiver, message_content, 
CHATROOM_chatroom_id, USER_user_id , TUTOR_USER_user_id, CLASS_class_id)
values (#{message_sender}, #{message_receiver}, #{message_content} , #{CHATROOM_chatroom_id} , #{USER_user_id},
#{TUTOR_USER_user_id} , #{CLASS_class_id})
</insert>

<select id = "getPartner" resultType = "MessageVO">
SELECT USER_user_id from MESSAGE where TUTOR_USER_user_id = #{TUTOR_USER_user_id} and CLASS_class_id = #{CLASS_class_id}
</select>
<select id = "getProfile" resultType = "String">
select user_profileImagePath from USER WHERE user_id = #{user_id}
</select>

<select id = "getName" resultType = "String">
select user_name from USER where user_id = #{user_id}
</select>

<select id = "getMessageList" resultType = "MessageVO">
select m.* , user_name, user_profileImagePath from MESSAGE m left outer join USER u on m.message_sender = u.user_id where CHATROOM_chatroom_id = #{CHATROOM_chatroom_id}

</select>

<select id = "getRoomList" resultType = "ChatRoomVO">
select * from CHATROOM where USER_user_id = #{USER_user_id}
</select>
<select id = "getRoomList2" resultType = "ChatRoomVO">
select * from CHATROOM where TUTOR_USER_user_id = #{TUTOR_USER_user_id}
</select>

<select id = "getRecentMessage" resultType = "MessageVO">

select m.* , class_name, class_id , TUTOR_tutor_id from MESSAGE m left outer join CLASS c on m.CLASS_class_id = c.class_id 
where CHATROOM_chatroom_id = #{CHATROOM_chatroom_id} order by message_id desc limit 1;


</select>


<select id = "getTutorId" resultType = "String">
select tutor_id from TUTOR where USER_user_id = #{USER_user_id}
</select>

<update id ="updateReadTime">
update MESSAGE set message_readTime = NOW() where TUTOR_USER_user_id = #{TUTOR_USER_user_id} AND CLASS_class_id = #{CLASS_class_id} AND message_readTime = message_sendTime and message_sender = TUTOR_USER_user_id and USER_user_id = #{USER_user_id};
</update>
<update id ="updateReadTimeTutor">
update MESSAGE set message_readTime = NOW() where TUTOR_USER_user_id = #{TUTOR_USER_user_id} AND CLASS_class_id = #{CLASS_class_id} AND message_readTime = message_sendTime and message_sender = USER_user_id and USER_user_id = #{USER_user_id};

</update>


<select id = "getUnReadCount" resultType = "int">

select count(*) from MESSAGE where USER_user_id = #{USER_user_id} and TUTOR_USER_user_id = #{TUTOR_USER_user_id} AND CLASS_class_id = #{CLASS_class_id} AND message_readTime = message_sendTime and message_sender = TUTOR_USER_user_id;

</select>
<select id = "getUnReadCountTutor" resultType = "int">

select count(*) from MESSAGE where TUTOR_USER_user_id =#{TUTOR_USER_user_id} and CLASS_class_id = #{CLASS_class_id} AND message_readTime = message_sendTime and message_sender = USER_user_id and USER_user_id = #{USER_user_id};

</select>

<select id = "getAllCount" resultType = "int">
select count(*) from MESSAGE WHERE (TUTOR_USER_user_id = #{TUTOR_USER_user_id} and message_readTime = message_sendTime and message_sender != #{USER_user_id}) or (USER_user_id = #{USER_user_id} and message_readTime = message_sendTime and message_sender != #{USER_user_id}); 

</select>
</mapper>

최종 구현 화면

Post Sample Image

Post Sample Image