본문 바로가기
학원/spring

1.26 (tiles-채팅방 목록보기, 상세)

by 쿠룽지 2024. 1. 28.
728x90
반응형

 

 

 

모든 작성은 끝

이제 채팅 연결

 

 

 

<목록 표시하기>

 

 

 

 

TalkMapper.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="kr.spring.talk.dao.TalkMapper">

	<!-- 사용할 map설정 -->
	<resultMap type="talkRoomVO" id="talkMap">
		<result property="talkVO.message" column="message"/>
		<result property="talkVO.chat_date" column="chat_date"/>
		<result property="talkMemberVO.room_name" column="room_name"/>
	</resultMap>
	
	<!-- sql태그 -->
	<sql id="talkSub">
		FROM sptalkroom JOIN sptalk_member m USING(talkroom_num)
		LEFT OUTER JOIN (SELECT
							talkroom_num,
							mem_num,
							COUNT(*) room_cnt
						FROM sptalk_read
						WHERE mem_num=#{mem_num}
						GROUP BY talkroom_num,mem_num) USING (talkroom_num)
		LEFT OUTER JOIN (SELECT
							talk_num,
							<![CDATA[
							REPLACE(REPLACE(REPLACE(message,'<','&lt;'),'>','&gt;'),'@{member}@','') message,
							]]>
							chat_date,
							talkroom_num
						FROM sptalk WHERE talk_num IN (SELECT
															MAX(talk_num) talk_num
														FROM sptalk
														GROUP BY talkroom_num))
		USING(talkroom_num)
		WHERE m.mem_num=#{mem_num}
		<if test="keyword != null and keyword != ''">
			AND room_name LIKE '%' || #{keyword} || '%'
		</if>
	</sql>
	
	<!-- 개수 -->
	<select id="selectRowCount" parameterType="map" resultType="integer">
		SELECT
		  COUNT(*)
		<include refid="talkSub"></include>
	</select>
	
	<!-- 목록 -->
	<select id="selectTalkRoomList" parameterType="map" resultMap="talkMap">
		SELECT
		  *
		FROM (SELECT
				a.*,
				rownum rnum
			  FROM (SELECT
			  		  *
			  		<include refid="talkSub"></include>
			  		ORDER BY chat_date DESC)a)
		<![CDATA[
		WHERE rnum >= #{start} AND rnum <= #{end}
		]]>
	</select>
</mapper>

1.
개수/목록 sql문 둘다
FROM sptalkroom 없애고 talkSub sql문 include

2.
채팅 메시지 날짜=null일 경우 채팅방 날짜  표시
목록에서 <include refid="talkSub"></include> ORDER BY chat_date DESC)a)
chat_date 라고 수정

===========================

실행 결과

 

 

 

 

 

 


 

 

 

 

<채팅 데이터 읽어오기>

 

 

 

 

