[ Java / Socket ] JSON을 이용하여 소켓 통신 (비회원 채팅, 익명채팅)

2024. 6. 30. 15:27· LANGUAGE/└ Java

환경 : Spring Tool Suite4

 

 

등록 → 재정의(Override) 순서로 socket을 활용하자~!!!!!1

 

   - JsonWebSocketServer.java

/**
 * 클라이언트와 JSON 형태의 데이터를 주고받도록 처리
 * - 사용자가 보낸 메세지에 시간과 같은 정보를 추가하여 회신하도록 구현
 * */

@Slf4j
@Service
public class JsonWebSocketServer extends TextWebSocketHandler{
	private Set<WebSocketSession> users = new CopyOnWriteArraySet<>();//동기화 됨(자물쇠 있음)
	
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		users.add(session);
		log.debug("사용자 접속! 현재 사용자 {}명", users.size());
	}
	
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		users.remove(session);
		log.debug("사용자 접속 종료! 현재 사용자 {}명", users.size());
	}

	@Override
	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
		//서버와 클라이언트 간의 메세지 규약을 만들어보자
		//- 클라이언트 -----> 서버 : ChatRequestVO
		//- 서버 -----> 클라이언트 : ChatResponseVO
		
		//[1] 사용자가 보낸 메세지를 ChatRequestVO로 해석
		ObjectMapper mapper = new ObjectMapper();
		ChatRequestVO requestVO = mapper.readValue(message.getPayload(), ChatRequestVO.class);
		
		//[2] 사용자에게 보낼 메세지를 ChatResponseVO로 생성
		ChatResponseVO responseVO = ChatResponseVO.builder()
				.content(requestVO.getContent())//내용은 그대로 복사
				.time(LocalDateTime.now().toString())//시간 추가
			.build();
		
		//[3] 메세지 객체 생성
		String json = mapper.writeValueAsString(responseVO);
		TextMessage response = new TextMessage(json);
		
		//전체에게 메세지를 전송(broadcast)
		for(WebSocketSession user : users) {
			user.sendMessage(response);
		}
	}
}

 

   - WebSocketServerConfiguration.java

/**
 * 웹소켓과 관련된 설정을 작성하는 파일
 * 이미 등록해둔 웹소켓 서버들을 가져와서 추가적인 설정을 한 뒤 활성화
 * */

@EnableWebSocket//웹소켓을 사용할 것임을 표시(활성화)
@Configuration//설정파일임을 표시
public class WebSocketServerConfiguration implements WebSocketConfigurer {
	@Autowired
	private JsonWebSocketServer jsonWebSocketServer;
	
	@Override
	public void registerWebSocketHandlers (WebSocketHandlerRegistry registry) {
		//SockJS를 사용하도록 설정하며 등록
		//[1] 웹소켓을 지원하지 않는 브라우저는 유사기술로 웹소켓처럼 구현해줌
		//(유사기술은 pulling, long-pulling과 같은 기술을 말함)
		//[2] 주소를 http로 사용 가능하며, 아무나 들어오지 못하도록 ws 주소가 변함
		//[3] 접속자에 대한 컴팩트한 관리가 가능하다(heartbeat 핑)
		registry.addHandler(jsonWebSocketServer, "/ws/json")
				.withSockJS();
	}
}

 

서버와 클라이언트 간의 메세지 규약을 만들어보자

  • 클라이언트 -----> 서버 : ChatRequestVO
  • 서버 -----> 클라이언트 : ChatResponseVO

   - ChatRequestVO.java

//클라이언트가 보내는 메세지
@JsonIgnoreProperties(ignoreUnknown = true)
@Data @Builder @NoArgsConstructor @AllArgsConstructor
public class ChatRequestVO {
	private String content;//채팅내용
}

 

   - ChatResponseVO.java

//클라이언트에게 보내는 메세지
@JsonIgnoreProperties(ignoreUnknown = true)
@Data @Builder @NoArgsConstructor @AllArgsConstructor
public class ChatResponseVO {
	private String content;
	private String time;
}

 


 페이지 설정

    - PageController.java

@Controller
@RequestMapping("/page")
public class PageController {	
	@RequestMapping("/json")
	public String json() {
		return "json";
	}
}

 

   - json.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<!-- javascript toast library -->
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/toastify-js/src/toastify.min.css">
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/toastify-js"></script>
<!-- sockjs cdn -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.6.1/sockjs.min.js"></script>
<!-- moment.js cdn -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/locale/ko.min.js"></script>

<h1>그룹채팅(JSON) 예제</h1>

<input type="text" class="text-input" placeholder="메세지 작성">
<button class="btn-send">전송</button>

<hr>

<div class="chat-wrapper"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
	//시작하자마자 웹소켓 서버에 연결
	window.socket = new SockJS("${pageContext.request.contextPath}/ws/json");
	
	//연결 완료 시 해야할 작업들을 "콜백 함수"로 설정
	window.socket.onmessage = function(e){
		
		var obj = JSON.parse(e.data);//전송된 문자열을 객체로 변환
		//obj는 ChatResponseVO와 동일한 구조를 가진다. 
		
		//시간 제어 라이브러리인 moment를 사용하여 시간 형식을 변경
		//var time = moment(obj.time).fromNow();//현재시간 기준
		//var time = moment(obj.time).format("HH:mm");//형식 지정
		var time = moment(obj.time).format("a h:mm");//형식 지정
		var area = $("<div>").append(obj.content)
							 .append("<br>")
							 .append(time);
		$(".chat-wrapper").append(area);
	}
	
	//전송버튼을 누르면 입력한 메세지가 있는 경우 서버에 전송
	$(".btn-send").click(function(){
		var text = $(".text-input").val();//입력창의 입력값을 불러온다
		if(text.length == 0) return;//입력값이 없으면 중지한다
		
		//서버에서 이해할 수 있는 형태로 객체를 생성
		var data = {
			content: text
		};
		//byte아님 문자열만 전송 가능. 객체는 전송 불가
		var json = JSON.stringify(data);//data를 JSON 문자열로 변환
		
		window.socket.send(json);//서버로 입력값을 전송한다
		$(".text-input").val("");//입력창의 입력값을 삭제한다
	});
});
</script>

    (+) 서버에서 byte 또는 문자열만 전송이 가능하다. 객체는 전송 불가능 하므로 data를 전송하고자 한다면 JSON 문자열로 변환하여 전송해야 한다.

    (+) 해당 주소로 접속과 동시에 연결이 가능하도록 코드 구현


   - 출력 결과

    누가 작성했는지 모르지만, 외부에서 접속하여 작성할 수 있음

 

 

 

 

개인 공부 기록용입니다:)

728x90