✿∘˚˳°∘°

81일차 : ajax, 에러처리, 웹소켓 본문

국비수업/Spring

81일차 : ajax, 에러처리, 웹소켓

_HYE_ 2023. 3. 24. 11:34

20230324

1. Ajax

ajax사용을 위한 GSON라이브러리 추가

		<!-- GSON 라이브러리 추가 -->
		<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
		<dependency>
		    <groupId>com.google.code.gson</groupId>
		    <artifactId>gson</artifactId>
		    <version>2.10.1</version>
		</dependency>

1 - 1 ) 비밀번호 변경

요즘 비밀번호는 마이페이지에서 바로변경X 암호화때문에 굉장히 복잡하기 때문이다.

그러므로 비밀번호 변경페이지를 새로 만들어줄 것

 

수정한 mypage.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>마이페이지</h1>
	<hr>
	<form action="/updateMember.do" method="post">
		<fieldset>
			<legend>회원정보</legend>
			회원번호 : <input type="text" name="memberNo" value="${sessionScope.m.memberNo }" readonly><br>
			아이디 : <input type="text" name="memberId" value="${sessionScope.m.memberId }" readonly><br>
			비밀번호 : <button type="button" onclick="pwChange();">비밀번호 변경하기</button><br>
			<%-- 비밀번호 : <input type="password" name="memberPw" value="${sessionScope.m.memberPw }" ><br>--%>
			이름 : <input type="text" name="memberName" value="${sessionScope.m.memberName }" readonly><br>
			전화번호 : <input type="text" name="memberPhone" value="${sessionScope.m.memberPhone }"><br>
			이메일 : <input type="text" name="memberEmail" value="${sessionScope.m.memberEmail }" ><br>
			<input type="submit" value="정보수정">
		</fieldset>
	</form>
	<a href="/">메인으로</a>
	<script>
		function pwChange(){
			location.href="/pwChangeFrm.do";
		}
	</script>
</body>
</html>

비밀번호변경페이지 pwChange.jsp(여기서 페이지이동없이 ajax로 데이터를 처리해줄것)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.6.1.js"></script>
<style>
	#pwChangeFrm{
		display: none;
	}
</style>
</head>
<body>
	<h1>비밀번호 변경</h1>
	<hr>
	현재 비밀번호 입력 : <input type="password" name="currentPw">
	<button type="button" id="checkBtn">입력</button>
	<%--현재 비밀번호를 입력해서 ajax를 통해 확인 후 비밀번호가 맞을 경우에 form태그를 보여줄것 --%>
	<form action="/pwChange.do" method="post" id="pwChangeFrm">
		<input type="hidden" name="memberId" value="${sessionScope.m.memberId }">
		비밀번호 : <input type="password" name="memberPw"><br>
		비밀번호 확인 : <input type="password" name="memberPwRe"><br>
		<input type="submit" value="비밀번호 변경하기" onclick="return checkPw();">
	</form>
	
	<script>
		$("#checkBtn").on("click", function(){
			const memberPw = $("[name=currentPw]").val();
			const memberId = $("[name=memberId]").val();
			$.ajax({
				url : "/pwCheck.do",
				type : "post",
				data : {memberId:memberId, memberPw:memberPw},
				success : function(data){
					if(data == "ok"){
						$("#pwChangeFrm").slideDown();
					}else{
						alert("비밀번호를 확인하세요");
					}
				},
				error : function(){
					console.log("실패");
				}
			});
		});
		
		function checkPw(){
			const pw = $("[name=memberPw]").val();
			const pwRe = $("[name=memberPwRe]").val();
			if(pw != pwRe){
				alert("비밀번호를 확인하세요.")
				return false;
			}
		}
	</script>
</body>
</html>

ajax에서 이동하는 Controller

	//페이지 이동이 아닌 값 자체를 return하는 코드가 된다.
	@ResponseBody
	@RequestMapping(value="/pwCheck.do")
	public String pwCheck(Member member) {
		//아이디&패스워드로 회원을 조회해주는 로그인 로직을 이용할것 -> 암호화도 된다
		Member m = service.selectOneMember(member);
		if(m != null) {
			//상단에 ResponseBody를 붙여줬으므로 페이지이동X 값만 넘겨준다.
			return "ok";
		}else {
			return "error";
		}
	}

