1.25 (tiles-그룹채팅 멤버 초대, 채팅방 생성)
<채팅 초대 멤버 선택 해제>
message.talk.js
//선택한 채팅방 멤버 삭제
$(document).on('click','.member-span',function(){
let id = $(this).attr('data-id');
//채팅 멤버가 저장된 배열에서 삭제할 멤버의 id를 제거
member_list.splice(member_list.indexOf(id),1);
$(this).remove(); // this=이벤트가 발생한 span태그
if($('#name_checked').is(':checked')){//채팅방 이름 자동생성이 설정되어있다면
makeRoom_name();
}
if($('#talk_member span').length == 0){ //개설자밖에 없을 경우
//초기화
$('#name_span').text(''); //span태그(보여짐)
$('#basic_name').val('');//input태그(내부적으로 동작)
}
});
member_list.splice(member_list.indexOf(id),1);
id가 있는 index에서 1개만 지우겠다 라는 뜻
실행 후 채팅방 회원 다 x자 눌러서
삭제하면 채팅방 이름이 초기화됨
이전에 만들었던 자바빈 파일에 넣고 작업 다시 시작
kr.spring.talk.vo
TalkMemberVO
package kr.spring.talk.vo;
import java.sql.Date;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class TalkMemberVO {
private int talkroom_num;
private int mem_num;
private String room_name;
private Date member_date;
//추가
private String id;
}
SQL문 작성
TalkMapper.java
//채팅방 번호 생성 (PK)
@Select("SELECT sptalkroom_seq.nextval FROM dual")
public int selectTalkRoomNum();
//채팅방 생성
@Insert("INSERT INTO sptalkroom (talkroom_num,basic_name) VALUES (#{talkroom_num},#{basic_name})")
public void insertTalkRoom(TalkRoomVO talkRoomVO);
//채팅방 멤버 등록
@Insert("INSERT INTO sptalk_member (talkroom_num,room_name,mem_num) VALUES (#{talkroom_num},#{room_name},#{mem_num})")
public void insertTalkRoomMember(@Param(value="talkroom_num") int talkroom_num,
@Param(value="room_name") String room_name,
@Param(value="mem_num") int mem_num);
talkroom / talkroommember table에 insert하는 sql문 작성
서비스 파일
TalkServiceImpl
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;
@Service
@Transactional
public class TalkServiceImpl implements TalkService{
@Autowired
private TalkMapper talkMapper;
@Override
public List<TalkRoomVO> selectTalkRoomList(Map<String, Object> map) {
return null;
}
@Override
public int selectRowCount(Map<String, Object> map) {
return 0;
}
@Override
public void insertTalkRoom(TalkRoomVO talkRoomVO) {
//기본키 생성해서 넣어줌
talkRoomVO.setTalkroom_num(talkMapper.selectTalkRoomNum());
//채팅방 생성
talkMapper.insertTalkRoom(talkRoomVO);
//입장 메시지 처리
//채팅방 멤버 생성
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 null;
}
}
TalkServiceImpl 안에
insertTalkRoom >> selectTalkRoomNum + insertTalkRoom + insertTalkRoomMember (TalkMapper 안 메서드)
TalkVO 작성
kr.spring.talk.vo
TalkVO
package kr.spring.talk.vo;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class TalkVO {
private int talk_num;
private int talkroom_num; //수신그룹
private int mem_num; //발신자
private String message;
private String chat_date;
//추가
private int read_count; //읽지않은 메시지 수
private String id;
}
컨트롤러 수정
TalkController
/* ============================
* 채팅방 생성
* ============================*/
//채팅방 생성폼 호출
@GetMapping("/talk/talkRoomWrite")
public String talkRoomWrite() {
return "talkRoomWrite"; //tiles설정
}
//전송된 데이터 처리
@PostMapping("/talk/talkRoomWrite")
public String talkRoomSubmit(TalkRoomVO vo, HttpSession session) {
log.debug("<<채팅방 생성 TalkRoomVO>> : " + vo);
MemberVO user = (MemberVO)session.getAttribute("user");
//채팅멤버 초대 시 문구설정
vo.setTalkVO(new TalkVO());
vo.getTalkVO().setTalkroom_num(vo.getTalkroom_num());
vo.getTalkVO().setMem_num(user.getMem_num()); //session에서 가져온 멤버 정보 넣기
vo.getTalkVO().setMessage(user.getId()+"님이 "
+findMemberId(vo,user)+"님을 초대했습니다.@{member}@");
talkService.insertTalkRoom(vo);
return "redirect:/talk/talkList";
}
/* ============================
* 초대한 회원의 id구하기
* ============================*/
//내부적으로만 호출되기 때문에 private으로 호출
private String findMemberId(TalkRoomVO vo, MemberVO user) {
String member_id = "";
int[] members = vo.getMembers();
for(int i=0;i<members.length;i++) {
String temp_id = memberService.selectMember(members[i]).getId();
//초대한 사람의 아이디는 제외
if(!user.getId().equals(temp_id)) {
member_id += temp_id;
if(i < members.length-1) member_id += ", ";
}
}
return member_id;
}
1.
vo.getTalkVO().setMessage(user.getId()+"님이 "+findMemberId(vo,user)+"님을 초대했습니다.@{member}@");
findMemberId(vo,user) == 멤버 아이디를 알려주는 메서드
@{member}@ << 안내메시지를 알려주는 특별한 기호
2.
private String findMemberId(TalkRoomVO vo, MemberVO user) {
MemberVO user 가 위 session 정보를 받은 user (로그인한 개설자) 임
3.
if(i < members.length-1) member_id += ", ";
마지막 사람 전까지는 , 넣음
예) 길동, 문래 님 << 이런식으로
채팅방 생성 후 전송 시 조건체크하는 구문 추가
message.talk.js
//채팅방 생성 전송
$('#talk_form').submit(function(){
if(member_list.length<=1){
//이미 배열에 로그인한 유저(채팅방 개설자)가 기본 등록되어 있어서
//로그인한 유저 포함 최소 2명이 되어야 채팅 가능
alert('채팅에 참여할 회원을 검색하세요');
$('#member_search').focus();
return false;
}
});
member_list에 본인만 있다면 alert창 표시
============================
아직 목록작업이 안되어 있기 때문에 채팅방 생성 후 oracle에서 데이터 확인 가능
sptalkroom / sptalk_member 순으로 테이블 확인
sptalkroom은 생성된 방 1컬럼만,
sptalk_member엔 각자 채팅방 이름 변경 가능하게끔 인원수만큼 컬럼 생성됨
<채팅방 목록처리>
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>
<!-- 개수 -->
<select id="selectRowCount" parameterType="map" resultType="integer">
SELECT
COUNT(*)
FROM sptalkroom
</select>
<!-- 목록 -->
<select id="selectTalkRoomList" parameterType="map" resultMap="talkMap">
SELECT
*
FROM (SELECT
a.*,
rownum rnum
FROM (SELECT
*
FROM sptalkroom
ORDER BY talkroom_num DESC)a)
<![CDATA[
WHERE rnum >= #{start} AND rnum <= #{end}
]]>
</select>
</mapper>
1.
<resultMap type="talkRoomVO" id="talkMap">
type=자바빈이름 id=설정id (자기마음대로 지어도 됨)
TalkRoomVO에
private TalkVO talkVO;
private TalkMemberVO talkMemberVO; 를 이미 넣음
얘네는 인자가 하나가 아니기 때문에 수동으로 인자를 걸어야 매핑이 됨
한 컬럼이 아닌 다른 테이블 전체 정보를 읽어오기 위해선 이렇게 resultMap(?)으로 조인해야한다고 함
2.
<result property="talkVO.message" column="message"/>
property=자바빈.컬럼 column=컬럼
talkVO 안에 있는 message, chat_date / talkMemberVO 안에 있는 room_name
3.
<select id="selectTalkRoomList" parameterType="map" resultMap="talkMap">
resultMap 有 resultMap
resultMap 無 resultType
우선은 조인하지않고 화면 출력
확인 후 조인연결
ServiceImpl 파일
TalkServiceImpl
@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);
}
컨트롤러 목록 구문 추가
TalkController
/* ============================
* 채팅방 목록
* ============================*/
@RequestMapping("/talk/talkList")
public String chatList(@RequestParam(value="pageNum",defaultValue="1") int currentPage,
String keyword, HttpSession session, Model model) {
MemberVO user = (MemberVO)session.getAttribute("user");
Map<String,Object> map = new HashMap<String,Object>();
map.put("keyword", keyword);
map.put("mem_num", user.getMem_num()); //사용자 본인 채팅목록만 빼내기 위해
int count = talkService.selectRowCount(map);
//keyfield가 없기 때문에 그냥 null처리하면 됨 (30개10페이지)
PageUtil page = new PageUtil(null,keyword,currentPage,count,30,10,"talkList");
List<TalkRoomVO> list = null;
if(count>0) {
map.put("start", page.getStartRow());
map.put("end", page.getEndRow());
list = talkService.selectTalkRoomList(map);
}
model.addAttribute("count", count);
model.addAttribute("list", list);
model.addAttribute("page", page.getPage());
return "talkList";
}
출력 화면
views
talk
talkList.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<!-- 내용 시작 -->
<div class="page-main">
<h2>채팅리스트</h2>
<!-- 검색 시작 -->
<form action="talkList" id="search_form" method="get">
<ul class="search">
<li>
<input type="search" name="keyword" id="keyword" value="${param.keyword}">
</li>
<li>
<input type="submit" value="찾기">
<input type="button" value="목록" onclick="location.href='talkList'">
</li>
</ul>
</form>
<!-- 검색 끝 -->
<div class="align-right">
<input type="button" value="채팅방 생성" onclick="location.href='talkRoomWrite'">
</div>
<c:if test="${count == 0}">
<div class="result-display">표시할 채팅방이 없습니다</div>
</c:if>
<c:if test="${count > 0}">
<table class="striped-table">
<!-- 따로 구분하는 항목이 없고 나열만 할거라 그냥 반복 -->
<c:forEach var="talk" items="${list}">
<tr>
<td style="text-align:left;">
<a href="talkDetail?talkroom_num=${talk.talkroom_num}">
<b>${talk.talkMemberVO.room_name}(${talk.room_cnt})</b>
<br>
<span>${fn:substring(talk.talkVO.message,0,45)}</span>
</a>
</td>
<td>
<c:if test="${!empty talk.talkVO.chat_date}">${talk.talkVO.chat_date}</c:if>
<c:if test="${empty talk.talkVO.chat_date}">${talk.talkroom_date}</c:if>
</td>
</tr>
</c:forEach>
</table>
<div class="align-center">${page}</div>
</c:if>
</div>
<!-- 내용 끝 -->
방이름(읽지않은 메시지 수)
제일 최근 메시지 45자 이내로 표시
1.
<b>${talk.talkMemberVO.room_name}(${talk.room_cnt})</b>
talkRoomVO에서 talkMemberVO를 넣었기 때문에 저렇게 불러올 수 있음
2.
<span>${fn:substring(talk.talkVO.message,0,45)}</span>
functions lib를 사용해서 메시지가 길면 잘라서 보여줌
3.
<c:if test="${empty talk.talkVO.chat_date}">${talk.talkroom_date}</c:if>
채팅한 날짜가 있으면 채팅날짜
없으면 채팅방 개설날짜 보여줌
============================
로그인 후 mypage > 채팅
들어가면
(0) 2024-01-25 10:39:35
이렇게 채팅방 뜸
지금까지 넣었던 데이터 모두 지우고 채팅방 생성+문구 저장이 잘 됐는지 확인해보기
(오라클 sptalk_member/ sptalkroom)
초대 문구 처리
메서드+SQL문 작성
TalkMapper.java
//채팅 메시지 번호 생성
@Select("SELECT sptalk_seq.nextval FROM dual")
public int selectTalkNum();
//채팅 메시지 등록
@Insert("INSERT INTO sptalk (talk_num,talkroom_num,mem_num,message) VALUES (#{talk_num},#{talkroom_num},#{mem_num},#{message})")
public void insertTalk(TalkVO talkVO);
//읽지 않은 채팅 기록 저장
public void insertTalkRead(@Param(value="talkroom_num") int talkroom_num,
@Param(value="talk_num") int talk_num,
@Param(value="mem_num") int mem_num);
//채팅 메시지 읽기
public List<TalkVO> selectTalkDetail(Map<String,Integer> map);
//읽은 채팅 기록 삭제
public void deleteTalkRead(Map<String,Integer> map);
서비스 파일에 코드 추가
TalkServiceImpl
@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);
}
}
채팅방pk 생성
채팅방 생성
채팅메시지pk 생성
위에서 생성한 채팅방pk talkRoomVO에 넣음
채팅메시지 등록
채팅방멤버 등록
============================
talkcontroller의 채팅방생성-초대시 문구설정 이거랑 연계해서 같이 작업하는거임
serviceimpl
talkMapper.insertTalk(talkRoomVO.getTalkVO());
이게
talkmapper.java
//채팅 메시지 등록
@Insert("INSERT INTO sptalk (talk_num,talkroom_num,mem_num,message) VALUES (#{talk_num},#{talkroom_num},#{mem_num},#{message})")
public void insertTalk(TalkVO talkVO);
이거임
============================
restart 후
[화면출력]
아직 join을 안했기 때문에 이전과 동일
[oracle]
sptalkroom > 1컬럼 생성
sptalk_member > 인원수만큼 컬럼 생성
sptalk > talkroom_num, mem_num(생성자), message (a 님이 b,c님을 초대했습니다.)
저장됨
sql문장 조인으로 좀더 자세히 작성
TalkMapper.xml
<!-- 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,'<','<'),'>','>'),'@{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>
sql태그 > 채팅방 목록을 보여주기 위한 sub_sql문
1.
REPLACE(REPLACE(REPLACE(message,'<','<'),'>','>'),'@{member}@','') message,
기존과 같은 방식으로 replace처리할 때 아까 처음에 초대 문구 작성했을 때 넣었던 @{member}@을 안 보이게 처리
2.
FROM sptalk WHERE talk_num IN (SELECT
sptalk안에서도 제일 최신 메시지 1건만 보여주기 위해 조건체크 수행
MAX(talk_num) talk_num << 이게 제일 최근 메시지임 (max)
3.
sptalk_member에 있는 mem_num과 조인하고 싶은거라 m 알리아스를 사용해서
WHERE m.mem_num=#{mem_num}
라고 지정함