0809 - 0815


# 0809 - 0815

# 0809 - Spring Web Socket

# WebSocket

  • ๋ ˆํผ๋Ÿฐ์Šค์— ๋”ฐ๋ฅด๋ฉด, websocket์€ ์›น ๋ธŒ๋ผ์šฐ์ €(ํด๋ผ์ด์–ธํŠธ)์™€ ์„œ๋ฒ„๊ฐ„์˜ full-duplex(์–‘๋ฐฉํ–ฅ), bi-directional(์ „์ด์ค‘์ ), persistent connection(์ง€์†์ ์ธ ์—ฐ๊ฒฐ)์˜ ํŠน์ง•์„ ๊ฐ–๋Š” ํ”„๋กœํ† ์ฝœ์ด๋ผ๊ณ  ๊ทœ์ •ํ•œ๋‹ค.

  • Websocket๊ณผ TCP์˜ ์ฐจ์ด

    1. ์›น์†Œ์ผ“์€ ์—ฐ๊ฒฐ ์š”์ฒญ์— ๋Œ€ํ•ด http๋ฅผ ํ†ตํ•ด switching ๋ฐ Handshaking์ด ์ด๋ฃจ์–ด์ง„๋‹ค.
    2. 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๋ฅผ ํ†ตํ•ด ๋ฉ”์„ธ์ง€๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค.

  1. Receive Client
    • ๋ฉ”์„ธ์ง€๋ฅผ ๋ฐ›๊ธฐ ์œ„ํ•ด ํŠน์ • ํ† ํ”ฝ์ด ์‚ฌ์ „์— ์„œ๋ฒ„์— subscribe ๋˜์–ด์•ผ ํ•œ๋‹ค.
  2. Send Client
    • ์„œ๋ฒ„์™€ ์—ฐ๊ฒฐ๋œ ํด๋ผ์ด์–ธํŠธ๋Š” ํŠน์ • path๋กœ ex) /app/message ์ „๋‹ฌํ•œ๋‹ค.
  3. 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

# ์“ฐ๋กœํ‹€๋ง

๋งˆ์ง€๋ง‰ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋œ ํ›„ ์ผ์ • ์‹œ๊ฐ„์ด ์ง€๋‚˜๊ธฐ ์ „์— ๋‹ค์‹œ ํ˜ธ์ถœ๋˜์ง€ ์•Š๋„๋ก ํ•˜๋Š” ๊ฒƒ

  • ๊ตฌํ˜„ ์˜ˆ์ œ
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);
Last update: September 2, 2021 22:00
Contributors: jaesungahn91