본문 바로가기
spring/게시판

스프링 웹 소켓 좋아요 알림(1)

by coie 2021. 4. 28.

좋아요 기능을 만들기 전에

알림 기능이 있으면 좋겠다!라고 생각했고

여기에 웹 소켓 기능을 추가하기로 했다.

아직은 기본적인 단계이다.

 

먼저 pom.xml에 웹 소켓을 추가해준다.

		<!-- socket -->
		<dependency>
    		<groupId>org.springframework</groupId>
    		<artifactId>spring-websocket</artifactId>
    		<version>${org.springframework-version}</version>
		</dependency>

 

그 후,

servlet-context.xml

	<!-- websocket -->
	
	<websocket:handlers>
		<websocket:mapping handler="myHandler" path="/alarm" />
		<websocket:sockjs websocket-enabled="true"/>
	</websocket:handlers>	
    
  <beans:bean id="myHandler" class="kr.co.korea.handler.WebSocketHandler" />

위와 같이 추가해준다.

mapping의 경우 handler를 설정하는데

경로를 /alarm로 해주고 이름을 myHandler라고 설정해줬다.

그리고 sockjs를 사용하므로 true로 설정해준다.(이렇게 안 하면 계속해서 오류가 난다.)

 

그다음 지정해준 bean의 클래스를 만들어준다.

public class WebSocketHandler extends TextWebSocketHandler{
	
	private static final Logger logger = LoggerFactory.getLogger(WebSocketHandler.class);
	//로그인 한 인원 전체
	private List<WebSocketSession> sessions = new ArrayList<WebSocketSession>();
	// 1:1로 할 경우
	private Map<String, WebSocketSession> userSessionsMap = new HashMap<String, WebSocketSession>();
	
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {//클라이언트와 서버가 연결
		// TODO Auto-generated method stub
		logger.info("Socket 연결");
		sessions.add(session);
		logger.info(currentUserName(session));//현재 접속한 사람
		userSessionsMap.put(currentUserName(session),session);
	}
	
	@Override
	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {// 메시지
		// TODO Auto-generated method stub
		String msg = message.getPayload();//자바스크립트에서 넘어온 Msg
		
		if(msg != null) {
			String[] msgs = msg.split(",");
			if(msgs != null && msgs.length ==3) {
				String bid = msgs[0];//게시물 번호
				String receiver = msgs[1];//글 작성자
				String count = msgs[2];//0이면 좋아요 취소 1이면 좋아요
				String btitle = msgs[3];//게시물 제목
				String comment = "";
				if(count.equals("0")) {
					comment = "의 좋아요를 취소했습니다.";
				}else if(count.equals("1")) {
					comment = "을 좋아합니다.";
				}
				String mid = currentUserName(session);//좋아요 누른 사람
				
				WebSocketSession receiversession = userSessionsMap.get(receiver);//글 작성자가 현재 접속중인가 체크
				
				if(receiversession !=null) {
					TextMessage txtmsg = new TextMessage(mid+"님이" + receiver + "님의" + btitle + comment);
					receiversession.sendMessage(txtmsg);//작성자에게 알려줍니다
				}else {
					TextMessage txtmsg = new TextMessage(mid+"님이" + receiver + "님의" + btitle + comment);
					session.sendMessage(txtmsg);//보내지는지 체크하기
				}
				
			}
			
		}
	}
	
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {//연결 해제
		// TODO Auto-generated method stub
		logger.info("Socket 끊음");
		sessions.remove(session);
		userSessionsMap.remove(currentUserName(session),session);
	}

	
	private String currentUserName(WebSocketSession session) {
		String mid = session.getPrincipal().getName();
		return mid;
	}

위와 같이 작성해준다.

list는 전체 알람, 혹은 전체 채팅을 원할 경우 작성(이에 대한 코드는 아직 작성 안 했다..)

그리고 map은 반드시 추가해줘야 한다.

왜냐하면 본인이 특정 누군가의 게시물의 좋아요를 눌렀는데 

해당 유저가 접속했는지 안 했는지를 Hashmap으로 알아내기 때문이다.

 

 

afterConnectionEstablished
(WebSocketSession session)
소켓과 연결 됬을 때 
handleTextMessage
(WebSocketSession session, TextMessage message)
메시지
 afterConnectionClosed
(WebSocketSession session, CloseStatus status)
소켓과 연결이 끊겼을 때
currentUserName
(WebSocketSession session)
현재 접속한 유저의 id(시큐리티를 이용해서 getPrincipal())

이 중에서도 handleTextMessag에 대해서 이야기하자면

@Override
	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {// 메시지
		// TODO Auto-generated method stub
		String msg = message.getPayload();//자바스크립트에서 넘어온 Msg
		
		if(msg != null) {
			String[] msgs = msg.split(",");
			if(msgs != null && msgs.length ==4) {
				String bid = msgs[0];//게시물 번호
				String receiver = msgs[1];//글 작성자
				String count = msgs[2];//0이면 좋아요 취소 1이면 좋아요
				String btitle = msgs[3];//게시물 제목
				String comment = "";
				if(count.equals("0")) {
					comment = "의 좋아요를 취소했습니다.";
				}else if(count.equals("1")) {
					comment = "을 좋아합니다.";
				}
				String mid = currentUserName(session);//좋아요 누른 사람
				
				WebSocketSession receiversession = userSessionsMap.get(receiver);//글 작성자가 현재 접속중인가 체크
				
				if(receiversession !=null) {
					TextMessage txtmsg = new TextMessage(mid+"님이" + receiver + "님의" + btitle + comment);
					receiversession.sendMessage(txtmsg);//작성자에게 알려줍니다
				}else {
					TextMessage txtmsg = new TextMessage(mid+"님이" + receiver + "님의" + btitle + comment);
					session.sendMessage(txtmsg);//보내지는지 체크하기
				}
				
			}
			
		}
	}

맨 아랫부분에 receiversession부분을 보면

본인의 session이 아니라 글 작성자의 session이기 때문에

현재 확인을 하지 못한다. 그래서 else로 null일 경우 

다시 자신에게 그 msg를 보내도록 설정 해 두었다.

 

그다음 view로 가서

 

<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>

CDN을 추가해준다.

 

그 다음 index.js를 만든 후

var sock = null;
 
