[Spring / WebSocket] Java Websocket을 이용한 1:1 채팅방, 단체 채팅방 만들기 - 2 [VO / Service / DAO / Mapper]
리트리버J
·2021. 5. 25. 10:01
채팅에 관한 문의사항이 많아져 추가로 VO / Service / DAO를 공유하며 상세한 설명을 덧붙여 보겠습니다.
사실 HandShake를 사용하지 않은 코드라, 완벽하진 않아서
다시 채팅부분만 그대로 붙여 쓸 수 있게 Git과 게시글을 준비중에 있는데
일단 급하신 분들을 위해 작성해보겠습니다.
※ 패키지가 다르기 때문에 그대로 복붙하시면 오류가 날 수 있습니다.
꼭 코드를 직접 한줄한줄 파악하시면서 작성해 주시길 바랍니다.
1. ChatSession :
현재 로그인 되어 있는 유저들을 저장하는 VO
DB 저장 X / 온라인 오프라인 확인용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
import java.util.ArrayList;
import org.springframework.stereotype.Component;
@Component("cSession")
public class ChatSession {
// static으로 필드변수를 설정하여 같은 ArrayList를 이용 할 수 있도록 선언합니다.
private static ArrayList<String> loginUser = new ArrayList<String>();
// 로그인 시 ArrayList에 추가합니다.
public void addLoginUser(String email) {
loginUser.add(email);
}
// 로그아웃 시 ArrayList에서 제거합니다.
public void removeLoginUser(String email) {
loginUser.remove(email);
}
// 현재 로그인 되어 있는 유저 목록을 가져옵니다.
public static ArrayList<String> getLoginUser() {
return loginUser;
}
// 자동 setter. 사용하진 않았습니다.
public static void setLoginUser(ArrayList<String> loginUser) {
ChatSession.loginUser = loginUser;
}
}
|
cs |
2. ChatRoom :
채팅방 VO
방번호와 사용자 - 상대방의 정보가 담겨있다.
roomId로 채팅방을 구분하며,
unReadCount를 통해 읽었는지 파악 할 수 있게 해준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
package com.fp.neezit.chat.model.vo;
public class ChatRoom {
private String roomId; // 방 번호
private String userEmail; // 사용자 이메일
private String userName; // 사용자 이름
private String userPic; // 사용자 사진
private String masterEmail; // 상대방 이메일
private String masterName; // 상대방 이름
private String masterPic; // 상대방 사진
private int unReadCount; // 안 읽은 메세지 수
public ChatRoom() {
super();
}
public ChatRoom(String roomId, String userEmail, String userName, String userPic, String masterEmail,
String masterName, String masterPic, int unReadCount) {
super();
this.roomId = roomId;
this.userEmail = userEmail;
this.userName = userName;
this.userPic = userPic;
this.masterEmail = masterEmail;
this.masterName = masterName;
this.masterPic = masterPic;
this.unReadCount = unReadCount;
}
public String getRoomId() {
return roomId;
}
public void setRoomId(String roomId) {
this.roomId = roomId;
}
public String getUserEmail() {
return userEmail;
}
public void setUserEmail(String userEmail) {
this.userEmail = userEmail;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPic() {
return userPic;
}
public void setUserPic(String userPic) {
this.userPic = userPic;
}
public String getMasterEmail() {
return masterEmail;
}
public void setMasterEmail(String masterEmail) {
this.masterEmail = masterEmail;
}
public String getMasterName() {
return masterName;
}
public void setMasterName(String masterName) {
this.masterName = masterName;
}
public String getMasterPic() {
return masterPic;
}
public void setMasterPic(String masterPic) {
this.masterPic = masterPic;
}
public int getUnReadCount() {
return unReadCount;
}
public void setUnReadCount(int unReadCount) {
this.unReadCount = unReadCount;
}
@Override
public String toString() {
return "ChatRoom [roomId=" + roomId + ", userEmail=" + userEmail + ", userName=" + userName + ", userPic="
+ userPic + ", masterEmail=" + masterEmail + ", masterName=" + masterName + ", masterPic=" + masterPic
+ ", unReadCount=" + unReadCount + "]";
}
}
|
cs |
3. ChatMessage :
본격적인 메세지 VO
방번호와 메세지번호 PK
sessionCount는 현재 1:1 채팅방에 들어와있는 유저 수이다.
sessionCount가 2이면 unReadCount는 0으로 DB에 집어넣을 수 있겠다.
[ => 2명이 들어와있으니 읽지않은 메세지는 없다.]
sessionCount가 1잉면 unReadCount는 1이 되는 것이다.
※ 이전 게시글의 WebSocketHandler에 나와 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
package com.fp.neezit.chat.model.vo;
public class ChatMessage {
private String roomId; // 방 번호
private String messageId; // 메세지 번호
private String message; // 메세지 내용
private String name; // 보낸이 이름
private String email; // 보낸이 이메일
private int unReadCount; // 안 읽은 메세지 수
private int sessionCount; // 현재 세션 수
public ChatMessage() {
super();
}
public ChatMessage(String roomId, String messageId, String message, String name, String email, int unReadCount,
int sessionCount) {
super();
this.roomId = roomId;
this.messageId = messageId;
this.message = message;
this.name = name;
this.email = email;
this.unReadCount = unReadCount;
this.sessionCount = sessionCount;
}
public String getRoomId() {
return roomId;
}
public void setRoomId(String roomId) {
this.roomId = roomId;
}
public String getMessageId() {
return messageId;
}
public void setMessageId(String messageId) {
this.messageId = messageId;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public int getUnReadCount() {
return unReadCount;
}
public void setUnReadCount(int unReadCount) {
this.unReadCount = unReadCount;
}
public int getSessionCount() {
return sessionCount;
}
public void setSessionCount(int sessionCount) {
this.sessionCount = sessionCount;
}
@Override
public String toString() {
return "ChatMessage [roomId=" + roomId + ", messageId=" + messageId + ", message=" + message + ", name=" + name
+ ", email=" + email + ", unReadCount=" + unReadCount + ", sessionCount=" + sessionCount + "]";
}
}
|
cs |
4. 로그인 시 ChatSession에 추가해주기.
다른 나머지 로직들은 다 제거하고, 채팅에 관한 로그인 로직만 작성했으니
자신의 코드에 추가하면 됩니다.
사실 HandShake-Interceptor를 통해 Handler에서 전부 처리 할 수 있지만,
현재 코드는 HandShake기법을 사용하지 않았으므로 로그인 Controller에 따로 구성했습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
@SessionAttributes({"loginUser","master2","rankPic","admin"}) // Model에 loginUser라는 키값으로 객체가 추가되면 자동으로 세션에 추가하라는 의미의 어노테이션
@Controller
public class UserContoller {
@Autowired
private UserService uService;
/* 채팅 */
@Autowired
private ChatSession cSession;
/**
* 1. 로그인 세션 메소드 ( 암호화 처리 )
*
* @param u
* @param model
* @return
*/
@RequestMapping(value = "login.do", method = {RequestMethod.GET, RequestMethod.POST})
public String userLogin(User u, Model model, HttpServletRequest request) { // view에 전달하는 데이터를 Model에 담는다.
User loginUser = uService.loginUser(u);
/* 채팅 */
// 현재 로그인 한 User 채팅 Session ArrayList에 추가.
cSession.addLoginUser(loginUser.getEmail());
}
/**
* 2. 로그아웃 세션 메소드 (@SessionAttributes가 있기 때문에 session.invalidate()가 먹히지 않으므로)
*
* @param status
* @return
*/
@RequestMapping("logout.do")
public String logout(HttpSession session) {
/* 채팅 */
User u = (User)session.getAttribute("loginUser");
/* 채팅 */
// 로그아웃한 User를 채팅 Session ArrayList에서 삭제.
cSession.removeLoginUser(u.getEmail());
}
|
cs |
5. Service
Service는 interface이기 때문에 따로 Impl을 작성해주셔야 합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
package com.fp.neezit.chat.model.service;
import java.util.List;
import com.fp.neezit.chat.model.vo.ChatMessage;
import com.fp.neezit.chat.model.vo.ChatRoom;
public interface ChatService {
/**
* 방 번호를 선택하는 메소드
* @param roomId
* @return
*/
ChatRoom selectChatRoom(String roomId);
/**
* 채팅 메세지 DB 저장
* @param chatMessage
* @return
*/
int insertMessage(ChatMessage chatMessage);
/**
* 메세지 내용 리스트 출력
* @param roomId
* @return
*/
List<ChatMessage> messageList(String roomId);
/**
* 채팅 방 DB 저장
* @param room
* @return
*/
int createChat(ChatRoom room);
/**
* DB에 채팅 방이 있는지 확인
* @param room
* @return
*/
ChatRoom searchChatRoom(ChatRoom room);
/**
* 채팅 방 리스트 출력
* @param userEmail
* @return
*/
List<ChatRoom> chatRoomList(String userEmail);
/**
* 채팅 읽지 않은 메세지 수 출력
* @param message
* @return
*/
int selectUnReadCount(ChatMessage message);
/**
* 읽은 메세지 숫자 0으로 바꾸기
* @param message
* @return
*/
int updateCount(ChatMessage message);
}
|
cs |
6. DAO
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
package com.fp.neezit.chat.model.dao;
import java.util.List;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.fp.neezit.chat.model.vo.ChatMessage;
import com.fp.neezit.chat.model.vo.ChatRoom;
@Repository
public class ChatDao{
@Autowired
SqlSessionTemplate sqlSession;
public ChatRoom selectChatRoom(String roomId) {
return sqlSession.selectOne("chatMapper.selectChatRoom", roomId);
}
public int insertMessage(ChatMessage chatMessage) {
return sqlSession.insert("chatMapper.insertMessage", chatMessage);
}
public List<ChatMessage> messageList(String roomId) {
return sqlSession.selectList("chatMapper.messageList", roomId);
}
public int createChat(ChatRoom room) {
return sqlSession.insert("chatMapper.createChat", room);
}
public ChatRoom searchChatRoom(ChatRoom room) {
return sqlSession.selectOne("chatMapper.searchChatRoom", room);
}
public List<ChatRoom> chatRoomList(String userEmail) {
return sqlSession.selectList("chatMapper.chatRoomList", userEmail);
}
public int selectUnReadCount(ChatMessage message) {
return sqlSession.selectOne("chatMapper.selectUnReadCount",message);
}
public int updateCount(ChatMessage message) {
return sqlSession.update("chatMapper.updateCount", message);
};
}
|
cs |
7. Mapper.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
<?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="chatMapper">
<resultMap type="ChatRoom" id="chatRoomResultSet">
<id property="roomId" column="ROOM_ID" />
<result property="userEmail" column="USER_EMAIL" />
<result property="userName" column="USER_NAME" />
<result property="userPic" column="USER_PIC" />
<result property="masterEmail" column="MASTER_EMAIL" />
<result property="masterName" column="MASTER_NAME" />
<result property="masterPic" column="MASTER_PIC" />
</resultMap>
<resultMap type="ChatMessage" id="chatMessageResultSet">
<id property="messageId" column="MESSAGE_ID" />
<result property="roomId" column="ROOM_ID" />
<result property="message" column="MESSAGE_CONTENT" />
<result property="name" column="USER_NAME" />
<result property="email" column="USER_EMAIL" />
<result property="unReadCount" column="UNREAD_COUNT" />
</resultMap>
<!-- 신규 채팅방일 때 채팅 방 생성 -->
<insert id="createChat" parameterType="ChatRoom">
insert into CHATROOM values(SEQ_CHATROOM_ID.NEXTVAL, #{userEmail}, #{userName}, DEFAULT, #{masterEmail}, #{masterName}, #{masterPic})
</insert>
<select id="selectChatRoom" parameterType="string" resultMap="chatRoomResultSet">
SELECT * FROM CHATROOM
WHERE ROOM_ID = #{roomId}
</select>
<insert id="insertMessage" parameterType="ChatMessage">
<if test="sessionCount == 1">
INSERT INTO CHATMESSAGE VALUES(#{roomId}, SEQ_CHATMESSAGE_ID.NEXTVAL, #{message}, #{name}, #{email}, DEFAULT)
</if>
<if test="sessionCount == 2">
INSERT INTO CHATMESSAGE VALUES(#{roomId}, SEQ_CHATMESSAGE_ID.NEXTVAL, #{message}, #{name}, #{email}, 0)
</if>
</insert>
<select id="messageList" parameterType="string" resultMap="chatMessageResultSet">
SELECT * FROM CHATMESSAGE
WHERE ROOM_ID = #{rooomId}
</select>
<select id="searchChatRoom" parameterType="ChatRoom" resultMap="chatRoomResultSet">
SELECT * FROM CHATROOM
WHERE USER_EMAIL = #{userEmail} AND MASTER_EMAIL = #{masterEmail}
</select>
<select id="chatRoomList" parameterType="string" resultMap="chatRoomResultSet">
SELECT * FROM CHATROOM
WHERE USER_EMAIL = #{userEmail} OR MASTER_EMAIL = #{userEmail}
</select>
<select id="selectUnReadCount" parameterType="ChatMessage" resultType="_int">
SELECT COUNT(*) FROM CHATMESSAGE
WHERE ROOM_ID = #{roomId} AND USER_EMAIL != #{email} AND UNREAD_COUNT = 1
</select>
<update id="updateCount" parameterType="ChatMessage">
UPDATE CHATMESSAGE
SET UNREAD_COUNT = 0
WHERE ROOM_ID = #{roomId} AND USER_EMAIL != #{email} AND UNREAD_COUNT = 1
</update>
</mapper>
|
cs |