๐Ÿ’ก์Šคํ”„๋ง๋ถ€ํŠธ ์›น ์†Œ์ผ“ ์‹ค์‹œ๊ฐ„ ์ฑ„ํŒ…ํ•˜๊ธฐ (JSP)๐Ÿ’ก

gdhiยท2024๋…„ 2์›” 22์ผ
post-thumbnail

๐Ÿ’กํ”„๋กœ์ ํŠธ์— JSP ์ถ”๊ฐ€ํ•ด์„œ ๋ชจ๋‹ฌ๋กœ ๋„์šฐ๋˜์ง€ ์ฑ—๋ด‡์„ ๋งŒ๋“ค๋˜์ง€ ์–ด๋–ป๊ฒŒ ํ•˜๋ฉด ๋  ๋“ฏ ํ•˜๋‹ค๐Ÿ’ก

๐Ÿ“–์ดˆ๊ธฐ ํ™˜๊ฒฝ์„ค์ •

๐Ÿ‘‰ JSP ์˜์กด์„ฑ ์ถ”๊ฐ€Tomcat Embed Jasper

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

๐Ÿ‘‰ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ



๐Ÿ“Œapplication.properties

server.port=80

spring.mvc.view.prefix=/WEB-INF/view/
spring.mvc.view.suffix=.jsp



๐Ÿ“ŒWebSocketConfig

package com.ChattingTest.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@EnableWebSocketMessageBroker
@Configuration
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/websocket").withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic");

    }
}



๐Ÿ“ŒMainController

package com.ChattingTest.controller;

import com.ChattingTest.dto.ChattingRoom;
import com.ChattingTest.dto.Message;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.messaging.handler.annotation.DestinationVariable;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.*;

@Controller
public class MainController {

    // ์ฑ„ํŒ…๋ฐฉ ๋ชฉ๋ก
    public static LinkedList<ChattingRoom> chattingRoomList = new LinkedList<>();


    //	----------------------------------------------------
    // ์œ ํ‹ธ ๋ฉ”์„œ๋“œ

    // ๋ฐฉ ๋ฒˆํ˜ธ๋กœ ๋ฐฉ ์ฐพ๊ธฐ
    public ChattingRoom findRoom(String roomNumber) {
        ChattingRoom room = ChattingRoom.builder().roomNumber(roomNumber).build();
        int index = chattingRoomList.indexOf(room);

        if(chattingRoomList.contains(room)) {
            return chattingRoomList.get(index);
        }
        return null;
    }


    // ์ฟ ํ‚ค์— ์ถ”๊ฐ€
    public void addCookie(String cookieName, String cookieValue) {
        ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpServletResponse response = attr.getResponse();

        Cookie cookie = new Cookie(cookieName, cookieValue);

        int maxage = 60 * 60 * 24 * 7;
        cookie.setMaxAge(maxage);
        response.addCookie(cookie);
    }



    // ๋ฐฉ ๋ฒˆํ˜ธ, ๋‹‰๋„ค์ž„ ์ฟ ํ‚ค ์‚ญ์ œ
    public void deleteCookie( ) {
        ServletRequestAttributes attr = (ServletRequestAttributes)RequestContextHolder.currentRequestAttributes();
        HttpServletResponse response = attr.getResponse();

        Cookie roomCookie = new Cookie("roomNumber", null);
        Cookie nicknameCookie = new Cookie("nickname",null);

        roomCookie.setMaxAge(0);
        nicknameCookie.setMaxAge(0);

        response.addCookie(nicknameCookie);
        response.addCookie(roomCookie);
    }



    // ์ฟ ํ‚ค์—์„œ ๋ฐฉ๋ฒˆํ˜ธ, ๋‹‰๋„ค์ž„ ์ฐพ๊ธฐ
    public Map<String, String> findCookie() {
        ServletRequestAttributes attr = (ServletRequestAttributes)RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = attr.getRequest();

        Cookie[] cookies = request.getCookies();
        String roomNumber = "";
        String nickname= "";

        if(cookies == null) {
            return null;
        }

        if(cookies != null) {
            for(int i=0;i<cookies.length;i++) {
                if("roomNumber".equals(cookies[i].getName())) {
                    roomNumber = cookies[i].getValue();
                }
                if("nickname".equals(cookies[i].getName())) {
                    nickname = cookies[i].getValue();
                }
            }

            if(!"".equals(roomNumber) && !"".equals(nickname)) {
                Map<String, String> map = new HashMap<>();
                map.put("nickname", nickname);
                map.put("roomNumber", roomNumber);

                return map;
            }
        }

        return null;
    }