TalkMapper.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="kr.spring.talk.dao.TalkMapper">

	<!-- 사용할 map설정 -->
	<resultMap type="talkRoomVO" id="talkMap">
		<result property="talkVO.message" column="message"/>
		<result property="talkVO.chat_date" column="chat_date"/>
		<result property="talkMemberVO.room_name" column="room_name"/>
	</resultMap>
	
	<!-- sql태그 -->
	<sql id="talkSub">
		FROM sptalkroom JOIN sptalk_member m USING(talkroom_num)
		LEFT OUTER JOIN (SELECT
							talkroom_num,
							mem_num,
							COUNT(*) room_cnt
						FROM sptalk_read
						WHERE mem_num=#{mem_num}
						GROUP BY talkroom_num,mem_num) USING (talkroom_num)
		LEFT OUTER JOIN (SELECT
							talk_num,
							<![CDATA[
							REPLACE(REPLACE(REPLACE(message,'<','&lt;'),'>','&gt;'),'@{member}@','') message,
							]]>
							chat_date,
							talkroom_num
						FROM sptalk WHERE talk_num IN (SELECT
															MAX(talk_num) talk_num
														FROM sptalk
														GROUP BY talkroom_num))
		USING(talkroom_num)
		WHERE m.mem_num=#{mem_num}
		<if test="keyword != null and keyword != ''">
			AND room_name LIKE '%' || #{keyword} || '%'
		</if>
	</sql>
	
	<!-- 개수 -->
	<select id="selectRowCount" parameterType="map" resultType="integer">
		SELECT
		  COUNT(*)
		<include refid="talkSub"></include>
	</select>
	
	<!-- 목록 -->
	<select id="selectTalkRoomList" parameterType="map" resultMap="talkMap">
		SELECT
		  *
		FROM (SELECT
				a.*,
				rownum rnum
			  FROM (SELECT
			  		  *
			  		<include refid="talkSub"></include>
			  		ORDER BY chat_date DESC)a)
		<![CDATA[
		WHERE rnum >= #{start} AND rnum <= #{end}
		]]>
	</select>
	
	<!-- 채팅 멤버 읽기 -->
	<select id="selectTalkMember" parameterType="integer" resultType="talkMemberVO">
		SELECT
			mem_num,
			id,
			room_name
		FROM sptalk_member JOIN spmember
		USING(mem_num)
		WHERE talkroom_num=#{talkroom_num}
	</select>
	
	<!-- 채팅 메시지 읽기 -->
	<select id="selectTalkDetail" parameterType="integer" resultType="talkVO">
		SELECT
			<![CDATA[
			REPLACE(REPLACE(message,'<','&lt;'),'>','&gt;') message,
			]]>
			chat_date,
			read_count,
			mem_num,
			id
		FROM sptalk
		LEFT OUTER JOIN (SELECT
							talk_num,
							COUNT(*) read_count
						FROM sptalk_read
						GROUP BY talk_num) USING(talk_num)
		JOIN spmember USING(mem_num)
		WHERE talkroom_num=#{talkroom_num}
		AND chat_date >= (SELECT
							member_date
						  FROM sptalk_member
						  WHERE talkroom_num=#{talkroom_num}
						  AND mem_num=#{mem_num}) /*멤버 등록일 이후의 정보만 읽어옴*/
		ORDER BY chat_date ASC
	</select>

</mapper>

1.
SELECT
member_date
FROM sptalk_member
 WHERE talkroom_num=#{talkroom_num}
 AND mem_num=#{mem_num})

멤버 초대/등록을 했는데 그 멤버의 초대 전 정보까지 읽어올 순 없기 때문에 등록일 이후의 정보만 읽어오게 함
그래서 sptalk_member에 date가 있는것


2.
ORDER BY chat_date ASC
메시지 정렬은 날짜 오름차순으로 정렬
그래서 최신 메시지가 아래, 위로 올리면 예전 메시지


3.
<![CDATA[
REPLACE(REPLACE(message,'<','&lt;'),'>','&gt;') message,
]]>
chat_date,
read_count,
mem_num,
id


+ 메시지 HTML태그 막기위해 *에서 수동으로 읽어올 정보 다시 지정

 

 

 

 

 

 

<읽은 채팅 기록 삭제 코드 작성> 

과부하가 발생하는걸 방지하기 위해 읽은건 삭제

 

 

TalkMapper.java

//읽은 채팅 기록 삭제
@Delete("DELETE FROM sptalk_read WHERE talkroom_num=#{talkroom_num} AND mem_num=#{mem_num}")
public void deleteTalkRead(Map<String,Integer> map);

 

 

 

 

 

 

ajax로 실시간 채팅을 구현하기 때문에 구현 순서는

목록 -> detail -> 읽기 -> 쓰기 순으로 작성하는 게 좋을 것 같다고 하심

 

 

 

 

 

TalkService에 채팅 메서드 추가 작성

TalkService.java

package kr.spring.talk.service;

import java.util.List;
import java.util.Map;

import kr.spring.talk.vo.TalkMemberVO;
import kr.spring.talk.vo.TalkRoomVO;
import kr.spring.talk.vo.TalkVO;

public interface TalkService {
	//채팅방 목록
	public List<TalkRoomVO> selectTalkRoomList(Map<String,Object> map);
	public int selectRowCount(Map<String,Object> map);
	//채팅방 생성
	public void insertTalkRoom(TalkRoomVO talkRoomVO);
	//채팅 멤버 읽기
	public List<TalkMemberVO> selectTalkMember(int talkroom_num);

	
	//채팅 메시지 등록
	public void insertTalk(TalkVO talkVO);
	//채팅 메시지 읽기
	public List<TalkVO> selectTalkDetail(Map<String,Integer> map);
}

TalkMapper 채팅메시지번호생성~ 기록삭제 까지 복사해서 Service파일에 복붙

채팅 메시지 등록
insertTalk 안에 selectTalkNum
insertTalkRead도 내부적으로 하는거라 삭제 / deleteTalkRead도 삭제


++
안 쓰는 자원 한번에 지우는 방법
source > organize imports
누르면 자동으로 import 정리해줌

 

 

 

 

 

TalkServiceImpl.java

아까 명시한 순대로 insert보다 select를 먼저 작성

package kr.spring.talk.service;

import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import kr.spring.talk.dao.TalkMapper;
import kr.spring.talk.vo.TalkMemberVO;
import kr.spring.talk.vo.TalkRoomVO;
import kr.spring.talk.vo.TalkVO;

@Service
@Transactional
public class TalkServiceImpl implements TalkService{
	
	@Autowired
	private TalkMapper talkMapper;
	
	@Override
	public List<TalkRoomVO> selectTalkRoomList(Map<String, Object> map) {
		return talkMapper.selectTalkRoomList(map);
	}

	@Override
	public int selectRowCount(Map<String, Object> map) {
		return talkMapper.selectRowCount(map);
	}

	@Override
	public void insertTalkRoom(TalkRoomVO talkRoomVO) {
		//기본키 생성해서 넣어줌
		talkRoomVO.setTalkroom_num(talkMapper.selectTalkRoomNum());
		//채팅방 생성
		talkMapper.insertTalkRoom(talkRoomVO);
		
		//입장 메시지 처리
		talkRoomVO.getTalkVO().setTalk_num(talkMapper.selectTalkNum()); //message pk생성
		talkRoomVO.getTalkVO().setTalkroom_num(talkRoomVO.getTalkroom_num()); //위에서 만들어진거 가져오기
		talkMapper.insertTalk(talkRoomVO.getTalkVO());
		
		
		//채팅방 멤버 생성
		for(int mem_num : talkRoomVO.getMembers()) {
			talkMapper.insertTalkRoomMember(talkRoomVO.getTalkroom_num(),
											talkRoomVO.getBasic_name(),
											mem_num);
		}
	}

	@Override
	public List<TalkMemberVO> selectTalkMember(int talkroom_num) {
		return talkMapper.selectTalkMember(talkroom_num);
	}
	
	
	//==============================채팅 메시지
	
	@Override
	public void insertTalk(TalkVO talkVO) {
		// TODO Auto-generated method stub
	}

	@Override
	public List<TalkVO> selectTalkDetail(Map<String, Integer> map) {
		//읽은 채팅 기록 삭제
		talkMapper.deleteTalkRead(map);
		return talkMapper.selectTalkDetail(map);
	}
}

deleteTalkRead (읽은 채팅 삭제) + selectTalkDetail(map); (list로 반환)

 

 

 

 

 

 

TalkController

/* ============================
 * 채팅 메시지 처리
 * ============================*/
//채팅 메시지 페이지 호출
@RequestMapping("/talk/talkDetail")
public String talkDetail(@RequestParam int talkroom_num,
                         Model model, HttpSession session) {
    String chatMember = ""; //빈문자열에 붙이기 위해 변수 생성+초기화
    String room_name = "";

    MemberVO user = (MemberVO)session.getAttribute("user");

    List<TalkMemberVO> list = talkService.selectTalkMember(talkroom_num);
    for(int i=0; i<list.size(); i++) {
        TalkMemberVO vo = list.get(i);
        //로그인한 회원의 채팅방 이름 셋팅
        if(user.getMem_num() == vo.getMem_num()) {
            room_name = vo.getRoom_name();
        }
        //채팅 멤버 저장
        if(i>0) chatMember += ", ";
        chatMember += list.get(i).getId();
    }

    //채팅 멤버 id
    model.addAttribute("chatMember", chatMember);
    //채팅 멤버 수
    model.addAttribute("chatCount", list.size());
    //로그인한 회원의 채팅방 이름
    model.addAttribute("room_name", room_name);

    return "talkDetail";
}

1.
채팅 페이지 호출 시
1) for문에서 채팅방 이름 셋팅+멤버 저장
2) 저장 작업
(채팅 멤버 수=list.size)

