πŸ’»
Albert's Til
GitHub
  • 맀일맀일 μ‘°κΈˆμ”© μ„±μž₯ν•˜κΈ°
    • README
    • CS
      • Network
      • HTTP
        • NO-CACHE
      • 였λ₯˜ μ½”λ“œ
      • ORM 도ꡬ
      • Design Pattern
        • CQRS Pattern
          • Event Sourcing and CQRS pattern
        • Builder Pattern
    • DB
      • MySQL
        • Timeline
        • Pagination
        • Index
        • Database Performance Optimization Strategies
        • B+ tree
        • MySQL Connectors VS MySQL Shell(Scripting) VS MySQL Workbench
        • MySQL Storage Engine Architecture
      • Normalization & Denormalization
      • JPA
        • @Transactional
        • Why JPA?
        • About JPA
        • N+1 Issue
        • Index
        • ElementCollection&CollectionTable
        • orphanRemoval
        • CascadeType
        • Use Subselect
        • Dynamic Instance Creation
        • Paging
        • Order
        • Spefication
        • mappedBy
      • MongoDB
        • ObjectId
      • Why MySQL?
      • ACID properties of transactions
      • Between JPA and JDBC
      • Identifiers in Hibernate/JPA
    • Java
      • Jackson de/serialize
      • Collections.singletonList() vs List.of()
      • Manage dependencies in Gradle
      • Logging Level
      • Bean Validation
      • JVM Internals
        • Threads
          • Frame
        • Shared Between Threads
          • Classloader
            • Class Loader Hierarchy
            • Loading Linking Initialization
      • Java Collection Framework
      • Annotation
      • Generic
      • λ””λ―Έν„° 법칙
    • Spring
      • Caching
      • Spring Integration Overview
        • ThreadPollTaskExecutor
        • Messaging Bridge
        • Channel Adapter
        • Poller
        • Configuration and @EnableIntegration
        • Message Endpoints
        • Message Channels
      • HATEOAS
      • @Autowired vs Constructor Dependency Injection
      • Spring Security
        • JWT 토큰 μ‚¬μš©ν•œ 인가
        • OAuth 2 Login
        • OAuth 2 인증
        • 인가
        • 인증
        • PasswordEncoder
      • IoC Container
      • Filter,Interceptor,AOP,Argument Resolver
      • Spring Annotation
      • About Spring
    • Kafka
      • Error Channel
    • Infra
      • Scale Up || Scale Out
      • Docker
        • Dockerfile
        • Docker Hub Deploy
        • Command
      • Cloud μœ ν˜•
        • Infrastructure as a Service
        • Platform as a Service
        • Software as a Service
      • 무쀑단 배포
        • μ—”μ§„μ—‘μŠ€(Nginx)
      • μ½”λ“œ μžλ™ 배포
        • Technical
      • AWS EC2
        • PEM(Privacy Enhanced Mail) ν‚€
      • AWS RDS
      • AWS S3
    • CodeSquad
      • Spring Boot Project 1μ£Όμ°¨ 회고
      • Spring Boot Project 2μ£Όμ°¨ 회고
      • Spirng Boot Project 3μ£Όμ°¨ 회고
      • Spring Boot Project 4μ£Όμ°¨ 회고
    • Foody Moody ν”„λ‘œμ νŠΈ
      • Query Performance Comparison
      • HeartCount Asynchronous Issue
      • DeferredResult
      • ResponseBodyEmitter
      • SseEmitter (Spring)
      • Server-Sent Events (SSE)
      • 기술 μŠ€νƒ 적용 이유
      • NO-CACHE(HTTP)
      • Transactional
    • DDD
      • AggregateId
    • Test
      • RestAssured
    • Coding and Algorithmic Problems
      • 819. Most Common Word
      • 344. Reverse String
      • 125. Valid Palindrome
      • 937. Reorder Data in Log Files
    • Node
      • Async... Await...
      • Custom Transactional Decorator Challenger
    • Python
      • Python Basic Grammar
        • Comments and Input/Output
        • Variable
        • Data type
        • Operations and syntax
        • List,Tuple,Dictionary,Set
        • Function
        • Conditional statement
        • Loop
    • HTML
      • HTML Basic
      • HTML Basic Tags
      • HTML Form Tags
      • HTML Table Tags
    • CSS
      • CSS Basic
      • CSS Practice
