<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>메모장</title>
    <link>https://sumni.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Wed, 12 Aug 2026 06:39:30 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>dddzr</managingEditor>
    <item>
      <title>HTML, DevTools Sources에 안 보이는 문제 해결 (sourceURL 사용)</title>
      <link>https://sumni.tistory.com/497</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; letter-spacing: 0px;&quot;&gt;개발자 모드에서 디버깅이 필요한데, 소스코드가 보이지 않는 문제가 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  요약 &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;HTML 내부&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;의 마지막에 다음을 추가&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1776388825598&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//# sourceURL={파일명지정}.js&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  1. 문제 상황&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;서버 렌더링 방식으로 HTML을 반환하는 구조에서,&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Chrome DevTools의 Sources 탭에 스크립트가 보이지 않는 문제가 발생.&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;span style=&quot;color: #000000;&quot;&gt;- 에러 메시지&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #188038;&quot;&gt;content unavailable. resource was not cached&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;요청이 리디렉션되었기 때문에 사용 가능한 콘텐츠가 없습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  2. 현재 구조&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 컨트롤러 (서버 렌더링)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1776388887573&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;@RequestMapping(value = &quot;/openPage.do&quot;) 
public ModelAndView openPage(...) {
    ModelAndView mv = setPledgeStatusViewParams(request);
    mv.setViewName(baseUrl + &quot;/page&quot;);
    return mv;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  요청 시 서버에서 &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;age&lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;.html&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;을 렌더링하여 반환한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  3. 원인 분석&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  3-1. inline script는 &amp;ldquo;파일&amp;rdquo;이 아니다&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;HTML 내부에 다음과 같은 &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가 있다고 가정한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// JS 코드&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 스크립트는:&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;별도의 JS 파일이 아님&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;URL(경로)이 없음&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;브라우저가 파일로 식별할 수 없음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  즉, DevTools 기준에서는 &amp;ldquo;파일이 아닌 익명 스크립트&amp;rdquo;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  3-2. Chrome의 처리 방식 (VM 파일)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;브라우저는 이름 없는 스크립트를 다음과 같이 처리한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;VM123&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;VM456&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  임시 가상 파일(VM)로 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 때문에:&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Sources 탭 트리에 안 보이거나&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;어디 코드인지 찾기 어려움&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;브레이크포인트 유지 불가&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  3-3. window.open + redirect 환경 영향&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;서버 렌더링 과정에서 redirect 발생 가능&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;캐시가 없는 상태&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 경우 DevTools는:&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;원본 리소스를 정확히 추적하지 못함&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;파일 기반으로 매핑 실패&lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  4. 해결 방법: sourceURL 사용&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  4-1. 적용 코드&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #188038;&quot;&gt;sourceURL&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;은 브라우저에게 &quot;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;이 스크립트의 이름은 이것이다&amp;rdquo;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;라는 정보를 제공한다.&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;span style=&quot;color: #000000;&quot;&gt;HTML 내부 &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;의 마지막(&lt;/span&gt;&lt;span style=&quot;color: #a4a4a4;&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #87c3ff;&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color: #a4a4a4;&quot;&gt;&amp;gt; 윗줄&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;)에 다음을 추가한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1776389063484&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//# sourceURL=workplace-page.js&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;workplace-page.js라는 이름으로 소스탭에서 파일 확인이 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;  즉, inline script를 파일처럼 다룰 수 있게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DevTools에 고정된 파일명으로 표시됨&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Sources 트리에 노출됨&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;브레이크포인트 가능&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  5. 실무 주의사항&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  5-1. inline script는 최소화한다&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가능하면 외부 JS 파일로 분리하는 것이 가장 안정적이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;lt;script src=&quot;/js/workplace-listPledgeStatus.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  5-2. 동적 실행 환경에서는 디버깅 문제가 발생하기 쉽다&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다음 조건이 겹치면 문제가 잘 발생한다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;inline script&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;window.open&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;redirect&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;캐시 없음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  이 경우 &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;sourceURL&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 매우 유용하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>Frontend/javaScript</category>
      <category>DevTools</category>
      <category>sourceURL</category>
      <category>개발자모드</category>
      <author>dddzr</author>
      <guid isPermaLink="true">https://sumni.tistory.com/497</guid>
      <comments>https://sumni.tistory.com/497#entry497comment</comments>
      <pubDate>Fri, 17 Apr 2026 10:27:57 +0900</pubDate>
    </item>
    <item>
      <title>자바스크립트 모듈 패턴 (IIFE, Closure)</title>
      <link>https://sumni.tistory.com/496</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;  자바스크립트 모듈 패턴을 활용한 안전한 데이터 관리 전략&lt;/span&gt;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;✅ 1. 개요: 전역 변수 선언의 구조적 취약점&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;자바스크립트에서 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #444746;&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt; 키워드를 사용해 파일 최상단에 변수를 선언하는 방식(Global Scope)은 데이터 노출과 오염에 매우 취약하다. 조회용 데이터라 할지라도 브라우저 콘솔을 통해 누구나 접근하고 수정할 수 있다면, 런타임 환경에서 데이터 무결성을 보장할 수 없다. 본 글에서는 즉시 실행 함수(IIFE)와 클로저(Closure)를 활용하여 데이터를 캡슐화하는 모듈 패턴에 대해 기술한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;✅ 2. 개념 및 패턴 기본 구조&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;✅ 2-1. 개념&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #1f1f1f;&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;즉시 실행 함수(IIFE):&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt; 함수 정의와 동시에 실행되는 패턴으로, 내부 변수가 전역 스코프에 침범하는 것을 방지한다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1f1f1f;&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;클로저(Closure):&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt; 함수가 선언될 당시의 렉시컬 환경을 기억하여, 외부 함수가 종료된 후에도 내부 변수에 접근할 수 있는 메커니즘이다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1f1f1f;&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;모듈 패턴(Module Pattern):&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt; 클로저를 이용하여 외부에서 접근 불가능한 Private 변수를 생성하고, 필요한 기능만 Public 메서드로 노출하는 설계 방식이다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;✅ 2-2. 기본 구조&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1775786578408&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var ModuleName = (function() {
    // Private: 외부에서 직접 접근 불가
    var _privateData = []; 

    // Public: 외부로 노출되는 인터페이스
    return {
        setData: function(data) {
            _privateData = data;
        },
        getData: function() {
            return _privateData;
        }
    };
})();&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;✅ 3. 구조적 개선 비교 (Before vs After)&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;✅ 3-1. [Before] 전역 변수 방식 (Global Variable)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;데이터가 전역 스코프에 노출되어 보안과 관리 측면에서 위험하다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775786602791&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 각 JS 파일 최상단 선언
var factoryListRowData = []; 

// 위험성 예시: 콘솔창에서 즉시 변조 가능
// &amp;gt; factoryListRowData = &quot;malicious data&quot;; (기존 데이터 파괴)&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;✅ 3-2. [After] 모듈 패턴 적용 (Encapsulated)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;데이터를 함수 스코프 안에 가두어 외부의 직접적인 접근을 차단한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775786626192&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var FactoryModule = (function() {
    var _factoryListRowData = []; // 금고 내부

    return {
        setList: function(list) {
            _factoryListRowData = list;
        },
        getRow: function(id) {
            return _factoryListRowData.find(function(item) {
                return item.portlet_id === id;
            });
        }
    };
})();

// 호출 시: FactoryModule.getRow('ID01');
// 조작 시도: FactoryModule._factoryListRowData; // undefined (접근 불가)&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;✅ 4. 데이터 검문소 역할을 통한 안정성 확보&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;단순히 변수를 숨기는 것을 넘어, 모듈 패턴은 데이터의 입구(Setter)에 '검문소'를 세워 데이터 무결성을 확보할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;✅4-1. 수정 의도의 명확한 제한 (Validation)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;데이터 입력 시 유효성 검사 로직을 포함하여 잘못된 데이터가 유입되는 것을 방지한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775786646159&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;setList: function(list) {
    if (!Array.isArray(list)) {
        console.error(&quot;배열 형식이 아닙니다.&quot;);
        return;
    }
    _factoryListRowData = list;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;✅4-2. 읽기 전용 상태 구현 (Read-Only)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;최초 1회만 데이터 저장을 허용하여 런타임 중 의도치 않은 수정을 원천 차단한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775786669599&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var isInitialized = false;