2.
실제 메시지는 ajax통신으로 처리할 거기 때문에 talkDetail return함

 

 

 

 

 

 

 

 

tiles-def

talk.xml

</definition>
    <definition name="talkDetail" extends="myPage">
    <put-attribute name="title" value="채팅하기"/>
    <put-attribute name="body" value="/WEB-INF/views/talk/talkDetail.jsp"/>
</definition>

 

 

 

 

 

 

 

views
talk
talkDetail.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!-- 내용 시작 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.6.0.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/message.talk.js"></script>
<div id="talkDetail" class="page-main">
	<h1 id="chatroom_title"><span id="chatroom_name">${room_name}</span>
		채팅방 <input type="button" value="채팅방이름 변경" id="change_name">
	</h1>
	<div class="align-right">
		<input type="button" value="목록" onclick="location.href='talkList'">
	</div>
	<p>
		채팅 멤버 :
		<span id="chat_member">${chatMember}</span><span id="chat_mcount">(${chatCount}명)</span>
	</p>
	<div id="chatting_message"></div>
	<form method="post" id="detail-form">
		<input type="hidden" name="talkroom_num" id="talkroom_num" value="${param.talkroom_num}">
		<ul>
			<li>
				<textarea rows="5" cols="40" name="message" id="message"></textarea>
			</li>
		</ul>
		<div id="message_btn">
			<input type="submit" value="전송"> <!-- 메시지 전송하는 버튼 (엔터만 쳐도 전송할 수 있음) -->
		</div>
	</form>
</div>
<!-- 내용 끝 -->

1.
메시지 입력 form에서 hidden값 = 수신그룹
<input type="hidden" name="talkroom_num" id="talkroom_num" value="${param.talkroom_num}">
>> talkroom_num이 수신그룹 의미

 

 

실행 화면

채팅방 클릭 후 상세로 들어가면 다음과 같이 뜸

 

728x90
반응형