<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>lee_dang.log</title>
        <link>https://velog.io/</link>
        <description>세계평화를 원하는 사람입니다.</description>
        <lastBuildDate>Thu, 05 Feb 2026 12:29:30 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>lee_dang.log</title>
            <url>https://velog.velcdn.com/images/lee_dang/profile/49437d1b-e22b-4c59-9aa2-d0e966f319a0/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. lee_dang.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/lee_dang" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Java 자료형 정리 – 배열, List, Set, Map]]></title>
            <link>https://velog.io/@lee_dang/Java-%EC%9E%90%EB%A3%8C%ED%98%95-%EC%A0%95%EB%A6%AC-%EB%B0%B0%EC%97%B4-List-Set-Map</link>
            <guid>https://velog.io/@lee_dang/Java-%EC%9E%90%EB%A3%8C%ED%98%95-%EC%A0%95%EB%A6%AC-%EB%B0%B0%EC%97%B4-List-Set-Map</guid>
            <pubDate>Thu, 05 Feb 2026 12:29:30 GMT</pubDate>
            <description><![CDATA[<h2 id="1️⃣-배열array--가장-기본-가장-단순한-구조">1️⃣ 배열(Array) – 가장 기본, 가장 단순한 구조</h2>
<h3 id="✅-특징">✅ 특징</h3>
<ul>
<li>크기 <strong>고정</strong></li>
<li>인덱스로 접근 (<code>O(1)</code>)</li>
<li>중복 허용</li>
<li>순서 유지</li>
</ul>
<pre><code class="language-java">int[] arr = new int[5];
String[] words = new String[3];</code></pre>
<h3 id="언제-쓰나">언제 쓰나?</h3>
<ul>
<li>데이터 개수가 <strong>처음부터 명확할 때</strong></li>
<li>성능이 중요한 경우</li>
</ul>
<h3 id="단점">단점</h3>
<ul>
<li>크기 변경 불가</li>
<li>중복 제거, 정렬 로직을 직접 구현해야 함</li>
</ul>
<p>👉 코테에서는 <strong>입력 개수가 유동적이면 잘 안 씀</strong></p>
<hr>
<h2 id="2️⃣-list--순서가-있는-자료들의-집합">2️⃣ List – 순서가 있는 자료들의 집합</h2>
<h3 id="대표-구현체">대표 구현체</h3>
<ul>
<li><code>ArrayList</code></li>
<li><code>LinkedList</code></li>
</ul>
<pre><code class="language-java">List&lt;String&gt; list = new ArrayList&lt;&gt;();</code></pre>
<h3 id="✅-특징-1">✅ 특징</h3>
<ul>
<li>입력 순서 유지</li>
<li>중복 허용</li>
<li>크기 자동 조절</li>
<li>정렬 가능</li>
</ul>
<pre><code class="language-java">Collections.sort(list);</code></pre>
<h3 id="언제-쓰나-1">언제 쓰나?</h3>
<ul>
<li>입력 순서가 중요할 때</li>
<li>정렬이 필요한 문제</li>
</ul>
<p>👉 <strong>코테에서 가장 많이 쓰는 자료형</strong></p>
<hr>
<h2 id="3️⃣-set--중복을-허용하지-않는-집합">3️⃣ Set – 중복을 허용하지 않는 집합</h2>
<h3 id="대표-구현체-1">대표 구현체</h3>
<table>
<thead>
<tr>
<th>타입</th>
<th>순서 유지</th>
<th>정렬</th>
<th>특징</th>
</tr>
</thead>
<tbody><tr>
<td>HashSet</td>
<td>❌</td>
<td>❌</td>
<td>가장 빠름</td>
</tr>
<tr>
<td>LinkedHashSet</td>
<td>⭕</td>
<td>❌</td>
<td>입력 순서 유지</td>
</tr>
<tr>
<td>TreeSet</td>
<td>⭕</td>
<td>⭕</td>
<td>자동 정렬</td>
</tr>
</tbody></table>
<pre><code class="language-java">Set&lt;String&gt; set = new HashSet&lt;&gt;();</code></pre>
<h3 id="✅-특징-2">✅ 특징</h3>
<ul>
<li><strong>중복 자동 제거</strong></li>
<li>인덱스 없음</li>
</ul>
<h3 id="언제-쓰나-2">언제 쓰나?</h3>
<ul>
<li>중복 제거가 목적일 때</li>
<li>&quot;같은 값이 있나?&quot;만 중요할 때</li>
</ul>
<hr>
<h2 id="4️⃣-map--key와-value의-관계-표현">4️⃣ Map – Key와 Value의 관계 표현</h2>
<pre><code class="language-java">Map&lt;String, Integer&gt; map = new HashMap&lt;&gt;();</code></pre>
<h3 id="✅-특징-3">✅ 특징</h3>
<ul>
<li>Key는 중복 ❌</li>
<li>Value는 중복 ⭕</li>
<li>순서 보장 X (기본)</li>
</ul>
<h3 id="대표-구현체-2">대표 구현체</h3>
<table>
<thead>
<tr>
<th>타입</th>
<th>순서</th>
<th>정렬</th>
<th>특징</th>
</tr>
</thead>
<tbody><tr>
<td>HashMap</td>
<td>❌</td>
<td>❌</td>
<td>기본 선택</td>
</tr>
<tr>
<td>LinkedHashMap</td>
<td>⭕</td>
<td>❌</td>
<td>입력 순서 유지</td>
</tr>
<tr>
<td>TreeMap</td>
<td>⭕</td>
<td>⭕</td>
<td>Key 기준 정렬</td>
</tr>
</tbody></table>
<h3 id="언제-쓰나-3">언제 쓰나?</h3>
<ul>
<li>빈도수 계산</li>
<li>이름 → 점수 같은 매핑</li>
</ul>
<p>👉 &quot;카운팅 문제&quot;의 거의 정답 자료형</p>
<hr>
<h2 id="5️⃣-정렬-관점에서-한-번에-정리">5️⃣ 정렬 관점에서 한 번에 정리</h2>
<table>
<thead>
<tr>
<th>자료형</th>
<th>정렬 방법</th>
</tr>
</thead>
<tbody><tr>
<td>Array</td>
<td><code>Arrays.sort()</code></td>
</tr>
<tr>
<td>List</td>
<td><code>Collections.sort()</code></td>
</tr>
<tr>
<td>Set</td>
<td>List로 변환 후 정렬</td>
</tr>
<tr>
<td>Map</td>
<td>Key/Entry를 List로 변환</td>
</tr>
</tbody></table>
<hr>
<h2 id="6️⃣-for-each-문과-자료형의-관계">6️⃣ for-each 문과 자료형의 관계</h2>
<pre><code class="language-java">for (String s : list) {
    System.out.println(s);
}</code></pre>
<ul>
<li>List, Set 모두 가능</li>
<li>내부적으로 Iterator 사용</li>
<li><strong>값을 읽는 용도</strong>에 적합</li>
</ul>
<p>❌ 반복 중 컬렉션 구조 변경 불가</p>
<hr>
<h2 id="7️⃣-코테에서-빠르게-선택하는-기준">7️⃣ 코테에서 빠르게 선택하는 기준</h2>
<ul>
<li>중복 제거 → <code>Set</code></li>
<li>정렬 필요 → <code>List</code></li>
<li>순서 유지 출력 → <code>List</code></li>
<li>Key-Value 관계 → <code>Map</code></li>
<li>성능 최우선 + 고정 크기 → <code>Array</code></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Redis와 Redis Sentinel]]></title>
            <link>https://velog.io/@lee_dang/Redis%EC%99%80-Redis-Sentinel</link>
            <guid>https://velog.io/@lee_dang/Redis%EC%99%80-Redis-Sentinel</guid>
            <pubDate>Wed, 10 Dec 2025 18:05:22 GMT</pubDate>
            <description><![CDATA[<p>프로젝트 완료 후 유지보수 측면에서
SPOF(single point of failure)로 꼽혔던 redis에 대한 문제를
Redis Sentinel을 적용하여 보완하기로 했다.
*SPOF: 특정 구성 요소가 장애가 나면 전체 시스템이 중단되는 문제</p>
<h2 id="1-현재-redis-세팅단일객체">1. 현재 redis 세팅(단일객체)</h2>
<p><img src="https://velog.velcdn.com/images/lee_dang/post/9a1fa3af-87aa-483b-9d73-efbfd264025d/image.png" alt="">
정보를 담아 둘 Redis 객체가 하나뿐인 현재는 Redis 서버가 다운되면 refreshToken을 통한 인증(연장) 마비, 예약된 테이블을 조회할 수 있게 해주는 실시간 서비스 마비 등 프로그램에 치명적인 영향을 끼치는 상태이다.</p>
<h2 id="2-대처방안">2. 대처방안</h2>
<ul>
<li>Redis Sentinel을 사용하여 고가용성 구조로 전환<blockquote>
<p>고가용성(High Availability, HA) 구조는 시스템이 장애 상황에서도 서비스를 지속적으로 제공할 수 있도록 설계된 아키텍처를 의미한다.</p>
</blockquote>
</li>
</ul>
<p>※ windows에서는 redis sentinel 구성설정을 지원하지 않으므로 Docker-redis를 이용한 sentinel 빌드를 하기로 함</p>
<h2 id="3-진행순서">3. 진행순서</h2>
<h3 id="1️⃣-root프로젝트-외부에-redis-sentinel을-설정파일을-담을-디렉토리-docker-composeyml생성">1️⃣ Root(프로젝트 외부)에 Redis Sentinel을 설정파일을 담을 디렉토리, docker-compose.yml생성</h3>
<p><img src="https://velog.velcdn.com/images/lee_dang/post/35dd7797-3eec-4e4e-b926-7805db9c7578/image.png" alt=""></p>
<ul>
<li>docker-compose.yml<pre><code class="language-yml">version: &#39;3&#39;
</code></pre>
</li>
</ul>
<p>services:</p>
<p>  redis-master:
    image: redis:7
    container_name: redis-master
    hostname: redis-master
    ports:
      - &quot;6379:6379&quot;
    volumes:
      - ./master/redis.conf:/usr/local/etc/redis/redis.conf
      - master-data:/data
    command: [&quot;redis-server&quot;, &quot;/usr/local/etc/redis/redis.conf&quot;]
    networks:
      - redis-network
    healthcheck:
      test: [&quot;CMD&quot;, &quot;redis-cli&quot;, &quot;ping&quot;]
      interval: 5s
      timeout: 3s
      retries: 5</p>
<p>  redis-replica:
    image: redis:7
    container_name: redis-replica
    hostname: redis-replica
    ports:
      - &quot;6380:6379&quot;
    depends_on:
      redis-master:
        condition: service_healthy
    volumes:
      - ./replica/redis.conf:/usr/local/etc/redis/redis.conf
      - replica-data:/data
    command: [&quot;redis-server&quot;, &quot;/usr/local/etc/redis/redis.conf&quot;]
    networks:
      - redis-network</p>
<p>  sentinel1:
    image: redis:7
    container_name: redis-sentinel1
    hostname: redis-sentinel1
    ports:
      - &quot;6381:26379&quot;
    depends_on:
      redis-master:
        condition: service_healthy
    volumes:
      - ./sentinel1:/usr/local/etc/redis
    command: [&quot;redis-sentinel&quot;, &quot;/usr/local/etc/redis/sentinel.conf&quot;]
    networks:
      - redis-network
    restart: on-failure</p>
<p>  sentinel2:
    image: redis:7
    container_name: redis-sentinel2
    hostname: redis-sentinel2
    ports:
      - &quot;6382:26379&quot;
    depends_on:
      redis-master:
        condition: service_healthy
    volumes:
      - ./sentinel2:/usr/local/etc/redis
    command: [&quot;redis-sentinel&quot;, &quot;/usr/local/etc/redis/sentinel.conf&quot;]
    networks:
      - redis-network
    restart: on-failure</p>
<p>  sentinel3:
    image: redis:7
    container_name: redis-sentinel3
    hostname: redis-sentinel3
    ports:
      - &quot;6383:26379&quot;
    depends_on:
      redis-master:
        condition: service_healthy
    volumes:
      - ./sentinel3:/usr/local/etc/redis
    command: [&quot;redis-sentinel&quot;, &quot;/usr/local/etc/redis/sentinel.conf&quot;]
    networks:
      - redis-network
    restart: on-failure</p>
<p>volumes:
  master-data:
  replica-data:</p>
<p>networks:
  redis-network:
    driver: bridge</p>
<pre><code>

### 2️⃣ 각각의 디렉토리에 설정을 담은 .conf파일 생성
&gt;- /master/redis.conf</code></pre><p>port 6379
bind 0.0.0.0
protected-mode no
replica-announce-ip 127.0.0.1
replica-announce-port 6379
appendonly yes
appendfilename &quot;appendonly.aof&quot;</p>
<pre><code>
&gt;- /replica/redis.conf</code></pre><p>port 6379
bind 0.0.0.0
protected-mode no</p>
<h1 id="replica-announce-설정-추가">Replica announce 설정 추가</h1>
<p>replica-announce-ip 127.0.0.1
replica-announce-port 6380
appendonly yes
appendfilename &quot;appendonly.aof&quot;</p>
<h1 id="master는-docker-내부-ip-유지">Master는 Docker 내부 IP 유지</h1>
<p>replicaof 172.19.0.2 6379
slave-priority 100
replica-read-only yes</p>
<pre><code>
&gt;- /sentinel1/sentinel.conf
```conf
port 26379
bind 0.0.0.0
protected-mode no
sentinel resolve-hostnames no
sentinel announce-hostnames no
# IP 주소로 모니터링 (Master IP를 확인 후 입력)
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel announce-ip &quot;127.0.0.1&quot;
sentinel announce-port 6381
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 10000
sentinel deny-scripts-reconfig yes</code></pre><p>sentinel2,3은 포트번호 이외에 모두 동일(6381,6382,6383순)</p>
<h3 id="redis의-root로-이동후-실행">redis의 root로 이동후 실행</h3>
<p>docker desktop을 먼저 실행 후 root디렉토리에서</p>
<pre><code class="language-cmd"># docker-compose.yml에 정의된 컨테이너들을 백그라운드(-d)에서 실행
1. docker-compose up -d

# 현재 실행 중인 도커 컨테이너 목록과 상태를 출력
2. docker ps

# &#39;sentinel1&#39; 서비스의 로그를 실시간(-f)으로 확인
3. docker-compose logs -f sentinel1

# &#39;redis-replica&#39; 컨테이너에 접속(-it)하여 
# redis-cli를 실행하고, 복제(replication) 상태 정보를 출력
4. docker exec -it redis-replica redis-cli info replication
4-1. docker stop redis-master
4-2. docker exec -it redis-replica redis-cli info replication</code></pre>
<h4 id="1-실행된-docker-컨테이너들">1. 실행된 docker 컨테이너들<img src="https://velog.velcdn.com/images/lee_dang/post/b0cee4fd-5f49-42ef-ae72-b2e1a507e125/image.png" alt=""></h4>
<h4 id="2-실행-중인-컨테이너-목록과-상태">2. 실행 중인 컨테이너 목록과 상태 <img src="https://velog.velcdn.com/images/lee_dang/post/4a9235d1-310e-4865-9f9c-8d1bf317a75a/image.png" alt=""></h4>
<h4 id="3-실시간-확인이-가능한-로그">3. 실시간 확인이 가능한 로그<img src="https://velog.velcdn.com/images/lee_dang/post/84d5d5c4-2a7d-461f-a225-02b13ce38105/image.png" alt=""></h4>
<h4 id="4-master를-종료하자-역할이-뒤바뀐-replica와-master">4. master를 종료하자 역할이 뒤바뀐 replica와 master<img src="https://velog.velcdn.com/images/lee_dang/post/8b7cfdf1-6848-4796-a8e8-5b5d2c6dda14/image.png" alt=""></h4>
<p>이후 <code>docker stop redis-replica</code>명령어로 replica를 종료해 본 결과 master가 다시 master 역할로 돌아오는 것을 확인 하였다.</p>
<h3 id="회고">회고</h3>
<p>현재 상태에서는 Docker가 실행 중일 때만 Redis HA가 작동하므로
추후 cloud등의 서비스에 Redis Sentinel환경을 구축하여 항시 작동하는 로직이 추가되어야 할 것 같다.</p>
<p>또한 하지만 두 개의 컨테이너가 모두 종료되는 경우 또 다시 서비스에 차질이 생기므로 분산환경에의 redis객체 구축이 필요할 것으로 보인다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ResponseEntity]]></title>
            <link>https://velog.io/@lee_dang/ResponseEntity</link>
            <guid>https://velog.io/@lee_dang/ResponseEntity</guid>
            <pubDate>Wed, 10 Dec 2025 11:50:11 GMT</pubDate>
            <description><![CDATA[<p>Spring 기반 개발을 하다 보면 서비스 로직 작성 중에 ResponseEntity를 정말 자주 보게 된다.</p>
<h2 id="💻-responseentity">💻 ResponseEntity</h2>
<p>HTTP 응답 전체를 직접 구성할 수 있는 Spring의 클래스</p>
<blockquote>
<p><strong>ResponseEntity가 제어할 수 있는 3요소</strong></p>
<ul>
<li>HTTP Status Code</li>
<li>HTTP Headers</li>
<li>Response Body (JSON, String, Object)</li>
</ul>
</blockquote>
<h3 id="왜-responseentity를-사용하는가">왜 ResponseEntity를 사용하는가</h3>
<h4 id="1️⃣-http-status코드를-정확히-내려줄-수-있음">1️⃣ HTTP status코드를 정확히 내려줄 수 있음</h4>
<p>리소스 생성 시 201 상태로 명확하게 응답예시</p>
<pre><code class="language-java">return ResponseEntity.status(HttpStatus.CREATED).body(data);</code></pre>
<h4 id="2️⃣-응답-header-세팅이-필요할-때">2️⃣ 응답 Header 세팅이 필요할 때</h4>
<p>JWT, Cookie기반 인증시 필수적</p>
<pre><code class="language-java">return ResponseEntity.ok()
        .header(&quot;Set-Cookie&quot;, cookie)
        .body(userInfo);</code></pre>
<h4 id="3️⃣-body에-객체를-자유롭게-담을-수-있음">3️⃣ body에 객체를 자유롭게 담을 수 있음</h4>
<p>담긴 객체는 자동으로 JSON문자열로 변환 됨</p>
<pre><code class="language-java">return ResponseEntity.ok(new UserResponse(...));
</code></pre>
<h4 id="4️⃣-에러-핸들링을-명확하게-할-수-있음">4️⃣ 에러 핸들링을 명확하게 할 수 있음</h4>
<p>에러 상황에서 적절한 상태 코드와 함께 커스텀 에러 메시지 전달이 가능</p>
<pre><code class="language-java">// 404 에러 응답 예시
return ResponseEntity.status(HttpStatus.NOT_FOUND)
        .body(new ErrorResponse(&quot;USER_NOT_FOUND&quot;, &quot;해당 사용자를 찾을 수 없습니다.&quot;));

// 400 에러 응답 예시
return ResponseEntity.badRequest()
        .body(new ErrorResponse(&quot;INVALID_INPUT&quot;, &quot;이메일 형식이 올바르지 않습니다.&quot;));</code></pre>
<h3 id="정리">정리</h3>
<p>다음과 같은 상황에서는 ResponseEntity는 선택이 아닌 필수이다. </p>
<ul>
<li>인증/인가 구현 시: JWT 토큰이나 세션 쿠키를 헤더에 담아 전달</li>
<li>RESTful API 설계 시: 리소스 생성(201), 수정(200), 삭제(204) 등 정확한 상태 코드 반환</li>
<li>에러 핸들링 시: 4xx, 5xx 에러와 함께 커스텀 에러 메시지 전달</li>
</ul>
<p>단순히 데이터만 반환하는 @ResponseBody와 달리, ResponseEntity는 HTTP 통신의 모든 측면을 제어할 수 있게 해주기 때문이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JWT란?]]></title>
            <link>https://velog.io/@lee_dang/JWT%EB%9E%80</link>
            <guid>https://velog.io/@lee_dang/JWT%EB%9E%80</guid>
            <pubDate>Sat, 06 Dec 2025 10:02:34 GMT</pubDate>
            <description><![CDATA[<h1 id="jwtjson-web-token">JWT(Json Web Token)</h1>
<p>프로젝트를 진행하며 다루었던 JWT에 대한 복습 겸 정리를 해보려고 한다.</p>
<hr>
<h2 id="🧩-jwt란">🧩 JWT란?</h2>
<p><strong>Json Web Token</strong>의 약자로, 사용자 인증/인가 정보를 JSON 형식으로 담아 클라이언트와 서버가 주고받는 서명된 토큰</p>
<h3 id="주요-특징">주요 특징</h3>
<ul>
<li><strong>Stateless</strong>: 서버가 세션을 저장하지 않아도 됨</li>
<li>클라이언트가 매 요청마다 토큰을 보내서 인증</li>
<li>토큰 변조를 <strong>서명(Signature)</strong>으로 방지</li>
</ul>
<hr>
<h2 id="📦-jwt-구조-3가지-파트">📦 JWT 구조 (3가지 파트)</h2>
<p>JWT는 <code>.</code>으로 구분된 3개의 Base64Url 문자열로 구성</p>
<pre><code>xxxxx.yyyyy.zzzzz
Header.Payload.Signature</code></pre><h3 id="1️⃣-header-헤더">1️⃣ Header (헤더)</h3>
<pre><code class="language-json">{
  &quot;alg&quot;: &quot;HMAC SHA256&quot;,
  &quot;typ&quot;: &quot;JWT&quot;
}</code></pre>
<ul>
<li><strong>alg</strong>: 서명 알고리즘 (HMAC SHA256, RS256 등)</li>
<li><strong>typ</strong>: 토큰 타입 (JWT)</li>
</ul>
<p>→ 이 JSON을 Base64Url로 인코딩한 것이 헤더 부분이다.</p>
<hr>
<h3 id="2️⃣-payload-페이로드">2️⃣ Payload (페이로드)</h3>
<p>토큰에 담긴 실제 데이터(클레임, Claims)</p>
<h4 id="대표적인-클레임">대표적인 클레임</h4>
<ul>
<li><strong>sub</strong>: 사용자 식별자 (주체, Subject)</li>
<li><strong>iat</strong>: 발급 시간 (Issued At)</li>
<li><strong>exp</strong>: 만료 시간 (Expiration)</li>
</ul>
<pre><code class="language-json">{
  &quot;sub&quot;: &quot;user123&quot;,
  &quot;role&quot;: &quot;USER&quot;,
  &quot;exp&quot;: 1700000000
}</code></pre>
<p>→ Header와 마찬가지로 Base64Url 인코딩</p>
<blockquote>
<p>※ Payload는 <strong>암호화가 아니라 인코딩</strong>이므로
<strong>민감 정보(비밀번호 등)를 절대 넣지 않도록 한다.</strong></p>
</blockquote>
<hr>
<h3 id="3️⃣-signature-서명">3️⃣ Signature (서명)</h3>
<p>토큰 위변조 방지를 위한 서명 부분입니다.</p>
<h4 id="예시-hs256-알고리즘">예시: HS256 알고리즘</h4>
<pre><code>HMACSHA256(
    Base64UrlEncode(header) + &quot;.&quot; + Base64UrlEncode(payload),
    secret
)</code></pre><p>서버는 이 Signature를 검증해 토큰이 조작되지 않았는지 확인함</p>
<p><strong>💡 Secret Key 관리</strong></p>
<blockquote>
</blockquote>
<p>서명에 사용되는 secret은 보안상 매우 중요하므로, 코드에 직접 작성하지 않고 application.properties 또는 application.yml 파일에서 관리</p>
<hr>
<h2 id="✅-jwt의-장점">✅ JWT의 장점</h2>
<ul>
<li><strong>무상태(Stateless)</strong>: 서버 확장 용이, 스케일 아웃 쉬움</li>
<li>HTTP Header에 실어서 보내기 편함</li>
<li>서버 저장소 불필요 → 로드 밸런싱에 유리</li>
<li>MSA(마이크로서비스) 환경에 적합</li>
</ul>
<hr>
<h2 id="❗-단점-및-주의사항">❗ 단점 및 주의사항</h2>
<table>
<thead>
<tr>
<th>단점</th>
<th>해결 방안</th>
</tr>
</thead>
<tbody><tr>
<td>토큰 탈취 시 만료까지 악용 가능</td>
<td>RefreshToken 전략, 짧은 만료 시간 설정</td>
</tr>
<tr>
<td>Payload가 암호화되지 않음</td>
<td>민감 정보 포함 금지</td>
</tr>
</tbody></table>
<!-- | 토큰 길이가 긺 | 쿠키/세션 대비 네트워크 오버헤드 |
| 즉시 무효화 어려움 | 블랙리스트(Redis) 또는 짧은 만료 시간 | -->

]]></description>
        </item>
        <item>
            <title><![CDATA[도메인 구매하여 포트폴리오 연동하기]]></title>
            <link>https://velog.io/@lee_dang/%EB%8F%84%EB%A9%94%EC%9D%B8-%EA%B5%AC%EB%A7%A4%ED%95%98%EC%97%AC-%ED%8F%AC%ED%8A%B8%ED%8F%B4%EB%A6%AC%EC%98%A4-%EC%97%B0%EB%8F%99%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@lee_dang/%EB%8F%84%EB%A9%94%EC%9D%B8-%EA%B5%AC%EB%A7%A4%ED%95%98%EC%97%AC-%ED%8F%AC%ED%8A%B8%ED%8F%B4%EB%A6%AC%EC%98%A4-%EC%97%B0%EB%8F%99%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 01 Dec 2025 10:44:14 GMT</pubDate>
            <description><![CDATA[<h2 id="도메인에-github-pages로-배포중인-포트폴리오를-연결하기">도메인에 Github Pages로 배포중인 포트폴리오를 연결하기</h2>
<blockquote>
<p>운이 좋게도 내 이름으로 된 도메인이 남아있어 연 2만원 정도의 금액을 주고 도메인을 구매했다.
<img src="https://velog.velcdn.com/images/lee_dang/post/d812211a-706d-49ca-b98f-ee97e7ad7991/image.png" alt=""></p>
</blockquote>
<h3 id="1️⃣-repository-pages탭에-구매한-도메인-입력">1️⃣ repository pages탭에 구매한 도메인 입력</h3>
<p><img src="https://velog.velcdn.com/images/lee_dang/post/b043c2f3-e2be-4734-a2c3-c275b8c729b9/image.png" alt="">도메인 구매 후 다음과 같이 Custom Domain을 설정하는 것 만으로는 바로 프로젝트 출력이 되지 않는 것을 확인했다.</p>
<hr>
<h3 id="2️⃣-도메인에-dns레코드-할당">2️⃣ 도메인에 DNS레코드 할당</h3>
<p>깃허브 공식문서(<a href="https://docs.github.com/en/pages)%EC%97%90%EC%84%9C">https://docs.github.com/en/pages)에서</a> 지원하는 DNS레코드 값을 도메인을 구매한 서비스에 할당해 주어야 한다.<img src="https://velog.velcdn.com/images/lee_dang/post/e5b3af4f-340b-42df-a075-b3bdf57a2888/image.png" alt=""></p>
<blockquote>
<p>할당된 DNS레코드 모달<img src="https://velog.velcdn.com/images/lee_dang/post/87059021-b65f-421a-a5aa-4b888b7505db/image.png" alt=""></p>
</blockquote>
<p>DNS Check가 완료된 후 Page Tab<img src="https://velog.velcdn.com/images/lee_dang/post/bf5834dd-7af8-4ea5-a459-78b277e2a855/image.png" alt=""></p>
<hr>
<h3 id="3️⃣-packagejson수정">3️⃣ package.json수정<img src="https://velog.velcdn.com/images/lee_dang/post/535de336-d2af-4ffb-8e5e-4462314275f3/image.png" alt=""></h3>
<p>원래 쓰던 도메인을 새로 구매한 도메인으로 변경</p>
<hr>
<h3 id="4️⃣-프로젝트-재빌드">4️⃣ 프로젝트 재빌드<img src="https://velog.velcdn.com/images/lee_dang/post/43880575-0966-4e19-93e5-8d34a6573e8e/image.png" alt=""></h3>
<hr>
<h3 id="5️⃣-경로수정트러블-슈팅">5️⃣ 경로수정(트러블 슈팅)<img src="https://velog.velcdn.com/images/lee_dang/post/19173949-a9af-471b-a08f-55d1cd753426/image.png" alt=""></h3>
<p>도메인 할당을 완료했으나 경로때문에 React 프로젝트를 읽어오지 못하는 상황 발생</p>
<blockquote>
<p>경로 문제인 줄 알았던 페이지가 이전 Cache의 영향을 받은게 원인이었음을 확인, 아래의 방법으로 캐시 초기화 후 재빌드 해서 해결<img src="https://velog.velcdn.com/images/lee_dang/post/b57e7572-8912-4317-a96b-8db21889a7f8/image.png" alt=""></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/lee_dang/post/13ee7051-efd2-4499-a89a-8d158008065a/image.png" alt="">원하는 도메인에 포트폴리오가 나오는 것을 확인 할 수 있었다.</p>
<hr>
<h3 id="🛠️-bugfix">🛠️ BugFix</h3>
<p>yml에 custom된 도메인을 추가하여 빌드 할 떄마다 초기화되는 버그를 픽스<img src="https://velog.velcdn.com/images/lee_dang/post/6a2d22f0-30b3-426e-9f92-c55ec2ad7595/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[변수와 접근제한자]]></title>
            <link>https://velog.io/@lee_dang/%EB%B3%80%EC%88%98%EC%99%80-%EC%A0%91%EA%B7%BC%EC%A0%9C%ED%95%9C%EC%9E%90</link>
            <guid>https://velog.io/@lee_dang/%EB%B3%80%EC%88%98%EC%99%80-%EC%A0%91%EA%B7%BC%EC%A0%9C%ED%95%9C%EC%9E%90</guid>
            <pubDate>Wed, 26 Nov 2025 10:52:23 GMT</pubDate>
            <description><![CDATA[<h1 id="📗-접근-제어자란">📗 접근 제어자란?</h1>
<p><strong>접근 제어자(Access Modifier)</strong>란
👉 <strong>클래스, 필드(변수), 메서드, 생성자에 대해
“어디까지 접근을 허용할지 범위를 정하는 키워드”</strong>이다.</p>
<h2 id="접근제어자-사용-범위">접근제어자 사용 범위</h2>
<blockquote>
<ul>
<li>접근 제어자는 클래스, 필드(변수), 메서드, 생성자에 적용할 수 있으며,</li>
<li>각 요소의 외부 접근 가능 범위를 제어해 객체의 구조와 데이터를 보호한다.</li>
</ul>
</blockquote>
<h2 id="🗒️-java-접근-제어자-정리-access-modifier">🗒️ Java 접근 제어자 정리 (Access Modifier)</h2>
<hr>
<h3 id="1️⃣-public--완전-개방형">1️⃣ <code>public</code> — 완전 개방형</h3>
<blockquote>
<p><strong>어디서든 접근 가능</strong></p>
</blockquote>
<ul>
<li>패키지 밖이든</li>
<li>클래스 밖이든</li>
<li>다른 프로젝트 모듈이든
→ <strong>전부 접근 가능</strong></li>
</ul>
<pre><code class="language-java">public int age;</code></pre>
<h4 id="✅-특징">✅ 특징</h4>
<ul>
<li>접근 제한 없음</li>
<li>공개 API 만들 때 주로 사용</li>
<li>너무 남발하면 <strong>캡슐화 깨져서 유지보수 힘들어짐</strong></li>
</ul>
<p>👉 <strong>가장 넓은 접근 범위</strong></p>
<hr>
<h3 id="2️⃣-protected--조금-좁혀진-공개-범위">2️⃣ <code>protected</code> — 조금 좁혀진 공개 범위</h3>
<pre><code class="language-java">protected int score;</code></pre>
<h4 id="✅-특징-1">✅ 특징</h4>
<ul>
<li><strong>같은 패키지</strong> → 바로 접근 가능</li>
<li><strong>다른 패키지</strong> → <em>상속받은 자식 클래스만</em> 접근 가능</li>
<li>👉 <strong>상속 관계에서 자주 사용</strong></li>
</ul>
<hr>
<h3 id="3️⃣-default--아무것도-안-쓰는-경우">3️⃣ <code>default</code> — 아무것도 안 쓰는 경우</h3>
<blockquote>
<p><strong>패키지 전용 접근</strong></p>
</blockquote>
<p>키워드가 없어서 <strong>“default 접근제어자”</strong>라고 부름</p>
<pre><code class="language-java">int level;   // default</code></pre>
<h4 id="✅-특징-2">✅ 특징</h4>
<ul>
<li><strong>같은 패키지 안에서는 접근 가능</strong></li>
<li><strong>다른 패키지에서는 절대 접근 불가</strong></li>
</ul>
<hr>
<h3 id="4️⃣-private--가장-폐쇄적">4️⃣ <code>private</code> — 가장 폐쇄적</h3>
<blockquote>
<p><strong>오직 같은 클래스 내부에서만 접근 가능</strong></p>
</blockquote>
<pre><code class="language-java">private String password;</code></pre>
<h4 id="✅-특징-3">✅ 특징</h4>
<ul>
<li>객체 내부에서만 사용</li>
<li>외부에서 절대 접근 불가</li>
<li><strong>캡슐화할 때 가장 많이 씀</strong>
→ <code>getter / setter</code>로 접근 조절</li>
</ul>
<p>👉 <strong>가장 좁은 접근 범위</strong></p>
<hr>
<h3 id="🔥-접근-범위-정리표">🔥 접근 범위 정리표</h3>
<table>
<thead>
<tr>
<th>제한자</th>
<th>접근 가능 범위</th>
<th>범위 크기</th>
</tr>
</thead>
<tbody><tr>
<td><code>public</code></td>
<td>어디서든</td>
<td>⭐⭐⭐⭐ (가장 넓음)</td>
</tr>
<tr>
<td><code>protected</code></td>
<td>동일 패키지 + 상속받은 클래스</td>
<td>⭐⭐⭐</td>
</tr>
<tr>
<td><code>default</code></td>
<td>동일 패키지</td>
<td>⭐⭐</td>
</tr>
<tr>
<td><code>private</code></td>
<td>동일 클래스</td>
<td>⭐ (가장 좁음)</td>
</tr>
</tbody></table>
<hr>
<h3 id="💡-어디에-어떻게-쓰면-좋냐">💡 어디에 어떻게 쓰면 좋냐?</h3>
<ul>
<li><p>✅ <strong><code>private</code></strong>
→ 거의 모든 <strong>필드(속성)</strong>
→ 외부에서 막 써버리면 객체 무너짐</p>
</li>
<li><p>✅ <strong><code>public</code></strong>
→ 진짜 <strong>외부에 공개해야 할 메서드</strong></p>
</li>
<li><p>✅ <strong><code>protected</code></strong>
→ <strong>자식 클래스에 기능 열어주고 싶을 때</strong></p>
</li>
<li><p>✅ <strong><code>default</code></strong>
→ <strong>패키지 단위로 묶어서 관리할 때</strong></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[생성자]]></title>
            <link>https://velog.io/@lee_dang/%EC%83%9D%EC%84%B1%EC%9E%90-3b0cuyp8</link>
            <guid>https://velog.io/@lee_dang/%EC%83%9D%EC%84%B1%EC%9E%90-3b0cuyp8</guid>
            <pubDate>Tue, 25 Nov 2025 06:37:27 GMT</pubDate>
            <description><![CDATA[<h2 id="☕️-자바java-생성자constructor-핵심-요약-객체를-만드는-코드">☕️ 자바(Java) 생성자(Constructor) 핵심 요약: 객체를 만드는 코드</h2>
<p>자바에서 <strong>생성자(Constructor)</strong>는 객체가 &quot;태어날 때&quot; 처음 세팅을 담당.</p>
<h3 id="1️⃣-생성자">1️⃣ 생성자</h3>
<p>생성자는 클래스로부터 인스턴스(객체)를 만들 때 무조건 호출되는 <strong>&#39;객체 초기화 메서드&#39;</strong>
객체를 쓰기 전에 필요한 초기 상태를 맞춰주는 역할</p>
<h3 id="2️⃣-생성자의-주요-특징들">2️⃣ 생성자의 주요 특징들</h3>
<p>특징    내용
이름    클래스 이름이랑 대소문자까지 똑같아야 함
반환 타입    return값이 없음(void도 안씀)
호출 시점    new 키워드로 객체 생성시 한 번만 호출
목적    인스턴스 변수(필드)의 초기값을 할당해주기 위함</p>
<h3 id="3️⃣-디폴트-생성자-default-constructor">3️⃣ 디폴트 생성자 (Default Constructor)</h3>
<p>생성자를 만들지 않을 경우
자바 컴파일러가 알아서 매개변수 없는 <strong>&#39;디폴트 생성자&#39;</strong>를 생성해 줌
이 디폴트 생성자가 호출되면, 변수들은 타입별 기본값으로 초기화됨.
변수 타입    기본값 (초기값)
참조 타입 (String, Class 등)    null (아무것도 없음)
정수형 (int, short, long 등)    0
실수형 (double, float)    0.0
논리형 (boolean)    false
문자형 (char)    &#39;\u0000&#39; (빈 문자)</p>
<h3 id="4️⃣-생성자-사용-예시-코드">4️⃣ 생성자 사용 예시 (코드)</h3>
<p>직접 생성자를 만들면, 객체를 만들 때 꼭 필요한 값을 넣어주도록 강제할 수 있음</p>
<pre><code class="language-java">public class Car {
    String model;
    int year;

    // 우리가 만든 생성자 (파라미터 있음)
    public Car(String modelName, int manufacturedYear) {
        this.model = modelName;      // 초기값 세팅
        this.year = manufacturedYear; // 초기값 세팅
        System.out.println(&quot;🚗 &quot; + model + &quot; 객체 생성 완료!&quot;);
    }

    // 참고: 이 생성자를 만들면 기본 생성자는 자동으로 안 생김
}</code></pre>
<p>객체 만들기:</p>
<pre><code class="language-java">// 객체 만들자마자 생성자 호출되고 초기화됨
Car myCar = new Car(&quot;테슬라 모델 Y&quot;, 2024);
// 출력 결과: 테슬라 모델 Y 객체 생성</code></pre>
<p>결론: 생성자는 자바에서 객체가 제대로 된 초기 상태를 갖도록 보장하는 필수적인 &quot;초기화 담당&quot;</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Java와 객체지향]]></title>
            <link>https://velog.io/@lee_dang/Java%EC%99%80-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5</link>
            <guid>https://velog.io/@lee_dang/Java%EC%99%80-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5</guid>
            <pubDate>Mon, 24 Nov 2025 06:28:31 GMT</pubDate>
            <description><![CDATA[<h1 id="📘-java-객체와-클래스">📘 Java 객체와 클래스</h1>
<p>Java를 처음 배우면서 가장 이해하기 힘들었던 개념이 객체(지향)이었다.
오늘은 그 객체와 더불어 java의 class에 대한 정리도 같이 하기로 했다.</p>
<hr>
<h2 id="🤔-객체object란">🤔 객체(Object)란?</h2>
<p>객체(Object)는 쉽게 말해 <strong>현실 세계의 사물이나 개념을 코드로 표현한 것</strong>이다.</p>
<p>예를 들어, 여러분 앞에 스마트폰이 있다고 생각해보자. 이 스마트폰은:</p>
<ul>
<li><strong>속성(특징)</strong>을 가지고 있다: 색상, 크기, 배터리 용량, 모델명 등</li>
<li><strong>동작(행동)</strong>을 할 수 있다: 전화 걸기, 문자 보내기, 사진 찍기 등</li>
</ul>
<p>프로그래밍에서 객체도 마찬가지다. 객체는 <strong>데이터(속성)</strong>와 그 데이터를 처리하는 <strong>메서드(동작)</strong>를 하나로 묶어놓은 것이다.</p>
<p><strong>중요한 점은, 한 번 생성된 객체는 메모리 상에 실체로서 존재하게 되고, 프로그램 어디서든 그 객체를 불러내서 재사용할 수 있다는 것이다.</strong> 이게 바로 객체의 핵심이다.</p>
<hr>
<h2 id="🤔-클래스class는">🤔 클래스(Class)는?</h2>
<p>클래스는 <strong>객체를 만들기 위한 설계도</strong> 또는 <strong>틀</strong>이라고 생각하면 된다.</p>
<p>붕어빵을 만든다고 생각해보자:</p>
<ul>
<li><strong>붕어빵 틀</strong> = 클래스</li>
<li><strong>실제로 만들어진 붕어빵</strong> = 🐟객체</li>
</ul>
<p>하나의 틀(클래스)로 여러 개의 붕어빵(객체)을 찍어낼 수 있는 것처럼, 하나의 클래스로 여러 개의 객체를 만들 수 있다.</p>
<hr>
<h2 id="실제-코드로-정리-💻">실제 코드로 정리 💻</h2>
<h3 id="1-클래스-정의">1. 클래스 정의</h3>
<pre><code class="language-java">public class Smartphone {
    // 속성 (필드, 멤버 변수)
    String brand;      // 브랜드
    String model;      // 모델명
    String color;      // 색상

    // 동작 (메서드)
    void call(String number) {
        System.out.println(number + &quot;로 전화를 겁니다.&quot;);
    }

    void sendMessage(String message) {
        System.out.println(&quot;메시지 전송: &quot; + message);
    }
}</code></pre>
<hr>
<h3 id="2-객체-생성-사용">2. 객체 생성, 사용</h3>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        // 객체 생성 (인스턴스화) - 이 순간 메모리에 실체가 만들어진다!
        Smartphone myPhone = new Smartphone();

        // 속성에 값 할당
        myPhone.brand = &quot;Samsung&quot;;
        myPhone.model = &quot;Galaxy S24&quot;;
        myPhone.color = &quot;Black&quot;;

        // 이제 이 객체(myPhone)를 언제든지 불러서 사용할 수 있다
        myPhone.call(&quot;010-1234-5678&quot;);
        myPhone.sendMessage(&quot;안녕하세요!&quot;);

        // 다른 메서드에서도 사용 가능
        usePhone(myPhone);

        // 또 다른 객체 생성 - 완전히 별개의 실체
        Smartphone friendPhone = new Smartphone();
        friendPhone.brand = &quot;Apple&quot;;
        friendPhone.model = &quot;iPhone 15&quot;;
        friendPhone.color = &quot;White&quot;;

        // 같은 클래스로 만들었지만 서로 다른 객체!
        // myPhone과 friendPhone은 각각 독립적으로 존재한다
        System.out.println(&quot;내 폰: &quot; + myPhone.model);
        System.out.println(&quot;친구 폰: &quot; + friendPhone.model);
    }

    // 다른 메서드에서도 객체를 전달받아 사용 가능!
    static void usePhone(Smartphone phone) {
        phone.sendMessage(&quot;다른 메서드에서도 사용 가능!&quot;);
    }
}</code></pre>
<hr>
<h3 id="3-생성자constructor-활용하기">3. 생성자(Constructor) 활용하기</h3>
<p>매번 속성을 하나씩 설정하기 번거로우니, 생성자를 사용하면 객체를 만들 때 바로 값을 넣을 수 있다.</p>
<pre><code class="language-java">public class Smartphone {
    String brand;
    String model;
    int battery;
    String color;

    // 생성자
    public Smartphone(String brand, String model, String color) {
        this.brand = brand;
        this.model = model;
        this.color = color;
        this.battery = 100;  // 초기 배터리는 100%
    }

    void call(String number) {
        System.out.println(number + &quot;로 전화를 겁니다.&quot;);
    }
}

// 사용 예시
Smartphone myPhone = new Smartphone(&quot;Samsung&quot;, &quot;Galaxy S24&quot;, &quot;Black&quot;);</code></pre>
<hr>
<h2 id="📚-용어-정리">📚 용어 정리</h2>
<ul>
<li><strong>클래스(Class)</strong>: 객체를 만들기 위한 설계도</li>
<li><strong>객체(Object)</strong>: 클래스를 바탕으로 만들어진 실체</li>
<li><strong>인스턴스(Instance)</strong>: 객체와 같은 의미 (클래스로부터 만들어진 것)</li>
<li><strong>필드(Field)</strong>: 객체의 속성, 데이터 (brand, model 등)</li>
<li><strong>메서드(Method)</strong>: 객체의 동작, 기능 (call, sendMessage 등)</li>
<li><strong>생성자(Constructor)</strong>: 객체 생성 시 호출되는 특별한 메서드</li>
</ul>
<hr>
<h2 id="왜-객체지향을-사용할까">왜 객체지향을 사용할까?</h2>
<h3 id="1️⃣-코드-재사용성">1️⃣ 코드 재사용성</h3>
<p>한 번 만든 클래스를 여러 곳에서 재사용할 수 있다.</p>
<h3 id="2️⃣-유지보수-용이">2️⃣ 유지보수 용이</h3>
<p>관련된 데이터와 기능이 하나로 묶여있어 수정이 쉽다.</p>
<h3 id="3️⃣-현실-세계-반영">3️⃣ 현실 세계 반영</h3>
<p>실제 세계의 사물을 코드로 표현하니까 이해하기 쉽다.</p>
<h3 id="4️⃣-협업에-유리">4️⃣ 협업에 유리</h3>
<p>팀원들과 역할을 나눠서 각자 다른 클래스를 개발할 수 있다.</p>
<hr>
<h2 id="마무리">마무리</h2>
<p>처음에는 “왜 굳이 이렇게 복잡하게?”라는 생각이 들 수 있다.
나도 그랬다. 하지만 프로그램의 규모가 커질수록, 그리고 실제 프로젝트를 해보면 객체지향의 필요성과 편리함을 자연스럽게 느끼게 된다.</p>
<p>핵심은 <strong>&quot;관련된 것들을 하나로 묶는다&quot;</strong>는 것이다.
스마트폰 관련 정보와 기능을 <code>Smartphone</code> 클래스 하나에 모아두면, 나중에 찾기도 쉽고 관리하기도 편하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[API]]></title>
            <link>https://velog.io/@lee_dang/API</link>
            <guid>https://velog.io/@lee_dang/API</guid>
            <pubDate>Thu, 20 Nov 2025 05:38:02 GMT</pubDate>
            <description><![CDATA[<p>수도없이 들어봤고, 실제 프로젝트에서도 써봤지만 정작 머릿속으로 정리하거나 글로 풀어 쓰려고 하면 막히는 개념들이 있다. 나한테는 그중 하나가 바로 <strong>“API란?”</strong>이다.</p>
<p>개발하다 보면 Google Maps API, Toss Payments API, Open API… 이런 식으로 API라는 말을 정말 많이 듣는다. 하지만 그 단어가 정확히 어떤 의미에서 쓰이고, 왜 필요한 건지 한 번쯤은 제대로 짚고 넘어갈 필요가 있었다.</p>
<p>API라는 개념에 접근하기전에 인터페이스라는 것에 대해 먼저 알고 넘어가기로 했다. API는 Application Programming Interface, <strong>결국 Interface</strong>이기 때문이다.</p>
<h3 id="1️⃣-interface">1️⃣ Interface?</h3>
<p>보통 인터페이스에 대한 설명에는 스마트폰과 전원버튼을 예시로 사용한다.</p>
<blockquote>
</blockquote>
<p>전원이 꺼진 스마트폰이 있다고 가정해보자.
전원버튼을 <code>누르면</code> 전원이 <code>켜진다.</code></p>
<p>이때 중요한 점은 내가 스마트폰 내부에서 무슨일이 일어나는지 모른다는 점이다.
스마트폰 내부의 복잡한 구조등을 몰라도 사용자는 그저 <code>버튼을 누르기</code>만 하면되는 것이다.
이처럼 간단하게 정해진 방식으로만 사용할 수 있게끔 A(사용자)와 B(스마트폰)를 연결해주는 통로가 바로 인터페이스이다.</p>
<h3 id="2️⃣-이를-토대로-api를-살펴보자">2️⃣ 이를 토대로 API를 살펴보자</h3>
<blockquote>
</blockquote>
<p>API는 &#39;애플리케이션 프로그래밍 인터페이스(Application Programming Interface)&#39;의 약자로, 두 소프트웨어 애플리케이션이 서로 통신하고 데이터를 주고받을 수 있도록 하는 규칙과 프로토콜의 집합입니다.</p>
<p>구글에 검색하면 나오는 API의 정의이다.
쉽게 풀어보면 API는 프로그램끼리 소통하는 인터페이스다.
스마트폰 예시에서는 &#39;사람&#39;과 &#39;기기&#39;를 연결했다면, API는 <strong>&#39;프로그램&#39;과 &#39;프로그램&#39;</strong>을 연결한다.</p>
<p>내가 사용했던 Toss Payments API문서를 살펴보면
(<a href="https://docs-pay.toss.im/reference/normal/create">https://docs-pay.toss.im/reference/normal/create</a>)</p>
<blockquote>
<p><img src="https://velog.velcdn.com/images/lee_dang/post/95900032-8dfe-448c-a558-8330f22e3e9f/image.png" alt="">
해당 형식의 요청에 필요한 파라미터를 문서로 만들어서 정리해 주고 있다.
나는 내부에서 무슨일이 일어나는지 모르지만 Toss측에서 원하는 파라미터만 보내서 요청하면 내가 원하는 Toss의 결제 기능을 사용 할 수 있는 것이다.
※반대로 생각하면 이런 정형화된 문서가 필수적이라는 단점도 가지고 있다</p>
</blockquote>
<h3 id="정리하며">정리하며</h3>
<ul>
<li>인터페이스는 복잡함을 숨기고 간단한 사용법만 제공한다</li>
<li>API는 프로그램 간 소통을 위한 인터페이스다</li>
<li>내부 구조를 몰라도 정해진 규칙만 따르면 기능을 사용할 수 있다</li>
</ul>
<p>결국 API는 <strong>&#39;약속된 방식으로 소통하는 통로&#39;</strong>라고 볼 수 있겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CSR, SSR 렌더링방식]]></title>
            <link>https://velog.io/@lee_dang/CSR-SSR-%EB%A0%8C%EB%8D%94%EB%A7%81%EB%B0%A9%EC%8B%9D</link>
            <guid>https://velog.io/@lee_dang/CSR-SSR-%EB%A0%8C%EB%8D%94%EB%A7%81%EB%B0%A9%EC%8B%9D</guid>
            <pubDate>Tue, 18 Nov 2025 08:36:23 GMT</pubDate>
            <description><![CDATA[<h1 id="🖥️-csr-vs-ssr-클라이언트와-서버-어디서-페이지를-렌더링할까">🖥️ CSR vs SSR: 클라이언트와 서버 어디서 페이지를 렌더링할까?</h1>
<p>웹 개발을 하다 보면 <strong>CSR(Client-Side Rendering)</strong>과 <strong>SSR(Server-Side Rendering)</strong>이라는 용어를 자주 마주하게 됩니다. 둘은 브라우저에 웹 페이지를 보여주는 방식이 달라, 성능과 SEO, 개발 구조에 큰 영향을 미칩니다.</p>
<hr>
<h2 id="1️⃣-csrclient-side-rendering--클라이언트-중심">1️⃣ CSR(Client-Side Rendering) – 클라이언트 중심</h2>
<p><strong>개념</strong>: 서버는 최소한의 HTML과 JavaScript만 내려주고, <strong>브라우저</strong>가 JS를 실행하여 화면을 렌더링하는 방식입니다.</p>
<p><strong>특징</strong>:</p>
<ul>
<li>React, Vue, Angular 같은 SPA(단일 페이지 애플리케이션)에서 주로 사용.</li>
<li>서버는 주로 API 데이터를 제공.</li>
<li>클라이언트에서 페이지를 렌더링하므로 초기 로딩은 느릴 수 있지만, 이후 페이지 전환은 빠름.</li>
<li>SEO 최적화가 어렵지만, 사용자 경험(UX)은 좋음.</li>
</ul>
<p><strong>예시</strong>:</p>
<pre><code>사용자 요청 → 서버(API) → JSON 데이터 전달
→ 브라우저에서 React가 HTML 생성 → 화면 렌더링</code></pre><p>⚡ React 프로젝트를 별도 포트에서 띄우고 Spring Controller가 단순 API만 제공하는 경우는 <strong>CSR</strong>에 해당합니다.</p>
<hr>
<h2 id="2️⃣-ssrserver-side-rendering--서버-중심">2️⃣ SSR(Server-Side Rendering) – 서버 중심</h2>
<p><strong>개념</strong>: 서버에서 완전히 렌더링된 HTML을 브라우저에 전달하는 방식입니다.</p>
<p><strong>특징</strong>:</p>
<ul>
<li>JSP, Thymeleaf, Spring 기반 SSR에서 사용.</li>
<li>초기 페이지 로딩 속도가 빠르고 SEO 친화적.</li>
<li>서버가 HTML을 만들어 브라우저에 보내므로 클라이언트는 바로 화면 확인 가능.</li>
</ul>
<p><strong>예시</strong>:</p>
<pre><code>사용자 요청 → 서버(Spring + Thymeleaf) → 서버에서 HTML 렌더링
→ 브라우저에 전달 → 화면 표시</code></pre><p>⚡ JSP나 Thymeleaf를 이용하면 서버에서 HTML을 렌더링한 후 브라우저에 전달하므로 <strong>SSR</strong>입니다.</p>
<hr>
<h2 id="3️⃣-csr-vs-ssr-비교">3️⃣ CSR vs SSR 비교</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>CSR</th>
<th>SSR</th>
</tr>
</thead>
<tbody><tr>
<td>렌더링 위치</td>
<td>브라우저</td>
<td>서버</td>
</tr>
<tr>
<td>초기 로딩 속도</td>
<td>느림</td>
<td>빠름</td>
</tr>
<tr>
<td>페이지 전환</td>
<td>빠름</td>
<td>요청마다 서버 렌더링</td>
</tr>
<tr>
<td>SEO</td>
<td>불리함</td>
<td>유리함</td>
</tr>
<tr>
<td>예시</td>
<td>React SPA</td>
<td>JSP, Thymeleaf</td>
</tr>
</tbody></table>
<hr>
<h2 id="4️⃣-혼동되는-상황">4️⃣ 혼동되는 상황</h2>
<ul>
<li>React 프로젝트를 <strong>Next.js 등 SSR 지원 프레임워크</strong>로 서버에서 렌더링하면 SSR 가능.</li>
<li>React 프로젝트를 <strong>별도 서버에서 실행하고 Spring이 API만 제공</strong>하면 CSR.</li>
<li>Tailwind CSS는 HTML 내부에서 작동하므로 <strong>CSR에서도 문제없이 동작</strong>.</li>
</ul>
<hr>
<h2 id="5️⃣-핵심-정리">5️⃣ 핵심 정리</h2>
<ul>
<li><strong>서버에서 HTML을 렌더링 → SSR</strong></li>
<li><strong>클라이언트에서 JS로 HTML을 렌더링 → CSR</strong></li>
<li>렌더링 위치와 초기 로딩 주체가 SSR과 CSR의 차이를 결정합니다.</li>
</ul>
<hr>
<hr>
<h1 id="🗒️-추가-용어-정리">🗒️ 추가 용어 정리</h1>
<h4 id="🔍-seo-search-engine-optimization--검색-엔진-최적화">🔍 SEO (Search Engine Optimization) – 검색 엔진 최적화</h4>
<blockquote>
<p>SEO는 검색 엔진 최적화를 의미하며, 구글, 네이버, 빙 같은 검색 엔진에서 내 웹사이트가 더 잘 검색되도록 개선하는 작업입니다. 쉽게 말해 “검색했을 때 내 페이지가 상단에 나오도록 하는 기술”이에요.</p>
</blockquote>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[Toss API 연동]]></title>
            <link>https://velog.io/@lee_dang/Toss-API%EB%A1%9C-%EC%97%B0%EB%8F%99</link>
            <guid>https://velog.io/@lee_dang/Toss-API%EB%A1%9C-%EC%97%B0%EB%8F%99</guid>
            <pubDate>Tue, 18 Nov 2025 06:21:33 GMT</pubDate>
            <description><![CDATA[<p>JavaScript : React.js, Java : SpringBoot 프레임웍 사용</p>
<ol>
<li>Front에서 결제 컨트롤러로 요청 보냄(Payment 객체에 Toss에서 필요한 요청을 전송하는 값들을 담아서</li>
<li>Back에서 매핑주소를 이용해서 Responsebody에 원하는 JSON형식을 담아 프론트에 리턴해줌(            return ResponseEntity.ok(response.getBody());)</li>
</ol>
<hr>
<ol start="3">
<li>결제결과 callBack에서 400이 나오면 orderId를 재생성 후 다시요청, 그래도 안되면 실패로 반환하도록 검증로직 구현하기</li>
</ol>
<hr>
<ol start="3">
<li>200을 받아오면 그때서야 토스 결제페이지로 리디렉션(response의 body에 checkoutPage 형태로 받아옴
<img src="https://velog.velcdn.com/images/lee_dang/post/5a41349b-3f69-4778-919c-3584986b8512/image.png" alt=""></li>
<li>결제 페이지를 받아와서 리디렉션 하는 코드
<img src="https://velog.velcdn.com/images/lee_dang/post/8952af91-eeda-4fb3-9180-10c25cd5f259/image.png" alt=""></li>
<li>4의 메서드로는 토스에서 보내는 요청(응답)이 토큰을 가지고 있지 않기 떄문에 해당 200코드를 해결하는 프로트엔드 로직이 필요</li>
</ol>
<hr>
<p>로그 찍는 방법이 잘못되어 원래대로 불러오는게 맞았는데 console.log(&quot;&quot;,response);로 찍어보도록 하자
올바른 요청주소는 response.data.checkoutPage 였다.
<img src="https://velog.velcdn.com/images/lee_dang/post/d4153087-b0e4-4cef-8d43-22103585bc20/image.png" alt=""></p>
<hr>
<ol start="6">
<li><p>retUrl로 프론트 주소를 설정하고, 이후 프론트엔드에서 onLoad 시점에  controller로 결제정보를 반환받도록 비동기 처리를 하자 
<img src="https://velog.velcdn.com/images/lee_dang/post/06667f76-12d1-48c1-8ad6-3c31efa6f13a/image.png" alt=""></p>
</li>
<li><p>SearchParams 모듈을 써서 들어오고 있는 status등 결제 정보를 받아옴..! 
<img src="https://velog.velcdn.com/images/lee_dang/post/ad49efa4-4554-4621-95cc-d88996aa70de/image.png" alt=""></p>
</li>
<li><p>보낸정보를 토대로 백엔드 컨트롤러에서 받아서 로직검증
<img src="https://velog.velcdn.com/images/lee_dang/post/5e3901c5-4698-406e-b2ad-82bcc8caf7f5/image.png" alt="">
아래가 컨트롤러(리턴해줍니다)
<img src="https://velog.velcdn.com/images/lee_dang/post/05a60358-4b2d-4436-8259-216213dbe591/image.png" alt=""></p>
</li>
<li><p>결제 완료 프론트엔드에서 들어온 요청을 검증 후 결제완료 창을 표시하면 결제 완료</p>
</li>
</ol>
<p>*<em>추가로 결제정보를 DB에 담는것과 위조정보 검증로직, 트랜잭션 처리 *</em>필요</p>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[Java, JS의 자료형]]></title>
            <link>https://velog.io/@lee_dang/Java-%EA%B0%9D%EC%B2%B4</link>
            <guid>https://velog.io/@lee_dang/Java-%EA%B0%9D%EC%B2%B4</guid>
            <pubDate>Mon, 17 Nov 2025 05:06:12 GMT</pubDate>
            <description><![CDATA[<p>매일 한 시간 가량의 Database 훈련을 병행하면서, 본격적으로 Java 수업이 시작되었다.</p>
<p>JavaScript <strong>(이하 JS)</strong> 수업 때와 마찬가지로 <strong>‘자료형’</strong>에 대해 먼저 배우게 되었다.</p>
<hr>
<h3 id="🟦-js">🟦 JS</h3>
<p>JS를 공부할 때도 물론 자료형이라는 개념은 알고 있었다.
하지만 JS에서는 <code>let</code>, <code>const</code>로 모든 선언을 끝내버리고, 변수에 어떤 값이 들어오든 타입이 자동으로 바뀌는 구조다.
즉, JS는 <strong>동적 타입 언어</strong>라서</p>
<pre><code class="language-javascript">let x = 10;   // number
x = &quot;hello&quot;;  // string
x = true;     // boolean</code></pre>
<p>이렇게 값이 바뀌면 변수의 타입도 즉석에서 바뀐다.
당시엔 “그냥 편하네~” 정도로만 생각했었다.</p>
<hr>
<h3 id="💡-java-자료형은-느낌이-완전-다르다">💡 Java 자료형은 느낌이 완전 다르다</h3>
<p>Java는 JS와 달리 <strong>정적 타입 언어</strong>다.
즉, 변수의 타입을 <strong>선언할 때 명확히 지정</strong>해야 하고, 타입에 맞지 않는 값을 넣으면 <strong>컴파일 단계에서 바로 오류</strong>가 난다.</p>
<hr>
<h3 id="📘-java-자료형-정리">📘 Java 자료형 정리</h3>
<table>
<thead>
<tr>
<th>구분</th>
<th>자료형</th>
<th>크기</th>
<th>특징</th>
</tr>
</thead>
<tbody><tr>
<td><strong>숫자(정수)</strong></td>
<td>byte</td>
<td>1 byte</td>
<td>-128 ~ 127</td>
</tr>
<tr>
<td></td>
<td>short</td>
<td>2 byte</td>
<td>-32,768 ~ 32,767</td>
</tr>
<tr>
<td></td>
<td>int</td>
<td>4 byte</td>
<td>기본 정수 타입</td>
</tr>
<tr>
<td></td>
<td>long</td>
<td>8 byte</td>
<td>뒤에 L 붙여 사용</td>
</tr>
<tr>
<td><strong>숫자(실수)</strong></td>
<td>float</td>
<td>4 byte</td>
<td>뒤에 F 필요(단정도)</td>
</tr>
<tr>
<td></td>
<td>double</td>
<td>8 byte</td>
<td>기본 실수 타입(배정도)</td>
</tr>
<tr>
<td><strong>문자</strong></td>
<td>char</td>
<td>2 byte</td>
<td>유니코드 1문자 저장</td>
</tr>
<tr>
<td></td>
<td>String</td>
<td>가변 길이</td>
<td>문자열(참조형)</td>
</tr>
<tr>
<td><strong>논리</strong></td>
<td>boolean</td>
<td>1 byte</td>
<td>true / false만 허용 (0, 1 사용 불가)</td>
</tr>
</tbody></table>
<hr>
<h3 id="🐶-클래스-예제에서-느낀-점">🐶 클래스 예제에서 느낀 점</h3>
<p>Java 수업에서 가장 먼저 만드는 클래스 중 하나가 이런 구조였다:</p>
<pre><code class="language-java">public class Dog {
    String name = &quot;뽀삐&quot;;
    int age = 2;

    public static void main(String[] args) {

    }
}</code></pre>
<p>여기서 바로 실수하기 쉬운 부분이 있다.</p>
<ul>
<li>문자열은 <code>&quot; &quot;</code>(큰따옴표)</li>
<li>문자는 <code>&#39; &#39;</code>(작은따옴표)</li>
<li><code>age</code>처럼 숫자를 넣는 필드는 <code>String</code>이 아니라 <code>int</code> 등 숫자 타입을 써야 함</li>
</ul>
<p>JS에서는 숫자를 <code>&quot;2&quot;</code>로 넣든 <code>2</code>로 넣든 대체로 넘어가지만, Java는 타입을 확실히 구분해야 한다.</p>
<p>이런 작은 차이부터 JS와 Java의 철학 차이가 확 드러난다.</p>
<hr>
<h3 id="✍️-회고">✍️ 회고</h3>
<p>자료형이라는 개념은 처음엔 다소 번거롭게 느껴질 수 있지만,
Java처럼 타입이 확실한 언어를 배워보면
“코드가 안정적이게 만들어지는 느낌”을 확실히 경험할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQLD, D-1 문제풀이 및 오답노트]]></title>
            <link>https://velog.io/@lee_dang/SQLD-D-1-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-%EB%B0%8F-%EC%98%A4%EB%8B%B5%EB%85%B8%ED%8A%B8</link>
            <guid>https://velog.io/@lee_dang/SQLD-D-1-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-%EB%B0%8F-%EC%98%A4%EB%8B%B5%EB%85%B8%ED%8A%B8</guid>
            <pubDate>Sat, 15 Nov 2025 10:33:00 GMT</pubDate>
            <description><![CDATA[<h2 id="🧩-한-줄-개념정리">🧩 한 줄 개념정리</h2>
<blockquote>
<ul>
<li>GROUP BY절에는 SUM, COUNT 함수를 사용할 수 없다.</li>
<li>RATIO_TO_REPORT</li>
<li>INLINE VIEW는 일반적으로 메인쿼리보다 먼저 수행되므로
SQL 문장 내에서 절차성을 주는 효과를 얻을 수 있다.</li>
<li>PL/SQL의 사용 순서는 Cursor 선언, Cursor open, FETCH, Cursor Close이다.</li>
</ul>
</blockquote>
<h3 id=""></h3>
<h2 id="🧩-개념정리">🧩 개념정리</h2>
<h3 id="1️⃣-or-조건-작동-방식">1️⃣ OR 조건 작동 방식</h3>
<p>쿼리 :</p>
<pre><code class="language-sql">SELECT COUNT(*)
FROM limbest.emp
WHERE JOB = &#39;CLERK&#39;
   OR (ENAME LIKE &#39;T%&#39; AND SAL &gt;= 3000);</code></pre>
<blockquote>
<p><strong>CLERK이면서 동시에 ENAME LIKE &#39;T%&#39; AND SAL &gt;= 3000 조건도 만족하면
그 행이 두 번 카운트되나?</strong></p>
</blockquote>
<h4 id="👉두-번-조회되지-않음-why">👉두 번 조회되지 않음, WHY?**</h4>
<p>행이 아래 두 조건을 모두 만족한다고 할때</p>
<blockquote>
<ol>
<li>JOB = &#39;CLERK&#39;</li>
<li>ENAME LIKE &#39;T%&#39; AND SAL &gt;= 3000</li>
</ol>
</blockquote>
<p>그러면 그 행의 where 결과는:</p>
<pre><code>TRUE OR TRUE → TRUE</code></pre><p>그러면 그 행은 <strong>그냥 한 번만</strong> 결과집합에 들어감.
설령 CLERK이면서 T%이면서 SAL &gt;= 3000이라도
그 사원은 <strong>1명으로만 카운트됨.</strong></p>
<h2 id="결과-요약">결과 요약</h2>
<ol>
<li><img src="https://velog.velcdn.com/images/lee_dang/post/614425c4-88ce-4856-9c40-bcf933e8baca/image.png" alt=""> </li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQLD, D-2 문제풀이 및 오답노트]]></title>
            <link>https://velog.io/@lee_dang/SQLD-D-2-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-%EB%B0%8F-%EC%98%A4%EB%8B%B5%EB%85%B8%ED%8A%B8</link>
            <guid>https://velog.io/@lee_dang/SQLD-D-2-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-%EB%B0%8F-%EC%98%A4%EB%8B%B5%EB%85%B8%ED%8A%B8</guid>
            <pubDate>Fri, 14 Nov 2025 08:09:28 GMT</pubDate>
            <description><![CDATA[<h2 id="🧩-한-줄-개념-정리">🧩 한 줄 개념 정리</h2>
<blockquote>
<ul>
<li>UNIQUE제약조건은 NULL을 가질 수 있다.</li>
<li>ORACLE에서는 <strong>ORDER BY</strong> 정렬 시 NULL을 가장 큰 값으로 취급한다.</li>
<li>ORDER BY 절은 “컬럼마다” 정렬 순서를 따로 준다</li>
<li>테이블 명은 숫자로 시작할 수 없으며, -(하이픈)을 사용할 수 없다.</li>
<li>NTILE함수 사용시 나머지는 앞 그룹부터 1씩 추가된다.</li>
<li><strong>&#39;=&#39;</strong> 연산은 NULL과 비교하면 항상 거짓을 반환한다.</li>
<li>LAG 함수는 현재 행을 기준으로 이전 행의 값을 가져온다.</li>
<li>반대로 LEAD 함수는 현재 행을 기준으로 다음 행의 값을 가져온다.</li>
<li>CUME_DIST는 누적백분율을 구하는 함수이다.</li>
</ul>
</blockquote>
<h2 id="🧩-용어정리">🧩 용어정리</h2>
<h3 id="1️⃣-decode">1️⃣ DECODE</h3>
<blockquote>
</blockquote>
<p>DECODE(A,
       &amp;nbsp&amp;nbsp&amp;nbspB, C,    <strong>-- A가 B면 → C</strong>
       &amp;nbsp&amp;nbsp&amp;nbspD, E,    <strong>-- A가 D면 → E</strong>
       &amp;nbsp&amp;nbsp&amp;nbspF, G,    <strong>-- A가 F면 → G</strong>
       H)       -- 그 외 → H</p>
<h3 id="2️⃣-exists-문법">2️⃣ EXISTS 문법</h3>
<blockquote>
</blockquote>
<ul>
<li>EXISTS: 서브쿼리 결과가 존재하면 TRUE</li>
<li>NOT EXISTS: 서브쿼리 결과가 없으면 TRUE<pre><code>EXISTS는 레코드 존재 여부만 확인하기 때문에
SELECT * 대신에  1, &#39;X&#39;, &#39;아무문자열&#39; 처럼 상수를 써도 상관없음</code></pre></li>
</ul>
<h3 id="3️⃣-서브쿼리subquery">3️⃣ 서브쿼리(subQuery)</h3>
<table>
<thead>
<tr>
<th>분류</th>
<th>위치</th>
<th>특징/용도</th>
</tr>
</thead>
<tbody><tr>
<td>Inline View / Derived</td>
<td>FROM</td>
<td>임시 테이블처럼 사용, 별칭 필요</td>
</tr>
<tr>
<td>Scalar</td>
<td>SELECT/WHERE/HAVING</td>
<td>단일 값 반환 (1행1열)</td>
</tr>
<tr>
<td>Correlated</td>
<td>WHERE/SELECT</td>
<td>메인쿼리 컬럼 참조, 행별 실행</td>
</tr>
<tr>
<td>EXISTS / NOT EXISTS</td>
<td>WHERE</td>
<td>존재 여부 판단</td>
</tr>
<tr>
<td>IN / NOT IN</td>
<td>WHERE</td>
<td>포함 여부 판단</td>
</tr>
<tr>
<td>View</td>
<td>FROM</td>
<td>재사용 가능, 복잡한 쿼리 간결화</td>
</tr>
</tbody></table>
<hr>
<h2 id="결과요약">결과요약</h2>
<ol>
<li><p><img src="https://velog.velcdn.com/images/lee_dang/post/4d6a7355-4e3b-4747-9b11-012e3e23fd50/image.png" alt=""></p>
</li>
<li><p><img src="https://velog.velcdn.com/images/lee_dang/post/ccfba8a5-9981-4e9d-945a-a934dcbd98eb/image.png" alt=""></p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Databases]]></title>
            <link>https://velog.io/@lee_dang/Databases</link>
            <guid>https://velog.io/@lee_dang/Databases</guid>
            <pubDate>Thu, 13 Nov 2025 14:51:59 GMT</pubDate>
            <description><![CDATA[<h2 id="🧠-javascript-databases">🧠 JavaScript, Databases</h2>
<p>프로그래밍 첫 강의는 <strong>HTML</strong>, <strong>JavaScript</strong>, 그리고 <strong>Database</strong>였다.
JavaScript는 이미 독학해본 경험이 있었기에 비교적 수월하게 따라갈 수 있었다.</p>
<p>하지만 <strong>데이터베이스(Database)</strong> —
이 단어를 처음 들었을 때의 충격은 아직도 기억난다.</p>
<blockquote>
<p>“내가 보는 프로그램의 데이터는 도대체 어디에 저장되어 있을까?”
“버튼을 누르면 화면이 바뀌는데, 그 안에서는 어떤 일이 일어나는 걸까?”</p>
</blockquote>
<p>그동안 단순히 “누르면 움직이는 화면” 정도로만 생각했던 웹이,
사실은 보이지 않는 곳에서 <strong>데이터를 저장하고 관리하는 구조</strong>라는 사실이 놀라웠다.</p>
<p>강의에서는 <strong>Schema</strong>, <strong>Entity</strong>, <strong>DBMS</strong> 같은 데이터의 기본 개념부터 다뤘다.
그리고 CMD 창에서 직접 쿼리문을 작성해 <strong>EMP 테이블</strong>을 조회했을 때,
HTML로 만든 웹페이지와는 전혀 다른 세계가 펼쳐졌다.
그때의 신선함은 지금도 잊을 수 없다.</p>
<p>이후 다양한 쿼리와 문법 예제를 풀다 보니
시간 가는 줄 모를 정도로 흥미로웠다.</p>
<p>물론 <strong>JOIN</strong>, <strong>서브쿼리(Subquery)</strong> 등을 배울 때는 많이 헤매기도 했지만,
프로젝트에선 <strong>SQL 문을 단독으로 관리</strong>하고 <strong>무결성 검증</strong>까지 맡을 만큼 성장했다.</p>
<p>이 경험을 바탕으로,
현재(<strong>2025년 11월 14일</strong>)는 <strong>SQLD 자격증 취득</strong>을 목표로 공부 중이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQLD, D-3 문제풀이 및 오답노트]]></title>
            <link>https://velog.io/@lee_dang/SQLD-D-3-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-%EB%B0%8F-%EC%98%A4%EB%8B%B5%EB%85%B8%ED%8A%B8</link>
            <guid>https://velog.io/@lee_dang/SQLD-D-3-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-%EB%B0%8F-%EC%98%A4%EB%8B%B5%EB%85%B8%ED%8A%B8</guid>
            <pubDate>Thu, 13 Nov 2025 09:13:42 GMT</pubDate>
            <description><![CDATA[<h2 id="🧩-한-줄-개념정리">🧩 한 줄 개념정리</h2>
<blockquote>
<ul>
<li><strong>&#39;ORDER BY (숫자)&#39;</strong>는 테이블의 숫자번째 컬럼을 기준으로 정렬한다.</li>
</ul>
</blockquote>
<!-- >- ROWNUMBER, NTILE -->
<!-- >- CONCAT (단일행 함수) -->
<blockquote>
<ul>
<li>비교연산자 <strong>&#39;&lt;&gt;&#39;</strong>는 같지 않음을 의미한다.</li>
<li><strong>&#39;GROUP BY COL1, COL2&#39;</strong>는 COL1, COL2의 조합이 같은 행들 끼리 묶는다.</li>
<li>한 개의 엔터티는 두 개 이상의 속성과 두 개 이상의 인스턴스를 가진다.</li>
<li>관계형 데이터베이스는 부하를 분석하는데 어려움이 있다.</li>
<li>주식별자의 특징은 유일성, 최소성, 불변성, 존재성 이다</li>
</ul>
</blockquote>
<h2 id="🧩-용어정리">🧩 용어정리</h2>
<h3 id="1️⃣-substr-vs-regexp_substr">1️⃣ SUBSTR vs REGEXP_SUBSTR</h3>
<table>
<thead>
<tr>
<th>항목</th>
<th><code>SUBSTR</code></th>
<th><code>REGEXP_SUBSTR</code></th>
</tr>
</thead>
<tbody><tr>
<td><strong>기능</strong></td>
<td>문자열의 <strong>위치와 길이</strong>로 자름</td>
<td>문자열의 <strong>패턴(정규식)</strong> 으로 자름</td>
</tr>
<tr>
<td><strong>문법</strong></td>
<td><code>SUBSTR(문자열, 시작위치, 길이)</code></td>
<td><code>REGEXP_SUBSTR(문자열, 패턴 ,시작위치 ,발생순서)</code></td>
</tr>
<tr>
<td><strong>예시</strong></td>
<td><code>SUBSTR(&#39;kkkkkzzzz&#39;, 6, 4)</code> → <code>&#39;zzzz&#39;</code></td>
<td><code>REGEXP_SUBSTR(&#39;kkkkkzzzz&#39;, &#39;z{3,4}&#39;)</code> → <code>&#39;zzzz&#39;</code></td>
</tr>
<tr>
<td><strong>차이점</strong></td>
<td>문자 위치를 직접 지정해야 함</td>
<td><strong>패턴을 찾아서 자동으로 추출</strong></td>
</tr>
</tbody></table>
<h3 id="2️⃣-인조식별자-vs-본질식별자">2️⃣ 인조식별자 vs 본질식별자</h3>
<table>
<thead>
<tr>
<th>구분</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><strong>본질식별자 (Natural Key)</strong></td>
<td>실제 <strong>업무상 의미가 있는 속성</strong> 중에서 고유하게 구분되는 값을 <strong>기본키로 지정</strong>한 것</td>
<td>예: 주민등록번호, 학번, 이메일, 주문번호 등</td>
</tr>
<tr>
<td><strong>인조식별자 (Surrogate Key)</strong></td>
<td>업무 의미와 관계없이 <strong>시스템이 자동 생성하는 값</strong>을 <strong>기본키로 지정</strong>한 것</td>
<td>예: <code>ID (AUTO_INCREMENT)</code>, <code>SEQ_USER.NEXTVAL</code></td>
</tr>
</tbody></table>
<h3 id="3️⃣-case문-문법요약">3️⃣ CASE문 문법요약</h3>
<blockquote>
<ul>
<li>CASE <pre><code> &amp;nbsp&amp;nbsp&amp;nbspWHEN 조건1 THEN 결과1</code></pre>  &amp;nbsp&amp;nbsp&amp;nbspWHEN 조건2 THEN 결과2
  &amp;nbsp&amp;nbsp&amp;nbspELSE 기본값
END</li>
</ul>
</blockquote>
<h3 id="결과-요약">결과 요약</h3>
<ol>
<li><img src="https://velog.velcdn.com/images/lee_dang/post/473cf63b-8c83-415b-a1df-5ea8bcf9ceaa/image.png" alt=""></li>
<li><img src="https://velog.velcdn.com/images/lee_dang/post/84dbec1c-37aa-4beb-8bd6-b263192635b4/image.png" alt=""></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQLD, D-4 문제풀이 및 오답노트]]></title>
            <link>https://velog.io/@lee_dang/SQLD-D-4-%EC%98%A4%EB%8B%B5%EB%85%B8%ED%8A%B8-%ED%95%9C-%EC%A4%84-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@lee_dang/SQLD-D-4-%EC%98%A4%EB%8B%B5%EB%85%B8%ED%8A%B8-%ED%95%9C-%EC%A4%84-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Wed, 12 Nov 2025 12:39:02 GMT</pubDate>
            <description><![CDATA[<h2 id="🧩-한-줄-개념정리">🧩 한 줄 개념정리</h2>
<blockquote>
<ul>
<li><strong>grant</strong>는 권한을 부여, <strong>revoke</strong>는 권한을 삭제하는 SQL문이다.</li>
<li><strong>INTERSECT</strong> 연산자는 중복된 행을 하나의 행으로 표시한다.</li>
<li>데이터모델링 순서는 개(념적) - 논(리적) - 물(리적)</li>
<li>SELECT * FROM SQLD5 WHERE COL1 IN (1,2,NULL)에서 NULL은 항상 &#39;UNKNOWN&#39;이 된다. -&gt; 1,2만 select 됨</li>
<li><strong>WHERE 1=1</strong> = &quot;모든 행을 선택하되, 조건을 나중에 쉽게 추가하기 위한 문법적 장치&quot;</li>
<li>고유키로 지정된 모든 칼럼은 중복된 값을 허용하진 않지만, NULL 값은 가질 수도 있다.</li>
</ul>
</blockquote>
<h2 id="🧩-용어정리">🧩 용어정리</h2>
<p>1️⃣ 속성사전(Attribute Dictionary)</p>
<p>정의: 데이터베이스 내 속성(컬럼)들의 이름, 타입, 제약 조건, 의미 등을 정리해 둔 사전.</p>
<p>용도: 데이터 설계와 관리 시 참조, 문서화, 일관성 유지.</p>
<p>2️⃣ 시스템카탈로그(System Catalog)</p>
<p>정의: 데이터베이스 자체가 관리하는 메타데이터 저장소.</p>
<p>내용: 테이블, 컬럼, 인덱스, 제약 조건, 사용자 권한 등.</p>
<p>특징: 데이터베이스 구조 정보를 제공 → DBMS 내부에서 사용.</p>
<p>3️⃣ 릴레이션(Relation)</p>
<p>정의: 관계형 데이터베이스에서 테이블 자체를 의미.</p>
<p>특징: 행(Row) = 튜플(Tuple), 열(Column) = 속성(Attribute) 구조.</p>
<p>핵심: 모든 데이터는 릴레이션 형태로 저장.</p>
<p>4️⃣ 도메인(Domain)</p>
<p>정의: 속성이 가질 수 있는 값의 범위와 형식을 정의.</p>
<p>예시: 나이 속성 → 정수, 0~150</p>
<p>용도: 데이터 무결성 유지, 입력 오류 방지.</p>
<h3 id="결과-요약">결과 요약</h3>
<ol>
<li><img src="https://velog.velcdn.com/images/lee_dang/post/5b0c40b3-14fe-4bc6-8ba9-2c2bbdc456aa/image.png" alt=""></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQLD, D-5 문제풀이 및 오답노트]]></title>
            <link>https://velog.io/@lee_dang/SQLD-D-5-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-%EB%B0%8F-%EC%98%A4%EB%8B%B5%EB%85%B8%ED%8A%B8</link>
            <guid>https://velog.io/@lee_dang/SQLD-D-5-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-%EB%B0%8F-%EC%98%A4%EB%8B%B5%EB%85%B8%ED%8A%B8</guid>
            <pubDate>Tue, 11 Nov 2025 12:30:18 GMT</pubDate>
            <description><![CDATA[<h2 id="한-줄-개념정리">한 줄 개념정리</h2>
<ul>
<li>BETWEEN은 <strong>&#39;=&#39;</strong> 를 포함한다.</li>
<li>DECODE (EMPNO.1000. &#39;TRUE&#39;, &#39;FALSE&#39;)&#39;로 IF문을 구현가능하다.</li>
<li>집합 연산자는 두 개 이상의 테이블에서 조인을 하지 않고
관련된 데이터를 조회한다.</li>
</ul>
<h3 id="like문">LIKE문</h3>
<blockquote>
<ul>
<li>&#39;%&#39;는 모든 문자열(개수상관X)을 의미</li>
<li>&#39;_&#39; 는 한 글자만을 의미</li>
</ul>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQLD, D-11 모델링, ER표기법 비교]]></title>
            <link>https://velog.io/@lee_dang/SQLD-D-11-%EB%AA%A8%EB%8D%B8%EB%A7%81-ER%ED%91%9C%EA%B8%B0%EB%B2%95-%EB%B9%84%EA%B5%90</link>
            <guid>https://velog.io/@lee_dang/SQLD-D-11-%EB%AA%A8%EB%8D%B8%EB%A7%81-ER%ED%91%9C%EA%B8%B0%EB%B2%95-%EB%B9%84%EA%B5%90</guid>
            <pubDate>Wed, 05 Nov 2025 10:03:01 GMT</pubDate>
            <description><![CDATA[<h3 id="데이터-관점-모델링">데이터 관점 모델링</h3>
<blockquote>
<ul>
<li>데이터 모델링</li>
<li>프로세스 모델링
  업무흐름 중심</li>
<li>상관관점 모델링
  업무에 따른 데이터 처리 흐름 중심</li>
</ul>
</blockquote>
<hr>
<h3 id="🧩-erd-표기법ie-표기법-vs-barker-표기법">🧩 ERD 표기법(IE 표기법 vs Barker 표기법)</h3>
<p><img src="https://velog.velcdn.com/images/lee_dang/post/a98fe249-c403-412b-baa9-5159b557b300/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQLD, D-12 오답노트]]></title>
            <link>https://velog.io/@lee_dang/SQLD-D-12-%EC%98%A4%EB%8B%B5%EB%85%B8%ED%8A%B8</link>
            <guid>https://velog.io/@lee_dang/SQLD-D-12-%EC%98%A4%EB%8B%B5%EB%85%B8%ED%8A%B8</guid>
            <pubDate>Tue, 04 Nov 2025 08:44:05 GMT</pubDate>
            <description><![CDATA[<h3 id="🧩-partition-preceding-following">🧩 PARTITION, PRECEDING, FOLLOWING</h3>
<p>SELECT SUM(SAL) OVER (
  PARTITION BY MGR
  ORDER BY HIREDATE -- DEFAULT ASC
  ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
) AS MGR_SUM FROM Mytest;</p>
<blockquote>
<ul>
<li><strong>PARTITION BY MGR</strong>
MGR(관리자) 별로 데이터를 그룹(파티션) 으로 나눕니다.
즉, 같은 MGR을 가진 직원들끼리만 윈도우 함수가 작동합니다.</li>
</ul>
</blockquote>
<blockquote>
<p>-
<strong>ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING</strong>
현재 행을 기준으로 이전 1행 + 현재 행 + 다음 1행을 윈도우(창)으로 설정합니다.
이 범위 내의 값을 이용해서 합계나 평균 등을 계산합니다.</p>
</blockquote>
<h3 id="🧩-joininner-outer-cross-self">🧩 JOIN(INNER, OUTER, CROSS, SELF)</h3>
<ul>
<li>JOIN관련 문제에 취약점을 보이므로 오늘 확실히 짚고 넘어가기</li>
<li><em>자세한 내용은 NOTION, 책보며 학습*</em></li>
</ul>
<p>📘 SQL JOIN 종류 요약표</p>
<table>
<thead>
<tr>
<th>JOIN 종류</th>
<th>키워드</th>
<th>반환되는 행</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>INNER JOIN</strong></td>
<td><code>INNER JOIN</code></td>
<td>양쪽 테이블에 <strong>공통된 값</strong>이 있는 행만</td>
<td>가장 기본적인 조인. 교집합처럼 동작</td>
</tr>
<tr>
<td><strong>LEFT OUTER JOIN</strong></td>
<td><code>LEFT JOIN</code></td>
<td><strong>왼쪽 테이블의 모든 행</strong> + 오른쪽 일치행</td>
<td>오른쪽에 없으면 <code>NULL</code>로 표시</td>
</tr>
<tr>
<td><strong>RIGHT OUTER JOIN</strong></td>
<td><code>RIGHT JOIN</code></td>
<td><strong>오른쪽 테이블의 모든 행</strong> + 왼쪽 일치행</td>
<td>왼쪽에 없으면 <code>NULL</code>로 표시</td>
</tr>
<tr>
<td><strong>FULL OUTER JOIN</strong></td>
<td><code>FULL JOIN</code></td>
<td>양쪽 테이블의 <strong>모든 행</strong></td>
<td>일치하지 않으면 NULL 채움 (Oracle은 <code>UNION</code>으로 대체)</td>
</tr>
<tr>
<td><strong>CROSS JOIN</strong></td>
<td><code>CROSS JOIN</code></td>
<td>두 테이블의 <strong>모든 행 조합</strong></td>
<td>곱집합 (모든 조합을 생성)</td>
</tr>
<tr>
<td><strong>SELF JOIN</strong></td>
<td>자기 자신과 조인</td>
<td>조건에 따라 자기 자신과 연결</td>
<td>계층 구조 표현 등에 사용</td>
</tr>
</tbody></table>
]]></description>
        </item>
    </channel>
</rss>