현재 로그인한 유저가 가지고 있는 쪽지의 목록을 출력하려 한다.
쪽지함은 현재 보낸 쪽지 / 받은 쪽지로 나뉘어져 있고, 이 둘은 같은 UI를 쓰고 있다. 그러니 불필요하게 jsp를 생성하지 않고 ajax를 이용해 버튼을 눌렀을 시에 페이지의 몇 부분만 바뀌도록 만들어줬다.
1. JSP, JavaScript
2. Controller
3. Service (DAO)
4. DTO
5. SQL (Mapper)
1. JSP, JavaScript
<div class="sec00">
<button type="button" id="btn-recv">받은 쪽지</button>
<button type="button" id="btn-send">보낸 쪽지</button>
</div>
위 버튼 중 어떤 것을 누르느냐에 따라 아래 출력 목록이 바뀌게 된다.
<div class="sec01">
<div class="sec-left">
<div class="left-top">
<table>
<tr>
<th class="msg-img">프로필</th>
<th class="msg-sort" style="width: 188px; padding-right: 20px;">이름</th>
<th class="msg-content">내용</th>
<th class="msg-time">시간</th>
<th class="msg-del">삭제</th>
</tr>
</table>
</div>
<div class="left-bottom">
<table>
<c:if test="${totalCnt == null || totalCnt == 0}">
<div style="display: flex; margin-top: 20px; justify-content: center; color: #8f8f8f;">보관된 쪽지가 없습니다.</div>
</c:if>
<c:forEach var="messageDTO" items="${list }">
<!-- 폼태그를 사용하면 아이디를 쓰든 클래스를 사용하든 맨 위에 있는 애만 작동된다 그러니 버튼 누를 때 폼태그 생성 -->
<tr class="title-line" style="font-weight: 200">
<td class="msg-no" style="display: none; ">${messageDTO.message_no}</td>
<input name="message_no" type="hidden" value="${messageDTO.message_no}" />
<td class="msg-img">
<a href="javascript:goProfile('${(messageDTO.send_user_no != sessionScope.user_no) ? messageDTO.send_user_no : messageDTO.receive_user_no}', '${messageDTO.user_nicknm}')">
<img src="${messageDTO.image }" class="user-image" alt="프로필사진" />
</a>
</td>
<td class="msg-nicknm">${messageDTO.user_nicknm }</td>
<td class="msg-sort" style="display: none; ">${(messageDTO.send_user_no != sessionScope.user_no) ? messageDTO.send_user_no : messageDTO.receive_user_no}</td>
<c:if test="${messageDTO.read_yn == true }">
<td class="msg-content" style="cursor: pointer; color: rgb(138, 138, 138);"><c:out value="${messageDTO.content }"></c:out></td>
</c:if>
<c:if test="${messageDTO.read_yn == false }">
<td class="msg-content" style="cursor: pointer;"><c:out value="${messageDTO.content }"></c:out></td>
</c:if>
<td class="msg-time"><fmt:formatDate value="${messageDTO.send_date}" pattern="yyyy-MM-dd HH:mm" type="date" /></td>
<td class="msg-del"><button class="delBtn" name="deleteBtn" style="border: none; color: red;" id="del" data-bs-toggle="modal" data-bs-target="#exampleModa2"><i class="fas fa-times"></i></button></td>
</tr>
</c:forEach>
</table>
</div>
</div>
받은 쪽지 목록 불러오기
$(document).ready(function() {
// 받은 쪽지 리스트 불러오기
$("#btn-recv").click(function() {
$.ajax({
url: '/mypage/message',
type: 'GET',
success: function(data) {
console.log("받은 쪽지 목록을 가져옴")
$(".left-bottom table").empty()
if(!Array.isArray(data) || data.length === 0) {
$(".left-bottom table").append('<div></div>')
} else {
let rows = ''
$.each(data, function(index, message) {
rows += '<tr class="title-line" style="font-weight: 200">'
rows += '<td class="msg-img">' + message.image + '</td>'
rows += '<td class="msg-nicknm">' + message.user_nicknm + '</td>'
rows += '<td class="msg-sort">' + message.send_user_no + '</td>'
rows += '<td class="msg-content">' + message.content + '</td>'
rows += '<td class="msg-time">' + message.send_date + '</td>'
rows += '<td class="msg-del"><button class="delBtn" style="border: none; color: red;"><i class="fas fa-times"></i></button></td>'
rows += '</tr>'
})
$(".left-bottom table").append(rows)
}
location.href="/mypage/message"
},
error: function() {
alert("error")
sendButton.click();
}
})
})
})
보낸 쪽지 목록 불러오기
$(document).ready(function() {
//보낸 쪽지 리스트 불러오기
$("#btn-send").click(function() {
$.ajax({
url: '/mypage/message/send',
type: 'GET',
success: function(data) {
console.log("보낸 쪽지 목록을 가져옴")
$(".left-bottom table").empty()
if(!Array.isArray(data) || data.length === 0) {
$(".left-bottom table").append('<div></div>')
} else {
let rows = ''
$.each(data, function(index, message) {
rows += '<tr class="title-line" style="font-weight: 200">'
rows += '<td class="msg-img">' + message.image + '</td>'
rows += '<td class="msg-nicknm">' + message.user_nicknm + '</td>'
rows += '<td class="msg-sort">' + message.receive_user_no + '</td>'
rows += '<td class="msg-content">' + message.content + '</td>'
rows += '<td class="msg-time">' + message.send_date + '</td>'
rows += '<td class="msg-del"><button class="delBtn" style="border: none; color: red;"><i class="fas fa-times"></i></button></td>'
rows += '</tr>'
})
$(".left-bottom table").append(rows)
}
location.href="/mypage/message/send"
},
error: function() {
alert("error")
recvButton.click();
}
})
})
})
위에서 보다시피 둘은 ajax를 통해 호출되는 controller가 다르다.
2. Controller
받은 쪽지함, 보낸 쪽지함
package com.ottt.ottt.controller.mypage.pageVar;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.ottt.ottt.dao.login.LoginUserDao;
import com.ottt.ottt.domain.MessagePageResolver;
import com.ottt.ottt.domain.MessageSearchItem;
import com.ottt.ottt.dto.MessageDTO;
import com.ottt.ottt.dto.UserDTO;
import com.ottt.ottt.service.message.MessageService;
@Controller
@RequestMapping("/mypage")
public class MessageController {
@Autowired
MessageService messageService;
@Autowired
LoginUserDao loginUserDao;
//받은 쪽지함
@GetMapping(value = "/message")
public String message(MessageSearchItem msc, Model m, HttpSession session) {
try {
UserDTO userDTO = loginUserDao.select((String) session.getAttribute("id"));
m.addAttribute("userDTO", userDTO);
msc.setUser_no(userDTO.getUser_no());
int totalCnt = messageService.getRecvResultCnt(msc);
MessagePageResolver msgPageResolver = new MessagePageResolver(totalCnt, msc);
//리스트 불러오기
List<MessageDTO> listAll = messageService.loadRecvListAll(msc);
//빈배열 생성
List<MessageDTO> msgList = new ArrayList<>();
//삭제 상태가 아닌 쪽지들만 넣기
for(MessageDTO messageDTO : listAll) {
if(!messageDTO.isDelete_by_receiver()) {
msgList.add(messageDTO);
}
}
int startIndex = ((msc.getPage() - 1) * msc.getPageSize()) < 0 ? 0 : (msc.getPage() - 1) * msc.getPageSize();
int endIndex = Math.min(startIndex + msc.getPageSize(), msgList.size());
List<MessageDTO> list = msgList.subList(startIndex, endIndex);
System.out.println("-------------list.size()--------------" +list.size());
m.addAttribute("list", list);
m.addAttribute("mpr", msgPageResolver);
m.addAttribute("totalCnt", list.size());
} catch (Exception e) {e.printStackTrace();}
return "/mypage/myprofile/message";
}
//보낸 쪽지함
@GetMapping(value = "/message/send")
public String sendMessage(MessageSearchItem msc, Model m, HttpSession session, Integer page) {
try {
UserDTO userDTO = loginUserDao.select((String)session.getAttribute("id"));
m.addAttribute("userDTO", userDTO);
msc.setUser_no(userDTO.getUser_no());
int totalCnt = messageService.getSendResultCnt(msc);
m.addAttribute("totalCnt", totalCnt);
MessagePageResolver msgPageResolver = new MessagePageResolver(totalCnt, msc);
//먼저 불러오고
List<MessageDTO> listAll = messageService.loadSendListAll(msc);
//빈배열 생성
List<MessageDTO> msgList = new ArrayList<>();
//삭제 상태가 아닌 쪽지들만 넣기
//false여야 넣어짐
for(MessageDTO messageDTO : listAll) {
if(!messageDTO.isDelete_by_sender()) {
msgList.add(messageDTO);
}
}
int startIndex = ((msc.getPage() - 1) * msc.getPageSize()) < 0 ? 0 : (msc.getPage() - 1) * msc.getPageSize();
int endIndex = Math.min(startIndex + msc.getPageSize(), msgList.size());
List<MessageDTO> list = msgList.subList(startIndex, endIndex);
m.addAttribute("list", list);
m.addAttribute("mpr", msgPageResolver);
m.addAttribute("totalCnt", list.size());
} catch (Exception e) {e.printStackTrace();}
return "/mypage/myprofile/message";
}
}
3. Service(DAO)
//DAO
package com.ottt.ottt.dao.message;
import com.ottt.ottt.domain.MessageSearchItem;
import com.ottt.ottt.dto.MessageDTO;
import java.util.List;
import java.util.Map;
public interface MessageDao {
//메시지 내용 불러오기
MessageDTO selectMsg(Integer message_no) throws Exception;
//메시지 추가(보내기)
int insert(MessageDTO messageDTO) throws Exception;
//작성자 일치 시, 선택한 메세지 삭제하기
int delete(Integer message_no) throws Exception;
//받은 쪽지 전체 목록 불러오기
List<MessageDTO> selectRecvAll(MessageSearchItem msc) throws Exception;
//보낸 쪽지 전체 목록 불러오기
List<MessageDTO> selectSendAll(MessageSearchItem msc) throws Exception;
//페이지별 게시글 목록 불러오기
List<MessageDTO> selectPage(Map map) throws Exception;
//받은 메시지 수 불러오기
int recvCount() throws Exception;
//보낸 메시지 수 불러오기
int sendCount() throws Exception;
//조건에 해당하는 게시글 수 불러오기(네비게이션 바 사용하기 위해) - 보낸 메시지
int recvResultCnt(MessageSearchItem msc) throws Exception;
//조건에 해당하는 게시글 수 불러오기(네비게이션 바 사용하기 위해) - 받은 메시지
int sendResultCnt(MessageSearchItem msc) throws Exception;
//조건에 해당하는 페이지별 게시글 목록 불러오기
List<MessageDTO> selectPage(MessageSearchItem msc) throws Exception;
//받은 메시지 중 삭제할 메시지 하나 고르기
MessageDTO selectOneRecv(Integer message_no) throws Exception;
//보낸 메시지 중 삭제할 메시지 하나 고르기
MessageDTO selectOneSend(Integer message_no) throws Exception;
//받은 메시지함에서 삭제 상태로 변경
int deleteByReceiver(MessageDTO messageDTO) throws Exception;
//보낸 메시지함에서 삭제 상태로 변경
int deleteBySender(MessageDTO messageDTO) throws Exception;
//읽음 유무 개수 조회
int readCnt() throws Exception;
//읽음 유무를 true로 수정
int updateRead(MessageDTO messageDTO) throws Exception;
}
//serviceImpl
package com.ottt.ottt.service.message;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ottt.ottt.dao.message.MessageDao;
import com.ottt.ottt.domain.MessageSearchItem;
import com.ottt.ottt.dto.MessageDTO;
@Service
public class MessageServiceImpl implements MessageService{
@Autowired
MessageDao messageDao;
@Override
public MessageDTO read(Integer message_no) throws Exception {
return messageDao.selectMsg(message_no);
}
@Override
public int writeMsg(MessageDTO messageDTO) throws Exception {
return messageDao.insert(messageDTO);
}
@Override
public int removeMsg(Integer message_no) throws Exception {
return messageDao.delete(message_no);
}
@Override
public int getSendResultCnt(MessageSearchItem msc) throws Exception {
return messageDao.sendResultCnt(msc);
}
@Override
public int getRecvResultCnt(MessageSearchItem msc) throws Exception {
return messageDao.recvResultCnt(msc);
}
@Override
public List<MessageDTO> getSelectPage(MessageSearchItem msc) throws Exception {
return messageDao.selectPage(msc);
}
@Override
public MessageDTO pickOneRecv(Integer message_no) throws Exception {
return messageDao.selectOneRecv(message_no);
}
@Override
public MessageDTO pickOneSend(Integer message_no) throws Exception {
return messageDao.selectOneSend(message_no);
}
@Override
public int removeByReceiver(MessageDTO messageDTO) throws Exception {
messageDTO.setDelete_by_receiver(true);
return messageDao.deleteByReceiver(messageDTO);
}
@Override
public int removeBySender(MessageDTO messageDTO) throws Exception {
return messageDao.deleteBySender(messageDTO);
}
@Override
public List<MessageDTO> loadRecvListAll(MessageSearchItem msc) throws Exception {
return messageDao.selectRecvAll(msc);
}
@Override
public List<MessageDTO> loadSendListAll(MessageSearchItem msc) throws Exception {
return messageDao.selectSendAll(msc);
}
@Override
public int getReadCnt(MessageSearchItem msc) throws Exception {
return messageDao.readCnt();
}
@Override
public int readYes(MessageDTO messageDTO) throws Exception {
return messageDao.updateRead(messageDTO);
}
}
4. DTO
package com.ottt.ottt.dto;
import java.util.Date;
import java.util.Objects;
/*
* message_no bigint generated always as identity primary key
,send_user_no bigint not null
,receive_user_no bigint not null
,content varchar(2000) not null
,send_date timestamptz not null
,read_yn boolean default false --추가
,delete_by_sender boolean default false
,delete_by_receiver boolean default false
*/
public class MessageDTO {
private Integer message_no;
private Integer send_user_no;
private Integer receive_user_no;
private String content;
private Date send_date;
private boolean read_yn;
private String user_nicknm;
private String image;
//보낸 메시지 지우기
private boolean delete_by_sender;
//받은 메시지 지우기
private boolean delete_by_receiver;
public MessageDTO () {}
public MessageDTO(Integer send_user_no, Integer receive_user_no, String content) {
super();
this.send_user_no = send_user_no;
this.receive_user_no = receive_user_no;
this.content = content;
}
public Integer getMessage_no() {
return message_no;
}
public void setMessage_no(Integer message_no) {
this.message_no = message_no;
}
public Integer getSend_user_no() {
return send_user_no;
}
public void setSend_user_no(Integer send_user_no) {
this.send_user_no = send_user_no;
}
public Integer getReceive_user_no() {
return receive_user_no;
}
public void setReceive_user_no(Integer receive_user_no) {
this.receive_user_no = receive_user_no;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Date getSend_date() {
return send_date;
}
public void setSend_date(Date send_date) {
this.send_date = send_date;
}
public boolean isRead_yn() {
return read_yn;
}
public void setRead_yn(boolean read_yn) {
this.read_yn = read_yn;
}
public String getUser_nicknm() {
return user_nicknm;
}
public void setUser_nicknm(String user_nicknm) {
this.user_nicknm = user_nicknm;
}
public boolean isDelete_by_sender() {
return delete_by_sender;
}
public void setDelete_by_sender(boolean delete_by_sender) {
this.delete_by_sender = delete_by_sender;
}
public boolean isDelete_by_receiver() {
return delete_by_receiver;
}
public void setDelete_by_receiver(boolean delete_by_receiver) {
this.delete_by_receiver = delete_by_receiver;
}
@Override
public int hashCode() {
return Objects.hash(message_no);
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MessageDTO other = (MessageDTO) obj;
return Objects.equals(message_no, other.message_no);
}
@Override
public String toString() {
return "MessageDTO [message_no=" + message_no + ", send_user_no=" + send_user_no + ", receive_user_no="
+ receive_user_no + ", content=" + content + ", send_date=" + send_date + ", read_yn=" + read_yn
+ ", user_nicknm=" + user_nicknm + ", image=" + image + ", delete_by_sender=" + delete_by_sender
+ ", delete_by_receiver=" + delete_by_receiver + "]";
}
//보낸 메시지 지우기(상태 변경)
public void deleteBySender() {
this.setDelete_by_sender(true);
}
//받은 메시지 지우기(상태 변경)
public void deleteByReceiver() {
this.setDelete_by_receiver(true);
}
public boolean isDelete() {
return this.isDelete_by_receiver() && this.isDelete_by_sender();
}
}
5. SQL (Mapper)
messageMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ottt.ottt.dao.message.MessageMapper">
<sql id="selectFromMessage">
SELECT a.message_no, a.send_user_no, delete_by_receiver, delete_by_sender
, a.receive_user_no, a.content, a.send_date, read_yn, b.user_nicknm, b.image
FROM tb_message a
JOIN tb_user b
ON a.send_user_no = b.user_no
</sql>
<!-- 받은 메시지 개수 세기 -->
<select id="recvCount" parameterType="MessageSearchItem" resultType="int">
SELECT count(*)
FROM tb_message
WHERE receive_user_no = #{user_no}
</select>
<!-- 보낸 메시지 개수 세기 -->
<select id="sendCount" parameterType="MessageSearchItem" resultType="int">
SELECT count(*)
FROM tb_message
WHERE send_user_no = #{user_no}
</select>
<!-- 페이지 개수 제한해서 출력하기 -->
<select id="selectPage" parameterType="map" resultType="MessageDTO">
<include refid="selectFromMessage" />
ORDER BY send_date DESC, message_no DESC
LIMIT #{pageSize} OFFSET #{offset}
</select>
<!-- 네비바 사용을 위한 해당되는 개수 세기 -->
<!-- 받은 메시지 -->
<select id="recvResultCnt" parameterType="MessageSearchItem" resultType="int">
SELECT count(*) FROM tb_message
WHERE receive_user_no = #{user_no} AND delete_by_receiver = 'false'
</select>
<!-- 네비바 사용을 위한 해당되는 개수 세기 -->
<!-- 보낸 메시지 -->
<select id="sendResultCnt" parameterType="MessageSearchItem" resultType="int">
SELECT count(*) FROM tb_message
WHERE send_user_no = #{user_no} AND delete_by_sender = 'false'
</select>
<!-- 메시지 내용 불러오기 -->
<select id="selectMsg" parameterType="Integer" resultType="MessageDTO">
<include refid="selectFromMessage" />
WHERE message_no = #{message_no}
</select>
<!-- 받은 메시지 전체 리스트 불러오기 -->
<select id="selectRecvAll" parameterType="int" resultType="MessageDTO">
<include refid="selectFromMessage" />
WHERE a.receive_user_no = #{user_no}
ORDER BY a.send_date DESC, a.message_no DESC
</select>
<!-- 보낸 메시지 전체 리스트 불러오기 -->
<select id="selectSendAll" parameterType="int" resultType="MessageDTO">
SELECT a.message_no, a.send_user_no, a.receive_user_no, a.content, a.send_date,
read_yn, b.user_nicknm, delete_by_receiver, delete_by_sender, b.image
FROM tb_message a
JOIN tb_user b
ON a.receive_user_no = b.user_no
WHERE a.send_user_no = #{user_no}
ORDER BY a.send_date DESC, a.message_no DESC
</select>
<!-- 메시지 보내기 -->
<insert id="insertMsg" parameterType="MessageDTO">
INSERT INTO tb_message
(send_user_no, receive_user_no, content)
VALUES(#{send_user_no}, #{receive_user_no}, #{content})
</insert>
<!-- 선택한 메시지 삭제하기 -->
<delete id="deleteMsg" parameterType="map">
DELETE FROM tb_message
WHERE message_no = #{message_no} AND receive_user_no = #{receive_user_no}
</delete>
<!-- 메시지 삭제 -->
<delete id="delete" parameterType="int">
DELETE FROM tb_message
WHERE message_no = #{message_no}
</delete>
<!-- 메시지 하나 선택하기(받은 메시지 삭제용) -->
<select id="selectOneRecv" parameterType="Integer" resultType="MessageDTO">
SELECT message_no, receive_user_no, delete_by_receiver, delete_by_sender, read_yn
FROM tb_message
WHERE message_no = #{message_no}
</select>
<!-- 메시지 하나 선택하기(보낸 메시지 삭제용) -->
<select id="selectOneSend" parameterType="Integer" resultType="MessageDTO">
SELECT message_no, send_user_no, delete_by_receiver, delete_by_sender
FROM tb_message
WHERE message_no = #{message_no}
</select>
<!-- 받은 메시지함에서 삭제 상태로 변경 -->
<update id="deleteByReceiver" parameterType="MessageDTO">
UPDATE tb_message
SET delete_by_receiver = true
WHERE message_no = #{message_no} AND receive_user_no = #{receive_user_no}
</update>
<!-- 보낸 메시지함에서 삭제 상태로 변경 -->
<update id="deleteBySender" parameterType="MessageDTO">
UPDATE tb_message
SET delete_by_sender = true
WHERE message_no = #{message_no} AND send_user_no = #{send_user_no}
</update>
<!-- 읽지 않은 메시지 개수 조회 -->
<select id="selectRead" parameterType="MessageDTO" resultType="int">
SELECT count(*) FROM tb_message
WHERE read_yn = false
AND receive_user_no = #{receive_user_no}
</select>
<!-- 읽음 여부를 true로 수정 -->
<update id="updateRead" parameterType="MessageDTO">
UPDATE tb_message
SET read_yn = true
WHERE receive_user_no = #{receive_user_no}
AND message_no = #{message_no}
</update>
</mapper>