    // ๋‹‰๋„ค์ž„ ์ƒ์„ฑ
    public void createNickname(String nickname) {
        addCookie("nickname", nickname);
    }

    // ๋ฐฉ ์ž…์žฅํ•˜๊ธฐ
    public boolean enterChattingRoom(ChattingRoom chattingRoom, String nickname) {
        createNickname(nickname);

        if(chattingRoom == null) {
            deleteCookie();
            return false;
        } else {
            LinkedList<String> users = chattingRoom.getUsers();
            users.add(nickname);

            addCookie("roomNumber", chattingRoom.getRoomNumber());
            return true;
        }
    }


    //	----------------------------------------------------

    // ์ปจํŠธ๋กค๋Ÿฌ

    // ๋ฉ”์ธํ™”๋ฉด
    @GetMapping("/")
    public String main() {
        return "main";
    }


    // ์ฑ„ํŒ…๋ฐฉ ๋ชฉ๋ก
    @GetMapping("/chattingRoomList")
    public ResponseEntity<?> chattingRoomList() {
        return new ResponseEntity<LinkedList<ChattingRoom>>(chattingRoomList, HttpStatus.OK);
    }


    // ๋ฐฉ ๋งŒ๋“ค๊ธฐ
    @PostMapping("/chattingRoom")
    public ResponseEntity<?> chattingRoom(String roomName, String nickname) {

        // ๋ฐฉ์„ ๋งŒ๋“ค๊ณ  ์ฑ„ํŒ…๋ฐฉ๋ชฉ๋ก์— ์ถ”๊ฐ€
        String roomNumber = UUID.randomUUID().toString();
        ChattingRoom chattingRoom = ChattingRoom.builder()
                .roomNumber(roomNumber)
                .users(new LinkedList<>())
                .roomName(roomName)
                .build();

        chattingRoomList.add(chattingRoom);

        // ๋ฐฉ ์ž…์žฅํ•˜๊ธฐ
        enterChattingRoom(chattingRoom, nickname);

        return new ResponseEntity<>(chattingRoom, HttpStatus.OK);
    }


