<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>이게 왜 되지?</title>
    <link>https://idea5595.tistory.com/</link>
    <description>왜 실행이 되는지(안되는지) 궁금할 때마다 와서 복습하는 곳</description>
    <language>ko</language>
    <pubDate>Fri, 24 Jul 2026 07:58:49 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>404NotFoundMe</managingEditor>
    <image>
      <title>이게 왜 되지?</title>
      <url>https://tistory1.daumcdn.net/tistory/7677748/attach/0f3253b598c04032b51b5cb0d3d3b242</url>
      <link>https://idea5595.tistory.com</link>
    </image>
    <item>
      <title>ExecutorService와 BlockingQueue</title>
      <link>https://idea5595.tistory.com/27</link>
      <description>&lt;p data-end=&quot;213&quot; data-start=&quot;186&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;213&quot; data-start=&quot;186&quot; data-ke-size=&quot;size18&quot;&gt;ExecutorService와 BlockingQueue는 Java에서 &lt;b&gt;동시성(Concurrency)&lt;/b&gt; 문제를 해결하고, &lt;b&gt;비동기 작업 처리&lt;/b&gt;를 효율적으로 하기 위해 자주 함께 사용되는 핵심 구성 요소입니다. 이 둘을 조합하면 &lt;b&gt;멀티스레드 환경에서 작업을 안전하고 효율적으로 분산 처리&lt;/b&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;213&quot; data-start=&quot;186&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;213&quot; data-start=&quot;186&quot; data-ke-size=&quot;size26&quot;&gt;✅ 1. ExecutorService란?&lt;/h2&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;215&quot; data-ke-size=&quot;size16&quot;&gt;ExecutorService는 Java의 &lt;b&gt;스레드 풀(Thread Pool)&lt;/b&gt; 기반 작업 실행기입니다. Thread를 직접 생성하고 관리하는 대신, ExecutorService가 스레드를 재사용하면서 효율적으로 작업을 실행합니다.&lt;/p&gt;
&lt;h3 data-end=&quot;365&quot; data-start=&quot;353&quot; data-ke-size=&quot;size23&quot;&gt;  주요 특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;589&quot; data-start=&quot;366&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;432&quot; data-start=&quot;366&quot;&gt;&lt;b&gt;작업 제출(Submit)&lt;/b&gt;: Runnable 또는 Callable을 넘기면 백그라운드에서 비동기로 실행&lt;/li&gt;
&lt;li data-end=&quot;472&quot; data-start=&quot;433&quot;&gt;&lt;b&gt;스레드 재사용&lt;/b&gt;: 매번 새 스레드를 만들지 않고 풀에서 재사용&lt;/li&gt;
&lt;li data-end=&quot;514&quot; data-start=&quot;473&quot;&gt;&lt;b&gt;스레드 수 제한&lt;/b&gt;: 동시 처리 개수 제한 가능 (예: 고정 5개)&lt;/li&gt;
&lt;li data-end=&quot;589&quot; data-start=&quot;515&quot;&gt;&lt;b&gt;종료 제어&lt;/b&gt;: .shutdown(), .awaitTermination() 등으로 graceful shutdown 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;756&quot; data-start=&quot;731&quot; data-ke-size=&quot;size26&quot;&gt;✅ 2. BlockingQueue란?&lt;/h2&gt;
&lt;p data-end=&quot;863&quot; data-start=&quot;758&quot; data-ke-size=&quot;size16&quot;&gt;BlockingQueue는 &lt;b&gt;스레드 간 안전한 큐&lt;/b&gt;입니다. 생산자-소비자 패턴에서 주로 사용되며, &lt;b&gt;큐가 비어 있으면 소비자는 대기하고&lt;/b&gt;, &lt;b&gt;가득 차면 생산자는 대기&lt;/b&gt;합니다.&lt;/p&gt;
&lt;h3 data-end=&quot;877&quot; data-start=&quot;865&quot; data-ke-size=&quot;size23&quot;&gt;  주요 특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1002&quot; data-start=&quot;878&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;915&quot; data-start=&quot;878&quot;&gt;&lt;b&gt;동기화 자동 처리&lt;/b&gt;: 여러 스레드에서 동시에 접근해도 안전&lt;/li&gt;
&lt;li data-end=&quot;951&quot; data-start=&quot;916&quot;&gt;&lt;b&gt;take()&lt;/b&gt;: 큐에 항목이 없으면 블로킹됨 (기다림)&lt;/li&gt;
&lt;li data-end=&quot;981&quot; data-start=&quot;952&quot;&gt;&lt;b&gt;put()&lt;/b&gt;: 큐가 가득 차 있으면 블로킹됨&lt;/li&gt;
&lt;li data-end=&quot;1002&quot; data-start=&quot;982&quot;&gt;&lt;b&gt;비동기 메시지 전달에 적합&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1182&quot; data-start=&quot;1152&quot; data-ke-size=&quot;size26&quot;&gt;✅ 3. 함께 사용하는 구조: 생산자-소비자 패턴&lt;/h2&gt;
&lt;blockquote data-end=&quot;1238&quot; data-start=&quot;1184&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1238&quot; data-start=&quot;1186&quot; data-ke-size=&quot;size16&quot;&gt;  메시지를 &lt;b&gt;생산자 스레드가 큐에 넣고&lt;/b&gt;, &lt;b&gt;소비자 스레드가 꺼내서 처리&lt;/b&gt;하는 구조&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  구조 설명&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;[WebSocket 수신 스레드] &amp;rarr; BlockingQueue &amp;rarr; [ExecutorService가 처리]&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  코드 예시&lt;/p&gt;
&lt;pre id=&quot;code_1752027461903&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;BlockingQueue&amp;lt;String&amp;gt; messageQueue = new LinkedBlockingQueue&amp;lt;&amp;gt;();
ExecutorService consumerPool = Executors.newFixedThreadPool(5);