실제 비밀번호 update를 진행할 Controller

	@RequestMapping(value="/pwChange.do")
	public String pwChange(Member member, String memberPwRe) {
		int result = service.updateMemberPw(member, memberPwRe);
		if(result > 0) {
			return "redirect:/";
		}else {
			return "redirect:/updateMember.do";
		}
	}

Service - update이기 때문에 트랜잭션관리를 해줄 것

	@Transactional
	public int updateMemberPw(Member member, String memberPwRe) {
		return dao.updateMemberPw(member);
	}

Dao

	public int updateMemberPw(Member member) {
		int result = sqlSession.update("member.pwChangeMember", member);
		return result;
	}

memberSQL

  	<update id="pwChangeMember" parameterType="m">
  		update member_tbl set member_pw = #{memberPw} where member_id = #{memberId}
  	</update>

 

1 - 2 ) 회원가입 시 아이디 중복체크

추가한 joinFrm.jsp - 아이디 input태그 옆에 span태그를 추가하고 ajax코드를 추가하였다

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.6.1.js"></script>
</head>
<body>
	<h1>회원가입</h1>
	<hr>
	<form action="/join.do" method="post">
		<fieldset>
			<legend>회원가입</legend>
			아이디 : <input type="text" name="memberId"><span id="idChk"></span><br>
			비밀번호 : <input type="password" name="memberPw"><br>
			이름 : <input type="text" name="memberName"><br>
			전화번호 : <input type="text" name="memberPhone"><br>
			이메일 : <input type="text" name="memberEmail"><br>
			<input type="submit" value="회원가입">
			<input type="reset" value="취소">
		</fieldset>
	</form>
	<a href="/">메인으로</a>
	
	<script>
		$("[name=memberId]").on("change", function(){
			const memberId = $(this).val();
			$.ajax({
				url : "/idCheck.do",
				type : "get",
				data : {memberId : memberId},
				success : function(data){
					if(data == "ok"){
						$("#idChk").text("사용 가능한 아이디 입니다.");
						$("#idChk").css("color", "blue");
					}else{
						$("#idChk").text("이미 사용중인 아이디 입니다.");
						$("#idChk").css("color", "red");
					}
				}
			});
		});
	</script>
</body>
</html>

ajax에서 이동하는 Controller

	@ResponseBody
	@RequestMapping(value="/idCheck.do")
	public String idCheck(Member member) {
		//매개변수를 String memberId로 받아도 된다
		//Member를 사용하는 이유는 Service에서 메소드를 재사용하려고(아이디찾는 메소드가 이미 있기때문에)
		Member m = service.selectOneMemberId(member);
		if( m == null ) {
			//아이디 사용가능
			return "ok";
		}else {
			//아이디 중복
			return "dup";
		}
	}

 

1 - 3 ) ajax로 전체회원 조회하기(객체를 받기)

객체를 받기 위해서는 GSON이 필요, 이를 위에 제일처음 라이브러리를 추가해줬다.

index.jsp에 추가한 코드

			<button id="allMemberAjax">전체회원조회</button>
			<div id="ajaxResult"></div>
			
			<script>
				$("#allMemberAjax").on("click", function(){
					$.ajax({
						url : "/ajaxAllMember.do",
						//ajax요청에 의한 데이터를 되돌려 줄 때 문제점2
						//1. 문자열 형식 -> 객체로변경 
						//ajax에서 json을 선언해줘도되지만 이러면 한글이 깨짐 -> 따로인코딩을 해줘야함
						//2. 한글깨짐
						//이 두가지를 동시에 해결하기 위해 Controller에서 진행
						success : function(data){
							$("#ajaxResult").empty();
							const table = $("<table>");
							const titleTr = $("<tr>");
							titleTr.html("<th>번호</th>th>아이디</th>th>이름</th>th>전화번호</th>");
							table.append(titleTr);
							for(let i=0; i<data.length; i++){
								const tr = $("<tr>");
								tr.append("<td>"+data[i].memberNo+"</td>");
								tr.append("<td>"+data[i].memberId+"</td>");
								tr.append("<td>"+data[i].memberName+"</td>");
								tr.append("<td>"+data[i].memberPhone+"</td>");
								table.append(tr);
							}
							$("#ajaxResult").append(table);
						}
					});
				});
			</script>

