고래씌

[SpringBoot] 2-3. React 스프링부트에 연동(채팅방 상세보기, 메시지) 본문

Server/SpringBoot

[SpringBoot] 2-3. React 스프링부트에 연동(채팅방 상세보기, 메시지)

고래씌 2024. 2. 6. 09:51

1. React 스프링부트에 연동(채팅방 상세보기)

 
▶ App.js

 
=> <Route path="detail/:chatRoomNo" ~ 추가
=>  <Context.Provider> 위에 <main></main> 태그로 묶기
 
 
▶ ChattingRoomList.js
=> 사용자들이 채팅방에 참여할수있도록 참여버튼 추가

 
 
=> 채팅방참여 함수 생성 추가

    let navi = useNavigate();

    function 채팅방참여(채팅방번호){
        navi('/chat/detail/'+채팅방번호);
    }

 
 
 
 
 
 
▶ ChattingRoom.js
 
=> 사용자의 접속상태를 표시하는데 웹소켓과 연동해서 실시간으로 바뀌게 할 예정
 
=> userNo를 가져와야하는데 redux에서 꺼내오는 방법이 있음. useSelector를 이용하여 꺼내옴
=> 채팅방 번호는 파라미터 값을 이용하여 가져옴

import { useEffect } from "react"
import axios from 'axios';
import { useSelector } from "react-redux";
import { useParams } from "react-router-dom";
import { useState } from "react";

export default function ChattingRoom (){

    // userNo를 가져와야하는데 redux에서 꺼내오는 방법이 있음. useSelector를 이용하여 꺼내옴
    let user = useSelector((state) => state.user)  // store에서 키값만 제시해서 꺼내오면 됨

    // 채팅방번호는 파라미터 값을 이용하여 가져올 예정
    const {chatRoomNo} = useParams();   // chatRoomNo로 넘어온 데이터를 변수로 꺼내어 사용

    let [chatMessages, setChatMessages] = useState([]);

    useEffect(() => {

        // 1) CHAT_ROOM_JOIN 테이블에 참여자정보 추가
        let chatRoomJoin = {
            userNo : user.userNo,
            chatRoomNo,
            userStatus : 1
        }


        axios
        .post("/api/joinChatRoom", chatRoomJoin)
        .then((res) => {
            console.log('참여완료');
        })


        // 2) 채팅방 메세지 목록 가져오기
        axios
        .get("/api/chatMessage/chatRoomNo" + chatRoomNo)
        .then((list) => {   // 만약 정상적으로 가져왔다면 배열형태의 메시지 가져옴
            setChatMessages(list.data);
        }).catch(err => console.log(err))


        // 3) 채팅방 참여자 정보 조회
    },[])

    return (
        <>
            {/* 채팅방 참여자 목록을 보여주는 부분 */}
            <div className="chat-room-Members">
                <h4>참여자 목록</h4>
                <ul className="chat-room-members-ul">
                    <li>
                        {/* 사용자의 접속상태를 표시. 웹소켓과 연동해서 실시간으로 바뀌게 할 예정 */}
                        <span className="user-status online"></span>루피1
                    </li>
                    <li>
                        <span className="user-status offline"></span>루피2
                    </li>
                </ul>
            </div>
            <div className="chatting-area">
                <div className="chat-header">
                    <button className="btn btn-outline-danger">나가기</button>
                </div>

                <ul className="display-chatting">
                   
                </ul>
                <div className="input-area">
                    <textarea rows="3" name="message"></textarea>
                    <button>전송</button>
                </div>
            </div>
        </>
    )
}

 
 
▶ ChatController.java

//	채팅방 참여
	@PostMapping("/joinChatRoom")
	public Member joinChatRoom(@RequestBody ChatRoomJoin crj) {
		
		return service.joinChatRoom(crj);
	}

 
 
▶ ChatService.java

//	채팅방 참여
	public Member joinChatRoom(ChatRoomJoin crj) {
		try {
			// ChatRoomJoin 테이블에 insert 시키는 함수
			dao.joinChatRoom(crj);
			
		}catch(Exception e) {
			
		}
		
		
		return dao.selectUser(crj);
	}

 
 
▶ ChatDao.java

//	채팅방 참여자 추가
	public void joinChatRoom(ChatRoomJoin crj) {
		session.insert("chat.joinChatRoom", crj);
	}

//	채팅방 참여자 조회
	public Member selectUser(ChatRoomJoin crj) {
		return session.selectOne("chat.selectUser", crj);
	}

 
 