// 소비자: 메시지 처리
for (int i = 0; i &amp;lt; 5; i++) {
    consumerPool.submit(() -&amp;gt; {
        while (true) {
            try {
                String msg = messageQueue.take(); // 메시지가 올 때까지 대기
                handleMessage(msg); // 메시지 처리 로직
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

// 생산자: 메시지 수신
public void onMessage(String msg) {
    try {
        messageQueue.put(msg); // 큐에 넣기 (가득 차 있으면 대기)
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장점&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;설명&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;✔ 스레드 재사용&lt;/td&gt;
&lt;td&gt;성능 효율 향상, 오버헤드 감소&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✔ 작업 분리&lt;/td&gt;
&lt;td&gt;수신/처리를 역할별로 나눠 안정적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✔ 큐 기반 흐름 제어&lt;/td&gt;
&lt;td&gt;메시지 폭주 시 자연스럽게 처리 속도 조절&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✔ 예외 관리 용이&lt;/td&gt;
&lt;td&gt;작업 단위로 try-catch 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;2241&quot; data-start=&quot;2220&quot; data-ke-size=&quot;size26&quot;&gt;✅ 5. 실서비스에서의 활용 예시&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2332&quot; data-start=&quot;2242&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2261&quot; data-start=&quot;2242&quot;&gt;실시간 주식 시세 수신 후 처리&lt;/li&gt;
&lt;li data-end=&quot;2294&quot; data-start=&quot;2262&quot;&gt;WebSocket 수신 메시지를 멀티스레드로 병렬 처리&lt;/li&gt;
&lt;li data-end=&quot;2319&quot; data-start=&quot;2295&quot;&gt;RabbitMQ, Kafka 메시지 소비&lt;/li&gt;
&lt;li data-end=&quot;2332&quot; data-start=&quot;2320&quot;&gt;백그라운드 작업 큐&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>404NotFoundMe</author>
      <guid isPermaLink="true">https://idea5595.tistory.com/27</guid>
      <comments>https://idea5595.tistory.com/27#entry27comment</comments>
      <pubDate>Wed, 9 Jul 2025 11:19:17 +0900</pubDate>
    </item>
    <item>
      <title>웹소켓</title>
      <link>https://idea5595.tistory.com/26</link>
      <description>&lt;h2 data-end=&quot;78&quot; data-start=&quot;64&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;1. 웹소켓이란?&lt;/h2&gt;
&lt;p data-end=&quot;185&quot; data-start=&quot;80&quot; data-ke-size=&quot;size16&quot;&gt;웹소켓(WebSocket)은 &lt;b&gt;클라이언트와 서버가 지속적으로 연결을 유지&lt;/b&gt;하면서 양방향 통신(Full-Duplex)을 할 수 있도록 해주는 &lt;b&gt;네트워크 프로토콜&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-end=&quot;239&quot; data-start=&quot;187&quot; data-ke-size=&quot;size16&quot;&gt;기존 HTTP 통신과는 달리 &quot;요청-응답&quot;이 아니라 &quot;지속 연결&quot;을 기반으로 동작해요.&lt;/p&gt;
&lt;hr data-end=&quot;244&quot; data-start=&quot;241&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;266&quot; data-start=&quot;246&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;2. 기존 HTTP와의 차이&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;항목&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;HTTP&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;WebSocket
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;518&quot; data-start=&quot;268&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;518&quot; data-start=&quot;322&quot;&gt;
&lt;tr data-end=&quot;376&quot; data-start=&quot;322&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;330&quot; data-start=&quot;322&quot;&gt;연결 방식&lt;/td&gt;
&lt;td data-end=&quot;352&quot; data-start=&quot;330&quot; data-col-size=&quot;sm&quot;&gt;요청-응답 후 끊김 (비연결 지향)&lt;/td&gt;
&lt;td data-end=&quot;376&quot; data-start=&quot;352&quot; data-col-size=&quot;sm&quot;&gt;연결을 맺고 계속 유지 (연결 지향)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;424&quot; data-start=&quot;377&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;385&quot; data-start=&quot;377&quot;&gt;통신 방향&lt;/td&gt;
&lt;td data-end=&quot;404&quot; data-start=&quot;385&quot; data-col-size=&quot;sm&quot;&gt;단방향 (클라이언트 &amp;rarr; 서버)&lt;/td&gt;
&lt;td data-end=&quot;424&quot; data-start=&quot;404&quot; data-col-size=&quot;sm&quot;&gt;양방향 (서버 &amp;harr; 클라이언트)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;477&quot; data-start=&quot;425&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;433&quot; data-start=&quot;425&quot;&gt;사용 목적&lt;/td&gt;
&lt;td data-end=&quot;449&quot; data-start=&quot;433&quot; data-col-size=&quot;sm&quot;&gt;문서 전송, API 통신&lt;/td&gt;
&lt;td data-end=&quot;477&quot; data-start=&quot;449&quot; data-col-size=&quot;sm&quot;&gt;실시간 데이터 통신 (채팅, 주식 시세 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;518&quot; data-start=&quot;478&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;485&quot; data-start=&quot;478&quot;&gt;오버헤드&lt;/td&gt;
&lt;td data-end=&quot;500&quot; data-start=&quot;485&quot; data-col-size=&quot;sm&quot;&gt;매 요청마다 헤더 포함&lt;/td&gt;
&lt;td data-end=&quot;518&quot; data-start=&quot;500&quot; data-col-size=&quot;sm&quot;&gt;연결 이후엔 오버헤드 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;523&quot; data-start=&quot;520&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;543&quot; data-start=&quot;525&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;3. 웹소켓의 동작 방식&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;824&quot; data-start=&quot;545&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;634&quot; data-start=&quot;545&quot;&gt;&lt;b&gt;HTTP 연결 요청&lt;/b&gt;&lt;br /&gt;클라이언트가 일반적인 HTTP 요청을 보내되, Upgrade: websocket 헤더를 포함시킴 &amp;rarr; 업그레이드 요청&lt;/li&gt;
&lt;li data-end=&quot;711&quot; data-start=&quot;636&quot;&gt;&lt;b&gt;프로토콜 업그레이드&lt;/b&gt;&lt;br /&gt;서버가 WebSocket 요청을 수락하면, 프로토콜이 HTTP &amp;rarr; WebSocket으로 전환됨&lt;/li&gt;
&lt;li data-end=&quot;776&quot; data-start=&quot;713&quot;&gt;&lt;b&gt;지속적인 통신&lt;/b&gt;&lt;br /&gt;연결이 유지되며 서버와 클라이언트가 서로 실시간으로 메시지를 주고받을 수 있음&lt;/li&gt;
&lt;li data-end=&quot;824&quot; data-start=&quot;778&quot;&gt;&lt;b&gt;연결 종료&lt;/b&gt;&lt;br /&gt;명시적으로 연결을 닫기 전까지는 계속 연결이 유지됨&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-end=&quot;829&quot; data-start=&quot;826&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;846&quot; data-start=&quot;831&quot; data-ke-size=&quot;size26&quot;&gt;4. 웹소켓의 장점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;939&quot; data-start=&quot;848&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;869&quot; data-start=&quot;848&quot;&gt;실시간 데이터 전송 (지연 최소화)&lt;/li&gt;
&lt;li data-end=&quot;888&quot; data-start=&quot;870&quot;&gt;서버 &amp;rarr; 클라이언트 푸시 가능&lt;/li&gt;
&lt;li data-end=&quot;924&quot; data-start=&quot;889&quot;&gt;REST 방식 대비 네트워크 트래픽 감소 (헤더 반복 없음)&lt;/li&gt;
&lt;li data-end=&quot;939&quot; data-start=&quot;925&quot;&gt;연결 유지로 성능 향상&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;944&quot; data-start=&quot;941&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;961&quot; data-start=&quot;946&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;5. 웹소켓의 단점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1047&quot; data-start=&quot;963&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;987&quot; data-start=&quot;963&quot;&gt;연결 상태 관리가 필요 (끊김 감지 등)&lt;/li&gt;
&lt;li data-end=&quot;1016&quot; data-start=&quot;988&quot;&gt;일반적인 HTTP 서버와 다르게 별도 설정 필요&lt;/li&gt;
&lt;li data-end=&quot;1047&quot; data-start=&quot;1017&quot;&gt;브라우저/네트워크 환경에 따라 방화벽 등 제약 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1052&quot; data-start=&quot;1049&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1070&quot; data-start=&quot;1054&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;6. 언제 사용하나?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1128&quot; data-start=&quot;1072&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1080&quot; data-start=&quot;1072&quot;&gt;실시간 채팅&lt;/li&gt;
&lt;li data-end=&quot;1095&quot; data-start=&quot;1081&quot;&gt;실시간 주식/코인 시세&lt;/li&gt;
&lt;li data-end=&quot;1111&quot; data-start=&quot;1096&quot;&gt;실시간 알림/푸시 시스템&lt;/li&gt;
&lt;li data-end=&quot;1128&quot; data-start=&quot;1112&quot;&gt;온라인 게임, 협업 앱 등&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2113&quot; data-start=&quot;2106&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;요약&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2208&quot; data-start=&quot;2115&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2147&quot; data-start=&quot;2115&quot;&gt;WebSocket은 실시간 양방향 통신을 위한 프로토콜&lt;/li&gt;
&lt;li data-end=&quot;2176&quot; data-start=&quot;2148&quot;&gt;연결을 유지하면서 지속적인 데이터 주고받기 가능&lt;/li&gt;
&lt;li data-end=&quot;2208&quot; data-start=&quot;2177&quot;&gt;실시간 서비스 구현에 적합 (채팅, 시세, 게임 등)&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>404NotFoundMe</author>
      <guid isPermaLink="true">https://idea5595.tistory.com/26</guid>
      <comments>https://idea5595.tistory.com/26#entry26comment</comments>
      <pubDate>Fri, 20 Jun 2025 10:43:45 +0900</pubDate>
    </item>
    <item>
      <title>RestTemplate란?</title>
      <link>https://idea5595.tistory.com/25</link>
      <description>&lt;h2 data-end=&quot;97&quot; data-start=&quot;78&quot; data-ke-size=&quot;size26&quot;&gt;✅ RestTemplate란?&lt;/h2&gt;
&lt;p data-end=&quot;193&quot; data-start=&quot;99&quot; data-ke-size=&quot;size16&quot;&gt;**RestTemplate은 자바(Spring)**에서&lt;br /&gt;&lt;b&gt;다른 서버의 API를 호출&lt;/b&gt;해서 데이터를 주고받을 수 있게 해주는 &lt;b&gt;HTTP 클라이언트 도구&lt;/b&gt;입니다.&lt;/p&gt;
&lt;hr data-end=&quot;198&quot; data-start=&quot;195&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;213&quot; data-start=&quot;200&quot; data-ke-size=&quot;size26&quot;&gt;  쉽게 말하면?&lt;/h2&gt;
&lt;blockquote data-end=&quot;259&quot; data-start=&quot;215&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;259&quot; data-start=&quot;217&quot; data-ke-size=&quot;size16&quot;&gt;  &quot;RestTemplate은 자바에서 HTTP 요청을 보내는 전화기다.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;386&quot; data-start=&quot;261&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;284&quot; data-start=&quot;261&quot;&gt;  전화번호 = 요청할 &lt;b&gt;URL&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;314&quot; data-start=&quot;285&quot;&gt; ️ 내가 말할 내용 = &lt;b&gt;요청 헤더/본문&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;352&quot; data-start=&quot;315&quot;&gt;  전화를 건다 = &lt;b&gt;API 호출 (GET/POST 등)&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;386&quot; data-start=&quot;353&quot;&gt;  상대방의 대답 = &lt;b&gt;응답 데이터(JSON 등)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;391&quot; data-start=&quot;388&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;418&quot; data-start=&quot;393&quot; data-ke-size=&quot;size26&quot;&gt;✅ RestTemplate이 필요한 이유&lt;/h2&gt;
&lt;h3 data-end=&quot;454&quot; data-start=&quot;420&quot; data-ke-size=&quot;size23&quot;&gt;예: 다른 서버에서 주식 가격 조회 API를 제공할 때&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;526&quot; data-start=&quot;456&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;487&quot; data-start=&quot;456&quot;&gt;자바 애플리케이션에서 한국투자증권 API에 요청하려면&lt;/li&gt;
&lt;li data-end=&quot;526&quot; data-start=&quot;488&quot;&gt;RestTemplate을 써서 요청을 보내고 응답을 받아야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;531&quot; data-start=&quot;528&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;547&quot; data-start=&quot;533&quot; data-ke-size=&quot;size26&quot;&gt;  기본 사용 흐름&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;738&quot; data-origin-height=&quot;176&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAA7pq/btsOlGkLvp2/eOJE99QPTTbkOJA7Ju9gBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAA7pq/btsOlGkLvp2/eOJE99QPTTbkOJA7Ju9gBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAA7pq/btsOlGkLvp2/eOJE99QPTTbkOJA7Ju9gBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAA7pq%2FbtsOlGkLvp2%2FeOJE99QPTTbkOJA7Ju9gBK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;738&quot; height=&quot;176&quot; data-origin-width=&quot;738&quot; data-origin-height=&quot;176&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;865&quot; data-start=&quot;862&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;890&quot; data-start=&quot;867&quot; data-ke-size=&quot;size26&quot;&gt; ️ POST나 헤더가 필요한 경우&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;263&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dnEg6Z/btsOj0rAsWZ/K5gLPola6SWEbKXpifcl41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dnEg6Z/btsOj0rAsWZ/K5gLPola6SWEbKXpifcl41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dnEg6Z/btsOj0rAsWZ/K5gLPola6SWEbKXpifcl41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdnEg6Z%2FbtsOj0rAsWZ%2FK5gLPola6SWEbKXpifcl41%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;582&quot; height=&quot;263&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;263&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1172&quot; data-start=&quot;1169&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1188&quot; data-start=&quot;1174&quot; data-ke-size=&quot;size26&quot;&gt;✅ 자주 쓰는 메서드&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;메서드설명
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1399&quot; data-start=&quot;1190&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1399&quot; data-start=&quot;1221&quot;&gt;
&lt;tr data-end=&quot;1263&quot; data-start=&quot;1221&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1240&quot; data-start=&quot;1221&quot;&gt;getForObject()&lt;/td&gt;
&lt;td data-end=&quot;1263&quot; data-start=&quot;1240&quot; data-col-size=&quot;sm&quot;&gt;GET 요청, 결과만 바로 가져오기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1310&quot; data-start=&quot;1264&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1283&quot; data-start=&quot;1264&quot;&gt;getForEntity()&lt;/td&gt;
&lt;td data-end=&quot;1310&quot; data-start=&quot;1283&quot; data-col-size=&quot;sm&quot;&gt;GET 요청, 결과 + 상태코드 같이 받기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1346&quot; data-start=&quot;1311&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1331&quot; data-start=&quot;1311&quot;&gt;postForObject()&lt;/td&gt;
&lt;td data-end=&quot;1346&quot; data-start=&quot;1331&quot; data-col-size=&quot;sm&quot;&gt;POST 요청 보내기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1399&quot; data-start=&quot;1347&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1362&quot; data-start=&quot;1347&quot;&gt;exchange()&lt;/td&gt;
&lt;td data-end=&quot;1399&quot; data-start=&quot;1362&quot; data-col-size=&quot;sm&quot;&gt;GET/POST/PUT/DELETE 전부 가능, 가장 유연함&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1404&quot; data-start=&quot;1401&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1414&quot; data-start=&quot;1406&quot; data-ke-size=&quot;size26&quot;&gt;  정리&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;항목설명
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1583&quot; data-start=&quot;1416&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1583&quot; data-start=&quot;1444&quot;&gt;
&lt;tr data-end=&quot;1475&quot; data-start=&quot;1444&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1449&quot; data-start=&quot;1444&quot;&gt;정체&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1475&quot; data-start=&quot;1449&quot;&gt;다른 서버에 HTTP 요청을 보내는 도구&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1504&quot; data-start=&quot;1476&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1481&quot; data-start=&quot;1476&quot;&gt;용도&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1504&quot; data-start=&quot;1481&quot;&gt;REST API 요청/응답 주고받기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1538&quot; data-start=&quot;1505&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1510&quot; data-start=&quot;1505&quot;&gt;대안&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1538&quot; data-start=&quot;1510&quot;&gt;더 복잡한 경우엔 WebClient 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1583&quot; data-start=&quot;1539&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1546&quot; data-start=&quot;1539&quot;&gt;한줄요약&lt;/td&gt;
&lt;td data-end=&quot;1583&quot; data-start=&quot;1546&quot; data-col-size=&quot;sm&quot;&gt;&lt;b&gt;자바에서 API를 호출하고 응답을 받는 전화기&lt;/b&gt; 같은 도구&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <author>404NotFoundMe</author>
      <guid isPermaLink="true">https://idea5595.tistory.com/25</guid>
      <comments>https://idea5595.tistory.com/25#entry25comment</comments>
      <pubDate>Fri, 30 May 2025 18:54:58 +0900</pubDate>
    </item>
    <item>
      <title>최종 프로젝트 오픈API 연동(5)</title>
      <link>https://idea5595.tistory.com/24</link>
      <description>&lt;h2 data-end=&quot;179&quot; data-start=&quot;120&quot; data-ke-size=&quot;size26&quot;&gt;✅ 한국투자증권 오픈API 연동 - 5단계: 응답 받은 JSON 데이터를 파싱하고 필요한 값 추출하기&lt;/h2&gt;
&lt;h3 data-end=&quot;193&quot; data-start=&quot;181&quot; data-ke-size=&quot;size23&quot;&gt;  1. 개요&lt;/h3&gt;
&lt;p data-end=&quot;354&quot; data-start=&quot;195&quot; data-ke-size=&quot;size16&quot;&gt;오픈API를 호출한 결과로 JSON 형식의 응답을 받게 됩니다.&lt;br /&gt;이 단계에서는 그 JSON 응답에서 **필요한 데이터(예: 일자별 시세, 거래량 등)**를 추출합니다.&lt;br /&gt;Spring에서는 일반적으로 **Jackson의 ObjectMapper**를 사용해 JSON을 파싱합니다.&lt;/p&gt;
&lt;hr data-end=&quot;359&quot; data-start=&quot;356&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;381&quot; data-start=&quot;361&quot; data-ke-size=&quot;size23&quot;&gt;  2. 응답 JSON 예시&lt;/h3&gt;
&lt;p data-end=&quot;417&quot; data-start=&quot;383&quot; data-ke-size=&quot;size16&quot;&gt;한국투자증권의 일별 시세 조회 응답은 다음과 같은 구조입니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;308&quot; data-origin-height=&quot;406&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTyk6n/btsOliYO3cv/BUOoF4YTIgMfYaRIbbMt10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTyk6n/btsOliYO3cv/BUOoF4YTIgMfYaRIbbMt10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTyk6n/btsOliYO3cv/BUOoF4YTIgMfYaRIbbMt10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTyk6n%2FbtsOliYO3cv%2FBUOoF4YTIgMfYaRIbbMt10%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;308&quot; height=&quot;406&quot; data-origin-width=&quot;308&quot; data-origin-height=&quot;406&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;737&quot; data-start=&quot;701&quot; data-ke-size=&quot;size16&quot;&gt;✅ 우리가 필요한 데이터는 output2 배열 안에 있습니다.&lt;/p&gt;
&lt;hr data-end=&quot;742&quot; data-start=&quot;739&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;784&quot; data-start=&quot;744&quot; data-ke-size=&quot;size23&quot;&gt;  3. 사용 도구: Jackson의 ObjectMapper&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;497&quot; data-origin-height=&quot;87&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uHPSE/btsOlMrxhMo/KTAbkTmXZF9AouQlZwEkW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uHPSE/btsOlMrxhMo/KTAbkTmXZF9AouQlZwEkW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uHPSE/btsOlMrxhMo/KTAbkTmXZF9AouQlZwEkW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuHPSE%2FbtsOlMrxhMo%2FKTAbkTmXZF9AouQlZwEkW1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;497&quot; height=&quot;87&quot; data-origin-width=&quot;497&quot; data-origin-height=&quot;87&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1036&quot; data-start=&quot;952&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;994&quot; data-start=&quot;952&quot;&gt;JsonNode는 Jackson이 제공하는 JSON 탐색 객체입니다.&lt;/li&gt;
&lt;li data-end=&quot;1036&quot; data-start=&quot;995&quot;&gt;readTree()는 문자열(JSON)을 트리 구조로 파싱해줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1041&quot; data-start=&quot;1038&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1070&quot; data-start=&quot;1043&quot; data-ke-size=&quot;size23&quot;&gt;  4. 반복문으로 원하는 데이터 꺼내기&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;251&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mayNG/btsOj2QpDix/kZMVSJuC4D65aiKurQfCyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mayNG/btsOj2QpDix/kZMVSJuC4D65aiKurQfCyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mayNG/btsOj2QpDix/kZMVSJuC4D65aiKurQfCyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmayNG%2FbtsOj2QpDix%2FkZMVSJuC4D65aiKurQfCyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;755&quot; height=&quot;251&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;251&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1585&quot; data-start=&quot;1582&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1607&quot; data-start=&quot;1587&quot; data-ke-size=&quot;size23&quot;&gt;  5. 실수하기 쉬운 부분&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;문제설명해결 방법
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1864&quot; data-start=&quot;1609&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1864&quot; data-start=&quot;1658&quot;&gt;
&lt;tr data-end=&quot;1713&quot; data-start=&quot;1658&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1681&quot; data-start=&quot;1658&quot;&gt;NullPointerException&lt;/td&gt;
&lt;td data-end=&quot;1693&quot; data-start=&quot;1681&quot; data-col-size=&quot;sm&quot;&gt;필드가 없는 경우&lt;/td&gt;
&lt;td data-end=&quot;1713&quot; data-start=&quot;1693&quot; data-col-size=&quot;sm&quot;&gt;.has(&quot;필드명&quot;) 체크&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1780&quot; data-start=&quot;1714&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1725&quot; data-start=&quot;1714&quot;&gt;날짜 파싱 오류&lt;/td&gt;
&lt;td data-end=&quot;1754&quot; data-start=&quot;1725&quot; data-col-size=&quot;sm&quot;&gt;&quot;yyyyMMdd&quot; &amp;rarr; LocalDate&lt;/td&gt;
&lt;td data-end=&quot;1780&quot; data-start=&quot;1754&quot; data-col-size=&quot;sm&quot;&gt;DateTimeFormatter 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1864&quot; data-start=&quot;1781&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1796&quot; data-start=&quot;1781&quot;&gt;숫자처럼 보여도 문자열&lt;/td&gt;
&lt;td data-end=&quot;1819&quot; data-start=&quot;1796&quot; data-col-size=&quot;sm&quot;&gt;&quot;83000&quot; &amp;rarr; 문자열로 처리됨&lt;/td&gt;
&lt;td data-end=&quot;1864&quot; data-start=&quot;1819&quot; data-col-size=&quot;sm&quot;&gt;.asText() 후 변환 (Integer.parseInt() 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1869&quot; data-start=&quot;1866&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1882&quot; data-start=&quot;1871&quot; data-ke-size=&quot;size23&quot;&gt;✅ 6. 정리&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2039&quot; data-start=&quot;1884&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1933&quot; data-start=&quot;1884&quot;&gt;JSON 응답은 대부분 문자열이므로 .asText()로 꺼낸 후 변환해야 합니다.&lt;/li&gt;
&lt;li data-end=&quot;1985&quot; data-start=&quot;1934&quot;&gt;필요한 필드만 골라서 꺼낼 수 있으며, DTO나 Entity에 담아 사용할 수 있습니다.&lt;/li&gt;
&lt;li data-end=&quot;2039&quot; data-start=&quot;1986&quot;&gt;이 데이터를 DB에 저장하거나, API 응답으로 보내거나, 시각화 등에 활용할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>404NotFoundMe</author>
      <guid isPermaLink="true">https://idea5595.tistory.com/24</guid>
      <comments>https://idea5595.tistory.com/24#entry24comment</comments>
      <pubDate>Fri, 30 May 2025 18:30:49 +0900</pubDate>
    </item>
    <item>
      <title>최종 프로젝트 오픈API 연동(4)</title>
      <link>https://idea5595.tistory.com/23</link>
      <description>&lt;h2 data-end=&quot;177&quot; data-start=&quot;124&quot; data-ke-size=&quot;size26&quot;&gt;✅ 한국투자증권 오픈API 연동 - 4단계: URL + 헤더를 사용하여 실제로 요청 보내기&lt;/h2&gt;
&lt;h3 data-end=&quot;191&quot; data-start=&quot;179&quot; data-ke-size=&quot;size23&quot;&gt;  1. 개요&lt;/h3&gt;
&lt;p data-end=&quot;313&quot; data-start=&quot;193&quot; data-ke-size=&quot;size16&quot;&gt;앞에서 준비한 &lt;b&gt;URL&lt;/b&gt;과 &lt;b&gt;헤더&lt;/b&gt;를 이용해서&lt;br /&gt;이제 실제로 오픈API 서버에 요청을 보냅니다.&lt;br /&gt;Spring에서는 RestTemplate이라는 클래스를 이용해 쉽게 HTTP 요청을 보낼 수 있습니다.&lt;/p&gt;
&lt;hr data-end=&quot;318&quot; data-start=&quot;315&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;352&quot; data-start=&quot;320&quot; data-ke-size=&quot;size23&quot;&gt;⚙️ 2. 사용할 도구: RestTemplate&lt;/h3&gt;
&lt;p data-end=&quot;394&quot; data-start=&quot;354&quot; data-ke-size=&quot;size16&quot;&gt;Spring 프레임워크에서 HTTP 요청을 보내기 위한 기본 도구입니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;429&quot; data-origin-height=&quot;38&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQ2vfs/btsOkKPhP3o/3mkCHQnmKDsikYbK5Qj5A1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQ2vfs/btsOkKPhP3o/3mkCHQnmKDsikYbK5Qj5A1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQ2vfs/btsOkKPhP3o/3mkCHQnmKDsikYbK5Qj5A1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQ2vfs%2FbtsOkKPhP3o%2F3mkCHQnmKDsikYbK5Qj5A1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;429&quot; height=&quot;38&quot; data-origin-width=&quot;429&quot; data-origin-height=&quot;38&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;460&quot; data-start=&quot;457&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;483&quot; data-start=&quot;462&quot; data-ke-size=&quot;size23&quot;&gt;  3. 요청 구성 요소 요약&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;구성 요소설명
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;769&quot; data-start=&quot;485&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;769&quot; data-start=&quot;572&quot;&gt;
&lt;tr data-end=&quot;609&quot; data-start=&quot;572&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;583&quot; data-start=&quot;572&quot;&gt;URL&lt;/td&gt;
&lt;td data-end=&quot;609&quot; data-start=&quot;583&quot; data-col-size=&quot;sm&quot;&gt;2단계에서 만든 API 요청 주소&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;647&quot; data-start=&quot;610&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;621&quot; data-start=&quot;610&quot;&gt;Headers&lt;/td&gt;
&lt;td data-end=&quot;647&quot; data-start=&quot;621&quot; data-col-size=&quot;sm&quot;&gt;3단계에서 만든 인증 헤더&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;694&quot; data-start=&quot;648&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;659&quot; data-start=&quot;648&quot;&gt;Method&lt;/td&gt;
&lt;td data-end=&quot;694&quot; data-start=&quot;659&quot; data-col-size=&quot;sm&quot;&gt;HttpMethod.GET&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;734&quot; data-start=&quot;695&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;706&quot; data-start=&quot;695&quot;&gt;Body&lt;/td&gt;
&lt;td data-end=&quot;734&quot; data-start=&quot;706&quot; data-col-size=&quot;sm&quot;&gt;(GET 요청이므로 없음)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;769&quot; data-start=&quot;735&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;742&quot; data-start=&quot;735&quot;&gt;응답타입&lt;/td&gt;
&lt;td data-end=&quot;769&quot; data-start=&quot;742&quot; data-col-size=&quot;sm&quot;&gt;일반적으로 String.class 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;774&quot; data-start=&quot;771&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;794&quot; data-start=&quot;776&quot; data-ke-size=&quot;size23&quot;&gt;✍️ 4. 요청 코드 예시&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;615&quot; data-origin-height=&quot;273&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mhHKI/btsOlALDzdg/An91A21wRnP5zd4W0gK7a1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mhHKI/btsOlALDzdg/An91A21wRnP5zd4W0gK7a1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mhHKI/btsOlALDzdg/An91A21wRnP5zd4W0gK7a1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmhHKI%2FbtsOlALDzdg%2FAn91A21wRnP5zd4W0gK7a1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;615&quot; height=&quot;273&quot; data-origin-width=&quot;615&quot; data-origin-height=&quot;273&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1218&quot; data-start=&quot;1215&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1233&quot; data-start=&quot;1220&quot; data-ke-size=&quot;size23&quot;&gt;  흐름 시각화&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;301&quot; data-origin-height=&quot;187&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boHdhC/btsOkkDxutm/TMw2JTKs7szHOhPeDAorvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boHdhC/btsOkkDxutm/TMw2JTKs7szHOhPeDAorvk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boHdhC/btsOkkDxutm/TMw2JTKs7szHOhPeDAorvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboHdhC%2FbtsOkkDxutm%2FTMw2JTKs7szHOhPeDAorvk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;301&quot; height=&quot;187&quot; data-origin-width=&quot;301&quot; data-origin-height=&quot;187&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1360&quot; data-start=&quot;1357&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1386&quot; data-start=&quot;1362&quot; data-ke-size=&quot;size23&quot;&gt;⚠️ 5. 오류가 나는 경우 (예시)&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;상태코드의미원인 예시
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1592&quot; data-start=&quot;1388&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1592&quot; data-start=&quot;1442&quot;&gt;
&lt;tr data-end=&quot;1482&quot; data-start=&quot;1442&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1461&quot; data-start=&quot;1442&quot;&gt;401 Unauthorized&lt;/td&gt;
&lt;td data-end=&quot;1469&quot; data-start=&quot;1461&quot; data-col-size=&quot;sm&quot;&gt;인증 실패&lt;/td&gt;
&lt;td data-end=&quot;1482&quot; data-start=&quot;1469&quot; data-col-size=&quot;sm&quot;&gt;토큰 누락, 만료&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1530&quot; data-start=&quot;1483&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1499&quot; data-start=&quot;1483&quot;&gt;403 Forbidden&lt;/td&gt;
&lt;td data-end=&quot;1507&quot; data-start=&quot;1499&quot; data-col-size=&quot;sm&quot;&gt;권한 없음&lt;/td&gt;
&lt;td data-end=&quot;1530&quot; data-start=&quot;1507&quot; data-col-size=&quot;sm&quot;&gt;appkey/appsecret 틀림&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1592&quot; data-start=&quot;1531&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1559&quot; data-start=&quot;1531&quot;&gt;500 Internal Server Error&lt;/td&gt;
&lt;td data-end=&quot;1570&quot; data-start=&quot;1559&quot; data-col-size=&quot;sm&quot;&gt;서버 내부 오류&lt;/td&gt;
&lt;td data-end=&quot;1592&quot; data-start=&quot;1570&quot; data-col-size=&quot;sm&quot;&gt;잘못된 파라미터, tr_id 오류&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1597&quot; data-start=&quot;1594&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1610&quot; data-start=&quot;1599&quot; data-ke-size=&quot;size23&quot;&gt;✅ 6. 정리&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1774&quot; data-start=&quot;1612&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1672&quot; data-start=&quot;1612&quot;&gt;RestTemplate.exchange()는 Spring에서 가장 직관적인 HTTP 호출 방식입니다.&lt;/li&gt;
&lt;li data-end=&quot;1711&quot; data-start=&quot;1673&quot;&gt;요청 시에는 반드시 올바른 헤더와 URL을 함께 전달해야 합니다.&lt;/li&gt;
&lt;li data-end=&quot;1774&quot; data-start=&quot;1712&quot;&gt;응답은 일반적으로 JSON 문자열이므로, 다음 단계에서 JSON을 파싱해서 필요한 데이터를 추출하게 됩니다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>404NotFoundMe</author>
      <guid isPermaLink="true">https://idea5595.tistory.com/23</guid>
      <comments>https://idea5595.tistory.com/23#entry23comment</comments>
      <pubDate>Fri, 30 May 2025 18:29:26 +0900</pubDate>
    </item>
    <item>
      <title>최종 프로젝트 오픈API 연동(3)</title>
      <link>https://idea5595.tistory.com/22</link>
      <description>&lt;h2 data-end=&quot;133&quot; data-start=&quot;89&quot; data-ke-size=&quot;size26&quot;&gt;✅ 한국투자증권 오픈API 연동 - 3단계: 요청에 필요한 인증 헤더 구성&lt;/h2&gt;
&lt;h3 data-end=&quot;147&quot; data-start=&quot;135&quot; data-ke-size=&quot;size23&quot;&gt;  1. 개요&lt;/h3&gt;
&lt;p data-end=&quot;266&quot; data-start=&quot;149&quot; data-ke-size=&quot;size16&quot;&gt;오픈API 서버는 요청을 보낸 사람이 &lt;b&gt;유효한 사용자이며 권한이 있는지 확인&lt;/b&gt;하기 위해&lt;br /&gt;&lt;b&gt;HTTP 헤더에 인증 정보를 요구&lt;/b&gt;합니다.&lt;br /&gt;이 단계에서는 필요한 헤더들을 정리하고 자바 코드로 구성합니다.&lt;/p&gt;
&lt;hr data-end=&quot;271&quot; data-start=&quot;268&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;291&quot; data-start=&quot;273&quot; data-ke-size=&quot;size23&quot;&gt;  2. 필수 헤더 목록&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;헤더 이름설명예시 값
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;963&quot; data-start=&quot;293&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;963&quot; data-start=&quot;491&quot;&gt;
&lt;tr data-end=&quot;587&quot; data-start=&quot;491&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;509&quot; data-start=&quot;491&quot;&gt;authorization&lt;/td&gt;
&lt;td data-end=&quot;551&quot; data-start=&quot;509&quot; data-col-size=&quot;sm&quot;&gt;인증 토큰 (Bearer 토큰 형식)&lt;/td&gt;
&lt;td data-end=&quot;587&quot; data-start=&quot;551&quot; data-col-size=&quot;sm&quot;&gt;Bearer eyJhbGciOiJIUzI1NiIs...&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;681&quot; data-start=&quot;588&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;606&quot; data-start=&quot;588&quot;&gt;appkey&lt;/td&gt;
&lt;td data-end=&quot;645&quot; data-start=&quot;606&quot; data-col-size=&quot;sm&quot;&gt;한국투자증권에서 발급한 App Key&lt;/td&gt;
&lt;td data-end=&quot;681&quot; data-start=&quot;645&quot; data-col-size=&quot;sm&quot;&gt;6a0c1f13-xxxx-xxxx-xxxx-abcdef&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;786&quot; data-start=&quot;682&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;700&quot; data-start=&quot;682&quot;&gt;appsecret&lt;/td&gt;
&lt;td data-end=&quot;749&quot; data-start=&quot;700&quot; data-col-size=&quot;sm&quot;&gt;App Secret Key&lt;/td&gt;
&lt;td data-end=&quot;786&quot; data-start=&quot;749&quot; data-col-size=&quot;sm&quot;&gt;1f04c311-xxxx-xxxx-xxxx-abcd...&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;872&quot; data-start=&quot;787&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;805&quot; data-start=&quot;787&quot;&gt;tr_id&lt;/td&gt;
&lt;td data-end=&quot;841&quot; data-start=&quot;805&quot; data-col-size=&quot;sm&quot;&gt;사용하는 API 고유 식별자 (API 문서에 명시됨)&lt;/td&gt;
&lt;td data-end=&quot;872&quot; data-start=&quot;841&quot; data-col-size=&quot;sm&quot;&gt;FHKST03010100 (일별 시세 조회용)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;963&quot; data-start=&quot;873&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;891&quot; data-start=&quot;873&quot;&gt;Content-Type&lt;/td&gt;
&lt;td data-end=&quot;927&quot; data-start=&quot;891&quot; data-col-size=&quot;sm&quot;&gt;요청 본문의 형식 (일반적으로 JSON 사용)&lt;/td&gt;
&lt;td data-end=&quot;963&quot; data-start=&quot;927&quot; data-col-size=&quot;sm&quot;&gt;application/json&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-end=&quot;1022&quot; data-start=&quot;965&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1022&quot; data-start=&quot;967&quot; data-ke-size=&quot;size16&quot;&gt;  tr_id는 사용하는 API마다 다르며, 반드시 해당 API에 맞는 값을 사용해야 합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;1027&quot; data-start=&quot;1024&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1056&quot; data-start=&quot;1029&quot; data-ke-size=&quot;size23&quot;&gt;  3. 헤더를 구성하는 자바 코드 예시&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;484&quot; data-origin-height=&quot;114&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eU9b8C/btsOk8Wpyfm/Eo5JdVdRndF8AqEPlxjkC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eU9b8C/btsOk8Wpyfm/Eo5JdVdRndF8AqEPlxjkC0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eU9b8C/btsOk8Wpyfm/Eo5JdVdRndF8AqEPlxjkC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeU9b8C%2FbtsOk8Wpyfm%2FEo5JdVdRndF8AqEPlxjkC0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;484&quot; height=&quot;114&quot; data-origin-width=&quot;484&quot; data-origin-height=&quot;114&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1577&quot; data-start=&quot;1441&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1482&quot; data-start=&quot;1441&quot;&gt;accessToken은 별도 인증 API를 통해 발급받은 값입니다.&lt;/li&gt;
&lt;li data-end=&quot;1535&quot; data-start=&quot;1483&quot;&gt;&quot;Bearer &quot; 문자열을 앞에 붙여야 합니다 (Bearer + 공백 + 토큰값).&lt;/li&gt;
&lt;li data-end=&quot;1577&quot; data-start=&quot;1536&quot;&gt;HttpHeaders는 Spring의 요청 헤더 전용 클래스입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1582&quot; data-start=&quot;1579&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1602&quot; data-start=&quot;1584&quot; data-ke-size=&quot;size23&quot;&gt;  4. 헤더 구성 흐름&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1.&lt;/span&gt;&lt;/span&gt;&lt;span&gt; accessToken 발급 (별도 API) &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;2.&lt;/span&gt;&lt;/span&gt;&lt;span&gt; 설정 파일에서 appkey, appsecret 읽기 &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;3.&lt;/span&gt;&lt;/span&gt;&lt;span&gt; tr&lt;span&gt;_id는 API 문서에서 확인 &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;4. 위 정보들을 HttpHeaders에 담기 &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1723&quot; data-start=&quot;1720&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1736&quot; data-start=&quot;1725&quot; data-ke-size=&quot;size23&quot;&gt;✅ 5. 정리&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1911&quot; data-start=&quot;1738&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1790&quot; data-start=&quot;1738&quot;&gt;한국투자증권 오픈API는 단순한 토큰 외에도 &lt;b&gt;앱 키와 시크릿 키가 함께 필요&lt;/b&gt;합니다.&lt;/li&gt;
&lt;li data-end=&quot;1844&quot; data-start=&quot;1791&quot;&gt;요청하려는 API마다 고유한 tr_id를 지정해야 하므로 문서를 반드시 확인해야 합니다.&lt;/li&gt;
&lt;li data-end=&quot;1911&quot; data-start=&quot;1845&quot;&gt;헤더를 올바르게 설정하지 않으면 401 Unauthorized, 403 Forbidden 오류가 발생합니다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>404NotFoundMe</author>
      <guid isPermaLink="true">https://idea5595.tistory.com/22</guid>
      <comments>https://idea5595.tistory.com/22#entry22comment</comments>
      <pubDate>Fri, 30 May 2025 18:27:21 +0900</pubDate>
    </item>
    <item>
      <title>최종 프로젝트 오픈API 연동(2)</title>
      <link>https://idea5595.tistory.com/21</link>
      <description>&lt;h2 data-end=&quot;128&quot; data-start=&quot;85&quot; data-ke-size=&quot;size26&quot;&gt;✅ 한국투자증권 오픈API 연동 - 2단계: 요청 URL과 파라미터 구성&lt;/h2&gt;
&lt;h3 data-end=&quot;142&quot; data-start=&quot;130&quot; data-ke-size=&quot;size23&quot;&gt;  1. 개요&lt;/h3&gt;
&lt;p data-end=&quot;273&quot; data-start=&quot;144&quot; data-ke-size=&quot;size16&quot;&gt;오픈API에 요청을 보낼 때는 정확한 &lt;b&gt;요청 URL과 쿼리 파라미터&lt;/b&gt;를 구성해야 합니다.&lt;br /&gt;한국투자증권의 REST API는 대부분 GET 방식이며, 쿼리스트링을 통해 종목코드, 날짜, 주기 등 다양한 값을 전달해야 합니다.&lt;/p&gt;
&lt;hr data-end=&quot;278&quot; data-start=&quot;275&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;312&quot; data-start=&quot;280&quot; data-ke-size=&quot;size23&quot;&gt;  2. 사용할 API: 국내주식 일별 시세 조회&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;412&quot; data-start=&quot;314&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;373&quot; data-start=&quot;314&quot;&gt;&lt;b&gt;API 설명&lt;/b&gt;: 지정한 종목의 일정 기간 동안의 주가(시가/종가/고가/저가/거래량)를 조회합니다.&lt;/li&gt;
&lt;li data-end=&quot;398&quot; data-start=&quot;374&quot;&gt;&lt;b&gt;HTTP Method&lt;/b&gt;: GET&lt;/li&gt;
&lt;li data-end=&quot;412&quot; data-start=&quot;399&quot;&gt;&lt;b&gt;요청 URL&lt;/b&gt;: &lt;a style=&quot;letter-spacing: 0px;&quot; href=&quot;https://openapi.koreainvestment.com:9443/uapi/domestic-stock/v1/quotations/inquire-daily-itemchartprice&quot;&gt;https://openapi.koreainvestment.com:9443/uapi/domestic-stock/v1/quotations/inquire-daily-itemchartprice&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;530&quot; data-start=&quot;527&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;552&quot; data-start=&quot;532&quot; data-ke-size=&quot;size23&quot;&gt;  3. 주요 쿼리 파라미터&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;파라미터명설명예시값
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1127&quot; data-start=&quot;554&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1127&quot; data-start=&quot;693&quot;&gt;
&lt;tr data-end=&quot;762&quot; data-start=&quot;693&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;720&quot; data-start=&quot;693&quot;&gt;FID_COND_MRKT_DIV_CODE&lt;/td&gt;
&lt;td data-end=&quot;748&quot; data-start=&quot;720&quot; data-col-size=&quot;sm&quot;&gt;시장 구분 코드 (J: 주식)&lt;/td&gt;
&lt;td data-end=&quot;762&quot; data-start=&quot;748&quot; data-col-size=&quot;sm&quot;&gt;J&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;841&quot; data-start=&quot;763&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;790&quot; data-start=&quot;763&quot;&gt;FID_INPUT_ISCD&lt;/td&gt;
&lt;td data-end=&quot;822&quot; data-start=&quot;790&quot; data-col-size=&quot;sm&quot;&gt;종목코드&lt;/td&gt;
&lt;td data-end=&quot;841&quot; data-start=&quot;822&quot; data-col-size=&quot;sm&quot;&gt;005930 (삼성전자)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;914&quot; data-start=&quot;842&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;869&quot; data-start=&quot;842&quot;&gt;FID_INPUT_DATE_1&lt;/td&gt;
&lt;td data-end=&quot;900&quot; data-start=&quot;869&quot; data-col-size=&quot;sm&quot;&gt;조회 시작일 (yyyyMMdd)&lt;/td&gt;
&lt;td data-end=&quot;914&quot; data-start=&quot;900&quot; data-col-size=&quot;sm&quot;&gt;20240501&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;987&quot; data-start=&quot;915&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;942&quot; data-start=&quot;915&quot;&gt;FID_INPUT_DATE_2&lt;/td&gt;
&lt;td data-end=&quot;973&quot; data-start=&quot;942&quot; data-col-size=&quot;sm&quot;&gt;조회 종료일 (yyyyMMdd)&lt;/td&gt;
&lt;td data-end=&quot;987&quot; data-start=&quot;973&quot; data-col-size=&quot;sm&quot;&gt;20240530&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1058&quot; data-start=&quot;988&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1015&quot; data-start=&quot;988&quot;&gt;FID_PERIOD_DIV_CODE&lt;/td&gt;
&lt;td data-end=&quot;1044&quot; data-start=&quot;1015&quot; data-col-size=&quot;sm&quot;&gt;조회 주기 (D: 일별, W: 주간)&lt;/td&gt;
&lt;td data-end=&quot;1058&quot; data-start=&quot;1044&quot; data-col-size=&quot;sm&quot;&gt;D&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1127&quot; data-start=&quot;1059&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1086&quot; data-start=&quot;1059&quot;&gt;FID_ORG_ADJ_PRC&lt;/td&gt;
&lt;td data-end=&quot;1113&quot; data-start=&quot;1086&quot; data-col-size=&quot;sm&quot;&gt;수정주가 여부 (0: 미적용)&lt;/td&gt;
&lt;td data-end=&quot;1127&quot; data-start=&quot;1113&quot; data-col-size=&quot;sm&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1132&quot; data-start=&quot;1129&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1165&quot; data-start=&quot;1134&quot; data-ke-size=&quot;size23&quot;&gt;  4. 자바 코드로 URL과 파라미터 구성하기&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;556&quot; data-origin-height=&quot;150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rPVkK/btsOlEmRqfk/TOW6WcG69FQPHlDv8OyGb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rPVkK/btsOlEmRqfk/TOW6WcG69FQPHlDv8OyGb0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rPVkK/btsOlEmRqfk/TOW6WcG69FQPHlDv8OyGb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrPVkK%2FbtsOlEmRqfk%2FTOW6WcG69FQPHlDv8OyGb0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;556&quot; height=&quot;150&quot; data-origin-width=&quot;556&quot; data-origin-height=&quot;150&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1680&quot; data-start=&quot;1598&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1653&quot; data-start=&quot;1598&quot;&gt;UriComponentsBuilder를 사용하면 쿼리 파라미터를 안전하게 붙일 수 있습니다.&lt;/li&gt;
&lt;li data-end=&quot;1680&quot; data-start=&quot;1654&quot;&gt;위 코드는 다음과 같은 URL을 생성합니다:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;134&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFS56d/btsOlYSLs9H/w19mR9u67WKonWFsMczHk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFS56d/btsOlYSLs9H/w19mR9u67WKonWFsMczHk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFS56d/btsOlYSLs9H/w19mR9u67WKonWFsMczHk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFS56d%2FbtsOlYSLs9H%2Fw19mR9u67WKonWFsMczHk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;560&quot; height=&quot;134&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;134&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-end=&quot;1947&quot; data-start=&quot;1944&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1960&quot; data-start=&quot;1949&quot; data-ke-size=&quot;size23&quot;&gt;✅ 5. 정리&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2105&quot; data-start=&quot;1962&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2005&quot; data-start=&quot;1962&quot;&gt;쿼리 파라미터는 API 문서에서 요구하는 필수값을 빠짐없이 넣어야 합니다.&lt;/li&gt;
&lt;li data-end=&quot;2067&quot; data-start=&quot;2006&quot;&gt;UriComponentsBuilder를 사용하면 URL 조합 실수를 줄이고 가독성을 높일 수 있습니다.&lt;/li&gt;
&lt;li data-end=&quot;2105&quot; data-start=&quot;2068&quot;&gt;이 URL은 다음 단계에서 헤더와 함께 실제 요청에 사용됩니다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>404NotFoundMe</author>
      <guid isPermaLink="true">https://idea5595.tistory.com/21</guid>
      <comments>https://idea5595.tistory.com/21#entry21comment</comments>
      <pubDate>Fri, 30 May 2025 18:26:09 +0900</pubDate>
    </item>
    <item>
      <title>최종 프로젝트 오픈API 연동(1)</title>
      <link>https://idea5595.tistory.com/20</link>
      <description>&lt;h2 data-end=&quot;138&quot; data-start=&quot;107&quot; data-ke-size=&quot;size26&quot;&gt;✅ 한국투자증권 오픈API 연동 - 1단계: 준비물&lt;/h2&gt;
&lt;h3 data-end=&quot;152&quot; data-start=&quot;140&quot; data-ke-size=&quot;size23&quot;&gt;  1. 개요&lt;/h3&gt;
&lt;p data-end=&quot;313&quot; data-start=&quot;154&quot; data-ke-size=&quot;size16&quot;&gt;한국투자증권에서 제공하는 OpenAPI를 사용하려면 **인증 키(appkey/appsecret)**와 **기본 서버 주소(base-url)**가 필요합니다.&lt;br /&gt;이 정보들은 보안상 코드에 직접 작성하지 않고, Spring의 설정파일(application.yml)을 통해 관리합니다.&lt;/p&gt;
&lt;hr data-end=&quot;318&quot; data-start=&quot;315&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;337&quot; data-start=&quot;320&quot; data-ke-size=&quot;size23&quot;&gt; ️ 2. 필요한 정보&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;설정 항목설명예시
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;776&quot; data-start=&quot;339&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;776&quot; data-start=&quot;514&quot;&gt;
&lt;tr data-end=&quot;595&quot; data-start=&quot;514&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;529&quot; data-start=&quot;514&quot;&gt;appkey&lt;/td&gt;
&lt;td data-end=&quot;559&quot; data-start=&quot;529&quot; data-col-size=&quot;sm&quot;&gt;한국투자증권 API에서 발급받은 App Key&lt;/td&gt;
&lt;td data-end=&quot;595&quot; data-start=&quot;559&quot; data-col-size=&quot;sm&quot;&gt;6a0c1f13-xxxx-xxxx-xxxx-abcdef&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;682&quot; data-start=&quot;596&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;611&quot; data-start=&quot;596&quot;&gt;appsecret&lt;/td&gt;
&lt;td data-end=&quot;645&quot; data-start=&quot;611&quot; data-col-size=&quot;sm&quot;&gt;위 App Key와 쌍을 이루는 Secret&lt;/td&gt;
&lt;td data-end=&quot;682&quot; data-start=&quot;645&quot; data-col-size=&quot;sm&quot;&gt;1f04c311-xxxx-xxxx-xxxx-abcd...&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;776&quot; data-start=&quot;683&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;698&quot; data-start=&quot;683&quot;&gt;base-url&lt;/td&gt;
&lt;td data-end=&quot;730&quot; data-start=&quot;698&quot; data-col-size=&quot;sm&quot;&gt;요청을 보낼 OpenAPI 서버 주소&lt;/td&gt;
&lt;td data-end=&quot;776&quot; data-start=&quot;730&quot; data-col-size=&quot;sm&quot;&gt;&lt;a href=&quot;https://openapi.koreainvestment.com:9443&quot;&gt;https://openapi.koreainvestment.com:9443&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;781&quot; data-start=&quot;778&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;816&quot; data-start=&quot;783&quot; data-ke-size=&quot;size23&quot;&gt;  3. application.yml 설정 예시&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;356&quot; data-origin-height=&quot;136&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4IQ34/btsOjtgkLYE/VJUWskkgEAXVfVHaTyLUXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4IQ34/btsOjtgkLYE/VJUWskkgEAXVfVHaTyLUXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4IQ34/btsOjtgkLYE/VJUWskkgEAXVfVHaTyLUXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4IQ34%2FbtsOjtgkLYE%2FVJUWskkgEAXVfVHaTyLUXk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;356&quot; height=&quot;136&quot; data-origin-width=&quot;356&quot; data-origin-height=&quot;136&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-end=&quot;1011&quot; data-start=&quot;998&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Tip:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1076&quot; data-start=&quot;1012&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1042&quot; data-start=&quot;1012&quot;&gt;이 정보들은 깃허브에 올리지 않도록 주의하세요!&lt;/li&gt;
&lt;li data-end=&quot;1076&quot; data-start=&quot;1043&quot;&gt;운영 환경과 개발 환경에서 분리 관리하는 것이 좋습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1081&quot; data-start=&quot;1078&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1109&quot; data-start=&quot;1083&quot; data-ke-size=&quot;size23&quot;&gt;  4. 자바 코드에서 설정값 불러오기&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;154&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnIFf9/btsOknmtfeB/yBJFxjQrRjSpCP8srLe8t1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnIFf9/btsOknmtfeB/yBJFxjQrRjSpCP8srLe8t1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnIFf9/btsOknmtfeB/yBJFxjQrRjSpCP8srLe8t1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnIFf9%2FbtsOknmtfeB%2FyBJFxjQrRjSpCP8srLe8t1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;340&quot; height=&quot;154&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;154&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1380&quot; data-start=&quot;1306&quot; data-ke-size=&quot;size16&quot;&gt;  이처럼 @Value 애너테이션을 사용하면 application.yml에 있는 값을 자동으로 읽어와서 필드에 주입해줍니다.&lt;/p&gt;
&lt;hr data-end=&quot;1385&quot; data-start=&quot;1382&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1398&quot; data-start=&quot;1387&quot; data-ke-size=&quot;size23&quot;&gt;✅ 5. 정리&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1520&quot; data-start=&quot;1400&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1467&quot; data-start=&quot;1400&quot;&gt;민감한 API 설정 값은 .yml에 정의하고 @Value로 주입받는 방식이 가장 안전하고 유지보수가 좋습니다.&lt;/li&gt;
&lt;li data-end=&quot;1520&quot; data-start=&quot;1468&quot;&gt;이 설정은 이후 RestTemplate 등으로 오픈API 호출할 때 반복적으로 사용됩니다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>404NotFoundMe</author>
      <guid isPermaLink="true">https://idea5595.tistory.com/20</guid>
      <comments>https://idea5595.tistory.com/20#entry20comment</comments>
      <pubDate>Fri, 30 May 2025 18:21:24 +0900</pubDate>
    </item>
    <item>
      <title>아웃소싱 프로젝트 내가 맡았던 부분 기능 간략 설명(User CURD, JWT토큰,시큐리티 필터)</title>
      <link>https://idea5595.tistory.com/19</link>
      <description>&lt;h2 data-end=&quot;219&quot; data-start=&quot;199&quot; data-ke-size=&quot;size26&quot;&gt;1. &lt;b&gt;프로젝트 개요&amp;nbsp; (중요도 및 어려움 표시 &lt;/b&gt;&lt;span&gt;★&lt;/span&gt;&lt;b&gt;)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;370&quot; data-start=&quot;220&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;256&quot; data-start=&quot;220&quot;&gt;회원 가입, 로그인, 회원 정보 조회/수정/삭제 기능을 제공.&lt;/li&gt;
&lt;li data-end=&quot;327&quot; data-start=&quot;257&quot;&gt;&lt;b&gt;JWT 토큰&lt;/b&gt;을 활용해 인증 및 인가를 처리하고, &lt;b&gt;Spring Security 필터&lt;/b&gt;를 커스텀하여 보안을 강화.&lt;/li&gt;
&lt;li data-end=&quot;370&quot; data-start=&quot;328&quot;&gt;상태 기반 세션이 아닌 &lt;b&gt;Stateless&lt;/b&gt;(무상태) 방식으로 구현.&lt;/li&gt;
&lt;li data-end=&quot;370&quot; data-start=&quot;328&quot;&gt;메서드 단에서는 @PreAuthorize를 사용하여 사용자의 권한(Role)을 세밀하게 제어.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;375&quot; data-start=&quot;372&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;401&quot; data-start=&quot;377&quot; data-ke-size=&quot;size26&quot;&gt;2. &lt;b&gt;JWT 인증/인가 흐름&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-end=&quot;419&quot; data-start=&quot;402&quot; data-ke-size=&quot;size23&quot;&gt;2-1. 로그인/회원가입&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;522&quot; data-start=&quot;420&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;463&quot; data-start=&quot;420&quot;&gt;&lt;b&gt;/auth/signup&lt;/b&gt; : 회원가입 API (비밀번호 암호화 후 저장)&lt;/li&gt;
&lt;li data-end=&quot;522&quot; data-start=&quot;464&quot;&gt;&lt;b&gt;/auth/login&lt;/b&gt; : 로그인 시 이메일+비밀번호 검증 후 &lt;b&gt;Access Token&lt;/b&gt; 발급.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;546&quot; data-start=&quot;524&quot; data-ke-size=&quot;size23&quot;&gt;2-2. 발급된 JWT 토큰 구조&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;656&quot; data-start=&quot;547&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;603&quot; data-start=&quot;547&quot;&gt;&lt;b&gt;Payload&lt;/b&gt; : userId, userName, email, role 저장&lt;/li&gt;
&lt;li data-end=&quot;656&quot; data-start=&quot;604&quot;&gt;&lt;b&gt;Header&lt;/b&gt; : Authorization: Bearer &amp;lt;AccessToken&amp;gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;661&quot; data-start=&quot;658&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;685&quot; data-start=&quot;663&quot; data-ke-size=&quot;size26&quot;&gt;3. &lt;b&gt;시큐리티 필터 기능&amp;nbsp; &amp;nbsp;&lt;/b&gt;&lt;span&gt;★&lt;/span&gt;&lt;span&gt;★&lt;/span&gt;&lt;span&gt;★&lt;/span&gt;&lt;span&gt;★&lt;/span&gt;&lt;span&gt;★&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-end=&quot;726&quot; data-start=&quot;686&quot; data-ke-size=&quot;size23&quot;&gt;3-1. JwtAuthenticationFilter (인증 필터)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;846&quot; data-start=&quot;727&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;769&quot; data-start=&quot;727&quot;&gt;모든 요청에 대해 &lt;b&gt;Authorization 헤더&lt;/b&gt;에서 토큰을 추출.&lt;/li&gt;
&lt;li data-end=&quot;825&quot; data-start=&quot;770&quot;&gt;토큰 검증 &amp;rarr; 유저 정보 조회 &amp;rarr; SecurityContextHolder에 인증 객체 저장.&lt;/li&gt;
&lt;li data-end=&quot;846&quot; data-start=&quot;826&quot;&gt;인증 실패 시 다음 필터로 넘김.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;String&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;token&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span&gt; request.getHeader(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;Authorization&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;if&lt;/span&gt;&lt;/span&gt;&lt;span&gt; (token == &lt;/span&gt;&lt;span&gt;&lt;span&gt;null&lt;/span&gt;&lt;/span&gt;&lt;span&gt; || !jwtUtil.validateToken(token)) { &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; filterChain.doFilter(request, response); &lt;/span&gt;&lt;span&gt;&lt;span&gt;return&lt;/span&gt;&lt;/span&gt;&lt;span&gt;; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;} &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1028&quot; data-start=&quot;1025&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1078&quot; data-start=&quot;1030&quot; data-ke-size=&quot;size23&quot;&gt;3-2. JwtAuthenticationEntryPoint (인증 실패 핸들러)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1153&quot; data-start=&quot;1079&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1122&quot; data-start=&quot;1079&quot;&gt;로그인하지 않은 사용자가 인증이 필요한 요청을 할 경우 401 에러 발생.&lt;/li&gt;
&lt;li data-end=&quot;1153&quot; data-start=&quot;1123&quot;&gt;커스텀 메시지로 &quot;로그인이 필요합니다.&quot; 반환.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1158&quot; data-start=&quot;1155&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1203&quot; data-start=&quot;1160&quot; data-ke-size=&quot;size23&quot;&gt;3-3. JwtAccessDeniedHandler (권한 거부 핸들러)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1278&quot; data-start=&quot;1204&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1236&quot; data-start=&quot;1204&quot;&gt;인증은 되었지만 권한이 부족한 경우 403 에러 발생.&lt;/li&gt;
&lt;li data-end=&quot;1278&quot; data-start=&quot;1237&quot;&gt;커스텀 메시지로 &quot;권한이 없습니다. 관리자에게 문의하세요.&quot; 반환.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1283&quot; data-start=&quot;1280&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;1160&quot; data-end=&quot;1203&quot; data-ke-size=&quot;size23&quot;&gt;3-4. @AuthenticationPrincipal&amp;nbsp; &lt;span&gt;★&lt;/span&gt;&lt;span&gt;★&lt;/span&gt;&lt;span&gt;★&lt;/span&gt;&lt;span&gt;★&lt;/span&gt;&lt;span&gt;★&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;347&quot; data-start=&quot;192&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;264&quot; data-start=&quot;192&quot;&gt;&lt;b&gt;Spring Security&lt;/b&gt;가 인증한 사용자 정보를 &lt;b&gt;컨트롤러 메서드 매개변수&lt;/b&gt;에 바로 주입해주는 어노테이션입니다.&lt;/li&gt;
&lt;li data-end=&quot;347&quot; data-start=&quot;265&quot;&gt;SecurityContextHolder에 저장된 인증 객체(Authentication)의 &lt;b&gt;Principal&lt;/b&gt;을 자동으로 꺼내서 넣어줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;347&quot; data-start=&quot;192&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;419&quot; data-start=&quot;362&quot;&gt;쉽게 말하면&amp;nbsp; &quot;로그인한 사용자의 정보를 별도 조회 없이 바로 받아서 사용할 수 있도록 해주는 어노테이션&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-start=&quot;1280&quot; data-end=&quot;1283&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-end=&quot;1203&quot; data-start=&quot;1160&quot; data-ke-size=&quot;size23&quot;&gt;3-4.&lt;span&gt; @PreAuthorize(&quot;hasRole('사장님')&quot;)&amp;nbsp; &amp;nbsp;★&lt;/span&gt;&lt;span&gt;★&lt;/span&gt;&lt;span&gt;★&lt;/span&gt;&lt;span&gt;★&lt;/span&gt;&lt;span&gt;★&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;376&quot; data-start=&quot;232&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;284&quot; data-start=&quot;232&quot;&gt;메서드 실행 &lt;b&gt;전에&lt;/b&gt; 특정 &lt;b&gt;권한(Role)&lt;/b&gt; 이 있는지 검사하는 어노테이션입니다.&lt;/li&gt;
&lt;li data-end=&quot;322&quot; data-start=&quot;285&quot;&gt;보통 &lt;b&gt;컨트롤러&lt;/b&gt; 또는 &lt;b&gt;서비스 메서드&lt;/b&gt; 위에 붙입니다.&lt;/li&gt;
&lt;li data-end=&quot;376&quot; data-start=&quot;323&quot;&gt;권한이 없으면 아예 메서드 실행을 막고 &lt;b&gt;403 Forbidden 에러&lt;/b&gt;를 발생시킵니다.&lt;/li&gt;
&lt;li data-end=&quot;376&quot; data-start=&quot;323&quot;&gt;&lt;b&gt;AOP(관점 지향 프로그래밍)&lt;/b&gt; 방식으로 동작합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1278&quot; data-start=&quot;1204&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-start=&quot;362&quot; data-end=&quot;419&quot;&gt;쉽게 말하면 &quot;이 메서드는 '사장님' 권한을 가진 사람만 사용할 수 있다.&quot;는 뜻&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1283&quot; data-start=&quot;1280&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1325&quot; data-start=&quot;1285&quot; data-ke-size=&quot;size26&quot;&gt;4. &lt;b&gt;CustomUserDetails (유저 인증 객체)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1424&quot; data-start=&quot;1326&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1372&quot; data-start=&quot;1326&quot;&gt;UserDetails를 구현해서 &lt;b&gt;User 엔티티&lt;/b&gt;를 그대로 들고 있음.&lt;/li&gt;
&lt;li data-end=&quot;1424&quot; data-start=&quot;1373&quot;&gt;인증된 사용자의 ID, Email, Role, Password 등을 관리.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1429&quot; data-start=&quot;1426&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1460&quot; data-start=&quot;1431&quot; data-ke-size=&quot;size26&quot;&gt;5. &lt;b&gt;SecurityConfig 설정&amp;nbsp; &amp;nbsp;&lt;/b&gt;&lt;span&gt;★&lt;/span&gt;&lt;span&gt;★&lt;/span&gt;&lt;span&gt;★&lt;/span&gt;&lt;span&gt;★&lt;/span&gt;&lt;span&gt;★&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1627&quot; data-start=&quot;1461&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1474&quot; data-start=&quot;1461&quot;&gt;csrf 비활성화(이 부분에 대해서 조금 많이 알게되었음)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1474&quot; data-start=&quot;1461&quot;&gt;CSRF(Cross-Site Request Forgery)란?&lt;br /&gt;&quot;로그인된&amp;nbsp;사용자의&amp;nbsp;세션/쿠키&amp;nbsp;정보를&amp;nbsp;이용해서, &lt;br /&gt;그&amp;nbsp;사용자가&amp;nbsp;원하지&amp;nbsp;않는&amp;nbsp;요청을&amp;nbsp;다른&amp;nbsp;웹사이트가&amp;nbsp;대신&amp;nbsp;보내는&amp;nbsp;공격&quot;&lt;/li&gt;
&lt;li data-end=&quot;1474&quot; data-start=&quot;1461&quot;&gt;보통 csrf와 세션을 같이 사용한다고 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1503&quot; data-start=&quot;1475&quot;&gt;session 비활성화 (STATELESS)&lt;/li&gt;
&lt;li data-end=&quot;1532&quot; data-start=&quot;1504&quot;&gt;/auth/** 경로는 인증 없이 접근 가능&lt;/li&gt;
&lt;li data-end=&quot;1555&quot; data-start=&quot;1533&quot;&gt;그 외 모든 경로는 JWT 인증 필요&lt;/li&gt;
&lt;li data-end=&quot;1627&quot; data-start=&quot;1556&quot;&gt;jwtAuthenticationFilter를 UsernamePasswordAuthenticationFilter 앞에 등록&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1632&quot; data-start=&quot;1629&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1656&quot; data-start=&quot;1634&quot; data-ke-size=&quot;size26&quot;&gt;6. &lt;b&gt;유저 CRUD 기능&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-end=&quot;1671&quot; data-start=&quot;1657&quot; data-ke-size=&quot;size23&quot;&gt;6-1. 유저 조회&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1746&quot; data-start=&quot;1672&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1705&quot; data-start=&quot;1672&quot;&gt;GET /user/{userId} : 특정 유저 조회&lt;/li&gt;
&lt;li data-end=&quot;1746&quot; data-start=&quot;1706&quot;&gt;GET /user/checkLogin : 로그인한 본인 정보 조회&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1762&quot; data-start=&quot;1748&quot; data-ke-size=&quot;size23&quot;&gt;6-2. 유저 수정&amp;nbsp; &amp;nbsp;&lt;span&gt;★&lt;/span&gt;&lt;span&gt;★&lt;/span&gt;&lt;span&gt;★&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1846&quot; data-start=&quot;1763&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1813&quot; data-start=&quot;1763&quot;&gt;&lt;b&gt;쿠키(delete_auth)&lt;/b&gt; 인증 후 수정 가능 (비밀번호로 인증된 3분 쿠키)&lt;/li&gt;
&lt;li data-end=&quot;1846&quot; data-start=&quot;1814&quot;&gt;이름, 이메일, 전화번호, 주소, 비밀번호 변경 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1871&quot; data-start=&quot;1848&quot; data-ke-size=&quot;size23&quot;&gt;6-3. 유저 삭제 (소프트 삭제)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1917&quot; data-start=&quot;1872&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1917&quot; data-start=&quot;1872&quot;&gt;실제 데이터베이스 삭제가 아닌, deletedAt 필드에 삭제 시간 기록 및 상태변경.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1944&quot; data-start=&quot;1924&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;7. &lt;b&gt;보안 강화 요소&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2055&quot; data-start=&quot;1945&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1968&quot; data-start=&quot;1945&quot;&gt;비밀번호는 BCrypt로 암호화 저장.&lt;/li&gt;
&lt;li data-end=&quot;1997&quot; data-start=&quot;1969&quot;&gt;삭제/수정 요청 전 비밀번호 재확인 쿠키 인증.&lt;/li&gt;
&lt;li data-end=&quot;2022&quot; data-start=&quot;1998&quot;&gt;JWT 토큰 검증 및 예외 처리 세분화.&lt;/li&gt;
&lt;li data-end=&quot;2055&quot; data-start=&quot;2023&quot;&gt;유저 탈퇴/잠금/삭제 상태 체크 후 API 접근 차단.&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>404NotFoundMe</author>
      <guid isPermaLink="true">https://idea5595.tistory.com/19</guid>
      <comments>https://idea5595.tistory.com/19#entry19comment</comments>
      <pubDate>Mon, 28 Apr 2025 21:48:19 +0900</pubDate>
    </item>
    <item>
      <title>Spring 심화 3주차 정리(1) (Bean 생명주기, API 예외처리)</title>
      <link>https://idea5595.tistory.com/18</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;769&quot; data-end=&quot;787&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;Bean 생명주기&lt;/h2&gt;
&lt;h3 data-end=&quot;112&quot; data-start=&quot;94&quot; data-ke-size=&quot;size23&quot;&gt;  생명주기와 콜백이란?&lt;/h3&gt;
&lt;p data-end=&quot;220&quot; data-start=&quot;113&quot; data-ke-size=&quot;size16&quot;&gt;스프링은 객체(빈)를 생성하고 관리합니다 이 과정에서 &lt;b&gt;초기화&lt;/b&gt;하거나 &lt;b&gt;소멸&lt;/b&gt;할 때 자동으로 호출되는 메서드들을 지정할 수 있습니다 이게 바로 &lt;b&gt;콜백(callback)&lt;/b&gt; 개념&lt;/p&gt;
&lt;h3 data-end=&quot;270&quot; data-start=&quot;222&quot; data-ke-size=&quot;size23&quot;&gt;✅ InitializingBean, DisposableBean 인터페이스&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;421&quot; data-start=&quot;272&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;348&quot; data-start=&quot;272&quot;&gt;&lt;b&gt;InitializingBean&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;348&quot; data-start=&quot;297&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;327&quot; data-start=&quot;297&quot;&gt;빈이 &lt;b&gt;생성되고 의존성 주입&lt;/b&gt;까지 끝나면 호출됨&lt;/li&gt;
&lt;li data-end=&quot;348&quot; data-start=&quot;330&quot;&gt;초기 설정 코드 넣을 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;421&quot; data-start=&quot;349&quot;&gt;&lt;b&gt;DisposableBean&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;421&quot; data-start=&quot;372&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;395&quot; data-start=&quot;372&quot;&gt;스프링 컨테이너가 종료되기 전에 호출됨&lt;/li&gt;
&lt;li data-end=&quot;421&quot; data-start=&quot;398&quot;&gt;정리 작업(예: 연결 닫기 등)에 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;@Component&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;public&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;class&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;MyBean&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;implements&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;InitializingBean&lt;/span&gt;&lt;/span&gt;&lt;span&gt;, DisposableBean { &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;@Override&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;public&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;afterPropertiesSet&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;throws&lt;/span&gt;&lt;/span&gt;&lt;span&gt; Exception { &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; System.out.println(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;빈 초기화: afterPropertiesSet()&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;} &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;@Override&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;public&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;destroy&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;throws&lt;/span&gt;&lt;/span&gt;&lt;span&gt; Exception { &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; System.out.println(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;빈 소멸: destroy()&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;} &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;821&quot; data-start=&quot;789&quot; data-ke-size=&quot;size23&quot;&gt;✅ @Bean 속성으로 초기화/소멸 메서드 지정&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;@Bean(initMethod = &quot;init&quot;, destroyMethod = &quot;cleanup&quot;)&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;public&lt;/span&gt;&lt;/span&gt;&lt;span&gt; MyService &lt;/span&gt;&lt;span&gt;&lt;span&gt;myService&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;return&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;new&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;MyService&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(); &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;} &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1002&quot; data-start=&quot;951&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;974&quot; data-start=&quot;951&quot;&gt;init()은 빈이 생성된 후 실행&lt;/li&gt;
&lt;li data-end=&quot;1002&quot; data-start=&quot;975&quot;&gt;cleanup()은 컨테이너 종료 시 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1007&quot; data-start=&quot;1004&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1052&quot; data-start=&quot;1009&quot; data-ke-size=&quot;size23&quot;&gt;✅ @PostConstruct, @PreDestroy 애너테이션&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1107&quot; data-start=&quot;1054&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1071&quot; data-start=&quot;1054&quot;&gt;더 간단하고 표준적인 방식!&lt;/li&gt;
&lt;li data-end=&quot;1107&quot; data-start=&quot;1072&quot;&gt;클래스 안에 메서드를 정의해두면, 스프링이 알아서 호출해줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;@Component&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;public&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;class&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;MyBean&lt;/span&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;@PostConstruct&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;public&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;init&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; System.out.println(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;초기화: @PostConstruct&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;} &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;@PreDestroy&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;public&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;destroy&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; System.out.println(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;소멸: @PreDestroy&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;} &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;} &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1360&quot; data-start=&quot;1357&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1386&quot; data-start=&quot;1362&quot; data-ke-size=&quot;size23&quot;&gt;✅ Bean Scope (빈의 범위)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1448&quot; data-start=&quot;1388&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1428&quot; data-start=&quot;1388&quot;&gt;스프링 빈이 &lt;b&gt;언제 생성되고 얼마나 오래 살아있는지&lt;/b&gt; 설정하는 것&lt;/li&gt;
&lt;li data-end=&quot;1448&quot; data-start=&quot;1429&quot;&gt;가장 자주 쓰는 것만 정리하면:&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;span data-state=&quot;closed&quot;&gt;&lt;/span&gt;
&lt;div&gt;&amp;nbsp;스코프&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 설명
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1659&quot; data-start=&quot;1450&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1659&quot; data-start=&quot;1493&quot;&gt;
&lt;tr data-end=&quot;1536&quot; data-start=&quot;1493&quot;&gt;
&lt;td data-end=&quot;1508&quot; data-start=&quot;1493&quot;&gt;singleton&lt;/td&gt;
&lt;td data-end=&quot;1536&quot; data-start=&quot;1508&quot;&gt;스프링 컨테이너에 딱 하나만 존재 (기본값)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1571&quot; data-start=&quot;1537&quot;&gt;
&lt;td data-end=&quot;1552&quot; data-start=&quot;1537&quot;&gt;prototype&lt;/td&gt;
&lt;td data-end=&quot;1571&quot; data-start=&quot;1552&quot;&gt;요청할 때마다 새 객체 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1614&quot; data-start=&quot;1572&quot;&gt;
&lt;td data-end=&quot;1587&quot; data-start=&quot;1572&quot;&gt;request&lt;/td&gt;
&lt;td data-end=&quot;1614&quot; data-start=&quot;1587&quot;&gt;HTTP 요청마다 새 빈 생성 (웹 전용)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1659&quot; data-start=&quot;1615&quot;&gt;
&lt;td data-end=&quot;1630&quot; data-start=&quot;1615&quot;&gt;session&lt;/td&gt;
&lt;td data-end=&quot;1659&quot; data-start=&quot;1630&quot;&gt;HTTP 세션마다 하나의 빈 사용 (웹 전용)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;@Component&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;@Scope(&quot;prototype&quot;)&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;public&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;class&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;MyBean&lt;/span&gt;&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span&gt;&lt;span&gt;public&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;MyBean&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; System.out.println(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;MyBean 인스턴스 생성!&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; } &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;} &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1807&quot; data-start=&quot;1804&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1823&quot; data-start=&quot;1809&quot; data-ke-size=&quot;size26&quot;&gt;  API 예외처리&lt;/h2&gt;
&lt;h3 data-end=&quot;1850&quot; data-start=&quot;1825&quot; data-ke-size=&quot;size23&quot;&gt;✅ @ExceptionHandler&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1903&quot; data-start=&quot;1852&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1882&quot; data-start=&quot;1852&quot;&gt;컨트롤러에서 예외가 발생했을 때 처리할 메서드 지정&lt;/li&gt;
&lt;li data-end=&quot;1903&quot; data-start=&quot;1883&quot;&gt;예외 유형별로 다양한 처리가 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;@RestController&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;public&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;class&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;MyController&lt;/span&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span&gt;&lt;span&gt;@GetMapping(&quot;/test&quot;)&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span&gt;&lt;span&gt;public&lt;/span&gt;&lt;/span&gt;&lt;span&gt; String &lt;/span&gt;&lt;span&gt;&lt;span&gt;test&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span&gt;&lt;span&gt;throw&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;new&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;IllegalArgumentException&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;잘못된 입력!&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span&gt;&lt;span&gt;@ExceptionHandler(IllegalArgumentException.class)&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span&gt;&lt;span&gt;public&lt;/span&gt;&lt;/span&gt;&lt;span&gt; ResponseEntity&amp;lt;String&amp;gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;handleIllegalArgument&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(Exception e)&lt;/span&gt;&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span&gt;&lt;span&gt;return&lt;/span&gt;&lt;/span&gt;&lt;span&gt; ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage()); &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; } &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;} &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;2296&quot; data-start=&quot;2293&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2323&quot; data-start=&quot;2298&quot; data-ke-size=&quot;size23&quot;&gt;✅ @ControllerAdvice&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2388&quot; data-start=&quot;2325&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2352&quot; data-start=&quot;2325&quot;&gt;예외 처리를 &lt;b&gt;공통&lt;/b&gt;으로 모아서 작성 가능&lt;/li&gt;
&lt;li data-end=&quot;2388&quot; data-start=&quot;2353&quot;&gt;여러 컨트롤러에서 예외가 발생했을 때 한 곳에서 처리 가능!&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;@ControllerAdvice&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;public&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;class&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;GlobalExceptionHandler&lt;/span&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; @ExceptionHandler(Exception.class)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span&gt;&lt;span&gt;public&lt;/span&gt;&lt;/span&gt;&lt;span&gt; ResponseEntity&amp;lt;String&amp;gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;handleException&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(Exception e)&lt;/span&gt;&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return&lt;/span&gt;&lt;/span&gt;&lt;span&gt; ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;오류 발생: &quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt; + e.getMessage());&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;h2 data-end=&quot;139&quot; data-start=&quot;108&quot; data-ke-size=&quot;size26&quot;&gt;⚠️ @RestControllerAdvice란?&lt;/h2&gt;
&lt;h3 data-end=&quot;149&quot; data-start=&quot;141&quot; data-ke-size=&quot;size23&quot;&gt;✅ 정의&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;291&quot; data-start=&quot;150&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;197&quot; data-start=&quot;150&quot;&gt;@ControllerAdvice + @ResponseBody의 조합힙니다&lt;/li&gt;
&lt;li data-end=&quot;238&quot; data-start=&quot;198&quot;&gt;주로 &lt;b&gt;REST API에서 전역 예외 처리&lt;/b&gt;를 할 때 사용합니다.&lt;/li&gt;
&lt;li data-end=&quot;291&quot; data-start=&quot;239&quot;&gt;반환값이 &lt;b&gt;JSON 형태&lt;/b&gt;로 자동 변환되기 때문에, 프론트엔드와의 통신 시에 유용합니다&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;296&quot; data-start=&quot;293&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;355&quot; data-start=&quot;298&quot; data-ke-size=&quot;size23&quot;&gt;✅ 차이점: @ControllerAdvice vs @RestControllerAdvice&lt;/h3&gt;
&lt;div&gt;&lt;span data-state=&quot;closed&quot;&gt;&lt;/span&gt;
&lt;div&gt;&amp;nbsp;항목&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; @ControllerAdvice&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; @RestControllerAdvice
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;582&quot; data-start=&quot;357&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;582&quot; data-start=&quot;471&quot;&gt;
&lt;tr data-end=&quot;539&quot; data-start=&quot;471&quot;&gt;
&lt;td data-end=&quot;479&quot; data-start=&quot;471&quot;&gt;반환 타입&lt;/td&gt;
&lt;td data-end=&quot;502&quot; data-start=&quot;479&quot;&gt;뷰(View) or JSON (선택)&lt;/td&gt;
&lt;td data-end=&quot;539&quot; data-start=&quot;502&quot;&gt;항상 JSON (자동으로 @ResponseBody 적용)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;582&quot; data-start=&quot;540&quot;&gt;
&lt;td data-end=&quot;548&quot; data-start=&quot;540&quot;&gt;사용 환경&lt;/td&gt;
&lt;td data-end=&quot;565&quot; data-start=&quot;548&quot;&gt;웹 페이지 기반 MVC 앱&lt;/td&gt;
&lt;td data-end=&quot;582&quot; data-start=&quot;565&quot;&gt;REST API 기반 앱&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;587&quot; data-start=&quot;584&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;608&quot; data-start=&quot;589&quot; data-ke-size=&quot;size23&quot;&gt;✅ 예제: 전역 예외 처리기&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;@RestControllerAdvice&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;public&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;class&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;GlobalExceptionHandler&lt;/span&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span&gt;&lt;span&gt;@ExceptionHandler(IllegalArgumentException.class)&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span&gt;&lt;span&gt;public&lt;/span&gt;&lt;/span&gt;&lt;span&gt; ResponseEntity&amp;lt;Map&amp;lt;String, String&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;handleIllegalArgument&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(IllegalArgumentException ex)&lt;/span&gt;&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Map&amp;lt;String, String&amp;gt; error = &lt;/span&gt;&lt;span&gt;&lt;span&gt;new&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;HashMap&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;lt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; error.put(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;error&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;잘못된 요청입니다.&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; error.put(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;message&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;, ex.getMessage());&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span&gt;&lt;span&gt;return&lt;/span&gt;&lt;/span&gt;&lt;span&gt; ResponseEntity.badRequest().body(error);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span&gt;&lt;span&gt;@ExceptionHandler(Exception.class)&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span&gt;&lt;span&gt;public&lt;/span&gt;&lt;/span&gt;&lt;span&gt; ResponseEntity&amp;lt;Map&amp;lt;String, String&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;handleAll&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(Exception ex)&lt;/span&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Map&amp;lt;String, String&amp;gt; error = &lt;/span&gt;&lt;span&gt;&lt;span&gt;new&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;HashMap&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;lt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; error.put(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;error&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;서버 오류 발생&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; error.put(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;message&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;, ex.getMessage());&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span&gt;&lt;span&gt;return&lt;/span&gt;&lt;/span&gt;&lt;span&gt; ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; } &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;} &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1459&quot; data-start=&quot;1387&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1422&quot; data-start=&quot;1387&quot;&gt;예외가 발생하면 JSON 형태로 에러 메시지를 반환해줍니다.&lt;/li&gt;
&lt;li data-end=&quot;1459&quot; data-start=&quot;1423&quot;&gt;Map으로 커스터마이징된 에러 메시지를 구성할 수 있습니다&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1464&quot; data-start=&quot;1461&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1476&quot; data-start=&quot;1466&quot; data-ke-size=&quot;size23&quot;&gt;✅ 실전 팁&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1615&quot; data-start=&quot;1477&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1552&quot; data-start=&quot;1477&quot;&gt;프론트엔드와 협업할 때, 에러 메시지를 통일된 형식으로 전달하기 위해 @RestControllerAdvice 사용을 추천합니다.&lt;/li&gt;
&lt;li data-end=&quot;1615&quot; data-start=&quot;1553&quot;&gt;실제 서비스에서는 예외 응답 형식을 별도의 클래스(ErrorResponse)로 만들어서 사용하기도 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <author>404NotFoundMe</author>
      <guid isPermaLink="true">https://idea5595.tistory.com/18</guid>
      <comments>https://idea5595.tistory.com/18#entry18comment</comments>
      <pubDate>Fri, 18 Apr 2025 10:41:16 +0900</pubDate>
    </item>
  </channel>
</rss>