    // ๋ฐฉ ๋“ค์–ด๊ฐ€๊ธฐ
    @GetMapping("/chattingRoom-enter")
    public ResponseEntity<?> EnterChattingRoom(String roomNumber, String nickname){

        // ๋ฐฉ ๋ฒˆํ˜ธ๋กœ ๋ฐฉ ์ฐพ๊ธฐ
        ChattingRoom chattingRoom = findRoom(roomNumber);

        if(chattingRoom == null) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        } else {
            // ๋ฐฉ ๋“ค์–ด๊ฐ€๊ธฐ
            enterChattingRoom(chattingRoom, nickname);

            return new ResponseEntity<>(chattingRoom, HttpStatus.OK);
        }
    }

    // ๋ฐฉ ๋‚˜๊ฐ€๊ธฐ
    @PatchMapping("/chattingRoom-exit")
    public ResponseEntity<?> ExitChattingRoom(){

        Map<String, String> map = findCookie();

        if(map == null) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }


        String roomNumber = map.get("roomNumber");
        String nickname = map.get("nickname");

        // ๋ฐฉ๋ชฉ๋ก์—์„œ ๋ฐฉ๋ฒˆํ˜ธ์— ๋งž๋Š” ์œ ์ €๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ
        ChattingRoom chattingRoom = findRoom(roomNumber);
        List<String> users = chattingRoom.getUsers();

        // ๋‹‰๋„ค์ž„ ์‚ญ์ œ
        users.remove(nickname);

        // ์ฟ ํ‚ค์—์„œ ๋‹‰๋„ค์ž„๊ณผ ๋ฐฉ๋ฒˆํ˜ธ ์‚ญ์ œ
        deleteCookie();

        // ์œ ์ €๊ฐ€ ํ•œ๋ช…๋„ ์—†๋‹ค๋ฉด ๋ฐฉ ์‚ญ์ œ
        if(users.size() == 0) {
            chattingRoomList.remove(chattingRoom);
        }

        return new ResponseEntity<>(chattingRoom, HttpStatus.OK);
    }


    // ์ฐธ๊ฐ€ ์ค‘์ด์—ˆ๋˜ ๋Œ€ํ™”๋ฐฉ
    @GetMapping("/chattingRoom")
    public ResponseEntity<?> chattingRoom() {
        // ์ฟ ํ‚ค์— ๋‹‰๋„ค์ž„๊ณผ ๋ฐฉ๋ฒˆํ˜ธ๊ฐ€ ์žˆ๋‹ค๋ฉด ๋Œ€ํ™”์ค‘์ด๋˜ ๋ฐฉ์ด ์žˆ๋˜๊ฒƒ
        Map<String, String> map = findCookie();

        if(map == null) {
            return new ResponseEntity<>(HttpStatus.OK);
        }

        String roomNumber = map.get("roomNumber");
        String nickname = map.get("nickname");

        ChattingRoom chattingRoom = findRoom(roomNumber);

        if(chattingRoom == null) {
            deleteCookie();
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        } else {
            Map<String, Object> map2 = new HashMap<>();
            map2.put("chattingRoom", chattingRoom);
            map2.put("myNickname", nickname);

            return new ResponseEntity<>(map2, HttpStatus.OK);
        }
    }



    //	----------------------------------------------------
    // ๋ฉ”์„ธ์ง€ ์ปจํŠธ๋กค๋Ÿฌ

    // ์—ฌ๊ธฐ์„œ ๋ฉ”์„ธ์ง€๊ฐ€ ์˜ค๋ฉด ๋ฐฉ๋ชฉ๋ก ์—…๋ฐ์ดํŠธ
    @MessageMapping("/socket/roomList")
    @SendTo("/topic/roomList")
    public String roomList() {
        return "";
    }

    // ์ฑ„ํŒ…๋ฐฉ์—์„œ ๋ฉ”์„ธ์ง€ ๋ณด๋‚ด๊ธฐ
    @MessageMapping("/socket/sendMessage/{roomNumber}")
    @SendTo("/topic/message/{roomNumber}")
    public Message sendMessage(@DestinationVariable String roomNumber, Message message) {
        return message;
    }

    // ์ฑ„ํŒ…๋ฐฉ์— ์ž…์žฅ ํ‡ด์žฅ ๋ฉ”์„ธ์ง€ ๋ณด๋‚ด๊ธฐ
    @MessageMapping("/socket/notification/{roomNumber}")
    @SendTo("/topic/notification/{roomNumber}")
    public Map<String, Object> notification(@DestinationVariable String roomNumber, Map<String, Object> chattingRoom) {
        return chattingRoom;
    }


}



๐Ÿ“ŒChattingRoom

package com.ChattingTest.dto;

import lombok.Builder;
import lombok.Data;

import java.util.LinkedList;
import java.util.Objects;

@Data
@Builder
public class ChattingRoom {
    private String roomNumber; // ๋ฐฉ ๋ฒˆํ˜ธ
    private String roomName; // ๋ฐฉ ์ด๋ฆ„
    private LinkedList<String> users; // ์œ ์ €๋ชฉ๋ก


    // ์ฑ„ํŒ…๋ฐฉ ๋ชฉ๋ก์—์„œ ๋ฐฉ ๋ฒˆํ˜ธ๋กœ ๋ฐฉ์„ ์ฐพ์„ ์ˆ˜ ์žˆ๊ฒŒ equals์™€ hashCode๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉ
    // ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  BuilderํŒจํ„ด์„ ์‚ฌ์šฉ

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        ChattingRoom other = (ChattingRoom) obj;
        return Objects.equals(roomNumber, other.roomNumber);
    }
    @Override
    public int hashCode() {
        return Objects.hash(roomNumber);
    }
}



๐Ÿ“ŒMessage

package com.ChattingTest.dto;

import lombok.Data;

import java.util.Date;

@Data
public class Message {
    private String message;
    private String nickname;
    private Date date;

    Message(){
        date = new Date();
    }
}



๐Ÿ“Œmain.css

@charset "UTF-8";

* {
    margin: 0;
    padding: 0;
}

li {
    list-style: none;
}

html {
    font-size: 62.5%;
}

.swal-footer {
	text-align: center;
}
/* ์ฑ„ํŒ…๋ฐฉ ๋ชฉ๋ก */


main {
    width: 35vw;
    min-width: 300px;
    height: 90vh;
    border: 1px solid #000;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
}