ajax에서 이동하는 Controller

	//application/json;charset=utf-8 되돌려주는타입이 Json이고 한글타입임을 명시
	@ResponseBody
	@RequestMapping(value="/ajaxAllMember", produces = "application/json;charset=utf-8")
	public String ajaxAllMember() {
		
		ArrayList<Member> list = service.selectAllMember();
		Gson gson = new Gson();
		String result = gson.toJson(list);
		System.out.println(result);
		return result;
	}

 

2. 에러처리 ( 많이 본 에러 : 500, 400, 404 )

Http Response.Status 
[ 2xx ] -> 정상적으로 페이지가 떳을 때
200 ok
[ 3xx ] -> redirect
----------------------------------------------------------------------
[ 4xx ] -> 클라이언트가 잘못한 거
400  -> bad request(잘못된 요청)
404 -> not found(사용자가 잘못하는 경우, 개발자잘못)
-> 1) Controller를 잘못요청하는 경우(주소창잘못요청)
       : 사용자가 잘못했을 수도 있고, 개발중에 실수가 있을 수도 있음
        (사용자의 잘못일 수도 있으니 에러페이지로 처리)
-> 2) Controller에서 리턴하는 JSP를 만들지 않았거나 오타가 있는 경우
       : 100% 개발자의 실수 -> 에러페이지로 처리하면 안됨 -> 소스코드수정

[ 5xx ]  -> 서버에서 에러난거
500 -> 정보가 유출가능성이 있음 -> 소스코드 수정
502 -> bad gateway(서버터졌을때) : 그냥 에러페이지를 띄우느 사이트도 있지만 
    접속자가 많다는 페이지로 빼는 사이트도 있다.

404와 500은 발생하면 안되므로 에러처리를 해줄 것 
처리하는 방법

우선 web.xml 의 <servlet></servlet> 사이에 에러관련 설정을 추가해준다.

	<servlet>
    		<!-- 프로젝트 생성 시 기본 설정 -->
		<servlet-name>appServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
		</init-param>
		<!-- 에러처리를 위한 추가 설정 -->
		<init-param>
			<param-name>throwExceptionIfNoHandlerFound</param-name>
			<param-value>true</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

에러 관련 class

package common;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.NoHandlerFoundException;

//@Component를 포함하고 있는 annotation이기 때문에 이걸 붙여놔도 객체생성O
//@Controller annotation이 포함되어있는 객체에서 에러가 발생했을 때 처리하는 annotation
@ControllerAdvice
public class ErrorUtil {
	
	@ExceptionHandler(Exception.class)
	public String handelException(Exception e) {
		//오류마다 다르게 처리할거면 여러개 생성하면된다.
		System.err.println("에러발생");
		//out으로 해도되지만 색 바꾸려고 err
		System.err.println(e.getMessage());
		return "error/error1";
	}
	@ExceptionHandler(NoHandlerFoundException.class)
	@ResponseStatus(value = HttpStatus.NOT_FOUND) //응답상태가 not_found(404) 오류
	public String notFound(NoHandlerFoundException e) {
		System.err.println("RequestMapping 오류");
		System.err.println(e.getMessage());
		return "error/error2";
	}
}

 

error1.jsp 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>서버에서 에러가 발생했습니다.</h1>
	<hr>
	<h3>잠시후 다시 시도해주세요</h3>
	<a href="/">메인페이지로</a>
</body>
</html>

error2.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>요청 에러 발생</h1>
	<hr>
	<a href="/">메인으로</a>
</body>
</html>

코드를 짜는 단계에서는 에러확인을 해야하기때문에, 완성 후 에러처리작업을 해주는것이 좋다.

 

3. 웹소켓

웹소켓 사용을 위한 라이브러리 추가 - pom.xml

		<!-- Websocket사용을 위한 라이브러리(spring-websocket, jackson-databind) -->
		<!-- spring-websocket은 spring버전과 맞춰줘야한다. -->
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-websocket -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-websocket</artifactId>
		    <version>5.0.6.RELEASE</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
		<dependency>
		    <groupId>com.fasterxml.jackson.core</groupId>
		    <artifactId>jackson-databind</artifactId>
		    <version>2.13.5</version>
		</dependency>

