0809 - 0815
# 0809 - 0815
# 0809 - Spring Web Socket
# WebSocket
๋ ํผ๋ฐ์ค์ ๋ฐ๋ฅด๋ฉด, websocket์ ์น ๋ธ๋ผ์ฐ์ (ํด๋ผ์ด์ธํธ)์ ์๋ฒ๊ฐ์ full-duplex(์๋ฐฉํฅ), bi-directional(์ ์ด์ค์ ), persistent connection(์ง์์ ์ธ ์ฐ๊ฒฐ)์ ํน์ง์ ๊ฐ๋ ํ๋กํ ์ฝ์ด๋ผ๊ณ ๊ท์ ํ๋ค.
Websocket๊ณผ TCP์ ์ฐจ์ด
- ์น์์ผ์ ์ฐ๊ฒฐ ์์ฒญ์ ๋ํด http๋ฅผ ํตํด switching ๋ฐ Handshaking์ด ์ด๋ฃจ์ด์ง๋ค.
- TCP๋ Binary ๋ฐ์ดํฐ๋ง ์ฃผ๊ณ ๋ฐ์ ์ ์์ง๋ง, Websocket์ Binary ๋ฐ์ดํฐ ๋ฟ๋ง ์๋๋ผ Text ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ์ ์ ์๋ค.
=> Websocket์ HTTP์ TCP์ ํน์ฑ์ ์์ด ๋์ ํ๋กํ ์ฝ์ด๋ฉฐ, ์น ๋ธ๋ผ์ฐ์ ํ๊ฒฝ์์ ์ฐ๊ฒฐ์งํฅ ํต์ ์ ํ๊ธฐ ์ํ ๊ธฐ์ ์ด๋ค.
# Spring WebSocket
์คํ๋ง์์๋ 2๊ฐ์ง ๋ฐฉ์์ผ๋ก ์น์์ผ์ ๊ตฌํ ํ ์ ์๋ค.
- WebSocket ๋ฐ์ดํฐ๋ฅผ ์ง์ ์ฒ๋ฆฌ
- Stomp ํ๋กํ ์ฝ์ ์ฌ์ฉํ์ฌ ๋ฉ์ธ์ง ์ฒ๋ฆฌ
# 1) Websocket Data ์ง์ ์ฒ๋ฆฌ
Config๋ฅผ ํตํด Websocket ์ต์ ์ค์ ๊ฐ๋ฅ. ์น์์ผ ํธ๋ค๋ฌ๋ฅผ ์์๋ฐ์ ํด๋์ค๋ low level ์์ค์์ ์์์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ์ ์์ผ๋ฉฐ, ๋ค์๊ณผ ๊ฐ์ 4๊ฐ์ง ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌ ํ ์ ์๋ค.
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// WebSocket์ ์ฌ์ฉํ ์์๋ ๊ฒฝ์ฐ ๋์ฒด ์ ์ก์ ์ฌ์ฉํ ์ ์๋๋ก SockJS ํด๋ฐฑ ์ต์
์ ํ์ฑํํฉ๋๋ค.
// SockJS ํด๋ผ์ด์ธํธ๋ "/ws"์ ์ฐ๊ฒฐํ์ฌ ์ฌ์ฉ ๊ฐ๋ฅํ ์ต์์ ์ ์ก (websocket, xhr-streaming, xhr-polling ๋ฑ)์ ์๋.
registry.addHandler(new WsTranportHandler(), "/ws").setAllowedOrigins("*").withSockJS();
}
}
@Component
public class WsTranportHandler extends TextWebSocketHandler {
// connection์ด ๋งบ์ด์ง ํ ์คํ๋๋ค
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
System.err.println("session connected +=" + session);
}
// ๋ฉ์ธ์ง ์์
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
System.err.println("handle message +=" + session) + ", message=" + message);
//echo Message
session.sendMessage(message);
}
// transport ์ค error
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
System.err.println("transport error =" + session +", exception =" + exception);
}
// connection close
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
System.err.println("session close -=" + session);
}
}
=> ์ธ์ ๋ ๋ฒจ์์ ๋ฐ์ดํฐ๋ฅผ Handle
# 2) Stomp ํ๋กํ ์ฝ์ ์ฌ์ฉํ์ฌ ๋ฉ์ธ์ง ์ฒ๋ฆฌ
STOMP ํ๋กํ ์ฝ์ simple text oriented messaging protocol์ ์ฝ์์ด๋ฉฐ, ํ ์คํธ ๊ธฐ๋ฐ์ ํ๋กํ ์ฝ์ด๋ค.
Spring ๋ด๋ถ์ In Memory Broker๋ฅผ ํตํด ๋ฉ์ธ์ง๋ฅผ ์ฒ๋ฆฌํ๋ค.
- Receive Client
- ๋ฉ์ธ์ง๋ฅผ ๋ฐ๊ธฐ ์ํด ํน์ ํ ํฝ์ด ์ฌ์ ์ ์๋ฒ์ subscribe ๋์ด์ผ ํ๋ค.
- Send Client
- ์๋ฒ์ ์ฐ๊ฒฐ๋ ํด๋ผ์ด์ธํธ๋ ํน์ path๋ก ex) /app/message ์ ๋ฌํ๋ค.
- Broker
- ๋ฉ์ธ์ง ๋ธ๋ก์ปค๋ Kafka, RabbitMQ, ActiveMQ ๋ฑ์ ์คํ์์ค๋ค ์ฒ๋ผ MQ์ด๋ฉฐ, pub/sub ๋ชจ๋ธ์ ๋ฐ๋ฅธ๋ค. ํ ํฝ์ ๋ฐ๋ผ ๋ฉ์ธ์ง๋ฅผ ์ ๋ฌํด์ผ ํ๋ ์ฌ์ฉ์๋ฅผ ๊ตฌ๋ถํ๋ค.
- ์ฐ๊ฒฐ๋ ํด๋ผ์ด์ธํธ์ ์ธ์ ์ ๊ด๋ฆฌํ๋ค.
- ํน์ ํ ํฝ๊ณผ ๋ฉ์ธ์ง๋ฅผ Mpaaping ํ์ฌ, ํ ํฝ์ ๊ตฌ๋ ํ๋ ์ธ์ ์ ์กด์ฌํ๋ ํด๋ผ์ด์ธํธ์๊ฒ ๋ฉ์ธ์ง๋ฅผ ์ ๋ฌํ๋ค.
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketStompConfig implements WebSocketMessageBrokerConfigurer {
//messageBroker config
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
//in-memory message-broker, topic์ ๋ํ prefix ์ค์
config.enableSimpleBroker("/topic");
//๋ฉ์ธ์ง๋ฅผ ์์ ํ๋ handler์ ๋ฉ์ธ์ง prefix ์ค์
config.setApplicationDestinationPrefixes("/api");
};
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS();
}
}
@RestController
public class MessageHandleController {
@MessageMapping("/echo")
@SendTo("/topic/messages")
public EchoMessage echo(String message) throws Exception {
System.err.println(message);
return new EchoMessage(message,LocalDateTime.now());
}
}
@MessageMapping์ผ๋ก MessageHandle์ ํ๋ค. ์ค์ ์ setApplicationDestinationPrefix๋ฅผ /api๋ก ์ค์ ํ๊ธฐ ๋๋ฌธ์, ์ต์ข ์ ์ผ๋ก ๋ฉ์ธ์ง๋ฅผ ๋ณด๋ด๋ ค๊ณ ํ ๊ฒฝ์ฐ /api/echo ๋ก ๋ฉ์ธ์ง ๋ณด๋ธ๋ค๋ฉด, MessageHandler๋ ๋ฉ์ธ์ง๋ฅผ ์์ ํ๋ค.
@MeesageMapping์ ํตํด ๋ฉ์ธ์ง๋ฅผ ์์ ํ๋ค๋ฉด, @SendTo๋ฅผ ํตํด ํน์ ํ ํฝ์ ๊ตฌ๋ ํ๋ ํด๋ผ์ด์ธํธ์๊ฒ ๋ฉ์ธ์ง๋ฅผ ๋ณด๋ผ ์ ์๋ค.
# 0812 - ๋์์ธํจํด : ์์ฑ, ๊ตฌ์กฐ, ํ์ ํจํด
# ์์ฑ ํจํด
๊ฐ์ฒด์ ์์ฑ๊ณผ ์ฐธ์กฐ ๊ณผ์ ์ ์บก์ํํ์ฌ ๊ฐ์ฒด๊ฐ ์์ฑ๋๊ฑฐ๋ ๋ณ๊ฒฝ๋์ด๋ ํ๋ก๊ทธ๋จ ๊ตฌ์กฐ์ ์ํฅ์ ํฌ๊ฒ ๋ฐ์ง ์๋๋ก ํ์ฌ ํ๋ก๊ทธ๋จ์ ์ ์ฐ์ฑ์ ๋ํด์ฃผ๋ ํจํด
# ๊ตฌ์กฐ ํจํด
ํด๋์ค/๊ฐ์ฒด๋ค์ ์กฐํฉํ์ฌ ๋ ํฐ ๊ตฌ์กฐ๋ก ๋ง๋ค ์ ์๊ฒ ํด์ฃผ๋ ํจํด. ์๋ฅผ ๋ค์ด ์๋ก ๋ค๋ฅธ ์ธํฐํ์ด์ค๋ฅผ ์ง๋ 2๊ฐ์ ๊ฐ์ฒด๋ฅผ ๋ฌถ์ด ๋จ์ผ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ๊ฑฐ๋ ์๋ก ๋ค๋ฅธ ๊ฐ์ฒด๋ค์ ๋ฌถ์ด ์๋ก์ด ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ ํจํด.
# ํ์ ํจํด
๊ฐ์ฒด๋ ํด๋์ค ์ฌ์ด์ ์๊ณ ๋ฆฌ์ฆ์ด๋ ์ฑ ์ ๋ถ๋ฐฐ์ ๊ด๋ จ๋ ํจํด. ํ ๊ฐ์ฒด๊ฐ ํผ์ ์ํํ ์ ์๋ ์์ ์ ์ฌ๋ฌ๊ฐ์ ๊ฐ์ฒด๋ก ์ด๋ป๊ฒ ๋ถ๋ฐฐํ๋์ง, ๋ ๊ทธ๋ ๊ฒ ํ๋ฉด์๋ ๊ฐ์ฒด ์ฌ์ด์ ๊ฒฐํฉ๋๋ฅผ ์ต์ํ ํ๋ ๊ฒ์ ์ค์ ์ ๋๋ ๋ฐฉ์
# 0813 - ์ฐ๋กํ๋ง๊ณผ ๋๋ฐ์ด์ฑ
- ๋๋ฐ์ด์ฑ์ ์ฃผ๋ก ajax ๊ฒ์์ ์ฃผ๋ก ์ฌ์ฉ. ์ฐ๋กํ๋ง์ ์คํฌ๋กค์ ์ฌ๋ฆฌ๊ฑฐ๋ ๋ด๋ฆด ๋ ๋ณดํต ์ฌ์ฉ.
- underscore๋ lodash์์ ์ง์ ํ๋ ๊ธฐ๋ฅ(๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ์ ๋ฐ๋ก ๊ตฌํ X)
- underscore :
_.debounce
,_.throttle
- underscore :
# ์ฐ๋กํ๋ง
๋ง์ง๋ง ํจ์๊ฐ ํธ์ถ๋ ํ ์ผ์ ์๊ฐ์ด ์ง๋๊ธฐ ์ ์ ๋ค์ ํธ์ถ๋์ง ์๋๋ก ํ๋ ๊ฒ
- ๊ตฌํ ์์
var timer;
document.querySelector('#input').addEventListener('input', function (e) {
if (!timer) {
timer = setTimeout(function() {
timer = null;
console.log('์ฌ๊ธฐ์ ajax ์์ฒญ', e.target.value);
}, 200);
}
});
# ๋๋ฐ์ด์ฑ
์ฐ์ด์ด ํธ์ถ๋๋ ํจ์๋ค ์ค ๋ง์ง๋ง ํจ์(๋๋ ์ ์ผ ์ฒ์)๋ง ํธ์ถํ๋๋ก ํ๋ ๊ฒ
// html
<input id="input" />
// script
document.querySelector('#input').addEventListener('input', function(e) {
console.log('์ฌ๊ธฐ์ ajax ์์ฒญ', e.target.value);
});
- ์์ฒญ ๋ญ๋น => ์ด๋ฒคํธ ๋ฐ์ ๋ง๋ค ํ์ด๋จธ๋ฅผ ์ฑ์
var timer;
document.querySelector('#input').addEventListener('input', function(e) {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(function() {
console.log('์ฌ๊ธฐ์ ajax ์์ฒญ', e.target.value);
}, 200);
});
- ๋๋ฐ์ด์ฑ ๊ตฌํ
# 0814 - @ModelAttribute, @RequestParam, @RequestBody
# @ModelAttribute
- multipart/form-data ํํ์ HTTP Body ๋ด์ฉ๊ณผ HTTP ํ๋ผ๋ฏธํฐ๋ค์ Setter๋ฅผ ํตํด 1๋1๋ก ๊ฐ์ฒด ๋ฐ์ธ๋ฉ
- Json์ด๋ XML๊ณผ ๊ฐ์ ํํ์ ๋ฐ์ดํฐ๋ฅผ MessageConverter๋ฅผ ํตํด ๋ณํ ์ํค๋ @RequestBody์ ๋ฌ๋ฆฌ, multipart/form-data ํํ์ HTTP Body์ HTTP ํ๋ผ๋ฏธํฐ๋ค์ ๋งคํ์ํจ๋ค๋ ์ฐจ์ด
# @RequestParam
- 1๊ฐ์ HTTP์์ฒญ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ๊ธฐ ์ํด์ ์ฌ์ฉ
- ๊ธฐ๋ณธ์ ์ผ๋ก ๋ฐ๋์ ํด๋น ํ๋ผ๋ฏธํฐ๊ฐ ์ ์ก๋์ด์ผ ํ๋ค (๊ธฐ๋ณธ์ด true) SS
# RequestBody
- Json(application/json) ํํ์ HTTP Body ๋ด์ฉ์ Java Object๋ก ๋ณํ์์ผ์ฃผ๋ ์ญํ
- Body๊ฐ ์กด์ฌํ์ง ์๋ Get ๋ฉ์๋์์๋ ์ฌ์ฉ ๋ถ๊ฐ
- MessageConverter๋ค ์ค ํ๋์ธ MappingJackson2HttpMessageConverte๋ฅผ ํตํด Java ๊ฐ์ฒด๋ก ๋ณํ
# 0815 - jackson, gson
jackson๊ณผ gson ๋ชจ๋ Java์ ๋ํ JSON ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ์ ์ง์ํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค.
์ง๋ ฌํ, serializing, marchal : java ๊ฐ์ฒด -> json
์ญ์ง๋ ฌํ, deserializing, umarshal : json -> java ๊ฐ์ฒด
# jackson
Json ๋ฟ๋ง ์๋๋ผ XML๊ณผ YAML ๋ ์ง์ํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค. ์๋๊ฐ ๋น ๋ฅด๊ณ ์ ์ฐํ๋ฉฐ ๊ณ ์ฉ๋์ JSON ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์ฑ๋ฅ๋ ํ์.
- ์ง๋ ฌํ
ObjectMapper mapper = new ObjectMapper();
String jsonResult = mapper.writeValueAsString(json์ผ๋ก ๋ฐ๊พธ๊ณ ์ถ์ java๊ฐ์ฒด);
- ์ญ์ง๋ ฌํ
String jsonInput = "json ๋ฐ์ดํฐ";
ObjectMapper mapper = new ObjectMapper();
Example exam = mapper.readValue(jsonInput, Example.class);
# gson
๋น๊ต์ ๊ฐ๋ฒผ์ฐ๋ฉฐ ๋ฉ์ด๋ธ ์ ์ฅ์๋ ์ง์ํ๋ค.
- ์ง๋ ฌํ
String jsonResult = new Gson().toJson(json์ผ๋ก ๋ฐ๊พธ๊ณ ์ถ์ java๊ฐ์ฒด);
- ์ญ์ง๋ ฌํ
String jsonInput = "json ๋ฐ์ดํฐ";
Example exam = new Gson().fromJson(jsonInput, Example.class);