main h1 {
    font-size: 2rem;
    padding: 10px;
    height: 50px;
    box-sizing: border-box;
}

main .new_chat {
	position: absolute;
	top: 10px;
	right: 10px;
	border-radius: 3px;
	padding: 3px;
	background: #fff;
	cursor: pointer;
}

main .new_chat:hover {
	background: #eee;
}

main nav {
	 font-size: 1.6rem;
	 display: flex;
	 text-align: center;
	 margin-bottom: 5px;
	 padding: 0 7px;
}

main nav > span:first-child {
	width: 80%;
}

main nav > span:last-child {
	width: 20%;
}

main ul {
    overflow-y: auto;
    max-height: calc(100% - 50px);
}

main li {
    font-size: 1.6rem;
    width: 100%;
    height: 70px;
    padding: 7px;
    box-sizing: border-box;
    display: flex;
    justify-content: space-between;
}

main li:hover {
   background: #eee;
}

main .chat_title {
    font-weight: bold;
    width: 80%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

main .chat_count {
    width: 20%;
    text-align: center;
}

/* ์ฑ„ํŒ…๋ฐฉ ๋ชฉ๋ก */



/* ์ฑ„ํŒ…๋ฐฉ ์•ˆ */

.chat {
    width: 50vw;
    min-width: 300px;
    height: 90vh;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    z-index: 10;
   	display: none;
}

.chat > div {
	height: 100%;
	display: flex;
}

.chat .chat_body {
  	background: rgb(195, 204, 221);
	height: 100%;
	width: 70%;
    order: 1;
    border: 1px solid #000;
    position: relative;
}

.chat h2 {
    font-size: 2rem;
    padding: 10px;
    height: 50px;
    box-sizing: border-box;
    text-align: center;
    background: #eee;
}

.chat .chat_back {
    font-size: 2rem;
    width: 50px;
    height: 50px;
    position: absolute;
    top: 0;
    left: 0;
    border: none;
    cursor: pointer;
}

.chat ul.chat_list {
    overflow-y: auto;
    height: calc(100% - 150px);
    box-sizing: border-box;
    padding: 5px 0;
}

.chat li {
    font-size: 1.5rem;
}

.chat li > div {
    padding: 10px;
    display: flex;
}

.chat li .notification {
	text-align: center;
}

.chat li .notification span {
	margin: 0 auto;
	border-radius: 15px;
	padding: 5px 10px;
	background: #ae9191;
	color: #fff;
}

.chat li > div .nickname {
	padding: 3px;
}

.chat li > div .message {
	display: flex;
}

.chat .chat_me {
   justify-content: end;
}

.chat .chat_other {
    justify-content: start;
}

.chat .chat_other .chat_in_time {
    order: 1;
}

.chat .chat_in_time {
    font-size: 1.3rem;
    margin: 0 5px;
    display: flex;
    align-items: flex-end;
}

.chat .chat_content {
    padding: 5px;
    border-radius: 3px;
    box-shadow: 0px 2px 3px 0px rgb(0 0 0 / 25%);
    display: inline-block;
    max-width: 250px;
    max-height: 400px;
    overflow-y: auto;
    word-break: break-all;
}

.chat .chat_me .chat_content {
    background: yellow;
}

.chat .chat_other .chat_content {
    background: #fff;
}

.chat .chat_input {
    height: 100px;
    display: flex;
    background: #fff;
}

.chat_input .chat_input_area {
    width: 87%;
}

.chat_input .chat_input_area textarea {
    width: 100%;
    height: 100%;
    border: none;
    resize: none;
    padding: 8px;
    box-sizing: border-box;
}

.chat_input .chat_input_area textarea:focus {
    outline: none;
}

.chat_input .chat_button_area {
    width: 13%;
}

.chat_input .chat_button_area button {
    background: yellow;
    border: 1px solid #ddd;
    border-radius: 3px;
    padding: 5px;
    width: 90%;
    margin-top: 10px;
    cursor: pointer;
}

.chat .chat_users {
	border: 1px solid #ddd;
	width: 30%;
	height: 300px;
/* 	position: absolute;
	right: 101%;
	top: 0; */
    margin-right: 3px;
}

/* ์ฐธ๊ฐ€์ธ์› */
.chat .chat_users h2 {
	font-size: 1.6rem;
}

.chat .chat_users .chat_nickname {
	font-size: 1.6rem;
	height: calc(100% - 50px);
	overflow: auto;
}

.chat .chat_users .chat_nickname li {
	padding: 5px;
}

/* ์ฐธ๊ฐ€์ธ์› */


/* ์ฑ„ํŒ…๋ฐฉ ์•ˆ */



@media(max-width: 1024px)  {
	html {
		font-size: 60%;
	}
	main {
		width: 99vw;
	}

	.chat {
		width: 99vw;
	}
}



๐Ÿ“Œmain.js

$(document).ready(function(){


// ๋ฐฉ ๋ชฉ๋ก ๊ทธ๋ฆฌ๊ธฐ
const listHtml = function(roomList) {
	let listHtml = "";

		for(let i=roomList.length-1;i>=0;i--) {
			listHtml += `
				<li data-room_number=${roomList[i].roomNumber}>
                    <span class="chat_title">${roomList[i].roomName }</span>
                    <span class="chat_count">${roomList[i].users.length}๋ช…</span>
	            </li>`;
		}
		$("main ul").html(listHtml);
}


// ์ฑ„ํŒ…๋ฐฉ ๋ชฉ๋ก ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
const chattingRoomList = function(){
	$.ajax({
		url: "/chattingRoomList",
		type: "GET",
	})
	.then(function(result){
		listHtml(result)
	})
	.fail(function(){
		alert("์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค");
	})
}



const socket = new SockJS('/websocket');
const stomp = Stomp.over(socket);
stomp.debug = null; // stomp ์ฝ˜์†”์ถœ๋ ฅ X


// ๊ตฌ๋…์„ ์ทจ์†Œํ•˜๊ธฐ์œ„ํ•ด ๊ตฌ๋… ์‹œ ์•„์ด๋”” ์ €์žฅ
const subscribe = [];

// ๋ชจ๋“  ๊ตฌ๋… ์ทจ์†Œํ•˜๊ธฐ
const subscribeCancle = function() {
	const length = subscribe.length;
	for(let i=0;i<length;i++) {
		const sid = subscribe.pop();
		stomp.unsubscribe(sid.id);
	}
}


// ๋ฉ”์ธ ํ™”๋ฉด
const main = function() {
	$("main").show();

	// ๊ธฐ์กด ๊ตฌ๋… ์ทจ์†Œ
	subscribeCancle();

	// ์ฑ„ํŒ… ์ค‘์ด์—ˆ๋˜ ๋ฐฉ์ด ์žˆ์„๋•Œ
	const room = chattingRoom();

	if(room) {
		return;
	}

	const subscribeId = stomp.subscribe("/topic/roomList", function(){
		// "/topic/roomList"์—์„œ ๋ฉ”์„ธ์ง€๊ฐ€ ์™”์„๋•Œ ์‹คํ–‰ํ•  ํ•จ์ˆ˜
		chattingRoomList();
	});

	subscribe.push(subscribeId);
	chattingRoomList();
};



stomp.connect({}, function(){
	main();
});


// ----------------- ๋ฉ”์ธํ™”๋ฉด ---------------------------



// ----------------- ์ฑ„ํŒ…๋ฐฉ ---------------------------


const info = (function(){
	let nickname = "";
	let roomNumber = "";

	const getNickname = function() {
		return nickname;
	}

	const setNickname = function(set){
		nickname = set;
	}

	const getRoomNumber = function() {
		return roomNumber;
	}

	const setRoomNumber = function(set) {
		roomNumber = set;
	}
	return {
		getNickname : getNickname,
		setNickname : setNickname,
		getRoomNumber : getRoomNumber,
		setRoomNumber : setRoomNumber,
	}
})();


const errorMSG = function(result){
	if(result.status == 404) {
		alert("์ข…๋ฃŒ๋˜์—ˆ๊ฑฐ๋‚˜ ์—†๋Š” ๋ฐฉ์ž…๋‹ˆ๋‹ค");
	} else {
		alert("์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค");
	}
	location.href = "/";
}


// ์ฐธ๊ฐ€์ž ๊ทธ๋ฆฌ๊ธฐ
const userList = function(users){
	$(".chat .chat_users .user").text(users.length + "๋ช…");

	let userHtml = "";
	for(let i=0;i<users.length;i++) {
		userHtml += `
			<li>${users[i] }</li>`;
	}

	$(".chat .chat_nickname ul").html(userHtml);
}


// ๋ฉ”์„ธ์ง€ ๊ทธ๋ฆฌ๊ธฐ
const chatting = function(messageInfo){
	let nickname = messageInfo.nickname;
	let message = messageInfo.message;

	message = message.replaceAll("\n", "<br>").replaceAll(" ", "&nbsp");

	const date = messageInfo.date;
	const d = new Date(date);

	const time = String(d.getHours()).padStart(2, "0")
				+ ":"
				+ String(d.getMinutes()).padStart(2, "0");

	let sender = "";

	if(info.getNickname() == nickname) {
		sender = "chat_me";
		nickname = "";
	} else {
		sender=  "chat_other";
	}


	const chatHtml = `
        <li>
            <div class=${sender }>
            	<div>
	            	<div class="nickname">${nickname }</div>
	            	<div class="message">
		                <span class=chat_in_time>${time }</span>
		                <span class="chat_content">${message }</span>
	                <span>
                </div>
            </div>
        </li>`;

	$(".chat ul.chat_list").append(chatHtml);

	$(".chat ul").scrollTop($(".chat ul")[0].scrollHeight);
}


// ์ฑ„ํŒ…๋ฐฉ ๊ตฌ๋…
const chattingConnect = function(roomNumber){
	// ๊ธฐ์กด ๊ตฌ๋… ์ทจ์†Œ
	subscribeCancle();

	// ๋ฉ”์„ธ์ง€๋ฅผ ๋ฐ›์„ ๊ฒฝ๋กœ
	const id1 = stomp.subscribe("/topic/message/" + roomNumber, function(result){
		const message = JSON.parse(result.body);

		// ๋ฉ”์„ธ์ง€๊ฐ€ ์™”์„๋•Œ ์‹คํ–‰ํ•  ํ•จ์ˆ˜
		chatting(message);
	})

	// ์ž…์žฅ,ํ‡ด์žฅ ์•Œ๋ฆผ์„ ๋ฐ›์„ ๊ฒฝ๋กœ
	const id2 = stomp.subscribe("/topic/notification/" + roomNumber, function(result){
		const room = JSON.parse(result.body);
		const message = room.message;

		// ๋ฉ”์„ธ์ง€๊ฐ€ ์™”์„๋•Œ ์‹คํ–‰ํ•  ํ•จ์ˆ˜
		userList(room.users);

		const chatHtml = `
	        <li>
	        	<div class="notification">
            		<span>${message}</span>
            	</div>
	        </li>`;

		$(".chat ul.chat_list").append(chatHtml);

		$(".chat ul").scrollTop($(".chat ul")[0].scrollHeight);

	})

	subscribe.push(id1);
	subscribe.push(id2);
}



// ์ฑ„ํŒ…๋ฐฉ ์„ธํŒ…
const initRoom = function(room, nickname) {
	// ๋ฐฉ ๋ชฉ๋ก ์—…๋ฐ์ดํŠธ
	stomp.send("/socket/roomList");

	$("main").hide();

	info.setNickname(nickname);
	info.setRoomNumber(room.roomNumber);

	$(".chat").show();
	$(".chat .chat_title").text(room.roomName);

	userList(room.users);
	chattingConnect(room.roomNumber);

	$(".chat_input_area textarea").focus();
}


// ๋ฉ”์„ธ์ง€ ๋ณด๋‚ด๊ธฐ
const sendMessage = function(){
	const message = $(".chat_input_area textarea");

	if (message.val() == "") {
		return;
	}

	const roomNumber = info.getRoomNumber();
	const nickname = info.getNickname();

	const data = {
		message : message.val(),
		nickname : nickname,
	}

	stomp.send("/socket/sendMessage/" + roomNumber, {}, JSON.stringify(data));
	message.val("");
}




$(".chat_button_area button").click(function() {
	sendMessage();
	$(".chat_input_area textarea").focus();
})


$(".chat_input_area textarea").keypress(function(event) {
	if (event.keyCode == 13) {
		if (!event.shiftKey) {
			event.preventDefault();

			sendMessage();
		}
	}
})


// ๋‹‰๋„ค์ž„ ๋งŒ๋“ค๊ณ  ์ฑ„ํŒ…๋ฐฉ ๋“ค์–ด๊ฐ€๊ธฐ
const enterChattingRoom = function(roomNumber) {

	swal({
		text: "์‚ฌ์šฉํ•˜์‹ค ๋‹‰๋„ค์ž„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”",
		content: "input",
		buttons: ["์ทจ์†Œ", "ํ™•์ธ"],
		closeOnClickOutside : false
	})
	.then(function(nickname){
		if(nickname) {

			const data = {
				roomNumber : roomNumber,
				nickname : nickname
			}

			$.ajax({
				url: "/chattingRoom-enter",
				type: "GET",
				data: data,
			})
			.then(function(room){
				initRoom(room, nickname);

				// ์ฑ„ํŒ…๋ฐฉ ์ฐธ๊ฐ€ ๋ฉ”์„ธ์ง€
				room.message = nickname + "๋‹˜์ด ์ฐธ๊ฐ€ํ•˜์…จ์Šต๋‹ˆ๋‹ค";
				stomp.send(
					"/socket/notification/" + roomNumber, {},
					JSON.stringify(room));

			})
			.fail(function(result){
				errorMSG(result);
			})
		}
	})
}



// ์ƒˆ ์ฑ„ํŒ…๋ฐฉ ๋งŒ๋“ค๊ธฐ
const createRoom = function(roomName) {
	swal({
		text: "์‚ฌ์šฉํ•˜์‹ค ๋‹‰๋„ค์ž„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”",
		content: "input",
		buttons: ["์ทจ์†Œ", "ํ™•์ธ"],
		closeOnClickOutside : false
	})
	.then(function(nickname){
		if(nickname) {

			const data = {
				roomName : roomName,
				nickname : nickname
			}

			$.ajax({
				url: "/chattingRoom",
				type: "POST",
				data: data,
			})
			.then(function(room){
				initRoom(room, nickname)
			})
			.fail(function(){
				alert("์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค");
			})
		}
	})
}




$(".new_chat").click(function(){
	swal({
		text: "๋ฐฉ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”",
		content: "input",
		buttons: ["์ทจ์†Œ", "ํ™•์ธ"],
		closeOnClickOutside : false
	})
	.then(function(roomName){
		if(roomName) {
			createRoom(roomName);
		}
	})
})






$(document).on("dblclick", "main li", function(){
	const roomNumber = $(this).data("room_number");
	enterChattingRoom(roomNumber);
})




// ์ฑ„ํŒ…๋ฐฉ ๋‚˜๊ฐ€๊ธฐ
$(".chat_back").click(function() {
	swal({
		text: "๋Œ€ํ™”๋ฐฉ์—์„œ ๋‚˜๊ฐˆ๊นŒ์š”?",
		buttons: ["์ทจ์†Œ", "ํ™•์ธ"]
	})
	.then(function(result){
		if(result) {
			$.ajax({
				url: "/chattingRoom-exit",
				type: "PATCH",
			})
			.then(function(room){
				const roomNumber = info.getRoomNumber();

				if(room.users.length != 0) {
					// ์ฑ„ํŒ…๋ฐฉ ๋‚˜๊ฐ€๊ธฐ ๋ฉ”์„ธ์ง€
					room.message = info.getNickname() + "๋‹˜์ด ํ‡ด์žฅํ•˜์…จ์Šต๋‹ˆ๋‹ค";
					stomp.send(
						"/socket/notification/" + roomNumber, {},
						JSON.stringify(room));
				}

				// ์ฑ„ํŒ…๋ฐฉ ๋ชฉ๋ก ์—…๋ฐ์ดํŠธ
				stomp.send("/socket/roomList");

				main();
				$(".chat").hide();
				$(".chat ul.chat_list").html("");

				info.setRoomNumber("");
				info.setNickname("");
			})
			.fail(function(){
				errorMSG();
			})
		}
	})
})



// ๋Œ€ํ™” ์ค‘์ด๋˜ ๋ฐฉ
const chattingRoom = function (){
	let returnRoom = null;

	$.ajax({
		url: "/chattingRoom",
		type: "GET",
		async: false,
	})
	.then(function(result){
		if(result != "") {
			const room = result.chattingRoom;
			const nickname = result.myNickname;
			initRoom(room, nickname);
			returnRoom = result;
		}
	})
	.fail(function(result){
		errorMSG(result);
	})

	return returnRoom;
};


}) // document.ready



๐Ÿ“Œmain.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>์ฑ„ํŒ…</title>

<link rel="stylesheet" href="/css/main.css">

</head>
<body>
	<!-- ์ฑ„ํŒ…๋ฐฉ ๋ชฉ๋ก -->
	<main>
        <h1>์ฑ„ํŒ…๋ฐฉ</h1>
        <button class="new_chat">์ƒˆ ์ฑ„ํŒ…๋ฐฉ ๋งŒ๋“ค๊ธฐ</button>
        <nav>
        	<span>๋ฐฉ ์ œ๋ชฉ</span>
        	<span>์ธ์›</span>
        </nav>
       	<hr>

        <ul>
            <li>
            <!--
				<span class="chat_title"></span>
				<span class="chat_count"></span>
				 -->
            </li>
        </ul>
    </main>
	<!-- ์ฑ„ํŒ…๋ฐฉ ๋ชฉ๋ก -->

	<!-- ์ฑ„ํŒ…๋ฐฉ ์ž…์žฅ -->
    <div class="chat">
   		<div>
   			<div class="chat_body">
		        <h2 class="chat_title">1๋ฒˆ๋ฐฉ</h2>
		        <button class="chat_back">โ—€</button>

		        <ul class="chat_list">
		            <li>
		            	<!-- <div class="notification">
		            		<span></span>
		            	</div> -->
		            </li>
		        </ul>

		        <div class="chat_input">
		            <div class="chat_input_area">
		                <textarea></textarea>
		            </div>

		            <div class="chat_button_area">
		                <button>์ „์†ก</button>
		            </div>
		        </div>
	        </div>

	        <div class="chat_users">
	        	<h2>
	        		์ฐธ๊ฐ€์ธ์›
	        		<span class="user"></span>
	        	</h2>

	        	<div class="chat_nickname">
	        		<ul>
	        			<li>
	       				</li>
	        		</ul>
	        	</div>
	        </div>
   		</div>
    </div>
    <!-- ์ฑ„ํŒ…๋ฐฉ ์ž…์žฅ -->

    <!-- sock js -->
	<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.5.2/sockjs.min.js"></script>
	<!-- STOMP -->
	<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>

    <script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
    <script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
    <script src="/js/main.js"></script>
</body>
</html>



โ“๊ตฌํ˜„ ๋ฐฉ์‹

  1. ๋ฉ”์ธํ™”๋ฉด์— ์ ‘์†ํ•˜๋ฉด ์›น์†Œ์ผ“์„ ์—ฐ๊ฒฐํ•˜๊ณ  /roomList๋ฅผ ๊ตฌ๋…
  2. ์‚ฌ์šฉ์ž๊ฐ€ ๋ฐฉ์„ ๋งŒ๋“ค๋ฉด /roomList๋กœ ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด๋‚ด ์ƒˆ๋กœ์šด ๋ฐฉ์ด ๋งŒ๋“ค์–ด์กŒ๋‹ค๋Š” ๊ฑธ ์•Œ๋ฆผ
  3. ๋ฉ”์ธํ™”๋ฉด์— ์žˆ๋Š” ์‚ฌ์šฉ์ž๋“ค์€ /roomList๋กœ ๋ฉ”์„ธ์ง€๋ฅผ ๋ฐ›์œผ๋ฉด ๋ฐฉ๋ชฉ๋ก์„ ๋ถˆ๋Ÿฌ์˜ด
  4. ๋ฐฉ์„ ๋งŒ๋“ค๊ฑฐ๋‚˜ ๋‹ค๋ฅธ์‚ฌ๋žŒ์ด ๋งŒ๋“  ๋ฐฉ์— ๋“ค์–ด๊ฐˆ ๊ฒฝ์šฐ /roomList์˜ ๊ตฌ๋…์„ ์ทจ์†Œํ•˜๊ณ  /message/๋ฐฉ๋ฒˆํ˜ธ(UUID)๋ฅผ ๊ตฌ๋…
  5. ๋ฐฉ ์•ˆ์—์„œ ๊ฐ™์€ ๋ฐฉ๋ฒˆํ˜ธ๋ฅผ ๊ตฌ๋…ํ•œ ์‚ฌ๋žŒ๋ผ๋ฆฌ ๋ฉ”์„ธ์ง€๋ฅผ ์ฃผ๊ณ ๋ฐ›์„ ์ˆ˜ ์žˆ์Œ









๊ฒฐ๊ณผ

0๊ฐœ์˜ ๋Œ“๊ธ€