servlet-context의 namespace 탭에서 웹소켓 선택

servlet-context의 source에서 웹소켓을 처리할 객체 생성

	<!-- 웹소켓 채팅을 처리할 객체 생성 -->
	<beans:bean id="allMemberChat" class="common.AllMemberChat" />
	<!-- 웹소켓 매핑 -->
	<websocket:handlers>
	 	<websocket:mapping handler="allMemberChat" path="/chat.do"/>
	 </websocket:handlers>

 

3 - 1 ) 채팅

채팅 페이지 이동

<h3><a href="/allMemberChat.do">전체채팅</a></h3>
	@RequestMapping(value="/allMemberChat.do")
	public String allMemberChat() {
		return "member/allMemberChat";
	}
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.6.1.js"></script>
<style>
	.chatting{
		width: 500px;
		display: none;
	}
		<%-- y축으로 내부컨텐츠가 넘어가면 스크롤생성 --%>
	.messageArea{
		overflow-y : auto;
		border: 1px solid black;
		height: 500px;
		display: flex;
		flex-direction: column;
		background-color: #b2c7d9;
	}
	.messageArea>p{
		text-align: center;
		width: 100%;
	}
	#sendMsg{
		width: 75%;
	}
	#sendBtn{
		width:20%;
	}
	.chat{
		margin-bottom: 10px;
		padding: 8px;
		border-radius: 3px;
	}
	.left{
		position: relative;
		max-width: 300px;
		align-self: flex-start;
		background-color: #fff;
		border-radius: 10px;
		margin-left: 16px;
		padding: 15px;
	}
	.left:after{
		content:'';
		position: absolute;
		border-style: solid;
		border-width: 15px 15px 15px 0;
		border-color: transparent #fff;
		display: block;
		width: 0;
		z-index: 1;
		left: -15px;
		top: 12px;
	}
	.right{
		position: relative;
		max-width: 300px;
		align-self: flex-end;
		background-color: #ffeb33;
		border-radius: 10px;
		margin-right: 16px;
		padding: 15px;
	}
	.right:after{
		content:'';
		position: absolute;
		border-style: solid;
		border-width: 15px 0 15px 15px;
		border-color: transparent #ffeb33;
		display: block;
		width: 0;
		z-index: 1;
		right: -15px;
		top: 12px;
	}
</style>
</head>
<body>
	<h1>전체채팅</h1>
	<c:if test="${not empty sessionScope.m }">
	<button onclick="initChat('${sessionScope.m.memberId}');">채팅시작하기</button>
	<div class="chatting">
		<div class="messageArea">
		</div>
		<div class="sendBox">
			<input type="text" id="sendMsg">
			<button id="sendBtn" onclick="sendMsg();">전송</button>
		</div>
	</div>
	<script>
		let ws; //웹소켓 객체를 저장하는 변수
		let memberId; // 회원아이디를 저장하는 변수
		function initChat(param){
			memberId = param;
			//웹소켓 연결 시도
			//주의점 127.0.0.1 또는 localhost로 사용하면 소켓연결을 할 수 없으므로 반드시 IP로 작성
			ws = new WebSocket("ws://192.168.10.17/chat.do");
			//웹소켓 연결 성공 시 실행할 함수 지정
			ws.onopen = startChat;
			//서버에서 데이터를 받으면 처리할 함수 지정
			ws.onmessage = receiveMsg;
			//웹소켓 연결이 종료되면 실행될 함수 지정
			ws.onclose = endChat;
			$(".chatting").slideDown();
		}
		function startChat(){
			console.log("웹소켓 연결완료");
			const data = {type:"enter", msg: memberId};
			//문자열이 넘어가야하는데 data는 Object이기 때문에 에러발생 JSON.stringify(data) 형태로 보내줘야한다
			console.log(JSON.stringify(data));
			ws.send(JSON.stringify(data));
			appendChat("<p>채팅방에 입장했습니다.</p>");
		}
		function receiveMsg(param){
			console.log(param);
			appendChat(param.data);
		}
		function endChat(){
			console.log("웹소켓 연결종료");
		}
		function sendMsg(){
			const msg = $("#sendMsg").val();
			if(msg != ''){
				const data = {type:"chat", msg:msg}
				ws.send(JSON.stringify(data)); 
				appendChat("<div class='chat right'>"+msg+"</div>");
				$("#sendMsg").val(''); //input clear
			}
		}
		$("#sendMsg").on("keyup", function(e){
			if(e.keyCode == 13){
				//keyCode == 13 : enter
				sendMsg();
			}
		});
		function appendChat(chatMsg){
			$(".messageArea").append(chatMsg);	
			//스크롤이 생기면 스크롤 위치를 잡아줌
			$(".messageArea").scrollTop($(".messageArea")[0].scrollHeight);
		}
	</script>

	</c:if>
	<hr>
	<a href="/">메인으로</a>