Powered by GitBook
On this page
  • μ½”λ“œ μš”μ•½
  • 응닡 ν™•μž₯:
  • 이벀트 λ°œμ†‘:
  • 이벀트 λΉŒλ”©:
  • SseEventBuilder:
  • SseEventBuilderImpl:
  • DataWithMediaType:
  • μ˜ˆμ‹œ

Was this helpful?

  1. 맀일맀일 μ‘°κΈˆμ”© μ„±μž₯ν•˜κΈ°
  2. Foody Moody ν”„λ‘œμ νŠΈ

SseEmitter (Spring)

Spring Frameworkμ—μ„œ SseEmitterλŠ” μ„œλ²„μ—μ„œ ν΄λΌμ΄μ–ΈνŠΈλ‘œ Server-Sent Events(SSE)λ₯Ό 보내기 μœ„ν•œ κ°μ²΄μž…λ‹ˆλ‹€. μ„œλ²„μ—μ„œ ν΄λΌμ΄μ–ΈνŠΈλ‘œ μ‹€μ‹œκ°„ μ—…λ°μ΄νŠΈλ₯Ό μ „μ†‘ν•˜λŠ” 데 μ‚¬μš©λ˜λŠ” μ„œλ²„ 전솑 이벀트(Server-Sent Events, SSE)λ₯Ό 보내기 μœ„ν•œ ResponseBodyEmitter의 특수 버전이닀.

μ½”λ“œ μš”μ•½

응닡 ν™•μž₯:

  • extendResponse(ServerHttpResponse outputMessage): ResponseBodyEmitterμ—μ„œ μ˜€λ²„λΌμ΄λ“œν•œ λ©”μ„œλ“œλ‘œ SSE에 맞게 μ„œλ²„ 응닡을 μ»€μŠ€ν„°λ§ˆμ΄μ¦ˆν•©λ‹ˆλ‹€. Content-Type을 text/event-stream으둜 μ„€μ •ν•©λ‹ˆλ‹€(λ§Œμ•½ 아직 μ„€μ •λ˜μ§€ μ•Šμ•˜λ‹€λ©΄).

이벀트 λ°œμ†‘:

  • send(Object object): 객체λ₯Ό 단일 SSE "data" 라인으둜 μ „μ†‘ν•©λ‹ˆλ‹€.

  • send(Object object, @Nullable MediaType mediaType): μ§€μ •λœ MediaType을 κ°€μ§„ 객체λ₯Ό μ „μ†‘ν•˜μ—¬ λ©”μ‹œμ§€ 컨버터 선택 μ‹œ 컨텐츠 ν˜‘μƒμ„ κ°€λŠ₯ν•˜κ²Œ ν•©λ‹ˆλ‹€.

  • send(SseEventBuilder builder): id, 이벀트 이름, μ½”λ©˜νŠΈ 및/λ˜λŠ” μž¬μ—°κ²° μ‹œκ°„κ³Ό 데이터λ₯Ό ν¬ν•¨ν•˜λŠ” λ³΅μž‘ν•œ SSE 이벀트λ₯Ό 전솑할 수 μžˆμŠ΅λ‹ˆλ‹€.

이벀트 λΉŒλ”©:

  • event(): SseEventBuilderImpl μΈμŠ€ν„΄μŠ€λ₯Ό λ°˜ν™˜ν•˜λŠ” 정적 λ©”μ„œλ“œμž…λ‹ˆλ‹€. SseEventBuilderImpl은 λ‚΄λΆ€ 클래슀둜 SseEventBuilder μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•©λ‹ˆλ‹€.