   $(document).ready(function(){
		connectWs();
   });
  
	function connectWs(){
	
	sock = new SockJS(getContextPath()+'/alarm');
	
   	sock.onopen = function() {
     console.log('open');
     
	 };

 	sock.onmessage = function(e) {
   	  console.log('message', e.data);
 //  	  sock.close();
	 };

 	sock.onclose = function() {
 	    console.log('close');
	 };
 
  };

	function getContextPath() {
	    var hostIndex = location.href.indexOf( location.host ) + location.host.length;
	    return location.href.substring( hostIndex, location.href.indexOf('/', hostIndex + 1) );
	}; 

위와 같이 작성해준다.

최소한의 정보만 표시하고 있다.(아직 알람이 보이게 할 span을 만들지 않아서...)

그리고 이러한 소켓을 이용할 때는

sock.send()가 있어야 만한다.(onopen에서 handler로 )

sock.send는 좋아요를 눌렀을 때

실행이 돼야 하므로 좋아요 부분의 ajax로 가준다.

 

	function likeupdate(){
		var root = getContextPath(),
		likeurl = "/like/likeupdate",
		mid = $('#mid').val(),
		bid = $('#bid').val(),
		receiver = $('#bwriter').val(),
		btitle = $('#btitle').val(),
		count = $('#likecheck').val(),
		data = {"ltmid" : mid,
				"ltbid" : bid,
				"count" : count};
		
	$.ajax({
		url : root + likeurl,
		type : 'PUT',
		contentType: 'application/json',
		data : JSON.stringify(data),
		success : function(result){
			console.log("수정" + result.like);
			if(count == 1){
				console.log("좋아요 취소");
				 $('#likecheck').val(0);
				 $('#likebtn').attr('class','btn btn-light');
				 $('#likecount').html(result.like);
				 if(sock){
				 var Msg = bid+","+receiver+","+count+","+btitle;
				 console.log(Msg);
				 sock.send(Msg);
				 }
			}else if(count == 0){
				console.log("좋아요!");
				$('#likecheck').val(1);
				$('#likebtn').attr('class','btn btn-danger');
				$('#likecount').html(result.like);
				if(sock){
				 var Msg = bid+","+receiver+","+count+","+btitle;
				 console.log(Msg);
				 sock.send(Msg);
				 }
			}
		}, error : function(result){
			console.log("에러" + result.result)
		}
		
		});
	};

이와 같이 기존에 어느 시점을 정해서 

그 시점에 if(sock)를 해준 후 sock.send를 해주면 된다.

 

이렇게 해주면.

좋아요를 누른 경우

좋아요를 취소한 경우

 

 

와 같이 작동되고 있는 것을 알 수 있습니다.

 

이다음에는 

DB를 만들어서 

console.log가 아니라 표시되게 만들어 보겠습니다.

'spring > 게시판' 카테고리의 다른 글

스프링 게시판 만들기 좋아요(2)  (0) 2021.04.24
스프링 게시판 좋아요 버튼  (0) 2021.04.24
스프링 Rest CRUD 구현  (0) 2021.04.07
스프링 시큐리티 예제  (0) 2021.04.07
스프링 이미지 업로드  (0) 2021.03.11