</body>
</html>

채팅 Controller

package common;

import java.util.ArrayList;
import java.util.HashMap;

import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import com.google.gson.JsonElement;
import com.google.gson.JsonParser;


public class AllMemberChat extends TextWebSocketHandler{
	//접속한 회원 세션을 저장하는 리스트
	private ArrayList<WebSocketSession> sessionList;
	//세션에 대한 아이디 mapping
	private HashMap<WebSocketSession, String> memberList;
	
	public AllMemberChat() {
		super();
		sessionList = new ArrayList<WebSocketSession>();
		memberList = new HashMap<WebSocketSession, String>();
	}

	//클라이언트가 웹소켓으로 최초에 접속했을 때 자동으로 수행되는 메소드
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception{
		System.out.println("클라이언트 접속");
		//최초 접속한 session정보를 세션목록에 추가
		sessionList.add(session);
	}
	
	//클라이언트가 메세지를 보내면 처리할 메소드
	@Override
	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception{
		//System.out.println("session : "+session);
		System.out.println("사용자가 전송한 메세지 : "+message.getPayload());
		//message.getPayload() : 문자열 형태로 객체데이터를 쓰기 위해서는 JSON형식으로 변환해서 사용해야함
		//문자열을 JSON으로 변환할 객체
		JsonParser parser = new JsonParser();
		JsonElement element = parser.parseString(message.getPayload());
		//key가 type인 값을 추출
		String type = element.getAsJsonObject().get("type").getAsString();
		//key가 msg인 값을 추출
		String msg = element.getAsJsonObject().get("msg").getAsString();
		System.out.println("type : "+type);
		System.out.println("msg : "+msg);
		if(type.equals("enter")) {
			//최초접속했을 때 memberId가 들어있음
			//최초접속이므로 memberList에 정보저장
			memberList.put(session, msg);
			String sendMsg = "<p>"+msg+"님이 입장하셨습니다.</p>";
			//클라이언트 전송용 객체
			TextMessage tm = new TextMessage(sendMsg);
			for(WebSocketSession s : sessionList) {
				if(!s.equals(session)) {
					s.sendMessage(tm);
				}
			}
		}else if(type.equals("chat")) {
			String sendMsg = "<div class='chat left'><span class='chatId'>"+memberList.get(session)+" : </span>"+msg+"</div>";
			TextMessage tm = new TextMessage(sendMsg);
			for(WebSocketSession s : sessionList) {
				if(!s.equals(session)) {
					s.sendMessage(tm);
				}
			}
		}
	}
	
	//클라이언트와 연결이 끊어졌을 때 자동으로 수행되는 메소드
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception{
		System.out.println("클라이언트 연결 끊김");
		//연결이 끊기면 세션목록에서 제거
		sessionList.remove(session);
		String sendMsg = "<p>"+memberList.get(session)+"님이 나갔습니다.</p>";
		TextMessage tm = new TextMessage(sendMsg);
		for(WebSocketSession s : sessionList) {
			if(!s.equals(session)) {
				s.sendMessage(tm);
			}
		}
		memberList.remove(session);
	}
}

 

3 - 2 ) 쪽지

쪽지기능을 위해 DB테이블 생성