return {
    setList: function(list) {
        if (isInitialized) {
            console.warn(&quot;이미 초기화된 데이터는 수정할 수 없습니다.&quot;);
            return; 
        }
        _factoryListRowData = list;
        isInitialized = true;
    }
};&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;✅ 4-3. 디버깅의 효율성 증대 (Traceability)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;데이터 변경이 일어나는 시점에 로깅이나 스택 추적을 수행하여 오류 발생 원인을 빠르게 파악할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775786682975&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;setList: function(list) {
    console.trace(&quot;데이터 변경 추적:&quot;); // 호출 스택 출력
    _factoryListRowData = list;
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;✅ 5. 결론: 모듈 패턴의 필요성&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;모듈 패턴은 관심사의 분리(SoC)를 실현하고, &lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;데이터의 무결성&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;을 보장하며, &lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;예측 가능한 코드&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;를 작성하게 한다. 이는 대규모 프로젝트에서 전역 오염을 방지하고 보안 사고의 실미를 차단하는 가장 기본적인 방어적 프로그래밍의 시작이다!!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt; &lt;/p&gt;</description>
      <category>Frontend/javaScript</category>
      <category>모듈 패턴</category>
      <category>즉시 실행 함수</category>
      <category>클로저</category>
      <author>dddzr</author>
      <guid isPermaLink="true">https://sumni.tistory.com/496</guid>
      <comments>https://sumni.tistory.com/496#entry496comment</comments>
      <pubDate>Fri, 10 Apr 2026 11:05:44 +0900</pubDate>
    </item>
    <item>
      <title>인덱스 파편화와 해결 전략</title>
      <link>https://sumni.tistory.com/495</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  &lt;/span&gt;&lt;/b&gt;UUID PK 사용 시 필수 고려사항: 인덱스 파편화와 해결 전략&lt;/h2&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;span style=&quot;color: #1f1f1f;&quot;&gt;이번에 메뉴테이블의 PK를 시스템 확장성을 위해 Sequence 대신 UUID(Universally Unique Identifier)로 변경하는 작업을 진행했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;하지만 무작위 UUID는 DB 인덱스 성능을 저하 시킬 수 있기에 인덱스 파편화는 UUID PK 채택 시 고려사항 중 하나다!!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;인덱스 관리가 필요한 이유와 실무적인 해결책을 정리한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;1. 인덱스 파편화(Index Fragmentation)의 정의&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;DB 인덱스는 '번호 순서대로 정렬된 백과사전'과 같다. 데이터를 빠르게 찾기 위해 내부적으로 일정한 정렬 상태를 유지해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #1f1f1f;&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;Sequence(1, 2, 3...) 방식:&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt; 새 데이터가 들어오면 기존 인덱스 페이지의 맨 뒤 빈 공간에 차곡차곡 쌓인다. 물리적 저장 순서와 논리적 순서가 일치하여 매우 효율적이다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1f1f1f;&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;UUID(Random) 방식:&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt; 새 값의 ID가 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #444746;&quot;&gt;a1...&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #444746;&quot;&gt;f5...&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt; 처럼 무작위다. 이미 데이터가 꽉 찬 사전 중간 어딘가에 억지로 끼워 넣어야 하는 상황이 발생한다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1f1f1f;&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;페이지 분할(Page Split):&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt; 중간에 자리가 없으면 DB는 기존 데이터를 옆으로 밀거나, 공간 확보를 위해 &lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;페이지를 반으로 쪼개는(Page Split)&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt; 작업을 수행한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;이 과정이 반복되면 인덱스 페이지 내부에 &lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;사용하지 않는 빈 공간&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;이 생기고 데이터가 물리적으로 흩어지게 된다. 이를 **'인덱스 파편화'**라고 부른다!!&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;2. 인덱스 관리가 필요한 이유 (정렬, 검색 성능)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;비즈니스 로직에서 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #444746;&quot;&gt;ORDER BY menu_id&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;를 호출하지 않더라도, 단건 검색(&lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #444746;&quot;&gt;WHERE menu_id = '...'&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;) 성능에 직접적인 타격을 준다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;✅&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;&amp;nbsp;이유 1: 검색 효율(Select) 저하&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;파편화가 심해지면 DB가 읽어야 할 '페이지' 수가 늘어난다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #1f1f1f;&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;&lt;b&gt;정상 상태&lt;/b&gt;:&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt; 데이터 100개가 페이지 1장에 모여 있음 &amp;rarr; &lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;디스크 I/O 1회 발생.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1f1f1f;&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;&lt;b&gt;파편화 상태&lt;/b&gt;:&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt; 데이터 100개가 쪼개진 페이지 10장에 흩어져 있음 &amp;rarr; &lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;디스크 I/O 10회 발생.&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;  결과적으로 동일한 데이터를 조회하더라도 서버 자원을 더 많이 소모하고 응답 속도가 느려진다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;✅&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;&amp;nbsp;이유 2: 삽입 성능(Insert) 저하&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;데이터를 저장할 때마다 최적의 위치를 계산하고 페이지를 쪼개는 추가 연산이 발생한다. 데이터가 쌓일수록 저장 속도가 점진적으로 저하되는 원인이 된다.&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;3. 실무적인 DB 설계 및 대응 전략&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;Oracle 등 주요 DBMS 환경에서 이를 방어하기 위한 3가지 전략이다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;✅ 전략 1: 일반적인 Heap 테이블 방식&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;데이터는 빈 공간에 자유롭게 쌓고(Heap), 인덱스만 별도로 정렬하여 관리하는 가장 보편적인 방식이다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #1f1f1f;&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;정렬, 검색의 기준이 되는 데이터로 보조 인덱스를 생성한다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1f1f1f;&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;만약 정렬/검색이 전혀 이루어 지지 않는다면 보조 인덱스 생성은 생략.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1775629934279&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 테이블 생성 (PK는 UUID)
CREATE TABLE MENU (
    MENU_ID      VARCHAR2(32) NOT NULL,
    MENU_NM      VARCHAR2(100),
    SORT_NUMBER  NUMBER(5), -- 비즈니스 정렬용 컬럼
    CREATED_AT   DATE DEFAULT SYSDATE,
    CONSTRAINT PK_MENU PRIMARY KEY (MENU_ID)
);

-- 실제 조회가 빈번한 SORT_NUMBER와 생성일자에 보조 인덱스 생성
CREATE INDEX IX_MENU_SORT ON MENU (SORT_NUMBER, CREATED_AT);

-- 사용 여부와 메뉴명을 묶은 인덱스 
CREATE INDEX IX_MENU_NAME_SEARCH ON MENU (USE_YN, MENU_NM);&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;✅ 전략 2: 인덱스 리빌드 (운영 단계)&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;랜덤 UUID를 사용 중이라면, 정기적으로 인덱스를 재구성하여 빈 공간을 제거해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #1f1f1f;&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;메뉴 ID(PK)로 검색할 때 성능(속도)를 위해 필요하다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1f1f1f;&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;메뉴 ID(PK)로 검색하는 로직이 아예 없고, 오직 메뉴명(MENU_NM)으로만 검색한다면 PK 인덱스 리빌드는 신경 쓰지 않아도 된다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1f1f1f;&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;보통 트래픽이 적은 시간대에 배치 작업으로 수행하여 인덱스 밀도를 높인다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1775629958510&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 서비스 중단 없이 인덱스 재구성 (Oracle 기준)
ALTER INDEX PK_MENU REBUILD ONLINE;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;✅ 전략 3: Sequential UUID (설계 단계 - 권장)&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;가장 근본적인 해결책이다. Java 등 애플리케이션 레이어에서 &lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;UUID v7&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;이나 &lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;Sequential UUID&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt; 라이브러리를 사용하여 식별자를 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #1f1f1f;&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;특징:&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt; UUID의 유일성은 유지하되, 앞부분에 타임스탬프를 포함하여 생성 순서대로 정렬되는 성질을 갖는다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1f1f1f;&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;장점:&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt; DB 입장에서는 데이터가 순차적으로 들어오는 것으로 인식하여 페이지 분할을 방지하고 삽입 성능을 극대화할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;  요약 및 결론&lt;/span&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1f1f1f;&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;현상:&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt; 랜덤 UUID는 인덱스 중간에 삽입되며 '페이지 분할'과 '파편화'를 유발한다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1f1f1f;&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;결과:&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt; 직접적인 정렬 로직이 없더라도 &lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;조회 성능 저하와 디스크 자원 낭비&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;로 이어진다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1f1f1f;&quot;&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;결론:&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt; 신규 설계 시 &lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;Sequential UUID&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt; 도입을 최우선으로 검토하고, 운영 중인 시스템은 &lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;Index Rebuild&lt;/span&gt;&lt;span style=&quot;color: #1f1f1f;&quot;&gt;를 통해 성능을 유지해야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB/데이터 관리</category>
      <category>Index Fragmentation</category>
      <category>인덱스 파편화</category>
      <author>dddzr</author>
      <guid isPermaLink="true">https://sumni.tistory.com/495</guid>
      <comments>https://sumni.tistory.com/495#entry495comment</comments>
      <pubDate>Wed, 8 Apr 2026 15:34:00 +0900</pubDate>
    </item>
    <item>
      <title>Functional Interface(함수형 인터페이스)</title>
      <link>https://sumni.tistory.com/494</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1. &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Functional Interface(함수형 인터페이스)란?&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;단 하나의 추상 메서드만 가지는 인터페이스&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;를 말함. (&lt;/span&gt;&lt;span style=&quot;background-color: #f1f1f1; color: #000000;&quot;&gt;default, static 메서드는 추가로 있어도 상관x)&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 인터페이스를 사용하면 람다식(Lambda Expression)이나 메서드 참조(Method Reference)로 구현 가능.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;자바 8부터 도입됨.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  즉, &amp;ldquo;하나의 기능을 표현하는 인터페이스&amp;rdquo;라고 생각하면 편함.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예시&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775522776882&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// *@FunctionalInterface = 단 하나의 추상 메서드만 가지도록 강제하는 어노테이션
@FunctionalInterface
public interface MyFunctionalInterface {
    void doSomething(); // 단 하나의 추상 메서드
}

// 람다식으로 구현 가능:
MyFunctionalInterface f = () -&amp;gt; System.out.println(&quot;Hello, Functional Interface!&quot;);
f.doSomething(); // 출력: Hello, Functional Interface!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2. 자바에서 제공하는 대표 Functional Interface&lt;/span&gt;&lt;/h2&gt;
&lt;div&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 style=&quot;width: 11.9767%;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;인터페이스&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.1395%;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;메서드&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 24.0698%;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;용도&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50.814%;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예제&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.9767%;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Supplier&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.1395%;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;T get()&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 24.0698%;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;값 공급, 지연 생성, 기본값&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50.814%;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Supplier&amp;lt;String&amp;gt; s = () -&amp;gt; &quot;Hello&quot;; s.get(); // &quot;Hello&quot;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.9767%;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Consumer&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.1395%;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;void accept(T t)&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 24.0698%;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;입력값 소비, 처리만 하고 반환 없음&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50.814%;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Consumer&amp;lt;String&amp;gt; c = s -&amp;gt; System.out.println(s); c.accept(&quot;Hi&quot;);&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.9767%;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Function&amp;lt;T,R&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.1395%;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;R apply(T t)&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 24.0698%;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;입력값 변환, 매핑, 계산&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50.814%;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Function&amp;lt;Integer,String&amp;gt; f = n -&amp;gt; &quot;Number: &quot;+n; f.apply(5); // &quot;Number: 5&quot;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.9767%;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Predicate&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.1395%;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;boolean test(T t)&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 24.0698%;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;조건 검사, 필터링&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50.814%;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Predicate&amp;lt;String&amp;gt; p = s -&amp;gt; s.length()&amp;gt;3; p.test(&quot;Hi&quot;); // false&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  추가 포인트&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Supplier&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &amp;rarr; Stream.generate(), 기본값, 난수 등&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Consumer&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &amp;rarr; Stream.forEach(), 값 처리만&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Function&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &amp;rarr; Stream.map(), 값 변환&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Predicate&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &amp;rarr; Stream.filter(), 조건 검사&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 3. 사용 이유&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&quot;그냥 메서드 직접 쓰기&quot;랑 비교했을 때 뭐가 좋을까?&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;span style=&quot;color: #000000;&quot;&gt;  공통적으로: 단순 실행보단&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;재사용성 + 조합성 + 스트림 API 활용성&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;때문에 유용하다!!&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Consumer&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr; &quot;실행 동작을 넘겨줄 수 있다&quot;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Function&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr; &quot;변환 로직을 독립시켜 재사용/조합할 수 있다&quot;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Predicate&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr; &quot;조건식을 객체화해서 필터링과 조합에 강력하다&quot;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Supplier&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr; &quot;값을 생성하는 책임을 분리할 수 있다&quot;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 3-1. Supplier 사용 이유&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1775522871584&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Supplier&amp;lt;Double&amp;gt; randomSupplier = () -&amp;gt; Math.random();
System.out.println(randomSupplier.get()); // 0~1 사이 난수&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;⭐ 그냥 &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Math.random()&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 호출하면 되는데 왜 Supplier?&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 1️⃣ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;지연 실행&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &amp;rarr; &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;get()&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 호출할 때만 실행됨 (Lazy Evaluation). 불필요한 자원 낭비를 줄이고 효율적으로 실행.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 2️⃣ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;재사용성&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &amp;rarr; 값 생성 로직을 변수로 저장해서 여러 곳에서 활용 가능.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 3️⃣ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;전략 교체 용이&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &amp;rarr; randomSupplier = () -&amp;gt; new Random().nextDouble();&amp;rarr; 구현체 교체 가능, 호출 코드는 그대로 randomSupplier.get() 사용&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 4️⃣ 스트림/테스트에서 유용 &amp;rarr; Stream.generate(randomSupplier) 가능(무한스트림, .limit(N)으로 제한), 테스트 시 고정값 주입 가능.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;➡️ 즉, &quot;즉시 실행&quot;이 아니라 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&quot;값을 공급하는 동작을 객체화해서 유연하게 쓸 수 있다&quot;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 가 장점.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 3-&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2. Consumer&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 사용 이유&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1775522880999&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Consumer&amp;lt;String&amp;gt; printer = s -&amp;gt; System.out.println(&quot;Hello, &quot; + s);
printer.accept(&quot;Java&quot;); // Hello, Java&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;⭐ 그냥 &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;System.out.println(&quot;Hello, Java&quot;)&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 쓰면 되는데 왜 Consumer?&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 1️⃣ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;재사용성&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &amp;rarr; Consumer를 변수로 저장해서 여러 군데 넘겨 쓸 수 있음.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 2️⃣ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;조합 가능&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &amp;rarr; &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;andThen&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 같은 메서드 체이닝 지원 &amp;rarr; 여러 Consumer를 합쳐서 실행 가능.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 3️⃣ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;전략 교체 용이&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &amp;rarr; 같은 메서드 로직이라도 상황에 따라 다른 Consumer를 주입 가능 (DI, 전략 패턴처럼).&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;➡️ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;즉, &quot;한번 실행&quot;보다 &quot;동작을 넘기고, 조합하고, 교체할 수 있다&quot;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 가 장점.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 3-&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3. Function&amp;lt;T, R&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 사용 이유&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1775522891975&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Function&amp;lt;Integer, String&amp;gt; intToStr = i -&amp;gt; &quot;Number: &quot; + i;
System.out.println(intToStr.apply(10)); // Number: 10&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;⭐ 그냥 &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;(&quot;Number: &quot; + 10)&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 해도 되는데 Function을 쓰는 이유?&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 1️⃣ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;맵핑 로직을 변수화&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &amp;rarr; 변환 과정을 객체처럼 전달할 수 있음.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 2️⃣ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;스트림 API에서 강력&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &amp;rarr; &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;map(Function)&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 과 같이 데이터 흐름에서 변환에 활용.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 3️⃣ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;함수 합성 지원&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &amp;rarr; &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;andThen&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;compose&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 로 여러 Function을 합쳐서 파이프라인 처리 가능.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;➡️ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;즉, &quot;데이터 변환 로직을 독립시켜 재사용 + 스트림 처리에 최적화&quot;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 3-&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;4. Predicate&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 사용 이유&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1775522898728&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Predicate&amp;lt;Integer&amp;gt; isEven = n -&amp;gt; n % 2 == 0;
System.out.println(isEven.test(4)); // true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;⭐ 그냥 &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;if (n % 2 == 0)&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 하면 되는데 왜 Predicate?&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 1️⃣ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;조건을 객체처럼 전달 가능&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &amp;rarr; 메서드 파라미터로 &quot;조건&quot;을 넘겨줄 수 있음.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 2️⃣ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;스트림 필터링에서 핵심&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &amp;rarr; &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;filter(Predicate)&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 와 같이 조건을 활용.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 3️⃣ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;조건 조합 가능&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &amp;rarr; &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;and&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;or&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;negate&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 등으로 여러 조건을 유연하게 합칠 수 있음.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;➡️ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;즉, &quot;조건을 코드로 직접 쓰는 대신, 독립된 객체로 다루면서 조합/전달 가능&quot;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  4. 참고 - &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Java에서 제공하는 Functional Interface 전체&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;자바 8 이후 &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;java.util.function&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 패키지에 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;약 43개 정도&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가 있음 (2~3에서 설명한 대표4개만 알아두자.. )&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;크게 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;입력/출력/조건/조합/특화형&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;으로 나뉜다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;*Runnable과 Callable도 Functional Interface의 일종이다!!&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1️⃣ 입력과 출력 기준&lt;/span&gt;&lt;/h3&gt;
&lt;div&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;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;타입&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예시&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;매개변수 X, 리턴 O&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Supplier&amp;lt;T&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;매개변수 O, 리턴 X&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Consumer&amp;lt;T&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;BiConsumer&amp;lt;T,U&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;매개변수 O, 리턴 O&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Function&amp;lt;T,R&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;BiFunction&amp;lt;T,U,R&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;매개변수 O, 리턴 boolean&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Predicate&amp;lt;T&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;BiPredicate&amp;lt;T,U&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2️⃣ 특화형(Primitive용)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;성능 최적화 위해 int, long, double 버전 제공&lt;/span&gt;&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 style=&quot;width: 16.2791%;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;타입&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 83.7209%;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;예시&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.2791%;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;int&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 83.7209%;&quot;&gt;&lt;span style=&quot;color: #188038;&quot;&gt;IntSupplier&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;IntConsumer&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;IntFunction&amp;lt;R&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;IntPredicate&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.2791%;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;long&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 83.7209%;&quot;&gt;&lt;span style=&quot;color: #188038;&quot;&gt;LongSupplier&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;LongConsumer&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;LongFunction&amp;lt;R&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;LongPredicate&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.2791%;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;double&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 83.7209%;&quot;&gt;&lt;span style=&quot;color: #188038;&quot;&gt;DoubleSupplier&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;DoubleConsumer&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;DoubleFunction&amp;lt;R&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;DoublePredicate&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3️⃣ 조합용&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;기존 Functional Interface를 연결하거나 변형할 때 사용&lt;/span&gt;&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 style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;예시&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;설명&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;color: #188038; text-align: start;&quot;&gt;UnaryOperator&amp;lt;T&amp;gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;Function&amp;lt;T,T&amp;gt;와 같음, 자기 자신으로 매핑&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;color: #188038; text-align: start;&quot;&gt;BinaryOperator&amp;lt;T&amp;gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;BiFunction&amp;lt;T,T,T&amp;gt;와 같음, 두 값으로 결과 생성&lt;/span&gt;&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;</description>
      <category>Backend/JAVA</category>
      <category>functional interface</category>
      <category>함수형 인터페이스</category>
      <author>dddzr</author>
      <guid isPermaLink="true">https://sumni.tistory.com/494</guid>
      <comments>https://sumni.tistory.com/494#entry494comment</comments>
      <pubDate>Tue, 7 Apr 2026 09:54:13 +0900</pubDate>
    </item>
    <item>
      <title>Docker 개념 및 예제</title>
      <link>https://sumni.tistory.com/493</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  0. Docker 개념&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 0-1. 개념&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Docker는 응용 프로그램과 그 의존성을 하나의 패키지로 묶어 실행할 수 있는 컨테이너 기술&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Docker: 가장 널리 사용하는 컨테이너 엔진&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨테이너 엔진: 컨테이너를 생성하고 실행하는 소프트웨어 (컨테이너 구현 기술)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨테이너: 애플리케이션을 실행하기 위한 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;격리된 실행 환경&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; (OS커널 공유, VM보다 가볍고 빠름)&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;VM&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;: OS까지 포함한 완전한 가상환경&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨테이너&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;: OS 없이 실행 환경만 격리&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 0-2. 사용 이유&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  성능 때문 ❌&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  운영/관리 때문 ⭕&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;환경 통일: 내 PC&amp;middot;팀원&amp;middot;서버 어디서든 동일한 실행 환경 보장&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;버전 관리: 이미지로 버전을 고정하여 환경 충돌 없이 안정적인 실행 가능&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;한 번에 실행: DB&amp;middot;Redis&amp;middot;서비스 등을 한 번에 실행하여 세팅 시간 최소화&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;격리 (Isolation): 서비스별로 분리되어 포트 및 라이브러리 충돌 방지&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;삭제/초기화 쉬움: 명령어 한 번으로 환경을 빠르게 초기화하고 재구성 가능&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;확장성: 서비스를 쉽게 추가&amp;middot;확장하고 독립적으로 실행 및 테스트 가능&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;⭐ Tip&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; Docker 이미지는 보통 인터넷에서 다운로드&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Docker Hub / 사설 레지스트리 &amp;rarr; pull &amp;rarr; 로컬 저장&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 폐쇠망에서는?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이미지 파일로 옮김&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker save -o mariadb.tar mariadb:10.6&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker load -i mariadb.tar&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✔ 외부망 &amp;rarr; 내부망 이동 가능&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✔ 폐쇄망에서도 사용 가능&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 0-3. 설치 가능 서비스 예시&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;데이터베이스 및 캐시 (RDBMS: MariaDB / NoSQL: MongoDB / 캐시: Redis 등)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;메시지 브로커 (Kafka, RabbitMQ 등)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;웹 서버 및 애플리케이션 서버 (웹 서버: Nginx / 애플리케이션 서버: Tomcat 등)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;개발 도구 (CI/CD 툴: Jenkins / 코드 품질 분석: ESLint / 로컬 개발 환경: Adminer )&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;빅데이터 및 분석 ( Hadoop / Elasticsearch + Kibana (ELK Stack) / Spark )&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;네트워크 및 보안 (프록시 서버 / 보안 스캐너)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;모니터링 및 로깅&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;머신러닝 및 데이터 사이언스&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;기타 (버전 관리 및 협업: Git, SVN / CMS / VPN 및 네트워크 관리)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;운영 자동화 (Ansible AWX, Terraform)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  1. Docker 기본&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 1-1. Docker 설치 (윈도우 기준)  &lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  Docker Desktop 설치&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;a href=&quot;https://www.docker.com/products/docker-desktop/&quot;&gt;https://www.docker.com/products/docker-desktop/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✔ 그냥 Next Next 설치&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✔ WSL2 자동 설정&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;설치 완료 시 아래 두개 창이 뜸. (둘 다 닫아도 된다.)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Qxvq7/dJMcaaY8nCK/nnOa3A4oxJX6opNKuLipAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Qxvq7/dJMcaaY8nCK/nnOa3A4oxJX6opNKuLipAK/img.png&quot; data-origin-width=&quot;1582&quot; data-origin-height=&quot;892&quot; data-is-animation=&quot;false&quot; width=&quot;340&quot; data-widthpercent=&quot;53&quot; style=&quot;width: 52.3811%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Qxvq7/dJMcaaY8nCK/nnOa3A4oxJX6opNKuLipAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQxvq7%2FdJMcaaY8nCK%2FnnOa3A4oxJX6opNKuLipAK%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;1582&quot; height=&quot;892&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0xtCk/dJMcaadMUXy/nlZNSG4NhQrwN79XzOa7IK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0xtCk/dJMcaadMUXy/nlZNSG4NhQrwN79XzOa7IK/img.png&quot; data-origin-width=&quot;1348&quot; data-origin-height=&quot;857&quot; data-is-animation=&quot;false&quot; width=&quot;434&quot; style=&quot;width: 46.4561%;&quot; data-widthpercent=&quot;47&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0xtCk/dJMcaadMUXy/nlZNSG4NhQrwN79XzOa7IK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0xtCk%2FdJMcaadMUXy%2FnlZNSG4NhQrwN79XzOa7IK%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;1348&quot; height=&quot;857&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt; &lt;/span&gt; Docker Desktop =&amp;gt; 작업표시줄에서 Docker Desktop이 실행중인지 확인 (미실행 중이면 docker 명령어 안 먹음)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt; &lt;/span&gt; WSL(Windows Subsystem for Linux) =&amp;gt; WSL 직접 쓸 필요 거의 없음, 그냥 Docker 쓰면 자동으로 돌아감&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;span style=&quot;color: #000000;&quot;&gt;  확인 방법. Version이 2면 제대로 실행중.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775520613880&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ wsl -l -v
  NAME              STATE           VERSION
* docker-desktop    Running         2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;*후에 성능 최적화 필요시 wsl에 우분투를 깔고, wsl 내부에서 도커 실행 가능하나 지금은 넘어간다!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  설치 후&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775520602497&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 설치 버전 확인
docker --version

# Docker Desktop 실행 중인지 확인
docker p&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅1-2. 컨테이너 실행 확인&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1579&quot; data-origin-height=&quot;892&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWVQGK/dJMcaiizdhy/stilwRBHIvv53r2FMFB551/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWVQGK/dJMcaiizdhy/stilwRBHIvv53r2FMFB551/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWVQGK/dJMcaiizdhy/stilwRBHIvv53r2FMFB551/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWVQGK%2FdJMcaiizdhy%2FstilwRBHIvv53r2FMFB551%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;713&quot; height=&quot;403&quot; data-origin-width=&quot;1579&quot; data-origin-height=&quot;892&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt; &lt;/span&gt; 컨테이너 실행&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775520645201&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run hello-world&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✔ Docker 설치하면 docker 명령어가 시스템 PATH에 등록됨 어느 경로에서든 명령어 실행 가능&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;span style=&quot;color: #000000;&quot;&gt;  성공하면 도커 정상 작동 (성공 출력)&lt;/span&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1775520666690&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ docker run hello-world
Unable to find image 'hello-world:latest' locally # ✔️이미지 로컬에서 찾을 수 없어서 다운로드 시작
latest: Pulling from library/hello-world # ✔️Docker Hub에서 이미지 받아옴
17eec7bbc9d7: Pull complete
ea52d2000f90: Download complete
Digest: sha256:85404b3c53951c3ff5d40de0972b1bb21fafa2e8daa235355baf44f33db9dbdd
Status: Downloaded newer image for hello-world:latest

Hello from Docker! # ✔️컨테이너 실행성공
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the &quot;hello-world&quot; image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/​&lt;/code&gt;&lt;/pre&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 2. 컨테이너 관리&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅2-1. Docker 핵심 명령어 정리&lt;/span&gt;&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;div&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;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;명령어&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;설명&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;언제 씀&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예시&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker ps&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;실행 중 컨테이너만 조회&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;지금 돌아가는 것 확인&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker ps&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker ps -a&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;전체 컨테이너 조회 (종료 포함)&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;과거 실행 기록 확인&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker ps -a&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker run&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨테이너 생성 + 실행&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;처음 실행할 때&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker run nginx&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker start&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;중지된 컨테이너 다시 시작&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;재사용&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker start my-container&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker stop&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;실행 중 컨테이너 종료&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;종료할 때&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker stop my-container&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker restart&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;재시작&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;설정 변경 후&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker restart my-container&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker rm&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨테이너 삭제&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;완전히 제거&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker rm my-container&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker images&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이미지 목록 조회&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다운로드된 이미지 확인&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker images&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker rmi&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이미지 삭제&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;용량 정리&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker rmi nginx&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker logs&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨테이너 로그 확인&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;에러/디버깅&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker logs my-container&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker exec&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨테이너 내부 접속&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DB 확인, 테스트&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker exec -it my-container bash&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker pull&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이미지 다운로드&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;미리 받아둘 때&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker pull nginx&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker build&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이미지 직접 생성&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Dockerfile 사용 시&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker build .&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅2-2. 개별 컨테이너 실행&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;각 컨테이너를 일일이 docker run으로 실행해야 해서 잘 쓰지 않는다!!&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775520727072&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# MariaDB
docker run -d \
 --name mariadb \
 -e MYSQL_ROOT_PASSWORD=root \
 -p 3306:3306 \
 -v mariadb_data:/var/lib/mysql \
 mariadb:10.6

# Redis
docker run -d \
 --name redis \
 -p 6379:6379 \
 -v redis_data:/data \
 redis&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  단점&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨테이너 간 의존성 관리 힘듦 (depends_on 같은 기능 없음)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;네트워크 연결 직접 설정 필요&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;서비스 추가/삭제 시 명령어 길게 반복&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;멀티 컨테이너 환경에서 실행 순서 관리 어려움&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  3. Docker Compose&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 3-1. Docker Compose 개념&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Docker Compose = 여러 컨테이너를 한 번에 정의하고 실행하는 도구&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker-compose.yml 한 파일 안에서 서비스(컨테이너) 정의 + 포트 + 환경 변수 + 볼륨 + 네트워크 모두 관리&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;명령어 한 번(docker-compose up -d)으로 여러 컨테이너 실행, 연결, 데이터 영속성까지 처리 가능&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;개발 환경에서 MSA/인프라 전체 스택 구성할 때 매우 유용&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  장점&lt;/span&gt;&lt;/p&gt;
&lt;div&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;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;항목&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;장점&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;자동화&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;단일 명령어로 모든 서비스 실행 가능&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;연결 관리&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨테이너끼리 네트워크 이름으로 바로 통신 가능&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;환경 분리&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;dev/test/prod 환경 별 Compose 파일 가능&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;재현성&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;팀원 모두 동일 환경 재현 가능&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 3-2. docker-compose.yml 작성&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker-compose.yml은 &amp;ldquo;프로젝트 폴더 루트&amp;rdquo;에 둔다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  Spring Boot(application.properties) 예시&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775520779664&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# DB (3307)
spring.datasource.url=jdbc:mariadb://localhost:3307/mydb
# 다른 컨테이너로 접근할 때 (localhost X &amp;rarr; 컨테이너 이름, 3306)
# spring.datasource.url=jdbc:mariadb://mariadb:3306/mydb
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update #테이블 자동 생성

# Redis
spring.redis.host=localhost
spring.redis.port=6379&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;* mariadb는 이미 로컬에서 3306으로 수행 중.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;학습을 위해 3307로 테스트. 실제로는 이미 데이터 들어있어서 그냥 로컬 썼음.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;service.msc에서 로컬 db 종료하고 도커에서 3306써도 됨. (동시 실행 불가)&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;span style=&quot;color: #000000;&quot;&gt;  docker-compose.yml 예시&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1775520826737&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;services:
  mariadb:
    image: mariadb:10.6
    container_name: mariadb
    environment:
      MYSQL_ROOT_PASSWORD: root
    ports:
      - &quot;3307:3306&quot; # 로컬 PC에 mariaDB가 있어서 포트 변경
    volumes:
      - mariadb_data:/var/lib/mysql   # DB 데이터 영구 저장

  redis:
    image: redis
    container_name: redis
    ports:
      - &quot;6379:6379&quot;
    volumes:
      - redis_data:/data             # Redis 데이터 저장

volumes:
  mariadb_data:
  redis_data:​&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  설정 항목&lt;/span&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;div&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;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;항목&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;역할&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예시&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;환경 변수&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨테이너 내부 설정 전달&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;MYSQL_ROOT_PASSWORD=root&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;포트&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;호스트 &amp;harr; 컨테이너 매핑&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3306:3306, 6379:6379&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;네트워크&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨테이너끼리 통신&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;app &amp;harr; mariadb 동일 네트워크&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;볼륨&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;데이터 영속성&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;/var/lib/mysql &amp;rarr; mariadb_data&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 3-3. 실행/종료&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;735&quot; data-origin-height=&quot;222&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cd8iMu/dJMcagrv9ER/uOUX7KiP8AtvB5iFLrz6iK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cd8iMu/dJMcagrv9ER/uOUX7KiP8AtvB5iFLrz6iK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cd8iMu/dJMcagrv9ER/uOUX7KiP8AtvB5iFLrz6iK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcd8iMu%2FdJMcagrv9ER%2FuOUX7KiP8AtvB5iFLrz6iK%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;695&quot; height=&quot;210&quot; data-origin-width=&quot;735&quot; data-origin-height=&quot;222&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;프로젝트 루트 경로(docker-compose.yml와 같은 경로)에서 실행.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 생성, 실행: up&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775520848625&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker-compose up -d&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨테이너 없으면 &amp;rarr; 생성 + 실행&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨테이너 있으면 &amp;rarr; (Compose.yml 수정) 변경사항 반영해서 &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; 재생성 + 실행&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;*Dockerfile 수정 시: docker-compose up -d --build &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;rarr; &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;시작 + 생성 + 실행&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;span style=&quot;color: #000000;&quot;&gt; 제거: down&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775520868384&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker-compose down&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨테이너 삭제&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;네트워크 삭제&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;✔ &amp;ldquo;완전히 종료 + 제거&amp;rdquo;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;❗volume은 기본 유지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 정지: stop&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775520876609&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker-compose stop&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨테이너 &amp;ldquo;정지&amp;rdquo;만 함&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;삭제 안 함 &lt;/span&gt;&amp;ldquo;일시정지 느낌&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 재실행: start&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775520881713&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker-compose start&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;stop된 컨테이너 다시 실행&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✔ &amp;ldquo;재시작 (이미 존재해야 함)&amp;rdquo;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 정지, 재실행: restrart&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775521002016&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker-compose restart&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;stop + start&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 4. 볼륨(volume)&amp;nbsp;&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1578&quot; data-origin-height=&quot;894&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zxqZ8/dJMcahcTmTG/fM6hnFuAdOjEp4Q9YrhSOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zxqZ8/dJMcahcTmTG/fM6hnFuAdOjEp4Q9YrhSOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zxqZ8/dJMcahcTmTG/fM6hnFuAdOjEp4Q9YrhSOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzxqZ8%2FdJMcahcTmTG%2FfM6hnFuAdOjEp4Q9YrhSOk%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;758&quot; height=&quot;429&quot; data-origin-width=&quot;1578&quot; data-origin-height=&quot;894&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅4-1. Volume 개념&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Volume=데이터 영속성&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Docker 볼륨 = 컨테이너 외부에 데이터를 저장하는 공간&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨테이너는 원래 임시 공간에서 동작 &amp;rarr; 삭제 시 데이터도 삭제&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;볼륨을 쓰면 컨테이너 삭제 후에도 데이터 유지 가능&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  예시: DB 데이터 저장&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨테이너 내부 기준: /var/lib/mysql (MariaDB)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여기 안에 DB 파일, 테이블, 인덱스, 로그 등 모두 저장&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 4-2. 볼륨 종류&lt;/span&gt;&lt;/h3&gt;
&lt;div&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;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;종류&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;설명&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예시&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Named Volume (추천)&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Docker가 관리, 안전하게 데이터 유지&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;mariadb_data:/var/lib/mysql&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Bind Mount&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;PC 경로와 컨테이너 연결, 파일 직접 확인 가능&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;./dbdata:/var/lib/mysql&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;✔&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;실무 기준: 기본은 Named Volume, 필요 시 Bind Mount&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 4-3. 볼륨 확인 방법&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1️⃣ 볼륨 리스트 확인&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker volume ls&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2️⃣ 볼륨 실제 경로 확인&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker volume inspect mariadb_data&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  결과 예시:&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775521052999&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[
 {
   &quot;Name&quot;: &quot;mariadb_data&quot;,
   &quot;Mountpoint&quot;: &quot;/var/lib/docker/volumes/mariadb_data/_data&quot;
 }
]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;✔&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;/var/lib/docker/volumes/mariadb_data/_data &amp;larr; 실제 DB 파일 저장 위치&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 4-4. 인프라 초기화 예제&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;많이 쓰는 외부 인프라 MariaDB와 Redis로 실습해보았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;*GUI에서도 생성/확인 가능하다!!&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;span style=&quot;color: #000000;&quot;&gt;  인프라 초기화 총정리&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker-compose up -d &amp;rarr; 공용 MariaDB, Redis, ES 컨테이너 실행&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;MariaDB 접속 &amp;rarr; 서비스별 DB 생성 (orders, products)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;테이블 생성 &amp;rarr; SQL 직접 작성 또는 Spring Boot JPA 자동 생성&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Redis 초기화 &amp;rarr; redis-cli 사용&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;서비스 실행 &amp;rarr; DB/Redis 연결 확인 &amp;rarr; 볼륨 덕분에 데이터 영구 저장&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 4-4-1. mariaDB&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2026-03-17 163430.png&quot; data-origin-width=&quot;1578&quot; data-origin-height=&quot;885&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Lxh5m/dJMcacCFWt5/j3V8LSHqW8oPYrvRxBixi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Lxh5m/dJMcacCFWt5/j3V8LSHqW8oPYrvRxBixi0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Lxh5m/dJMcacCFWt5/j3V8LSHqW8oPYrvRxBixi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLxh5m%2FdJMcacCFWt5%2Fj3V8LSHqW8oPYrvRxBixi0%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;423&quot; data-filename=&quot;화면 캡처 2026-03-17 163430.png&quot; data-origin-width=&quot;1578&quot; data-origin-height=&quot;885&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1️⃣ MariaDB 접속 및 DB 생성&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;① 컨테이너 내부 접속&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775521149784&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker exec -it common-mariadb mysql -uroot -p
# 비밀번호: root&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;&lt;span style=&quot;color: #000000;&quot;&gt;② 호스트에서 접속 (포트 매핑 활용)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775521155294&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mysql -h 127.0.0.1 -P 3306 -uroot -p&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;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;③ 서비스별 DB 생성&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775521137384&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- Order 서비스용 DB
CREATE DATABASE orders;

-- Product 서비스용 DB
CREATE DATABASE products;

-- 권한 부여 (root 계정은 기본으로 모든 DB 접근 가능, 필요 시 별도 계정 생성)
GRANT ALL PRIVILEGES ON orders.* TO 'root'@'%';
GRANT ALL PRIVILEGES ON products.* TO 'root'@'%';
FLUSH PRIVILEGES;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  포인트: 공용 MariaDB 하나지만, DB 이름만 다르게 생성 &amp;rarr; MSA 서비스별 데이터 분리&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2️⃣ 테이블 생성&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;  방법 1: &lt;/span&gt;SQL 직접 작성 (기존 코드 없을 때!!)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775521123234&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- orders DB
USE orders;

CREATE TABLE order_info (
  id BIGINT AUTO_INCREMENT PRIMARY KEY,
  user_id BIGINT NOT NULL,
  product_id BIGINT NOT NULL,
  quantity INT NOT NULL,
  status VARCHAR(50) DEFAULT 'ORDERED',
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;  방법 2:&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;/b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Spring Boot JPA 자동 생성 (기존 코드 있을 )&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- application.properties 예시 (Order 서비스 기준)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775521106967&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# DB
spring.datasource.url=jdbc:mariadb://localhost:3306/orders
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;JPA 엔티티 기반으로 테이블 자동 생성&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;장점: 코드 중심 테이블 관리, 컨테이너 재시작해도 볼륨 덕분에 데이터 유지&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;단점: 운영 환경에서는 SQL 스크립트/마이그레이션 툴 권장&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3️⃣ 테이블 조회&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  방법 1: Docker Desktop &amp;rarr; 컨테이너 접속&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;mariadb 컨테이너 Terminal에서.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775521209206&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mysql -u root -p
비번: root
SHOW DATABASES;
USE orders;
SHOW TABLES;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  방법 2: DB 툴 (추천  )&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  연결 정보&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;host: localhost&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;port: 3307 (나는 로컬에 mariaDB가 3306써서 이렇게 설정함)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;user: root&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;password: root&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;database: orders&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;# DB&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;spring.datasource.url=jdbc:mariadb://localhost:3307/orders&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ IDE에서 실행할 때&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;jdbc:mariadb://&lt;span style=&quot;color: #188038;&quot;&gt;localhost:3307&lt;/span&gt;/orders&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;span style=&quot;color: #000000;&quot;&gt;✅ Docker 안에서 실행할 때&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;jdbc:mariadb://&lt;span style=&quot;color: #188038;&quot;&gt;mariadb:3306&lt;/span&gt;/orders&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 4-4-2. Redis 초기화 / 확인&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt; &lt;/span&gt; 컨테이너 접속:&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker exec -it common-redis redis-cli&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;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt; &lt;/span&gt; 데이터 확인 / 삭제&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; KEYS *&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; # 모든 key 확인&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; FLUSHALL&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; # 모든 데이터 삭제 (초기화)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  Redis는 기본적으로 메모리 기반이라 초기화는 이렇게 CLI로 간단하게 가능&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  5. Docker 네트워크 &amp;amp; DNS&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  컨테이너는 각각 localhost를 가진다&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;각 컨테이너는 다른 컴퓨터 취급&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;localhost = 자기 자신&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  컨테이너 간 통신 방법&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Docker Compose는 컨테이너끼리 통신용 DNS를 자동 생성한다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;서비스 이름으로 통신 (&lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;eureka-server&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  외부 &amp;harr; 컨테이너 통신&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;포트 매핑 (&lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;8761:8761&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;포트 포워딩(port mapping) =&amp;gt; 내 로컬 PC에서 실행중인 프로그램 or 브라우저로 직접 접속 시에는, localhost로 컨테이너에서 실행중인 서비스에 접속가능하다!!&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;span style=&quot;color: #000000;&quot;&gt;  컨테이너 &amp;rarr; 로컬 PC 접근&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Host.docker.internal =&amp;gt; &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Docker가 특별히 제공하는 가짜 DNS 이름&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;*Linux는 안 될수도 있다고 한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  네트워크 흐름 총정리&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775521478893&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[내 PC]
   localhost:8080  &amp;rarr; 컨테이너 (포트포워딩)
   localhost:8761  &amp;rarr; 컨테이너 (포트포워딩)

[컨테이너 내부]
   localhost       &amp;rarr; 자기 자신 ❌
   eureka-server   &amp;rarr; 다른 컨테이너 ✅
   host.docker.internal &amp;rarr; 내 PC ✅&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  6. 환경변수&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;로컬/컨테이너 실행환경이 다르기 때문에 환경변수 설정이 필요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Docker-compose.yml에 환경 변수 설정하면 application.yml 설정 덮어써서 로컬실행, 도커실행 둘다 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;✅&lt;/span&gt; 6-1. 환경 변수 이름&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Spring boot 설정파일 (application.yml or application-properties)랑 매핑된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;eureka.client.service-url.defaultZone&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;darr;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;EUREKA_CLIENT_SERVICEURL_DEFAULTZONE&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;span style=&quot;color: #000000;&quot;&gt;  예시&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775521581373&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 로컬 pc에서 서비스 실행 시 (eureka, gateway)
# application.yml
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
&amp;darr;
# 도커쓰면 서비스 네임으로 컨테이너 간 통신
# docker-compose.yml
environment:
 - EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:8761/eureka/&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  7. 실습: MSA 공통 인프라 자동 실행&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;기존 존재하던 MSA 프로젝트에서 애플리케이션 인프라를 컨테이너 시작 시 같이 실행되게 하려고한다!&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;eureka-server와 api-gateway는 공통 인프라는 변경이 적고, 항상 먼저 실행되어야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨테이너로 고정 실행하여 안정적으로 서비스 의존성 순서 보장 (eureka &amp;rarr; gateway &amp;rarr; 서비스)하고자 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;비즈니스 서비스(order, product 등)는 개별로 수동 실행&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 7-1. Compose.yml 수정 (나머지 부분은 3번 예제 참고!)&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;포트 매핑&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Healthcheck과 depends_on으로 실행 순서 제어. (의존성 관리)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Environment로 환경변수 설정&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Profile 설정&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1775521610741&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; # =====================
  # 자동 시작 MSA
  # =====================
  eureka-server:
    build: ./eureka
    container_name: eureka-server
    ports:
      - &quot;8761:8761&quot;
    depends_on:  # 리스트 방식 (예시임. 얘는 의존성 필요없다)
      - mariadb
    healthcheck:
      test: [&quot;CMD&quot;, &quot;curl&quot;, &quot;-f&quot;, &quot;http://localhost:8761/actuator/health&quot;]
      interval: 5s
      retries: 10

  api-gateway:
    build: ./gateway
    container_name: api-gateway
    ports:
      - &quot;8080:8080&quot;
    Depends_on: # 객체 방식
        mariadb:
            condition: service_started
        eureka-server:
            condition: service_healthy
    environment:
      - EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:8761/eureka/
    # healthcheck:
    #   test: [&quot;CMD&quot;, &quot;curl&quot;, &quot;-f&quot;, &quot;http://localhost:8080/actuator/health&quot;]
    #   interval: 5s
    #   retries: 10


# =====================
# 다른 서비스 (수동 실행)
# =====================
  order-service:
    build: ./order-service
    container_name: order-service
    profiles: [&quot;optional&quot;]
    ports:
      - &quot;8085:8080&quot;
    depends_on:
      eureka-server:
        condition: service_healthy
    environment:
      - EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:8761/eureka/
  product-service:
    build: ./product-service
    container_name: product-service
    profiles: [&quot;optional&quot;]
    ports:
      - &quot;8083:8080&quot;
    depends_on:
      eureka-server:
        condition: service_healthy
    environment:
      - EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:8761/eureka/​&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 7-2. JAR 파일 준비&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1️⃣ Build.gradle&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775521626804&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;tasks.bootJar {
    archiveFileName = 'gateway.jar'                // JAR 이름
    destinationDirectory = file(&quot;$buildDir/target&quot;) // 경로
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2️⃣ \gradlew bootJar 수행&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3️⃣ build/target/{}.jar 파일 생성 확인.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅7-3. 도커 이미지 준비&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;각 서비스(폴더) 안에 Dockerfile 필요&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- Dockerfile (eureka)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775521659628&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM eclipse-temurin:17-jdk # jdk버전 유의 (유효버전 검색)
COPY build/target/eureka-server.jar /app.jar # 실제 jar 위치
ENTRYPOINT [&quot;java&quot;, &quot;-jar&quot;, &quot;/app.jar&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 7-4. docker-compose up 실행 옵션&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  기본 실행&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;profile 속성이 없는 서비스 전체 실행&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker-compose up -d&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  profile 포함 실행&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;profiles: [&quot;optional&quot;] 속성 포함 전체 서비스 실행&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;*비즈니스 서비스 개발 시에는 로컬PC IDE에서 실행, 운영에서는 컨테이너에서 실행 가능!!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker-compose --profile optional up -d&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 개별 서비스 실행&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Profiles여부와 상관없이 개별로 실행가능.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker-compose up -d order-service&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여러개 선택 실행도 가능.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;docker-compose up -d&amp;nbsp; eureka-server api-gateway mariadb redis&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;span style=&quot;color: #000000;&quot;&gt;1️⃣ 스프링부트 Jar 파일 직접 실행 (Dockerfile 없이)&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이미 빌드된 jar 파일이 있다면 image: + command:로 바로 컨테이너 실행 가능&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1775521688124&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;api-gateway:
 image: openjdk:17
 container_name: api-gateway

 ports:
   - &quot;8080:8080&quot;

 volumes:
   - ./api-gateway/target:/app

 working_dir: /app
 command: [&quot;java&quot;, &quot;-jar&quot;, &quot;api-gateway.jar&quot;]
 depends_on:
   - eureka-server&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;✔&lt;/span&gt;&amp;nbsp; ./api-gateway/target/api-gateway.jar 경로에 실제 jar 파일 있어야 함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;✔&lt;/span&gt;&amp;nbsp; Dockerfile 없이도 컨테이너에서 실행 가능&lt;/span&gt;&lt;b&gt;&lt;/b&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;span style=&quot;color: #000000;&quot;&gt; &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt; &lt;/span&gt; 확인&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1488&quot; data-origin-height=&quot;203&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ISeGc/dJMcaa5Vh6E/WQ4Zu2CxXHCL1OWOiRk22k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ISeGc/dJMcaa5Vh6E/WQ4Zu2CxXHCL1OWOiRk22k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ISeGc/dJMcaa5Vh6E/WQ4Zu2CxXHCL1OWOiRk22k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FISeGc%2FdJMcaa5Vh6E%2FWQ4Zu2CxXHCL1OWOiRk22k%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;1488&quot; height=&quot;203&quot; data-origin-width=&quot;1488&quot; data-origin-height=&quot;203&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1775521798684&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 컨테이너 상태 확인
docker ps

# Eureka 서버가 정상 구동됐는지 확인
docker logs eureka-server

# Gateway 정상 구동 확인
docker logs api-gateway&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/b&gt; &lt;/p&gt;</description>
      <category>tool</category>
      <category>docker</category>
      <category>도커</category>
      <author>dddzr</author>
      <guid isPermaLink="true">https://sumni.tistory.com/493</guid>
      <comments>https://sumni.tistory.com/493#entry493comment</comments>
      <pubDate>Tue, 7 Apr 2026 09:42:10 +0900</pubDate>
    </item>
    <item>
      <title>크롤링(Crawling)</title>
      <link>https://sumni.tistory.com/489</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  1. 크롤링(Crawling)이란?&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;웹 크롤링은 인터넷 상의 웹 페이지를 자동으로 탐색하고, 그 내용을 수집하는 기술 또는 과정! 보통 검색 엔진(예: 구글)이나 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;데이터 수집 봇&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 사용하는 기술이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  크롤링의 기본 원리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1️⃣ 크롤러(bot, spider)가 시작 URL(예: &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;&lt;a href=&quot;https://example.com&quot;&gt;https://example.com&lt;/a&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;)에 접속&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 2️⃣ 해당 페이지의 HTML 문서를 읽고, 내부에 있는 링크들을 수집&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 3️⃣ 수집한 링크를 따라가면서 다른 페이지도 탐색&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 4️⃣ 이 과정을 반복하면서 점점 더 많은 데이터를 수집&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  크롤링을 사용하는 이유&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 웹사이트의 정보를 자동으로 모으기 위해&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; ✅ 상품 가격, 뉴스 기사, 게시글 등을 수집해 분석하기 위해&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; ✅ 검색 엔진이 웹사이트를 인덱싱하기 위해&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  크롤링 vs 스크래핑&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;크롤링: 웹페이지를 돌아다니며 데이터를 모으는 과정&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;스크래핑: 그 페이지 안에서 원하는 정보를 뽑아내는 작업&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&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;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;항목&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;크롤링&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;스크래핑&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;목적&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;페이지 탐색 및 링크 수집&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;페이지에서 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;특정 정보 추출&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예시&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여러 뉴스 사이트 순회&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;뉴스 기사에서 제목/본문 추출&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  2. 크롤링 구현 방법 (파이썬)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;파이썬에서 크롤링 라이브러리를 이용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; ✅ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;크롤링 라이브러리&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #188038;&quot;&gt;BeautifulSoup&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &amp;rarr; 정적 HTML에서 데이터 추출&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Selenium&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &amp;rarr; 동적으로 생성되는 데이터 (JS 렌더링된 페이지)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Scrapy&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &amp;rarr; 대규모 크롤링에 적합&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 2-1. 기본 웹 크롤링 방식 (requests &amp;amp; BeautifulSoup)&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #188038;&quot;&gt;requests.get(url)&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;을 사용하면 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;웹사이트의 HTML을 가져올 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&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;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;import requests&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;from bs4 import BeautifulSoup&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;url = &quot;&lt;a href=&quot;https://example.com&quot;&gt;https://example.com&lt;/a&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;headers = {&quot;User-Agent&quot;: &quot;Mozilla/5.0&quot;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;response = requests.get(url, headers=headers)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;soup = BeautifulSoup(response.text, &quot;html.parser&quot;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;print(soup.prettify())&amp;nbsp; # 사이트의 HTML 코드 출력&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 2-2. 동적 웹페이지 크롤링 (Selenium)&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;requests는 HTML 코드만 가져오기 때문에, JavaScript로 렌더링되는 데이터(예: 유튜브 댓글, 쿠팡 상품 목록 등)는 크롤링할 수 없음!&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Selenium을 사용하면 실제 브라우저를 띄우기 때문에 JavaScript로 렌더링된 데이터도 가져올 수 있음!&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&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;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;from selenium import webdriver&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;from selenium.webdriver.chrome.service import Service&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;from selenium.webdriver.common.by import By&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;from selenium.webdriver.common.keys import Keys&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;import time&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;# 크롬 드라이버 실행&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;service = Service(&quot;chromedriver.exe&quot;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;driver = webdriver.Chrome(service=service)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;# 웹사이트 접속&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;driver.get(&quot;&lt;/span&gt;&lt;span style=&quot;color: #1155cc;&quot;&gt;&lt;/span&gt;&lt;a href=&quot;https://example.com&quot;&gt;https://example.com&lt;/a&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&quot;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;time.sleep(2)&amp;nbsp; # 페이지가 로딩될 때까지 대기&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;# HTML 가져오기&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;html = driver.page_source&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;print(html)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;#뉴스 제목 가져오기&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;titles = driver.find_elements(By.CLASS_NAME, &quot;sa_text_strong&quot;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;print(&quot;  네이버 뉴스 제목:&quot;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;for idx, title in enumerate(titles, 1):&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&quot;{idx}. {title.text}&quot;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;# 브라우저 종료&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;driver.quit()&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✔ find_elements(By.CLASS_NAME, &quot;클래스이름&quot;) 으로 원하는 데이터를 가져올 수 있음.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✔ driver.quit()으로 브라우저를 닫아야 함.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  2-3. 크롤링 방식 비교&lt;/span&gt;&lt;/h3&gt;
&lt;div&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;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;방식&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가져올 수 있는 데이터&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;주요 라이브러리&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;requests&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; + &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;BeautifulSoup&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;서버에서 제공하는 정적인 HTML&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;requests&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;BeautifulSoup&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Selenium&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;JavaScript로 동적으로 생성된 데이터 (예: 무한 스크롤)&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Selenium&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;webdriver&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Scrapy&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;대량의 웹페이지에서 데이터 수집 (크롤링 속도 빠름)&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Scrapy&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  어떤 데이터를 크롤링하느냐에 따라 적절한 라이브러리를 선택!&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 3. 크롤링 주의사항&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅3-1. &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;robots.txt&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 확인 (사이트 크롤링 허용 여부 체크)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;웹사이트마다 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;크롤링 허용 여부를 설정한 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;robots.txt&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 파일이 있다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;➡️ 크롤링 가능 여부를 먼저 체크!!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;확인 방법:&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;https://사이트주소/robots.txt&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예시&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; (네이버 뉴스)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;a href=&quot;https://news.naver.com/robots.txt&quot;&gt;https://news.naver.com/robots.txt&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✔ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;User-agent: *&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 부분에서 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Disallow&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 된 URL이 있으면 크롤링하면 안 됨!&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; ✔ 만약 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Allow: /&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 라고 되어 있으면 크롤링 가능!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅3-2. User-Agent 설정 (크롤링 차단 방지)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;서버가 봇(자동 크롤러)인 걸 감지하면 차단할 수도 있다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;➡️ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;User-Agent를 설정하면 사람이 요청하는 것처럼(브라우저 처럼) 보일 수 있음!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예시 (네이버 뉴스 크롤링)&lt;/span&gt;&lt;/p&gt;
&lt;div&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;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;import requests&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;url = &quot;&lt;a href=&quot;https://news.naver.com/&quot;&gt;https://news.naver.com/&lt;/a&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;headers = {&quot;User-Agent&quot;: &quot;Mozilla/5.0&quot;}&amp;nbsp; # 크롬 브라우저처럼 보이게 설정&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;response = requests.get(url, headers=headers)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;print(response.status_code)&amp;nbsp; # 200이면 정상 접속&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅3-3. IP 차단 방지 (요청 간격 조절)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;너무 빠르게 요청하면 차단될 수도 있어!&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;➡️ &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;time.sleep(1)&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 같은 코드를 추가해서 요청 간격을 조절.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예제 (10초마다 뉴스 크롤링)&lt;/span&gt;&lt;/p&gt;
&lt;div&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;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;import time&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;for _ in range(5):&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response = requests.get(url, headers=headers)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&quot;크롤링 완료, 10초 대기 중...&quot;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(10)&amp;nbsp; # 10초 대기&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  4. 추가 기능&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅4-1. API 데이터 가져오기 (requests + JSON 활용)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;웹사이트에서 제공하는 API를 이용하면 더 빠르고 안정적으로 데이터를 가져올 수 있다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; (  API는 데이터를 JSON 형식으로 제공하는 경우가 많음!)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  API 요청 예제 (jsonplaceholder.typicode.com 사용)&lt;/span&gt;&lt;/p&gt;
&lt;div&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;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;import requests&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;url = &quot;&lt;a href=&quot;https://jsonplaceholder.typicode.com/posts&quot;&gt;https://jsonplaceholder.typicode.com/posts&lt;/a&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;response = requests.get(url)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;data = response.json()&amp;nbsp; # JSON 데이터를 파이썬 딕셔너리로 변환&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;# 5개의 제목 출력&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;for post in data[:5]:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(post[&quot;title&quot;])&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✔ 장점: 크롤링보다 빠르고 정확함! (robots.txt 걱정 없음)&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✔ 단점: API를 제공하는 사이트에서만 사용 가능&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅4-2. 크롤링 데이터 가공 후 시각화 (pandas + matplotlib)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;크롤링한 데이터를 분석하고 그래프로 시각화할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;설치 방법&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;pip install pandas matplotlib&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  CSV 데이터 불러와서 시각화 예제&lt;/span&gt;&lt;/p&gt;
&lt;div&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;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;import pandas as pd&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;import matplotlib.pyplot as plt&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;# CSV 파일 불러오기&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;df = pd.read_csv(&quot;news.csv&quot;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;# 뉴스 개수 확인&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;print(df.head())&amp;nbsp; # 상위 5개 출력&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;# 뉴스 제목 글자 수 분포 시각화&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;df[&quot;title_length&quot;] = df[&quot;뉴스 제목&quot;].str.len()&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;plt.hist(df[&quot;title_length&quot;], bins=10, color=&quot;skyblue&quot;, edgecolor=&quot;black&quot;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;plt.xlabel(&quot;제목 길이&quot;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;plt.ylabel(&quot;기사 개수&quot;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;plt.title(&quot;뉴스 제목 길이 분포&quot;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;plt.show()&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✔ pandas로 데이터를 다룰 수 있음&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✔ matplotlib로 데이터를 그래프로 표시 가능&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt; &lt;/p&gt;</description>
      <category>python</category>
      <category>크롤링</category>
      <author>dddzr</author>
      <guid isPermaLink="true">https://sumni.tistory.com/489</guid>
      <comments>https://sumni.tistory.com/489#entry489comment</comments>
      <pubDate>Sun, 25 Jan 2026 13:22:22 +0900</pubDate>
    </item>
    <item>
      <title>멀티 모듈 (Multi-module)이란?</title>
      <link>https://sumni.tistory.com/488</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;msa 프로젝트 구성 중 각 시스템(서비스)에서 공통으로 필요로 하는 코드들이 많았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 중복을 줄이기 위해서 멀티 모듈로 관리하는 방법이 있다는 걸 알게되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;결론적으로 내 프로젝트에는&amp;nbsp; 멀티모듈 구조가 적합하지 않다고 판단해서 적용하지 않았지만, 멀티 모듈에 대해 알아본 것들을 정리했다!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 1. 멀티 모듈 (Multi-module)이란?&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;멀티 모듈은 하나의 큰 프로젝트 내에서 여러 개의 모듈을 정의하는 방식.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;단일 애플리케이션에서 여러 모듈로 나누어 관리하는 방식&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;MSA에서는 서비스 간의 의존성 관리나, 공통 라이브러리 등을 관리하기 위해 멀티 모듈을 사용할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예시: common-utils라는 모듈을 만들고, 여러 서비스가 이 모듈을 의존성으로 추가하여 공통 기능(로그 처리, 유효성 검사, 예외 처리 등)을 공유.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 2. 멀티모듈 구조가 적합한 경우&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;모든 서비스가 동일한 기술 스택(예: Spring Boot + Gradle)을 사용하는 경우.&lt;b&gt;&lt;/b&gt; &lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;각 서비스가 동일한 코딩 스타일과 공통 라이브러리를 사용하는 경우.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;개발자 간 협업이 원활하고, 서비스 간 높은 결합도가 있어야 하는 경우.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;각 서비스가 동일한 배포 주기를 가질 수 있는 경우.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 3. 멀티모듈 구조가 적합하지 않은 경우&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;서비스마다 기술 스택이 다양한 경우.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예: 주문 서비스(Java), 사용자 서비스(Python).&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;서비스마다 DB가 달라서 독립적으로 관리해야 하는 경우.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 예: MySQL, PostgreSQL, MongoDB 등 다양한 DB를 사용하는 경우. &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;서비스별 개발팀이 다르거나, 각 팀의 작업 속도가 크게 다른 경우.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;각 서비스가 독립적으로 배포 및 테스트가 가능한 구조를 원할 때.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 4. 대안: 독립 서비스로 관리&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;멀티모듈 대신 각 서비스를 독립적으로 관리하면서도, 공통 코드를 공유하는 방식&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;공통 코드(예: DTO, 유틸리티 등)를 별도의 공통 라이브러리 프로젝트로 관리. &lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&amp;gt; Git 서브모듈이나 별도의 공통 라이브러리 Git 저장소를 만들어 공유.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;각 서비스는 완전히 독립적으로 개발 및 배포.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;서비스별로 독립적인 빌드 및 파이프라인을 설정.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 5. 예시 (이벤트 기반 통신)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이벤트 기반 통신에서 발행하는 쪽과 수신하는 쪽의 Event 객체를 동일하게 사용.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;root-module/&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;├── order-service/&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;│ &amp;nbsp; &amp;nbsp; └── 발행자&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;├── product-service/&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;│ &amp;nbsp; &amp;nbsp; └── 수신자&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;├── common-events/&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;└── OrderEvent.java&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✔️ 장점&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;코드 재사용성: 발행 및 수신 양쪽에서 동일한 객체를 사용하므로 코드 중복을 방지.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;일관성 유지: 이벤트의 스키마(필드 구조)가 항상 동일하게 유지. 이벤트를 발행할 때와 수신할 때 필드가 다를 위험x.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;의존성 관리 용이: 공통 모듈로 이벤트 클래스를 두면, 발행 서비스와 수신 서비스 모두 해당 모듈을 의존성으로 추가해 사용할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;테스트 효율성 증가: 동일한 이벤트 객체를 사용하면, Mocking이나 Serialization 테스트 시 같은 클래스를 사용할 수 있어 효율적.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;✔️ 고려할 점&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;서비스 간 강결합 가능성&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;공통 이벤트 객체를 사용하면 서비스 간 간접적인 의존성이 생김.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이를 완화하려면 공통 모듈의 변경을 신중히 하고, 이벤트 버전 관리(예: OrderEventV1, OrderEventV2)를 도입해야함. &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;모듈 간 독립성 손상 가능성&lt;br /&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 각 서비스가 독립적으로 배포되고 관리되어야 하는 경우, 공통 이벤트 클래스에 변경이 생기면 각 서비스의 독립 배포 주기를 방해할 수 있다. &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;메시지 호환성&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;발행자가 오래된 이벤트를 사용하고, 수신자가 새 이벤트를 수신할 경우 호환성 문제가 발생할 수 있다. JSON 직렬화 구조를 유연하게 처리하거나 필드 추가만 허용하는 방식으로 관리해야함.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;직렬화 라이브러리&lt;br /&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 이벤트 객체를 직렬화/역직렬화하는 라이브러리(예: Jackson, Gson) -&amp;gt; 같은 직렬화 라이브러리를 사용하는 것을 권장. &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 6. 공통 모듈 설정 방법&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;common 모듈은 공통 코드를 포함하는 별도의 프로젝트로 만들고, 각 서비스가 이를 참조하도록 설정할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 방법 1: JAR 파일로 사용&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1️⃣common 모듈을 빌드하여 JAR 파일을 생성, 파일은 common/build/libs/에 생성된다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1769312924154&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd common
./gradlew build&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2️⃣각 서비스의 build.gradle에 common JAR 파일을 의존성으로 추가합니다.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1769312935769&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dependencies {
    implementation files('../common/build/libs/common-0.0.1-SNAPSHOT.jar')
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 방법 2: 로컬 프로젝트 참조&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1️⃣각 서비스의 build.gradle에서 common 폴더를 직접 참조하도록 설정.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;service-a/build.gradle&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1769312946369&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dependencies {
    implementation project(':common')
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2️⃣상위 settings.gradle에서 common 모듈을 포함시킨다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;workspace-folder/settings.gradle&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1769312953153&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;include ':common', ':service-a', ':service-b', ':service-c'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>Backend/spring cloud (MSA)</category>
      <category>공통모듈</category>
      <category>멀티모듈</category>
      <category>프로젝트관리</category>
      <author>dddzr</author>
      <guid isPermaLink="true">https://sumni.tistory.com/488</guid>
      <comments>https://sumni.tistory.com/488#entry488comment</comments>
      <pubDate>Sun, 25 Jan 2026 12:49:40 +0900</pubDate>
    </item>
    <item>
      <title>Spring Boot DTO &amp;harr; Entity 변환 방법</title>
      <link>https://sumni.tistory.com/487</link>
      <description>&lt;h2 data-end=&quot;76&quot; data-start=&quot;45&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  왜 DTO &amp;harr; Entity 변환이 필요한가?&lt;/span&gt;&lt;/h2&gt;
&lt;p data-end=&quot;226&quot; data-start=&quot;80&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Entity는 DB 모델이고, DTO는 입출력&amp;middot;뷰 모델이기 때문.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;226&quot; data-start=&quot;80&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;엔티티를 그대로 노출하면 보안&amp;middot;커플링&amp;middot;유효성 검증&amp;middot;API 스펙 분리 문제가 생기므로,&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;226&quot; data-start=&quot;80&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DTO로 변환해서 외부와 내부를 분리하는 것이 Spring 실무 표준이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  객체 변환 3가지 방법 비교&lt;/span&gt;&lt;/h2&gt;
&lt;p data-end=&quot;646&quot; data-start=&quot;591&quot; data-ke-size=&quot;size16&quot;&gt;Spring Boot에서 DTO &amp;harr; Entity 변환 시 대표적으로 아래 3가지를 비교할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;646&quot; data-start=&quot;591&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;660&quot; data-start=&quot;648&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;비교 기준&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;765&quot; data-start=&quot;661&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;680&quot; data-start=&quot;661&quot;&gt;&lt;b&gt;컬렉션(List) 변환&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;722&quot; data-start=&quot;681&quot;&gt;&lt;b&gt;연관 관계 필드 변환&lt;/b&gt; (예: User &amp;rarr; Address 포함)&lt;/li&gt;
&lt;li data-end=&quot;765&quot; data-start=&quot;723&quot;&gt;&lt;b&gt;타입 변환&lt;/b&gt; (예: LocalDateTime &amp;rarr; String)&lt;/li&gt;
&lt;/ol&gt;
&lt;div&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;span style=&quot;color: #000000;&quot;&gt;방법&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #000000;&quot;&gt;List 변환&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #000000;&quot;&gt;연관 관계 필드 변환&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #000000;&quot;&gt;타입 변환 (예: LocalDateTime &amp;rarr; String)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #000000;&quot;&gt;BeanUtils.copyProperties()&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #000000;&quot;&gt;❌ 수동 처리 필요&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #000000;&quot;&gt;❌ 자동 변환 불가&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #000000;&quot;&gt;❌ 직접 변환 필요&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #000000;&quot;&gt;ModelMapper&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 자동 변환 가능&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #000000;&quot;&gt;   일부 변환 가능&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 커스텀 변환 지원&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #000000;&quot;&gt;수동 변환 (직접 매핑)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 완벽한 제어 가능&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 원하는 대로 변환 가능&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 원하는 방식으로 변환 가능&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 1. BeanUtils.copyProperties()&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Spring의 BeanUtils.copyProperties()는 간단한 DTO 변환에 유용.&lt;br /&gt;하지만, 연관 관계 필드(@OneToMany, @ManyToOne)나 타입 변환(LocalDateTime &amp;rarr; String)이 자동으로 처리되지 않아서 직접 변환해야 한다.&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;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  예제 코드&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;OrderItemDetails orderItemDetails = new OrderItemDetails();&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;BeanUtils.copyProperties(orderItem, orderItemDetails);&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  장점 &amp;amp; 단점&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✔ 장점&lt;br /&gt;빠르고 단순&lt;br /&gt;필드명이 같으면 자동 변환&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;span style=&quot;color: #000000;&quot;&gt;❌ 단점&lt;br /&gt;커스텀/중첩 필드 처리 거의 없음 &lt;br /&gt;&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;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  리스트 변환 및 연관 관계 변환 예제 (수동 처리 필요)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1769312270395&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;orderItemDetails.setOrderId(orderItem.getOrder().getOrderId()); // 연관 관계 필드 직접 매핑
orderItemDetails.setProductName(orderItem.getProduct().getName());&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 2. ModelMapper&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;ModelMapper는 List 변환, 연관 관계 변환, 타입 변환을 자동으로 처리.&lt;br /&gt;하지만 성능이 다소 저하될 수 있음.&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;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  예제 코드&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;ModelMapper modelMapper = new ModelMapper();&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;OrderItemDetails orderItemDetails = modelMapper.map(orderItem, OrderItemDetails.class);&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  장점 &amp;amp; 단점&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✔ 장점&lt;br /&gt;자동 매핑, 컨벤션 기반 &lt;br /&gt;&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;span style=&quot;color: #000000;&quot;&gt;❌ 단점&lt;br /&gt;설정 복잡, 런타임 성능 이슈 가능 &lt;br /&gt;&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;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  리스트 &amp;amp; 연관 관계 자동 변환 예제&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1769312261563&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;modelMapper.createTypeMap(Product.class, ProductDTO.class)
    .addMappings(mapper -&amp;gt; {
        mapper.map(Product::getName, ProductDTO::setProductName);
        mapper.map(src -&amp;gt; src.getCategory().getCategoryName(), ProductDTO::setCategoryName);
    });&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 3. 수동 변환&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;연관 관계(@OneToMany, @ManyToOne) 필드 변환, 리스트 변환, 타입 변환을 완벽하게 제어할 수 있다.&lt;br /&gt;하지만 코드가 길어질 수 있음.&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;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  예제 코드&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1769312295995&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static ProductDTO convertToDto(Product product) {
    ProductDTO productDTO = new ProductDTO();
    productDTO.setId(product.getId());
    productDTO.setName(product.getName());

    // 연관 관계 변환
    productDTO.setCategoryName(product.getCategory().getCategoryName());

    // 리스트 변환
    List&amp;lt;ProductDetailDTO.ProductStockDto&amp;gt; stockDTOs = product.getStocks().stream()
        .map(stock -&amp;gt; new ProductDetailDTO.ProductStockDto(
            stock.getSize().getSizeName(),
            stock.getColor().getColorName(),
            stock.getStockQuantity()))
        .collect(Collectors.toList());

    productDTO.setProductStocks(stockDTOs);

    return productDTO;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  장점 &amp;amp; 단점&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✔ 장점&lt;br /&gt;가장 명확, 유지보수 쉬움 &lt;br /&gt;&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;span style=&quot;color: #000000;&quot;&gt;❌ 단점&lt;br /&gt;코드가 길어질 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  최종 결론: 어떤 방법을 선택할까?&lt;/span&gt;&lt;/h2&gt;
&lt;div&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;span style=&quot;color: #000000;&quot;&gt;방법&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #000000;&quot;&gt;추천 사용 경우&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #000000;&quot;&gt;BeanUtils.copyProperties()&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #000000;&quot;&gt;필드명이 동일한 간단한 DTO 변환일 때&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #000000;&quot;&gt;ModelMapper&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #000000;&quot;&gt;자동 변환이 필요한 경우 (연관 관계 포함)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #000000;&quot;&gt;수동 변환&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #000000;&quot;&gt;최대 성능 &amp;amp; 정확한 제어가 필요한 경우&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Backend/spring (Boot)</category>
      <category>객체변환</category>
      <author>dddzr</author>
      <guid isPermaLink="true">https://sumni.tistory.com/487</guid>
      <comments>https://sumni.tistory.com/487#entry487comment</comments>
      <pubDate>Sun, 25 Jan 2026 12:42:19 +0900</pubDate>
    </item>
    <item>
      <title>Elasticsearch &amp;gt; analyzer</title>
      <link>https://sumni.tistory.com/486</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  1. settings / analysis / analyzer 개념&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  1-1. settings란?&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;인덱스의 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;구성 설정&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;을 정의하는 영역이다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;샤드 수, 리플리카 수, 분석기(analyzer) 설정 등이 포함된다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  1-2. analysis란?&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;텍스트 분석기 관련 설정 전부를 담는다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;내부 구성:&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;analyzer&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;tokenizer&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;filter&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;char_filter&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;/b&gt; &lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  1-3. analyzer란?&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;텍스트를 쿼리 시 또는 색인 시 &amp;ldquo;어떻게 쪼개고(normalizing) 처리할지&amp;rdquo;를 정의하는 도구이다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;최소 구성 요소:&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;tokenizer (필수)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;filter (선택)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;char_filter (선택)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  2. analyzer는 필수인가?&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;analyzer를 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;반드시 설정해야 하는 것은 아니며&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;, 기본 분석기만으로도 충분한 경우가 많다.&lt;/span&gt;&lt;/p&gt;
&lt;div&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;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;항목&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;필수 여부&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;설명&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;analyzer 설정 자체&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;❌ 선택&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;설정하지 않으면 Elasticsearch 기본 분석기(standard analyzer)가 적용됨&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;tokenizer&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ 필수&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;custom analyzer를 정의할 때 반드시 지정해야 함&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;filter&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;❌ 선택&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;필요 시 lowercase, stopword 등을 추가&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;char_filter&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;❌ 선택&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;HTML strip 등 전처리 용도&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✔ analyzer가 필요한 경우&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;한국어 검색&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &amp;rarr; ✔ 필수&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;자동완성, 부분 검색 &amp;rarr; ✔ 필수&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;동의어(synonym) &amp;rarr; ✔ 필수&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;검색 정확도 높이기 (형태소, 불용어, 대소문자) &amp;rarr; ✔ 필수&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;특수 문자 기반 토큰 분리 &amp;rarr; ✔ 필수&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✔ analyzer가 필요 없는 경우&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;exact match(keyword) 필드&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;단순 영어 검색 + 기본 기능으로 충분한 경우&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  3. settings와 analyzer의 기본 구조&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Elasticsearch 인덱스를 생성할 때 아래처럼 &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;settings&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;와 &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;analyzer&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;를 지정할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;PUT /my_index&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;{&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&quot;settings&quot;: {&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;analysis&quot;: {&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;analyzer&quot;: {&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;my_custom_analyzer&quot;: {&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;type&quot;: &quot;custom&quot;,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;tokenizer&quot;: &quot;standard&quot;,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;filter&quot;: [ &quot;lowercase&quot;, &quot;asciifolding&quot; ]&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;},&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&quot;mappings&quot;: {&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;properties&quot;: {&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;message&quot;: {&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;type&quot;: &quot;text&quot;,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;analyzer&quot;: &quot;my_custom_analyzer&quot;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  4. 주요 구성 요소 설명&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  analyzer&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사용자 정의 분석기(custom) 또는 기본 분석기를 의미한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  tokenizer (필수)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;텍스트를 쪼개는 기준이다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #188038;&quot;&gt;standard&lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #188038;&quot;&gt;whitespace&lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #188038;&quot;&gt;ngram&lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #188038;&quot;&gt;nori_tokenizer&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; (한국어 형태소 분석기)&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  filter&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;토큰에 대한 후처리를 진행한다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;lowercase&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;asciifolding&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;nori_part_of_speech&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;stop (불용어 제거)&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  예제 1: 영어용 소문자 분석기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&quot;analyzer&quot;: {&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&quot;my_lowercase_analyzer&quot;: {&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;type&quot;: &quot;custom&quot;,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;tokenizer&quot;: &quot;standard&quot;,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;filter&quot;: [&quot;lowercase&quot;]&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  예제 2: 한글용 nori 분석기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&quot;analyzer&quot;: {&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&quot;korean_analyzer&quot;: {&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;type&quot;: &quot;custom&quot;,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;tokenizer&quot;: &quot;nori_tokenizer&quot;,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;filter&quot;: [&quot;nori_part_of_speech&quot;]&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  5. analyzer를 필드에 적용하는 법 (mapping)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&quot;mappings&quot;: {&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&quot;properties&quot;: {&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;title&quot;: {&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;type&quot;: &quot;text&quot;,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;analyzer&quot;: &quot;my_custom_analyzer&quot;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;⚠️ analyzer를 정의해도 mapping에서 지정하지 않으면 적용되지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  6. analyzer 테스트 방법&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;설정이 잘 되었는지 확인하려면 _analyze API를 호출!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;POST /my_index/_analyze&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;{&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&quot;analyzer&quot;: &quot;my_custom_analyzer&quot;,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&quot;text&quot;: &quot;Hello WORLD!&quot;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  7. analyzer 수정&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;analyzer는 생성 후 수정 불가!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;❌ 왜 수정이 불가능한가?&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;analyzer는 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;인덱스 생성 시 Lucene 구조로 고정&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;됨.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;중간에 기준을 바꾸면 기존 문서의 분석 기준과 신규 문서 기준이 달라짐&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  8. analyzer 수정이 필요한 경우는?&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;기존 인덱스를 복사해서 새로 만드는 방식&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1️⃣ 새 인덱스를 원하는 설정으로 생성&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 2️⃣ 기존 인덱스에서 데이터 가져오기 (reindex API)&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 3️⃣ 기존 인덱스 삭제 (선택)&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 4️⃣ 별칭(alias)을 바꿔서 기존 인덱스처럼 사용&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;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1️⃣ 새 인덱스 생성&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;PUT /my_index_v2&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;{&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&quot;settings&quot;: {&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;analysis&quot;: {&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;analyzer&quot;: {&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;my_custom_analyzer&quot;: {&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;type&quot;: &quot;custom&quot;,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;tokenizer&quot;: &quot;standard&quot;,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;filter&quot;: [&quot;lowercase&quot;]&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;},&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&quot;mappings&quot;: {&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;properties&quot;: {&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;title&quot;: {&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;type&quot;: &quot;text&quot;,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;analyzer&quot;: &quot;my_custom_analyzer&quot;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2️⃣ 데이터 복사 (reindex)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;POST /_reindex&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;{&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&quot;source&quot;: { &quot;index&quot;: &quot;my_index&quot; },&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&quot;dest&quot;: &amp;nbsp; { &quot;index&quot;: &quot;my_index_v2&quot; }&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3️⃣ alias 전환&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;POST /_aliases&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;{&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&quot;actions&quot;: [&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{ &quot;remove&quot;: { &quot;index&quot;: &quot;my_index&quot;,&amp;nbsp; &amp;nbsp; &quot;alias&quot;: &quot;current_index&quot; }},&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{ &quot;add&quot;:&amp;nbsp; &amp;nbsp; { &quot;index&quot;: &quot;my_index_v2&quot;, &quot;alias&quot;: &quot;current_index&quot; }}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;]&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  9. Spring Boot에서 analyzer 매핑하는 법&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅9-1. 도메인 클래스&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Spring Data Elasticsearch는 &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;@Document&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;와 &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;@Field&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 어노테이션 기준으로 매핑을 잡아줌.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;@Field(analyzer = &quot;my_custom_analyzer&quot;)&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 를 반드시 명시해야 커스텀 analyzer 사용됨.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1769310593121&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Document(indexName = &quot;article_index&quot;)
public class Article {

    @Id
    private String id;

    @Field(type = FieldType.Text, analyzer = &quot;my_custom_analyzer&quot;)
    private String title;

    @Field(type = FieldType.Text)
    private String content;

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 9-2. ElasticsearchRepository 작성&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #188038;&quot;&gt;findByXXX()&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 자동 쿼리 or &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;@Query&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 커스텀 사용&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;복잡한 구현에선 repository 안 쓰고 ElasticsearchClient 직접 호출해서 쓸 수도 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1769310614209&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface ArticleRepository extends ElasticsearchRepository&amp;lt;Article, String&amp;gt; {

    List&amp;lt;Article&amp;gt; findByTitle(String title);

    @Query(&quot;{ \&quot;match\&quot;: { \&quot;title\&quot;: \&quot;?0\&quot; } }&quot;)
    List&amp;lt;Article&amp;gt; findByCustomTitle(String title);

}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 9-3. 검색 테스트&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1769310640480&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Autowired
private ArticleRepository articleRepository;
public void testSearch() {
    List&amp;lt;Article&amp;gt; articles = articleRepository.findByTitle(&quot;hello world&quot;);
    articles.forEach(System.out::println);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt; &lt;/p&gt;</description>
      <category>DB/데이터 관리</category>
      <category>elasticsearch</category>
      <author>dddzr</author>
      <guid isPermaLink="true">https://sumni.tistory.com/486</guid>
      <comments>https://sumni.tistory.com/486#entry486comment</comments>
      <pubDate>Sun, 25 Jan 2026 12:11:11 +0900</pubDate>
    </item>
    <item>
      <title>DTO / VO / DAO / Entity / Model 비교</title>
      <link>https://sumni.tistory.com/485</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DTO / VO / DAO / Entity / Model&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;은 모두 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Spring에서 데이터와 관련된 객체들&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;로, 각기 다른 역할을 한다. 헷갈리는 개념들을 한 번에 정리해보자!  &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0d0d0d;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0d0d0d;&quot;&gt;1. &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DTO / VO / DAO / Entity / Model 비교&lt;/span&gt;&lt;/h2&gt;
&lt;div&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;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;구분&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;역할/목적&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;특징&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사용하는 층(Layer)&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;변경 가능성&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예시&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;VO&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;값 객체 (Value Object)&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;불변 객체 (immutable)&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DTO, Entity와 연동 가능&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;변경 X&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Money&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Point&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Address&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DTO&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;데이터 전달 객체 (Data Transfer Object)&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;계층 간 데이터 전달용&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Controller &amp;harr; Service &amp;harr; DAO&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;변경 O&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;UserDTO&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;LoginDTO&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DAO&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DB 접근 객체 (Data Access Object)&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DB 호출/쿼리 수행&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Repository Layer&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;변경 O&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;UserDao&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;OrderDao&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Entity&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;실제 DB 테이블과 매핑되는 객체&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;JPA 사용 시 @Entity&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DB &amp;harr; Application&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;변경 O&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Product&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Model&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;View에 넘겨주는 데이터 묶음 (MVC용)&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;UI에 최적화&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Controller &amp;harr; View&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;변경 O&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Model.addAttribute(&quot;user&quot;, user)&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;➡️ DTO는 계층 간 데이터 전달, VO는 값 객체, DAO는 DB 접근, Entity는 DB 테이블과 매핑, Model은 View에 데이터를 전달하는 역할을 한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2. 각 객체 개념 상세 설명&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;VO (Value Object)&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;값 자체가 중요한 객체 (예: &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Address&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Money&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Coordinate&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;일반적으로 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;불변 객체&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;로 설계 (getter만 있고 setter 없음)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;값 세팅은 객체가 생성될 때 생성자(constructor)에서함. (예: AddressVO address = new AddressVO(&quot;서울&quot;, &quot;테헤란로&quot;);)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;equals(), hashCode() 오버라이딩해서 값 비교 중심&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;주로 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DDD&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(도메인 주도 설계)에서 많이 등장함&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;JPA에서 &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;@Embeddable&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;로 쓰이기도 함&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예시&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1769310115378&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class AddressVO {
    private final String city;
    private final String street;

// 생성자 + getter만 있음
    public AddressVO(String city, String street) {
        this.city = city;
        this.street = street;
    }

    public String getCity() { return city; }
    public String getStreet() { return street; }

    // equals / hashCode override
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DTO (Data Transfer Object)&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;계층 간 데이터를 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;전달&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;하기 위한 객체&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;일반적으로 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;getter/setter 다 있음&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Controller &amp;harr; Service &amp;harr; DAO(&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Repository) 간에 데이터를 넘기기 위해 사용&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가공된 데이터나 UI에 맞는 구조로 만들어짐&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;네트워크 전송, API 요청/응답 등에 사용됨&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Validation용 어노테이션 붙기도 함 (&lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;@NotNull&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;@Size&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 등)&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  예:&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1769310140834&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class UserDTO {
    private String username;
    private String email;
    
    // getter / setter
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DAO (Data Access Object)&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DB와 직접 통신하는 역할 (CRUD 수행)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;SQL 또는 MyBatis, JPA 등으로 실제 DB 쿼리 실행&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;보통 interface + 구현체 (&lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;UserDao&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;UserDaoImpl&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;내부에서 DTO나 VO를 주고받음&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #188038;&quot;&gt;주로 @Repository or @Mapper&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 붙음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  예:&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1769310068899&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Repository
public interface UserDao {
    User findById(String id);
}

// or

@Mapper
public interface UserMapper {
    User selectUserById(String id);
}&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;&lt;span style=&quot;color: #000000;&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;@Repository&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;나 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;@Mapper&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;는&amp;nbsp; &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;DAO&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 역할 인터페이스, 사용하는 프레임워크에 따라 다름&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #188038;&quot;&gt;@Repository&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &amp;rarr; 스프링 일반 컴포넌트 등록 (MyBatis에서도 사용 가능)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #188038;&quot;&gt;@Mapper&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &amp;rarr; MyBatis에서 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;자동으로 Mapper Proxy를 등록해주는 전용 애노테이션&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Spring Boot에서는 &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;@Mapper&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;를 자주 사용, Spring에서는 &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;@Repository&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; + &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;MapperScannerConfigurer&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 조합도 흔함&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Entity&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DB 테이블과 매핑되는 객체 (ORM 용도)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;JPA, Hibernate에서 &lt;/span&gt;&lt;span style=&quot;color: #188038;&quot;&gt;@Entity&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;로 사용됨&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;데이터 변경 감지를 위해 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;setter 있음&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;비즈니스 로직 포함하기도 함&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  예:&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1769310084451&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class User {
    @Id
    private Long id;
    private String name;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✅ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Model (Spring MVC)&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;View(ViewResolver, JSP 등)에 데이터를 넘기기 위한 객체&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨트롤러에서 View로 데이터 전달&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 시 사용&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #188038;&quot;&gt;Model.addAttribute(&quot;key&quot;, value)&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 식으로 전달&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  예:&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1769310093026&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@GetMapping(&quot;/user&quot;)
public String userDetail(Model model) {
    model.addAttribute(&quot;user&quot;, userDTO);
    return &quot;userPage&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3. 정리 그림 (흐름)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;[Client]&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;⬇&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;[Controller] &amp;rarr; View (Model)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;⬇ (DTO 사용)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;[Service]&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;⬇ (Entity, VO 사용)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;[DAO/Repository] ⬅&amp;rarr; DB (Entity 매핑)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;br /&gt;&lt;/b&gt; &lt;/p&gt;</description>
      <category>Backend/spring (Boot)</category>
      <category>spring 구조</category>
      <category>데이터 객체</category>
      <author>dddzr</author>
      <guid isPermaLink="true">https://sumni.tistory.com/485</guid>
      <comments>https://sumni.tistory.com/485#entry485comment</comments>
      <pubDate>Sun, 25 Jan 2026 12:02:57 +0900</pubDate>
    </item>
  </channel>
</rss>