<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>gariguri.log</title>
        <link>https://velog.io/</link>
        <description>@gari_guri</description>
        <lastBuildDate>Sun, 11 Aug 2024 23:27:56 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>gariguri.log</title>
            <url>https://velog.velcdn.com/images/gari_guri/profile/755648e8-0570-4e83-83fb-c097da5361a2/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. gariguri.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/gari_guri" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[AOP]]></title>
            <link>https://velog.io/@gari_guri/AOP</link>
            <guid>https://velog.io/@gari_guri/AOP</guid>
            <pubDate>Sun, 11 Aug 2024 23:27:56 GMT</pubDate>
            <description><![CDATA[<h2 id="복습">&lt;복습&gt;</h2>
<p>Spring Data JPA Dependency 추가
: 포함된 dependency -JDBC, JPA, hibernate(jpa 구현체), AOP
왜 포함되어있을까? aop를 왜 포함하고 있을까?</p>
<ul>
<li>GlobalException처리-&gt;@RestControllerAdvice - AOP연결</li>
<li>@Transactional-&gt; 트랜잭션이 시작/끝을 알리기위해 앞뒤로 붙어야 함 스프링이 어노테이션을 달아놓으면 자동으로 해줌.</li>
<li>DI, IOC, AOP 스프링만 가지고 있는 것이아니라, 좋은 걸 골라다가 만들어 놓은 프레임워크</li>
</ul>
<p>왜 aop가 필요할까?</p>
<h2 id="aop-aspect-oriented-programming-관점지향-프로그래밍">AOP (Aspect Oriented programming: 관점지향 프로그래밍)</h2>
<ul>
<li><p>관점 지향 프로그래밍
  1) 구매 개발자: 구매 버튼 클릭 &gt; ✔️ ~&gt; 구매 완료
  2) 장바구니 개발자: 장바구니 버튼 클릭 &gt; ✔️ ~&gt; 아이템 삭제 완료
  3) 찜하기: 장바구니 버튼 클릭 &gt; ✔️ ~&gt; 찜하기 로직
  4) 로그인 체크 개발자: ** 로그인 체크**✔️</p>
<p>  각각 다들 개발하려는 관심은 다르지만, 구매를 클릭했을 때 로그인이 여부를 체크하는 로직은 동일함.
  =&gt; 세로 관점을 봤을 때, 로그인 체크로직이 공통적임 새로운 관점으로 개발할게~! 필요할때 갖다 쓰기만 하면 됑!</p>
<p>  @Before: 시점을 찍어놓는 것: 객체를 불러다가 메소드를 호출시켜줌</p>
</li>
</ul>
<blockquote>
<h3 id="aop란">AOP란?</h3>
<p>어떠한 메소드 코드를 실행시키전/후의 시점에서 다양한 로직들을 횡단적(세로 관점)으로 보았을 때 반복적인 로직 로직을 하나의 모듈로써 통합하여 짜는 프로그래밍 </p>
</blockquote>
<blockquote>
<h3 id="객체지향과-관점지향의-차이">객체지향과 관점지향의 차이</h3>
<ul>
<li>객체 지향 프로그래밍: 잘 분리가 되어있고, 모듈화가 잘 되어있다는 뜻 필요한 시점에 객체.메소드를 호출 가능</li>
</ul>
</blockquote>
<ul>
<li>하지만, 코드 중복이 일어날 수 밖에 없고, aop(관점 지향)을 적용하기 좋은 바탕이라고 생각 </li>
<li>객체지향 프로그래밍은 응집도가 높고, 의존성이 낮고, 결합도가 낮고, 모듈화가 잘 되어있기 때문!</li>
</ul>
<h2 id="jpapi복습">JPA(PI)&lt;복습&gt;</h2>
<ul>
<li><p>JPA의 일꾼: EntityManager</p>
</li>
<li><p>@Entity (cf. @Component -&gt; ApplicationContext)</p>
</li>
<li><p>persist(): entityContext에 추가, DB에 저장까지 해줘! = 영속화한다
  entityContext: 영속화된 객체가 모여있는 공간</p>
</li>
<li><p>@Transactional</p>
</li>
<li><p>@Id: entityContext안에 너같은 애가 여러개 있어 식별할 수 있게 id를 부여하는 역할</p>
</li>
</ul>
<h2 id="entitymanager">EntityManager</h2>
<ul>
<li><code>persist(객체)</code></li>
<li><strong><code>find(타입, 식별자)</code></strong>
cf. Spring도 type으로 빈 구별했지.. 하지만 여기에서는 객체가 여러개이기 때문에 식별자도 필요
= 같은 타입의 객체가 1개 뿐(default)=&quot;싱글톤 패턴&quot;
<img src="https://velog.velcdn.com/images/gari_guri/post/bb5533b6-2fdd-4ee9-bd9c-843d8d12ef36/image.png" alt="">
데이터베이스에 데이터를 저장하기 위해서 EntityContext를 무조건 들려서 옴 -&gt; &quot;class 타입&quot;와 &quot;id&quot;가 필요하기 때문
왜 식별자까지 필요할까? 똑같은 객체가 여러개 존재하기 때문에 각 객체를 식별하기 위해 @Id을 통해 식별이 가능함!</li>
</ul>
<h2 id="entitymanager-2">EntityManager-2</h2>
<ul>
<li><code>createQuery(쿼리)</code>: 
  cf. JPA는 자바-디비 패러다임 일치 목적!
  =&gt; 자바는 자바스럽게, 디비는 디비스럽게<ul>
<li>JPQL(Java Persistence Query Language)
자바스럽게 쿼리 짜면=&gt; JPA가 알아서 SQL로 바꿔서 쓸게!
(like 슈도 코드)</li>
<li>ex. 
SQL: SELECT *(컬럼) FROM room(테이블 명);
JPQL: SELECT r.price(필드) FROM Room(클래스명) AS r(별칭)</li>
</ul>
</li>
</ul>
<ul>
<li><code>clear()</code>: 영속성 컨텍스트를 클리어! 다 비워버리는 것!</li>
<li><strong><code>flush()</code></strong>: 영속성 컨텍스트 - DB 동기화</li>
<li><code>close()</code>:영속성 컨텍스트를 영업 종료!</li>
</ul>
<h2 id="dto관련-구현-질문">DTO관련 구현 질문?</h2>
<ul>
<li>왜쓰는가? -&gt; 어떻게 쓰는가?</li>
<li>DTO는 몇 개가 적당할까??<ul>
<li>DTO 1개 vs 여러개: 2개 이상 만들기!</li>
<li>사용자의 요청마다 다른 request-&gt;dto-&gt;response
entity당 DTO 몇개씩 가지게 됨</li>
</ul>
</li>
</ul>
<ul>
<li>DTO &lt;-&gt; Entity 변환 어떤 계층?<ul>
<li>Controller: DTO(클라이언트 필요) </li>
<li>Service: 변환하는 것도 로직이라고 생각</li>
<li>Repository: Service에서 연산 다했을 것이라고 믿고, repository에서 변환</li>
</ul>
</li>
<li>변환 방법: 필드, setter &lt; 생성자, builder</li>
<li>Entity는 객체(행위)라기 보단 개체
:    Data덩어리(행위x)</li>
<li>Entity는 지켜줘야징<h3 id="1차-코드-작성">1차 코드 작성</h3>
<h4 id="roomservice">RoomService</h4>
<img src="https://velog.velcdn.com/images/gari_guri/post/02c0faaf-5ffa-4647-a348-c7a1ab59e065/image.png" alt="">
분리가 잘 된것인가? NO
이유: 생성자 인자값이 바뀌거나 메소드명이 바뀐다면 다 같이 바꿔야함
그리고, 방을 저장하는 거지 방을 생성하는 건 아닌데 그 코드까지 있어야 하는가?에 대한 의문증,,,즉, service가 할일이 너무 많음!=&gt;DTO로 코드 이동하자<img src="https://velog.velcdn.com/images/gari_guri/post/1cc6e324-54a3-400a-9274-60e46f3a5f34/image.png" alt=""> </li>
</ul>
<h2 id="jpa-vs-spring-data-jpa">JPA vs Spring Data JPA</h2>
<ul>
<li><p>EntityManager를 누가 다루는가</p>
<ul>
<li><p>JPA: 개발자가 직접</p>
</li>
<li><p>Spring Data JPA: Spring</p>
</li>
<li><p>추상화(인터페이스 제공): 쉽고, 편하게 JPA 사용할 수 있음!</p>
</li>
<li><p><em>대왕 인터페이스 &quot;JPARepository&quot;*</em></p>
<p>(1) (List)CrudRepository 
(2) (List)PagingAndSortingRepository
(3) QueryByExampleExecutor</p>
<h3 id="그럼-jpa-springjpa코드로-변환해보자">그럼 JPA-&gt;SpringJPA코드로 변환해보자!</h3>
</li>
</ul>
</li>
<li><p>가정: <strong>MAP-&gt;JPA</strong>-&gt;Spring Data JPA를 나중엔 쓸거야
 <img src="https://velog.velcdn.com/images/gari_guri/post/b8957b59-6ffa-44af-8b8a-0f6a0eb46316/image.png" alt="">
  변환을 하려고 했더니....
  개방 폐쇄 원칙을 위반!!!⛔️ 
  -&gt; 해결책: interface/추상클래스 🌟추상화🌟</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/a3faa141-e0da-4bbd-a648-4d1b69c3f7e4/image.png" alt="">