-- 쪽지기능
CREATE TABLE DIRECT_MESSAGE(
    DM_NO       NUMBER      PRIMARY KEY,
    SENDER      VARCHAR2(20)    REFERENCES MEMBER_TBL(MEMBER_ID) ON DELETE CASCADE,
    RECEIVER    VARCHAR2(20)    REFERENCES MEMBER_TBL(MEMBER_ID) ON DELETE CASCADE,
    DM_CONTENT  VARCHAR2(300)   NOT NULL,
    DM_DATE     DATE,
    READ_CHECK  NUMBER      -- 0이면 읽지앖음 1이면 읽음
);
CREATE SEQUENCE DM_SEQ;

VO : DM.class

package kr.or.iei.dm.model.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class DM {
	private int dmNo;
	private String sender;
	private String receiver;
	private String dmContent;
	private String dmDate;
	private int readCheck;
}

쪽지 페이지 이동

<h3><a href="/dmMain.do">쪽지함</a></h3>
	@RequestMapping(value="/dmMain.do")
	public String dmMain() {
		return "dm/dmMain";
	}
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="/resources/css/dm.css">
<script src="https://code.jquery.com/jquery-3.6.1.js"></script>
</head>
<body>
	<h1>쪽지함</h1>
	<hr>
	<h3>쪽지보내기</h3>
	<button onclick="sendDmModal();">쪽지보내기</button>
	<hr>
	<h3>받은쪽지함</h3>
	<table border="1" class="receiveDmTbl">
		<thead>
			<tr>
				<th>보낸사람</th>
				<th>내용</th>
				<th>시간</th>
				<th>읽음여부</th>
			</tr>
		</thead>
		<tbody></tbody>
	</table>
	<hr>
	<h3>보낸쪽지함</h3>
	<table border="1" class="sendDmTbl">
		<thead>
			<tr>
				<th>받은사람</th>
				<th>내용</th>
				<th>시간</th>
				<th>읽음여부</th>
			</tr>
		</thead>
		<tbody></tbody>
	</table>
	
	
	<!-- 쪽지보내기 모달 -->
	<div id="sendDm-modal" class="modal-wrapper">
		<div class="modal">
			<div class="modal-header">
				<h2>쪽지보내기</h2>
			</div>
			<hr>
			<div class="modal-content">
				<div class="sendDmFrm">
					<label>수신자 : </label>
					<select name="receiver"></select>
					<textarea name="dmContent"></textarea>
					<input type="hidden" id="sender" value="${sessionScope.m.memberId }">
					<button onclick="dmSend();">쪽지보내기</button>
					<button onclick="closeModal();">닫기</button> 
				</div>
			</div>
		</div>
	</div>
	
	<script src="/resources/js/dm.js"></script>
</body>
</html>

dmMain - css

@charset "UTF-8";

h1{
    color: pink;

}
.modal-wrapper{
    position: fixed;
    width: 100vw;
    height: 100vh;
    background-color: rgba(0, 0, 0, 0.5);
    top: 0;
    left: 0;
    display: none;
    justify-content: center;
    align-items: center;
}
.modal{
    width: 350px;
    background-color: #fff;
}
.modal-header{
    padding: 10px;
}
.modal-content{
    padding: 20px;
}
textarea[name=dmContent]{
    width: 100%;
    height: 100px;
    resize: none;
}

dmMain - js

/**
 * 
 */

/* 버튼을 클릭하면 회원목록을 아작스로 가져올것*/
/* 회원조회는 memberController에 생성 */
function sendDmModal(){
    $.ajax({
        url : "/selectAllMemberId.do",
        success : function(list){
            //이름 중첩을 하지않기 위해 
            $("[name=receiver]").empty();
            for(let i=0; i<list.length; i++){
                const option = $("<option>");
                option.val(list[i]);
                option.text(list[i]);
                $("[name=receiver]").append(option);
            }
            $("#sendDm-modal").css("display", "flex");
        }
    });
}

function closeModal(){
    $("#sendDm-modal").hide();
    //내용도 전부 삭제해줘야함
    $("textarea[name=dmContent]").val("");
}

function dmSend(){
    //sender receiver dmcotnent를 받아올 것
    const receiver = $("[name=receiver]").val();
    const sender = $("#sender").val();
    const dmContent = $("[name=dmContent]").val();
    console.log(receiver, sender, dmContent);

    $.ajax({
        url : "/insertDm.do",
        type : "post",
        data : {receiver:receiver, sender:sender, dmContent:dmContent},
        success : function(data){
            if(data == "0"){
                alert("쪽지보내기 실패");
            }
            closeModal();
        }
    });
}

