"샘플앱 spring-talk"의 두 판 사이의 차이

잔글 (Jmnote님이 SpringTalk 문서를 Spring-talk 문서로 이동했습니다)
1번째 줄: 1번째 줄:
;SpringTalk
==개요==
;SpringTalk, spring-talk
;스프링-토크, 스프링톡
* [[SpringBoot]] 기반으로 작성한 채팅 웹애플리케이션 (샘플)
* 웹소켓 활용


==Message.java==
==Message.java==
59번째 줄: 63번째 줄:
     }
     }
}
}
</source>
==index.html==
<source lang='html'>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>SpringTalk</title>
<link rel="stylesheet" href="/webjars/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="main.css">
<script src="/webjars/jquery/jquery.min.js"></script>
<script src="/webjars/sockjs-client/sockjs.min.js"></script>
<script src="/webjars/stomp-websocket/stomp.min.js"></script>
<script src="/app.js"></script>
<script src='//cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/core-min.js'></script>
<script src='//cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/md5-min.js'></script>
<script src="//rawgit.com/stewartlord/identicon.js/master/pnglib.js"></script>
<script src="//rawgit.com/stewartlord/identicon.js/master/identicon.js"></script>
<script src='//cdn.rawgit.com/zenozeng/color-hash/master/dist/color-hash.js'></script>
</head>
<body>
<div class="container">
<div>
이름: <input id='username' type='text'>
</div>
</div>
<div id="main-content" class="container">
<div class="row">
<div id="conversation"></div>
</div>
<div class="row">
<form class="form-inline">
<div class="col-xs-9">
<input type="text" style='width: 100%' id="content"
class="form-control">
</div>
<div class="col-xs-3">
<button id="send" style='width: 100%' class="btn btn-default"
type="submit">보내기</button>
</div>
</form>
</div>
</div>
</body>
</html>
</source>
</source>


170번째 줄: 126번째 줄:
$( "#send" ).click(function() { send(); });
$( "#send" ).click(function() { send(); });
});
});
</source>
==main.css==
<source lang='css'>
#conversation {
display: block;
width: 100%;
height: 350px;
background: #9bbbd4;
vertical-align: top;
padding: 8px;
overflow-y: scroll;
float: left;
}
::-webkit-scrollbar {
width: 14px;
height: 18px;
}
::-webkit-scrollbar-thumb {
height: 6px;
border: 4px solid rgba(0, 0, 0, 0);
background-clip: padding-box;
background-color: rgba(0, 0, 0, 0.2);
-webkit-border-radius: 7px;
-webkit-box-shadow: inset -1px -1px 0px rgba(0, 0, 0, 0.05), inset 1px
1px 0px rgba(0, 0, 0, 0.05);
}
::-webkit-scrollbar-button {
width: 0;
height: 0;
display: none;
}
::-webkit-scrollbar-corner {
background-color: transparent;
}
.sender-show {
clear: both;
margin-top: 20px !important;
}
.sender-hidden .username {
display: none;
}
.sender-hidden .photobox {
display: none;
}
.message {
margin: 7px;
}
.photo {
object-fit: cover;
object-position: top;
border-radius: 50%;
}
.lavatar {
width: 48px;
height: 48px;
line-height: 48px;
font-size: 24px;
text-align: center;
color: #fff;
}
.message span {
padding: 4px;
margin: 2px;
border-radius: 3px;
}
.textbox {
margin: 0 70px;
}
.message-mine {
text-align: right;
}
.message-mine .photobox {
float: right;
}
.message-mine span {
background: #fef01b;
}
.message-others span {
background: #ffffff;
}
.message-others .photobox {
float: left;
}
</source>
</source>



2016년 10월 11일 (화) 17:47 판

1 개요

SpringTalk, spring-talk
스프링-토크, 스프링톡
  • SpringBoot 기반으로 작성한 채팅 웹애플리케이션 (샘플)
  • 웹소켓 활용

2 Message.java

package com.example.springtalk;

import lombok.Data;

@Data
public class Message {
	private String username;
    private String content;
}

3 MessageController.java

package com.example.springtalk;

import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;

@Controller
public class MessageController {

    @MessageMapping("/message")
    @SendTo("/topic/messages")
    public Message transfer(Message message) throws Exception {
        Thread.sleep(200);
        return message;
    }
}

4 WebScoketConfig.java

package com.example.springtalk;

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

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/app");
    }

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

5 app.js

var stompClient = null;
var username = null;
var last_sender = null;

function randomUsername() {
	var text = "";
	var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	for( var i=0; i < 5; i++ ) text += possible.charAt(Math.floor(Math.random() * possible.length));
	return text;
}

function connect() {
	var socket = new SockJS('/websocket-endpoint');
	stompClient = Stomp.over(socket);
	stompClient.connect({}, function (frame) {
		console.log('Connected: ' + frame);
		stompClient.subscribe('/topic/messages', function (message) {
			showMessage(JSON.parse(message.body));
		});
	});
}

function send() {
	if( $("#content").val() == '' ) return;
	stompClient.send("/app/message", {}, JSON.stringify({
		'username': $("#username").val(),
		'content': $("#content").val()
	}));
}

function showMessage(message) {
	var hash = CryptoJS.MD5(message.username).toString();
	var img_data = new Identicon(hash, 50).toString();
	var colorHash = new ColorHash({
	      lightness: 0.5,
	      saturation: 0.7
	    });
    var color = colorHash.hex(message.username);
    var initial = message.username.charAt(0);
	    
	var message_class = ( $("#username").val() == message.username )? 'message-mine' : 'message-others';
	var sender_class = ( last_sender == message.username )? 'sender-hidden' : 'sender-show';
	$("#conversation")
	.append("<div class='message "+message_class+" "+sender_class+"'>" +
			//"<div class='photobox'><img class='photo' src='data:image/png;base64," + img_data + "'></div>" +
			"<div class='photobox'><div class='photo lavatar' style='background:" + color + "'>" + initial + "</div></div>" +
			"<div class='textbox'>" +
			"<div class='username'>"+message.username+"</div>" +
			"<div><span>" + message.content + "</span></div></div></div>");
	$("#conversation")[0].scrollTop = $("#conversation")[0].scrollHeight;
	last_sender = message.username;
}

$(function () {
	$("form").on('submit', function (e) { e.preventDefault(); });
	connect();
	$( "#username" ).val( randomUsername() );
	$( "#send" ).click(function() { send(); });
});

6 같이 보기

7 참고 자료

문서 댓글 ({{ doc_comments.length }})
{{ comment.name }} {{ comment.created | snstime }}