<img src="https://velog.velcdn.com/images/gari_guri/post/f3a8d332-f0fc-44d1-92a7-8585432dd2c5/image.png" alt=""></p>
<ul>
<li>Repository가 바꾸어도 서비스가 바뀌지 않도록 하기 위해 ! 중간에 인터페이스를 둠
사실 자바세상에서 확장은 추상화말고는 답이 없어요,,
어렵조..?
다시다시 쉬운 예제로 한번 더 갈게용!
아니 그거 기억나시나요 폰 사람 예제요...
그게 무려 여기서 쓰일려고 미리 했던 거였던 거였던 거였다요...
대박!!!!!!!!!!!이런 큰그림을 
<img src="https://velog.velcdn.com/images/gari_guri/post/bc46a0ef-2e5e-4912-9f46-16e0954e519d/image.png" alt=""></li>
</ul>
<hr>
<h3 id="여기서-잠깐-테스트-코드를-짜려고-했는데">여기서 잠깐,, 테스트 코드를 짜려고 했는데..</h3>
<p>test코드가 aop가 있었다고..?
aop가 test에 나와?!!?
<img src="https://velog.velcdn.com/images/gari_guri/post/13af8652-3342-45d8-821f-2d2b7afb7016/image.png" alt=""></p>
<hr>
<h2 id="예전의-기억을-살려-아래-코드에-먼저-적용해보쟈">예전의 기억을 살려 아래 코드에 먼저 적용해보쟈~</h2>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/27339625-6e44-4049-bac3-e0c9ad791b49/image.png" alt="">
service변경없이 A, B모두 사용가능
(위세줄은 spring이 대신 해줌)하하 개편해!
<img src="https://velog.velcdn.com/images/gari_guri/post/766bedbc-0001-412e-bbfd-8d71903b14ec/image.png" alt="">
아니 근데 안되자나왜 안넣어주냐고!!!! 
nullpointerException이 터져!개빡쳐!
Test코드에서는 스프링이 일을 안하는 거구낭...
스프링 더 일하자,, 
해결방안 : 클래스 위에 <em><strong>@SpringBootTest</strong></em> 추가하면 됨 
그럼 스프링이 테스트에서도 일을하게 됩니당! 스프링 열일해!</p>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/941e794c-dcb6-44b0-9d9f-42283eeb1558/image.png" alt="">음 이제 기동은 되는데 여전히 NullPointerException이 뜨네!??!
어떻게 해결해야 할까?!</p>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/0fb392fa-e5ce-4fe1-bc40-d65b31a6fe54/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MQ]]></title>
            <link>https://velog.io/@gari_guri/MQ</link>
            <guid>https://velog.io/@gari_guri/MQ</guid>
            <pubDate>Wed, 07 Aug 2024 05:01:20 GMT</pubDate>
            <description><![CDATA[<h2 id="mqmessage-queue">MQ(Message Queue)</h2>
<ul>
<li>Message를 Publisher가 보내면 <strong>Queue</strong>에 담겨있다가 Consumer(Customer)가 받아 간다.
cf. &#39;큐잉(Queue)&#39;
<img src="https://velog.velcdn.com/images/gari_guri/post/0aa117ed-5413-4844-9130-0d6edf4651b2/image.png" alt=""><a href="https://www.rabbitmq.com/tutorials">참고자료- rabbitMQ공식문서</a> <h3 id="msa뿐-아니라-여러-시스템의-통신-방식">MSA뿐 아니라 여러 시스템의 통신 방식</h3>
: 분리된 어플리케이션 (모듈)끼리 데이터를 주고 받는 (통신) 방식
ex. A service &lt;-&gt; B service</li>
</ul>
<h3 id="그럼-블로킹논블로킹은-동기와-비동기와-뭐가-다른거지">그럼 블로킹/논블로킹은 동기와 비동기와 뭐가 다른거지?</h3>
<h2 id="동기비동기--블로킹논블로킹-조합">동기/비동기 + 블로킹/논블로킹 조합</h2>
<h3 id="먼저-동기와-비동기에-대해-알아보자">먼저 동기와 비동기에 대해 알아보자!</h3>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/1b7f05b1-6c56-4d8a-8e2f-3c57a13fc6f6/image.png" alt=""></p>
<hr>
<h4 id="동기적-통신방식">동기적 통신방식</h4>
<ul>
<li>요청을 보냈을 때 응답이 올때까지 기다리는 것, 요청과 응답의 순서가 보장된다.</li>
<li>종류<ul>
<li>REST API: http프로토콜 사용</li>
</ul>
</li>
</ul>
<h4 id="비동기적-통신방식">비동기적 통신방식</h4>
<ul>
<li>요청과 응답의 sync가 맞지 않아도 되기때문에 동시에 다른 일을 가능하다.<ul>
<li>완료 여부 신경쓰지 않는 것</li>
<li>요청/전달을 보낸 후, 응답과 관계없이 다음 동작 실행
= 작업이 병렬로 <strong>배치</strong>되어 실행된다.
=&gt; 나중에 시작된 작업이 먼저 끝나는 경우도 가능!</li>
</ul>
</li>
<li><h2 id="종류">종류</h2>
<ul>
<li>메시지 큐 (Message Queue): 메시지 큐를 통해 모듈 간 비동기 메시지를 주고 받는 방식 ex) RabbitMQ, Kafka, ActiveMQ</li>
<li>Publish/Subscribe 모델: 한 모듈이 이벤트를 발행하고 다른 모듈이 이를 구독하여 비동기적으로 통신하는 방식  ex) Apache Kafka</li>
<li>메시지 브로커(중개인) 방식(기술)</li>
</ul>
</li>
</ul>
<p>즉 동기와 비동기는 응답을 받을 때까지, 기다리냐 안기다리냐의 차이!
=&gt; 이렇게 생각하면, 블로킹이랑 마치 비슷해보이는데 완료여부를 신경쓸지 말지의 차이이다.</p>
<table>
<thead>
<tr>
<th>동기</th>
<th>비동기</th>
</tr>
</thead>
<tbody><tr>
<td>A가 B의 리턴(값) 계속 확인! 신경!</td>
<td>B의 작업 완료 여부는 노상관</td>
</tr>
<tr>
<td></td>
<td>콜백함수를 같이 주면서 끝나면 알아서 이거 실행해~</td>
</tr>
<tr>
<td>### 다음은 블로킹과 논블로킹~!</td>
<td></td>
</tr>
<tr>
<td>- 블로킹과 논블로킹은 제어권을 넘겨주는지 아닌지에 대한 차이</td>
<td></td>
</tr>
<tr>
<td>- 제어권을 넘겨주게 되면 다른일을 수행하지 못함.</td>
<td></td>
</tr>
</tbody></table>
<table>
<thead>
<tr>
<th>블로킹</th>
<th>논블로킹</th>
</tr>
</thead>
<tbody><tr>
<td>A　　-&gt; B 제어권 넘김</td>
<td>A가 제어권을 가진 상태로 B 호출!</td>
</tr>
<tr>
<td>A 멈춤 / B 실행</td>
<td>A 계속 실행 / B 실행</td>
</tr>
<tr>
<td>A　　&lt;- B 제어권을 다시 넘김</td>
<td></td>
</tr>
<tr>
<td>(ex. B 함수 완료 시)</td>
<td></td>
</tr>
</tbody></table>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/e0bbbd14-1a28-48a6-9021-4653e80a76c9/image.png" alt=""></p>
<h3 id="이제-블로킹논블로킹--동기비동기의-조합의-차이를-그림으로-보자">이제 블로킹/논블로킹 , 동기/비동기의 조합의 차이를 그림으로 보자!</h3>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/6e5eb429-bc99-4829-bec1-d9fbedd7b516/image.png" alt=""></p>
<hr>
<h2 id="메시지-브로커">메시지 브로커?</h2>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/4a515de1-b6c4-4897-bb5f-3869f4966df8/image.png" alt=""></p>
<ul>
<li><p>메시지 브로커가 왜 생긴걸까?
또, 비동기여야만 하는 이유는?</p>
</li>
<li><p>양쪽 모두에게 자유를 주어 받아가고 싶을 때 받아가고 주고 싶을때 줄 수 있도록!! 주는 친구뿐 아니라, 받아가는 친구의 자유도 높여줌. <em>*<em>like kakaotalk *</em></em>
즉, 서로의 자유도를 높여주기 위해 비동기 메시지 브로커를 사용한다!</p>
</li>
</ul>
<h3 id="예시-주문-서비스">예시) 주문 서비스</h3>
<ul>
<li>주문 서비스에서 메시지 브로커에게 주문 정보를 던져주고, <strong>주문 서비스는 비동기적으로 자기 할 일 계속 함.</strong></li>
<li>재고 서비스가 메시지 브로커에게 주문 정보를 <strong>비동기적으로</strong> 받아가서 재고 수량을 하나 뺀다.</li>
</ul>
<h3 id="종류-1">종류</h3>
<ul>
<li>카프카(Kafka)<ul>
<li>데이터 취합 =&gt; 분산 &quot;스트리밍&quot;</li>
<li>Redis(공유 데이터베이스)
ex. 메신저, 유튜브/넷플릭스</li>
</ul>
</li>
<li>Message Queue(RabbitMQ, ActiveMQ ...)</li>
</ul>
<h2 id="🧶-실습">🧶 실습</h2>
<ul>
<li><a href="https://www.rabbitmq.com/tutorials">실습 자료</a></li>
</ul>
<ol>
<li><p>&quot;Hello World!&quot;</p>
<ul>
<li><p>보내는 쪽</p>
<pre><code class="language-java">package com.example.a_module;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.MessageProperties;
public class Sender {
private final static String QUEUE_NAME = &quot;hello&quot;;
public static void main(String[] argv) throws Exception {
    ConnectionFactory factory = new ConnectionFactory();
    factory.setHost(&quot;localhost&quot;);
    try (Connection connection = factory.newConnection();
         Channel channel = connection.createChannel()) {
            String message = String.join(&quot; &quot;, argv);
            channel.basicPublish(&quot;&quot;, &quot;hello&quot;, null, message.getBytes());
            System.out.println(&quot; [x] Sent &#39;&quot; + message + &quot;&#39;&quot;);
    }
}
}</code></pre>
</li>
<li><p>받는 쪽</p>
<pre><code class="language-java">package com.example.b_module;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
import java.nio.charset.StandardCharsets;
public class Recv {
private final static String QUEUE_NAME = &quot;hello&quot;;
public static void main(String[] argv) throws Exception {
    ConnectionFactory factory = new ConnectionFactory();
    factory.setHost(&quot;localhost&quot;);
    Connection connection = factory.newConnection();
    Channel channel = connection.createChannel();

    channel.queueDeclare(QUEUE_NAME, false, false, false, null);
    System.out.println(&quot; [*] Waiting for messages. To exit press CTRL+C&quot;);

    DeliverCallback deliverCallback = (consumerTag, delivery) -&gt; {
        String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
        System.out.println(&quot; [x] Received &#39;&quot; + message + &quot;&#39;&quot;);
    };
    channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -&gt; { });
}
}
</code></pre>
</li>
</ul>
</li>
<li><p>Work Queues</p>
</li>
</ol>
<ul>
<li><p>라운드 로빈 방식으로 데이터를 받는다.</p>
</li>
<li><p>NewTask</p>
<pre><code class="language-java">//package com.example.a_module;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.MessageProperties;
public class NewTask {
  private static final String TASK_QUEUE_NAME = &quot;task_queue&quot;;
  public static void main(String[] argv) throws Exception {
      ConnectionFactory factory = new ConnectionFactory();
      factory.setHost(&quot;localhost&quot;);
      try (Connection connection = factory.newConnection();
           Channel channel = connection.createChannel()) {
          channel.queueDeclare(TASK_QUEUE_NAME, true, false, false, null);

          String message = String.join(&quot; &quot;, argv);

          channel.basicPublish(&quot;&quot;, TASK_QUEUE_NAME,
                  MessageProperties.PERSISTENT_TEXT_PLAIN,
                  message.getBytes(&quot;UTF-8&quot;));
          System.out.println(&quot; [x] Sent &#39;&quot; + message + &quot;&#39;&quot;);
      }
  }
}
</code></pre>
</li>
</ul>
<pre><code>- Worker
```java
//package com.example.b_module;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
import java.nio.charset.StandardCharsets;

public class Worker {
    private static final String TASK_QUEUE_NAME = &quot;task_queue&quot;;

    public static void main(String[] argv) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(&quot;localhost&quot;);
        final Connection connection = factory.newConnection();
        final Channel channel = connection.createChannel();

        channel.queueDeclare(TASK_QUEUE_NAME, true, false, false, null);
        System.out.println(&quot; [*] Waiting for messages. To exit press CTRL+C&quot;);

        channel.basicQos(1);

        DeliverCallback deliverCallback = (consumerTag, delivery) -&gt; {
            String message = new String(delivery.getBody(), &quot;UTF-8&quot;);

            System.out.println(&quot; [x] Received &#39;&quot; + message + &quot;&#39;&quot;);
            try {
                doWork(message);
            } finally {
                System.out.println(&quot; [x] Done&quot;);
                channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
            }
        };
        channel.basicConsume(TASK_QUEUE_NAME, false, deliverCallback, consumerTag -&gt; { });
    }

    private static void doWork(String task) {
        for (char ch : task.toCharArray()) {
            if (ch == &#39;.&#39;) {
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException _ignored) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    }
}
</code></pre><h4 id="결과-화면">결과 화면</h4>
<ul>
<li>2개의 워커가 번갈아가면서 메세지를 받을 수 있다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/fbff4851-81a0-4312-853f-d623174a4b63/image.png" alt=""><img src="https://velog.velcdn.com/images/gari_guri/post/1d32f8a8-7eaf-41d8-ba30-67682ed886e5/image.png" alt=""><img src="https://velog.velcdn.com/images/gari_guri/post/1d32f8a8-7eaf-41d8-ba30-67682ed886e5/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MSA]]></title>
            <link>https://velog.io/@gari_guri/MSA</link>
            <guid>https://velog.io/@gari_guri/MSA</guid>
            <pubDate>Tue, 06 Aug 2024 00:11:57 GMT</pubDate>
            <description><![CDATA[<h2 id="모놀리식">모놀리식</h2>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/8f35efda-1ad1-43be-96da-348bbfdc7848/image.png" alt=""></p>
<h2 id="msa">MSA</h2>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/0e400a5a-2096-49a0-b467-09258a6933a8/image.png" alt=""></p>
<h3 id="msa의-장점-scale-out">MSA의 장점: Scale-out</h3>
<ul>
<li>Scale-out: 서버를 추가하여 시스템을 확장<ul>
<li>서비스가 다 나뉘어져 있기 때문에 추가 삭제 수정이 용이하기 때문(서비스가 죽지 않아야 한다!) </li>
<li>만약, 각 서버들이 수정될 때마다 주소값을 수동으로 바꿔야 한다면?</li>
<li>Scale-out장점이 되려 단점이 되버림ㅠㅠ 관리 포인트가 늘어나기 때문!</li>
<li>따라서, <strong>&quot;서비스 레지스트리&quot;</strong>: <em><strong>서비스</strong></em> 주소를 관리해주는 친구(User, Room...)</li>
</ul>
</li>
<li>Scalue-up: 기존 서버 사양 업그레이드</li>
</ul>
<h3 id="service-registry">Service Registry</h3>
<p>서비스의 위치 저장/관리 전담</p>
<ul>
<li>내부 서비스 간 통신(다른 서비스 주소 필요할 때)</li>
<li>게이트웨이가 Request에 따른 서비스 주소가 필요할 때</li>
<li>사실 서비스 B, C, D가 아니라, 서비스 A 부하 분산용 인스턴스를 여러개 둘때 많이 씀
(로드밸런스도 여기서 함께 사용됨 부하를 막기 위해!)</li>
</ul>
<p>cf. 레지스트리 
윈도우 레지스트리: OS설정값, 정보를 담고 있는 저장소)
=&gt; 소프트웨어들에 대한 각종 설정값, 정보를 담고있는 저장소</p>
<h3 id="게이트-웨이">게이트 웨이</h3>
<ul>
<li>네트워크 상에서 서로 다른<ul>
<li>통신망</li>
<li>프로토콜
끼리 통신이 가능하게 하는 컴퓨터/소프트웨어</li>
</ul>
</li>
<li>*&quot;(종류가) 다른 하드웨어/소프트웨어 간 통로의 역할&quot;**</li>
</ul>
<p>ex) ESL, 여러개의 게이트 웨이를 통해 매장 내 가격 태그를 커버한다.</p>
<h3 id="registry">registry</h3>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/e4194f18-020b-4fbb-bb13-9743d4c1a51b/image.png" alt="">
1️⃣그림<img src="https://velog.velcdn.com/images/gari_guri/post/30393a4d-f0fd-48e8-be20-4ec2da234671/image.png" alt=""></p>
<p>2️⃣그림<img src="https://velog.velcdn.com/images/gari_guri/post/1a95be38-cfd5-4b2d-980f-59ee878957c3/image.png" alt="">
1️⃣과2️⃣의 그림과 다른 점은 서비스가 직접 regitry에 주소를 저장하고, 레지스터를 참고하는 것은 api gateway단에서 진행되며 api gateway에서 뿌려준다는 것</p>
<h3 id="고민한-점">고민한 점</h3>
<p>로드 밸런스를 여러 개 두면,
룸과 유저에서 소통할때 부하가 너무 심해지지않을까?</p>
<ul>
<li>주문 내역을 가져오기 위해 회원 ID가 필요한 경우</li>
<li>미리 인증 인가를 판단하고 들어오도록 해서 부하를 줄이자!</li>
</ul>
<p>DB를 다 따로 사용하면, DB를 동기화하는데 어렵지 않을까?</p>
<ul>
<li>RDS를 사용하자!! DB서버 따로, 웹서버 따로 사용해서 하나의 DB만 사용할 수 있도록</li>
<li>그럼 위 그림에서는 RDS를 4개 사용하게 되는 거겠쪼?!</li>
</ul>
<p><em><strong>정리</strong></em>
MSA는 연관관계를 다 끊는 것!
: user에게 요청을 하면 안된다. order객체 안에 파라미터 안에 직접 유저 아이디를 집어 넣어야하고, 객체간의 연관관계를 끊어야 하기 때문</p>
<p>그럼 어떻게 연관관계를 끊어야 할까?</p>
<ul>
<li>foriegn key를 사용하지 않고 순수한 컬럼을 사용하고,</li>
<li>메시지 큐를 사용해서 탈퇴했다는 이벤트가 발생하면 각각의 테이블을 업데이트 하는 방법</li>
</ul>
<h3 id="client-side-discovery">Client Side Discovery</h3>
<ul>
<li><p>서비스 레지스트리(구현체)를 직접 사용 </p>
</li>
<li><p>대표적인 라이브러리: Spring Cloud Netflix Eureka
<img src="https://velog.velcdn.com/images/gari_guri/post/03f49c7c-525a-4005-b8c3-936ab7571103/image.png" alt="">
서비스 A와 서비스 B가 소통하고 싶을때 서비스 A는 주소를 registy에 등록하고, 서비스 B가 A의 주소를 받아와 소통함</p>
</li>
<li><p>장점: 구현 간단, 레퍼런스가 많음</p>
</li>
<li><p>단점: 각 서비스임에도 불구하고, 서비스 레지스트리에 모두 완전 의존
=&gt; 폴리그랏의 경우, 환경에 따라 여러번 구현해야 한다!
cf. 폴리그랏(polyglot) 각 서비스가 다른 언어/프레임워크 환경</p>
<h3 id="server-side-discovery">Server Side Discovery</h3>
<p>로드 밸런스가 있는 것: 인스턴스가 여러개
4번까지 로드밸런스가 해줌
<img src="https://velog.velcdn.com/images/gari_guri/post/2cdb88af-d181-48c7-83f1-e5770146a4a1/image.png" alt="">
&lt;그림에는 없지만, A외에도 B, C서비스가 존재한다&gt;
서비스가 registy에 주소를 등록하고, 서비스 A가 직접 동사무소에 가지않고, 로드밸런스에게 대신 물어보고, B가 하려는 일도 대신 해줌
질의(주소 알아와주고) + 통신(다른 서비스와 통신)</p>
</li>
<li><p>장점: 로드밸런스(추상화)-서비스레지스트리(구현체)</p>
</li>
<li><p>단점: 네트워크 hop이 증가 = &#39;상대적&#39; 속도 지연</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[유효성 검사]]></title>
            <link>https://velog.io/@gari_guri/%EC%9C%A0%ED%9A%A8%EC%84%B1-%EA%B2%80%EC%82%AC</link>
            <guid>https://velog.io/@gari_guri/%EC%9C%A0%ED%9A%A8%EC%84%B1-%EA%B2%80%EC%82%AC</guid>
            <pubDate>Mon, 05 Aug 2024 01:33:48 GMT</pubDate>
            <description><![CDATA[<h2 id="유효성-검사">유효성 검사</h2>
<ul>
<li>검증(증명) vs 검사/검정(확인)</li>
<li>백엔드 세상의 조건에 부합하는지 확인
ex. 비밀번호 규칙</li>
</ul>
<h3 id="추가-질문">추가 질문</h3>
<ul>
<li><p>(1) 이미 가입된 id(중복 검사) 확인은 유효성 검사일까?</p>
<ul>
<li>맞다: 잘못된 값이라면 비지니스 로직을 돌리는데 의미가 없다. 앞단에서 유효성검사로 걸러줘야 한다.</li>
<li>아니다: 올바른 값인 것은 맞지만 조건에 맞지 않은 것 뿐, 이를 처리하는 것은 또 다른 하나의 로직이라고 생각한다.</li>
</ul>
</li>
<li><p>(2) 검사는 어디서? 처리는 어디서?</p>
<ul>
<li>백엔드 세상 조건에 부합하는지 확인해야하기 때문에 </li>
<li>컨트롤러에서 검사를 해서 들여보낸다 백엔드 들어가기 직전에!</li>
<li>검사에서 걸렸어 처리좀 해줘!: 처리는 서비스에서 시킴</li>
<li>서비스가 어떤 에러에 걸렸는지 알려줌</li>
<li>컨트롤러가 받아서 클라이언트에게 알려줌</li>
<li>유효성 검사를 예외처리로 풀어내는 것: 어떤 필드가 문제인지 예외처리로 필터링하는 것 (예외 처리를 일종)</li>
<li>즉, controller가 exception을 던지고, service가 받아서 처리한다.
(정답은 아니고 보통 처리하는 방법)</li>
</ul>
</li>
</ul>
<h2 id="valid-vs-validated">@Valid( vs @Validated)</h2>
<p>1) 어느 dependency 소속일까?: spring boot starter validation
2) 어떤 어노테이션과 같이 쓸까?</p>
<ul>
<li><code>@Email</code> : 이메일 형식 검사</li>
<li><code>@Size</code>: 값이 min과 max사이에 속해야함 @Size(max = 10, min = 1)</li>
<li><code>@NotBlank</code>: 값이 비어있으면 X </li>
<li><code>@NotNull</code>: Null값이 아니어야 한다.</li>
<li><code>@PositiveOrZero</code> : 0이거나 양수인 값이다.</li>
<li><code>@Future</code>: 날짜 필드가 미래여야 함을 지정</li>
<li><code>@FutureOrPresent</code>: Now 거나 미래의 날짜, 시간이어야 한다.</li>
<li><code>@Max(9999)</code> <code>Min</code> : 최대 9999까지 허용 (최소도 마찬가지)</li>
<li><code>@Pattern</code>: 비밀번호 유효성 검사에 주로 사용</li>
</ul>
<p>3) 어노테이션들은 어디에다 붙여야 할까?</p>
<ul>
<li><code>@Valid</code>: Controller/<code>@RequestBody</code> <code>@Valid</code> DTO</li>
<li><code>@NotNull</code>, <code>@Pattern</code>...: DTO field 위</li>
</ul>
<h3 id="validation">@Validation</h3>
<ul>
<li><code>@Valid</code>는 자바 표준 스펙이고 <code>@Validated</code>는 스프링에서 제공하는 어노테이션</li>
<li><code>@Validated</code>를 통해 <strong>그룹 유효성 검사</strong>나 Controller가 아닌 다른 계층에서 유효성 검증 가능 </li>
<li><code>@Valid</code>는 MethodArgumentNotValidException 예외를, <code>@Validated</code>는 ConstraintViolationException 예외를 발생시킨다.
AOP 기반으로 메소드 요청을 인터셉터하여 처리된다.</li>
</ul>
<h2 id="validator-유틸성-클래스">Validator: 유틸성 클래스</h2>
<ul>
<li><code>isNumber</code></li>
<li><code>isAlpha</code></li>
</ul>
<h2 id="sme-라이브러리">SME 라이브러리</h2>
<ul>
<li>자바 표준 라이브러리(ex 컬렉션)를 확장하여 좀 더 편리한 기능을 제공하는 라이브러리</li>
<li>대표적인 예시: Apache commons, Google guava</li>
<li>implemenation &#39;com.google.guava:guava&#39;
ex. Range.closed(1,10), Strings.inNullOrEmpty(문자열)
Strings.commonPrefix()/Suffix() &lt;-&gt; padStart()/End();
joiner.on(문장부호).join(배열)
🌟ex) Splitter.on(&quot;&amp;&quot;).trimResults().withKeyValueSeparator(&quot;=&quot;).split(&quot;name=gari&amp;age=20&quot;)
=&gt; {name=gari, age=20}</li>
</ul>
<h2 id="user--validation">User + Validation</h2>
<ul>
<li><p>1단계. 회원가입할 때 조건!</p>
<ul>
<li><p>이름이 NotBlank</p>
</li>
<li><p>비밀번호 최소 8자리 이상</p>
</li>
<li><p>이메일 주소 이메일 형식에 맞게</p>
<h4 id="만약-위-조건에-부합하지-않은-값을-입력한다면">만약 위 조건에 부합하지 않은 값을 입력한다면?</h4>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/3e046c98-6edc-4c52-84ae-0b99291f3625/image.png" alt=""> 조건에 만족하지 않는 필드를 모두 보여준다.
그럼 위 내용들을 에러처리하고 싶은 데 어떻게 해야할까?</p>
<h3 id="방법1-errors-파라미터에-추가">방법1: Errors 파라미터에 추가</h3>
<pre><code class="language-java">@PostMapping(&quot;/join&quot;)
public void join(@RequestBody @Valid UserJoinReq userJoinReq, Errors errors){
   //userService.join(userJoinReq);
   for (FieldError fieldError: errors.getFieldErrors()){
       System.out.println(&quot;Error field : &quot;+fieldError.getField());
   }
   System.out.println(&quot;회원가입 완료&quot;);
}</code></pre>
<h4 id="결과화면">결과화면 <img src="https://velog.velcdn.com/images/gari_guri/post/5112169f-f84a-45d6-84d7-3793ebfa9e4a/image.png" alt=""></h4>
<h3 id="방법1-1-bindingresult">방법1-1: BindingResult</h3>
</li>
<li><p>Spring validator가 검증/검사 하다가 오류가 발생하면, 오류가 난 특정 필드 or 객체를 Errors(BindingResult)에 담음!</p>
</li>
<li><p>BindingResult와 Errors중 어느것이 더 구체적일까?
<code>BindingResult extends Errors</code>
: Errors를 상속하는 BindingResult가 더 구체적이다. 
=&gt; Errors를 상속받았기 때문에 Errors 인터페이스를 통해서 BindingResult의 유효성 검증 에러 관련 멤버에 접근 가능!
cf. BindingResult는 &quot;데이터 바인딩 에러&quot; + &quot;유효성 검증 에러&quot;
ex. @ModelAttribute Model model</p>
</li>
</ul>
</li>
<li><p>그래서 유효성 검사 중 에러가 나면 어디에 담기는걸까?
   **  AbstractBindingResult의 필드에 addError메소드를 통해 저장함**
  <img src="https://velog.velcdn.com/images/gari_guri/post/b81a935b-7215-4c52-85a2-f3e186112246/image.png" alt=""></p>
<h3 id="방법2-컨트롤러에서-서비스로-에러를-전달해서-처리해보자">방법2: 컨트롤러에서 서비스로 에러를 전달해서 처리해보자!</h3>
<pre><code class="language-java">@PostMapping(&quot;/join&quot;)
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  public Map&lt;String, String&gt; join(@RequestBody @Valid UserJoinReq userJoinReq, Errors errors){
      //userService.join(userJoinReq);
      Map&lt;String, String&gt; errormessages=userService.handleErrors(errors);
      //Map =&gt; new ApiError(errorMessages);
      return errormessages;
  }</code></pre>
<pre><code class="language-java"> @Component
public class UserService {
  public Map&lt;String, String &gt; handleErrors(Errors errors){
      Map&lt;String, String&gt; errorMessages=new HashMap&lt;&gt;();
      for (FieldError fieldError: errors.getFieldErrors()){
          String errorField=fieldError.getField();
          String errorMessage=fieldError.getDefaultMessage();
          errorMessages.put(errorField, errorMessage);
      }
      return errorMessages;
  }
 }</code></pre>
<h4 id="결과화면-1">결과화면</h4>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/23758f79-4e3e-4601-b9fc-cc373f473f85/image.png" alt=""></p>
<h3 id="방법3-에러를-global하게-처리하자">방법3: 에러를 global하게 처리하자</h3>
<p>Controller</p>
<pre><code class="language-java"> @PostMapping(&quot;/signup&quot;)
  public ResponseEntity&lt;String&gt; signup(@RequestBody @Valid UserJoinReq userJoinReq) {
      userService.join(userJoinReq); // 유효성 검사를 통과한 경우 처리 로직 호출
      return ResponseEntity.status(HttpStatus.CREATED).body(&quot;success&quot;); // 성공 응답 반환
  }</code></pre>
<p>Global  Exception</p>
<pre><code class="language-java"> @ExceptionHandler
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  public Map&lt;String, String &gt; handleValidationExceptions(MethodArgumentNotValidException errors) {
      Map&lt;String, String&gt; errorMessages=new HashMap&lt;&gt;();
      for (FieldError fieldError: errors.getFieldErrors()){
          String errorField=fieldError.getField();
          String errorMessage=fieldError.getDefaultMessage();
          errorMessages.put(errorField, errorMessage);
      }
      return errorMessages;
  }</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Generic 뜯어보자]]></title>
            <link>https://velog.io/@gari_guri/Generic-%EA%B2%BD%ED%97%98%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@gari_guri/Generic-%EA%B2%BD%ED%97%98%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 02 Aug 2024 12:41:33 GMT</pubDate>
            <description><![CDATA[<h2 id="아래-코드를-보고-apiresult의-생김새를-추측해보자">아래 코드를 보고 ApiResult의 생김새를 추측해보자!</h2>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/546fd009-aeb4-4428-8118-49f96e1f1e48/image.png" alt=""></p>
<hr>
<pre><code class="language-java">public static class ApiResult&lt;T&gt; {
    private private boolean success;
    private private T response;
    private private Throwable error;

    public ApiResult(boolean success, T response, Throwable error) {
        this.success = success;
        this.response = response;
        this.error = error;
    }
}</code></pre>
<hr>
<h2 id="보완하고-싶은-점">보완하고 싶은 점</h2>
<ul>
<li>ApiUtils 굳이 없어도 될듯! 리턴을 하는 역할 밖에 안하기 때문</li>
<li>null을 굳이 생성자에 들어가야 할까?<ul>
<li>private fianl로 선언해서 수정이 불가능하도록 하고,</li>
<li>constructor에서 초기화하는 것 외에는 불가 constructor로 무조건 주입해야해 발생한 상황</li>
</ul>
</li>
<li>차라리 성공/실패 객체를 따로 만드는게 좋을 듯</li>
</ul>
<h2 id="왜-이렇게-설계했을까">왜 이렇게 설계했을까?</h2>
<ul>
<li>성공이든 실패이든 <strong>같은 필드</strong>로 보고 싶어서 </li>
<li>프론트 입장에서 쉽게 꺼내서 확인하고 처리할 수 있도록 하기 위해</li>
<li>프론트엔드와 협의해야할 부분일듯 </li>
</ul>
<p><a href="https://github.com/hui3363/OrderManagement/blob/main/src/main/java/com/github/prgrms/utils/ApiUtils.java">참고 깃 허브 주소</a>
<del>코드 내 static: 객체 생성없이 사용 가능하도록 함.-&gt; 단일책임원칙을 어기진 않음</del></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[제네릭 ]]></title>
            <link>https://velog.io/@gari_guri/%EC%A0%9C%EB%84%A4%EB%A6%AD-2jrfbfay</link>
            <guid>https://velog.io/@gari_guri/%EC%A0%9C%EB%84%A4%EB%A6%AD-2jrfbfay</guid>
            <pubDate>Fri, 02 Aug 2024 02:50:37 GMT</pubDate>
            <description><![CDATA[<h2 id="제네릭">제네릭?</h2>
<ul>
<li>클래스 <strong>내부에서</strong> 사용할 객체를 <em><strong>외부에서</strong></em> 사용자 정의해서 쓸 수 있는 기술</li>
</ul>
<h2 id="왜-제네릭을-쓸까-제네릭의-장점">왜 제네릭을 쓸까? [제네릭의 장점]</h2>
<ol>
<li>다운캐스팅을 안해줘도 됨=바로 꺼내쓰기 가능</li>
<li>컴파일 시점에서 캐스팅 가능 여부 알려줌<pre><code class="language-java">package com.example.summer.generic;
</code></pre>
</li>
</ol>
<p>public class GenericClassDemo {
    private static Component t;
    private static Component component;</p>
<pre><code>public static void main(String[] args) {
    BoxObject boxObject=new BoxObject();
    boxObject.o=new Object();
    System.out.println(boxObject.o.toString());


    BoxGeneric&lt;Object&gt; boxGeneric=new BoxGeneric&lt;&gt;();
    boxGeneric.t=new Object();
    System.out.println(boxGeneric.t.toString());

    BoxObject boxComponent=new BoxObject();
    boxComponent.o=new Component();
    Component component =(Component) boxComponent.o; //down grading을 해야하고
    System.out.println(component.field);


    BoxGeneric&lt;Component&gt; boxGenericComponent=new BoxGeneric&lt;&gt;();
    boxGenericComponent.t=new Component();
    System.out.println(boxGenericComponent.t.field);//그냥 꺼내써도 됨

    String str1=(String) boxObject.o;
    String str2=(String) boxGeneric.t;
    //String str3=(String) boxGenericComponent.t;

}</code></pre><p>}</p>
<p>class BoxGeneric<T>{
    T t;
}
class BoxObject{
    Object o;
}
class Component{</p>
<pre><code>String field;</code></pre><p>}</p>
<pre><code>
### 그렇다면 아래 코드가 가능할까?
1) String str1=(String) boxObject.o; : **NO!**
2) String str2=(String) boxGeneric.t; : **NO!**

--&gt;String 타입으로 안전하게 사용하려면 타입 확인 및 적절한 캐스팅이 필요함!
## 제네릭 메소드
클래스와 독립적으로 제네릭을 운용(사용)할 수 있는 메소드
```java
class GenericClass&lt;C&gt;{
    C c;
    //제네릭 클래스
    public C methodC(C c){ //외부에서 정해준 객체 C 다 같은 것
        return c;
    }
    //제네릭 메소드
    public &lt;M&gt; M methodM(M m){ //&lt;M&gt;: 나 제네릭 메소드라고 선언하는 것
        return m;

    }
    public &lt;G&gt; C multiMethod(G g, C c){ //제네릭메소드꺼+ 클래스꺼 반환타입은 클래스꺼(멀티 가능)
        return c;
    }


}</code></pre><h3 id="예시-아래-t들에-대해-구별해보자">예시) 아래 T들에 대해 구별해보자</h3>
<pre><code class="language-java">class ClassWithGenericMethod&lt;T&gt; {
    // 클래스명 옆의 T와 같은 타입.
    // 객체 생성 시점에 정해진 타입으로 결정, 타입을 바꾸고 싶으면 해당 타입의 객체를 새로 만들어야 함.
     T t;

     // 필드의 T과 다른 독립적인 타입, 객체 생성 때와 다른 타입 가능.(덮어쓰기 가능)
     // 이때 메소드의 T는 동적 타입으로 메소드를 호출할 때마다 모든 타입 가능!
     public &lt;T&gt; T genericMethod(T t1, T t2) {
         return t1;
     }
}

class BoxGeneric2&lt;T&gt; {
    // 클래스명 옆의 T와 같은 타입으로만 가능하다.&lt;T&gt; 선언X
    public void test(T t1) {
    }
}</code></pre>
<ul>
<li>제네릭 메소드는 클래스 레벨의 타입과 독립적으로 메소드 레벨의 타입으로 덮어쓰기가 가능하다!</li>
</ul>
<h2 id="t--타입-파라미터">&lt; T &gt; 타입 파라미터</h2>
<ul>
<li>&lt; T &gt;</li>
<li>&lt; S &gt;</li>
<li>&lt; U &gt;</li>
<li>아무의미 없음, 암묵적인 약속일뿐</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[파리 올림픽]]></title>
            <link>https://velog.io/@gari_guri/%ED%8C%8C%EB%A6%AC-%EC%98%AC%EB%A6%BC%ED%94%BD</link>
            <guid>https://velog.io/@gari_guri/%ED%8C%8C%EB%A6%AC-%EC%98%AC%EB%A6%BC%ED%94%BD</guid>
            <pubDate>Wed, 31 Jul 2024 06:28:54 GMT</pubDate>
            <description><![CDATA[<h2 id="파리올림픽-class">파리올림픽 class</h2>
<ul>
<li><p>종목들: Sports class 상속 종목 &quot;클래스&quot;</p>
</li>
<li><p>참여 국가들: Nation class 상속 국가 &quot;클래스&quot;</p>
</li>
<li><p>Add종목(종목): 종목들에 종목 추가</p>
</li>
<li><p>Add국가(국가): 국가들에 국가 추가</p>
</li>
<li><p>print종목들(): 종목 전체 출력</p>
</li>
<li><p>print참여국가들(): 국가 전체 출력</p>
</li>
<li><p>GenericDemo class: psvm</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[쿠키와 세션 그리고JWT..]]></title>
            <link>https://velog.io/@gari_guri/%EC%BF%A0%ED%82%A4%EC%99%80-%EC%84%B8%EC%85%98-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%ED%86%A0%ED%81%B0</link>
            <guid>https://velog.io/@gari_guri/%EC%BF%A0%ED%82%A4%EC%99%80-%EC%84%B8%EC%85%98-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%ED%86%A0%ED%81%B0</guid>
            <pubDate>Wed, 31 Jul 2024 00:56:35 GMT</pubDate>
            <description><![CDATA[<h3 id="로그인">로그인</h3>
<p>쿠키가 왜 필요할까?</p>
<ul>
<li>웹은 stateless이기 때문에 서로 상태를 기억하지 못한다는 것이 문제</li>
<li>포춘 쿠키 : 나의 정보를 담고 있음</li>
<li>서버가 쿠키를 구워서 클라이언트에게 주고, 들고 다녀야 서버가 확인 가능함-&gt; 로그인 유지</li>
<li>보안이 좋지 않음: 다른 사람이 포춘 쿠키를 먹을 수 있음</li>
</ul>
<p>그래서 나온것이 세션!</p>
<ul>
<li>로그인 세션이 만료되었습니다.</li>
<li>보안이 안좋기 때문에</li>
<li>중요한 정보는 돌 밑에다 숨겨놓고 어디에 숨겨놓았는지에 대한 돌번호 정보는 쿠키에 저장해서 전달</li>
<li>세션 아이디? 돌 번호</li>
</ul>
<p>그렇다면 JWT는?</p>
<ul>
<li><a href="https://jwt.io/">jwt 문서</a></li>
<li>정보를 암호화해서 만든 토큰</li>
<li>헤더/내용/서명</li>
<li>서버에서 생성된 토큰을 클라이언트에게 전달</li>
<li>클라이언트는 이 토큰을 저장하고, 요청 시마다 서버에 전달</li>
<li>서버는 토큰을 검증하여 요청을 처리</li>
</ul>
<h3 id="쿠키-vs-세션-vs-jwt">쿠키 vs 세션 vs JWT</h3>
<h3 id="쿠키">쿠키</h3>
<ul>
<li>클라이언트 측에 저장됨</li>
<li>보안에 취약할 수 있음</li>
<li>간단한 데이터 저장에 유용</li>
</ul>
<h3 id="세션">세션</h3>
<ul>
<li>서버 측에 저장됨</li>
<li>더 높은 보안 수준</li>
<li>서버 리소스를 사용함</li>
</ul>
<h3 id="jwt">JWT</h3>
<ul>
<li>클라이언트 측에 저장됨</li>
<li>정보가 암호화되어 있음</li>
<li>서버 확장성에 유리</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring Boot 프로세스 분석하기]]></title>
            <link>https://velog.io/@gari_guri/Spring-Boot</link>
            <guid>https://velog.io/@gari_guri/Spring-Boot</guid>
            <pubDate>Tue, 30 Jul 2024 00:56:49 GMT</pubDate>
            <description><![CDATA[<h2 id="spring-boot의-공통-프로세스-처리">Spring Boot의 공통 프로세스 처리</h2>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/f39a29f6-4eda-455e-adf9-7e9398cfaeec/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/53178cd1-f300-47a3-b94a-86d1e8413e54/image.png" alt=""></p>
<ul>
<li>위 그림에서 아쉬운점 AOP의 위치
: AOP는 어디서든 쓸 수 인터셉터와 컨트롤러 사이뿐만아니라!<blockquote>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/5229fc5e-e739-4f3b-8f6b-28a676e05ce1/image.png" alt=""></p>
<ul>
<li>DispatcherServlet: 순서를 결정해서 그에 맞게 불러주는 친구, 스케쥴링, http 프로토콜로 들어오는 모든 요청을 가장 먼저 받아 알맞은 컨트롤러에 위임해주는 프론트 컨트롤러</li>
</ul>
</blockquote>
</li>
</ul>
<ul>
<li>HandlerInterceptor: 핸들러로 가는애를 인터셉트 낚아채서 값을 체크, 검사하는 용도로만 사용함, 데이터를 건들지 않음
로그인 체크, <ul>
<li>인터셉터: 요청에 대한 작업 전(후) 가로채어 공통 작업 수행</li>
<li>res/req 낚아채서 (데이터 접근 가능 but,)
직접 다루는 일은 없어야 함!데이터를 바꾸면 안된다!<ul>
<li>사용예시
: 로그인 여부 체크, 검사<pre><code class="language-java">@Configuration //스프링아 나 이 파일 설정파일로 쓸거야
public class CustomWebMvcConfigurer extends WebMvcConfigurationSupport {
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor())
 .addPathPatterns(&quot;/**&quot;);
}
}</code></pre>
</li>
<li>registry(feat.MSA)
모듈 간 소통 어떻게? 서로의 주소를 알아야하잖아?! </li>
<li><em>아이디어1*</em>💡 : 대신 전달하는 전달자 역할을 하는 친구를 하나 두자!
<img src="https://velog.velcdn.com/images/gari_guri/post/3545640f-5e53-4189-80dd-069a24832923/image.png" alt="">
그런데! 
대신 전달자 역할 친구: 야 나 전달만 하고 싶어 주소록 관리까지 하는게 너무 힘들어!
전달하는 친구의 부하를 너무 크다ㅠ^ㅠ 부하를 줄일 방법은?</li>
</ul>
</li>
</ul>
</li>
</ul>
<p><strong>아이디어2</strong>💡 : 주소를 관리하는 친구를 따로 두자!
<img src="https://velog.velcdn.com/images/gari_guri/post/39b27c11-01a5-4a98-ad98-42a309b4057e/image.png" alt="">
위 그림과 같이 주소를 관리하는 친구를 따로 두고 요청이 들어오면 주소록 친구에게 주소를 받아서 소통하는 방식을 채택함.</p>
<ul>
<li>여기서 주소록 역할을 하는 친구가 registry</li>
<li>대신 전달해주는 친구가 load balancer</li>
</ul>
<h3 id="필터--인터셉터">필터 ~ 인터셉터</h3>
<blockquote>
<h4 id="✔️-필터인터셉터-어떻게-구동될까🧐">✔️ 필터~인터셉터 어떻게 구동될까?🧐</h4>
</blockquote>
<ul>
<li>성공적으로 Res 날아올때</li>
<li>404처럼 처리할 수 없는 요청이 날아올 때</li>
<li>아예 예외가 터져버렸을 때(/error)</li>
</ul>
<h3 id="🌟webmvcconfigurationsuppor">🌟WebMvcConfigurationSuppor</h3>
<ul>
<li>잘못된 요청을 보냈을 때!
<img src="https://velog.velcdn.com/images/gari_guri/post/f8067396-16fc-4a61-ae44-813c2a13c998/image.png" alt="">디스패처 서블릿이 일 시킬 게 없음 즉, 요청을 받는 컨트롤러가 없음
: 요청이 틀리면 전달해줄값이 없으면 받아줄 컨트롤러가 없으면 filter로 돌아가게 됨.
<em><strong>그럼 왜 로그가 두 번 찍히는 걸까?</strong></em>
요청이 받아주지 않으면 왜 response안오지? 라고 생각하고, 먼저 돌아 나가고, 핸들러 인터셉터는 할 일 하고 나감!
그래서 로그가 2번 찍히는 것!
즉, exception 에러가 터지면 controller로 다시 요청이 가서, 두바퀴돌기 때문!</li>
</ul>
<hr>
<ul>
<li>올바른 요청 보냈을 때!
<img src="https://velog.velcdn.com/images/gari_guri/post/25aff60f-61ad-43ab-a963-8a2ea2ca16eb/image.png" alt="">
디스패처 서블릿이 리퀘스트가 날라오면 일 시킬거리인 요청만 보내기 때문에 잘 나옴 나어디 줄데 있나 있으면 컨트롤러로 보냄 핸들러 인터셉터할일 하기..
vs @autoConfiguration 자동등록해드릴게 자동등록안해줄게 <h3 id="🌟-webmvcconfigurer">🌟 WebMvcConfigurer</h3>
</li>
<li>잘못된 요청
<img src="https://velog.velcdn.com/images/gari_guri/post/38413a7f-ad9c-47c1-8d5f-6df526e8aef5/image.png" alt=""></li>
</ul>
<ul>
<li>올바른 요청
<img src="https://velog.velcdn.com/images/gari_guri/post/9f39b911-5d02-4930-9a8e-f669081039f1/image.png" alt=""></li>
</ul>
<h2 id="역할">역할</h2>
<ul>
<li><p>Data Binding: 잭슨, 역직렬화/직렬화(interceptor), requestBody</p>
</li>
<li><p>validation</p>
</li>
<li><p>Handler exception resolver: exception이 터지면 잡아줌</p>
</li>
<li><p>filter: log 찍기 가능, 헤더관련된 것 처리, 인코딩(헤더값에 존재) 변환 처리, XSS 방어</p>
<ul>
<li>ServletRequest/ServletResponse 객체 변경 및 조작 수행 가능</li>
<li>WAS 내의 ApplicationContext에서 등록된 필터가 실행됨.
➡️ 스프링이 알아야 한다! 스프링아 이거 필터니깐 봐줘! ➡️ 에노테이션 존재 ➡️ spring context는 bean 밖에 존재하는데 어떻게 스프링이 스캔할까?➡️ <code>@serveltComponentScan</code>
<img src="https://velog.velcdn.com/images/gari_guri/post/a2e4db92-2b96-4275-9fe4-2c7fb10193c4/image.png" alt=""></li>
</ul>
</li>
<li><p>chain.doFilter</p>
<pre><code class="language-java">@Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
          throws IOException, ServletException {
      HttpServletRequest req = (HttpServletRequest) request;
      HttpServletResponse res = (HttpServletResponse) response;

      String requestURI = req.getRequestURI();

      System.out.println(&quot;Filter Request - &quot; + requestURI);
      chain.doFilter(request, response); //필터가 이 사이에서 실행될 것
      System.out.println(&quot;Filter Response - &quot; + requestURI);
  }
</code></pre>
</li>
</ul>
<pre><code>다음 필터나 마지막 필터로 넘겨주는 것 (나 방금 이 리퀘스트 지나왔거든!)
다음 리스펀스 들고 다음 리퀘스트로 넘겨주는 것

&gt; 💡OWASP(Open web Application Security project)
⚠️ 웹이 공격을 당하는 방법
&gt;1. SQL Injection
&gt;2. XSS: 버튼을 누르면 숨겨진 스크립트가 날라감
&gt;3. CSRF(Cross Site Request Forgery): 사용자인척 웹 취약점을 공격



## 시큐리티 with 필터, 인터셉터
- 필터: 시큐리티 먹일까 말까 고민! 필터 씌울까말까 체인을 걸까 말까?
- 인터셉터: 필터로 시큐리티를 먹임 로그인을 해야만 들어갈 수 있도록 하고 싶음. 필터가 걸렸으면 **인터셉터가 등장**해서 체크해 드림! 사전 권한 체크

</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[🧶실습 당근마켓]]></title>
            <link>https://velog.io/@gari_guri/%EC%8B%A4%EC%8A%B5-%EB%8B%B9%EA%B7%BC%EB%A7%88%EC%BC%93</link>
            <guid>https://velog.io/@gari_guri/%EC%8B%A4%EC%8A%B5-%EB%8B%B9%EA%B7%BC%EB%A7%88%EC%BC%93</guid>
            <pubDate>Tue, 30 Jul 2024 00:26:38 GMT</pubDate>
            <description><![CDATA[<h3 id="할인-2가지-중복-할인은-안됨">할인: 2가지 중복 할인은 안됨!</h3>
<ul>
<li>회원 등급(1~5등급, 5%) 당 할인</li>
<li>5명 선착순 (10%) 할인<h3 id="비회원-서비스-비회원-할인">비회원 서비스=&gt; 비회원 할인</h3>
</li>
<li>선착순 할인<h3 id="회원-서비스-회원-할인">회원 서비스=&gt; 회원 할인</h3>
</li>
<li>등급 할인</li>
</ul>
<h3 id="컨트롤러-서비스-or-추가-클래스">컨트롤러, 서비스 or 추가 클래스</h3>
<h4 id="input-price--a---x">input: price + a  / X</h4>
<h4 id="output-discounted-price--01">output: discounted price / 0,1</h4>
<h2 id="당근마켓-with-solid-원칙">당근마켓 with SOLID 원칙</h2>
<ol>
<li>서비스-메소드 2개 (회원/비회원)
<img src="https://velog.velcdn.com/images/gari_guri/post/fbbacd7b-df62-4a9a-bd0f-f00c0105995a/image.png" alt=""></li>
<li>서비스 분리 or Not<h3 id="member">Member</h3>
</li>
</ol>
<ul>
<li><p>비밀번호 저장
  : 비밀번호 암호화해서 저장 &gt; 다른 곳에 로직 빼기: 책임 분리!</p>
</li>
<li><p>회원정보 조회</p>
</li>
<li><p>...</p>
<h3 id="할인-기능-구현-어디서-할까">할인 기능 구현 어디서 할까?</h3>
<p>회원 서비스에서 다 구현하기에는.. 좀,,,</p>
<h3 id="할인-정책-분리-or-not">할인 정책 분리 or Not</h3>
<p>회원 서비스에서 다 구현하기에는 회원 서비스의 역할이 너무 많다.
분리 진행-&gt; 인터페이스로 분리할까? 추상 메소드로 분리할까?
둘의 차이점을 먼저 보자. 둘
인터페이스와 추상메소드는 객체를 만들 수 있냐없냐의 차이가 존재하고,
인터페이스는 객체를 만들지 못하고, 생성자가 없다는 특징!
이후 결정해보자~</p>
</li>
</ul>
<h2 id="primaryqulifier">@Primary+@Qulifier</h2>
<h3 id="step1-discountpolicy가-2개">step1. discountPolicy가 2개</h3>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/b3f45c67-5003-411c-9951-7f5dd00c6574/image.png" alt="">
스프링은 타입이 같을때에는 이름을 보고 구별해 빈에서 골라와 의존성을 주입한다.
<del>충격적 스프링은 천재다..!</del>
하나의 타입으로 여러개 객체가 있으면 매개변수 이름으로 구별한다는 뜻!
하지만 추천하지 않는다.
&lt;이유: 타입으로 스프링 빈 찾기에 실패하면, 매개변수명으로도 찾을 수는 있다. 하지만, 추천하지 않는다. 불명확하기 때문 &gt;</p>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/cd7207a1-ae05-4e65-a786-3a86392dbf34/image.png" alt="">
그렇다면 이름까지 같게 만들면 스프링이 구별을 전혀 못하게찌~?
역시 에러 발생!!-&gt; 스프링: 야 개발자야! 빈이 2개야...뭘 넣어줘야해?라는 오류⛔️</p>
<h3 id="해결방안-primary">해결방안: @Primary</h3>
<p><code>@Primary</code>를 비회원에 달아줬더니
<img src="https://velog.velcdn.com/images/gari_guri/post/6f0b3c54-c09b-4c75-bb14-477c69563c81/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/335ff3b3-7eae-4900-9066-bcc65635cbc2/image.png" alt="">
회원임에도 0이 나오네,,1이 나와야하는데ㅠㅠ😹
그럼 MemberPolicy 도대체 어떻게 써야 할까??</p>
<h4 id="방법1">방법1.</h4>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/dc9df696-03aa-4976-90b7-6f38c79b3101/image.png" alt=""></p>
<h4 id="방법2qulifier-애노테이션-쓰기">방법2.@Qulifier 애노테이션 쓰기!</h4>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/f539010f-0f37-46af-9770-db0dcab33f26/image.png" alt=""></p>
<h3 id="드디어-해결-완료-😝"><em><strong>드디어 해결 완료 😝</strong></em></h3>
<hr>
<h2 id="위-코드를-확장하면서">위 코드를 확장하면서...</h2>
<h3 id="🚨문제-상황발생🚨">🚨문제 상황발생🚨</h3>
<ul>
<li>회원은 <strong>가격</strong>과, <strong>등급</strong>을</li>
<li>비회원 <strong>가격</strong>만 받기 때문에
인터페이스를 분리하려고 했을때...
discountPolicy를</li>
</ul>
<ol>
<li><em>discount(price): 비회원</em>, </li>
<li><em>discount(price, level)</em>: 회원 로 구현하려고 하는데 매개변수가 다르기 때문에 하나의 인터페이스로 추상화 실패<h3 id="해결방안">해결방안</h3>
</li>
</ol>
<ul>
<li><ol>
<li>매개변수를 리스트로 받아오면, [0]: price, [1]: level</li>
</ol>
</li>
<li><ol start="2">
<li>level을 매개변수로 안받고 메소드 내에서 해결하기</li>
</ol>
</li>
<li><ol start="3">
<li>인터페이스를 분리? 어떻게 ? 상위의 인터페이스를 만들어주어 연결하기!</li>
</ol>
</li>
</ul>
<h3 id="tradeoff">TradeOff</h3>
<ul>
<li>인터페이스를 메소드를 안써도 하나로 쓴다면? 다형성이 좋을듯, 하지만 ISP포기해야한다.</li>
<li>하지만 인터페이스를 분리한다면? 다형성은 떨어지지만, ISP원칙은 지킬 수 있다<h2 id="인터페이스-분리-원칙isp">인터페이스 분리 원칙(ISP)</h2>
: 클라이언트가 자신이 이용하지 않는 메서드에 의존하지 않아야 한다는 원칙
(<del>컨벤션: 약속</del>)</li>
</ul>
<h3 id="isp와-다형성-실습-🧶">ISP와 다형성 실습 🧶</h3>
<ul>
<li><p>BluetoothAISpeaker: volumeUp, heyGoogle();</p>
</li>
<li><p><code>Marshall, JBL, Britz implements BluetoothAISpeake</code></p>
<ul>
<li>장점) 하나의 타입으로 여러 구현체 담아 &quot;다형성&quot;</li>
<li>단점) 필요없는 메소드도 구현하는 척 해야함</li>
</ul>
</li>
<li><p>Speaker/Bluetooth/AI 인터페이스로 분리</p>
</li>
<li><p><code>Marshall: Speaker, Blutooth, A</code></p>
</li>
<li><p><code>JBL: Speaker, Blutoot</code></p>
</li>
<li><p><code>Britz: Speaker</code></p>
<ul>
<li>장점) 필요한 메소드만 구현</li>
<li>단점) 하나의 타입으로 담을 수 없다. +팔다리 접고 들어가야함...하지만</li>
</ul>
</li>
</ul>
<h3 id="진짜-real-팔다리를-다시-펼순-없는거야">진짜?!? real? 팔다리를 다시 펼순 없는거야?</h3>
<p>아니지 아니지</p>
<h3 id="해결방안-1">해결방안</h3>
<p>[1] 매개변수로 받아서 사용하는 메소드를 오버로딩<img src="https://velog.velcdn.com/images/gari_guri/post/e8ff9193-0eb2-4c41-81e3-e1462e5e1226/image.png" alt="">
[2] 상위 인터페이스를 만들어서, 팔다리 접어서 들어간 구현체를 instancof + 캐스팅을 활용하여 팔다리 다시 폄</p>
<pre><code class="language-java">package com.example.summer.isp;

interface ABInterface {

}

interface AInterface extends ABInterface{
    void methodA();
}

interface BInterface extends ABInterface{
    void methodB();
}

class ImplA implements AInterface{

    @Override
    public void methodA() {
        System.out.println(&quot;implA&quot;);
    }
}

class ImplB implements BInterface {

    @Override
    public void methodB() {
        System.out.println(&quot;implB&quot;);
    }
}

public class IspDemo {
    public static void main(String[] args) {
        ispMethod(new ImplA());
        ispMethod(new ImplB());
    }

    public static void ispMethod(ABInterface abInterface) {
        if (abInterface instanceof AInterface)
            ((AInterface) abInterface).methodA();
        else if (abInterface instanceof BInterface)
            ((BInterface) abInterface).methodB();
    }
}</code></pre>
<p>[3] 제네릭 사용</p>
<pre><code class="language-java">package com.example.summer.isp;

interface ABInterface {

}

interface AInterface extends ABInterface{
    void methodA();
}

interface BInterface extends ABInterface{
    void methodB();
}

class ImplA implements AInterface{

    @Override
    public void methodA() {
        System.out.println(&quot;implA&quot;);
    }
}

class ImplB implements BInterface {

    @Override
    public void methodB() {
        System.out.println(&quot;implB&quot;);
    }
}

public class IspDemo {
    public static void main(String[] args) {
        GenericIsp&lt;AInterface&gt; genericIspA = new GenericIsp&lt;&gt;();
        genericIspA.ispMethod(new ImplA());

        GenericIsp&lt;BInterface&gt; genericIspB = new GenericIsp&lt;&gt;();
        genericIspB.ispMethod(new ImplB());
    }
}

class GenericIsp&lt;T&gt; {
    public void ispMethod(T abInterface) {
        if (abInterface instanceof AInterface)
            ((AInterface) abInterface).methodA();
        else if (abInterface instanceof BInterface)
            ((BInterface) abInterface).methodB();
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[JPA에 맞서기 위한 준비!]]></title>
            <link>https://velog.io/@gari_guri/JPA%EC%97%90-%EB%A7%9E%EC%84%9C%EA%B8%B0-%EC%9C%84%ED%95%9C-%EC%A4%80%EB%B9%84</link>
            <guid>https://velog.io/@gari_guri/JPA%EC%97%90-%EB%A7%9E%EC%84%9C%EA%B8%B0-%EC%9C%84%ED%95%9C-%EC%A4%80%EB%B9%84</guid>
            <pubDate>Sun, 28 Jul 2024 05:41:56 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>드디어 악명 높던 JPA를 배울 시간<del>!✨
그 전에 !!! JPA에 정복하기 위해서는 준비를 탄탄히 하는데 중요하게쬬?!🌟
사전 지식들을 다지러 가봅시다</del>!</p>
</blockquote>
<h2 id="validation-유효성-검사-">validation 유효성 검사 ?</h2>
<ul>
<li>null이냐? not null이냐?를 알아보는 것</li>
<li>유요한 데이터인지 검사하는 것</li>
<li>백엔드/프론트엔드에서 하는 유효성검사가 다를까?</li>
<li>만약 다르다면 어떤 시점으로 보는가?</li>
<li>같은 유효성검사를 해야 할 때 어디에서 할 것인가?<ul>
<li>백엔드와 프론트엔드 둘다? 두 군데에서 모두 암호화할듯!<ul>
<li>그렇다면 중복된 로직을 사용하는 건가? NO! 다른 로직을 통해 암호화<ul>
<li>프론트엔드에서 한다면? 프론트에서 암호화해서 넘겼을 때, 백은 검사안해도 될까? 암호화 안해도 될까? -&gt; 생각해보기! </li>
<li>백엔드에서 한다면? 서버를 따로 띄울때 프론트엔드에서 보낸 날 것의 비밀번호를 가로챌 수 있음</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="데이터베이스를-왜쓸까">데이터베이스를 왜쓸까?</h2>
<ul>
<li>데이터가 뭔가요❓데이터베이스에 들어가야하는 데이터</li>
<li>데이터베이스 왜쓸까? 자료구조를 왜 사용하는 지에 대한 이유와 동일하게 효율적으로 데이터를 쉽고 빠르게 사용하기 위해 사용하지!</li>
</ul>
<p>즉 데이터베이스는 검증된 데이터가 체계적으로 모여있어서 나중에 사용할 때, 효율적으로 데이터를 찾아서 쓸 수 있는 멋진 공간이다!</p>
<ul>
<li>DB엔진: 코어</li>
<li>DBMS: DB엔진을 인터페이스로 한겹 감싸서 managment system을 사용<h2 id="정규화반정규화">정규화/반정규화</h2>
</li>
<li>정규화란? <em><strong>쪼개기</strong></em> 
: 데이터베이스의 컬럼이 많을 때, <strong>중복된</strong> 데이터가 많을 때 중복된 데이터를 많이 사용하면 메모리 사용량이 크고, 불필요한 비용이 듦 </li>
<li><blockquote>
<p>유지보수에 좋음</p>
</blockquote>
</li>
<li>반정규화란? <em><strong>합치기</strong></em> 
: join을 많이 해야할 때, 데이터를 조회할 때 많은 시간이 걸릴 때<blockquote>
<p>최대 제 3정규화까지 사용!</p>
</blockquote>
<ul>
<li>🌟 sub query</li>
<li>🌟 select join</li>
<li>🌟 union</li>
</ul>
</li>
</ul>
<h2 id="eof-exception은-언제-발생">EOF exception은 언제 발생?</h2>
<ul>
<li>connection이 끊겼을 때</li>
<li>권한이 없을 때</li>
<li>도커에서 포트 넘버가 다를때 
3307:3306 외부에서 도커 들어울때, 안쪽에서 처리할때 각각 포트 넘버<h3 id="이제-본격적으로-jpajdbc에-대해-배워봅시당☛-다음-블로그">이제 본격적으로 JPA(+jdbc)에 대해 배워봅시당~!☛<a href="https://velog.io/@gari_guri/JPA"> 다음 블로그</a></h3>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[자바와 DB 패러다임의 차이]]></title>
            <link>https://velog.io/@gari_guri/%EC%9E%90%EB%B0%94%EC%99%80-DB-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84%EC%9D%98-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@gari_guri/%EC%9E%90%EB%B0%94%EC%99%80-DB-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84%EC%9D%98-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Sat, 27 Jul 2024 13:13:39 GMT</pubDate>
            <description><![CDATA[<h3 id="✅-단어-정리부터">✅ 단어 정리부터!</h3>
<blockquote>
<h3 id="패러다임이란">패러다임이란?</h3>
<p>한 시대의 사람들의 견해나 사고를 근본적으로 규정하고 있는 인식의 체계. 또는, 사물에 대한 이론적인 틀이나 체계.</p>
</blockquote>
<p>흠... 쉽지 않은데.. 자바세상과 DB세상에서 데이터를 다루는 룰? 이라고 해석해보자!</p>
<h3 id="✅-그럼-자바세상과-db세상의-룰-차이는-뭘까">✅ 그럼 자바세상과 DB세상의 룰 차이는 뭘까?</h3>
<p>먼저 자바세상의 규칙을 보자!
✔️자바는 데이터를 &quot;객체&quot;로 다룬다. (객체 지향적)
✔️DB에서는 &quot;데이터&quot; 간의 &quot;관계&quot;를 표현한다.(데이터 지향적, sql지향적)</p>
<h3 id="🌟-예시-호텔과-룸">🌟 예시: 호텔과 룸</h3>
<p>✔️fact: 호텔은 여러개의 방을 가지고 있다 -&gt; <strong>1 : N 관계</strong></p>
<p><strong>Q. 그럼 자바 세상에서는 어떻게 호텔과 방의 데이터들을 표현할까?</strong>
<img src="https://velog.velcdn.com/images/gari_guri/post/4f43decc-6e91-4ecd-8e91-45883280d135/image.png" alt="">
호텔 클래스에 방 객체를 리스트 형태로 포함하고 있다!</p>
<p><strong>Q. 그렇다면 DB 세상에서는 호텔과 방의 관계를 어떻게 표현할까?</strong>
<img src="https://velog.velcdn.com/images/gari_guri/post/433e2db8-afcb-4d46-a4af-ac90e734bfe6/image.png" alt=""></p>
<p>위 erd설계와 같이 일대다 관계로 호텔과 방을 연결하였다!</p>
<h3 id="정리">정리</h3>
<blockquote>
<p>자바세상과 DB세상에서는 1:N 관계를 나타내는 방식이 다르다.
 : 일대일/일대다 관계에서 id로 연결하느냐/객체로 연결하느냐의 차이가 존재 -&gt; 객체 사이의 연관이 있을 때 문제가 생김
자바: 상속, 계층 관계    <em><strong>&quot;객체 세상&quot;</strong></em>
DB: 매핑, 동등 관계   <em><strong>&quot;데이터 세상&quot;</strong></em></p>
</blockquote>
<p>✨그렇다면 자바와 DB의 데이터를 다루는 데이터의 기본 단위(자바: 객체, DB: 데이터)가 다른데 어떻게 자바에서 데이터를 저장해야 할까??</p>
<p>둘 중에 하나가 양보해서 한쪽의 방식에 맞춰준다면 가능하겠지만,
서로가 양보할 수는 없어❌
양보하는 순간 자바와 DB의 가장 중요한 특성을 잃어버리기 때문이지ㅠㅠ
🤔: 그럼..방법이 모야?! 자바에서는 데이터를 저장할 수 없는거야?!!!</p>
<p>😀: 하나의 방법이 있긴해..
자바와 DB 사이 에서 중개자 역할을 해주는 어떤 것이 존재하면 되잖아!</p>
<p>두둥!! 이런 니즈로 인해 ⚡️ <em><strong>JPA</strong></em>(JAVA Persistant Api)⚡️ 등장한 것이야</p>
<p>JAVA에게 꼭 필요한 JPA는 서로의 특성을 유지해 자바는 객체 지향 설계를, DB에서는 관계 지향 설계를 할 수 있도록하는 역할을 하지</p>
<p>그럼 <a href="https://velog.io/@gari_guri/JPA">다음 블로그</a>에서는 JPA를 본격적으로 들어가기 앞서 지식을 정리해보자!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JPA 진입..!]]></title>
            <link>https://velog.io/@gari_guri/JPA</link>
            <guid>https://velog.io/@gari_guri/JPA</guid>
            <pubDate>Thu, 25 Jul 2024 05:46:47 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h3 id="들어가기-앞서">들어가기 앞서....</h3>
<p>음...제가 한번 JPA 경험을 해봤는데요..
정말 매콤하더라구요 😂
단단히 마음의 준비 하시구요! 천천히 JPA에 스며들어봅시당..!</p>
</blockquote>
<h2 id="먼저-jdbc부터">먼저 JDBC부터!</h2>
<p> ✔️ JDBC의 특징</p>
<ul>
<li>JDBC는 사실 api! </li>
<li>JDBC를 한겹 더 싸는 것이 myBatis이고, </li>
<li>default: 하이버 네이트 사용</li>
<li>sql을 통해서 직접 객체를 mapping하는 역할</li>
</ul>
<h2 id="jpa는-해결사✨">JPA는 해결사!✨</h2>
<p>앞 포스팅에서 JPA가 필요한 이유는 말씀드렸쬬?! 
그럼 JPA가 얼마나 중요한지 체감하신걸로 알고! 넘어가겠습니당
먼저 maven repository에 들어가서 jpa을 검색해볼까요~?
<img src="https://velog.velcdn.com/images/gari_guri/post/90fc9277-22b2-47da-8765-ceb95cb83422/image.png" alt="">
<a href="https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa/3.3.2">maven repository</a>에서 찾은 JPA repository에 jdbc가 포함되어 있는거 보이시나용?!
JPA는 사실 JDBC를 포함하고 있는데요
JDBC만으로 sql를 통해서 직접 객체를 mapping하는 것도 쉽지 않았다고 합니다...
그래서  JDBC를 포함하고 있는 <strong>JPA가</strong> 이 중대한 문제의 해결사‼️라는 말이죠.</p>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/e3faa06f-69ae-471c-8fb3-2338d4fe7da8/image.png" alt="">
(cf. ORM: 객체와 관계를 mapping하는 것)
위 그림과 같이 JPA(+JDBC)가 자바와 mysql사이에서 데이터를 요청하고, 제공하며 mapping시켜주고 있네요.</p>
<h3 id="코드-적용1">코드 적용1</h3>
<p>이론으로 배웠으니 이제 코드에 적용해봅시당</p>
<p>Q. MySQL과 JPA를 깔고 싶은데 어떻게 해야할까요?
▶︎ 간단합니당 인텔리제이의 build.gradle파일에 DB설치 명령하면 되게쬬?!
코드</p>
<pre><code class="language-java">implementation &#39;mysql:mysql-connector-java:8.0.31&#39; //mysql을 사용할거야!
implementation &#39;org.springframework.boot:spring-boot-starter-data-jpa:3.3.2&#39; //jpa를 사용할거야!</code></pre>
<p>위에서 언급했다시피 jpa안에 jdbc가 포함되어 있기 때문에 jdbc코드는 추가하지 않아도 됩니다.
또 버전을 추가로 적지않아도, 안정화된 최신 버전을 자동으로 다운해줍니다! </p>
<h3 id="spring-data-jpa는-또-뭐야">Spring Data JPA는 또 뭐야?</h3>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/0d98a0a9-d76c-4416-a81d-d187a1903b67/image.png" alt=""></p>
<ul>
<li>JPA와 Spring Data JPA와 같을까 다를까용?</li>
<li>JPA와 같기도 하고 다르기도하다...! 
<img src="https://velog.velcdn.com/images/gari_guri/post/b52bd49d-9898-4d27-bca3-6bf34eb786de/image.png" alt="">
스프링이 기존 JPA+스프링 추가 기능을 덧댄 것이 Spring Data JPA이기 때문이죠!</li>
</ul>
<blockquote>
<p>즉 , spring이 우리가 JPA를 더 편하게 쓸 수 있게 도와주는 것!
&quot;Spring Data JPA&quot;는 더욱 추상화한 인터페이스이다!
로 정리할 수 있겠네용</p>
</blockquote>
<hr>
<h3 id="jdbc에서-일하는-친구">JDBC에서 일하는 친구</h3>
<ul>
<li><p>DataSource: &quot;JDBC주요 일꾼&quot;으로 무슨역할을 할까?</p>
<ul>
<li>DB와 소통 역할</li>
<li>데이터를 주고받을 터널을 뚫을 주는 객체</li>
</ul>
</li>
<li><p>jdbc 구현체: Hikari</p>
</li>
</ul>
<h3 id="코드-적용2---데이터-소스">코드 적용2 - 데이터 소스</h3>
<h4 id="applicationpropertiesn-프로젝트-속성-코드-추가">application.propertiesn &lt;프로젝트 속성&gt; 코드 추가</h4>
<p>1) DB 연결(JDBC를 사용하려면, &#39;<strong>DabaSource</strong> 객체&#39;속성)</p>
<pre><code>    spring.datasource.driver-class-name=마리아db
    spring.datasource.url=내 컴퓨터에 있는 디비
    spring.datasource.username=dbwjspdla
    spring.datasource.password=비밀번호</code></pre><p><a href="https://docs.spring.io/spring-boot/reference/data/sql.html">spring datasource 공식문서</a></p>
<p>2) 포트 넘버 바꾸기
3) 프로젝트 이름 바꾸기
4) 로그 파일 경로</p>
<blockquote>
<h4 id="주의할-점--막간지식">주의할 점 + 막간지식</h4>
</blockquote>
<ul>
<li>yml: 코드의 중복을 해결하는 파일형식 (트리구조)</li>
<li>xml: &lt;&gt; 파일 형식</li>
<li>데이터베이스도 일종의 웹서버처럼 데이터 베이스 서버역할을 하기 때문에 port번호가 필요한 것</li>
<li>jpa는 기본 속성이 없어서 필요한 것만 추가해야 함</li>
</ul>
<hr>
<h2 id="db-api들의-구현체-내-주요-객체">DB API들의 구현체 내 주요 객체</h2>
<ul>
<li>JDBC &lt;복습&gt;<ul>
<li>구현체: Hikari(패키지)</li>
<li>주요 객체: DataSource</li>
</ul>
</li>
<li>JPA<ul>
<li>구현체: hibernate(패키지)</li>
<li>주요 객체: <strong>EntityManager</strong>: persistant 운동장에서 열심히 일하는 일꾼</li>
<li>EntityManager는 어디에 구현되어있을까? 직접 찾아봅시다!! ⬇️<img src="https://velog.velcdn.com/images/gari_guri/post/37d3f63e-6eff-4280-aaf0-4bcb0b4b5e8d/image.png" alt=""><img src="https://velog.velcdn.com/images/gari_guri/post/797a99a6-f822-4825-9fec-7a067ad18a06/image.png" alt=""><ul>
<li>Spring Data JPA</li>
<li>구현체: </li>
</ul>
</li>
<li>주요 객체: <blockquote>
<h3 id="여기서-생긴-궁금증❓">여기서 생긴 궁금증❓</h3>
<p>dataSource와 EntityManager를 우리는 등록한적이 없는데 어떻게 등록되어있는 걸까yo?!?!
<img src="https://velog.velcdn.com/images/gari_guri/post/84331cab-026a-4ce1-9628-e7387697c9b6/image.png" alt=""><code>@AutoConfiguration</code>애노테이션을 통해 스프링이 자동으로 미리 등록해준다고 합니다!! 
스프링 짱!🫡</p>
</blockquote>
</li>
</ul>
</li>
</ul>
<hr>
<hr>
<hr>
<h2 id="entity-method">Entity method</h2>
<p><a href="https://bnzn2426.tistory.com/143">참고 자료</a></p>
<ul>
<li>persist(Object entity): 새로운 엔티티를 영속성 컨텍스트에 추가+저장</li>
<li>merge(T entity): 분리된 엔티티의 상태를 현재 영속성 컨텍스트와 병합</li>
<li>remove(Object entity): 영속성 컨텍스트에서 엔티티를 제거</li>
<li>flush(): 영속성 컨텍스트의 변경 사항을 데이터베이스에 즉시 반영</li>
<li>clear(): 영속성 컨텍스트를 비운다.</li>
<li>close(): EntityManager를 닫는다.</li>
</ul>
<h2 id="jpa가-어떻게-영속화를-해줄까">JPA가 어떻게 영속화를 해줄까?</h2>
<ul>
<li><p>Entity: 나 영속화되고 싶은 객체/영속화가 된 객체 </p>
<ul>
<li>@Entity 어노테이션을 클래스 위에 달아두면, </li>
<li>EntityContext(영속화가 될/된 객체 공간)에 들어가<strong>고 싶어!</strong>라는 말!</li>
</ul>
</li>
<li><p>EntityManager: </p>
<ul>
<li>persist(): EntityContext에 Entity를 모아둠 + 테이블에 저장
그렇다면... Entitycontext에 없는 객체를 테이블에 저장할 수 있을까❓NO!
EntityContext에 추가되어야 테이블에 저장됨!!!</li>
</ul>
</li>
<li><p>EntityContext:</p>
</li>
<li><p>ORM
JPA의 최고 일꾼 EntityManager가 ORM을 해줌 어떻게? 영속성을 지키고자 하는 객체를 entityContext에 넣어놓고, entityManager가 
entityContext를 보고 오? 너 영속화 되길 원하는 구나 ! 내가 해줄게 해서 ORM을 실시!</p>
<blockquote>
<h3 id="🔮정리">🔮<strong>정리</strong></h3>
<p>자바와 DB사이(정확히는 자바 끄트머리)에 엔터티 컨텍스트가 있고, 둘 사이를 데이터가 왔다 갔다하려면, 엔터티 컨텍스트에 꼭 들렸다 와야한다. 
이를 담당하는 것이 <em><strong>EntityManager</strong></em>!
<img src="https://velog.velcdn.com/images/gari_guri/post/ad8f43ce-a9c8-4a2f-a901-a474004b02cf/image.png" alt=""></p>
</blockquote>
</li>
</ul>
<h2 id="코드에-적용을-해봅시다">코드에 적용을 해봅시다!</h2>
<pre><code class="language-java">@Component
public class RoomRepository {
    EntityManager entityManager;
    public RoomRepository(EntityManager entityManager) {
        this.entityManager = entityManager;
    }
    Map&lt;Integer, Room&gt; roomTable=new HashMap&lt;&gt;();
    int idx=0;
    public void saveRoom(Room room) {
        entityManager.persist(room);
    }
}</code></pre>
<pre><code class="language-java">@Entity
public class Room {
    int id;
    private String type;
    int price;

    public String getType(){
        return type;
    }
}</code></pre>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/c5490617-a8f2-47a1-b619-341b24020d67/image.png" alt=""></p>
<h3 id="⛔️-오류가-발생함-무슨-오류일까">⛔️ 오류가 발생함.. 무슨 오류일까?</h3>
<p>위 사진을 보니.. @Id가 필요하다구 왜..?!?!</p>
<p><strong>이유</strong>: DB에 들어가면 id가 생기겠지만, EntityContext내에서는 id가 없음-&gt; @id: 룸들을 식별하기 위한 식별자
EntityManager가 EntityContext안을 보는데 똑같은 애들room들을 식별하기 위해 붙여주는 것
Id를 만들어서 식별해줘야겠다!</p>
<h3 id="해결-id를-통해-식별자로-쓰면-돼">해결: @Id를 통해 식별자로 쓰면 돼!</h3>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/93518885-c151-4854-99ec-dc4b771c79c0/image.png" alt=""></p>
<h2 id="다시-코드-적용">다시 코드 적용</h2>
<pre><code class="language-java">@Entity
public class Room {
    @Id //추가
    int id;
    private String type;
    int price;

    public String getType(){
        return type;
    }
}</code></pre>
<h3 id="⛔️-다시-실행했더니-아래와-같이-transaction-오류가-뜨네">⛔️ 다시 실행했더니 아래와 같이 transaction 오류가 뜨네</h3>
<p>또 뭐가 문제야!!
<img src="https://velog.velcdn.com/images/gari_guri/post/71f29b2d-b5ba-49e4-b51d-9c9d376f1432/image.png" alt=""><img src="https://velog.velcdn.com/images/gari_guri/post/6d7d8a85-3e3a-4538-9bfe-d7d21aab9dc5/image.png" alt=""></p>
<ul>
<li>transaction: 로직 단위 여러개-&gt; service에서 처리<h3 id="해결-transactional로-처리">해결: @Transactional로 처리</h3>
<h2 id="코드에-다시-또-적용해보자">코드에 다시 또 적용해보자!</h2>
<pre><code class="language-java">RoomService
@Transactional
  public void saveRoom(Room room) {
      roomRepository.saveRoom(room);
  }</code></pre>
오 드디어 !!200 Ok가 떴지만, id가 자동으로 만들어지네 나는 id를 따로 생성한적이 없는데 어떻게 자동으로 만들어지는 걸까?!?🤔</li>
<li><blockquote>
<p>entitymanager가 식별할 수 없어서, 
entity context에 들어와야 저장 가능한데 id가 없음 그럼 아이디가 어떻게 만들지? db한테 가서 아직 저장하지 말고 잠깐만 해봐봐 id만들어볼게 rollback도 가능해!
id 만들었어 1가지고 와서 entity로 만드는 것 
transaction을 왜 만들까? 잘못하면 db에서 만든 id를 rollback해야할 수 있음
db야 내가 관리하기 전이긴 한데 너가 id좀 만들어줬으면 좋겠어 저장은 하지말고 저장해보더니 1이던데? 이제 entity식별 가능하네 다시 db에 저장완료!
<img src="https://velog.velcdn.com/images/gari_guri/post/4314d275-9a2f-4c47-a64a-373495817f71/image.png" alt=""></p>
</blockquote>
</li>
</ul>
<p>post=&gt; getter가 있어야 함
나머지 =&gt;setter가 있어야함?</p>
<h2 id="드디어-끝-😝">드디어 끝! 😝</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[예외 처리 최종편🔥]]></title>
            <link>https://velog.io/@gari_guri/%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC-%EC%B5%9C%EC%A2%85%ED%8E%B8</link>
            <guid>https://velog.io/@gari_guri/%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC-%EC%B5%9C%EC%A2%85%ED%8E%B8</guid>
            <pubDate>Wed, 24 Jul 2024 23:42:28 GMT</pubDate>
            <description><![CDATA[<h2 id="호텔-룸-코드-호출-스택-처리과정">호텔 룸 코드 &lt;호출 스택 처리과정&gt;</h2>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/a8127694-c2ad-416e-bc3a-473307d195e4/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/36b447cd-6e5c-42cd-ab53-0d6ebe5cab17/image.png" alt=""></p>
<h2 id="예외처리-끝장내자">예외처리 끝장내자!</h2>
<h3 id="📖-복습">📖 복습</h3>
<ul>
<li><p>Unchecked: Runtime(Call stack) 구동</p>
<ul>
<li><strong>링킹 흐름/호출 스택 안에서 어디에서든 처리를 하면 된다!</strong></li>
</ul>
</li>
<li><p>Checked: Compile시 구동</p>
<ul>
<li>예외 처리를 하지 않으면 컴파일 오류 발생
해결 방안
1) 예외터진 곳에서 직접 try catch로 처리
2) throws를 사용해서 책임 전가 처리</li>
<li>예외를 전달받은 곳에서 예외 처리를 해야만 함!</li>
</ul>
</li>
<li><p>Handler: 자동으로 호출되는 메소드</p>
<h3 id="그런데-unchecked-exception은-진짜-어디에서든-처리하면돼-진짜로">그런데.. unchecked exception은 진짜 어디에서든 처리하면돼..? 진짜로?</h3>
<p>아닛 정신차려! 우리에겐 세가지 선택지가 있어!</p>
</li>
</ul>
<ol>
<li>앞서 실습한 에러 터진 곳에서 바로 처리-&gt; 이건 checked exception에서는 필수로 해야해!바로 처리안하면 컴파일 에러 생기거등!!</li>
<li>controller에서 처리</li>
<li>global하게 처리</li>
</ol>
<h3 id="1번은-앞선-포스트에서-실습했으니깐-2번부터-배워보자">1번은 앞선 포스트에서 실습했으니깐 2번부터 배워보자!!</h3>
<hr>
<ul>
<li><h2 id="exceptionhandler"><code>@ExceptionHandler</code></h2>
: 예외가 터지면 자동으로 호출되는 메소드 at Controller(무조건 컨트롤러에서만 실행됨)</li>
<li>예시<pre><code class="language-java"> @ExceptionHandler(value = RoomNotFoundException.class) //이 예외 발생하면 아래 메소드 실행할거야!
  public String catchRoomNotFoundException(RoomNotFoundException e){
      return e.getMessage();
  }</code></pre>
  <img src="https://velog.velcdn.com/images/gari_guri/post/09d7f3d3-ff89-424c-bdf6-934d92805481/image.png" alt=""><ul>
<li>value가 없어도 실행가능: 인자 예외 클래스를 통해 스프링이 추측 가능하기 때문!</li>
</ul>
</li>
</ul>
<ul>
<li><strong>궁금증1❓</strong>RoomController의 Request를 처리하다가 발생한 예외를     AccommodationController에서 @ExceptionHandler로 처리가능할까?
직접 한번 해보자 ! Room controller코드를 Hotel controller코드로 이동만하고 실행했더니...
 <img src="https://velog.velcdn.com/images/gari_guri/post/e18921ee-e0fd-45ed-9e90-d06804b25ddc/image.png" alt="">
오류발생..
그렇다면 답은 ❌NO❌</li>
</ul>
<ul>
<li><strong>궁금증2</strong>❓RoomController랑 AccommodationController가 같은 예외를 같은 방법으로 처리한다면?
Ex. NullPointerException -&gt; &quot;없음!&quot;
=&gt; 다른 Controller끼리는 @ExceptionHandler 공유 ❌</li>
</ul>
<p>두 군데에서 같은 로직을 중복되게 짜야한다는 말이야...?
너무 비효율적인데, 개발자가 이걸 두고만 봤을리가 없징,,ㅎ</p>
<p>=&gt; 아이디어: totalController를 만들어서 그 안에 넣자!
그렇다면 totalController역할을 하는건,,?</p>
<hr>
<ul>
<li><h2 id="바로-controlleradvice">바로 <code>@ControllerAdvice</code></h2>
<p>: AOP가 없으면 일어날 수 없는 어노테이션
: 모든 controller들의 공통 Exception 처리 클래스 생성 가능!!
: 모든 컨트롤러에 예외가 발생하면 낚아챌거야!!라는 의미 가진 어노테이션
이거면 다양한 컨트롤러에서 발생하는 중복된 에러를 처리할 수 있겠당! 
<img src="https://velog.velcdn.com/images/gari_guri/post/e6cb6a4c-2016-42a6-8f2e-8d8fb677b46b/image.png" alt="">
<img src="https://velog.velcdn.com/images/gari_guri/post/94dd3f2d-b201-4c03-b8e0-a1b2c76a2d72/image.png" alt="">
실행했더니 400번 오류가 뜨네 😭 뭐가 문제일까?</p>
</li>
<li><p>해결: @RestControllerAdvice을 사용 <code>@RestControllerAdvice</code>=<code>@ControllerAdvice</code>+<code>@ResponseBody</code>
(ResponseBody에노테이션은 반환을 뷰로 하지 않고, 데이터로 넘겨줄거야! 라는 의미)</p>
</li>
</ul>
<p>그런데 왜 아직도 200번 OK로 오는거지..?! 거슬린다💥
200번이 아니라 오류니깐 400이나 404 응답 코드를 보내줬으면 좋겠엉!
이때 사용하는 어노테이션이 <em><strong>@ResponseStatus</strong></em>!</p>
<pre><code class="language-java">@RestControllerAdvice
public class GlobalExceptionHandler { //모든 컨트롤러에 예외가 발생하면 낚아챌거야!!
    @ExceptionHandler(value = RoomNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public String catchRoomNotFoundException(RoomNotFoundException e){
        System.out.println(e.getClass());
        return &quot;No Room!!!&quot;;
    }
}</code></pre>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/0020dfa2-3251-4a39-80f8-2d4e7929357b/image.png" alt=""></p>
<p>🎉성공!!🎉</p>
<p>~~### 진짜 어디에서든 처리하면 된다고..?!</p>
<h3 id="controller에서-처리">controller에서 처리</h3>
<p>응답을 보내는 곳이 controller이기 때문에 에러처리+응답코드와 함께 보내는게 좋을듯
unchecked exception은 어차피 controller에서 처리하니깐 프론트엔드에게 돌려주기전에 한방에 모아서 처리하자</p>
<h3 id="예외가-터지는-곳에서-처리">예외가 터지는 곳에서 처리</h3>
<p>우회를 시켜주자 다른 방향을 제시해주자
~~</p>
<h2 id="로그-찍기-in-java">로그 찍기 in JAVA</h2>
<p><a href="https://www.slf4j.org/manual.html">slf4j 공식문서</a></p>
<ul>
<li><p>logger</p>
</li>
<li><p>log level: 로그에도 단계가 있는데 warning, error, 큰 에러, 정보 제공성 로그 등
시스템마다 로그의 목적이 다른 경우가 있음 따라서 레벨에 따라서 로그를 찍어줌
그런데 레벨을 설정하면 다른 레벨이 뜨지 않음</p>
<ul>
<li><p>Trace: 중요도가 매우 낮은 정보</p>
</li>
<li><p>Debug: 진행상황 체크(심각도, 중요도 낮은 정보)</p>
</li>
<li><p>info: 진행상황</p>
</li>
<li><p>warn: 잠재적으로 유해한 이벤트</p>
</li>
<li><p>error: 오류 이벤트(치명적인지 여부는 상관 없음)</p>
<h3 id="예시">예시</h3>
<pre><code class="language-java">@RestControllerAdvice
@Component
public class GlobalExceptionHandler { //모든 컨트롤러에 예외가 발생하면 낚아챌거야!!
private final org.slf4j.Logger logger=LoggerFactory.getLogger(GlobalExceptionHandler.class);

@ExceptionHandler(value = RoomNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public String catchRoomNotFoundException(RoomNotFoundException e){
  logger.error(&quot;exception class: {}&quot;, e.getClass());
//        System.out.println(e.getClass());
  return &quot;No Room!!!&quot;;
}
</code></pre>
</li>
</ul>
</li>
</ul>
<p>}</p>
<pre><code>
 ![](https://velog.velcdn.com/images/gari_guri/post/4afde22a-2e24-4a4d-8604-51cdf05726f4/image.png)


- 프로젝트 환경에서 로그 레벨 지정 가능
```java
resorces/application.properties
#log level setting
logging.level.root=warn (ex. 로그 레벨: warn로 지정)</code></pre><ul>
<li><p>서버 환경에서도 별도로 로그 레벨 지정 가능</p>
<ul>
<li>개발 서버: debug</li>
<li>운영 서버: info설정 권장</li>
</ul>
</li>
<li><p>이번에는 @slf4j인터페이스를 사용해서 로그를 찍어보자
<img src="https://velog.velcdn.com/images/gari_guri/post/72be2589-348b-4af2-88f6-2cf3b8c369d1/image.png" alt="">
엥 에러가 뜨네 왜 에러가 뜰까? 
<img src="https://velog.velcdn.com/images/gari_guri/post/abccd46b-6d73-405e-b470-9f7441b0d0a5/image.png" alt="">아하! annotatioProcessor를 추가안해줬구나! 
그럼 annotationProcessor의 역할은? 컴파일시점에서 annotation을 읽어주는 역할이구나!</p>
</li>
<li><p>결과
<img src="https://velog.velcdn.com/images/gari_guri/post/86c4af9b-583c-4341-8077-58c2d5a45ce6/image.png" alt=""></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[어디서 예외 처리를 하실 건가요?]]></title>
            <link>https://velog.io/@gari_guri/%EC%96%B4%EB%94%94%EC%84%9C-%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC%EB%A5%BC-%ED%95%98%EC%8B%A4-%EA%B1%B4%EA%B0%80%EC%9A%94</link>
            <guid>https://velog.io/@gari_guri/%EC%96%B4%EB%94%94%EC%84%9C-%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC%EB%A5%BC-%ED%95%98%EC%8B%A4-%EA%B1%B4%EA%B0%80%EC%9A%94</guid>
            <pubDate>Wed, 24 Jul 2024 07:31:10 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/gari_guri/post/3c912111-a4e3-4b70-9828-abbd4659964a/image.png" alt=""></p>
<blockquote>
<h3 id="예외처리를-어디서-하는게-좋을까">예외처리를 어디서 하는게 좋을까?</h3>
<p>나는 예외 처리를 예외가 발생한 메소드에서 <strong>바로바로 처리</strong>하는 것이 더 좋다고 생각한다. 
그 이유는...</p>
</blockquote>
<ul>
<li>예외 처리를 모아서 한번에 처리하는 로직은 발생한 에러들을 계속 가지고 있어야 하기 때문에 성능 저하와 메모리 사용의 문제 발생</li>
<li>반면, 에러가 발생한 클래스에서 바로 에러 처리를 하게 된다면, 에러를 놓치지 않고 꼼꼼히 처리 가능</li>
<li>또, 코드를 읽을 때 어떻게 에러를 처리했는지 바로 파악 가능하다는 점까지!
그 외의 장점들이 있겠지만, 개발자 입장에서 에러 처리 코드를 구현할 생각을 하니깐 중복된 로직이 많을 것 같다는 단점이.....있을 것 같네용..ㅎ</li>
</ul>
<h3 id="그럼-위-방법-외에-어떤-방법들이-있을까">그럼 위 방법 외에 어떤 방법들이 있을까?</h3>
<h2 id="에러처리-위치">에러처리 위치</h2>
<ol>
<li>로컬 (함수 내부) 예외 처리</li>
<li>중간 레벨 (모듈 또는 클래스 레벨) 예외 처리</li>
<li>글로벌 (전체 애플리케이션 레벨) 예외 처리</li>
</ol>
<p>이렇게 3가지 방법이 있고, 위에서 내가 언급한 방법은 1번에 속하는 거겠져,,?!</p>
<p>그럼 이 세가지 방법의 장단점에 대해 공부한 후, 나의 주장이 달라질 수도 있다는 생각이 막 드네용..!</p>
<h3 id="에러처리-1번-예시">에러처리 1번 예시</h3>
<pre><code class="language-java">public Room getRoom(int id) {
    RoomfoundRoom=roomTable.get(1d)://0W있지모르고쓸때예외가터짐
    try{
        if(foundRoom! =null)
            return roomTable.get(id);
        else
            throw new NoSuchElementException (&quot;No room!&quot;);
    }catch (NoSuchElementException e){
        return new Room;
    }
｝</code></pre>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/dc5f5ed9-c3d6-4217-b3f5-a81157d11b73/image.png" alt="">NO room! 메시지가 출력되었다.</p>
<h2 id="에러처리위치의-장단점">에러처리위치의 장단점</h2>
<h3 id="로컬-함수-내부-예외-처리">로컬 (함수 내부) 예외 처리</h3>
<ul>
<li>장점: 즉각적 처리, 세밀한 제어, 지역적 범위</li>
<li>단점: 중복 코드, 복잡성 증가<h3 id="중간-레벨-모듈-또는-클래스-레벨-예외-처리">중간 레벨 (모듈 또는 클래스 레벨) 예외 처리</h3>
</li>
<li>장점: 코드 재사용성, 모듈화</li>
<li>단점: 추적 어려움, 일관성 부족<h3 id="글로벌-전체-애플리케이션-레벨-예외-처리">글로벌 (전체 애플리케이션 레벨) 예외 처리</h3>
</li>
<li>장점: 중앙 관리, 일관된 처리, 로깅 및 모니터링</li>
<li>단점: 지연된 대응, 상세 정보 부족, 복잡한 제어 흐름</li>
</ul>
<blockquote>
<p>음....각 방법마다 장단점이 너무 뚜렷해서 프바프(프로젝트 바이 프로젝트) 상바상(상황바이상황)인것 같습니당</p>
</blockquote>
<p>.
.
.
그럼 다음 블로그에서 상황에 따라 어떻게 예외처리를 하는지 포스팅해볼게요!!
많관부😝
<a href="https://velog.io/@gari_guri/%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC-%EC%B5%9C%EC%A2%85%ED%8E%B8">다음 블로그</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[예외처리]]></title>
            <link>https://velog.io/@gari_guri/%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@gari_guri/%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Tue, 23 Jul 2024 07:41:07 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h3 id="예외란">예외란?</h3>
<p>예상된 결과 외의 다른 결과
원하는 것이 아니거나 의도치 않은 경우</p>
</blockquote>
<h3 id="💣-예외오류를-경험해보자">💣 예외(오류)를 경험해보자</h3>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/108f0b98-f314-4e2b-86cf-a8484db2b78f/image.png" alt=""></p>
<ul>
<li>위코드를 실행하면 nullpointerexception 오류가 발생한다..펑..!💣</li>
<li>오류가 발생한 이유는 뭐고, 어디서 터진걸까?
id을 통해 찾은 결과가 null인데 .getName()을 적용하였기 nullpointerexception 아무것도 존재하지 않는다는 의미의 에러를 발생한다. (cf. 참조 자료형이기 때문에 null** pointer** 에러가 생김)</li>
</ul>
<h3 id="발생한-에러처리는-어디에서-해야할까">발생한 에러처리는 어디에서 해야할까?</h3>
<p><em>첫번째</em> 궁금증. 호출을 당한 곳에서 에러처리를 해야해?
아니지! 호출을 한 곳에서 에러처리를 해야되지!! 그게 매너아니겠어?!</p>
<p>먼저, if else를 걸어서 에러 처리를 해보자!<img src="https://velog.velcdn.com/images/gari_guri/post/5157bb5c-33b5-4f77-9590-7d968070e7f1/image.png" alt=""></p>
<p>코드를 짜고보니깐 맘에 들지 않는 점ㅎ</p>
<ol>
<li>중복 코드가 너무 많으니깐 아래 코드로 일단 고치자!<img src="https://velog.velcdn.com/images/gari_guri/post/2fc2faa5-1ba1-4863-ab7b-a63a15922ff0/image.png" alt=""></li>
<li>null자체가 에러인데 이걸 반환해..? 좀 거슬리네!!
폭탄 돌리기하는 것도 아니구,, 이것도..내가 처리해야하는거 아닌가..?
그럼 null을 바로 반환하지말고 한겹 포장해서 보내자!</li>
</ol>
<p><del>⚠️주의할 점  한쪽에 몰려서 에러를 처리하는 것보다 적당량을 나눠서 처리하는 것이 좋음</del></p>
<h2 id="optional의-등장-️두둥️">Optional의 등장 ‼️두둥‼️</h2>
<ul>
<li>장점: 언제든 npe가 터지지 않게 null을 한겹 포장해서 보내자! 받는 즉시 NPE가 터지는 걸 막을 수 있고, 받는 애는 까기 전까지는 에러가 터지지 않게 하기 위해! -&gt; Optional class(java)<h4 id="쉽게-말하자면-optional-포장지같은-용도로-null인지-아닌지-확인할-수-있도록-껍데기를-싸는-것이다">쉽게 말하자면, Optional: 포장지같은 용도로 null인지 아닌지 확인할 수 있도록 껍데기를 싸는 것이다!</h4>
</li>
</ul>
<h3 id="optional-메소드">Optional 메소드</h3>
<ul>
<li>isPresent(): 안에 값이 있나 없나? </li>
<li>get(): 안에 있는 값을 꺼내는 것
=&gt; 이렇게 쓸거면,, 왜 return null 안쓰고 굳이 optional쓰지?</li>
</ul>
<p>[안에 값이 없을 때]</p>
<ul>
<li><p><em><strong>orElse</strong></em>(기존에 있는 객체): 안에 값이 없을때, 기존에 있던 객체를 대입</p>
</li>
<li><p><em><strong>orElseGet</strong></em>(새로운 객체를 생성해 달라고 요청하는 함수): 안에 값이 없을 때, 디폴트 값으로 새로운 객체를 대입(이거 가져가서 써~! )</p>
</li>
<li><p><em><strong>orElseThrow</strong></em>(새로운 객체를 생성해 달라고 요청하는 함수): 안에 값이 없을 때, <strong>예외</strong> 객체로 처리해줘~</p>
</li>
</ul>
<hr>
<p>⚠️주의⚠️</p>
<ul>
<li>get 사용금지
return null을 하기위해 존재하긴 하지만, null을 확인하고 넘어가는게 목적이기 때문에 지양하는 메소드이다. 대신 orElse throws orElse get을 쓰자!
<img src="https://velog.velcdn.com/images/gari_guri/post/bc31e8dc-4ca0-46d6-a2a1-2ca855908825/image.png" alt="">
<del>Supplier? 예외 클래스를 받아서 처리? 함수가 반환하는 값을 쓰고 싶은데 근데 그 함수를 한번만 쓸거야, 함수로 따로 빼기에는 굳이? 매개변수로 함수가 들어가고, 함수의 반환값을 받아주는 타입이 supplier
orElseGet 내가 예외 말고 객체를 만들어줘!
orElseThrow 야 없다 내가 만들어둔 예외 터트려!
lambda? 내가 원하는 Exception 예외 클래스를 발생시키기 위해 사용
: new 예외 클래스를 생성시키는 문법으로 lambda를 간추려서 보낸 것</del></li>
<li>ispresent 사용금지 <img src="https://velog.velcdn.com/images/gari_guri/post/787d6d4f-d245-49b0-9536-b07664fbd644/image.png" alt="">
우리가 짤 수 있는 코드를 Optional에게 전가한 것이기 때문</li>
<li><em><strong>여기서 퀴즈~!</strong></em> field에 Optional을 쓰지 않은 이유는?</li>
</ul>
<ol>
<li>직렬화가 되지 않음-&gt; 포장지를 어떻게 쌀거야...</li>
<li>null을 대체하는데 null이 보통 클래스에서 어디에 위치할까? 뭐할때 등장 ? 꺼낼때만 등장 
null을 타입으로 써본적은 없음 return null을 대체하거나 반환타입을 대체하려고 나온 것이기 때문에 field에서 사용하는 것은 고려하지 않았기 때문에 필드에서 사용하지 않음</li>
</ol>
<ul>
<li>map lambda string 문법을 잘 사용하지 않음 없어도 구현이 가능하기 때문!
return null을 할 일이 언제일까? 없는 값 조회할때 
아무것도 없네? null을 던졌다가는 객체를 줄 것이라고 생각할텐데 프로그램이 죽을텐데 <blockquote>
<p><strong>결국 Optional은 프로그램의 안정성을 위해서 사용됨</strong>
cf. 영속성: 영원히 지속하는 것 
jpa는 java persistant api 자바(객체)가 영원히 지속될 수 있도록 도와주는 api로 optional이 유명해진 이유이다!</p>
</blockquote>
</li>
</ul>
<h2 id="예외처리-방법">예외처리 방법</h2>
<ol>
<li>try catch (finally)<pre><code class="language-java">try{
 // 예외 발생할 일이 없는 로직 -1
 // **예외가 발생할 수도 있는 로직**
 // 예외 발생할 일이 없는 로직 -2: 예외 터지면 실행 X finally에 넣거나 밖에 두면 됨
}catch(예외 클래스 e객체){ //예외가 터진 로직이 발생한 예외객체를 매개변수에 넣어줌
 // 예외 처리
}</code></pre>
</li>
<li>throw: 개발자가 임의로 발생시키는 예외
= 자바 입장에서는 예외가 아님.
<img src="https://velog.velcdn.com/images/gari_guri/post/60912aa5-bbb2-4180-a655-369c2d55b884/image.png" alt="">
Null을 보내기 좀 그러니깐, null을 받을 수 있는 room을 상속받아서 NullRoom을 return하자!</li>
</ol>
<ol start="3">
<li>throws: 예외가 터졌는데 내가 터트린게 아냐! 나를 부른 상위메소드에게 예외를 던지는 것 = 예외에 대한 책임을 전가</li>
</ol>
<ul>
<li>unchecked: 런타임 시점 ex.NoSuchElementException
=&gt; 호출 흐름상 어딘가에서 catch해주면 됨!</li>
<li>checked: 컴파일 시점 ex.IOException
(아직 어떤 클래스끼리 호출하는지 &quot;흐름&quot; 모름 : A클래스와 B클래스연결(링킹)이 컴파일 이후 일어남 따라서 누가 처리를 해줄거라는 인지가 되지 않기 때문)
=&gt; throws를 쓰지 않으면, 컴파일 에러! </li>
</ul>
<p><strong>Repository</strong>
<img src="https://velog.velcdn.com/images/gari_guri/post/9de39f02-9a35-43aa-aebe-f36d3fc38f01/image.png" alt="">
<strong>Service</strong>
<img src="https://velog.velcdn.com/images/gari_guri/post/32d6f977-23f1-4259-9fd6-28b8e68feced/image.png" alt=""></p>
<p>try-catch안쓰고 throws쓰는 이유는 &quot;나 에러 발생시킨다!!&quot;를 명시적으로 보여주기 위해 </p>
<h2 id="예외-클래스">예외 클래스</h2>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/543c875a-c739-4bcf-a9b0-2afa1203d017/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/3ae4718d-884d-4514-af5d-f2f6722ec3ef/image.png" alt=""></p>
<p>위 표에서 잘못된 점⛔️
3번째줄: 자바예외 클래스에서는 roll-back을 해주지 않는다. (스프링은 가능)
JAVA 세상에서는 roll-back하지 않음, roll-back 함-&gt; roll-back을 해야 함으로 변경해야 한다.</p>
<h4 id="올바른-표-✅">올바른 표 ✅</h4>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/257d9b39-f223-446c-96a9-1f7a9f2b3c81/image.png" alt=""></p>
<h3 id="사용자-예외-클래스-생성하기">사용자 예외 클래스 생성하기</h3>
<ul>
<li>NoSuchElementException을 상속받아 사용자 예외 클래스를 생성한다.
<img src="https://velog.velcdn.com/images/gari_guri/post/07ebf657-5524-4154-bcdc-3936720469e2/image.png" alt=""></li>
<li>위는 자식(자신의) getMessage메소드를 사용하는 코드<img src="https://velog.velcdn.com/images/gari_guri/post/59eba0dd-0a1a-41bd-9c61-61717817172c/image.png" alt=""></li>
<li>위는 부모 getMessage메소드를 사용하는 코드
<img src="https://velog.velcdn.com/images/gari_guri/post/d2f7d8bf-072c-4b42-8a8d-d09ea04621ef/image.png" alt=""></li>
</ul>
<blockquote>
<h3 id="마무리-예외-클래스를-구체화하면-좋은-이유">마무리~ 예외 클래스를 구체화하면 좋은 이유</h3>
</blockquote>
<ul>
<li>에러를 잡기가 쉬워요!
= 추적하기가 쉽다.</li>
<li>어떤 에러인지 알 수 있어요!
= 의미를 가지게 할 수 있어요 
=&gt;<em>** 클래스명 구체화 가능**</em></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[HTTP status code]]></title>
            <link>https://velog.io/@gari_guri/HTTP-status-code</link>
            <guid>https://velog.io/@gari_guri/HTTP-status-code</guid>
            <pubDate>Tue, 23 Jul 2024 06:21:53 GMT</pubDate>
            <description><![CDATA[<h2 id="404-vs-405-vs-501">404 vs 405 vs 501</h2>
<ul>
<li>404 (Not Found) : 클라이언트가 요청한 자원이 존재하지 않음
못찾는거야~</li>
<li>405 (Method Not Allowed): 요청이 허용되지 않은 메소드임을 의미 서버에서 해당 요청 HTTP 메소드에 대해 기능을 제한/금지함
야 하지마! 금지야!</li>
<li>501 (Notimplemented): 요청에 대해 구현되지 않아 수행하지 아니함. 다만 앞으로 영원히 기능을 지원하지 않는다는 의미보다는 추후에 기능이 개발되면 지원한다는 의미가 더 크다.</li>
</ul>
<p>미안 내가 아직 구현 안했어...
예시) https/http로 맞추어 줘야함!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[객체 연관관계]]></title>
            <link>https://velog.io/@gari_guri/%EA%B0%9D%EC%B2%B4-%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84</link>
            <guid>https://velog.io/@gari_guri/%EA%B0%9D%EC%B2%B4-%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84</guid>
            <pubDate>Tue, 23 Jul 2024 02:24:57 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/gari_guri/post/91464694-6b07-4ca7-a978-c87c8b1a3f87/image.png" alt="">
호텔 -&gt; 방은 조회가능하지만, 방-&gt; 호텔은 조회하지 못함</p>
<p>업데이트 중..</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[M:N연관관계 👎]]></title>
            <link>https://velog.io/@gari_guri/MN%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84</link>
            <guid>https://velog.io/@gari_guri/MN%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84</guid>
            <pubDate>Tue, 23 Jul 2024 02:00:46 GMT</pubDate>
            <description><![CDATA[<h2 id="연관관계">연관관계</h2>
<h3 id="1대1">1대1</h3>
<ul>
<li>예시? 소개팅, 한 유저당 하나의 위시리스트, 신분증-사람, 회원-비밀번호</li>
</ul>
<h3 id="1대다">1대다</h3>
<ul>
<li>예시? 팬미팅, 지도교수님은 한 명-학생은 여러명, 사람-신용카드, 유저-리뷰
, 호텔-호텔방, 팀-학생, 하나의 가게-여러개의 리뷰</li>
</ul>
<blockquote>
<h4 id="❓-fk가-있는-팀이-1-없는-팀이-1">❓ fk가 있는 팀이 1? 없는 팀이 1?</h4>
<p>** 🅰️ 없는 팀이 <em>1</em>**
이유는❓
<img src="https://velog.velcdn.com/images/gari_guri/post/0fdead43-8efc-4df4-b29a-8b7ca7cc6ec2/image.png" width="60%">
위 테이블에서 호텔은 여러개의 방을 가질 수 있으므로 호텔: 1이고, 방:N이다. 
만약 호텔에 방에 대한 fk가 존재한다면 데이터가 중복되는 상황이 발생하기 때문!
방 테이블에 데이터가 추가된다면, 방 테이블의 fk에 호텔의 id가 저장됨</p>
</blockquote>
<h3 id="다대다">다대다</h3>
<ul>
<li>예시? 과팅, 수업-학생</li>
</ul>
<hr>
<h2 id="다대다-테이블-예시">다대다 테이블 예시</h2>
<p><em><strong>&lt;과목&gt;</strong></em>
JAVA-홍길동, 김구리
DB-김가리
<em><strong>&lt;학생&gt;</strong></em>
홍길동-JAVA
김가리-DB
김구리-JAVA</p>
<h3 id="초기-테이블-세팅">초기 테이블 세팅</h3>
<p>학생이 과목을 수강하는 거니깐 학생 테이블에 FK를 추가하자! 1️⃣테이블<img src="https://velog.velcdn.com/images/gari_guri/post/3f0cedfe-1d48-44b1-b0d9-d990215214c6/image.png" alt=""></p>
<p>오잉 ?! 그럼 같은 원리로 과목 테이블에 FK를 추가하는 것도 가능하잖아! 2️⃣테이블 <img src="https://velog.velcdn.com/images/gari_guri/post/a3a1b8f4-df00-4c87-8977-74f7d6dbc71a/image.png" alt=""></p>
<p>그럼 두 테이블에 모두 추가하자! 3️⃣테이블 <img src="https://velog.velcdn.com/images/gari_guri/post/d9ecd638-6b0e-467a-bae9-23b539a6d753/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/gari_guri/post/088673e4-453b-4606-8a88-6cfb0c7ca0fa/image.png" alt=""></p>
<h3 id="위-테이블들의-문제점은-뭘까">위 테이블들의 문제점은 뭘까?</h3>
<ul>
<li><p>😓  1️⃣번, 2️⃣번, 3️⃣번 테이블
만약 수강이 끝났다면,학생 테이블에서 학생을 아예 삭제할 수 없으니깐 학생/과목 테이블에서 fk를 제거해야한다. 하지만, fk를 삭제하기 위해서는 연관된 과목 테이블의 행을 삭제해야한다는 불편함이 존재한다!</p>
</li>
<li><p>😓 1️⃣번 테이블
특정 과목을 수강한 사람의 이름을 찾고 싶은 경우, 
보통 fk를 들고가서 pk를 찾지만, 위 테이블에서는 pk를 보고 fk를 찾는 상황이 발생할 수 있다..</p>
</li>
<li><p>과목 테이블을 조회하고, 학생 테이블을 조회해야 하므로 불필요한 조회가 발생한다!</p>
</li>
<li><p>😓 2️⃣번, 3️⃣번 테이블
여러 명이 한 과목을 수강할 경우, 과목 테이블에 리스트 형태로 컬럼에 넣어야 하고, 리스트 형태를 풀어서 테이블에 저장한다면 데이터 중복이 발생한다.</p>
</li>
</ul>
<hr>
<blockquote>
<h3 id="다시-말해서-mn을-쓰면-안되는-이유는">다시 말해서, M:N을 쓰면 안되는 이유는?</h3>
<ul>
<li>⭐️ 속성의 원자성을 위배 ⭐️: 하나의 컬럼에 리스트를 넣을 수 없음
(해결: RDB, noSQL사용 <em>cf) RDB를 왜쓰는지? 다른 테이블의 원하는 데이터를 가져올 수 있음 우리의 뇌가 관계형 데이터들을 찾을 수 있도록 설계되어 있기 때문!)</em></li>
<li>⭐️ 이중 조회 ⭐️: 특정 과목을 수강한 학생 조회 및 특정 학생이 듣는 과목을 조회할 때 불필요한 조회가 발생! </li>
<li>⭐️ 유지보수 및 확장성 저하 ⭐️: 데이터의 추가 및 변경이 일어날 시 데이터를 모두 수정해야 한다.</li>
<li>⭐️ 데이터 중복의 문제 ⭐️: pk의 중복이 발생하여 참조 무결성이 훼손된다.
<img src="https://velog.velcdn.com/images/gari_guri/post/e56156a7-3207-4ae7-b379-e801e549f7ce/image.png" alt=""></li>
</ul>
</blockquote>
<h2 id="해결책">해결책</h2>
<p>위와 같은 문제들을 어떻게 해결하면 좋을까?
두 테이블 사이에 예약 테이블을 새로 만들자!</p>
<p><strong>이상적인 테이블</strong><br><img src="https://velog.velcdn.com/images/gari_guri/post/e0374348-b228-481d-ae8f-e190c8cac85f/image.png" alt=""></p>
<h3 id="✅-수강-테이블을-따로-두어-테이블-수정-삭제-추가-시-발생하는-문제를-해결할-수-있음">✅ <em><strong>수강 테이블을 따로 두어 테이블 수정 삭제, 추가 시 발생하는 문제를 해결할 수 있음</strong></em></h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[DTO]]></title>
            <link>https://velog.io/@gari_guri/DTO</link>
            <guid>https://velog.io/@gari_guri/DTO</guid>
            <pubDate>Mon, 22 Jul 2024 00:29:36 GMT</pubDate>
            <description><![CDATA[<h2 id="rest-api-url-사용-규칙">&lt;Rest API url 사용 규칙&gt;</h2>
<ul>
<li><p>동사는 사용 지양 ⇒ 행동은 method로 나타낸다</p>
</li>
<li><p>복수, 단수 통일 ⇒ 프론트가 헷갈리니까!</p>
</li>
<li><p>_ 사용 금지 ⇒ 대신 하이픈(-) 사용</p>
</li>
<li><p>소문자 사용 ⇒ 의미를 알아보기 쉽게 하기 위해</p>
</li>
<li><p>마지막에 슬래시를 포함하지 않는다 ⇒ 후행 슬래시는 의미가 없다</p>
</li>
<li><p>URI 사이에 연관 관계를 있는 경우 /리소스/고유ID/관계있는리소스 순으로 작성 
ex) users/profile/{userId} (X) user/{userId}/profile (O)</p>
</li>
<li><p><strong>전세계적으로 &quot;규칙&quot; -&gt; 무조건 지켜야한다? NO!</strong></p>
<h2 id="✅-dto의-필요성을-느끼다">✅ DTO의 필요성을 느끼다..</h2>
<h3 id="회원-api-설계">회원 API 설계</h3>
</li>
<li><p>로그인</p>
<ul>
<li>id,pw 
req: id/pw 
res: name</li>
</ul>
</li>
<li><p>회원가입</p>
<ul>
<li>id, pw, name, email, address, contack
req: 필드 전부
res: id<blockquote>
<p> 회원가입과 로그인에서 주고받는 정보가 다른데,,, User라는 하나의 객체만 생성하는건 비효율적이야! 그럼 객체를 여러개 만들어야 할까..? 그럼 DB도 여러개를 만들어야 하나...?!? 🤯 어떡해야하지 -&gt;DTO가 해결: 객체를 변환(아직 코드 완성은 못함..to be continued..)</p>
</blockquote>
<h3 id="어떻게-객체를-변환할-것인가">어떻게 객체를 변환할 것인가?</h3>
</li>
</ul>
</li>
<li><p>어디서(클래스 위치)?</p>
</li>
<li><p>어떻게(방법)?</p>
<ul>
<li>생성자</li>
<li>빌더의 장점=생성자의 단점: 파라미터에 뭘 넣어야 할 지 모름</li>
<li>setter</li>
<li>copy product : 생성자, builder, setter</li>
<li>map contructor</li>
</ul>
</li>
<li><p>+객체 분리 기준/각 역할</p>
<h2 id="✅-dto가-왜-필요할까">✅ DTO가 왜 필요할까?</h2>
<p>하나의 객체, 데이터가 repository까지 들어갔을 때 장점? 단점?
단점: </p>
</li>
<li><p>클라이언트에게 굳이 ~ 전달되지 않아도 되는 데이터 포함
ex. 시스템 활용 데이터(생성/수정 일시) -&gt; 네트워크 비용만 올라가고, 보안 안 좋음 (hint. 극단적으로 생각해보기!)</p>
</li>
<li><p>클라이언트가 필요한 데이터 미포함
ex. 구현 코드 연관관계 X -&gt; 화면에는 같이 뿌려줘야 하는 경우
ex. 생년월일-&gt;나이</p>
</li>
</ul>
<p>1️⃣ <strong>예시1)</strong> req-&gt;dto안에 사용하는 필드만 넣어서 통채로 반환
서비스 코드를 바꾸지 않게 전달 가능
먼저, a 객체가 그대로 db로 들어감 처음 ui/ux에 맞춰져서 설계됨.
이후, 화면 단에 하나가 더 추가되었을 경우, 입력을 받았는데 db저장 용도가 아니 연산하려는 용도일 경우
(예를 들어, mbti, <del>저축, 자산, 대출, 부동산</del>와 같은 정보) 종합적으로 평가 db에 &quot;소비성향&quot;으로 저장해두는 경우)
즉, 당장 db에 저장할 것은 아닌데 화면 단의 내용이 바뀌는 경우</p>
<ul>
<li>일단은 시스템 안쪽까지 들고오는게 문제가 됨!</li>
<li>해결: 중간에 끊으면 앞까지만 변경하면 됨. 그 이후의 로직을 따로 가지고 가도록 중간에서 하나의 객체를 더 만들어 처리할 수 있도록 함!</li>
</ul>
<p>2️⃣ <strong>예시2)</strong> 스키마 이름 바꾸는 일
password-&gt; pwd 컬럼명을 바꾸었을 때 프론트엔드까지 바꿔야하는 상황 발생.
중간에 끊어서 프론트엔드에서는 여전히 같은 컬럼명 사용 가능하고, 중간에 전환 로직을 추가하는 것이 좋음!</p>
<blockquote>
<h3 id="결론">결론</h3>
<p>** 아래의 예시에서 단일 책임의 원칙이 깨지지 않게 하기 위해 DTO가 필요하다!**
단일 책임 원칙: 수정은 _<strong>하나의 actor</strong>_만 존재해야 함!</p>
</blockquote>
<p>1) client 무슨 일 생겼을 때 -&gt; DB까지 
db에 그대로 저장될 데이터는 아님 필드를 추가해도 되니?
2) DB에 무슨 일 생겼을 때 -&gt; client가 알아야 해?
(DB 컬럼 이름이 바뀌면, 클라이언트 호출도 바껴야 함?)
➡️ 데이터를 옮기는 객체가 하나일 경우 여러 계층에서 그 객체에 수정을 가하면 단일 책임 원칙이 바로 깨진다!</p>
<h2 id="정리해서dtodata-transfer-object-특징은">정리해서..DTO(Data Transfer Object) 특징은?</h2>
<ul>
<li><p>데이터 전송용 객체 = 엔티티(Entity)의 사본</p>
</li>
<li><p>setter: 되도록이면 사용하지 말자!
setter 사용시 언제든 누구나 값을 변경할 수 있어 DB의 사용이유인 &#39;무결성&#39;을 위반하기때문!</p>
<ul>
<li>DB -&gt; (Object: setter 포함)-&gt;Client</li>
<li>DB 쓰는 이유? 보안, 무결성 </li>
</ul>
</li>
<li><p>Q. setter를 DTO가 절대 가지면 안될까요?
NOPE! 절대는 NOPE!
그럼 언제써야할까? update할 때 사용가능!!</p>
</li>
</ul>
<h2 id="entity이자-domain-object인-친구">Entity(이자 Domain Object인 친구)</h2>
<ul>
<li>데이터 원본 from DB</li>
<li><strong>DB로 들어갈/연산이 끝난 (=원본이 될 ) 객체</strong>
<img src="https://velog.velcdn.com/images/gari_guri/post/c3b01837-da76-499c-8271-e502fbeef047/image.png" alt="">*<em>강형욱: DTO, 박완규: Entity *</em></li>
</ul>
<p><del>- JPA &gt; jdbc Entity..? 왜...?</del></p>
<h2 id="✅-그렇다면-dto---entity-어디서-바뀌는-걸까">✅ 그렇다면 DTO &lt;-&gt; Entity 어디서 바뀌는 걸까?</h2>
<ul>
<li>원본 이름 : 엔터티</li>
<li>전송일때 DTO</li>
<li>Client-&gt;Controller-&gt;Service-&gt;Repository-&gt;DB</li>
<li>DB-&gt;Repository-&gt;Service-&gt;Controller-&gt;Client
<img src="https://velog.velcdn.com/images/gari_guri/post/37166f2c-c5fc-43dc-bffc-0ee627a8e690/image.png" alt=""></li>
<li>입장1: <strong>controller에서 변환되는거야!</strong>
: request, response를 받는 역할인데 연산을 왜해?
서비스에서 dto로 바꾼다는 건 클라이언트꺼까지 고민해야한다는 건데 왜     service에서 클라이언트를 굳이 고민해야해?</li>
<li>입장2: <strong>service에서 변환되는 거야!</strong>
:DTO와 Entity를 변환하는 것은 연산이므로 이는 Service의 책임이라고 생각해! </li>
<li>입장3: <strong>repository에서 변환되는 거야!</strong>
: 이동할때 dto사용하는거라며!! 그럼 repository로 부터 나온 결과를 service에 전달할때도 필요하잖아~!</li>
</ul>
<h3 id="controller-service-repository-모두-다-가능">controller, service, repository 모두 다 가능!</h3>
<blockquote>
<h3 id="🌟-미리보기">🌟 미리보기</h3>
</blockquote>
<ul>
<li>A service-&gt;B Service ❌: 의존성 존재, 서로가 없으면 못 돌아간다는 것! 잘못된 설계!</li>
<li>A controller-&gt; B Service 🅾️</li>
<li>A Service-&gt; B repository 🅾️</li>
<li>A controller -&gt; B controller ❌
<em>** 같은 계층끼리 사용하는 것: 서로 의존하는 것
다른 계층끼리 사용하는 것: 독립/모듈화가 잘 되어있는 것**</em></li>
</ul>
]]></description>
        </item>
    </channel>
</rss>