function getSendDm(){
    const sender = $("#sender").val();
    $.ajax({
        url : "/myDmList.do",
        data : {sender:sender},
        success : function(list){
            console.log(list);
        }
    });
}

function getReceiverDm(){
    const receiver = $("#sender").val();
    $.ajax({
        url : "/myDmList.do",
        data : {receiver:receiver},
        success : function(list){
            const tbody = $(".receiveDmTbl>tbody");
            tbody.empty();
            for(let i=0; i<list.length; i++){
                const dm = list[i];
                const tr = $("<tr>");
                //보낸사람, 내용, 시간 읽음여부
                const td1 = $("<td>");
                td1.text(dm.sender);
                const td2 = $("<td>");
                td2.text(dm.dmContent);
                const td3 = $("<td>");
                td3.text(dm.dmDate);
                const td4 = $("<td>");
                if(dm.readCheck == 0){
                    td4.text("읽지않음");
                }else{
                    td4.text("읽음");
                }
                tr.append(td1).append(td2).append(td3).append(td4);
                tbody.append(tr);               
            }
        }
    });
}

$(function(){
    getReceiverDm();
    getSendDm();
});

css와 js위치 webapp/resources 아래 각각 css js 폴더를 만들어서 cssFile/JavaScriptFile생성

 

쪽지보내기 버튼을 클릭 했을 때 회원들의 ID를 받아올 Controller(기존에 생성해놓았던 Service 사용)

	@ResponseBody
	@RequestMapping(value="/selectAllMemberId.do", produces = "application/json;charset=utf-8")
	public String selectAllMemberId() {
		ArrayList<String> list = service.search3();
		//ajax요청이기 때문에 위에 ResponseBody를 붙어야함
		//전달하려는 값이 객체이므로 produces
		return new Gson().toJson(list);
	}

쪽지를 보낼 Controller

	@ResponseBody
	@RequestMapping(value="/insertDm.do")
	public String insertDm(DM dm) {
		int result = service.insertDm(dm);
		return String.valueOf(result);
	}

Service - insert이기 때문에 트랙잭션 관리를 해줌

	@Transactional
	public int insertDm(DM dm) {
		return dao.insertDm(dm);
	}

Dao

	public int insertDm(DM dm) {
		int result = sqlSession.insert("dm.insetDm", dm);
		return result;
	}

dmSQL

	<insert id="insetDm" parameterType="dm">
		insert into direct_message values(dm_seq.nextval, #{sender}, #{receiver}, #{dmContent}, sysdate, 0)
	</insert>

받은쪽지List를 조회해올 Controller

	@ResponseBody
	@RequestMapping(value="/myDmList.do", produces = "application/json;charset=utf-8")
	public String myDmList(DM dm) {
		ArrayList<DM> list = service.selectDmList(dm);
		return new Gson().toJson(list);
	}

Service

	public ArrayList<DM> selectDmList(DM dm) {
		return dao.selectDmList(dm);
	}

Dao

	public ArrayList<DM> selectDmList(DM dm) {
		List list = sqlSession.selectList("dm.selectDmList", dm);
		return (ArrayList<DM>)list;
	}

dmSQL

	<select id="selectDmList" parameterType="dm" resultType="dm">
		select 
			dm_no as dmNo,
			sender,
			receiver,
			dm_content as dmContent,
			to_char(dm_date, 'yyyy-mm-dd hh:mi:ss') as dmDate,
			read_check as readCheck
		from direct_message
		<choose>
			<when test="sender != null">
			where sender = #{sender}
			</when>
			<when test="receiver != null">
			where receiver = #{receiver}
			</when>
		</choose>
		order by dm_no desc
	</select>

 

'국비수업 > Spring' 카테고리의 다른 글

80일차 : AOP, Transaction, Schedul  (0) 2023.03.22
79일차 : Dynamic Mybatis  (0) 2023.03.21
78일차 : Mybatis  (0) 2023.03.21
77일차 : SpringMVC - 게시판2  (0) 2023.03.17
76일차 : 정규화, SpringMVC - 게시판  (0) 2023.03.16
Comments