SseEventBuilder:

  • SseEmitter 클래슀 λ‚΄λΆ€μ˜ μΈν„°νŽ˜μ΄μŠ€λ‘œ, SSE 이벀트λ₯Ό κ΅¬μΆ•ν•˜κΈ° μœ„ν•œ λ©”μ„œλ“œλ₯Ό μ •μ˜ν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄ id, name, reconnectTime, comment, data λ“±μ˜ λ©”μ„œλ“œκ°€ μžˆμŠ΅λ‹ˆλ‹€.

SseEventBuilderImpl:

  • SseEventBuilder μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λŠ” λ‚΄λΆ€ private static ν΄λž˜μŠ€μž…λ‹ˆλ‹€. SSE ν˜•μ‹μ˜ λ¬Έμžμ—΄μ„ κ΅¬μ„±ν•˜κΈ° μœ„ν•΄ StringBuilderλ₯Ό μ‚¬μš©ν•˜κ³  전솑할 데이터λ₯Ό λ‹΄λŠ” Set<DataWithMediaType>λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

DataWithMediaType:

  • 전솑될 객체와 κ·Έ MediaType을 μ—°κ΄€μ‹œν‚€λŠ” κ°„λ‹¨ν•œ μ»¨ν…Œμ΄λ„ˆ 클래슀둜 λ³΄μž…λ‹ˆλ‹€. λ‚΄λΆ€μ μœΌλ‘œ SseEventBuilderImpl에 μ˜ν•΄ μ‚¬μš©λ©λ‹ˆλ‹€.

send(SseEventBuilder builder) λ©”μ„œλ“œμ—μ„œ synchronizedλ₯Ό μ‚¬μš©ν•˜λŠ” 것은 데이터가 μŠ€λ ˆλ“œ μ•ˆμ „ν•œ λ°©μ‹μœΌλ‘œ μ „μ†‘λ˜λ„λ‘ 보μž₯ν•©λ‹ˆλ‹€. μ„œλ²„ 전솑 μ΄λ²€νŠΈλŠ” 일반적으둜 μ„œλ²„κ°€ μ‹€μ‹œκ°„μœΌλ‘œ μ—…λ°μ΄νŠΈλ₯Ό ν΄λΌμ΄μ–ΈνŠΈ λΈŒλΌμš°μ €λ‘œ ν‘Έμ‹œν•΄μ•Ό ν•˜λŠ” μ• ν”Œλ¦¬μΌ€μ΄μ…˜, 예λ₯Ό λ“€μ–΄ λŒ€μ‹œλ³΄λ“œ λ˜λŠ” μ‹€μ‹œκ°„μœΌλ‘œ μ—…λ°μ΄νŠΈλ˜λŠ” ν”Όλ“œμ—μ„œ μ‚¬μš©λ©λ‹ˆλ‹€.

μ˜ˆμ‹œ

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

@Controller
@RequestMapping("/sse")
public class SseController {

    @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter streamSseMvc() {
        SseEmitter emitter = new SseEmitter();
        // μƒˆλ‘œμš΄ μŠ€λ ˆλ“œμ—μ„œ λΉ„λ™κΈ°λ‘œ 처리
        Executors.newSingleThreadExecutor().execute(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    // 데이터λ₯Ό μ „μ†‘ν•˜κΈ° 전에 μ„œλ²„μ—μ„œ 데이터λ₯Ό μƒμ„±ν•˜κ±°λ‚˜ κ²€μƒ‰ν•©λ‹ˆλ‹€.
                    Thread.sleep(1000);
                    emitter.send("/sse/stream - " + LocalTime.now().toString());
                }
                emitter.complete();
            } catch (IOException | InterruptedException e) {
                emitter.completeWithError(e);
            }
        });
        return emitter;
    }
}

Last updated 1 year ago

Was this helpful?