▶ chatting-mapper.xml
 
=> resultType 이 아닌, resultMap을 사용하는 이유는 Member 클래스에 private userStatus가 enum 객체이기 때문이다!
 

	<!-- 채팅방 참여자 추가 -->
	<insert id="joinChatRoom">
		INSERT INTO CHAT_ROOM_JOIN
		VALUES(
			#{userNo},
			#{chatRoomNo},
			#{userStatus}
		)
	</insert>
	
	<!-- 특수한 enum 필드때문에 resultType으로 못하고 resultMap 이용 -->
	<resultMap type="member" id="userResultSet">
		
	</resultMap>
	
	<!-- 채팅방 참여자 조회 -->
	<select id="selectUser" resultMap="userResultSet">
		
	</select>

 
 

 
=> UserStatusHandelr.java 클래스 파일 생성
 
▶ UserStatusHandelr.java

package com.kh.api.model.handelr;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;

import com.kh.api.model.vo.UserStatus;

@MappedTypes(UserStatus.class)
@MappedJdbcTypes(JdbcType.INTEGER)
public class UserStatusHandelr extends BaseTypeHandler<UserStatus>{

	@Override
	public void setNonNullParameter(PreparedStatement ps, int i, UserStatus parameter, JdbcType jdbcType)
			throws SQLException {
		ps.setInt(i, Integer.parseInt(parameter.getUserStatus()));
	}

	@Override
	public UserStatus getNullableResult(ResultSet rs, String columnName) throws SQLException {
		return UserStatus.getValueOfUserStatus(rs.getInt(columnName));
	}

	@Override
	public UserStatus getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
		return UserStatus.getValueOfUserStatus(rs.getInt(columnIndex));
	}

	@Override
	public UserStatus getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
		return UserStatus.getValueOfUserStatus(cs.getInt(columnIndex));
	}

}

 
 
▶ 결과
 

 
 


2. 채팅방 메시지 목록 가져오기

 
 
▶ ChattingRoom.js

=>  추가
 
 
=> Messages.js 파일 생성

 
 
▶ Messages.js

import { useSelector } from "react-redux"
import MyChat from "./MyChat";
import OtherChat from "./OtherChat";

export default function Message({chatMessages}) {
    
    
    let user = useSelector((state) => state.user);

    return(
        chatMessages.map((chatMessage) => {
            return (

                chatMessage.userNo == user.userNo ? <MyChat chatMessage={chatMessage} /> : <OtherChat chatMessage={chatMessage}/>
                
            )
        })
    )
}

 
 
=> MyChat.js 과 OtherChat.js 파일 생성

 
 
▶ MyChat.js

export default function MyChat({chatMessage}){
    return (
        <li className="myChat">
            <span className="chatDate">{chatMessage.createDate}</span>
            <p className="chat">{chatMessage.message}</p>
        </li>
    )
}

 
 
▶ OhterChat.js

export default function OtherChat({chatMessage}){
    return(
        <li>
            <div>
                <img src={chatMessage.profile} style={{width:'30px', borderRadius:'50px'}} />
                <b>{chatMessage.nickName}</b>
            </div>
            <p className="chat">{chatMessage.message}</p>
            <span className="chatDate">{chatMessage.createDate}</span>
        </li>
    )
}

 
 
 
▶ ChatController.java

//	메시지 목록 조회
	@GetMapping("/chatMessage/chatRoomNo/{chatRoomNo}")
	public List<ChatMessage> selectMessages(@PathVariable int chatRoomNo){
		return service.selectMessages(chatRoomNo);
	}

 
 
▶ ChatService.java

//	메시지 목록 조회
	public List<ChatMessage> selectMessages(int chatRoomNo) {
		return dao.selectMessages(chatRoomNo);
	}

 
 
▶ ChatDao.java

//	메시지 목록 조회
	public List<ChatMessage> selectMessages(int chatRoomNo) {
		return session.selectList("chatMapper.selectMessages", chatRoomNo);
	}

 
 
▶ chatting-mapper.xml

	<!-- 채팅 메세지 조회 -->
	<select id="selectMessages" resultType="chatMessage">
		SELECT
			CM_NO,
			MESSAGE,
			CHAT_ROOM_NO,
			USER_NO,
			NICK_NAME,
			PROFILE
		FROM CHAT_MESSAGE
		JOIN MEMBER USING(USER_NO)
		WHERE CHAT_ROOM_NO = #{chatRoomNo}
	</select>