<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>코딩성장스토리</title>
    <link>https://aimk12.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sat, 11 Apr 2026 14:12:27 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>까르르꿍꿍</managingEditor>
    <item>
      <title>코드 리뷰 회고 (클린 코드, DB 모델링, 공통코드 or Enum)</title>
      <link>https://aimk12.tistory.com/157</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;여태껏 동아리 프로젝트들을 하면서 클린코드에 대해 잘 모르고 막 코드를 작성했었다는 걸 깨닫게 되었습니다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인턴 생활을 진행하면서 시니어 개발자분이 코드리뷰를 해주시면서 배운 것들을 정리해보려 합니다 &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt;1. API 문서화&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SwaggerUI 를 통해 API 규격이 잘 드러나도록 하면 좋음
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;FE 개발자와의 커뮤니케이션 비용을 낮출 수 있음&lt;/li&gt;
&lt;li&gt;규격이 명확하면, FE 를 위한 DTO 자동생성도 가능함&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Swagger 어노테이션을 통해 설명을 많이 달아준다.&lt;/li&gt;
&lt;li&gt;DTO 는 Request, Response 를 명료하게 분리하기.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스 수가 많아지더라도 파라미터가 다름을 FE 에게 인지시키는게 나을수도 있다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;필요한 경우 액션이름 포함하여 DTO 생성하기
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex) 사용자 설정정보 수정요청: UserSettingInfoRequest --&amp;gt; UserSettingUpdateRequest&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt;2. 컴파일후 가장 깨끗한 상태 유지&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Warning 을 모두 없애기&lt;/li&gt;
&lt;li&gt;코드상 잘못된 부분을 찾을때, Error/Warning 은 혼동을 유발한다&lt;/li&gt;
&lt;li&gt;또한, 잠재적인 오류를 포함할 수 있다.&lt;/li&gt;
&lt;li&gt;개발프로세스가 엄격한 경우, 정적분석도구(컴파일된 코드의 문제점 분석)를 이용하여 코드개선을 해야할 수 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;sonarcube 등의 툴을 이용하여 분석&lt;/li&gt;
&lt;li&gt;테스트 단계에서 코드가 안전한지 확인하고, 개선되어야만 통과된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt;3. naming convention 은 명료한 명칭사용하기&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Info 같은 명칭은 추상적으로 모든 정보를 포함할 수 있다.
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;정보에도 종류가 다양함&lt;/li&gt;
&lt;li&gt;Info 에서 특정 정보를 분리하여 Entity 로 만들기 원한다면? -&amp;gt; 구체적인 정보의 명칭표기로 변경&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt;4. 유효성체크 로직 추가&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장 앞단의 Request,Response 에 validation 로직을 추가하여 400 에러 응답&lt;/li&gt;
&lt;li&gt;FE 개발자가 어떤게 잘못된 요청인지 인지할수 있도록 알려야 개발단계 커뮤니케이션 비용이 줄어듦&lt;/li&gt;
&lt;li&gt;또한, 잘못된 값의 유입을 막을수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. &lt;span data-token-index=&quot;0&quot;&gt;class vs record ?&lt;/span&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span data-token-index=&quot;0&quot;&gt;&amp;nbsp; record&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp; &lt;span style=&quot;color: #006dd7;&quot;&gt;장점&amp;nbsp;&lt;/span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;필드 값 변질의 우려가 없음&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/li&gt;
&lt;li&gt;대부분의 보일러 플레이트 코드가 사라짐&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #ee2323;&quot;&gt;단점&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;필드 값 수정 불가&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/li&gt;
&lt;li&gt;상속 불가 (final 클래스)&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/li&gt;
&lt;li&gt;abstract 선언 불가 (final 클래스)&lt;/li&gt;
&lt;li&gt;static이 아닌 멤버 변수 선언 불가&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. DB 모델링 어떤게 나을지&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자연키 와 인조키로 DB모델링을 했을 떄 생기는 차이에 대해 알아보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘은 인조키로 만드는게 추세라고 합니다. 그 이유는 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;자연키 값이 바뀌는 상황이 온다면 시스템 전체적으로 문제&lt;/span&gt;&lt;/b&gt;가 생기기 때문입니다.&amp;nbsp;&lt;/p&gt;
&lt;table id=&quot;303b1e4e-3b39-4728-9549-fa80f351fec3&quot; style=&quot;border-collapse: collapse; width: 100%; height: 317px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 19px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 54.0699%; height: 19px;&quot;&gt;자연키&lt;/td&gt;
&lt;td style=&quot;width: 32.093%; height: 19px;&quot;&gt;인조키&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;89f99005-a590-41a5-be1a-3b334f23eb06&quot; style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 19px;&quot;&gt;의미&lt;/td&gt;
&lt;td id=&quot;ko{x&quot; style=&quot;width: 54.0699%; height: 19px;&quot;&gt;실세계에서 Entity 를 유일하게 식별하는 키&lt;/td&gt;
&lt;td id=&quot;D~hd&quot; style=&quot;width: 32.093%; height: 19px;&quot;&gt;인위적으로 부여되는 키&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;5576c8c4-fdcb-437b-9320-3c377c156688&quot; style=&quot;height: 51px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 51px;&quot;&gt;실세계와의 관계&lt;/td&gt;
&lt;td id=&quot;ko{x&quot; style=&quot;width: 54.0699%; height: 51px;&quot;&gt;실세계의 값을 그대로 사용&lt;/td&gt;
&lt;td id=&quot;D~hd&quot; style=&quot;width: 32.093%; height: 51px;&quot;&gt;무관&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;4e792ece-d38d-4b29-94b5-8fb1f09e120e&quot; style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 19px;&quot;&gt;생성주체&lt;/td&gt;
&lt;td id=&quot;ko{x&quot; style=&quot;width: 54.0699%; height: 19px;&quot;&gt;사용자로부터 입력받음&lt;/td&gt;
&lt;td id=&quot;D~hd&quot; style=&quot;width: 32.093%; height: 19px;&quot;&gt;어플리케이션이 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;959eed38-ecd2-405e-9e38-c74374812e1c&quot; style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 19px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;예제&lt;/span&gt;&lt;/td&gt;
&lt;td id=&quot;ko{x&quot; style=&quot;width: 54.0699%; height: 19px;&quot;&gt;주민번호, 차량번호판&lt;/td&gt;
&lt;td id=&quot;D~hd&quot; style=&quot;width: 32.093%; height: 19px;&quot;&gt;auto-increment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;7d8a167c-079f-47fa-b936-0ad1d2cc081b&quot; style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 19px;&quot;&gt;전달&lt;/td&gt;
&lt;td id=&quot;ko{x&quot; style=&quot;width: 54.0699%; height: 19px;&quot;&gt;쉽게 이해됨 (실시계값 그대로 이용)&lt;/td&gt;
&lt;td id=&quot;D~hd&quot; style=&quot;width: 32.093%; height: 19px;&quot;&gt;한번 이상 거쳐야 이해가 됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;8a282a98-e00e-4a14-84e0-a5f2b88ddb6d&quot; style=&quot;height: 38px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 38px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;변경 가능성&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td id=&quot;ko{x&quot; style=&quot;width: 54.0699%; height: 38px;&quot;&gt;변경가능성이 있는 경우 부적절한 선택&lt;br /&gt;전화번호가 대표적인 비판예시.사용자의 핸드폰번호는 바뀔수 있다. 어떻게 대처할 것인가?&lt;/td&gt;
&lt;td id=&quot;D~hd&quot; style=&quot;width: 32.093%; height: 38px;&quot;&gt;실세계값과 연관이 없으므로 변경에서 안전&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;e652149a-d92a-4855-b699-1fc713af8b3c&quot; style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 19px;&quot;&gt;복합키 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;발생&lt;/span&gt;&lt;/td&gt;
&lt;td id=&quot;ko{x&quot; style=&quot;width: 54.0699%; height: 19px;&quot;&gt;발생가능&lt;/td&gt;
&lt;td id=&quot;D~hd&quot; style=&quot;width: 32.093%; height: 19px;&quot;&gt;필요없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;0eac86dd-c123-4b15-98d3-129c13868420&quot; style=&quot;height: 57px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 57px;&quot;&gt;보안&lt;/td&gt;
&lt;td id=&quot;ko{x&quot; style=&quot;width: 54.0699%; height: 57px;&quot;&gt;보안을 필요로 한다면, PK 로 부적합&lt;br /&gt;여러군데 값을 저장하여 암호화변경 등에 대처가 어렵다.&lt;/td&gt;
&lt;td id=&quot;D~hd&quot; style=&quot;width: 32.093%; height: 57px;&quot;&gt;의미없는 값이므로 무관&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;1eb72a46-594f-4dbc-9202-9dd8dafde341&quot; style=&quot;height: 38px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 38px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;비지니스 변경대처&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td id=&quot;ko{x&quot; style=&quot;width: 54.0699%; height: 38px;&quot;&gt;변경가능성을 완벽하게 예측할 수 없다.&lt;br /&gt;비지니스변경으로 인해 변경가능성이 발생하고 이로인해 유일성이 훼손될 수 있다.&lt;/td&gt;
&lt;td id=&quot;D~hd&quot; style=&quot;width: 32.093%; height: 38px;&quot;&gt;비지니스 즉, 실세계의 값과는 무관하게 유일성을 보장한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;e94d758a-1bad-4f7a-b1cc-6c380ca66363&quot; style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 19px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;쿼리 복잡성&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td id=&quot;ko{x&quot; style=&quot;width: 54.0699%; height: 19px;&quot;&gt;Join 발생빈도가 보다 낮음.&lt;/td&gt;
&lt;td id=&quot;D~hd&quot; style=&quot;width: 32.093%; height: 19px;&quot;&gt;간단한 조회문에도 Join 이 발생할 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;7. 공통코드 vs Enum&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 옛날에는 공통코드로 관리하는 프로젝트가 많았다고 합니다. 그 이유는 외부 사용자가 관리페이지 같은 것을 이용해 관리하기 편하게 사용하기 위함입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Enum은 코드를 봐야 알 수 있기 때문입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 요새 &lt;b&gt;개발자가 직접 운영 관리를 하고 CI/CD가 구축되어 가면서 Enum&lt;/b&gt;으로 코드를 관리하는 것이 추세가 되어 가고 있습니다.&lt;/p&gt;
&lt;table id=&quot;89420e9d-3ada-4e02-b1b5-1e90ffe2fe44&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 17.4418%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 47.2094%;&quot;&gt;공통코드&lt;/td&gt;
&lt;td style=&quot;width: 35.2326%;&quot;&gt;Enum&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;692fa5b8-cbfc-4316-a292-2af41bf13347&quot;&gt;
&lt;td style=&quot;width: 17.4418%;&quot;&gt;처리방식&lt;/td&gt;
&lt;td id=&quot;pqJh&quot; style=&quot;width: 47.2094%;&quot;&gt;&quot;&lt;b&gt;코드를 관리하는 테이블을 하나&lt;/b&gt;&quot;만 만들고, 어플리케이션 전반에 사용&lt;/td&gt;
&lt;td id=&quot;e_;n&quot; style=&quot;width: 35.2326%;&quot;&gt;코드를 &quot;&lt;b&gt;어플리케이션 로직&lt;/b&gt;&quot;에 관리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;655bfc61-93a5-4efc-b44d-c367e42e5b18&quot;&gt;
&lt;td style=&quot;width: 17.4418%;&quot;&gt;타입&amp;nbsp;세이프&lt;/td&gt;
&lt;td id=&quot;pqJh&quot; style=&quot;width: 47.2094%;&quot;&gt;별도의 체크로직이 필요함&lt;/td&gt;
&lt;td id=&quot;e_;n&quot; style=&quot;width: 35.2326%;&quot;&gt;보장됨.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;142c4980-c0c7-40c9-8431-f8cecc60145a&quot;&gt;
&lt;td style=&quot;width: 17.4418%;&quot;&gt;코드별 Customizing&lt;/td&gt;
&lt;td id=&quot;pqJh&quot; style=&quot;width: 47.2094%;&quot;&gt;코드 특성에 맞는 속성을 정의하거나, 메서드를 넣기 어려움&lt;br /&gt;개별 특성까지 맞추려면 초기설계단계에서 많은 노력이 필요함&lt;/td&gt;
&lt;td id=&quot;e_;n&quot; style=&quot;width: 35.2326%;&quot;&gt;Enum 고유의 기능을 활용하여 개별특성을 반영할 수 있음&lt;br /&gt;어플리케이션에서 서비스, 유틸 클래스의 혼용을 줄여줌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;faa3ccd8-d1f8-45a3-836c-1b385c740f1f&quot;&gt;
&lt;td style=&quot;width: 17.4418%;&quot;&gt;변경 가능성대처&lt;/td&gt;
&lt;td id=&quot;pqJh&quot; style=&quot;width: 47.2094%;&quot;&gt;DB 에서만 변경&lt;br /&gt;데이터변경이 아닌 속성이나 기능의 변경엔 취약함&lt;/td&gt;
&lt;td id=&quot;e_;n&quot; style=&quot;width: 35.2326%;&quot;&gt;어플리케이션을 변경하고 재구동하는 절차가 필요함&lt;br /&gt;속성과 기능변경엔 유연함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;a97d9684-820a-4f22-b2a3-23e70b332c3b&quot;&gt;
&lt;td style=&quot;width: 17.4418%;&quot;&gt;성능&lt;/td&gt;
&lt;td id=&quot;pqJh&quot; style=&quot;width: 47.2094%;&quot;&gt;Join 을 이용하면 성능저하&lt;br /&gt;보완책으로 캐시를 이용할수는 있음&lt;/td&gt;
&lt;td id=&quot;e_;n&quot; style=&quot;width: 35.2326%;&quot;&gt;DB 로직과 무관하게 코드값을 관리하므로 성능 영향없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;2112ca28-dbae-49cc-b14b-2b3d593d2b05&quot;&gt;
&lt;td style=&quot;width: 17.4418%;&quot;&gt;어플리케이션 의존도&lt;/td&gt;
&lt;td id=&quot;pqJh&quot; style=&quot;width: 47.2094%;&quot;&gt;DB 의존&lt;/td&gt;
&lt;td id=&quot;e_;n&quot; style=&quot;width: 35.2326%;&quot;&gt;철저히 어플리케이션 의존&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 링크 : &lt;a href=&quot;https://techblog.woowahan.com/2527/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://techblog.woowahan.com/2527/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1718363203132&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Java Enum 활용기 | 우아한형제들 기술블로그&quot; data-og-description=&quot;안녕하세요? 우아한 형제들에서 결제/정산 시스템을 개발하고 있는 이동욱입니다. 이번 사내 블로그 포스팅 주제로 저는 Java Enum 활용 경험을 선택하였습니다. 이전에 개인 블로그에 Enum에 관해 &quot; data-og-host=&quot;techblog.woowahan.com&quot; data-og-source-url=&quot;https://techblog.woowahan.com/2527/&quot; data-og-url=&quot;https://techblog.woowahan.com/2527/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bxjucJ/hyWk90CMUT/1oeRxjpAtkAJsw0vuqDti1/img.jpg?width=1640&amp;amp;height=856&amp;amp;face=0_0_1640_856,https://scrap.kakaocdn.net/dn/cvjsMe/hyWlhRS4Kx/SgBbl3bP4Wgxrrp682PXB0/img.jpg?width=1640&amp;amp;height=856&amp;amp;face=0_0_1640_856,https://scrap.kakaocdn.net/dn/I6k4R/hyWlkHSX9N/Tx9IRLtVy4uu1nWjb2xYKK/img.png?width=521&amp;amp;height=456&amp;amp;face=0_0_521_456&quot;&gt;&lt;a href=&quot;https://techblog.woowahan.com/2527/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://techblog.woowahan.com/2527/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bxjucJ/hyWk90CMUT/1oeRxjpAtkAJsw0vuqDti1/img.jpg?width=1640&amp;amp;height=856&amp;amp;face=0_0_1640_856,https://scrap.kakaocdn.net/dn/cvjsMe/hyWlhRS4Kx/SgBbl3bP4Wgxrrp682PXB0/img.jpg?width=1640&amp;amp;height=856&amp;amp;face=0_0_1640_856,https://scrap.kakaocdn.net/dn/I6k4R/hyWlkHSX9N/Tx9IRLtVy4uu1nWjb2xYKK/img.png?width=521&amp;amp;height=456&amp;amp;face=0_0_521_456');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Java Enum 활용기 | 우아한형제들 기술블로그&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요? 우아한 형제들에서 결제/정산 시스템을 개발하고 있는 이동욱입니다. 이번 사내 블로그 포스팅 주제로 저는 Java Enum 활용 경험을 선택하였습니다. 이전에 개인 블로그에 Enum에 관해&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;techblog.woowahan.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>기타</category>
      <category>DB모델링</category>
      <category>enum</category>
      <category>공통코드</category>
      <category>인조키</category>
      <category>자연키</category>
      <category>코드 리뷰</category>
      <category>클린코드</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/157</guid>
      <comments>https://aimk12.tistory.com/157#entry157comment</comments>
      <pubDate>Fri, 14 Jun 2024 20:11:57 +0900</pubDate>
    </item>
    <item>
      <title>MSA 추상적인 개념 잡아가기</title>
      <link>https://aimk12.tistory.com/156</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;마이크로서비스 아키텍쳐 (MicroService Architecture , MSA)&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;각각을 마이크로하게 나눈&amp;nbsp;독립적인 서비스를 연결한 구조&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2420&quot; data-origin-height=&quot;1260&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byaciE/btsHGcXMEga/dWKMJ1kvKfXU6deDUkLAMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byaciE/btsHGcXMEga/dWKMJ1kvKfXU6deDUkLAMK/img.png&quot; data-alt=&quot;마이크로 서비스와 모놀리식 비교&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byaciE/btsHGcXMEga/dWKMJ1kvKfXU6deDUkLAMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyaciE%2FbtsHGcXMEga%2FdWKMJ1kvKfXU6deDUkLAMK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2420&quot; height=&quot;1260&quot; data-origin-width=&quot;2420&quot; data-origin-height=&quot;1260&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;마이크로 서비스와 모놀리식 비교&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MSA의 장점&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;변경된 서비스만 빌드,배포하면 되므로 배포시간이 단축 됩니다.&lt;/li&gt;
&lt;li&gt;일부 서비스의 오류가 다른 서비스에 영향을 안끼치므로 다른 서비스는 사용이 가능합니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;다른 서비스와 독립적으로 확장(scale-out) 가능 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MSA의 단점&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;마이크로서비스에 대한 내부 경험 부족&lt;/li&gt;
&lt;li&gt;복잡성이 늘어남 ( 다른 서비스와 함꼐 트랜잭션 관리)&lt;/li&gt;
&lt;li&gt;구축에 소요되는 기간 및 비용에 대한 불확실성&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에 까지는 그냥 잠깐 공부하면 아는 내용이었습니다. 개념적으로는 이해가 안되고 제가 받아들이기 힘든 부분이 몇가지 있었습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;각 서비스 DB에&lt;span style=&quot;color: #ee2323;&quot;&gt; 연관되어 있는 데이터&lt;/span&gt; 처리 (조인쿼리)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;트랜잭션 관리&lt;/span&gt;는 어떻게 하는지&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;각 서비스 간의 &lt;span style=&quot;color: #ee2323;&quot;&gt;통신 과정&lt;/span&gt;을 어떻게 하는지&amp;nbsp;&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이제 위에 대한 궁금증을 해결해준 글들을 정리해보겠습니다. (다른 글들 참고를 많이 했습니다... 이미 좋은 글이 많기에)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;아래에 들어가기 전에 아래 글 시리즈 정독하면 추상화 개념을 좀 구체화시킬수 있을 것 같습니다. (Spring 기반 MSA)&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://sjh9708.tistory.com/120&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://sjh9708.tistory.com/120&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1716879429766&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Spring Cloud] Microservice(MSA) 구축 : (2) Eureka Server와 Gateway, Microservice 서버들의 연결&quot; data-og-description=&quot;이전 포스팅에서 MSA 아키텍쳐의 구조와 Spring Cloud에 대한 소개를 하였었다. 이번 포스팅에서는 이전에 소개했던 아키텍쳐의 구성 요소들인 Gateway, Naming Server, MSA Service들을 만들어보고 연동하는 &quot; data-og-host=&quot;sjh9708.tistory.com&quot; data-og-source-url=&quot;https://sjh9708.tistory.com/120&quot; data-og-url=&quot;https://sjh9708.tistory.com/120&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bNP3qr/hyWdoio359/dC78NEKwRliCfT2CfEBVUK/img.png?width=410&amp;amp;height=356&amp;amp;face=0_0_410_356,https://scrap.kakaocdn.net/dn/ckebZA/hyWdkG3UB2/NpCToxyGbcc6BHARN2wbU0/img.png?width=410&amp;amp;height=356&amp;amp;face=0_0_410_356,https://scrap.kakaocdn.net/dn/QVHiK/hyWdfFKzvE/NJZY4QzgZ6Vwr96JkZKUx1/img.png?width=1054&amp;amp;height=1256&amp;amp;face=0_0_1054_1256&quot;&gt;&lt;a href=&quot;https://sjh9708.tistory.com/120&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sjh9708.tistory.com/120&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bNP3qr/hyWdoio359/dC78NEKwRliCfT2CfEBVUK/img.png?width=410&amp;amp;height=356&amp;amp;face=0_0_410_356,https://scrap.kakaocdn.net/dn/ckebZA/hyWdkG3UB2/NpCToxyGbcc6BHARN2wbU0/img.png?width=410&amp;amp;height=356&amp;amp;face=0_0_410_356,https://scrap.kakaocdn.net/dn/QVHiK/hyWdfFKzvE/NJZY4QzgZ6Vwr96JkZKUx1/img.png?width=1054&amp;amp;height=1256&amp;amp;face=0_0_1054_1256');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Spring Cloud] Microservice(MSA) 구축 : (2) Eureka Server와 Gateway, Microservice 서버들의 연결&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이전 포스팅에서 MSA 아키텍쳐의 구조와 Spring Cloud에 대한 소개를 하였었다. 이번 포스팅에서는 이전에 소개했던 아키텍쳐의 구성 요소들인 Gateway, Naming Server, MSA Service들을 만들어보고 연동하는&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;sjh9708.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 각 서비스 DB에 연관되어 있는 데이터 처리(조인쿼리)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;연관 데이터 처리를 위한 두가지 패턴&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p id=&quot;api-aggregation-pattern&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. API Aggregation Pattern&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API Aggregation Pattern은 여러 서비스로부터 정보를 모아서 하나의 응답으로 제공하는 패턴이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트는 여러 서비스로부터 데이터를 요청하는 대신 한 번의 요청으로 필요한 모든 데이터를 얻을 수 있다.&lt;/li&gt;
&lt;li&gt;클라이언트의 로직이 단순해진다. 서비스 간의 상호작용이 API 게이트웨이 내에서 수행되기 때문이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프론트는 어차피 API 게이트웨이를 통해서 받기에 프론트가 고민해야할 문제는 아니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;각각의 마이크로서비스는 독립적으로 진화하며, API 게이트웨이만 적절히 업데이트하면 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;단점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;API 게이트웨이가 병목 지점이 될 수 있습니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MSA에 모든 트래픽이 API 게이트웨이를 지나기에 여러 서비스에 대한 요청을 하면 네트워크 지연이 있을 가능성이 높다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;여러 서비스의 응답을 모아 처리하는 로직이 복잡해질 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;cqrscommand-query-responsibility-segregation-pattern&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. CQRS(Command Query Responsibility Segregation)&lt;span&gt;&amp;nbsp;&lt;/span&gt;Pattern&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;CQRS는 시스템의 명령(Command) 부분과 조회(Query) 부분을 명확히 분리하는 패턴이다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;MSA 환경에서 도메인 복잡성을 관리하고 확장성을 향상시키기 위해 사용된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;명령과 조회를 분리함으로써 각각의 부분을 독립적으로 확장할 수 있다&lt;/li&gt;
&lt;li&gt;읽기와 쓰기 모델을 분리함으로써 각 모델에 최적화된 성능 튜닝이 가능한다.&lt;/li&gt;
&lt;li&gt;읽기 전용 모델을 따로 설계할 수 있기 때문에, 조회 성능과 구조를 최적화할 수 있다.&lt;/li&gt;
&lt;li&gt;CQRS는 이벤트 소싱과 잘 결합됩니다. 이로 인해 시스템의 상태 변경 내역을 추적하고 재생할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;단점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전통적인 CRUD 패턴보다 구현이 복잡해질 수 있다.&lt;/li&gt;
&lt;li&gt;명령과 조회 모델을 동기화하는 것이 도전적일 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;구체화한 참고 링크&lt;/b&gt;&amp;nbsp; -&amp;gt; 이미 구현해주시고 좋은 글인거 같아 읽어보면 좋을 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@devty/MSA-Phase-8.-CQRS&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@devty/MSA-Phase-8.-CQRS&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1716878488941&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;MSA Phase 8. CQRS&quot; data-og-description=&quot;MSA의 태생적인 한계모든 서비스는 각 프로덕트로서 도메인을 책임진다.서비스/도메인 간 협럽과 디펜던시가 지양된다.또한 각 서비스의 DB는 각 서비스를 통해서 접근해야한다. (데이터 오너쉽)&quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@devty/MSA-Phase-8.-CQRS&quot; data-og-url=&quot;https://velog.io/@devty/MSA-Phase-8.-CQRS&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/u72aV/hyV9ZxP5w0/LkzLQxKTbx87jIu9mK1ihk/img.png?width=2000&amp;amp;height=1121&amp;amp;face=0_0_2000_1121,https://scrap.kakaocdn.net/dn/o22Q7/hyWdfFKr4R/tkeq4lRBMAXSLg8MP17Mq0/img.jpg?width=800&amp;amp;height=860&amp;amp;face=0_0_800_860&quot;&gt;&lt;a href=&quot;https://velog.io/@devty/MSA-Phase-8.-CQRS&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@devty/MSA-Phase-8.-CQRS&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/u72aV/hyV9ZxP5w0/LkzLQxKTbx87jIu9mK1ihk/img.png?width=2000&amp;amp;height=1121&amp;amp;face=0_0_2000_1121,https://scrap.kakaocdn.net/dn/o22Q7/hyWdfFKr4R/tkeq4lRBMAXSLg8MP17Mq0/img.jpg?width=800&amp;amp;height=860&amp;amp;face=0_0_800_860');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;MSA Phase 8. CQRS&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;MSA의 태생적인 한계모든 서비스는 각 프로덕트로서 도메인을 책임진다.서비스/도메인 간 협럽과 디펜던시가 지양된다.또한 각 서비스의 DB는 각 서비스를 통해서 접근해야한다. (데이터 오너쉽)&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;velog.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 트랜잭션 관리는 어떻게 하는지&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;트랜잭션 관리를 위한 두가지 패턴&amp;nbsp;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;a style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;1. Two-Phase Commit&lt;/span&gt;&lt;/b&gt;&lt;/a&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;분산 트랜잭션을 구현하는 데 널리 사용되는 패턴이며, Prepare 단계와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a style=&quot;font-family: 'Nanum Gothic'; color: #000000; text-align: start;&quot;&gt;&amp;nbsp;&lt;/a&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;Commit 단계로 구성된다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li style=&quot;list-style-type: circle; color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Prepare Phase : 관련된 모든 서비스는 Commit을 준비하고, Transaction Coordinator에 트랜잭션을 시작할 준비가 되었음(Commit 할 준비가 되었음)을 알린다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: circle; color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Commit Phase : 이전 단계에서 트랜잭션을 시작할 준비가 되었다면, Coordinator는 Commit을 요청한다. 만약 서비스 하나라도 실패가 발생한다면, Coordinator는 관련된 모든 서비스에 해당 트랜잭션을 롤백하도록 요청한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;다음은 Two-Phase Commit 방안을 적용한 예시이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;사용자가 요청을 보내면, Transaction Coordinator는 모든 콘텍스트 정보를 기반으로 트랜잭션을 시작한다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;OrderMicroservice에 Prepare 명령을 보낸다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;그 후 InventoryMicroservice에 Prepare 명령을 보낸다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;a style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;Coordinator&lt;/span&gt;&lt;/a&gt;가 두 서비스가 트랜잭션 처리 준비가 되었음을 확인하면, Commit을 요청한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1368&quot; data-origin-height=&quot;674&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r8sTS/btsHErIXPwq/K2QmwhJpB6QevFiU6UX2t0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r8sTS/btsHErIXPwq/K2QmwhJpB6QevFiU6UX2t0/img.png&quot; data-alt=&quot;성공 처리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r8sTS/btsHErIXPwq/K2QmwhJpB6QevFiU6UX2t0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr8sTS%2FbtsHErIXPwq%2FK2QmwhJpB6QevFiU6UX2t0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;692&quot; height=&quot;341&quot; data-origin-width=&quot;1368&quot; data-origin-height=&quot;674&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;성공 처리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1368&quot; data-origin-height=&quot;662&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R0HmY/btsHFbyDWcc/LvcGmuEyQujkHIgdnsTCLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R0HmY/btsHFbyDWcc/LvcGmuEyQujkHIgdnsTCLk/img.png&quot; data-alt=&quot;실패처리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R0HmY/btsHFbyDWcc/LvcGmuEyQujkHIgdnsTCLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR0HmY%2FbtsHFbyDWcc%2FLvcGmuEyQujkHIgdnsTCLk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;690&quot; height=&quot;334&quot; data-origin-width=&quot;1368&quot; data-origin-height=&quot;662&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;실패처리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;b&gt;정리&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;two-phase commit은 분산 트랜잭션 처리를 위한 전통적인 방법이지만, Transaction Coordinator에 의존하여 모든 서비스에 대해 준비 상태를 확인하고 Rocking 상태로 변경하는 등 성능 측면에서 효율적인 방법이 아니다. 또한 NoSQL 등 일부 구현에도 지원하지 않아 제약이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;2. Saga Pattern&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;2-1 .&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;Choreography-based saga&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;각 로컬 트랜잭션이 다른 서비스의 로컬 트랜잭션을 이벤트 트리거 하는 방식이다. 중앙 집중된 지점 없이 이벤트를 교환하며, 모든 서비스가 메시지 브로커를 통해 이벤트를 Publish/Response 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1294&quot; data-origin-height=&quot;754&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvoYz2/btsHF301067/3nfblpRcaO9cAEyd78MX71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvoYz2/btsHF301067/3nfblpRcaO9cAEyd78MX71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvoYz2/btsHF301067/3nfblpRcaO9cAEyd78MX71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvoYz2%2FbtsHF301067%2F3nfblpRcaO9cAEyd78MX71%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;711&quot; height=&quot;414&quot; data-origin-width=&quot;1294&quot; data-origin-height=&quot;754&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;b&gt;장점&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;서비스가 많지 않은 간단한 워크플로우에 적합하다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;b&gt;단점 &lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;새로운 서비스 추가가 필요할 시 서비스 간 연계성 파악이 중요하다. 서비스 간 이벤트를 주고받기 때문에 Cyclic&lt;a style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/a&gt;Dependency 발생에 주의해야 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;a style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;(&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;관련 프레임워크 : Axon Saga, Eclipse MicroProfile LRA, Eventuate Tram Saga, Seata)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;2-2.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;Orchestration-based saga&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;a style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;Orchestrator&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;중앙 집중식 컨트롤러 역할을 하고, 각 서비스에 실행할 트랜잭션을 알려주는 방법이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;Orchestrator&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;는 요청을 실행, 각 서비스의 상태를 확인, 실패에 대한 복구 처리한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1504&quot; data-origin-height=&quot;754&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRoteP/btsHGa6Omnx/UPkApCnCKiuyuiBFLXB9yk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRoteP/btsHGa6Omnx/UPkApCnCKiuyuiBFLXB9yk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRoteP/btsHGa6Omnx/UPkApCnCKiuyuiBFLXB9yk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRoteP%2FbtsHGa6Omnx%2FUPkApCnCKiuyuiBFLXB9yk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;563&quot; height=&quot;282&quot; data-origin-width=&quot;1504&quot; data-origin-height=&quot;754&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;장점&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;비교적 많은 서비스가 있는 복잡한 워크플로우에 적합하다. 서비스 및 워크플로우의 제어가 필요한 경우 또한 적합하다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;Orchestrator&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;가 전체 워크플로우를 관리하여 실패 지점이 될 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;참고링크&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;a href=&quot;https://blog.neonkid.xyz/243&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://blog.neonkid.xyz/243&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1716879345482&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[MSA] 6. MSA의 트랜잭션 이야기 2 - Two-Phase commit과 Saga&quot; data-og-description=&quot;이전 글에 이어서 MSA 내에서 트랜잭션을 원활히 하는 방법 2가지를 소개해드리고자 합니다. 관계형 데이터베이스와 더불어 모놀리틱 아키텍처를 도입한 서버 애플리케이션은 DB 서버에서 제공&quot; data-og-host=&quot;blog.neonkid.xyz&quot; data-og-source-url=&quot;https://blog.neonkid.xyz/243&quot; data-og-url=&quot;https://blog.neonkid.xyz/243&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/c0uL5g/hyV9OXl7fF/Xaq6TsFKkfGDiOTt6VW7TK/img.png?width=401&amp;amp;height=332&amp;amp;face=0_0_401_332,https://scrap.kakaocdn.net/dn/e9P4x/hyWdpuP126/vwBkfl0QDwmidHpOdQmjT1/img.png?width=401&amp;amp;height=332&amp;amp;face=0_0_401_332,https://scrap.kakaocdn.net/dn/faWFK/hyWdkUBBM3/0vkZA2ESi0kY7HFyTlpZM1/img.jpg?width=1280&amp;amp;height=520&amp;amp;face=0_0_1280_520&quot;&gt;&lt;a href=&quot;https://blog.neonkid.xyz/243&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.neonkid.xyz/243&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/c0uL5g/hyV9OXl7fF/Xaq6TsFKkfGDiOTt6VW7TK/img.png?width=401&amp;amp;height=332&amp;amp;face=0_0_401_332,https://scrap.kakaocdn.net/dn/e9P4x/hyWdpuP126/vwBkfl0QDwmidHpOdQmjT1/img.png?width=401&amp;amp;height=332&amp;amp;face=0_0_401_332,https://scrap.kakaocdn.net/dn/faWFK/hyWdkUBBM3/0vkZA2ESi0kY7HFyTlpZM1/img.jpg?width=1280&amp;amp;height=520&amp;amp;face=0_0_1280_520');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[MSA] 6. MSA의 트랜잭션 이야기 2 - Two-Phase commit과 Saga&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이전 글에 이어서 MSA 내에서 트랜잭션을 원활히 하는 방법 2가지를 소개해드리고자 합니다. 관계형 데이터베이스와 더불어 모놀리틱 아키텍처를 도입한 서버 애플리케이션은 DB 서버에서 제공&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.neonkid.xyz&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;3. 각 서비스 간의&amp;nbsp;통신 과정을 어떻게 하는지&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #343a40; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;1. API 기반 통신&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #343a40; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;MSA 아키텍처에서 가장 일반적인 서비스 간 통신 방법은 API를 통한 통신입니다. RESTful API는 HTTP 프로토콜을 사용하여 서비스 간에 데이터를 교환하는 방법입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #343a40; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;장점&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RESTful API는 간단하고 이해하기 쉽다.&lt;/li&gt;
&lt;li&gt;다른 플랫폼과 연결하기 쉽다.(대중적)&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #343a40; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서비스가 서로의 위치를 알아야 함&lt;/li&gt;
&lt;li&gt;통신 오버헤드가 발생할 수 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #343a40; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;2. 이벤트 기반 통신&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #343a40; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #505860; text-align: start;&quot;&gt;이벤트 브로커를 사용하여 서비스 간에 이벤트를 전달합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #343a40; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;장점&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서비스가 서로를 직접 알 필요 없이 메시지를 교환할 수 있다.&lt;/li&gt;
&lt;li&gt;시스템의 확장성과 유연성을 크게 향상시킵니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #343a40; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;이벤트 기반 통신은 이벤트의 추적과 관리가 복잡해질 수 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #343a40; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. 메시지 큐를 활용한 비동기 통신&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #343a40; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #505860; text-align: start;&quot;&gt;메시지 큐를 사용한 비동기 통신도 MSA 아키텍처에서 널리 사용되는 방법입니다. 메시지 큐는 서비스 간 메시지를 저장하고 전달하는 역할을 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #343a40; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;장점&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #505860; text-align: start;&quot;&gt;서비스 간의 통신을 비동기적으로 처리할 수 있어 시스템의 부하를 분산&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #505860; text-align: start;&quot;&gt;시스템의 안정성을 높이는 데 도움이 됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #343a40; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #505860; text-align: start;&quot;&gt;메시지의 순서와 처리 상태를 관리해야 한다&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #505860; text-align: start;&quot;&gt;위의 내용들을 정리 해보았는데 솔직히 아직 감이 잘 안잡히는 거 같습니다.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #505860; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #505860; text-align: start;&quot;&gt;실제로 구현을 해보면서 구체화시키는게 제일 좋은 것 같습니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>백 엔드</category>
      <category>CQRS</category>
      <category>MSA</category>
      <category>SAGA</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/156</guid>
      <comments>https://aimk12.tistory.com/156#entry156comment</comments>
      <pubDate>Tue, 28 May 2024 16:06:12 +0900</pubDate>
    </item>
    <item>
      <title>Mybatis와 JPA의 차이</title>
      <link>https://aimk12.tistory.com/155</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번 글은 인턴하면서 느낀 나의 개발 회고록이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 주로 학교 프로젝트를 할 때 Jpa를 활용하면서 개발을 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 인턴 생활을 하면서 Mybaits를 사용해 Sql를 짜면서 Mybatis로 마음이 기울기 시작했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제부터 나의 생각이 왜 바꼈는지 글을 작성해본다..(그냥 저의 사견일 뿐입니다..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Jpa &lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;장점&amp;nbsp;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가독성이 좋다.&lt;/li&gt;
&lt;li&gt;데이터베이스에 종속 되지 않는다.&lt;/li&gt;
&lt;li&gt;간편하게 구현이 가능하다.&lt;/li&gt;
&lt;li&gt;동일한 쿼리에 캐싱기능이 제공이 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;단점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Sql 구현을 안해 JPA에 의존성이 늘어난다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;복잡한 설계에서는 구현하기 힘들다&lt;/li&gt;
&lt;li&gt;공부량이 많다.&lt;/li&gt;
&lt;li&gt;동적 쿼리 구현하기 위해 다른 것들을 활용해야한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Mybatis&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;장점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;공부량이 적다 (sql문 공부하면 됨)&lt;/li&gt;
&lt;li&gt;sql과 자바의 분리&amp;nbsp;&lt;/li&gt;
&lt;li&gt;동적 쿼리도 간단하게 구현 가능(if문 이용해서)&amp;nbsp;&lt;/li&gt;
&lt;li&gt;복잡한 쿼리 작성시 용이하다&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;단점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;반복된 쿼리 작성시 중복 작업이 생긴다.&lt;/li&gt;
&lt;li&gt;Sql에 의존적으로 개발하게 된다.&lt;/li&gt;
&lt;li&gt;가독성이 Jpa에 비해 떨어진다&amp;nbsp;&lt;/li&gt;
&lt;li&gt;데이터베이스 변경시 로직도 수정해야한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;나의 생각 정리&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 테이블 설계는 절대 이상적으로 흘러가지 않는다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가 기능구현할 시 점점 테이블은 복잡해지기 마련이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엥? 그냥 테이블에 컬럼만 추가해서 하면 쉬운거 아닌가? 라고 생각할 수도 있지만 실제 운영되고 있는 데이터 테이블에 새로운 컬럼을 추가하는 것은 위험한 행동이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 이유는 이미 테이블의 컬럼 순서대로 디스크에 저장이 되어있기 때문이다. 운영중인 디비에 새로 컬럼을 추가하면 추가된 컬럼만 다른 공간에 저장이 된다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 테이블의 하나의 로우를 읽기위해 디스크 한블록만 읽으면 될 것을 새로 추가한 컬럼 때문에 다른 블록까지 참조해야하는 상황이 생길 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 어떤 상황이든 데이터베이스가 이상적으로 흘러가지 않을 가능성이 높다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. 동적쿼리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Jpa에서 동적쿼리를 처리하기 위해 Jpql을 사용하기도 하고 QueryDsl을 사용하기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 내가 느끼기에는 해당 기술을 적용하는 거 자체가 이미 복잡하게 구현이 된다고 느낀다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 다른 곳에서 편한 이점들이 있지만 어려운 개발에 대응하기가 mybatis보다 힘들다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 복잡한 쿼리(with절, json_to_array 같은 문법 적용 및 서브쿼리 적용 )&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Jpa의 명확한 한계라고 느낀 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각보다 실무에서는 복잡한 쿼리를 작성하는 순간이 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럴 때마다 native 쿼리를 작성하면 굳이 Jpa를 사용한다는 느낌이 들었다. 오히려 다양한 툴을 사용해 복잡하게 된다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;4.&amp;nbsp; Sql을 직접 구현 안한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sql을 직접 구현안한다는게 장점이지만 난 개인적으로 Sql을 직접 구현안해서 더 불안한 거 같다. (특히 복잡해질수록...)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPA에게 제어를 뺏긴 기분이랄까..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;5. 엔티티 주도 설계는 JPA가 좋은 거 같긴하다&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확실히 가독성도 좋고 무엇보다 개발이 너무 편하다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;최종 정리&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼 JPA나 Mybatis는 각각의 장단점이 있는 거 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔티티 주도 설계는 확실히 가독성이 좋은거 같고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPA가 여기에 맞게 잘 사용할 수 있는 거 같다.&lt;/p&gt;</description>
      <category>백 엔드/spring</category>
      <category>JPA</category>
      <category>mybatis</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/155</guid>
      <comments>https://aimk12.tistory.com/155#entry155comment</comments>
      <pubDate>Fri, 5 Apr 2024 21:44:26 +0900</pubDate>
    </item>
    <item>
      <title>Spring Batch 적용기</title>
      <link>https://aimk12.tistory.com/154</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Spring Batch란?&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;로깅/추적, 트랜잭션 관리, 작업 처리 통계, 작업 재시작, 건너뛰기, 리소스 관리 등 대용량 레코드 처리에 필수적인 기능을 제공합니다. 또한 최적화 및 파티셔닝 기술을 통해 대용량 및 고성능 배치 작업을 가능하게 하는 고급 기술 서비스 및 기능을 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #ee2323; text-align: start;&quot;&gt;(Spring Batch는 대용량 처리를 도와줄 뿐 scheduler랑은 상관 없다는 것을 주의하자.. 둘이 같이 사용하는 경우가 많아 혼동하지 않기)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Spring Batch 용어&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;h2 id=&quot;6714&quot; style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size26&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Job&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;2933&quot;&gt;배치처리 과정을 하나의 단위로 만들어 놓은 객체입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;12ce&quot; style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size26&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;JobInstance&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;1cdd&quot;&gt;Job의 실행의 단위를 나타냅니다.&lt;/li&gt;
&lt;li&gt;Job을 실행시키게 되면 하나의 JobInstance가 생성되게 됩니다. &lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;b8f8&quot; style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size26&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;JobParameters&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;4f2f&quot;&gt;JobInstance 구별하게 해줍니다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; text-align: left;&quot;&gt;JobInstacne에 전달되는 매개변수 역할도 하고 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;b946&quot; style=&quot;background-color: #ffffff; color: #242424; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Step&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;5f65&quot; style=&quot;list-style-type: disc; color: #242424;&quot; data-selectable-paragraph=&quot;&quot;&gt;배치 작업의 독립적이고 순차적인 단계를 캡슐화하는 도메인 객체입니다.&lt;/li&gt;
&lt;li id=&quot;6db1&quot; style=&quot;list-style-type: disc; color: #242424;&quot; data-selectable-paragraph=&quot;&quot;&gt;Step의 내용은 개발자마다 각자의 재량껏 비즈니스 코드를 구현해야 합니다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #242424;&quot; data-selectable-paragraph=&quot;&quot;&gt;Step은 Chunk 기반 ,Task 기반 두가지로 구현이 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #595959;&quot;&gt;●&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #595959;&quot;&gt;Tasklet을&lt;/span&gt;&lt;span style=&quot;color: #595959;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #595959;&quot;&gt;사용한&lt;/span&gt;&lt;span style=&quot;color: #595959;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Task&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #595959;&quot;&gt;기반&lt;/span&gt;&lt;span style=&quot;color: #595959;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #595959;&quot;&gt;처리&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #555555; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: circle;&quot;&gt;배치 처리 과정이 비교적 쉬운 경우 쉽게 사용&lt;/li&gt;
&lt;li style=&quot;list-style-type: circle;&quot;&gt;대량 처리를 하는 경우 더 복잡&lt;/li&gt;
&lt;li style=&quot;list-style-type: circle;&quot;&gt;하나의 큰 덩어리를 여러 덩어리로 나누어 처리하기 부적합&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1566&quot; data-origin-height=&quot;696&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0q6VI/btsGrbeEMKU/zkzSYW1xjp4TtaTtKcCDck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0q6VI/btsGrbeEMKU/zkzSYW1xjp4TtaTtKcCDck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0q6VI/btsGrbeEMKU/zkzSYW1xjp4TtaTtKcCDck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0q6VI%2FbtsGrbeEMKU%2FzkzSYW1xjp4TtaTtKcCDck%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;570&quot; height=&quot;253&quot; data-origin-width=&quot;1566&quot; data-origin-height=&quot;696&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #595959;&quot;&gt;●&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #595959;&quot;&gt;Chunk를&lt;/span&gt;&lt;span style=&quot;color: #595959;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #595959;&quot;&gt;사용한&lt;/span&gt;&lt;span style=&quot;color: #595959;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;chunk(&lt;/span&gt;&lt;span style=&quot;color: #595959;&quot;&gt;덩어리&lt;/span&gt;&lt;span style=&quot;color: #595959;&quot;&gt;)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #595959;&quot;&gt;기반&lt;/span&gt;&lt;span style=&quot;color: #595959;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #595959;&quot;&gt;처리&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #555555; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: circle;&quot;&gt;ItemReader, ItemProcessor, ItemWriter의 관계 이해 필요&lt;/li&gt;
&lt;li style=&quot;list-style-type: circle;&quot;&gt;대량 처리를 하는 경우 Tasklet 보다 비교적 쉽게 구현&lt;/li&gt;
&lt;li style=&quot;list-style-type: circle;&quot;&gt;예를 들면 10,000개의 데이터 중 1,000개씩 10개의 덩어리로 수행&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1590&quot; data-origin-height=&quot;814&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ifu5k/btsGp0ep8xq/a53sHC4hm5sqnK8DwHIe61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ifu5k/btsGp0ep8xq/a53sHC4hm5sqnK8DwHIe61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ifu5k/btsGp0ep8xq/a53sHC4hm5sqnK8DwHIe61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIfu5k%2FbtsGp0ep8xq%2Fa53sHC4hm5sqnK8DwHIe61%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;503&quot; height=&quot;258&quot; data-origin-width=&quot;1590&quot; data-origin-height=&quot;814&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1410&quot; data-origin-height=&quot;942&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7lYL9/btsGqY0VlPJ/YTgmHq3Fn9PaTshUVf35N0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7lYL9/btsGqY0VlPJ/YTgmHq3Fn9PaTshUVf35N0/img.png&quot; data-alt=&quot;살행 방식&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7lYL9/btsGqY0VlPJ/YTgmHq3Fn9PaTshUVf35N0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7lYL9%2FbtsGqY0VlPJ%2FYTgmHq3Fn9PaTshUVf35N0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;411&quot; height=&quot;275&quot; data-origin-width=&quot;1410&quot; data-origin-height=&quot;942&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;살행 방식&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;예약알람 시스템 구축의 여정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인턴을 진행하면서 예약알람 시스템을 만들어야 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러기 위해서 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;스케줄러&lt;/b&gt;&lt;/span&gt;가 필요했고 &lt;b&gt;대용량 처리&lt;/b&gt;를 위한 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Spring Batch&lt;/b&gt;&lt;/span&gt;를 사용해야했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실시간으로 알람을 보내야 하는 기능이었으면 &lt;b&gt;메시지 큐&lt;/b&gt;를 이용해서 실시간 처리를 이용했겠지만 지금 구현하는 기능은 실시간보다 &lt;b&gt;데이터 추적&lt;/b&gt;이 필요하므로 이렇게 작업을 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설계도면&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1922&quot; data-origin-height=&quot;1236&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQtfoo/btsGoPx4z30/YnCCMjKPjBhRvNokWkIUlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQtfoo/btsGoPx4z30/YnCCMjKPjBhRvNokWkIUlK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQtfoo/btsGoPx4z30/YnCCMjKPjBhRvNokWkIUlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQtfoo%2FbtsGoPx4z30%2FYnCCMjKPjBhRvNokWkIUlK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1922&quot; height=&quot;1236&quot; data-origin-width=&quot;1922&quot; data-origin-height=&quot;1236&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대략 설계 그림을 보면 이렇게 작동이 된다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이벤트 감지,발송 대상 수집, 재발송, 발송은 각각 하나의 Task로 계속 실행되는 작업이다.&lt;/li&gt;
&lt;li&gt;상태값을 설정해서 데이터의 상태를 추적할 수 있게 만들었다.&lt;/li&gt;
&lt;li&gt;또한 배치 작업할 때 대용량을 다루므로 chunk 방식을 도입했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>백 엔드/spring</category>
      <category>Spring Batch</category>
      <category>대용량 처리</category>
      <category>스프링 배치</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/154</guid>
      <comments>https://aimk12.tistory.com/154#entry154comment</comments>
      <pubDate>Fri, 5 Apr 2024 21:18:04 +0900</pubDate>
    </item>
    <item>
      <title>무중단 배포 (Blue,Green 적용기)</title>
      <link>https://aimk12.tistory.com/153</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번 프로젝트를 진행을 하면서 무중단 (Blue,Green) 배포를 시도해보았다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;무중단 배포란 ?&lt;/b&gt;&lt;br /&gt;배포를 할 떄에 서버가 잠시 중단되는 현상을 방지하기 위한 것이다!&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Blue,Green 무중단 배포란?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 2대(하나는 blue,하나는 green) 을 가동시키고 번갈아가면서 배포시키는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 그림을 참고로 설명하겠다!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1564&quot; data-origin-height=&quot;824&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cez8hF/btsAy8pKuvW/JspYwjL2W28Y82A5kyLrs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cez8hF/btsAy8pKuvW/JspYwjL2W28Y82A5kyLrs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cez8hF/btsAy8pKuvW/JspYwjL2W28Y82A5kyLrs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcez8hF%2FbtsAy8pKuvW%2FJspYwjL2W28Y82A5kyLrs0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;780&quot; height=&quot;411&quot; data-origin-width=&quot;1564&quot; data-origin-height=&quot;824&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 사진처럼 blue서버에 사람들이 접근할 하고 있는데 새로운 버전을 배포를 해야하는 상황이 올 때가 있을 것이다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;새로운 버전을 Green 서버&lt;/b&gt;&lt;/span&gt;에 배포를 하고&amp;nbsp;&lt;br /&gt;배포가 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;완료 되면 유저를 Green서버에만 접근가능하게 변경&lt;/span&gt;&lt;/b&gt;해준다!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1564&quot; data-origin-height=&quot;824&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cz8d4k/btsAy75uj7i/XJ54WGukDfYZXMYQM0F570/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cz8d4k/btsAy75uj7i/XJ54WGukDfYZXMYQM0F570/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cz8d4k/btsAy75uj7i/XJ54WGukDfYZXMYQM0F570/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcz8d4k%2FbtsAy75uj7i%2FXJ54WGukDfYZXMYQM0F570%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;761&quot; height=&quot;401&quot; data-origin-width=&quot;1564&quot; data-origin-height=&quot;824&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 Blue서버를 다운 시켜 주면 된다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Blue,Green 구현&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 도커로 컨테이너를 두개 띄웠다.(하나는 blue,하나는 green)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Docker-Compose&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1700546343299&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;version: '3'
services:

  blue:
    container_name: blue
    image: {container}/blue-green
    expose:
      - 8080
    ports:
      - 8080:8080

  green:
    container_name: green
    image: {container}/blue-green
    expose:
      - 8080
    ports:
      - 8081:8080&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Nginx.conf 설정&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 nginx.blue.conf(blue 서버 nginx 설정 파일) , nginx.green.conf(green서버 nginx 설정파일) 을 만들어 준다.&lt;br /&gt;저는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;https&lt;/b&gt;&lt;/span&gt;도 설정해서 인증서 적용되게 해주었습니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nginx.blue.conf - (green은 포트번호만 변경)&lt;/p&gt;
&lt;pre id=&quot;code_1700546606824&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

    events {
        worker_connections  1024;
        }

        http {

        include       mime.types;

     
        server {

        server_name [도메인 이름]
        client_max_body_size 20M;    // 이건 해두는게 좋습니다..
        // 저는 이거 안하다고 용량이 큰 파일(multiparfile)이 전달이 안되어서 고생했던 기억이..
        location / {

        # GREEN - 8081 포트로 연결합니다.
        # BLUE 설정파일은 이부분의 포트만 8080로 변경해주면 됩니다.
        proxy_pass http://127.0.0.1:8081;
        proxy_set_header Host $host;

        }
        
        //https 적용

        listen 443 ssl; # managed by Certbot

        ssl_certificate /etc/letsencrypt/live/{도메인}/fullchain.pem; # managed by Cert&amp;gt;
        ssl_certificate_key /etc/letsencrypt/live/{도메인}/privkey.pem; # managed by Ce&amp;gt;
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
        }

        # 80 포트로 접근시 443 포트로 리다이렉트 시켜주는 설정
        server {

        return 301 https://$host$request_uri;

        listen 80;
        server_name {도메인 주소};
        return 404; # managed by Certbot
        }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;deploy.sh 설정&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 배포할때마다 서버 변경해주는 명령어 실행시켜줄 deploy.sh 설정&lt;/p&gt;
&lt;pre id=&quot;code_1700547072955&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#!/bin/bash

IS_GREEN_EXIST=$(docker ps | grep green)
DEFAULT_CONF=&quot;/etc/nginx/nginx.conf&quot;     // nginx.conf

# blue가 실행 중이면 green을 up합니다.
if [ -z $IS_GREEN_EXIST ]; then
  echo &quot;### BLUE =&amp;gt; GREEN ####&quot;
  echo &quot;&amp;gt;&amp;gt;&amp;gt; green image를 pull합니다.&quot;
  docker-compose pull green
  echo &quot;&amp;gt;&amp;gt;&amp;gt; green container를 up합니다.&quot;
  docker-compose up -d green
  sleep 3
  echo &quot;&amp;gt;&amp;gt;&amp;gt; nginx를 다시 실행 합니다.&quot;
   //설정해 두었던 nginx.green.conf를 nginx.conf 파일로 옮겨줌
  sudo cp /etc/nginx/nginx.green.conf /etc/nginx/nginx.conf 
 //nginx 재시동해서 설정적용
  sudo nginx -s reload
  echo &quot;&amp;gt;&amp;gt;&amp;gt; blue container를 down합니다.&quot;
  docker-compose stop blue

# ^Hgreen이 실행 중이면 blue를 up합니다.
else
  echo &quot;### GREEN =&amp;gt; BLUE ###&quot;
  echo &quot;&amp;gt;&amp;gt;&amp;gt; blue image를 pull합니다.&quot;
  docker-compose pull blue
  echo &quot;&amp;gt;&amp;gt;&amp;gt; blue container up합니다.&quot;
  docker-compose up -d blue
  sleep 3
  echo &quot;&amp;gt;&amp;gt;&amp;gt; nginx를 다시 실행 합니다.&quot;
  sudo cp /etc/nginx/nginx.blue.conf /etc/nginx/nginx.conf
  sudo nginx -s reload
  echo &quot;&amp;gt;&amp;gt;&amp;gt; green container를 down합니다.&quot;
  docker-compose stop green
  fi&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러고 github action으로 CI/CD 구축하면 끝!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무중단 배포란 것을 처음 알게 되었는데 확실히 서버 배포하는 동안에 nginx 재로드 되는 시간 제외하면 유지되어서&amp;nbsp;&lt;br /&gt;프론트 분들이 서버닫혀있다는 경험을 안한것 같다!&lt;/p&gt;</description>
      <category>기타</category>
      <category>Blue/Green</category>
      <category>CI/CD</category>
      <category>docker</category>
      <category>도커</category>
      <category>무중단배포</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/153</guid>
      <comments>https://aimk12.tistory.com/153#entry153comment</comments>
      <pubDate>Tue, 21 Nov 2023 15:14:57 +0900</pubDate>
    </item>
    <item>
      <title>Github action 빌드 캐싱</title>
      <link>https://aimk12.tistory.com/152</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;CI/CD 쪽을 공부하다가 배포과정에서 많은 시간이 걸리고 이를 줄이는 방법에 대해 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간을 줄이기 위해서는 캐싱작업이 필수적이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;캐싱작업이란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배포하면서 거의 변동되지 않는 파일을 중복적으로 설치 및 배포하는 과정이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 파일들을 미리 Github의 캐시에 올려두고 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(대표적으로는 Spring 의 gradle을 예시로 둘 수 있다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 별도의 설정 없이 Github action이나 Docker에서&amp;nbsp; 이미 캐싱 기능을 지원해주고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 이 두가지에 대해 알아보겠다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 도커 배포 빌드 캐싱&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참조 자료: &lt;a href=&quot;https://docs.docker.com/build/cache/backends/gha/#scope&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.docker.com/build/cache/backends/gha/#scope&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1694940953498&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;GitHub Actions cache&quot; data-og-description=&quot;Use the GitHub Actions cache to manage your build cache in CI&quot; data-og-host=&quot;docs.docker.com&quot; data-og-source-url=&quot;https://docs.docker.com/build/cache/backends/gha/#scope&quot; data-og-url=&quot;https://docs.docker.com/build/cache/backends/gha/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bAQg9u/hyTY0cvYQ5/h9CRAnPyNZUHg6PMIVYeV0/img.png?width=129&amp;amp;height=128&amp;amp;face=0_0_129_128,https://scrap.kakaocdn.net/dn/Oz090/hyTVWJAMuE/UNj1HWNUTpNOUd9U3l8Wa0/img.png?width=950&amp;amp;height=500&amp;amp;face=0_0_950_500&quot;&gt;&lt;a href=&quot;https://docs.docker.com/build/cache/backends/gha/#scope&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.docker.com/build/cache/backends/gha/#scope&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bAQg9u/hyTY0cvYQ5/h9CRAnPyNZUHg6PMIVYeV0/img.png?width=129&amp;amp;height=128&amp;amp;face=0_0_129_128,https://scrap.kakaocdn.net/dn/Oz090/hyTVWJAMuE/UNj1HWNUTpNOUd9U3l8Wa0/img.png?width=950&amp;amp;height=500&amp;amp;face=0_0_950_500');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub Actions cache&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Use the GitHub Actions cache to manage your build cache in CI&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.docker.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배포.yml&lt;/p&gt;
&lt;pre id=&quot;code_1694939929743&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;uses: docker/build-push-action@v3
        with:
          context: .
          platforms: linux/amd64,linux/arm64
          push: true
          tags: myunghyunnero/latest
          cache-from: type=gha             //캐싱 작업
          cache-to: type=gha,mode=max       //캐싱 작업&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dockerfile&lt;/p&gt;
&lt;pre id=&quot;code_1694939993435&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Build stage
FROM openjdk:11 AS builder
WORKDIR /gradle
COPY gradlew build.gradle settings.gradle ./
COPY gradle/ gradle/
# 의존성 패키지만 빌드해서 캐싱 적용
RUN ./gradlew build || return 0

#모든 파일 도커로 옮김 
COPY . . 

# gradlew build 실행해서 모든 파일 빌드 -&amp;gt; 여기서 의존성 패키지는 캐싱되므로 바뀐 부분만 빌드 
RUN [&quot;./gradlew&quot;, &quot;clean&quot;, &quot;build&quot;, &quot;--no-daemon&quot;]


# Run stage
FROM openjdk:11
EXPOSE 8080
WORKDIR /app
COPY --from=builder /gradle/build/libs/*.jar ./app.jar   #gradle밑에 있는 실행파일 롬ㄱ미

# 이미지 실행하면 기본으로 실행되는 명령어
CMD [&quot;java&quot;, &quot;-jar&quot;, &quot;app.jar&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2.github 캐싱 지원&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1694941371490&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;- name: Cache Gradle packages
        uses: actions/cache@v2
        with:
        # gradle 빌드시 파일 저장되는 경로 
          path: |
            ~/.gradle/caches     
            ~/.gradle/wrapper
        # 캐싱할 때 쓰이는 키 -&amp;gt; 해당 키가 존재하면 캐시 히트 , githib action 내장함수 hashFiles로 키지정
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
          # 키를 못찾으면 restore key를 이용해 다른 키 찾음 , 우선순위별로 위에서 아래로 감 
          restore-keys: |
            ${{ runner.os }}-gradle-&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 두가지 캐싱작업은 오래걸리는 작업인 Gradle을 기준으로 한 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 프로젝트에서는 중복적이고 오래작업하는 것을 캐싱하면 될 것 이다.&lt;/p&gt;</description>
      <category>GitHub,Git</category>
      <category>cache</category>
      <category>github action</category>
      <category>캐싱</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/152</guid>
      <comments>https://aimk12.tistory.com/152#entry152comment</comments>
      <pubDate>Sun, 17 Sep 2023 18:08:46 +0900</pubDate>
    </item>
    <item>
      <title>도커 용량 줄이기</title>
      <link>https://aimk12.tistory.com/151</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터를 사용하는 도중 용량이 이상하게 부족했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1090&quot; data-origin-height=&quot;346&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfgElP/btsp644MZev/Q6caAM2TWIKF6pmdbsgFi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfgElP/btsp644MZev/Q6caAM2TWIKF6pmdbsgFi0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfgElP/btsp644MZev/Q6caAM2TWIKF6pmdbsgFi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfgElP%2Fbtsp644MZev%2FQ6caAM2TWIKF6pmdbsgFi0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;428&quot; height=&quot;136&quot; data-origin-width=&quot;1090&quot; data-origin-height=&quot;346&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템 데이터가 비정상적으로 많았다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 MacCleaner X를 사용해서 스캔을 해본결과..&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1168&quot; data-origin-height=&quot;462&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lc3lI/btsp33rxcwG/YsF19aNKnG4iMG7K7mwjH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lc3lI/btsp33rxcwG/YsF19aNKnG4iMG7K7mwjH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lc3lI/btsp33rxcwG/YsF19aNKnG4iMG7K7mwjH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flc3lI%2Fbtsp33rxcwG%2FYsF19aNKnG4iMG7K7mwjH0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;508&quot; height=&quot;201&quot; data-origin-width=&quot;1168&quot; data-origin-height=&quot;462&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도커에 엄청난 용량이... + (UTM에서 22기가도...)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본격적으로 도커 정리를 시작해보자..&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 밑에 코드를 이용해서 미사용하는 &lt;b&gt;컨테이너,이미지,볼륨을 삭제&lt;/b&gt;하자..&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;삭제 명령어&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1691216751893&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker container prune : 중지된 모든 컨테이너 삭제
docker image prune : 사용하지 않는 이미지 삭제(dangling images)
docker volume prune : 컨테이너와 연결되지 않은 모든 볼륨 삭제
docker network prune : 컨테이너와 연결되지 않은 모든 네트워크 삭제
docker system prune -a : 위에 명령어를 통합해서 한번에 실행. 사용하지 않는 모든 오브젝트를 삭제&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쌓여있는 로그 삭제 명령어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적인 &lt;b&gt;도커 로그 용량&lt;/b&gt;을 확인&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1691219148823&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo du -h $(docker inspect --format='{{.LogPath}}' $(docker ps -qa))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도커 로그 전체 삭제 명령어&lt;/p&gt;
&lt;pre id=&quot;code_1691219249706&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo sh -c &quot;truncate -s 0 /var/lib/docker/containers/*/*-json.log&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;compose 파일을 이용한 로그 용량 제한 방법&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1691219092672&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#docker-compose 파일
logging:
      driver: &quot;json-file&quot;
      options:
        max-size: &quot;200k&quot;
        max-file: &quot;10&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 자료&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.docker.com/compose/compose-file/compose-file-v3/#logging&quot;&gt;https://docs.docker.com/compose/compose-file/compose-file-v3/#logging&lt;/a&gt;&lt;/p&gt;</description>
      <category>기타</category>
      <category>도커</category>
      <category>용량</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/151</guid>
      <comments>https://aimk12.tistory.com/151#entry151comment</comments>
      <pubDate>Sat, 5 Aug 2023 16:09:07 +0900</pubDate>
    </item>
    <item>
      <title>최소 스패팅 트리 와 다익스트라 정리</title>
      <link>https://aimk12.tistory.com/150</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;오랜만에 문제를 풀다가 헷갈리는 부분들이 있어서 정리를 해본다..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;최소 스패팅 트리&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 노드에서 가중치 합이 가장 작은 트리를 만드는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;크루스칼 vs 프림&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;크루스칼 알고리즘&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;간선의 길이가 짧은 것 부터 시작해서 사이클이 생기지 않게 간선을 추가하는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프림 알고리즘&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 시작 노드를 정한 후에 노드에 연결된 간선 중 최소 값을 선택하여 확장해나가는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;크루스칼 알고리즘 구현&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1688026728456&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 유니온 파인트도 사이클 체크
int findparent(int x){
    if(x==findparent(parent[x])){
        return x;
    }else{
        return parent[x]=findparent(parent[x]);
    }
}
void uni(int x,int y){
    x=findparent(x);
    y=findparent(y);
    parent[y]=x;
}
void solution(){
    
    for(int i=1; i&amp;lt;=n; i++) parents[i] = i;
    sort(edges.begin(), edges.end(), cmp);
    
    for(int i=0; i&amp;lt;edges.size(); i++){
        int node1 = edges[i].second.first;
        int node2 = edges[i].second.second;
        int cost = edges[i].first;  
        
        if(get_parent(node1) != get_parent(node2)){. // 사이클이 안만들어지면 간선 추가
            union_parents(node1, node2);
            total -= cost;       //total은 총 가중치 합 
        }
    }
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프림 알고리즘 구현(우선순위 큐)&lt;/p&gt;
&lt;pre id=&quot;code_1688026751053&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void prim(int start){
    visited[start]=true;    //오름차순 우선순위 큐 사용
    priority_queue&amp;lt;pair&amp;lt;int,int&amp;gt;,vector&amp;lt;pair&amp;lt;int,int&amp;gt;&amp;gt;,greater&amp;lt;pair&amp;lt;int,int&amp;gt;&amp;gt;&amp;gt; pq;
    for(int i=0;i&amp;lt;v[start].size();i++){
        int dis=v[start][i].first;
        int node=v[start][i].second;
        pq.push({dis,node});   //시작 노드에서 이어지는 간선들 큐에 삽입
    }
    while(!pq.empty()){
        int dis=pq.top().first;
        int node=pq.top().second;
        pq.pop();
        if(visited[node]) continue;  //이미 방문한 노드는 넘어간다.
        ans+=dis;             // 추가 되는 가중치 합을 더함 -&amp;gt; 최소 가중치 트리 
        visited[node]=true;
        for(int i=0;i&amp;lt;v[node].size();i++){
            int nextdis=v[node][i].first;
            int nextnode=v[node][i].second;
            if(!visited[nextnode]){
                pq.push({nextdis,nextnode});
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;다익스트라 vs 최소 스패닝 트리 (크루스칼 , 프림)&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다익스트라&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 노드에서 다른 노드 한점 까지의 최소 노드를 구하는 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;최소 스패닝 트리&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 노드에서 가중치 합이 가장 작은 트리를 만드는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;다익스트라 알고리즘 구현 (방문노드 체크는 필요하지 않다 &amp;rarr;최소 로 갱신이 필요하기 때문)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1688026830121&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void dijkstra(int start){
    dist[start]=0;
    priority_queue&amp;lt;pair&amp;lt;int,int&amp;gt;, vector&amp;lt;pair&amp;lt;int,int&amp;gt;&amp;gt;,greater&amp;lt;pair&amp;lt;int,int&amp;gt;&amp;gt;&amp;gt; q;
    q.push({dist[start],start});
    while(!q.empty()){
        int distNow = q.top().first;
        int node = q.top().second;
        q.pop();
        
        if(dist[node]&amp;lt;distNow) continue;    //방문할 노드 가중치가 현재 가중치보다 작으면 넘어감
        for(int i=0;i&amp;lt;arr[node].size();i++){
            int distNext = arr[node][i].first;
            int nodeNext = arr[node][i].second;
            if( dist[nodeNext]&amp;gt; dist[node]+distNext){
                dist[nodeNext] = dist[node] + distNext;
                q.push({dist[nodeNext],nodeNext});
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>백준 코딩</category>
      <category>Dijkstra</category>
      <category>Kruskal</category>
      <category>Prin</category>
      <category>다익스트라</category>
      <category>백준</category>
      <category>알고리즘</category>
      <category>최소 스패닝 트리</category>
      <category>크루스칼</category>
      <category>프림</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/150</guid>
      <comments>https://aimk12.tistory.com/150#entry150comment</comments>
      <pubDate>Thu, 29 Jun 2023 17:21:48 +0900</pubDate>
    </item>
    <item>
      <title>AWS 서비스들 알아보기 4 (RDS, Aurora, DynamoDB , Elasticache)</title>
      <link>https://aimk12.tistory.com/149</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;원티드 프리온보딩 마지막 수업 마지막 강의 정리!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘 서비스들은 주로 데이터 베이스 관련 서비스들이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;AWS RDS&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Amazon Relational Database Service&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라우드에서 관계형 데이터 베이스 를 간편하게 설정 , 운영 및 확장할 수 있는 관리형 서비스 모음&lt;/li&gt;
&lt;li&gt;주요기능:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RDS 백업 : 자동백업, 스냅샷&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;멀티 A-Z:두개 이상의 AZ에 걸쳐 DB를 구축하고 원본과 다른 DB를 자동으로 동기화 , 읽기전용 복제본&lt;/li&gt;
&lt;li&gt;cloudWatch 연동: DB인스턴스의 모니터링&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1330&quot; data-origin-height=&quot;874&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nJRNQ/btseQfb9a2p/bU9It0KDSXRSgvFYTpapzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nJRNQ/btseQfb9a2p/bU9It0KDSXRSgvFYTpapzk/img.png&quot; data-alt=&quot;RDS 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nJRNQ/btseQfb9a2p/bU9It0KDSXRSgvFYTpapzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnJRNQ%2FbtseQfb9a2p%2FbU9It0KDSXRSgvFYTpapzk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;615&quot; height=&quot;404&quot; data-origin-width=&quot;1330&quot; data-origin-height=&quot;874&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;RDS 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Amazon Aurora&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AWS만의 관계형데이터 베이스로써 기존의 소스를 커스터마이징하여 AWS에 최적화 시킨것&lt;/li&gt;
&lt;li&gt;RDS에서 사용하는 EBS대신 NVme SSD 드라이브 위에 구축되어 훨씬 빠름&lt;/li&gt;
&lt;li&gt;서비리스 기능과 auto Scaling을 기본적으로 지원&lt;/li&gt;
&lt;li&gt;비쌈&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;자동으로 다른 존 sync가 됨 -&amp;gt; 다른 존이 망가져도 다른 존이 있어서 안정적&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1338&quot; data-origin-height=&quot;876&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KFNV2/btseTfoku00/RbyQSbkqb1jqTHdwDCqDpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KFNV2/btseTfoku00/RbyQSbkqb1jqTHdwDCqDpK/img.png&quot; data-alt=&quot;Aurora 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KFNV2/btseTfoku00/RbyQSbkqb1jqTHdwDCqDpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKFNV2%2FbtseTfoku00%2FRbyQSbkqb1jqTHdwDCqDpK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;566&quot; height=&quot;371&quot; data-origin-width=&quot;1338&quot; data-origin-height=&quot;876&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Aurora 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Aurora 가 RDS의 mysql 보다 성능이 좋음을 알 수 있음&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1546&quot; data-origin-height=&quot;874&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWfVN4/btseTEg72ZC/1bwWFId98jRW31X6pqkSf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWfVN4/btseTEg72ZC/1bwWFId98jRW31X6pqkSf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWfVN4/btseTEg72ZC/1bwWFId98jRW31X6pqkSf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWfVN4%2FbtseTEg72ZC%2F1bwWFId98jRW31X6pqkSf1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;531&quot; height=&quot;300&quot; data-origin-width=&quot;1546&quot; data-origin-height=&quot;874&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Amazon DynamoDB&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;완전 관리형 NoSQL 데이터베이스 서비스로서 원활한 확장성과 함께 빠르고 예측가능한 성능을 제공&lt;/li&gt;
&lt;li&gt;서버리스 이므로 따로 유지비용 없이 사용한 만큼만 지불&lt;/li&gt;
&lt;li&gt;보조 인덱스를 통한 빠른 조회를 지원&lt;/li&gt;
&lt;li&gt;서버리스(람다) 서버와의 궁합이 매우 잘 맞는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;AWS Elasticache&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그냥 Redis라 생각 하면됨&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>기타</category>
      <category>Aurora</category>
      <category>AWS</category>
      <category>dynamodb</category>
      <category>RDS</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/149</guid>
      <comments>https://aimk12.tistory.com/149#entry149comment</comments>
      <pubDate>Thu, 11 May 2023 21:52:32 +0900</pubDate>
    </item>
    <item>
      <title>AWS 서비스들 알아보기 3(SQS,Kinesis)</title>
      <link>https://aimk12.tistory.com/148</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;원티드 프리온보디으 백엔드 과정 3번쨰 강의를 들으면서 정리 해보기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 SQS,Kinesis에 대해서 배워 보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전에 서버리스인 Lamda에 대해 배웠는데&amp;nbsp; 아무리 비동기 처리라도 Lamda한개로만 실행시키면 무리가 올 수밖에 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그걸 위해 SQS,Kinesis가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 서비스들은 들어온 요청을 Lamda 함수를 여러개 만들어 분산처리 가능하게 만들어준다 .&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;AWS SQS&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;simple queue service&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;마이크로서비스 ,분산 시스템 및 서버리스 애플리케이션을 위한 완전관리형 메시지 대기열&lt;/li&gt;
&lt;li&gt;표준 대기열 : 무제한 처리량/최소한 한번 전달 (여러번 전달 가능 )/최선 노력 순서 ,순서 보장 X&lt;/li&gt;
&lt;li&gt;FIFO대기열 : 초당 최대 300개의 메시지 /정확히 한번 처리 / 선입선출 전달 순서 보장&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- Lamda 트리거랑 연결지어서 사용가능&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 은행이나 예약시스템같은 순서가 중요한거 쓰임&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1712&quot; data-origin-height=&quot;864&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caSP1R/btseAUq9kfg/3iCsgp3kqzraKXvgMI5Bt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caSP1R/btseAUq9kfg/3iCsgp3kqzraKXvgMI5Bt0/img.png&quot; data-alt=&quot;SQS 그림&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caSP1R/btseAUq9kfg/3iCsgp3kqzraKXvgMI5Bt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaSP1R%2FbtseAUq9kfg%2F3iCsgp3kqzraKXvgMI5Bt0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;610&quot; height=&quot;308&quot; data-origin-width=&quot;1712&quot; data-origin-height=&quot;864&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SQS 그림&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;AWS Kinesis&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 규모의 스트리밍 데이터를 비용 효율적으로 처리할 수 있는 핵심 기능과 더불어 애플리케이션 요구사항에 가장 적합한 도구를 선택할 수 있는 유연성을 제공&lt;/li&gt;
&lt;li&gt;여러 기능이 큐에서 메시지를 가져올 수 있음&lt;/li&gt;
&lt;li&gt;예시) 비디오 ,스트림&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;726&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qz49T/btsey6Z1T5C/S1Avu6UpFe4dGMGSM752B1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qz49T/btsey6Z1T5C/S1Avu6UpFe4dGMGSM752B1/img.png&quot; data-alt=&quot;KInesis&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qz49T/btsey6Z1T5C/S1Avu6UpFe4dGMGSM752B1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fqz49T%2Fbtsey6Z1T5C%2FS1Avu6UpFe4dGMGSM752B1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;719&quot; height=&quot;326&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;726&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;KInesis&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;SQS와 Kinesis의 차이점&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 55px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 17px;&quot;&gt;SQS&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 17px;&quot;&gt;Kinesis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 19px;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;애플리케이션 통합,분산 시스템 연계&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 19px;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;로그 모바일 ,click stream 데이터 수집/분석&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 19px;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;메시지의 지연시간 지정이 필요한 경우&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 19px;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;Real-time 분석&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;716&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kQwgP/btsexhBiaKl/JoMxa6fbSTlMOP7nHAjnh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kQwgP/btsexhBiaKl/JoMxa6fbSTlMOP7nHAjnh1/img.png&quot; data-alt=&quot;차이점&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kQwgP/btsexhBiaKl/JoMxa6fbSTlMOP7nHAjnh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkQwgP%2FbtsexhBiaKl%2FJoMxa6fbSTlMOP7nHAjnh1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;733&quot; height=&quot;369&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;716&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;차이점&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>기타</category>
      <category>AWS</category>
      <category>kinesis</category>
      <category>SQS</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/148</guid>
      <comments>https://aimk12.tistory.com/148#entry148comment</comments>
      <pubDate>Tue, 9 May 2023 21:53:45 +0900</pubDate>
    </item>
    <item>
      <title>AWS 서비스들 알아보기2(EC2,Elastic Beanstalk, Fargate,ECR,ECS,Lamda)</title>
      <link>https://aimk12.tistory.com/147</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;원티드 프리온보딩 강의를 들으며 다시 정리해보기&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 EC2를 사용할 때 그냥 하라는 대로만 했는데 요금책정 방식도 여러개 있었네요..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;EC2(Amazon Elastic Cloud Compute)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장 기본적인 형태의 클라우드 컴퓨팅 (=클라우드 컴퓨터 한대)&lt;/li&gt;
&lt;li&gt;온디맨드: 선결제 금액이나 장기 약정 없이 저렴하고 유연하게 Amazon EC2를 사용하기 원하는 사용자&lt;/li&gt;
&lt;li&gt;스팟 인스턴스: 시작 및 종료 시간이 자유로운 애플리케이션 (Batch,머신러닝 할 때 사용)&lt;/li&gt;
&lt;li&gt;Saving plans: 1년 또는 3년 기간의 일정 사용량 약정을 조건으로 EC2 및 Fargate 사용량에 대해 저렴한 요금을 제공하는 유연한 요금&lt;/li&gt;
&lt;li&gt;탄력적 ip 를 설정안하면 ip 변동이 생김 (웬만하면 탄력적 ip 하기)&lt;/li&gt;
&lt;li&gt;pem키로 접속 할때 권한을 chmod 777로 하면 접속 권한이 너무 널널해져서 접속 안됨 &amp;rarr;chmod 400 으로 접근권한 수정&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;AWS Elastic Beanstalk&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AWS 클라우드에서 애플리케이션을 신속하게 배포하고 관리할 수 있는 서비스(애플리케이션 코드를 업로드하기만하면 작동)&lt;/li&gt;
&lt;li&gt;Elastic Beanstalk = EC2+배포 버전 관리(롤백) + Elastic Load Balancer + 모니터링 + 로그 트래킹 + 오토 스케일링&lt;/li&gt;
&lt;li&gt;다양한 언어 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 애플리케이션 배포를 간편하게 해주기위해 생긴 서비스이다&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;AWS Fargate(간단히 컨테이너)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;더이상 컨테이너를 실행하기 위해 가상머신의 클러스터를 프로비저닝, 구성 또는 조정할 필요 없다.따라서 서버유형을 선택하거나 , 클러스터를 조정할 시점을 결정하거나 ,클러스터 패킹을 최적화할 필요가 없다&lt;/li&gt;
&lt;li&gt;이전에는 컨테이너를 실행하기 위해서는 컨테이너를 실행할 Instance(EC2)를 실행시켜야 하지만&lt;/li&gt;
&lt;li&gt;단점: 가격이 높고 낮은 성능의 프로세스 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;AWS ECR( Elastic Container Registry)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;안전하고 확장 가능하고 신뢰할 수 있는 AWS 관리형 컨테이너 이미지 레지스트리 서비스&lt;/li&gt;
&lt;li&gt;도커 이미지를 저장하는 장소&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;AWS ECS(Elastic Container Service). -쿠버네티스 느낌 ?&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AWS에서 제공하는 컨테이너 오케스트레이션 서비스로 여러 어플리케이션 컨테이너를 쉽고 빠르게 실행하고 , 컨테이너를 적절하게 분배 및 확장 &amp;amp; 축소 할 수 있도록 도와주는 서비스&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;용어 정리&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;task definition: 컨테이너 이미지, CPU/메모리 리소스 할당 설정,port 매핑 ,volume 설정&lt;/li&gt;
&lt;li&gt;task: task안에는 한개 이상의 컨테이너들이 포함되어 있으며 ECS에서 컨테이너를 실행하는 최소 단위는 task&lt;/li&gt;
&lt;li&gt;Service: task등의 life cycle을 관리 하며 오토스케일링과 로드밸런싱을 관리&lt;/li&gt;
&lt;li&gt;Cluster: task가 배포되는 Container instance들은 논리적인 그룹&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;784&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQ1Zji/btsdZIMavAs/Cqr4M89B0rkkOiNKLVGR40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQ1Zji/btsdZIMavAs/Cqr4M89B0rkkOiNKLVGR40/img.png&quot; data-alt=&quot;ecs 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQ1Zji/btsdZIMavAs/Cqr4M89B0rkkOiNKLVGR40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQ1Zji%2FbtsdZIMavAs%2FCqr4M89B0rkkOiNKLVGR40%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;505&quot; height=&quot;232&quot; data-origin-width=&quot;784&quot; data-origin-height=&quot;360&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ecs 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;AWS Lamda&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버 없이도 코드를 실행시킬 수 있는 서버리스(코드 실행하고 바로 꺼짐) 컴퓨팅 서비스&lt;/li&gt;
&lt;li&gt;코드를 돌리기 위한 리소스를 임의로 지정할 수 있으며 , 사용 리소스 x 사용시간에 따라 과금이 된다(ex. 메모리 용량 /코어 갯수)&lt;/li&gt;
&lt;li&gt;최대 15분 /최대 10 GB/ 최대 6개의 core&lt;/li&gt;
&lt;li&gt;사용 예시 - 비동기 처리(이미지 썸네일 생성), 예측이 불가능한 리소스 사용(대용량 처리/머신러닝),분산 처리 가능&lt;/li&gt;
&lt;li&gt;cold start : 배포 패키지의 크기와 코드 실행 시간 및 코드의 초기화 시간에 따라 새실행 환경으로 호출을 라우팅 할때 지연시간이 발생하는 람다 호출 시작(겨울에 자동차 시동걸때에서 유래)&lt;/li&gt;
&lt;li&gt;5분 정도 warm하게 유지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lamda는 S3의 이미지를 트리거로 함수 실행을 시킬 수 있다고 한다.. 다른 방법도 가능하다고 하네요&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시로 사람 동물 이미지들을 분류하는 머신러닝이 있다고 하자. 그럼 이미지가 수천개가 필요하다고 가정을하는데 이때는 비동기 처리가 필수 적이다.&amp;nbsp; 그래서 S3에 이미지들을 올리고 S3에 트리거를 발동시켜 Lamda(머신러닝 코드)를 실행한다. 그렇게 서버리스에서 분류작업을 하게 할 수 있다.&lt;/p&gt;</description>
      <category>기타</category>
      <category>AWS</category>
      <category>EC2</category>
      <category>lamda</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/147</guid>
      <comments>https://aimk12.tistory.com/147#entry147comment</comments>
      <pubDate>Thu, 4 May 2023 21:20:46 +0900</pubDate>
    </item>
    <item>
      <title>AWS 서비스들 알아보기 1(API GateWay,S3,ELB,CloudFront,Secret manager)</title>
      <link>https://aimk12.tistory.com/146</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;원티드 프리 온보딩 백엔드 강의를 들으며 AWS에 대해 정리를 해본다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평소에 AWS의 서비스들은 많고 복잡해서 접근하기 힘들었는데 강의에서 큰 틀로 정리를 해주어서 정리가 잘되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;AWS란? -클라우드 컴퓨팅&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;on-premise : 자체적으로 보유한 전산실 서버에 직접 설치해 운영하는 방식&lt;/li&gt;
&lt;li&gt;clouding-computing: 인터넷을 통하여 다양한 서비스(서버,네트워킹)를 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;* ARN&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156; text-align: left;&quot;&gt;은 Amazon Resource Number의 약자로 우리가 람다함수를 생성할때 EC2를 생성할때 등 생성되는 일련번호&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;항상 ec2나 rds 등 aws 서비스를 만지면 마주치는 VPC...&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 초반 설정 말고는 딱히 건드릴 일이 없다고 한다&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;VPC란?&amp;nbsp; &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;(virtual private cloud)&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가상네트워크 서비스로 퍼블릭네트워크와 프라이빗 네트워크를 분리하고 모니터링할수 있도록하는 서비스&lt;/li&gt;
&lt;li&gt;네트워크 구성과 관련된 사실상 모든 기능들을 담당하며 ,자체 데이터 센터에서 운영하는 기존네트워크와 유사한 형태&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;집을 짓는 기분 :&amp;nbsp; 방(서브넷) 현관문 (인터넷 게이트 웨이)&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;퍼블릭 서브넷 : 인터넷 연결이 됨&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프라이빗 서브넷 : 인터넷 연결이 안됨&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1232&quot; data-origin-height=&quot;674&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNcjJX/btsdBPeR8LE/4oYezlAe2dWawwDYEzbx51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNcjJX/btsdBPeR8LE/4oYezlAe2dWawwDYEzbx51/img.png&quot; data-alt=&quot;VPC&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNcjJX/btsdBPeR8LE/4oYezlAe2dWawwDYEzbx51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNcjJX%2FbtsdBPeR8LE%2F4oYezlAe2dWawwDYEzbx51%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;615&quot; height=&quot;336&quot; data-origin-width=&quot;1232&quot; data-origin-height=&quot;674&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;VPC&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;AWS API GateWay란?&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 규모에서든 개발자가 api를 손쉽게 생성, 게시,유지 관리 ,모니터링 및 보안 유지 할 수 있도록 하는 안전관리형 서비스&lt;/li&gt;
&lt;li&gt;서버의 &amp;ldquo;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;대문&lt;/span&gt;&lt;/b&gt;&amp;rdquo; 같은 역할&amp;nbsp; - 서버에 들어오면 가장 마주치는 API&lt;/li&gt;
&lt;li&gt;할 수 있는 것 : 트래픽 관리(제한) , CORS 지원 , 권한 부여 및 액세스 제어, API 버전 관리 ,인증관련 등&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;S3란?&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엄청난 내구성과 가용성을 자랑하며 정적파일들을 용이하게 관리하도록 돕는 서비스&lt;/li&gt;
&lt;li&gt;presigned URL 을 통해 S3로 바로 저장하게 할 수도 있음( 서버를 통해 가면 서버 부하가 올 수도 있음)&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;단순 파일 저장을 넘어 데이터 저장하는 스토리지 플랫폼&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;ex) 데이터 처리 (s3에 저장되는 Trigger를 이용해 람다를 실행시킬 수 있음), 로그 , 쿼리지원 , 호스팅&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;나는 S3에 이미지 저장을 하는 방식을 이용했지만 데이터를 저장해 처리할 수 있는 기능도 있음을 알게 되었다.(Trigger을 통한 자동화를 하기위해 사용한다고 한다)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ELB(Elastic Load Balancing) 란?&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다수의 컴퓨팅 리소스(EC2,Lamda, 등) 을 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;부하 분산&lt;/b&gt;&lt;/span&gt; 시켜주는 아주 중요한 서비스&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;총 3가지 분산 서비스가 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;390&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EHlz6/btsdG6GChki/qwFzPWBIiEbZHgstvH2LM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EHlz6/btsdG6GChki/qwFzPWBIiEbZHgstvH2LM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EHlz6/btsdG6GChki/qwFzPWBIiEbZHgstvH2LM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEHlz6%2FbtsdG6GChki%2FqwFzPWBIiEbZHgstvH2LM0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;580&quot; height=&quot;276&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;390&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;CloudFront란?&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전세계에 있는 AWS 엣지 로케이션을 통하여 CDN 서비스를 제공함 (CDN은 저번에 정리해서 넘어간다)&lt;/li&gt;
&lt;li&gt;글로벌 네트워크를 지원&lt;/li&gt;
&lt;li&gt;속도는 높이고 가격은 내리며 서버 부하를 줄일 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 얼마나 속도가 빨라지고 가격은 내려가는지 확인해보자&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1250&quot; data-origin-height=&quot;266&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHqz59/btsdGnhMOpj/45BdMNcM1NSmbRbkFw1HdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHqz59/btsdGnhMOpj/45BdMNcM1NSmbRbkFw1HdK/img.png&quot; data-alt=&quot;cloudFront&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHqz59/btsdGnhMOpj/45BdMNcM1NSmbRbkFw1HdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHqz59%2FbtsdGnhMOpj%2F45BdMNcM1NSmbRbkFw1HdK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;752&quot; height=&quot;160&quot; data-origin-width=&quot;1250&quot; data-origin-height=&quot;266&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;cloudFront&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용 안 할 이유가 없네..&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Secrets Manager 란?&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AWS에서 제공하는 비밀 값 관리 서비스이다. 비밀 값들을 저장해두고 어플리케이션에서 AWS의 API를 호출해서 받아가 사용하는 방식이다.&lt;/li&gt;
&lt;li&gt;env 파일 관리한다곳 생각하면 된다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 env파일을 github secret에 저장하고&amp;nbsp; ci/cd에서 ec2에 저장 할 수 있게 했는데 이런 서비스로도 ,env파일 같은 것을 관리 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>기타</category>
      <category>AWS</category>
      <category>프리온보딩</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/146</guid>
      <comments>https://aimk12.tistory.com/146#entry146comment</comments>
      <pubDate>Tue, 2 May 2023 21:40:55 +0900</pubDate>
    </item>
    <item>
      <title>CI/CD(Github action)</title>
      <link>https://aimk12.tistory.com/145</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;CI/CD에 대해 공부를 진행하면서 배웠던 거에 적어 보려한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;CI/CD의 개념&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;CI란?&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #151515;&quot;&gt;-&quot;CI&quot;는 개발자를 위한 자동화 프로세스인 지속적인 통합(Continuous Integration)을 의미합니다. 지속적인 통합이 제대로 구현되면 애플리케이션 코드의 새로운 변경 사항이 정기적으로 빌드 및 테스트를 거쳐 공유 리포지토리에 병합&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;CD란?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&lt;span style=&quot;background-color: #ffffff; color: #151515;&quot;&gt;&quot;CD&quot;는 지속적인 서비스 제공(Continuous Delivery) 및/또는 지속적인 배포(Continuous Deployment)를 의미하며 이 두 용어는 상호 교환하여 사용됩니다. 두 가지 의미 모두 파이프라인의 추가 단계에 대한 자동화&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CI/CD를 지원해주는 툴은 여러개가 있다.(github action, jenkins 등등...)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 나는 가장 익숙하게 접할 수 있는 Github action 을 다루어 보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Github action을 사용하면 빌드,테스트를 진행시켜줄 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;runner&lt;/b&gt;&lt;/span&gt;가 필요하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단히 생각하면 빌드,테스트 진행이 필요한 서버이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(runner는 github 레포지토리에 지정한 행동이 생기면 자동으로 진행이 된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 runner에는 두가지 방식이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. GitHub-hosted runners:(Github 에서 제공해줌 )&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자동으로 업데이트되느 운영체제 및 사전 설치된 패키지들과 도구들 및 self-hosted runner 애플리케이션을 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;관리와 유지보수를 GitHub에서 한다.&lt;/li&gt;
&lt;li&gt;모든 job 실행에 깨끗한 인스턴스를 제공한다.&lt;/li&gt;
&lt;li&gt;GitHub plan안에서 무료 시간을 사용할 수 있다.(무료 시간을 초과하면 분당 요금이 적용된다,public repository는 무료)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. Self-hosted runners: (우리가 사용하는 서버에 runner을 설치하고 실행가능)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;러너의 자동 업데이트를 비활성화할 수 있지만 self-hosted runner 애플리케이션에 대한 자동 업데이트만 수신한다.&lt;/li&gt;
&lt;li&gt;사전 결제된 클라우드 서비스나 로컬 머신을 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;하드웨어나 운영체제, 소프트웨어, 보안 요구사항에 맞게 커스터마이징할수 있다.&lt;/li&gt;
&lt;li&gt;모든 job 실행에 깨끗한 인스턴스가 필요하지 않는다.&lt;/li&gt;
&lt;li&gt;GitHub Actions를 무료로 사용할 수 있으나, runner 머신에 대해 유지보수 비용을 부담해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1582&quot; data-origin-height=&quot;952&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0Oovz/btr6nX4B6lK/kd5uevvumAzrBAX7P2ukgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0Oovz/btr6nX4B6lK/kd5uevvumAzrBAX7P2ukgK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0Oovz/btr6nX4B6lK/kd5uevvumAzrBAX7P2ukgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0Oovz%2Fbtr6nX4B6lK%2Fkd5uevvumAzrBAX7P2ukgK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1582&quot; height=&quot;952&quot; data-origin-width=&quot;1582&quot; data-origin-height=&quot;952&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;위 사진이 self-hosted와 hosted의 차이이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;여기서 내가 궁금 했던 점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;self-hosted runner에서 빌드,배포를 할 경우 배포할 서버에서 파일이 갱신되므로 배포까지 바로바로 진행이 된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;하지만 Github-hosted인 경우는 빌드,배포가 Github runner 서버에서 진행이 될뿐 내가 배포되길 원하는 서버에 배포를 하려면 어떻게 해야하는가이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;사실 여기에는 여러가지 방법이 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. dockerhub에 이미지 파일을 만든후 Rsycn 툴을 이용해 원격에 있는 서버(내가 배포할 서버) 에 파일을 옮기고 ssh 접근으로 명령어 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2. aws codeDeploy + S3로 배포 후 ssh 접근으로 명령어 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;등등 이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #051922;&quot;&gt;(Rsync(Remoe Sync)는 원격에 있는 파일과 디렉토리를 복사하고 동기화 하기 위해서 사용하는 툴이며 동시에 네트워크 프로토콜이다) 안써도 배포가능&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #051922;&quot;&gt;나는 1번방식을 접해 보았다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #051922;&quot;&gt;Rsync는 처음 보는 용어이고 이걸 어떻게 사용하는지 어렵다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #051922;&quot;&gt;그래서 Gitbub marketPlace에 사용하기 쉽게 만들어진 코드들이 많다&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #051922;&quot;&gt;예를들어&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #051922;&quot;&gt;&lt;a href=&quot;https://github.com/easingthemes/ssh-deploy&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/easingthemes/ssh-deploy&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1679912433961&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - easingthemes/ssh-deploy: GitHub Action for deploying code via rsync over ssh. (with NodeJS)&quot; data-og-description=&quot;GitHub Action for deploying code via rsync over ssh. (with NodeJS) - GitHub - easingthemes/ssh-deploy: GitHub Action for deploying code via rsync over ssh. (with NodeJS)&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/easingthemes/ssh-deploy&quot; data-og-url=&quot;https://github.com/easingthemes/ssh-deploy&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/h94GS/hyR39pRM5a/NQPHLOWQlcGZ7LTnOVuwK1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/easingthemes/ssh-deploy&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/easingthemes/ssh-deploy&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/h94GS/hyR39pRM5a/NQPHLOWQlcGZ7LTnOVuwK1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - easingthemes/ssh-deploy: GitHub Action for deploying code via rsync over ssh. (with NodeJS)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;GitHub Action for deploying code via rsync over ssh. (with NodeJS) - GitHub - easingthemes/ssh-deploy: GitHub Action for deploying code via rsync over ssh. (with NodeJS)&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이런 방식이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이해하기 쉽게 코드를 보자&amp;nbsp; (github marketplace에서 지원된 코드를 많이 사용한 코드) -사용법만 알면 상당히 편리하다&lt;/p&gt;
&lt;pre id=&quot;code_1679912610214&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;name: deploy

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-20.04
    steps:
      - uses: actions/checkout@v3
      - uses: gradle/wrapper-validation-action@v1
      - uses: docker/setup-qemu-action@v2
      - uses: docker/setup-buildx-action@v2
      - name: Login to DockerHub                        //도커허브 로그인
        uses: docker/login-action@v2              //github marketplace에서 지원 
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      - name: Build and Push a Main Docker Image   //dockerhub에 이미지 올리기
        uses: docker/build-push-action@v3
        with:
          context: .
          platforms: linux/amd64,linux/arm64
          push: true
          tags: myunghyunnero/test:latest
      - name: Deploy Main Docker Compose Production Configuration    //내 서버에 이미지 배포
        uses: easingthemes/ssh-deploy@v2         //github marketplace에서 지원
        env:
          REMOTE_HOST: ${{ secrets.REMOTE_SSH_HOST }}
          REMOTE_PORT: ${{ secrets.REMOTE_SSH_PORT }}
          REMOTE_USER: ${{ secrets.REMOTE_SSH_USERNAME }}
          SSH_PRIVATE_KEY: ${{ secrets.REMOTE_SSH_KEY }}
          SOURCE: .deploy/
          ARGS: -avz --delete
          TARGET: ${{ secrets.REMOTE_TARGET }}   
      - name: Run Main Docker                 //내 서버에서 도커 이미지 실행
        uses: appleboy/ssh-action@master    //github marketplace에서 지원
        env:
          TARGET: ${{ secrets.REMOTE_TARGET }}
        with:
          host: ${{ secrets.REMOTE_SSH_HOST }}
          port: ${{ secrets.REMOTE_SSH_PORT }}
          username: ${{ secrets.REMOTE_SSH_USERNAME }}
          key: ${{ secrets.REMOTE_SSH_KEY }}
          envs: TARGET
          script_stop: true
          script: |
            cd $TARGET
            docker compose -f docker-compose-production.yml pull
            docker compose -f docker-compose-production.yml up -d test
            docker image prune -af&lt;/code&gt;&lt;/pre&gt;</description>
      <category>기타</category>
      <category>CI/CD</category>
      <category>docker</category>
      <category>dockerhub</category>
      <category>github action</category>
      <category>Runner</category>
      <category>도커</category>
      <category>도커허브</category>
      <category>배포</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/145</guid>
      <comments>https://aimk12.tistory.com/145#entry145comment</comments>
      <pubDate>Mon, 27 Mar 2023 19:30:06 +0900</pubDate>
    </item>
    <item>
      <title>aws CloudFront + S3</title>
      <link>https://aimk12.tistory.com/144</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번에 프로젝트를 하면서 Security, Swagger 서버에 배포하기 , S3 등등 다양한 걸 많이 접하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러다가 S3를 이용할 때 CloudFront 라는 CDN 서비스를 같이 사용하면 비용 + 성능 면에서 좋아지는 것을 지인을 통해 알게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;CloudFront란&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- AWS에서 제공하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;CDN(Content delivery network)&lt;span&gt;&amp;nbsp;&lt;/span&gt;서비스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;CDN이란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;&amp;nbsp;&lt;b&gt;콘텐츠 전송 네트워크로써 지리, 물리적으로 떨어져 있는 사용자에게 컨텐츠를 더 빠르게 제공하는 시스템&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;(사용자와 가까운 곳에 위치한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Cache Server&lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;에 해당&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Content&lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;를 저장(캐싱)하고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Content&lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;요청시에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Cache Server&lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;가 응답을 주면서 속도 개선)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 데이터 접근할 때&amp;nbsp; 쓰이는 캐시 메모리나 웹페이지에 송수신 할 떄 쓰이는 캐시와 비슷한 개념이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;748&quot; data-origin-height=&quot;746&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5x3Jp/btrZkTmHw0T/arii4KZ38pCRL0BOJiLPnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5x3Jp/btrZkTmHw0T/arii4KZ38pCRL0BOJiLPnK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5x3Jp/btrZkTmHw0T/arii4KZ38pCRL0BOJiLPnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5x3Jp%2FbtrZkTmHw0T%2Farii4KZ38pCRL0BOJiLPnK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;463&quot; height=&quot;462&quot; data-origin-width=&quot;748&quot; data-origin-height=&quot;746&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 사진 처럼 세계 곳곳에 서버를 설치해 거리가 먼 사용자라도&amp;nbsp; 가까운 CDN을 통해 정보를 제공 받게 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;동작 방식&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자로부터 요청이 발생합니다.&lt;/li&gt;
&lt;li&gt;요청이 발생한 Edge Server는 요청이 발생한 데이터에 대하여 캐싱 여부를 확인합니다.&lt;/li&gt;
&lt;li&gt;캐싱 데이터가 존재하면 사용자에 요청에 맞게 응답하고 존재하지 않으면 Origin Server로 요청합니다.&lt;/li&gt;
&lt;li&gt;요청 받은 데이터에 대해 Origin Server로부터 전달 받은 Edge Server는 캐싱 데이터를 생성하고 사용자에게 응답합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;CDN의 장단점&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장점:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;데이터 제공 받는 속도 빠름&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;트래픽 급증 처리 가능&lt;/b&gt;&lt;br /&gt;하나의 Origin Serve로 수많은 사용자가 몰리는 것 방지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단점:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;단일 장애 지점&lt;/b&gt;&lt;br /&gt;시스템 하나가 잘못되면 전체 시스템을 사용 못 할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;불필요한 여러개의 네트워크 연결&lt;/b&gt;&lt;br /&gt;특정 지역에서 서비스하는 즉, 타겟팅이 분명한 곳은 불필요하게 연결해야하는 네트워크 수가 많아 오히려 데이터 제공 시간이 지연될 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이제 cloudfront와 s3를 이용해보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 Iam을 통해 S3권한을 받은 사용자를 만들 었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;617&quot; data-origin-height=&quot;234&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cY1tF6/btrZc8zyKhk/EZZVdbtKWnIkDTLiJ8rMQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cY1tF6/btrZc8zyKhk/EZZVdbtKWnIkDTLiJ8rMQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cY1tF6/btrZc8zyKhk/EZZVdbtKWnIkDTLiJ8rMQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcY1tF6%2FbtrZc8zyKhk%2FEZZVdbtKWnIkDTLiJ8rMQK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;258&quot; height=&quot;98&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;617&quot; data-origin-height=&quot;234&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;226&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwWtM1/btrZex6IaeP/Ks8PNjPOoJtk0KHuIKP700/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwWtM1/btrZex6IaeP/Ks8PNjPOoJtk0KHuIKP700/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwWtM1/btrZex6IaeP/Ks8PNjPOoJtk0KHuIKP700/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwWtM1%2FbtrZex6IaeP%2FKs8PNjPOoJtk0KHuIKP700%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;278&quot; height=&quot;109&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;226&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 accessKey와 SecretKey를 받을 수 있고 이 값들이 있어야 S3 접근에 대한 권한이 생긴다.( 보안적으로 좋아짐)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 S3를 만들고 cloudFront를 만든다. (저는 일단 기본값으로 세팅했습니다) -더 구체적인 것은 공부가 필요해 보이네요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cloudFront를 생성할 때 원본도메인에 내가 만들었던&amp;nbsp; S3 주소가 나오게 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1338&quot; data-origin-height=&quot;968&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cyXGN7/btrZdd1LtIT/RXaVHF63KxquwOec2sQDkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cyXGN7/btrZdd1LtIT/RXaVHF63KxquwOec2sQDkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cyXGN7/btrZdd1LtIT/RXaVHF63KxquwOec2sQDkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcyXGN7%2FbtrZdd1LtIT%2FRXaVHF63KxquwOec2sQDkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;411&quot; height=&quot;297&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1338&quot; data-origin-height=&quot;968&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 cloudfront가 s3에 연동되고 cloudFront의 도메인이 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 기존에 S3Service 만들때 버킷 주소를 cloudFront 도메인으로 수정하면 끝!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 작성한 S3Service 코드&lt;/p&gt;
&lt;pre id=&quot;code_1676363673228&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
@NoArgsConstructor
public class S3Service {
    private AmazonS3 s3Client;

    public static final String CLOUD_FRONT_DOMAIN_NAME = &quot;{cloudFront 도메인 주소}&quot;;

    @Value(&quot;${cloud.aws.credentials.access-key}&quot;)
    private String accessKey;   //S3접근할 키

    @Value(&quot;${cloud.aws.credentials.secret-key}&quot;)
    private String secretKey;  //S3접근할 키

    @Value(&quot;${cloud.aws.s3.bucket}&quot;)
    private String bucket;

    @Value(&quot;${cloud.aws.region.static}&quot;)
    private String region;

    @PostConstruct
    public void setS3Client() {
        AWSCredentials credentials = new BasicAWSCredentials(this.accessKey, this.secretKey);

        s3Client = AmazonS3ClientBuilder.standard()
            .withCredentials(new AWSStaticCredentialsProvider(credentials))
            .withRegion(this.region)
            .build();
    }

    public String upload(MultipartFile multipartFile) throws IOException {
        String fileName = UUID.randomUUID().toString();
        String extension = StringUtils.trimToNull(FilenameUtils.getExtension(multipartFile.getOriginalFilename()));
        String s3FileName = (extension != null) ? (fileName + &quot;.&quot; + extension) : fileName;

        //파일 사이즈를 s3에 알려줌
        ObjectMetadata objMeta = new ObjectMetadata();
        objMeta.setContentLength(multipartFile.getInputStream().available());
        objMeta.setContentType(multipartFile.getContentType());  //컨텐트타입 지정해줘야 안드로이드 단에서 사진을 사용가능 
        //안알려주면 사진이 크롬에 띄워지는게 아니라 다운을 받게됨

        s3Client.putObject(bucket, s3FileName, multipartFile.getInputStream(), objMeta);

        return CLOUD_FRONT_DOMAIN_NAME + &quot;/&quot; + s3FileName;  //저장경로 반환
    }

    public void deleteFile(String fileName) {
        s3Client.deleteObject(new DeleteObjectRequest(bucket, fileName));
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>기타</category>
      <category>AWS</category>
      <category>CDN</category>
      <category>cloudfront</category>
      <category>S3</category>
      <category>SpringBoot</category>
      <category>스프링부트</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/144</guid>
      <comments>https://aimk12.tistory.com/144#entry144comment</comments>
      <pubDate>Tue, 14 Feb 2023 17:39:22 +0900</pubDate>
    </item>
    <item>
      <title>Swagger + Security 적용</title>
      <link>https://aimk12.tistory.com/143</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;팀 프로젝트를 하다가 api관리를 하면 좋겠다는 생각이 들었고 보기 편하게 되면 같이 작업하시는 분들한테도 좋고 나한테도 좋을 것이라 생각했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그걸 위한 Swagger가 존재한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;심지어 설정도 매우 쉬운 편이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swagger를 설정해 보자&lt;/p&gt;
&lt;pre id=&quot;code_1674659347373&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@EnableSwagger2
public class SwaggerConfig {
    private final String version = &quot;v1&quot;;

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
            .title(&quot;API&quot;)
            .description(&quot;설명&quot;)
            .build();
    }

    @Bean
    public Docket api() {
        return new Docket(DocumentationType.OAS_30)
            .securityContexts(Arrays.asList(securityContext()))
            .securitySchemes(Arrays.asList(apiKey()))
            .select()
            .apis(RequestHandlerSelectors.basePackage(&quot;com.swagger.controller&quot;))
            .paths(PathSelectors.any())
            .build()
            ;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;@EnableSwagger2&lt;/b&gt; -Swagger2 버전을 활성화 하겠다는 어노테이션&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Docket&amp;nbsp;&lt;/b&gt; - Swager 설정의 핵심이되는 Bean&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;select()&lt;/b&gt; - ApiSelectorBuilder를 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;apis()&lt;/b&gt; -api 스펙이 작성되어 있는 패키지를 지정하여, 컨트롤러가 존재하는 패키지를&amp;nbsp;basepackage&amp;nbsp;&lt;span&gt;로 지정하여, RequestMapping(GetMapping, PostMapping&amp;hellip;)이 선언된 API를 문서화&lt;span&gt; (저 위코드에서는 com.swagger.controller 밑에 있는 모든 api 포함)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;paths() &lt;/b&gt;-apis()로 선택되어진 API 증 특정 path 조건에 맞는 APi들을 다시 필터링하여 문서화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;apiInfo()&lt;/b&gt;- 제목, 설명 등 문서에 대한 정보들을 보여주기 위해 호출&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 설정만 하면 나는 오류가 나왔다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 Spring security를 사용했기 때문에&amp;nbsp; swagger관련된 url을 열어줘야 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;b&gt;SecurityConfig&lt;/b&gt;에 등록&amp;nbsp; ( security가 최신 버전으로 바뀌면서 기존 코드들이랑 달라 찾는데 좀 걸렸다.. )&lt;/p&gt;
&lt;pre id=&quot;code_1674659762209&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -&amp;gt; web.ignoring().antMatchers( &quot;/swagger-resources/**&quot;,
            &quot;/swagger-ui/**&quot;,
            &quot;/v3/api-docs&quot;,
            &quot;/webjars/**&quot;);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 나는&lt;b&gt; jwt를 통한 인증&lt;/b&gt;도 구현하고 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 swagger 내부에 인증을 담고 싶었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 된 코드&lt;/p&gt;
&lt;pre id=&quot;code_1674660009374&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private SecurityContext securityContext() {
        return SecurityContext.builder()
            .securityReferences(defaultAuth())
            .build();
    }

    private List&amp;lt;SecurityReference&amp;gt; defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope(&quot;global&quot;, &quot;accessEverything&quot;);
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        return Arrays.asList(new SecurityReference(&quot;Authorization&quot;, authorizationScopes));
    }

    private ApiKey apiKey() {
        return new ApiKey(&quot;Authorization&quot;, &quot;Authorization&quot;, &quot;header&quot;);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 코드&lt;/p&gt;
&lt;pre id=&quot;code_1674660057903&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@EnableSwagger2
public class SwaggerConfig {
    private final String version = &quot;v1&quot;;

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
            .title(&quot;API&quot;)
            .description(&quot;설명&quot;)
            .build();
    }

    @Bean
    public Docket api() {
        return new Docket(DocumentationType.OAS_30)
            .securityContexts(Arrays.asList(securityContext()))
            .securitySchemes(Arrays.asList(apiKey()))
            .select()
            .apis(RequestHandlerSelectors.basePackage(&quot;com.swagger.controller&quot;))
            .paths(PathSelectors.any())
            .build()
            ;
    }

    private SecurityContext securityContext() {
        return SecurityContext.builder()
            .securityReferences(defaultAuth())
            .build();
    }

    private List&amp;lt;SecurityReference&amp;gt; defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope(&quot;global&quot;, &quot;accessEverything&quot;);
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        return Arrays.asList(new SecurityReference(&quot;Authorization&quot;, authorizationScopes));
    }

    private ApiKey apiKey() {
        return new ApiKey(&quot;Authorization&quot;, &quot;Authorization&quot;, &quot;header&quot;);
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1958&quot; data-origin-height=&quot;1036&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brWUv4/btrW6qIYqwA/vHA93eXVq6q9CyIG9JAEDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brWUv4/btrW6qIYqwA/vHA93eXVq6q9CyIG9JAEDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brWUv4/btrW6qIYqwA/vHA93eXVq6q9CyIG9JAEDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrWUv4%2FbtrW6qIYqwA%2FvHA93eXVq6q9CyIG9JAEDk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;658&quot; height=&quot;348&quot; data-origin-width=&quot;1958&quot; data-origin-height=&quot;1036&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;390&quot; data-origin-height=&quot;204&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqmiBx/btrXaDUK2Jh/DAqmwpKY7fX0jzIGoPGXSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqmiBx/btrXaDUK2Jh/DAqmwpKY7fX0jzIGoPGXSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqmiBx/btrXaDUK2Jh/DAqmwpKY7fX0jzIGoPGXSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdqmiBx%2FbtrXaDUK2Jh%2FDAqmwpKY7fX0jzIGoPGXSK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;250&quot; height=&quot;131&quot; data-origin-width=&quot;390&quot; data-origin-height=&quot;204&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;권한 표시도 잘 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;권한에 내가 원하는 토큰 값을 넣고 url 실행!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;830&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oEBdY/btrW9lUKb1c/9HnMlhGzBzSM2R03B2jqo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oEBdY/btrW9lUKb1c/9HnMlhGzBzSM2R03B2jqo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oEBdY/btrW9lUKb1c/9HnMlhGzBzSM2R03B2jqo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoEBdY%2FbtrW9lUKb1c%2F9HnMlhGzBzSM2R03B2jqo1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2404&quot; height=&quot;830&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;830&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성공!!&lt;/p&gt;</description>
      <category>기타</category>
      <category>API</category>
      <category>jwt</category>
      <category>SWAGGER</category>
      <category>스웨거</category>
      <category>인증</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/143</guid>
      <comments>https://aimk12.tistory.com/143#entry143comment</comments>
      <pubDate>Thu, 26 Jan 2023 00:24:17 +0900</pubDate>
    </item>
    <item>
      <title>Spring Security 공부 + Jwt 적용</title>
      <link>https://aimk12.tistory.com/142</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀 프로젝트를 하면서 여태껏 추상적으로만 알았던 개념들을 구체화 시킨 것들이 많아 졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중에 하나가 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Security&lt;/b&gt;&lt;/span&gt;이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 Spring Security를 공부하면서 당연하지만 잊지 말아야 하는건 Security는 우리의 편의를 위해 만들어진 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 스트레스 받지 말장... (시큐리티 버전이 업그레이드 되면서 메서드가 많이 달라짐... )&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;1208&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pvUIv/btrW4E1KfmH/O53KK5WkYliI1ydqmNncv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pvUIv/btrW4E1KfmH/O53KK5WkYliI1ydqmNncv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pvUIv/btrW4E1KfmH/O53KK5WkYliI1ydqmNncv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpvUIv%2FbtrW4E1KfmH%2FO53KK5WkYliI1ydqmNncv0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;765&quot; height=&quot;461&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;1208&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난 처음에 이 사진을 보고 이게 도대레 뭔 소리인지 감이 안잡히고 스트레스 받았었다...  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 공부를 하고 난 후 이 그림은 그냥 완벽한 그림이다...&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 이해가 안되고 헷갈렸던 부분은 &lt;b&gt;UserDetails&lt;/b&gt;이다... 아니 User라는 객체를 만들었는데 UserDetails는 뭘까...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것 또한 개발의 편의를 위해 만들어진 것이다.&amp;nbsp; 아래 코드가 UserDetails를 구현한 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1674652997582&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Getter
@RequiredArgsConstructor
public class PrincipalUserDetails  implements UserDetails {

    private final User user;

    @Override
    public Collection&amp;lt;? extends GrantedAuthority&amp;gt; getAuthorities() {
        return Collections.singleton(new SimpleGrantedAuthority(RoleType.USER.getKey()));
    }

    @Override
    public String getPassword() {
        return user.getPassword();
    }

    @Override
    public String getUsername() {
        return user.getEmail();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 오버라이드 된 메서드들은 이름만 보면 쉽게 유추가 가능하다. 그런데 Authorities란&amp;nbsp; 뭘까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 우리가 임의로 유저에게 역할을 정해주는 것이다. 즉 일반 사용자 (ROLE_USER)가 있을 수도 있고 관리자(ROLE_ADMIN) 같은 역할들이 나누어 질 수 있다. 그럼 SecurityConfig를 만들어 구분짓게 할 수 있다.. 아래 코드를 보자&lt;/p&gt;
&lt;pre id=&quot;code_1674653303648&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean  //해당 메서의 리턴되는 오브젝트를 ioc로 등록해준다
    public BCryptPasswordEncoder encoderPwd(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
        http
                .csrf().disable()//admin만 들어 갈 수 있음
                .authorizeHttpRequests(authorize -&amp;gt; authorize
                        .requestMatchers(&quot;&quot;).authenticated()
                        .requestMatchers(&quot;/&quot;).authenticated()
                        .requestMatchers(&quot;/user/**&quot;).authenticated()  //권한이 있는 자만 들어올 수 있음
                        .requestMatchers(&quot;/admin/**&quot;).hasRole(&quot;ADMIN&quot;)  //시큐리티는 role변수에 ROLE_* 규칙으로 적어야함 그리고 hasRole()에는 ROLE_뺴고 뒤에 적어야
                        .anyRequest().permitAll() //이외의 url은 모든 사람 접근 허용
                )
        return http.build();
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 저 위에서 hasRole(&quot;ADMIN&quot;)을 보듯이 우리가 UserDetails에 저장된 권한을 보고 시큐리티가 알아서 걸러준다!&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이제 궁금한 게 authenticated() 이 부분이다! 사실 Spring Security는 기본적으로 /login url을 지원해 준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;706&quot; data-origin-height=&quot;410&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d3zqmq/btrW9pW0mZf/InoELV8gv21oInmVhctma1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d3zqmq/btrW9pW0mZf/InoELV8gv21oInmVhctma1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d3zqmq/btrW9pW0mZf/InoELV8gv21oInmVhctma1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd3zqmq%2FbtrW9pW0mZf%2FInoELV8gv21oInmVhctma1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;479&quot; height=&quot;278&quot; data-origin-width=&quot;706&quot; data-origin-height=&quot;410&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 loginpage를 따로 지정 할 수 있지만 일단 구조를 보기때문에 넘어가자&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;1208&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pvUIv/btrW4E1KfmH/O53KK5WkYliI1ydqmNncv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pvUIv/btrW4E1KfmH/O53KK5WkYliI1ydqmNncv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pvUIv/btrW4E1KfmH/O53KK5WkYliI1ydqmNncv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpvUIv%2FbtrW4E1KfmH%2FO53KK5WkYliI1ydqmNncv0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;431&quot; height=&quot;260&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;1208&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 이 그림을 보자 . &lt;b&gt;UserDetailService&lt;/b&gt;를 보자&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1674655826060&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
public class PrincipalDetailsService implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

    //시큐리티 session(내부 Authentication(내부 UserDetails))
    //함수 종료시 @AuthenticationPrincipal 어노테이션이 만들어진다.
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println(&quot;----&quot;);
        User user = userRepository.findByUsername(username);
        System.out.println(user);
        if(user != null){
            return new PrincipalDetails(user);
        }
        return null;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저기 loadUserByUsername이 로그인 할때 들어오는 username과 password를 DB값과 비교해주는 메서드 이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것도 디폴트 값으로 /login 이 호출되면 실행 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난 Jwt로 로그인을 구현 할 생각이다.&amp;nbsp; 그럼 &lt;b&gt;UsernamePasswordAuthenticationFilter&lt;/b&gt; 를 상속받아 필터를 추가하자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UsernamePasswordAuthenticationFilter 이란? 시큐리티필터체인에 있는 필터중 하나이고 유저 인증할때 쓰이는 필터이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1238&quot; data-origin-height=&quot;894&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/x9CWR/btrW38IxPnv/1kyVwZTWY29M47ECWOwMuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/x9CWR/btrW38IxPnv/1kyVwZTWY29M47ECWOwMuK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/x9CWR/btrW38IxPnv/1kyVwZTWY29M47ECWOwMuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fx9CWR%2FbtrW38IxPnv%2F1kyVwZTWY29M47ECWOwMuK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;629&quot; height=&quot;454&quot; data-origin-width=&quot;1238&quot; data-origin-height=&quot;894&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 json으로 로그인 정보를 받을려고 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1674657032333&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@RequiredArgsConstructor
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private final AuthenticationManager authenticationManager;
    private final UserRepository userRepository;
    private ObjectMapper mapper = new ObjectMapper();



    //로그인 시도시 이 메서드 실행해서 Authentication에 담음

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        System.out.println(&quot;----------------------------&quot;);

        //Json으로 받기
        ServletInputStream inputStream = null;
        LoginDto helloData = null;
        try {
            inputStream = request.getInputStream();
            String msgBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
            System.out.println(&quot;msg Body = &quot; + msgBody);


            helloData = mapper.readValue(msgBody, LoginDto.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        String email = helloData.getEmail();
        String password = helloData.getPassword();
        System.out.println(email + &quot; &quot; +password);
        String encodedPassword = passwordEncoder.encode(password);

        Authentication authenticationToken = new UsernamePasswordAuthenticationToken(email, password);
        Authentication authentication =
                authenticationManager.authenticate(authenticationToken);

        PrincipalUserDetails principalDetailis = (PrincipalUserDetails) authentication.getPrincipal();
        System.out.println(&quot;Authentication : &quot;+principalDetailis.getUser().getEmail());
        return authentication;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이 필터를 보면 &lt;b&gt;authenticationManager&lt;/b&gt;가 보이고 이는 위에서 보던 구조 그림에서 나온 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;인증은 SpringSecurity의 AuthenticatonManager를 통해서 처리하게 되는데, 실질적으로는 AuthenticationManager에 등록된 AuthenticationProvider(구조그림에서 authenticationManager 다음에 나오는 것) 에 의해 처리된다. 인증이 성공하면 2번째 생성자를 이용해 인증이 성공한(isAuthenticated=true) 객체를 생성하여 Security Context에 저장&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 A&lt;b&gt;uthenticationProvider&lt;/b&gt;도 구현해보자 (구현안해도 돌아가긴하는데 내가 임의로 짤 수 있음)&lt;/p&gt;
&lt;pre id=&quot;code_1674657753989&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Component
//Authentication에 담은 정보를 DB와 일치하는지 체크
public class UserAuthenticationProvider implements AuthenticationProvider {

    private final UserDetailsService userDetailsService;
    private final PasswordEncoder passwordEncoder;



    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String email = authentication.getName();
        String password = (String) authentication.getCredentials();
        PrincipalUserDetails userDetails = (PrincipalUserDetails) userDetailsService.loadUserByUsername(email);
        // 비밀번호 확인
        if (!passwordEncoder.matches(password, userDetails.getPassword())) {
            throw new BadCredentialsException(&quot;비밀번호가 일치하지 않습니다.&quot;);
        }
		//이 토큰이 곧 인증 객체
        return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
    }

    @Override
    public boolean supports(Class&amp;lt;?&amp;gt; authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1238&quot; data-origin-height=&quot;894&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k54Y2/btrXaCO7xNi/bUAazHuw9TiiYiptF6KMyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k54Y2/btrXaCO7xNi/bUAazHuw9TiiYiptF6KMyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k54Y2/btrXaCO7xNi/bUAazHuw9TiiYiptF6KMyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk54Y2%2FbtrXaCO7xNi%2FbUAazHuw9TiiYiptF6KMyk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;478&quot; height=&quot;345&quot; data-origin-width=&quot;1238&quot; data-origin-height=&quot;894&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아까 봤던 구조에서 밑줄 친 곳 과 화살표를 보자 . 우리는 UsernamepasswordAuhtenticaiton을 통해 인증을 했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 그 결과에 대한 값이 있어야 되야 한다. 그걸 위한게 저 AuthenticaitonSuccessHandler 와 AuthenticaitonFailureHandler&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;AuthenticaitonSuccessHandler&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1674658151627&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@RequiredArgsConstructor
@Component
//로그인 성공시 처리 클래스
public class UserSuccessHandler implements AuthenticationSuccessHandler {

    private final UserRepository userRepository;
    private final JwtService jwtService;

    @Transactional
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        PrincipalUserDetails userDetails = (PrincipalUserDetails) authentication.getPrincipal();
        User user = userRepository.findByEmail(userDetails.getUsername())
                .orElseThrow(() -&amp;gt; new UsernameNotFoundException(&quot;가입된 이메일이 존재하지 않습니다.&quot;));

        // JWT Token 생성 &amp;amp; Response
        String accessToken = jwtService.createAccessToken(user.getEmail(), user.getId());
        String refreshToken = jwtService.createRefreshToken(user.getEmail());
        user.updateRefreshToken(refreshToken);
        response.setContentType(APPLICATION_JSON_VALUE);
        LoginTokenRes loginTokenRes = new LoginTokenRes(accessToken,refreshToken,signYN);
        new ObjectMapper().writeValue(response.getWriter(), new BaseResponse(loginTokenRes));
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성공하면 jwt 반환!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;그럼 여기서 궁금점?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;로그인을 하는 것은 좋다. 그럼 로그인해서 얻은 jwt로 다른 화면도 들어갈텐데 그때도 필터가 필요하지 않을까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 해결법은 간단하다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;일단 jwt를 가지고 인증하는 필터를 만든다 .&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;securityConfig의&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;filterchain 메서드에 http&lt;span style=&quot;background-color: #ffffff;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;addFilter&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;JwtAuthorizationFilter&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;authenticationManager&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;userRepository&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;));&lt;/span&gt; 를 추가해&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;인증 전에 내가 만든 필터를 거치게 한다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;코드를 보자&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;로그인 후 jwt가지고 접근 할 때 필터&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1674658817477&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 인가  BasicAuthenticationFilter 권한 인증 들어올때 실행됨
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {

    private UserRepository userRepository;

    public JwtAuthorizationFilter(AuthenticationManager authenticationManager, UserRepository userRepository) {
        super(authenticationManager);
        this.userRepository = userRepository;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        String header = request.getHeader(JwtProperties.HEADER_STRING);
        if(header == null || !header.startsWith(JwtProperties.TOKEN_PREFIX)) {
            chain.doFilter(request, response);
            return;
        }
        System.out.println(&quot;header : &quot;+header);
        String token = request.getHeader(JwtProperties.HEADER_STRING)
                .replace(JwtProperties.TOKEN_PREFIX, &quot;&quot;);

        // 토큰 검증 (이게 인증이기 때문에 AuthenticationManager도 필요 없음)
        // 내가 SecurityContext에 집적접근해서 세션을 만들때 자동으로 UserDetailsService에 있는 loadByUsername이 호출됨.
        String username = JWT.require(Algorithm.HMAC512(JwtProperties.SECRET)).build().verify(token)
                .getClaim(&quot;username&quot;).asString();

        if(username != null) {
            User user = userRepository.findByUsername(username);

            // 인증은 토큰 검증시 끝. 인증을 하기 위해서가 아닌 스프링 시큐리티가 수행해주는 권한 처리를 위해
            // 아래와 같이 토큰을 만들어서 Authentication 객체를 강제로 만들고 그걸 세션에 저장!
            PrincipalDetails principalDetails = new PrincipalDetails(user);
            Authentication authentication =
                    new UsernamePasswordAuthenticationToken(
                            principalDetails, //나중에 컨트롤러에서 DI해서 쓸 때 사용하기 편함.
                            null, // 패스워드는 모르니까 null 처리, 어차피 지금 인증하는게 아니니까!!
                            principalDetails.getAuthorities());

            // 강제로 시큐리티의 세션에 접근하여 값 저장
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }

        chain.doFilter(request, response);
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드를 보면 헤더에 아무 것도 없으면 이 필터는 거치지 않게 한다-&amp;gt; 로그인 진행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;헤더에 jwt가 있으면 로그인이 된 것이므로 적절한 jwt인지 검증 거치게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;요약&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1 .Security는 우리가 만든 User 객체에 Userdetail을 감싸고 그 위에 authentication을 감싸고 인증이 이루어 진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2 .인증은 시큐리티 안에 있는 필터인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;UsernamepasswordAuhtenticaitonFilter를 만들고 그 안에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;authenticationManager 을 이용한 인증을 한다. (이 안에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;AuthenticationProvider을 이용한 인증 그리고 그 안에 UserDetailService 안에 정의된&lt;span&gt;&amp;nbsp;&lt;/span&gt;loadUserByUsername를 통한 db값 비교) 이 과정을 통한 로그인 인증이 된다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>기타</category>
      <category>jwt</category>
      <category>Security</category>
      <category>Spring</category>
      <category>스프링</category>
      <category>시큐리티</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/142</guid>
      <comments>https://aimk12.tistory.com/142#entry142comment</comments>
      <pubDate>Thu, 26 Jan 2023 00:04:20 +0900</pubDate>
    </item>
    <item>
      <title>백준 14725번 : 개미굴 (트라이)</title>
      <link>https://aimk12.tistory.com/141</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/14725&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/14725&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1673846309767&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;14725번: 개미굴&quot; data-og-description=&quot;첫 번째 줄은 로봇 개미가 각 층을 따라 내려오면서 알게 된 먹이의 정보 개수 N개가 주어진다. &amp;nbsp;(1 &amp;le; N &amp;le; 1000) 두 번째 줄부터 N+1 번째 줄까지, 각 줄의 시작은 로봇 개미 한마리가 보내준 먹이 &quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/14725&quot; data-og-url=&quot;https://www.acmicpc.net/problem/14725&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bu1XXP/hyRiX4dIIg/qQNarDZcY1Zln9VIDABC30/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480,https://scrap.kakaocdn.net/dn/ktMIC/hyRi4ChRKQ/Uv4CyRft1hqRifvxvg71jK/img.png?width=1503&amp;amp;height=785&amp;amp;face=0_0_1503_785&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/14725&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/14725&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bu1XXP/hyRiX4dIIg/qQNarDZcY1Zln9VIDABC30/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480,https://scrap.kakaocdn.net/dn/ktMIC/hyRi4ChRKQ/Uv4CyRft1hqRifvxvg71jK/img.png?width=1503&amp;amp;height=785&amp;amp;face=0_0_1503_785');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;14725번: 개미굴&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;첫 번째 줄은 로봇 개미가 각 층을 따라 내려오면서 알게 된 먹이의 정보 개수 N개가 주어진다. &amp;nbsp;(1 &amp;le; N &amp;le; 1000) 두 번째 줄부터 N+1 번째 줄까지, 각 줄의 시작은 로봇 개미 한마리가 보내준 먹이&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 풀 떄 트라이라는 자료구조를 알고 풀면 더 쉽게 접근이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 나도 트라이라는 것이 생소해서 공부를 시작하고 풀었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 문제를 풀때 다른 사람 코드를 참조했다...(아직 트라이는 어색하다..ㅜㅜ)&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;트라이란?&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 말해서 트리구조이다. 이걸 문자열에 특화되게 만든게 트라이 라는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(처음에는 포인터 부분이 약해 이해가 잘 안되는데 그냥 해당 노드에 들어있는 child에 들어가는 값을 각 층별로 들어있는 값이라 생각하면 된다. )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 내가 공부한 블로그이다. (많은 도움이 되었습니당...)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://rebro.kr/86&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://rebro.kr/86&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1673846465549&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[자료구조] 트라이(Trie) 자료구조&quot; data-og-description=&quot;[목차] 1. 트라이(Trie) 자료구조란? 2. 트라이(Trie)의 작동 원리 3. 트라이(Trie) 자료구조의 장/단점 4. 트라이(Trie) 자료구조의 구현 5. 트라이(Trie) 예제 문제 1. 트라이(Trie) 자료구조란? 트라이(Trie)는&quot; data-og-host=&quot;rebro.kr&quot; data-og-source-url=&quot;https://rebro.kr/86&quot; data-og-url=&quot;https://rebro.kr/86&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dc76Aq/hyRhIHCbL8/f1bhtKtkBOdJXttH9R5fF0/img.png?width=557&amp;amp;height=530&amp;amp;face=0_0_557_530,https://scrap.kakaocdn.net/dn/0M2wZ/hyRhOuhZ1g/mAkXpd4NVW6GvmdHMuLoRk/img.png?width=557&amp;amp;height=530&amp;amp;face=0_0_557_530,https://scrap.kakaocdn.net/dn/looM0/hyRi6UqaaW/MmI8jiq7PF4lE2oK5Crut0/img.png?width=557&amp;amp;height=530&amp;amp;face=0_0_557_530&quot;&gt;&lt;a href=&quot;https://rebro.kr/86&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://rebro.kr/86&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dc76Aq/hyRhIHCbL8/f1bhtKtkBOdJXttH9R5fF0/img.png?width=557&amp;amp;height=530&amp;amp;face=0_0_557_530,https://scrap.kakaocdn.net/dn/0M2wZ/hyRhOuhZ1g/mAkXpd4NVW6GvmdHMuLoRk/img.png?width=557&amp;amp;height=530&amp;amp;face=0_0_557_530,https://scrap.kakaocdn.net/dn/looM0/hyRi6UqaaW/MmI8jiq7PF4lE2oK5Crut0/img.png?width=557&amp;amp;height=530&amp;amp;face=0_0_557_530');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[자료구조] 트라이(Trie) 자료구조&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;[목차] 1. 트라이(Trie) 자료구조란? 2. 트라이(Trie)의 작동 원리 3. 트라이(Trie) 자료구조의 장/단점 4. 트라이(Trie) 자료구조의 구현 5. 트라이(Trie) 예제 문제 1. 트라이(Trie) 자료구조란? 트라이(Trie)는&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;rebro.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 다시 본론으로 돌아가서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 풀기 위해&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1 . 노드를 설정&amp;nbsp; (사전순으로 정렬이 필요하기해 Map 자료구조를 이용해서 자동으로 정렬되게 만들었다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. insert 함수를 만들어서 해당 문자열이 있으면 다음 층으로 넘어감&amp;nbsp; , 문자열이 없으면 새로운 노드를 만들고 연결시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 그리고 출력 방식을 보면 dfs로 탐색을 하는 것을 알 수 있다. 이를 신경써서 dfs 함수 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1673847552986&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;string&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;map&amp;gt;
using namespace std;

struct Trie{
	map&amp;lt;string, Trie*&amp;gt; child;
	
	void insert(vector&amp;lt;string&amp;gt; v, int depth) {
		if (depth == v.size()) return;
		string s = v[depth];
        map&amp;lt;string, Trie*&amp;gt;::iterator iter;
		iter = child.find(s);		
		if (iter != child.end()) 		
			iter-&amp;gt;second-&amp;gt;insert(v, depth + 1);    //해당 문자열이 있으면 다음 층으로 넘어감    
		else {
			Trie* n = new Trie;    //해당 문자열이 없으면 새로운 노드 생성후 연결
			child.insert({ s,n });
			n-&amp;gt;insert(v, depth + 1);
		}
	}
	void dfs(int depth) {
		if (child.empty()) return;

		for (auto it = child.begin(); it != child.end(); it++) {  //child는 각 층에 있는 값들 
			for (int i = 0; i &amp;lt; depth; i++)
				cout &amp;lt;&amp;lt; &quot;--&quot;;
			cout &amp;lt;&amp;lt; it-&amp;gt;first &amp;lt;&amp;lt; '\n';
			it-&amp;gt;second-&amp;gt;dfs(depth + 1);
		}
	}
};

int main() {
	ios_base::sync_with_stdio(false); 
    cin.tie(NULL);
     cout.tie(NULL);
	int num, index;
	Trie* root = new Trie;
	string s;
	cin &amp;gt;&amp;gt; num;
	for (int i = 0; i &amp;lt; num; i++) {
		cin &amp;gt;&amp;gt; index;
		vector&amp;lt;string&amp;gt; v;
		for (int j = 0; j &amp;lt; index; j++) {
			cin &amp;gt;&amp;gt; s;
			v.push_back(s);
		}
		root-&amp;gt;insert(v, 0);
	}
	root-&amp;gt;dfs(0);
	return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>백준 코딩</category>
      <category>14725</category>
      <category>개미굴</category>
      <category>문자열</category>
      <category>백준</category>
      <category>트라이</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/141</guid>
      <comments>https://aimk12.tistory.com/141#entry141comment</comments>
      <pubDate>Mon, 16 Jan 2023 14:39:46 +0900</pubDate>
    </item>
    <item>
      <title>컴퓨터 네트워크 개념 정리(CH.06 The Link Layer and LANs)</title>
      <link>https://aimk12.tistory.com/140</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Link Layer and LANS- 즉 이제는 2계층에 대해서 알아볼 것이다.&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;link layer는 한 노드에서 링크를 통해 물리적으로 인접한 노드에 데이터 그램을 보내줄 책임이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;통신 경로를 따라 인접 노드들을 연결 하는 통신 채널들을 link라고 함 (유선 링크,무선 링크 ,LANs)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대부분의 경우 링크 계층은 네트워크 인터페이스 카드(Network Interface Card, NIC)로 알려진&amp;nbsp;네트워크 어뎁터(network adapter)에 구현&lt;/li&gt;
&lt;li&gt;링크, 물리계층 구현&lt;/li&gt;
&lt;li&gt;호스트의 시스템 버스에 연결&lt;/li&gt;
&lt;li&gt;하드웨어, 소프트웨어, 펌웨어의 조합&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;934&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WUHa3/btrSLIyIpkF/64vEQaC0t8o9B9B9JNT2eK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WUHa3/btrSLIyIpkF/64vEQaC0t8o9B9B9JNT2eK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WUHa3/btrSLIyIpkF/64vEQaC0t8o9B9B9JNT2eK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWUHa3%2FbtrSLIyIpkF%2F64vEQaC0t8o9B9B9JNT2eK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;192&quot; height=&quot;224&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;934&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;link 계층에서 추상화된 소통&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1960&quot; data-origin-height=&quot;740&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWGEEf/btrSJaQuEIP/ByP9rIOc2a9vj5B57GWtXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWGEEf/btrSJaQuEIP/ByP9rIOc2a9vj5B57GWtXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWGEEf/btrSJaQuEIP/ByP9rIOc2a9vj5B57GWtXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWGEEf%2FbtrSJaQuEIP%2FByP9rIOc2a9vj5B57GWtXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;349&quot; height=&quot;132&quot; data-origin-width=&quot;1960&quot; data-origin-height=&quot;740&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;sending side : 프레임에 데이터그램 캡슐화 + 오류 검사 비트, rdt,&amp;nbsp;flow control&amp;nbsp;등을 추가&lt;/li&gt;
&lt;li&gt;receiver side : 오류, rdt, flow control 등을 확인, 데이터그램 추출, 수신 측 상위 계층 통과&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;error detection, correction &lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;EDC = Error Detection and Correction bits(redundancy) - 오류 감지 및 수정 비트(중복성)&lt;/li&gt;
&lt;li&gt;D = 오류 검사로 보호되는 데이터, 헤더 필드가 포함될 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1114&quot; data-origin-height=&quot;686&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u2MI2/btrSHLYuR4h/XHt7zKnDROQznj7Catgz51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u2MI2/btrSHLYuR4h/XHt7zKnDROQznj7Catgz51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u2MI2/btrSHLYuR4h/XHt7zKnDROQznj7Catgz51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu2MI2%2FbtrSHLYuR4h%2FXHt7zKnDROQznj7Catgz51%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;243&quot; height=&quot;150&quot; data-origin-width=&quot;1114&quot; data-origin-height=&quot;686&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Parity checking&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;single bit parity : 한 비트의 에러를 검출&lt;/li&gt;
&lt;li&gt;two-dimensional bit parity :&amp;nbsp;2차원 패리티 기법&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1836&quot; data-origin-height=&quot;976&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GkFBE/btrSHUOk9cm/vsRhQU63wqNnKG2rtljf8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GkFBE/btrSHUOk9cm/vsRhQU63wqNnKG2rtljf8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GkFBE/btrSHUOk9cm/vsRhQU63wqNnKG2rtljf8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGkFBE%2FbtrSHUOk9cm%2FvsRhQU63wqNnKG2rtljf8K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;279&quot; height=&quot;148&quot; data-origin-width=&quot;1836&quot; data-origin-height=&quot;976&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Cyclic Redundancy Check (CRC)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2022&quot; data-origin-height=&quot;934&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTRDUT/btrSIRwPwg9/QV9krEPrxwxL7Lmg3HAE80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTRDUT/btrSIRwPwg9/QV9krEPrxwxL7Lmg3HAE80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTRDUT/btrSIRwPwg9/QV9krEPrxwxL7Lmg3HAE80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTRDUT%2FbtrSIRwPwg9%2FQV9krEPrxwxL7Lmg3HAE80%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;253&quot; height=&quot;117&quot; data-origin-width=&quot;2022&quot; data-origin-height=&quot;934&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*더 정확한 오류 검증&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;D,R&amp;gt; 을 G 로 나눌때 나머지가 0이 아니면 에러임&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나머지는 생성자보다 1bit 적게 적어야함 - (실제 전송할 데이터에서 생성자 나누면 나머지가 0이 아니면 오류임)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #000000;&quot;&gt;1100 1010&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;11010/10110110 0000&amp;nbsp; &amp;nbsp;--그럼 이렇게 0으로 나오게 됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;11010&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;11001&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;11010&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;11110&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;11010&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;0100. &amp;mdash; 이 것을 데이터프레임 뒤에 붙이면&lt;span&gt;&amp;nbsp;됨&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1292&quot; data-origin-height=&quot;636&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzHvC7/btrSKRJlKuQ/XCvvGKp7kA29hHxr26HgFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzHvC7/btrSKRJlKuQ/XCvvGKp7kA29hHxr26HgFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzHvC7/btrSKRJlKuQ/XCvvGKp7kA29hHxr26HgFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzHvC7%2FbtrSKRJlKuQ%2FXCvvGKp7kA29hHxr26HgFk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;358&quot; height=&quot;176&quot; data-origin-width=&quot;1292&quot; data-origin-height=&quot;636&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Multiple access links, protocols&lt;/b&gt;&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;point-to-point(ppp) -&lt;/li&gt;
&lt;li&gt;broadcast (shared wire or medium). - 데이터 공유하는데 어떻게 잘 보낼수 있는지&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;three broad classes:&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;channel partitioning -채널 분할&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;채널 분할해서 할당한 구간 사용가능&lt;/li&gt;
&lt;li&gt;주파수 분할해서 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;random access. &amp;mdash; 충돌이 일어날수 밖에 없음 - 어떻게 충돌회복을 할 것인가가 중요 - 단점 많은 데이터 충돌확률 증가&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;보낼거 있으면 그냥 보냄 -충돌&lt;/li&gt;
&lt;li&gt;pure ALOHA(동기화 필요없음 최대 효율성 18퍼) , Slotted ALOHA(충돌 덜 받게 개선된 방식- slot으로 나누어서 확 충돌이 나거나 안나게 만듬, 동기화 필수(시작점과 끝점 맞추면서 보내야함 ) , 장점:높은 분산성,단순함, 단점: 충돌나면 버려짐 최대 효율성 37퍼)&lt;/li&gt;
&lt;li&gt;CSMA(carrier sense multiple access) - 보낼려 할 때 다른 사람이 보내고 있는지 확인 (채널이 비었는지, 사용 중인지 체크)&lt;/li&gt;
&lt;li&gt;CSMA/CD - 충돌이 일어나면. 멈춰버림 (충돌 하는지 검사) (무선에서는 못씀) - NIC chooses K at random from {0,1,2, &amp;hellip;, 2m-1} 점차 2의 제곱승으로 기다리게 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;multiple access 3가지 - csma,csma/cd coma/ca(짧은 패킷으로 무선도 가능하게함)&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;taking turns. &amp;mdash; 차례로 보내게함&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;polling : 마스터가 통신의 주도권을 가지고 누구 데이터 보낼지 결정함. -단점 폴링 오버헤드 , 마스터 의존성 높음 (마스터 죽으면 망함) , 지연시간 기다려야함&lt;/li&gt;
&lt;li&gt;token passing : 연속적으로 돌아가며 토큰을 돌리고 사용할거면 토큰에 데이터 넣음 단점 - 토큰 오버헤드 ,의존성 높움, 지연시간&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;LANs(Local Area Network)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MAC address&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터 만들 때 생성 - 주민번호 느낌 (portability)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ARP: address resolution protocol&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;보내고자 하는 수신자 mac address 알아내기 위한 프로토콜&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ARP table:&amp;lt; IP address; MAC address; TTL&amp;gt;. : TTL 은 시간 별 갱신해줘야함 (ip가 달라질수 있기 때문)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동작&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;맥주소는 모르고 ip는 알고 있으니 broadcast로 일단 쿼리로 맥주소 알기 위한 요청&lt;/li&gt;
&lt;li&gt;그럼 맥주소 응답을 받게 됨&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Ethernet&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;사무실이나 가정에서 사용되는&amp;nbsp;LAN 중&amp;nbsp;가장 많이 활용되는 기술 규격이다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-99656bc5-419f-42c2-93df-f120d89ddc6e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- unreliable, connectionless 하다. (CSMA/CD방식을 사용한다)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;physical topology&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;bus방식 - 충돌이 자주 일어남(옛날 방식)&lt;/li&gt;
&lt;li&gt;switched. - 현재 쓰는 방식 충돌 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1994&quot; data-origin-height=&quot;526&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oyqSx/btrSJTgoLO7/R2QkqI79QMs6JNuXmydnL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oyqSx/btrSJTgoLO7/R2QkqI79QMs6JNuXmydnL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oyqSx/btrSJTgoLO7/R2QkqI79QMs6JNuXmydnL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoyqSx%2FbtrSJTgoLO7%2FR2QkqI79QMs6JNuXmydnL0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;511&quot; height=&quot;135&quot; data-origin-width=&quot;1994&quot; data-origin-height=&quot;526&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Ethernet switch&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;link 계층의 디바이스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- mac address에서 기반해서 이더넷 프레임을 store하고 forward한다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1c6d309d-e293-4a19-b5af-771041195f6b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- buffer가 있어 frame을 먼저 저장을 하고 해당 link로 전달한다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c762054b-0f23-4931-9676-988258e2b7cd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- switch는 point - to - point 통신을 하기 때문에 충돌이 생기지 않지만 CSMA/CD를 그대로 사용&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-92279b42-bddb-4445-be72-e52dc4a35cc7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- link switch는 host는 switch의 존재를 모른다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;self-learning - 스위치는 호스트가 인터페이스를 통해 도달될수있는지 스스로 학습한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정방향이 아니면 끝내주고 정방향이면(목적지 알고있으면) forwarding 해주고 flooding 모든 포트에 데이터를 뿌린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;라우터 vs 스위치&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라우터는 3, 스위치는 2계층&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘다 포워딩 테이블&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라우터는 알고리즘 으로 테이블 채움 switch는 self-learing으로 채움&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS</category>
      <category>Link Layer</category>
      <category>네트워크</category>
      <category>컴퓨터 네트워크</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/140</guid>
      <comments>https://aimk12.tistory.com/140#entry140comment</comments>
      <pubDate>Sat, 3 Dec 2022 18:56:47 +0900</pubDate>
    </item>
    <item>
      <title>컴퓨터 네트워크 개념 정리(CH.05 Network Layer:Control Plane)</title>
      <link>https://aimk12.tistory.com/139</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Network Layer : Control Plane 에 대해 알아보자&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 control 이란 목적지 까지 갈 때 어떤 라우터를 거쳐가야 최적의 경로인지 정하는 것이라고 생각하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Control 하는 데에는 두가지 방법이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 이전에 했던 Per-router control plane&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 라우터들이 서로 통신하며 알고리즘으로 계산&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1498&quot; data-origin-height=&quot;770&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KQLSI/btrSIqe9PQe/ozA39iY4R4BBobQTkKp5K0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KQLSI/btrSIqe9PQe/ozA39iY4R4BBobQTkKp5K0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KQLSI/btrSIqe9PQe/ozA39iY4R4BBobQTkKp5K0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKQLSI%2FbtrSIqe9PQe%2FozA39iY4R4BBobQTkKp5K0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;255&quot; height=&quot;131&quot; data-origin-width=&quot;1498&quot; data-origin-height=&quot;770&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2.Software-Defined Networking (SDN) control plane&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중앙에 라우팅 해주는 control server을 생성하고 거기서 라우터들 테이블을 알고리즘으로 계산에 적용해준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래는 라우터 - 하드웨어 프로토콜 등등 다 포함되어있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이제는 컨트롤 plane을 따로 뗴어내서 하나의 remote control 에서 정보 제공 - 네트워크 관리 쉬워짐&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1584&quot; data-origin-height=&quot;916&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oOR1o/btrSIsDX3xp/l2oQVklEqy0pbofJ0u48V1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oOR1o/btrSIsDX3xp/l2oQVklEqy0pbofJ0u48V1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oOR1o/btrSIsDX3xp/l2oQVklEqy0pbofJ0u48V1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoOR1o%2FbtrSIsDX3xp%2Fl2oQVklEqy0pbofJ0u48V1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;251&quot; height=&quot;145&quot; data-origin-width=&quot;1584&quot; data-origin-height=&quot;916&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Routing protocol : 보내는 자에서 받는 자 까지의 경로를 정해주는 역할&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크게 두가지가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.Link state (모든 라우터들이 다른 라우터에 대한 정보들을 가지고 있어야함)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Dijkstra&amp;rsquo;s link-state routing algorithm&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평소에 알고리즘 공부할 때 쓰이는 다익스트라 알고리즘&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최소 경로안 곳을 최우선으로 계산해 가며 목적지 도달&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1794&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Moe5b/btrSIQYZ2sf/UGFsbSitFpXK4KipgKJVNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Moe5b/btrSIQYZ2sf/UGFsbSitFpXK4KipgKJVNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Moe5b/btrSIQYZ2sf/UGFsbSitFpXK4KipgKJVNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMoe5b%2FbtrSIQYZ2sf%2FUGFsbSitFpXK4KipgKJVNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;562&quot; height=&quot;157&quot; data-origin-width=&quot;1794&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1794&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bagHFA/btrSKQjkR4M/GdW942pK1BGlHtDZKnkRLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bagHFA/btrSKQjkR4M/GdW942pK1BGlHtDZKnkRLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bagHFA/btrSKQjkR4M/GdW942pK1BGlHtDZKnkRLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbagHFA%2FbtrSKQjkR4M%2FGdW942pK1BGlHtDZKnkRLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;380&quot; height=&quot;106&quot; data-origin-width=&quot;1794&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2.Dintance Vector (물리적으로 연결되어 있는 인접한 이웃의 정보만 가지고 있으면 됨)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; Bellman-Ford algorithm&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 각각 이웃에 대한 코스트 정보 테이블을 만들고 이웃에 보낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 받은 테이블을 가지고 경로 최소 코스트로 재계산 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 만약 재계산 되면 그 테이블을 주변 이웃에 다시 보낸다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1916&quot; data-origin-height=&quot;868&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dKmrcF/btrSI9cTzDr/oZLF6k9a13CLP0Mv5f9kZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dKmrcF/btrSI9cTzDr/oZLF6k9a13CLP0Mv5f9kZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dKmrcF/btrSI9cTzDr/oZLF6k9a13CLP0Mv5f9kZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdKmrcF%2FbtrSI9cTzDr%2FoZLF6k9a13CLP0Mv5f9kZk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;446&quot; height=&quot;202&quot; data-origin-width=&quot;1916&quot; data-origin-height=&quot;868&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자세한 설명은 알고리즘으로 가서 생략&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이제 어떻게 라우터에 저장되는 최적 경로 테이블이 저장되는 방법을 알아 보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 여기서 문제가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 목적지 정보가 너무 커서 담을 수가 없다(부담이 크다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 라우팅을 관리 할 수 있는 규모로 분할 하게 하는게&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt; intra-AS routing&lt;/b&gt; (as: autonomous systems)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.as안에 있는 모든 라우터들은 같은 인트라 프로토콜에서 작동한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.다른as안에 있는 라우터들은 다른 다른 인트라 라우팅 프로토콜을 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3.gateway router: at &amp;ldquo;edge&amp;rdquo; of its own AS, has link(s) to router(s) in other AS&amp;rsquo;es&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; as안에 있는 모서리는 다른 as라우터와 연결을 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1684&quot; data-origin-height=&quot;568&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1qUHm/btrSHXROV0U/MUNBHshqUQiAB5Rvsy1Hk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1qUHm/btrSHXROV0U/MUNBHshqUQiAB5Rvsy1Hk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1qUHm/btrSHXROV0U/MUNBHshqUQiAB5Rvsy1Hk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1qUHm%2FbtrSHXROV0U%2FMUNBHshqUQiAB5Rvsy1Hk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;376&quot; height=&quot;127&quot; data-origin-width=&quot;1684&quot; data-origin-height=&quot;568&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;intra AS 라우팅 종류를 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. RIP(Routing Information Protocol )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. OSPF(Open Shortest Path First )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. EIGRP (Enhanced Interior Gateway Routing Protocol)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;OSPF(Open Shortest Path First ) 란?&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;open&amp;rdquo;: publicly available&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;link-state 알고리즘을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 계층성을 가지고 있다 이게 뭘 의미하냐면 link-state를 사용해 모든 라우터 정보를 가지기에는 부담이 있기에 계층화시켜서 나누는 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림을 보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2216&quot; data-origin-height=&quot;664&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qyaUl/btrSL1x8TrD/lqNCYDIQ1fzAqTipiu5Q41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qyaUl/btrSL1x8TrD/lqNCYDIQ1fzAqTipiu5Q41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qyaUl/btrSL1x8TrD/lqNCYDIQ1fzAqTipiu5Q41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqyaUl%2FbtrSL1x8TrD%2FlqNCYDIQ1fzAqTipiu5Q41%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;453&quot; height=&quot;664&quot; data-origin-width=&quot;2216&quot; data-origin-height=&quot;664&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Internet inter-AS routing: BGP&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BGP (Border Gateway Protocol)-&lt;span style=&quot;color: #000000;&quot;&gt; as 를 넘어갈때사용하는 프로토콜&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ebgp : 외부적에서 받을 정보 - 이웃 as 에게 받음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ibgp : 내부적에서 받을 정보 - 다른 모든 as에게 정보를 전파함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1570&quot; data-origin-height=&quot;936&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8I91a/btrSLIlarKW/oaTxOAOgWpsVY7k2gROmN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8I91a/btrSLIlarKW/oaTxOAOgWpsVY7k2gROmN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8I91a/btrSLIlarKW/oaTxOAOgWpsVY7k2gROmN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8I91a%2FbtrSLIlarKW%2FoaTxOAOgWpsVY7k2gROmN0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;384&quot; height=&quot;229&quot; data-origin-width=&quot;1570&quot; data-origin-height=&quot;936&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;BGP path advertisement&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;: 다른 as 에 보내기 위해 어떤 as 에 보내야하는지 알려줌&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1966&quot; data-origin-height=&quot;726&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dGDLdp/btrSKuUX1zB/StxBXkYn6gfKv6CmcQj7xk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dGDLdp/btrSKuUX1zB/StxBXkYn6gfKv6CmcQj7xk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dGDLdp/btrSKuUX1zB/StxBXkYn6gfKv6CmcQj7xk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdGDLdp%2FbtrSKuUX1zB%2FStxBXkYn6gfKv6CmcQj7xk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;446&quot; height=&quot;165&quot; data-origin-width=&quot;1966&quot; data-origin-height=&quot;726&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 여러개 inter-as 만드는 이유&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;policy - 관리자는 트래픽 라우팅을 컨트롤하고 누가 네트워크를 이용하는지 제어하기 원함&lt;/li&gt;
&lt;li&gt;scale - 계층화가 되어야 트래픽 줄고 편함&lt;/li&gt;
&lt;li&gt;performance - 수행이 더 좋고 가격이 쌈&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Hot potato routing&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;인트라 도메인 비용이 가장 적은 로컬게이트웨이를 선택해야하는 것&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2130&quot; data-origin-height=&quot;1150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnckOm/btrSJTAKHKW/D0nO7POLkSaZLK20MPFNq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnckOm/btrSJTAKHKW/D0nO7POLkSaZLK20MPFNq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnckOm/btrSJTAKHKW/D0nO7POLkSaZLK20MPFNq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnckOm%2FbtrSJTAKHKW%2FD0nO7POLkSaZLK20MPFNq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;449&quot; height=&quot;242&quot; data-origin-width=&quot;2130&quot; data-origin-height=&quot;1150&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS</category>
      <category>3계층</category>
      <category>Control Plane</category>
      <category>routing</category>
      <category>네트워크</category>
      <category>컴퓨터 네트워크</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/139</guid>
      <comments>https://aimk12.tistory.com/139#entry139comment</comments>
      <pubDate>Sat, 3 Dec 2022 17:39:34 +0900</pubDate>
    </item>
    <item>
      <title>컴퓨터 네트워크 개념 정리(CH.4 Network Layer:Data Plane)</title>
      <link>https://aimk12.tistory.com/138</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;네트워크 계층&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Network Layer: Data Plane&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3계층은 네트워크 코어에도 다 들어있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;forwarding:input link &amp;rarr; outputlink&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;routing: 패킷을 목적지에 갈 길 결정해주는 것&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. data plane&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-local&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-input link에서 받은 데이터그램을 어떤 output link 로 결정해줌&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-알고리즘으로 받은 값 테이블로 저장후 데이터 이동&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.control plane&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-네트워크 전반적&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-라우터 사이에서 목적지까지 길을 정해줌&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-라우터 각자 개개인 라우팅 알고리즘 공유함 (알고리즘으로 길 정함)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2006&quot; data-origin-height=&quot;1138&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhAVBo/btrSah3n1B5/YanazHCjHm6YO1eFPxma2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhAVBo/btrSah3n1B5/YanazHCjHm6YO1eFPxma2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhAVBo/btrSah3n1B5/YanazHCjHm6YO1eFPxma2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhAVBo%2FbtrSah3n1B5%2FYanazHCjHm6YO1eFPxma2K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;522&quot; height=&quot;296&quot; data-origin-width=&quot;2006&quot; data-origin-height=&quot;1138&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;SDN control plane&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘이 라우터에 없고 remote controller에서 알고리즘 값을 라우터에 내려줌&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2130&quot; data-origin-height=&quot;1192&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blaSai/btrSaq60GPo/ByZ2V7jk1EBUKhXyLYi2JK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blaSai/btrSaq60GPo/ByZ2V7jk1EBUKhXyLYi2JK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blaSai/btrSaq60GPo/ByZ2V7jk1EBUKhXyLYi2JK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblaSai%2FbtrSaq60GPo%2FByZ2V7jk1EBUKhXyLYi2JK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;196&quot; data-origin-width=&quot;2130&quot; data-origin-height=&quot;1192&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock floatRight&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1714&quot; data-origin-height=&quot;836&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/70cKl/btrSarkxbtn/QPGVHthHZMQ5kpJJyGQZyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/70cKl/btrSarkxbtn/QPGVHthHZMQ5kpJJyGQZyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/70cKl/btrSarkxbtn/QPGVHthHZMQ5kpJJyGQZyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F70cKl%2FbtrSarkxbtn%2FQPGVHthHZMQ5kpJJyGQZyk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;385&quot; height=&quot;188&quot; data-origin-width=&quot;1714&quot; data-origin-height=&quot;836&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;라우터 아키텍쳐&lt;/h1&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로세서-control plane&lt;/li&gt;
&lt;li&gt;스위칭 fabric -data plane하드웨어)&lt;/li&gt;
&lt;li&gt;router input port -data plane하드웨어)&lt;/li&gt;
&lt;li&gt;router output port-data plane하드웨어)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatRight&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1574&quot; data-origin-height=&quot;956&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/X0vio/btrR9LDD5Pm/5XT1XUjVFSBSer1mKWkCbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/X0vio/btrR9LDD5Pm/5XT1XUjVFSBSer1mKWkCbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/X0vio/btrR9LDD5Pm/5XT1XUjVFSBSer1mKWkCbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FX0vio%2FbtrR9LDD5Pm%2F5XT1XUjVFSBSer1mKWkCbK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;387&quot; height=&quot;235&quot; data-origin-width=&quot;1574&quot; data-origin-height=&quot;956&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;input port&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;line terminal&lt;/li&gt;
&lt;li&gt;link layer protocol&lt;/li&gt;
&lt;li&gt;decentralized switching&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-테이블을 찾아본다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;목적지(ip)보고 포워딩&lt;/li&gt;
&lt;li&gt;헤더에 다른 필드 참조 포워딩&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;switching fabrics&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-input port를 어느 output port에 연결할지 결정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-속도가 중요하다 (input n개 r개의 q를 가지고 있으면 최소 nr 속도를 내야함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫번째 generetion 라우터 -병목현상, 더 느림&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1732&quot; data-origin-height=&quot;484&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biEpEC/btrSc9jaKpv/WKQNUksIFlb2KKQ7mvv0n0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biEpEC/btrSc9jaKpv/WKQNUksIFlb2KKQ7mvv0n0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biEpEC/btrSc9jaKpv/WKQNUksIFlb2KKQ7mvv0n0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiEpEC%2FbtrSc9jaKpv%2FWKQNUksIFlb2KKQ7mvv0n0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;591&quot; height=&quot;165&quot; data-origin-width=&quot;1732&quot; data-origin-height=&quot;484&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;swithcing bus -버스가 주소지로 데려다 주는 느낌 but bus contention 대역폭에 속도 제한 , 각 포트 별 영향을 받음&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1142&quot; data-origin-height=&quot;470&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXHRts/btrSc9KeGNk/KslL010Qp03rKsKuFcSaQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXHRts/btrSc9KeGNk/KslL010Qp03rKsKuFcSaQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXHRts/btrSc9KeGNk/KslL010Qp03rKsKuFcSaQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXHRts%2FbtrSc9KeGNk%2FKslL010Qp03rKsKuFcSaQk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;401&quot; height=&quot;165&quot; data-origin-width=&quot;1142&quot; data-origin-height=&quot;470&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;swithcing via interconnection network - 회선 수를 늘림 서로 영향을 안받음,multiprocessor , multistage swith 로 데이터를 더 쪼개고 보냄으로 더 속도 빠름 (동시성 적용)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;548&quot; data-origin-height=&quot;474&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UlL8V/btrSehae4Y7/nU1BCKXx6npVrYY9XzZ3I1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UlL8V/btrSehae4Y7/nU1BCKXx6npVrYY9XzZ3I1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UlL8V/btrSehae4Y7/nU1BCKXx6npVrYY9XzZ3I1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUlL8V%2FbtrSehae4Y7%2FnU1BCKXx6npVrYY9XzZ3I1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;221&quot; height=&quot;191&quot; data-origin-width=&quot;548&quot; data-origin-height=&quot;474&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;input port queing&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Head of the line (HOL) blocking - 갈 수 있는데 앞에 있는 애 때문에 못감&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;output port&lt;/b&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;buffering - 혼잡이나 버퍼 공간 부족하면 데이터 손실&lt;/li&gt;
&lt;li&gt;scheduling discipline -네트워크 최우선 스케줄림 선택&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-너무큰 버퍼는 딜레이가 증가할 수 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-어느정도 버퍼크기를 유지해야하나 : (RTT*c)/루트(n) ,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;buffer management:&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;drop: 버려도 어떤걸 버려야 효율적인가 1.tail drop 2.priority&lt;/li&gt;
&lt;li&gt;marking: 어느 패킷에 혼잡신호를 마킹하나&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;packet scheduling&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FCFS - 먼저 온 녀석 먼저 보내기, 우선순위, round robin(일부일부 뺴서 기다리는거 방지-문제점 우선수순위를 정해서 먼저들어왔음에도 밀릴 수 있음), weighted fair queueing(가중치에 의거해서 골고루 보내기)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;망 중립성(Network Neutrality)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;누구나 공평하게 망 사용하자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IP address: 32bit host or router interface(host/router 와 물리적 link 사이의 연결)에 할당&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;subnets- router를 통과하지 않고 갈 수 있는 범위&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1106&quot; data-origin-height=&quot;900&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dLspdt/btrScbIjWRh/WqcgauSM0jNKUoMYW5LxRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dLspdt/btrScbIjWRh/WqcgauSM0jNKUoMYW5LxRk/img.png&quot; data-alt=&quot;서브넷&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dLspdt/btrScbIjWRh/WqcgauSM0jNKUoMYW5LxRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdLspdt%2FbtrScbIjWRh%2FWqcgauSM0jNKUoMYW5LxRk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;150&quot; height=&quot;122&quot; data-origin-width=&quot;1106&quot; data-origin-height=&quot;900&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;서브넷&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서브넷 마스크 -어디까지가 네트워크 범위인지 체크 and 연산후 subnet part host part 구분지음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라우터-라우터 사이도 subnet&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ip addressing :CIDR (Classless InterDomain Routing) (클래스방식을 없앰)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;a.b.c.d/x - a클래스 .b클래스 등 구분지음 그리고 x만큼 서브넷 부분&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-그럼 클래스 방식이란? 원래 ip는 a.b.c.d 로 a클래스 b 클래스 구분지음 즉 host는 고정적으로 주어짐- ip 낭비 또는 부족&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1296&quot; data-origin-height=&quot;358&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMm1fq/btrR9t4jXVd/yEamolpXjmE6txflMKSq81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMm1fq/btrR9t4jXVd/yEamolpXjmE6txflMKSq81/img.png&quot; data-alt=&quot;CIDR&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMm1fq/btrR9t4jXVd/yEamolpXjmE6txflMKSq81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMm1fq%2FbtrR9t4jXVd%2FyEamolpXjmE6txflMKSq81%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;416&quot; height=&quot;115&quot; data-origin-width=&quot;1296&quot; data-origin-height=&quot;358&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;CIDR&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DHCP(Dynamic Host Configuration Protocol) 자동으로 ip 를 받아옴&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1966&quot; data-origin-height=&quot;1010&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/msfvB/btrR9uoCdyn/vu2VsaCKi74PSnvbGa2JHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/msfvB/btrR9uoCdyn/vu2VsaCKi74PSnvbGa2JHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/msfvB/btrR9uoCdyn/vu2VsaCKi74PSnvbGa2JHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmsfvB%2FbtrR9uoCdyn%2Fvu2VsaCKi74PSnvbGa2JHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;316&quot; height=&quot;162&quot; data-origin-width=&quot;1966&quot; data-origin-height=&quot;1010&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;route aggregation - 서로 다른 subnet을 알려주기 위해 상위 Provider ISP router에게 메시지를 보내 줘야 함. 이를 활용해서 관리 하는 라우터 범위 변경가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;NAT&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;private IP address는 인터넷에 나가지 못 하는 non-routable address. 이를 routable한 Public IP address로 convert해주는 것을 NAT라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;10/8~ , 172.16/12~ , 192.168/16.~. 인건 다 사설 ip&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이점: 호스트의 주소가 바뀌어도 사설 주소는 안 바뀌어도 됨 , 보안적으로도 오름&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단점&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;라우터는 원래 3계층임 근데 NAT를 사용하려면 port까지 가야해서 4계층까지 가야함 즉 규약을 어길 수 밖에 없음&lt;/li&gt;
&lt;li&gt;NAT 뒤에 서버가 존재하면 클라이언트는 들어오기 힘듬&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;IPv6&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주소 부족 문제 해결 하지만 갑자기 모든 것을 바꾸기 힘듬&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;checksum 없음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fragmentation/reassembly 없음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옵션 없음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;IPv4 에서 IPv6로 어떻게 이동하나&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tunneling - IPv6 datagram 위에 IPv4의 헤더를 붙인다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1856&quot; data-origin-height=&quot;1196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Kq2mi/btrSarrmlV7/4RSkbF06KVuA0AxqCahBW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Kq2mi/btrSarrmlV7/4RSkbF06KVuA0AxqCahBW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Kq2mi/btrSarrmlV7/4RSkbF06KVuA0AxqCahBW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKq2mi%2FbtrSarrmlV7%2F4RSkbF06KVuA0AxqCahBW1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;421&quot; height=&quot;271&quot; data-origin-width=&quot;1856&quot; data-origin-height=&quot;1196&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Generalized forwarding&lt;/b&gt; : 패킷을 핸들링 할 수 있는 간단한 룰 (match : 똑같은 애를 받아서 &amp;rarr; action : 이런이런 행동을 한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;flow: 헤더 필드 값들을 정의하는 것 (link , network, transport-layer 필드)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1960&quot; data-origin-height=&quot;916&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDCagD/btrR9Mie6Aj/znWf50NT9pg3qLElSLiRbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDCagD/btrR9Mie6Aj/znWf50NT9pg3qLElSLiRbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDCagD/btrR9Mie6Aj/znWf50NT9pg3qLElSLiRbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDCagD%2FbtrR9Mie6Aj%2FznWf50NT9pg3qLElSLiRbK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;329&quot; height=&quot;154&quot; data-origin-width=&quot;1960&quot; data-origin-height=&quot;916&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;OpenFlow&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;router switch firewall nat &amp;mdash; match , action 이용해서 처리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Middleboxes&lt;/b&gt; :&lt;b&gt;서로 통신하는 두 개의 최종 호스트 사이의 경로에 있는 네트워크 내 디바이스&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하드 웨서 솔루선 &amp;rarr; 소프트웨어 쪽으로 이동&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS</category>
      <category>Data Plane</category>
      <category>Network Layer</category>
      <category>네트워크 계층</category>
      <category>컴퓨터 네트워크</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/138</guid>
      <comments>https://aimk12.tistory.com/138#entry138comment</comments>
      <pubDate>Sat, 26 Nov 2022 21:28:39 +0900</pubDate>
    </item>
    <item>
      <title>컴퓨터 네트워크 개념 정리(CH.3 Transport layer)</title>
      <link>https://aimk12.tistory.com/137</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Transport layer&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저번 파트에서 application layer를 다루어 봤는데 이번에는&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Transport layer를 다루어 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 장은 transport layer service 뒤의 원칙을 다루는 시간이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;TCP: Transmission Control Protocol&amp;nbsp; 와 UDP: User Datagram Protocol&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;TCP -연결형, 신뢰할수있는 데이터 전송을 보장, 흐름/혼잡제어 해줌, 보안안함&lt;/li&gt;
&lt;li&gt;UDP -비연결형, 완전한 데이터 전송 보장안함, 빠름, 영상 스트리밍 회사에서 이용&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;stream socket : TCP 전송을 위하여 통신하는 소켓&lt;/li&gt;
&lt;li&gt;datagram socket : UDP 전송을 위해 통신하는 소켓&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Multiplexing/demultiplexing&lt;/b&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Multiplexing : 보내는 자가&amp;nbsp; 받는 자에게 특정 ip와 port에 데이터를 특정해서 보내는 것&lt;/b&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;demultiplexing : 받은 자가 보낸 자에게 응답을 보내는 특정 ip와 port에 보내는 것&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2142&quot; data-origin-height=&quot;1164&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0uTia/btrR8Vtv1lO/2J5qutKB5dSPZMv0z9obg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0uTia/btrR8Vtv1lO/2J5qutKB5dSPZMv0z9obg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0uTia/btrR8Vtv1lO/2J5qutKB5dSPZMv0z9obg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0uTia%2FbtrR8Vtv1lO%2F2J5qutKB5dSPZMv0z9obg1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;576&quot; height=&quot;313&quot; data-origin-width=&quot;2142&quot; data-origin-height=&quot;1164&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;connectionless demultiplexing할 때 필요한 것 (UDP)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;destinaion IP address&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;destination port number&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1330&quot; data-origin-height=&quot;624&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dmvJ1I/btrR9vVmaMC/vqZrBfYYW6wBqJOp6Ns7i1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dmvJ1I/btrR9vVmaMC/vqZrBfYYW6wBqJOp6Ns7i1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dmvJ1I/btrR9vVmaMC/vqZrBfYYW6wBqJOp6Ns7i1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdmvJ1I%2FbtrR9vVmaMC%2FvqZrBfYYW6wBqJOp6Ns7i1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;385&quot; height=&quot;181&quot; data-origin-width=&quot;1330&quot; data-origin-height=&quot;624&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;connetction-oriented demux할 때 필요한 것 (TCP)&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;destinaion IP address &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;destination port number &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;source IP address &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;source port number&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1306&quot; data-origin-height=&quot;726&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/71nYl/btrSa6N0Pfx/7KwDRjDRcR8kOfcUDAKg01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/71nYl/btrSa6N0Pfx/7KwDRjDRcR8kOfcUDAKg01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/71nYl/btrSa6N0Pfx/7KwDRjDRcR8kOfcUDAKg01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F71nYl%2FbtrSa6N0Pfx%2F7KwDRjDRcR8kOfcUDAKg01%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;370&quot; height=&quot;206&quot; data-origin-width=&quot;1306&quot; data-origin-height=&quot;726&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;UDP&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UDP checksum&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UDP 는 연결하지 않고 보내는 것이기에 에러가 있는지 없는지 체크를 해야한다. 체크하기 위해 있는게 checksum이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- checksum 세그먼트 안의 비트에 대한 변경사항이 있는지 검사하는 것이다. (16bit 워드의 합으로 오버플로는 제일 오른쪽 자리에 더해준다. 그 값을 1의 보수(토글)를 취한다.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;데이터에 에러가 없으면 receiver checksum 의 값은? 111111111111111111 (all 1)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;신뢰적인 데이터 전달 원칙&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ACK and NAK 데이터의 오류 발생 유무를 검사한다. 오류가 없다면 ACK를, 있다면 NAK를 전송한다. -&lt;/li&gt;
&lt;li&gt;sequence number 메시지를 통신망에 보낼 수 있도록 패킷으로 나눈 경우, 그 순서에 따라 붙인 일련 번호이다. -&lt;/li&gt;
&lt;li&gt;timeout Data를 보냈는데 일정 시간 동안 피드백이 없을 시에 데이터를 다시 보낸다. 이때 이 일정 시간이 초과되는 것이 timeout이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;RDT(Reliable data transfer protocol)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RDT 2.0 : error가 발생하는 신회할 수 없는 채널에 Data를 보내는 것 따라서 error check를 해야함 -&amp;gt; 이때, checksum을 이용한다. error 감지 작업이 끝나면 피드백을 해줘야한다. error 없으면 ACK 전달, error 있으면 NAK 전달한다. -&lt;/li&gt;
&lt;li&gt;RDT 2.1 : 피드백인 ACK, NAK도 에러가 발생할 수 있음 -&amp;gt; 따라서, sequence number를 이용 수신부에서 ACK를 보냈는데, 송신부에서는 NAK로 읽어서 데이터를 다시 보내는 상황이 생김 (즉, 수신부에서는 ACK를 보내면 1을 기다리는데 0이 온다. 그러면 수신부에서는 ACK를 다시 보낸다. 그러면 다음꺼인 1이 온다.) -&lt;/li&gt;
&lt;li&gt;RDT 2.2 : NAK를 사용하지 않는다. ACK에 sequence number을 붙인다. -&lt;/li&gt;
&lt;li&gt;RDT 3.0 : error 뿐만아니라 loss도 발생하는 경우이다. 만약, 데이터가 가다가 사라진 경우에는 수신부에서 받지 못해서 feedback을 주지 않는다.(보낸줄모름) RDT 3.0은 일정시간 기다려도 feedback을 받지 못하면 최근에 보낸 sequence를 넣어서 다시 데이터를 보낸다.&lt;/li&gt;
&lt;li&gt;RDT가 진행되는 layer와 protocol을 각각 쓰시오. - application laye, transport layer, link layer&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Pipelining: increased utilization. - 데이터 페킷을 보낼 때 여러개를 한번에 보내는 것&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Go-Back-N&amp;nbsp; - window size를 한번에 다 보내고 손실로 안오는 패킷이 있으면 안 온 패킷부터 window size로 보내는 것&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1136&quot; data-origin-height=&quot;228&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0DcBB/btrR9L4J0bo/HtV1g6SAyoXHnNOgrgqKK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0DcBB/btrR9L4J0bo/HtV1g6SAyoXHnNOgrgqKK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0DcBB/btrR9L4J0bo/HtV1g6SAyoXHnNOgrgqKK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0DcBB%2FbtrR9L4J0bo%2FHtV1g6SAyoXHnNOgrgqKK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;780&quot; height=&quot;157&quot; data-origin-width=&quot;1136&quot; data-origin-height=&quot;228&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Selective repeat- window size를 한번에 보내고 손실로 안오는 패킷이 있어도 그 다음 패킷 계속 보냄&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1134&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RBVAh/btrR9uvnkGj/fkmISdyRvzHq8KcKiqI9xK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RBVAh/btrR9uvnkGj/fkmISdyRvzHq8KcKiqI9xK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RBVAh/btrR9uvnkGj/fkmISdyRvzHq8KcKiqI9xK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRBVAh%2FbtrR9uvnkGj%2FfkmISdyRvzHq8KcKiqI9xK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;762&quot; height=&quot;202&quot; data-origin-width=&quot;1134&quot; data-origin-height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;TCP congestion control: AIMD&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;패킷을 점진적으로 갯수를 늘려가며 보내다가 손실이 나거나 오류가 나오면 보내는 패킷 수를 줄임&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1318&quot; data-origin-height=&quot;702&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nbXUI/btrSahWChpW/F0fIV04irJrdk1G5gOk4f1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nbXUI/btrSahWChpW/F0fIV04irJrdk1G5gOk4f1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nbXUI/btrSahWChpW/F0fIV04irJrdk1G5gOk4f1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnbXUI%2FbtrSahWChpW%2FF0fIV04irJrdk1G5gOk4f1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;507&quot; height=&quot;270&quot; data-origin-width=&quot;1318&quot; data-origin-height=&quot;702&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS</category>
      <category>TCP</category>
      <category>Transport Layer</category>
      <category>UDP</category>
      <category>전송</category>
      <category>전송 계층</category>
      <category>컴퓨터 네트워크</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/137</guid>
      <comments>https://aimk12.tistory.com/137#entry137comment</comments>
      <pubDate>Sat, 26 Nov 2022 20:39:11 +0900</pubDate>
    </item>
    <item>
      <title>컴퓨터 네트워크 개념 정리(CH.2 Application Layer)</title>
      <link>https://aimk12.tistory.com/136</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;Application Layer&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저번 파트는 네트워크 전반적인 개념을 설명했으면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 파트는&amp;nbsp; OSI 계층의&amp;nbsp; Application Layer 에 대해서 알아 보자&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;005&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/005.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/005.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Application Layer에는 다양한 network App 이 존재한다.&amp;nbsp; (ex- social networking , Web ,text messaging , e-mail ,multi-user network games ,streaming stored video (YouTube, Hulu, Netflix) , P2P file sharing)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;network app 들이 서로 통신 하는 방식은 크게 두 가지가 있다.&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1.client-server service (Client-server paradigm)&amp;nbsp; &amp;nbsp; 2. p2p service&amp;nbsp; &amp;nbsp;(Peer-peer architecture)&lt;/b&gt;&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;client-server service&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;p2p service&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;고정 IP를 가진 서버는 클라이언트에게 요청을 받 고, 서버는 클라이언트에게 서비스를 제공한다. 서버는 항상 동작한다. 클라이언트 끼리는 직접적으로 통신하지 않는다&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;P2P 구조에서는 서버가 존재하지 않는다. peer라는 임의의 호스트 쌍이 서로 직접 통신한다. 특정 서버를 통하지 않고 호스트가 직접 통신한다. P2P 구조에서는 참여 호스트가 항상 동작하도록 요구하지 않는다. 참여 호스트는 자신이 네트워크로 들어왔을 때 주소를 교환한다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;웹, 파일전송, 원격로그인, 전자메일&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그누텔라 Gnutella&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이제 어떻게 Application layer에서 다른 컴퓨터 Application layer로 데이터를 보내는지 알아보자&amp;nbsp; (이해 안되도 넘어가기-많은게 필요하고 세부적인 것은 뒤에 다룬다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 첫번쨰로 필요한게 소켓(socket) 이다&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;socket이란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;네트워크에서 프로세스로 데이터를 전달하며, 또한 프로세스에서 네트워크로 데이터를 전달하는 출입구역할을 함&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1564&quot; data-origin-height=&quot;504&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dPFnzk/btrR9c2Icvs/RGMEP7vT8nq7jirex22jZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dPFnzk/btrR9c2Icvs/RGMEP7vT8nq7jirex22jZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dPFnzk/btrR9c2Icvs/RGMEP7vT8nq7jirex22jZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdPFnzk%2FbtrR9c2Icvs%2FRGMEP7vT8nq7jirex22jZ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;668&quot; height=&quot;215&quot; data-origin-width=&quot;1564&quot; data-origin-height=&quot;504&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대이터를 보내기 위해선 보내고자 하는 주소가 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;여기서 두번쨰로 필요한게&amp;nbsp;&lt;b&gt;ip와 port&lt;/b&gt;&lt;/span&gt; 다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;HTTP : 80 FTP : control - 21, data - 20 SMTP : 25 등&amp;nbsp; 각 프로토콜마다 포트가 지정되어 있고 컴퓨터 ip 에 통신한다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그리고 이런 HTTP,FTP,SMTP에 적절한 Transport layer service 도 적용하여야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;대표적 으로 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;TCP 와 UDP&lt;/b&gt;&lt;/span&gt; 이다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;TCP 와 UDP 란?&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;TCP -연결형, 신뢰할수있는 데이터 전송을 보장, 흐름/혼잡제어 해줌, 보안안함&lt;/li&gt;
&lt;li&gt;UDP -비연결형, 완전한 데이터 전송 보장안함, 빠름, 영상 스트리밍 회사에서 이용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 application layer 인데 transport layer 가 나오는지 이해가 안될 거 같아 예시를 든다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;TCP 사용하는 network app&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;HTTP는 웹 객체를 전송하기 위한 프로토콜 ,SMTP는 메일 전송을 위한 프로토콜, FTP는 파일 전송을 위한 프로토콜 모두 Data loss가 일어나면 안되는 것들이기 때문에 신뢰성을 중시하는 TCP 사용&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;UDP 사용하는 &lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;network app&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주로 빠르게 보내야하는 영상 스트리밍&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;즉 어떤 APP의 특징에 따라 transport layer service 적용이 달라진다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이제 우리가 주로 사용하고 있는 HTTP에 대해서 알아보자&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;HTTP란?&amp;nbsp; - web에서 사용하는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;hypertext transfer protocol&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TCP 사용 하고 &lt;b&gt;stateless&lt;/b&gt; 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;HTTP 연결에는&amp;nbsp; 두 가지 타입이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;비영속성과 영속성&lt;/b&gt;&lt;/span&gt;이다. 두가지 차이를 알아 보자&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;non-persistent HTTP&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;persistent HTTP&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;한 번의 연결 시 하나의 web 객체만 보낼 수 있 다. 요청하는 클라이언트가 많아질 때 서버에 심각 한 부담을 줄 수 있다.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;한 번의 연결에 여러개의 web 객체를 보낼 수 있다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 에서 정해진 request와 response 규칙이 있다 . 참고 하면 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Request&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2148&quot; data-origin-height=&quot;882&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5TMPX/btrR9c2I8BG/P6mKvXgDj0XU2r3Zr2kpJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5TMPX/btrR9c2I8BG/P6mKvXgDj0XU2r3Zr2kpJk/img.png&quot; data-alt=&quot;Request&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5TMPX/btrR9c2I8BG/P6mKvXgDj0XU2r3Zr2kpJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5TMPX%2FbtrR9c2I8BG%2FP6mKvXgDj0XU2r3Zr2kpJk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;641&quot; height=&quot;263&quot; data-origin-width=&quot;2148&quot; data-origin-height=&quot;882&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Request&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Response&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2066&quot; data-origin-height=&quot;1124&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LuuRv/btrR9dtMDoN/GgTOuXk1GREewTpRCgZoI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LuuRv/btrR9dtMDoN/GgTOuXk1GREewTpRCgZoI1/img.png&quot; data-alt=&quot;response&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LuuRv/btrR9dtMDoN/GgTOuXk1GREewTpRCgZoI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLuuRv%2FbtrR9dtMDoN%2FGgTOuXk1GREewTpRCgZoI1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;627&quot; height=&quot;341&quot; data-origin-width=&quot;2066&quot; data-origin-height=&quot;1124&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;response&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;HTTP에서 stateless의 의미&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;연결 상태정보를 유지하지 않는다는 것을 의미한다. 즉 과거의 상태에 대하여 기억하지 않는다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;하지만 우리가 사용하는 web에는 로그인 기능도 있고 사용자의 정보를 기억하고 있어야 할 떄가 있다 이럴 경우 쿠키를 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;쿠키는 사용자에게 쿠키를 주고 그 사용자는 다음 요청 때 쿠키를 들고 요청한다. 그러면 서버는 사용자 식별이 가능해진다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1888&quot; data-origin-height=&quot;1010&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPnmqm/btrR9F4CsS6/s6z4nf6nB8JYroI1WkCV8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPnmqm/btrR9F4CsS6/s6z4nf6nB8JYroI1WkCV8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPnmqm/btrR9F4CsS6/s6z4nf6nB8JYroI1WkCV8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPnmqm%2FbtrR9F4CsS6%2Fs6z4nf6nB8JYroI1WkCV8k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;652&quot; height=&quot;349&quot; data-origin-width=&quot;1888&quot; data-origin-height=&quot;1010&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Web caches (proxy servers) 에 대해서도 알아보자&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Web Cache(캐시)이란? &lt;/b&gt;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;오리지널 웹 서버와 클라이언트 중간에 있는 서버 client가 요청한 것이 웹 캐시에 존재한다면 오리지널 웹 서버에 요구하지 않고 웹 캐시가 전송한다&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Web Cache(캐시)의 장점 &lt;/b&gt;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;① 클라이언트의 요구에 대한 응답시간을 줄일 수 있다.&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;② 오리지널 서버의 트래픽을 줄일 수 있다.&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;③ 빠른 콘텐츠 분배를 위한 기반구조를 제공한다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;830&quot; data-origin-height=&quot;966&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2rfWO/btrScQw74ac/mrkZPy1HxznKgEImtKzib0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2rfWO/btrScQw74ac/mrkZPy1HxznKgEImtKzib0/img.png&quot; data-alt=&quot;웹 캐시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2rfWO/btrScQw74ac/mrkZPy1HxznKgEImtKzib0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2rfWO%2FbtrScQw74ac%2FmrkZPy1HxznKgEImtKzib0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;485&quot; height=&quot;564&quot; data-origin-width=&quot;830&quot; data-origin-height=&quot;966&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;웹 캐시&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 우리는 webcache를 이용해 멀리있는 origin server에 통신하지 않아도 정보를 가져올 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 web cache랑 origin server의 내용이 다를 수 있다 . 이럴 경우를 위해 조건부 get이 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;조건부 GET &lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;캐시서버와 오리지널 서버의 동기화가 필요하므로, 조건부 GET을 이용해 최신상태인지를 확인&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1082&quot; data-origin-height=&quot;1122&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crjRqo/btrSagwzl5m/g4rnRPDolMnWM2pLUWPFNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crjRqo/btrSagwzl5m/g4rnRPDolMnWM2pLUWPFNK/img.png&quot; data-alt=&quot;조건부 Get&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crjRqo/btrSagwzl5m/g4rnRPDolMnWM2pLUWPFNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcrjRqo%2FbtrSagwzl5m%2Fg4rnRPDolMnWM2pLUWPFNK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;298&quot; height=&quot;309&quot; data-origin-width=&quot;1082&quot; data-origin-height=&quot;1122&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;조건부 Get&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;E-mail&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SMTP - 이메일 메시지를 mail server에 보내기 위한 프로토콜&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;946&quot; data-origin-height=&quot;1114&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FmSou/btrScP53jAC/wklAKx2zxxNulX6KpKcP60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FmSou/btrScP53jAC/wklAKx2zxxNulX6KpKcP60/img.png&quot; data-alt=&quot;이메일&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FmSou/btrScP53jAC/wklAKx2zxxNulX6KpKcP60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFmSou%2FbtrScP53jAC%2FwklAKx2zxxNulX6KpKcP60%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;208&quot; height=&quot;245&quot; data-origin-width=&quot;946&quot; data-origin-height=&quot;1114&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이메일&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;HTTP와 SMTP 비교 &lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP는 pull 프로토콜이다. 클라이언트가 요청한 것을 서버가 전송해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SMTP는 push 프로토콜이다. 클라이언트가 요청하지 않았는데도 서버가 전송해준다. 35. mail 접속 프로토콜 POP3, IMAP, HTTP&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;DNS (Domain name System) -ip 주소를 사용자가 식별하기 좋게 변환&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;도메인 사용하는 이유&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;각 웹 사이트마다의 IP 주소를 기억하기는 어렵다. 그래서 주소를 기억하기 위해 나온 것이 도메인 네임이고, DNS는 도메인 네임을 IP 주소로 바꿔 준다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DNS는 분산되어 있고 계층구조를 띄고 있다. 종류를 확인해 보자&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Local DNS serverDNS 계층에는 속하지 않는다. host와 가장 가까운 DNS이다. -&lt;/li&gt;
&lt;li&gt;Root DNS server 계층의 최상위 DNS이다.local DNS server에게 host가 요청한 정보가 있지 않으면 다음은 root DNS로 간다. -&lt;/li&gt;
&lt;li&gt;TLD DNS server com, org, net, edu 등 all top-level country domains kr, uk, fr, ca, jp, 등 를 책임진다. -&lt;/li&gt;
&lt;li&gt;Authoritative DNS server (DNS server) 권위적 기관 회사의 DNS server&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2196&quot; data-origin-height=&quot;590&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvlz28/btrSah3kvvA/Xeezfl0a7enmiz6TueuHW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvlz28/btrSah3kvvA/Xeezfl0a7enmiz6TueuHW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvlz28/btrSah3kvvA/Xeezfl0a7enmiz6TueuHW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcvlz28%2FbtrSah3kvvA%2FXeezfl0a7enmiz6TueuHW1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;607&quot; height=&quot;163&quot; data-origin-width=&quot;2196&quot; data-origin-height=&quot;590&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;DNS query의 흐름 모델 2가지(그림)&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.iterated query (반복적 질의)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;local DNS에 없으면, local DNS가 root DNS에 게 질문 root DNS에도 없으면, local DNS가 TLD DNS에 질문 TLD 에도 없으면 local DNS가 authoritative 에 질문&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1370&quot; data-origin-height=&quot;884&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBKPaQ/btrR9kzDtjc/wqPcbTY5SVfnMNhkUSabMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBKPaQ/btrR9kzDtjc/wqPcbTY5SVfnMNhkUSabMk/img.png&quot; data-alt=&quot;반복적 질의&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBKPaQ/btrR9kzDtjc/wqPcbTY5SVfnMNhkUSabMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBKPaQ%2FbtrR9kzDtjc%2FwqPcbTY5SVfnMNhkUSabMk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;397&quot; height=&quot;256&quot; data-origin-width=&quot;1370&quot; data-origin-height=&quot;884&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;반복적 질의&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.recursive query(재귀적 질의)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;local DNS에 없으면, local DNS가 root DNS에 질문 root DNS에 없으면, root DNS는 TLD DNS 에 질문 TLD DNS에 없으면, TLD DNS는 authoritative에 질문&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1402&quot; data-origin-height=&quot;860&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7bYuf/btrR8yd9hyX/Wo2Qdl4RLNBDiTF7aBzDx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7bYuf/btrR8yd9hyX/Wo2Qdl4RLNBDiTF7aBzDx0/img.png&quot; data-alt=&quot;재귀적 질의&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7bYuf/btrR8yd9hyX/Wo2Qdl4RLNBDiTF7aBzDx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7bYuf%2FbtrR8yd9hyX%2FWo2Qdl4RLNBDiTF7aBzDx0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;404&quot; height=&quot;248&quot; data-origin-width=&quot;1402&quot; data-origin-height=&quot;860&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;재귀적 질의&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;DNS format이 가지는 4개의 정보&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;question record: 질의에 대한 name, type field들을 포함&lt;/li&gt;
&lt;li&gt;answer record : 응답 메세지에서만 사용되며 여러개의 RR을 보낼 수 있다. -&lt;/li&gt;
&lt;li&gt;authority record : 질의의 대한 인증 권한이 있는 서버 정보를 제공(누가 권리를 가지고 있는지) -&lt;/li&gt;
&lt;li&gt;additional record : 다른 도움이 되는 추가정보 40-1. RR format - name(도메인이름), value(IP주소), type(서버type), ttl(Time To Line&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS</category>
      <category>Application Layer</category>
      <category>dns</category>
      <category>HTTP</category>
      <category>SMTP</category>
      <category>SOCKET</category>
      <category>TCP</category>
      <category>UDP</category>
      <category>애플리케이션 계층</category>
      <category>컴퓨터 네트워크</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/136</guid>
      <comments>https://aimk12.tistory.com/136#entry136comment</comments>
      <pubDate>Sat, 26 Nov 2022 18:45:33 +0900</pubDate>
    </item>
    <item>
      <title>컴퓨터 네트워크 개념 정리 (CH.1 네트워크란)</title>
      <link>https://aimk12.tistory.com/135</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;컴퓨터네트워크 개념 정리&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중간 고사가 끝나면서 공부했던 것들을 정리하고 공유해보려 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터 네트워크 공부할 떄 다른 분들 블로그를 많이 참고 했는데 도움이 정말 많이 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부족하지만 나도 다른사람들에게 도움이 되었으면 좋을 거 같다!&amp;nbsp;&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;002&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/002.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/002.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;네트워크 구성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 네트워크가 이루는 큰 느낌을 알기 위해서 가장 이해하기 쉬운 그림이다&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2194&quot; data-origin-height=&quot;1090&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvM9tK/btrSah91DUo/GDZKO6EhmDGeG55tpZChwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvM9tK/btrSah91DUo/GDZKO6EhmDGeG55tpZChwk/img.png&quot; data-alt=&quot;네트워크 구조 설명&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvM9tK/btrSah91DUo/GDZKO6EhmDGeG55tpZChwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvM9tK%2FbtrSah91DUo%2FGDZKO6EhmDGeG55tpZChwk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;711&quot; height=&quot;353&quot; data-origin-width=&quot;2194&quot; data-origin-height=&quot;1090&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;네트워크 구조 설명&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Network Structure 3가지 에 대해서 알아보자&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Network Edge&amp;nbsp; : 호스트: 클라이언트 나 서버&lt;/li&gt;
&lt;li&gt;Network Core&amp;nbsp; : 상호연결된 라우터 , 네트워크 중의 네트워크&lt;/li&gt;
&lt;li&gt;Access Network (Physical Media)&amp;nbsp; :무선 , 유선&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ACCESS network에는 무엇이 있을까?&lt;/b&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-size: 1.44em; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;1.mobile access networks&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가정에서 쓰는 Access network 4가지&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DSL(Digital Subscriber line) or cable modem&lt;/li&gt;
&lt;li&gt;router/firewall/NAT&lt;/li&gt;
&lt;li&gt;Ethernet (이더넷)&lt;/li&gt;
&lt;li&gt;Wireless Access Point (무선랜)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. guided media(유선)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Coaxial cable (동축케이블)&lt;/li&gt;
&lt;li&gt;Fiber Optic Cable (광섬유 케이블)&lt;/li&gt;
&lt;li&gt;Twisted Pair (꼬임쌍 동선)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;네트워크 코어(network core)&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;470&quot; data-origin-height=&quot;634&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/K8Mag/btrScQX9LOl/kyKfB8AABRa3FyxKWJfU00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/K8Mag/btrScQX9LOl/kyKfB8AABRa3FyxKWJfU00/img.png&quot; data-alt=&quot;네트워크 코어&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/K8Mag/btrScQX9LOl/kyKfB8AABRa3FyxKWJfU00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FK8Mag%2FbtrScQX9LOl%2FkyKfB8AABRa3FyxKWJfU00%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;240&quot; height=&quot;634&quot; data-origin-width=&quot;470&quot; data-origin-height=&quot;634&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;네트워크 코어&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp; 라우터로 데이터를 송수신 하고&amp;nbsp; 데이터를 보내는 과정에서&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.Packet Switching&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2,Circuit Switching&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.Packet Switching과 Circuit Switching 차이 설명&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;circuit switching network&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;packet switching network&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;특징&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;서킷 스위칭은 하나의 회선을 할당받아 데이터를 주고받는다. 출발지와 목적지 사이의 물리적인 경로가 존재한다. 모든 패킷은 같은 경로를 이용한다. 경로상 필요한 대역폭을 사전에 예약 한다. 대역폭의 낭비가 있을 수 있다. 저장하고 전달하는 store and forward 방 식을 이용하지 않는다.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;패킷 스위칭은 데이터를 패킷 단위로 쪼개서 전송한다. 물리적인 경로가 존재하지 않는다. 패킷들은 독립적으로 이동한다. 사전에 예약하지 않는다. 대역폭의 낭비가 없다. 다음 링크로 전송하기 전에 저장한 뒤 전달하는 store and forward 방식을 따른다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;장점&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;대역폭이 예약되므로 송신자는 수신자에게 보장된 일정 전송률로 보낼 수 있다.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;대역폭 공유에 효율적이다. 더 간단하고, 구현 비용이 적게 든다. 패킷들은 링크의 최대 전송률 속도로 전송된다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;단점&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;할당된 대역폭을 모두 사용하고 있다면 연결이 끊어질 때까지 기다려야 한다&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가변적이고 예측할 수 없는 종단 간의 지연이 발생 한다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;예&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;전화망&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;인터넷&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1508&quot; data-origin-height=&quot;486&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bs3mWA/btrR8x7lAPN/iR4my8oKwHP7ez8isHTOLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bs3mWA/btrR8x7lAPN/iR4my8oKwHP7ez8isHTOLk/img.png&quot; data-alt=&quot;Packet Switching&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bs3mWA/btrR8x7lAPN/iR4my8oKwHP7ez8isHTOLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbs3mWA%2FbtrR8x7lAPN%2FiR4my8oKwHP7ez8isHTOLk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;487&quot; height=&quot;486&quot; data-origin-width=&quot;1508&quot; data-origin-height=&quot;486&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Packet Switching&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;902&quot; data-origin-height=&quot;900&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dvuc5L/btrSaq6UtrQ/hDfShbZ4voV6Stvru42vk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dvuc5L/btrSaq6UtrQ/hDfShbZ4voV6Stvru42vk1/img.png&quot; data-alt=&quot;Circuit Switching&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dvuc5L/btrSaq6UtrQ/hDfShbZ4voV6Stvru42vk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdvuc5L%2FbtrSaq6UtrQ%2FhDfShbZ4voV6Stvru42vk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;170&quot; height=&quot;170&quot; data-origin-width=&quot;902&quot; data-origin-height=&quot;900&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Circuit Switching&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Circuit switching: FDM and TDM&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2106&quot; data-origin-height=&quot;990&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n8reQ/btrScRpdTvz/mKm0iGYXAmJQaGLJmcSLK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n8reQ/btrScRpdTvz/mKm0iGYXAmJQaGLJmcSLK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n8reQ/btrScRpdTvz/mKm0iGYXAmJQaGLJmcSLK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn8reQ%2FbtrScRpdTvz%2FmKm0iGYXAmJQaGLJmcSLK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;505&quot; height=&quot;237&quot; data-origin-width=&quot;2106&quot; data-origin-height=&quot;990&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FDM은 주파수 대역을 나누어 사용한다.&lt;/li&gt;
&lt;li&gt;TDM은 총 대역폭을 시간 슬롯으로 나누어, 정해진 시간엔 사용자가 대역폭 전체를 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;왜 Packet Switching은 통계적 다중화(statistical multiplexing)을 사용하는지, TDM과 대조하여 설명&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;TDM은 시간을 일정 주기로 나누어, 정해진 시간엔 사용자가 대역폭 전체를 사용한다.&lt;/li&gt;
&lt;li&gt;통계적 다중화는 링크에 전송할 패킷을 가진 사용자만이 패킷을 공유하는 것으로, 패킷 요청이 있을 때마다 미리 할당하지 않고 자원을 사용할 때 마다 공유하는 것이다.&lt;/li&gt;
&lt;li&gt;이 둘의 가장 큰 차이점은 서킷 스위칭은 요구에 관계 없이 미리 전송 링크의 사용을 할당하는(예약) 반면에, 패킷 교환은 요구할 때만 링크 사용을 할당한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ISP(internet service provider)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제일 크게 global ISP, regional(지역) ISP, 그 다음으로 access ISP를 두어 계층화 한다. access ISP는 통신을 위해 regional ISP를 거쳐가고 regional ISP는 global ISP를 거친다. access ISP는 host가 인터넷으로 진입할 때 가장 먼저 거친다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ISP끼리 연결되는 지점을 IXP 라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2092&quot; data-origin-height=&quot;1096&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p7rSP/btrR8XdD3n3/npVkdyg4xlEQoM2qQ1WUIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p7rSP/btrR8XdD3n3/npVkdyg4xlEQoM2qQ1WUIk/img.png&quot; data-alt=&quot;ISP&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p7rSP/btrR8XdD3n3/npVkdyg4xlEQoM2qQ1WUIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp7rSP%2FbtrR8XdD3n3%2FnpVkdyg4xlEQoM2qQ1WUIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;404&quot; height=&quot;212&quot; data-origin-width=&quot;2092&quot; data-origin-height=&quot;1096&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ISP&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;네트워크가 지연 되고 손실 나는 경우&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;네트워크 지연 4가지 Delay 특징&amp;nbsp; &amp;nbsp; (특정 하나가 오래걸리면 지연)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 처리 Processing 패킷 헤더를 읽고 그 패킷을 어디로 보낼지 결정하는데 필요한 시간&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 큐잉 Queueing 큐에서 패킷이 링크로 전송될 때까지의 시간&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 전송 Transmission 패킷의 모든 비트를 링크로 전송하는데 필요한 시간 전파&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. Propagation 링크의 시작에서 라우터까지 전파되는데 필요한 시간&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;packet loss되는 메커니즘 2가지 &lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1534&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4bdLV/btrR9Mh7yej/nYL8SeMgvKiIczI7Db5z41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4bdLV/btrR9Mh7yej/nYL8SeMgvKiIczI7Db5z41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4bdLV/btrR9Mh7yej/nYL8SeMgvKiIczI7Db5z41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4bdLV%2FbtrR9Mh7yej%2FnYL8SeMgvKiIczI7Db5z41%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;384&quot; height=&quot;252&quot; data-origin-width=&quot;1534&quot; data-origin-height=&quot;252&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;① 병목현상이 발생했을 때 패킷 손실 (큰길-&amp;gt;작은길)&lt;/p&gt;
&lt;table id=&quot;a0293527-78e9-4db0-8416-80b255027378&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;/table&gt;
&lt;table id=&quot;a0293527-78e9-4db0-8416-80b255027378&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1206&quot; data-origin-height=&quot;468&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cl7ITY/btrSahWww0Y/Db9BXNmanNeuzYvftp1wZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cl7ITY/btrSahWww0Y/Db9BXNmanNeuzYvftp1wZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cl7ITY/btrSahWww0Y/Db9BXNmanNeuzYvftp1wZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcl7ITY%2FbtrSahWww0Y%2FDb9BXNmanNeuzYvftp1wZ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;314&quot; height=&quot;122&quot; data-origin-width=&quot;1206&quot; data-origin-height=&quot;468&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;② 큐에 빈자리가 없는 상태에서 패킷이 도착하면 큐에 저장하지 못하고 손실&lt;/p&gt;
&lt;table id=&quot;a0293527-78e9-4db0-8416-80b255027378&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;/table&gt;
&lt;table id=&quot;a0293527-78e9-4db0-8416-80b255027378&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;네트워크가 소통을 하기위해서는 프로토콜을 사용해야한다.&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;protocol(프로토콜)이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;통신하려는 사람, 디바이스 등의 법칙 규약&lt;/p&gt;
&lt;table id=&quot;a0293527-78e9-4db0-8416-80b255027378&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터가 컴퓨터에 송수신 할때 OSI 모델을 따르고 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;OSI 계층이란&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;네트워크에서 통신이 일어나는 과정을 7단계로 나눈 것을 말한다.&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;계층을 나눈 이유는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;통신이 일어나는 과정이 단계별로 파악할 수 있기 때문이다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;(원래는 구체적 으로 7계층이 있지만 요즘은 5계층으로 부르고 있는 추세다 )&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;OSI 참조모델(7계층) 어플리케이션 &amp;ndash; 프레젠테이션 &amp;ndash; 세션 &amp;ndash; 트랜스포트 - 네트워크 - 링크 - 물리&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;OSI 모델 5계층&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 특징&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;데이터타입&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;application&lt;/td&gt;
&lt;td&gt;네트워크 애플리케이션을 돕는다FTP, SMTP, HTTP&lt;/td&gt;
&lt;td&gt;message&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;transport&lt;/td&gt;
&lt;td&gt;프로세스와 프로세스 간 데이터를 전달한다 TCP, UDP&lt;/td&gt;
&lt;td&gt;segment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;network&lt;/td&gt;
&lt;td&gt;다른 호스트로 데이터그램을 라우팅한다. IP&lt;/td&gt;
&lt;td&gt;datagram&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;link&lt;/td&gt;
&lt;td&gt;전체 프레임을 이웃 네트워크 요소로 이동한다 . Ethenet&lt;/td&gt;
&lt;td&gt;frame&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;physical&lt;/td&gt;
&lt;td&gt;상위 계층에서 내려온 비트들을 전송 매체를 통하여 어떤 전기적 신호로 전송할 것인가를 담당&lt;/td&gt;
&lt;td&gt;bit&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(스위치&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가 여러 디바이스를 연결하여 네트워크를 만들듯이,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라우터&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;는 여러&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;스위치&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;그리고 각각의 네트워크들을 연결하여 더 큰 네트워크를 형성합니다.)&lt;/span&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Switch와 Router에서 쓰이는 레이어 &lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;switch : link layer, physical layer router : network layer, link layer, physical layer&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;캡슐화&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터넷 프로토콜에서 메세지에 각 층을 내려오며 헤더를 붙여 보내는 걸 캡슐화라고 한다. 그리고 각 계층에선 자기 단계에서 필요한 헤더를 하나씩 까보면서 자기가 할일을 하는걸 인캡슐화라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1968&quot; data-origin-height=&quot;1116&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDOeOk/btrSaI7o9iY/kumCGRuykLxaVzGvpSByWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDOeOk/btrSaI7o9iY/kumCGRuykLxaVzGvpSByWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDOeOk/btrSaI7o9iY/kumCGRuykLxaVzGvpSByWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDOeOk%2FbtrSaI7o9iY%2FkumCGRuykLxaVzGvpSByWK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;751&quot; height=&quot;426&quot; data-origin-width=&quot;1968&quot; data-origin-height=&quot;1116&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Network security&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;botnet PC란? (좀비PC) botnet은 악성 bot에 감염된 pc끼리 형성된 네트워크를 말하며, botnet의 일원이 되면 DDos attack에 가담된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Packet Sniffing이란? 패킷을 중간에 가로채 디코딩하여 안에 있는 정보를 얻는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IP spoofing이란? 전송되는 패킷의 송신자 주소(IP)를 바꾸어 보내는 공격 방법 (ex,발신자번호표시제한) B라는 사용자가 A에게 C인척하면서 패킷을 보내는 것(위장)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;malware의 종류를 쓰시오&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;computer virus,&lt;/li&gt;
&lt;li&gt;트로이목마,&lt;/li&gt;
&lt;li&gt;웜 바이러스,&lt;/li&gt;
&lt;li&gt;스파이 웨어&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>CS</category>
      <category>circuit switching</category>
      <category>Network</category>
      <category>OSI</category>
      <category>Packet</category>
      <category>Packet Switching</category>
      <category>개념</category>
      <category>개념정리</category>
      <category>서킷스위칭</category>
      <category>컴퓨터 네트워크</category>
      <category>패킷스위칭</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/135</guid>
      <comments>https://aimk12.tistory.com/135#entry135comment</comments>
      <pubDate>Sat, 26 Nov 2022 17:27:11 +0900</pubDate>
    </item>
    <item>
      <title>백준 1916번:최소비용 구하기</title>
      <link>https://aimk12.tistory.com/134</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1916&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/1916&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1668953359306&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;1916번: 최소비용 구하기&quot; data-og-description=&quot;첫째 줄에 도시의 개수 N(1 &amp;le; N &amp;le; 1,000)이 주어지고 둘째 줄에는 버스의 개수 M(1 &amp;le; M &amp;le; 100,000)이 주어진다. 그리고 셋째 줄부터 M+2줄까지 다음과 같은 버스의 정보가 주어진다. 먼저 처음에는 그&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/1916&quot; data-og-url=&quot;https://www.acmicpc.net/problem/1916&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/fntds/hyQDskjRNc/8oDOIkQvJI7VNgYlIQiLy1/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1916&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/1916&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/fntds/hyQDskjRNc/8oDOIkQvJI7VNgYlIQiLy1/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;1916번: 최소비용 구하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에 도시의 개수 N(1 &amp;le; N &amp;le; 1,000)이 주어지고 둘째 줄에는 버스의 개수 M(1 &amp;le; M &amp;le; 100,000)이 주어진다. 그리고 셋째 줄부터 M+2줄까지 다음과 같은 버스의 정보가 주어진다. 먼저 처음에는 그&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 다익스트라 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 !&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 하던 다익스트라 방식으로는 시간초과가 난다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 왜지... 라는 의구심을 가지고 생각을 해봤다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;아래가 시간초과가 난 코드다 .&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드의 잘못된 점을 찾아보면 방문된 점의 처리가 제대로 안되어 있다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인접한 점의 노드의 간선들을 모두 우선순위 큐에 넣는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 이미 방문했던 노드들은 굳이 for문을 돌릴 필요가 없다 . 하지만 아래는 불필요하게 for문이 돌아가고 있고 여기서 시간이 초과가 되는 것이다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1668930573757&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;queue&amp;gt;
#include &amp;lt;vector&amp;gt;
using namespace std;
#define INF 987654321
int n,m;
int start,e;
int dist[1001];
bool check[1001];
vector&amp;lt;pair&amp;lt;int,int&amp;gt;&amp;gt; arr[1001];
void dijkstra(int start){
    dist[start]=0;
    priority_queue&amp;lt;pair&amp;lt;int,int&amp;gt;, vector&amp;lt;pair&amp;lt;int,int&amp;gt;&amp;gt;,greater&amp;lt;pair&amp;lt;int,int&amp;gt;&amp;gt;&amp;gt; q;
    q.push({dist[start],start});
    while(!q.empty()){
        int distNow = q.top().first;
        int node = q.top().second;
        q.pop();
        check[node] = true;
        for(int i=0;i&amp;lt;arr[node].size();i++){
            int distNext = arr[node][i].first;
            int nodeNext = arr[node][i].second;
            if(!check[nodeNext] &amp;amp;&amp;amp; dist[nodeNext]&amp;gt; dist[node]+distNext){
                dist[nodeNext] = dist[node] + distNext;
                q.push({dist[nodeNext],nodeNext});
            }
        }
    }
}
int main(){
    cin&amp;gt;&amp;gt;n&amp;gt;&amp;gt;m;
    for(int i=0;i&amp;lt;m;i++){
        int a,b,c;
        cin&amp;gt;&amp;gt;a&amp;gt;&amp;gt;b&amp;gt;&amp;gt;c;
        arr[a].push_back({c,b});
    }
    for (int i = 1; i &amp;lt;= n; i++) 
		dist[i] = INF;
    cin&amp;gt;&amp;gt;start&amp;gt;&amp;gt;e;
    dijkstra(start);
    cout &amp;lt;&amp;lt; dist[e];
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;그럼 개선된 코드를 보자&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드와 위의 코드의 차이는&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1668952317073&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if(check[node]) continue;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 이미 방문했던 노드는 for문을 안돌리게 하는 것이다. 불필요한 반복문은 지우자..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 시간 복잡도&amp;nbsp; n log(e)가 되는 것이다. (n은 정점 ,e는 간선)&lt;/p&gt;
&lt;pre id=&quot;code_1668952287640&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;queue&amp;gt;
#include &amp;lt;vector&amp;gt;
using namespace std;
#define INF 987654321
int n,m;
int start,e;
int dist[1001];
bool check[1001];
vector&amp;lt;pair&amp;lt;int,int&amp;gt;&amp;gt; arr[1001];
void dijkstra(int start){
    dist[start]=0;
    priority_queue&amp;lt;pair&amp;lt;int,int&amp;gt;, vector&amp;lt;pair&amp;lt;int,int&amp;gt;&amp;gt;,greater&amp;lt;pair&amp;lt;int,int&amp;gt;&amp;gt;&amp;gt; q;
    q.push({dist[start],start});
    while(!q.empty()){
        int distNow = q.top().first;
        int node = q.top().second;
        q.pop();
        if(check[node]) continue;               //코드 추가
        check[node] = true;
        for(int i=0;i&amp;lt;arr[node].size();i++){
            int distNext = arr[node][i].first;
            int nodeNext = arr[node][i].second;
            if(!check[nodeNext] &amp;amp;&amp;amp; dist[nodeNext]&amp;gt; dist[node]+distNext){
                dist[nodeNext] = dist[node] + distNext;
                q.push({dist[nodeNext],nodeNext});
            }
        }
    }
}
int main(){
    cin&amp;gt;&amp;gt;n&amp;gt;&amp;gt;m;
    for(int i=0;i&amp;lt;m;i++){
        int a,b,c;
        cin&amp;gt;&amp;gt;a&amp;gt;&amp;gt;b&amp;gt;&amp;gt;c;
        arr[a].push_back({c,b});
    }
    for (int i = 1; i &amp;lt;= n; i++) 
		dist[i] = INF;
    cin&amp;gt;&amp;gt;start&amp;gt;&amp;gt;e;
    dijkstra(start);
    cout &amp;lt;&amp;lt; dist[e];
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;이제 인터넷에 잘 알려진 코드를 보자.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드는 방문노드를 생성하지 않고&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1668952600444&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if(dist[node]&amp;lt;distNow) continue;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드를 추가 하면 된다. 이 코드는 시작 점부터 현 node 까지의 최소 거리가&amp;nbsp; 간선으로 등록된 거리보다 작으면 탐색을 안한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 이유는 이미 최소거리가 선정이 되었기때문이다. (이해가 안가면 다익스트라의 최소 간선 크기부터 선택하고 올라가는 것을 잘 생각해보자)&lt;/p&gt;
&lt;pre id=&quot;code_1668952546396&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;queue&amp;gt;
#include &amp;lt;vector&amp;gt;
using namespace std;
#define INF 987654321
int n,m;
int start,e;
int dist[1001];
vector&amp;lt;pair&amp;lt;int,int&amp;gt;&amp;gt; arr[1001];
void dijkstra(int start){
    dist[start]=0;
    priority_queue&amp;lt;pair&amp;lt;int,int&amp;gt;, vector&amp;lt;pair&amp;lt;int,int&amp;gt;&amp;gt;,greater&amp;lt;pair&amp;lt;int,int&amp;gt;&amp;gt;&amp;gt; q;
    q.push({dist[start],start});
    while(!q.empty()){
        int distNow = q.top().first;
        int node = q.top().second;
        q.pop();
        
        if(dist[node]&amp;lt;distNow) continue;    //이거 추가 + 방문 노드 탐색 안함
        for(int i=0;i&amp;lt;arr[node].size();i++){
            int distNext = arr[node][i].first;
            int nodeNext = arr[node][i].second;
            if( dist[nodeNext]&amp;gt; dist[node]+distNext){
                dist[nodeNext] = dist[node] + distNext;
                q.push({dist[nodeNext],nodeNext});
            }
        }
    }
}
int main(){
    cin&amp;gt;&amp;gt;n&amp;gt;&amp;gt;m;
    for(int i=0;i&amp;lt;m;i++){
        int a,b,c;
        cin&amp;gt;&amp;gt;a&amp;gt;&amp;gt;b&amp;gt;&amp;gt;c;
        arr[a].push_back({c,b});
    }
    for (int i = 1; i &amp;lt;= n; i++) 
		dist[i] = INF;
    cin&amp;gt;&amp;gt;start&amp;gt;&amp;gt;e;
    dijkstra(start);
    cout &amp;lt;&amp;lt; dist[e];
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>백준 코딩</category>
      <category>1916</category>
      <category>다익스트라</category>
      <category>백준</category>
      <category>시간초과</category>
      <category>최소비용 구하기</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/134</guid>
      <comments>https://aimk12.tistory.com/134#entry134comment</comments>
      <pubDate>Sun, 20 Nov 2022 23:09:40 +0900</pubDate>
    </item>
    <item>
      <title>R data 연습 다루기</title>
      <link>https://aimk12.tistory.com/133</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;&quot;에 있는건 다 예시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;list.files()-작업 디렉토리 파일 보기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;Csv파일&amp;nbsp;텍스트&amp;nbsp;(탭으로분리)로&amp;nbsp;만듬 &lt;br /&gt;data&amp;lt;-read.table(&quot;sp.txt&quot;,header=TRUE,sep=&quot;\t&quot;)&amp;nbsp; -- data라는 변수에&amp;nbsp; 데이터 테이블 만들기&lt;br /&gt;안되면&amp;nbsp;read.table(&quot;sp.txt&quot;,header=TRUE,sep='\t',fileEncoding=&quot;CP949&quot;,encoding=&quot;UTF-8)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;기능 예시들&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.테이블 추출&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;data[1:5,1:3] 행 과 열 정하기 &lt;br /&gt;head(data)&amp;nbsp;모든변수에&amp;nbsp;대해&amp;nbsp;행&amp;nbsp;6개&amp;nbsp;보여줌 &lt;br /&gt;a=data[ ,c(&quot;Q2A1&quot;,&quot;Q2A2&quot;)]&amp;nbsp; &amp;nbsp; &amp;nbsp;-- 열을 Q2A1,Q2A2 두 개 만 추출해서 테이블 만들고 a변수에 넣기&lt;br /&gt;head(a)&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-- 맨위에서 일부 추출&amp;nbsp;&lt;br /&gt;dim(a)&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -- 행 열 개수 알려줌&lt;br /&gt;a1&amp;lt;-b[b$Q2B==4,]&amp;nbsp; --Q2B가 4인거 출력 &lt;br /&gt;a1&amp;lt;-a1[complete.cases(a1),]&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;--na인 값 빼고 출력&amp;nbsp;&amp;nbsp;또한 중복된 값 제거 &lt;br /&gt;&lt;br /&gt;merge(a1,a2,key=pid)&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;--pid변수를 기준으로 a1,a2 테이블 합치기&lt;br /&gt;sum(b$study) &lt;br /&gt;Summary(data$필드명)-&amp;nbsp;최소&amp;nbsp;평균&amp;nbsp;다나옴 &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; (Min 음수나오면 그냥 코딩에러)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2.freq,hist 함수 쓰기위한 라이브러리&lt;/b&gt;&lt;br /&gt;install.packages(&quot;descr&quot;) &lt;br /&gt;library(descr) &lt;br /&gt;freq(data$sex)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;hist(d1$A_steps)&amp;nbsp; &amp;nbsp; --histgram 만들기&lt;br /&gt;hist(d1$A_steps,breaks=seq(0,10000,by=100))&amp;nbsp; &amp;nbsp;--0부터 10000까지 100단위로 쪼갬&lt;br /&gt;&lt;br /&gt;&lt;b&gt;3.조건문&lt;/b&gt; &lt;br /&gt;d1&amp;lt;-data[(data$A_steps&amp;gt;=0 &amp;amp; data$A_steps&amp;lt;=10000),]&amp;nbsp; -- ($뒤에 있는건 다 테이블안 변수)&lt;br /&gt;View(d1) &lt;br /&gt;Summary(d1)&lt;br /&gt;d2$astepif&amp;lt;-ifelse(d2$A_steps&amp;gt;=3450,1,0)&amp;nbsp; -- 조건문에&amp;nbsp;속한거&amp;nbsp;1,0&amp;nbsp;데이터를&amp;nbsp;astepif라는&amp;nbsp;열&amp;nbsp;생성하고&amp;nbsp;넣음&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;더미데이터 만들기&amp;nbsp;&lt;br /&gt;R2&amp;lt;-aggregate(r2$a_steps,list(r2$pid),mean) -한 피드에 여러개 스텝잇으면 여러개스텝 평균으로 한 피드에 나타냄 &lt;br /&gt;o1=aggregate(A_steps~pid,data=d1,mean)&amp;nbsp; -Pid를&amp;nbsp;기준으로&amp;nbsp;A_steps의&amp;nbsp;mean&amp;nbsp;나오기 &lt;br /&gt;&lt;br /&gt;aggregate(cbind(Q2A1,Q2A2)~Q2B,data=d1,mean) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;4.분산분석법&lt;/b&gt;&lt;br /&gt;t 검증 - 범위 2개&lt;br /&gt;&lt;br /&gt;c1&amp;lt;-a[which(a$MH==7),]&amp;nbsp; mh 가 7 인 테이블&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;c2&amp;lt;-a[which(a$MH!=7),]&amp;nbsp; mh 가 7 아 아닌 테이블&lt;br /&gt;C1_2&amp;lt;-rbind(c1,c2) 행으로 합침&lt;br /&gt;var.test(HT ~ F_BR_2,data=a,conf.level=0.95)&amp;nbsp; -등분산 검정 p-value &amp;gt; 0.05 하면 등분산하다 분산이 같다&lt;br /&gt;데이터&amp;nbsp;분포&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;a$F_BR_2&amp;lt;- ifelse(a$F_BR_1==7,1,0)&lt;br /&gt;t.test(HT ~ F_BR_2,data=a,var.equal=FALSE,conf.level=0.95)&amp;nbsp; &amp;nbsp;-p-value &amp;lt;0.05 이면 유의미 하게 차이있다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;var.equal -&amp;gt;등분산 검정으로 결정&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;5.정규분포&lt;/b&gt;&lt;br /&gt;shapiro.test(o3$A_steps) - p-value &amp;gt;0.05 이면 정규분포 따름&amp;nbsp; ,데이터 크면 굳이 정규분포 검정안해도됨&lt;br /&gt;5000개&amp;nbsp;이내&amp;nbsp;잇어야함&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&lt;b&gt;6.Anova -범위 3개이상&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;a&amp;lt;-b[,c(3,4,8)] &lt;br /&gt;aa$F_BR3=with(aa,ifelse(F_BR1==0,0,ifelse((F_BR1&amp;gt;=1&amp;amp;F_BR1&amp;lt;=6),1,2))) &lt;br /&gt;1)등분산검정 &lt;br /&gt;bartlett.test(HT~F_BR3,data=a) &lt;br /&gt;p-value&amp;lt;0.05 이면 분산 다르다 &lt;br /&gt;out=aov(HT~factor(F_BR3),data=a)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;summary(out)&lt;br /&gt;2)사후검정 &lt;br /&gt;install.packages('agricolae') &lt;br /&gt;library(agricolae) &lt;br /&gt;TukeyHSD(out) &lt;br /&gt;plot(TukeyHSD(out))&amp;nbsp; &amp;nbsp; -- 각각 0을 포함하지 않으면 각각 유의한 차이 존재&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bibG5n/btrPApa5urr/Rjnf2GKmRjXXTROuHyGaM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bibG5n/btrPApa5urr/Rjnf2GKmRjXXTROuHyGaM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bibG5n/btrPApa5urr/Rjnf2GKmRjXXTROuHyGaM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbibG5n%2FbtrPApa5urr%2FRjnf2GKmRjXXTROuHyGaM1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;319&quot; height=&quot;287&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;개념 &lt;br /&gt;포아송분포&amp;nbsp;-이항분포인데&amp;nbsp;한쪽으로&amp;nbsp;치우침&amp;nbsp;(시긴개념이&amp;nbsp;든다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;비모수&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;1. Wilcoxon&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;Signed rank test &lt;span style=&quot;background-color: #ffffff;&quot;&gt;범주형&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;(2&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;군&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;vs. &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;연속형&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;중위수&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;비교&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;wilcox.text(weight~group,data=data1,exact=FALSE,conf.level=0.95)&amp;nbsp; -weight 과 group을 data1이란 곳에서 꺼내와 비교&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2.&lt;span style=&quot;background-color: #ffffff;&quot;&gt;Kruskal&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;Wallis test &lt;span style=&quot;background-color: #ffffff;&quot;&gt;범주형&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;(3&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;군&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;vs. &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;연속형&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;중위수&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;비교&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;kruskal.test(weight~group,data=data)&amp;nbsp; -weight 과 group을 data1이란 곳에서 꺼내와 비교&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;상관관계&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;plot(speed~dist,data=cars)&amp;nbsp; &amp;nbsp; -- cars란 곳에서 speed 와 dist 꺼내와 두 변수의 관계를 그림으로 나타냄&lt;br /&gt;lines(lowess(cars))&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-- 라인을 따라그림&lt;br /&gt;cor.test(cars$speed,cars&amp;amp;dist)&amp;nbsp; &amp;nbsp; -- p-value&amp;lt;0.05 면 상관성이 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;다중회귀 분석&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;res=lm(play ~ study, data=data)&amp;nbsp; &amp;nbsp; -- study가 play에 미치는 영향력 계산후 res 담기&lt;br /&gt;res&lt;br /&gt;abline(res)&lt;br /&gt;summary(res)&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -- 요약해서 보여줌&lt;br /&gt;AIC는&amp;nbsp;값이&amp;nbsp;작을수록&amp;nbsp;설명력이&amp;nbsp;커진다&lt;br /&gt;Step(res,direction=&quot;forward&quot;)&lt;br /&gt;Step(res,direction=&quot;backward&quot;)&lt;br /&gt;Step(res,direction=&quot;both&quot;)&lt;br /&gt;library(car)&lt;br /&gt;vif(res)&amp;nbsp;10넘기면&amp;nbsp;비정확&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;값이 2개이상이면&lt;br /&gt;res=lm(addicted ~play+ study, data=data)&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -- addicted변수에 play,study가 미치는 영향을 계산후 res 담음&lt;br /&gt;summary(res)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;br /&gt;&lt;b&gt;범주형 자료 분석&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;a4 &amp;lt;- CrossTable(b$obstruct,b$status) --범주현 변수 2개를 테이블로 만듬&lt;br /&gt;a3&amp;lt;-table(b$mh,b$sex)&lt;br /&gt;install.packages(&quot;Rcmdr&quot;)&lt;br /&gt;library(Rcmdr)&lt;br /&gt;rowPercents(a3)&lt;br /&gt;colPercents(a3)&amp;nbsp;&lt;br /&gt;&lt;br /&gt;chisq.test(b$mh,b$sex)&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>기타</category>
      <category>anova검정</category>
      <category>R</category>
      <category>t검정</category>
      <category>등분산검정</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/133</guid>
      <comments>https://aimk12.tistory.com/133#entry133comment</comments>
      <pubDate>Tue, 25 Oct 2022 23:07:04 +0900</pubDate>
    </item>
    <item>
      <title>docker 안에 있는 mariaDB 접속하기</title>
      <link>https://aimk12.tistory.com/132</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;오픈소스 기여 하기 위해 docker개발 환경을 구축했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 DB에 접근하는 기회가 생기고 방법을 알아내서 기록을 남긴다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 해당 파일에서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;docker ps&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;누르기&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1146&quot; data-origin-height=&quot;356&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JSfEI/btrMaJRGuw0/lA9elEl1IZDMr5xXwkMIGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JSfEI/btrMaJRGuw0/lA9elEl1IZDMr5xXwkMIGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JSfEI/btrMaJRGuw0/lA9elEl1IZDMr5xXwkMIGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJSfEI%2FbtrMaJRGuw0%2FlA9elEl1IZDMr5xXwkMIGK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1146&quot; height=&quot;356&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1146&quot; data-origin-height=&quot;356&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 이런 컨테이너 id랑 이미지 커맨드 등등 여러개가 나올 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 밑에 있는 mariadb를 실행하기 위해&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;docker exec -it [컨테이너 이름] /bin/bash&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1126&quot; data-origin-height=&quot;60&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7Djk4/btrMafcdDNP/EVF2hWnkd0kxiNT7Fi929K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7Djk4/btrMafcdDNP/EVF2hWnkd0kxiNT7Fi929K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7Djk4/btrMafcdDNP/EVF2hWnkd0kxiNT7Fi929K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7Djk4%2FbtrMafcdDNP%2FEVF2hWnkd0kxiNT7Fi929K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1126&quot; height=&quot;60&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1126&quot; data-origin-height=&quot;60&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;mysql -u root -p&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력하면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;292&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d4xOlQ/btrMabt61zC/FfYvVwZfwiO3UldLhZIVeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d4xOlQ/btrMabt61zC/FfYvVwZfwiO3UldLhZIVeK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d4xOlQ/btrMabt61zC/FfYvVwZfwiO3UldLhZIVeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd4xOlQ%2FbtrMabt61zC%2FFfYvVwZfwiO3UldLhZIVeK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;292&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;292&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접속 성공!&lt;/p&gt;</description>
      <category>기타</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/132</guid>
      <comments>https://aimk12.tistory.com/132#entry132comment</comments>
      <pubDate>Thu, 15 Sep 2022 00:27:33 +0900</pubDate>
    </item>
    <item>
      <title>docker mailserver 메일이 발송이 안될때</title>
      <link>https://aimk12.tistory.com/131</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Docker 메일 서버를 세팅하고 테스트 삼아 내 이메일에 보내봤다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지메일 네이버 둘 다 실패하고 outlook 학교메일에 보내봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과는..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;550 5.7.606 Access denied, banned sending IP 뒤에는 내 컴퓨터 IP주소가 나와서 생략.. ㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결 방법은 코드 뒤에 나오는&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1502&quot; data-origin-height=&quot;50&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R6Odj/btrL83X5zYv/GIvWrKCLWkj2yivw0hgJ80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R6Odj/btrL83X5zYv/GIvWrKCLWkj2yivw0hgJ80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R6Odj/btrL83X5zYv/GIvWrKCLWkj2yivw0hgJ80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR6Odj%2FbtrL83X5zYv%2FGIvWrKCLWkj2yivw0hgJ80%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1502&quot; height=&quot;50&quot; data-origin-width=&quot;1502&quot; data-origin-height=&quot;50&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 링크를 따라 가면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;링크를 가면 이런 창이 나온다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2420&quot; data-origin-height=&quot;1328&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckJxUz/btrL6QEXqWJ/vfYL9BxevWIMGzMpDRmXIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckJxUz/btrL6QEXqWJ/vfYL9BxevWIMGzMpDRmXIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckJxUz/btrL6QEXqWJ/vfYL9BxevWIMGzMpDRmXIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckJxUz%2FbtrL6QEXqWJ%2FvfYL9BxevWIMGzMpDRmXIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2420&quot; height=&quot;1328&quot; data-origin-width=&quot;2420&quot; data-origin-height=&quot;1328&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전자 메일 주소에 office 365 이메일을 입력하고 내 컴퓨터 ip 주소 입력!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1556&quot; data-origin-height=&quot;270&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bg3Do6/btrL9rc844I/QhoYRk2r3oBPXFaNBIvIOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bg3Do6/btrL9rc844I/QhoYRk2r3oBPXFaNBIvIOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bg3Do6/btrL9rc844I/QhoYRk2r3oBPXFaNBIvIOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbg3Do6%2FbtrL9rc844I%2FQhoYRk2r3oBPXFaNBIvIOK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1556&quot; height=&quot;270&quot; data-origin-width=&quot;1556&quot; data-origin-height=&quot;270&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이런 메일이 오게 된다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주소 확인 버튼을 누르면 요청이 되고 한 30분 정도 지나고 다시 시도하면 성공!!&lt;/p&gt;</description>
      <category>기타</category>
      <category>도커</category>
      <category>메일</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/131</guid>
      <comments>https://aimk12.tistory.com/131#entry131comment</comments>
      <pubDate>Wed, 14 Sep 2022 23:58:22 +0900</pubDate>
    </item>
    <item>
      <title>백준 1197번: 최소 스패닝 트리(프림 알고리즘)</title>
      <link>https://aimk12.tistory.com/130</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1197&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/1197&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1661008786375&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;1197번: 최소 스패닝 트리&quot; data-og-description=&quot;첫째 줄에 정점의 개수 V(1 &amp;le; V &amp;le; 10,000)와 간선의 개수 E(1 &amp;le; E &amp;le; 100,000)가 주어진다. 다음 E개의 줄에는 각 간선에 대한 정보를 나타내는 세 정수 A, B, C가 주어진다. 이는 A번 정점과 B번 정점이 &quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/1197&quot; data-og-url=&quot;https://www.acmicpc.net/problem/1197&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bcMZ0h/hyPvXeLAxr/YagKHfK015ZRhrZcz7L8c0/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1197&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/1197&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bcMZ0h/hyPvXeLAxr/YagKHfK015ZRhrZcz7L8c0/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;1197번: 최소 스패닝 트리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에 정점의 개수 V(1 &amp;le; V &amp;le; 10,000)와 간선의 개수 E(1 &amp;le; E &amp;le; 100,000)가 주어진다. 다음 E개의 줄에는 각 간선에 대한 정보를 나타내는 세 정수 A, B, C가 주어진다. 이는 A번 정점과 B번 정점이&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 최소신장 트리 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최소 신장 트리는 크루스칼 알고리즘과 프림 알고리즘으로 풀 수 있는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;BFS에 우선순위 큐&lt;/b&gt;&lt;/span&gt;만 더하면 된다고 생각해서 프림 알고리즘으로 풀었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프림 알고리즘은&amp;nbsp; 간단하게&amp;nbsp; 시작 노드에서 가중치가 작은 간선을 이어가며 구하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크루스칼 알고리즘은 사이클이 생성되지 않게 작은 가중치를 가진 간선을 연결하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 보자&lt;/p&gt;
&lt;pre id=&quot;code_1661008953701&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;queue&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;vector&amp;gt;
using namespace std;
int v,e;
long long ans;
bool visit[10001];
vector&amp;lt;pair&amp;lt;int,int&amp;gt;&amp;gt; node[10001];
priority_queue&amp;lt;pair&amp;lt;int,int&amp;gt;,vector&amp;lt;pair&amp;lt;int,int&amp;gt;&amp;gt;,greater&amp;lt;pair&amp;lt;int,int&amp;gt;&amp;gt;&amp;gt; pq;
int main(){
    cin.tie(NULL);
	cout.tie(NULL);
	ios_base::sync_with_stdio(false);
    cin &amp;gt;&amp;gt;v&amp;gt;&amp;gt;e;
    for(int i=0;i&amp;lt;e;i++){
        int a,b,c;
        cin&amp;gt;&amp;gt;a&amp;gt;&amp;gt;b&amp;gt;&amp;gt;c;
        node[a].push_back({b,c});
        node[b].push_back({a,c});
    }
    pq.push({0,1}); //가중치, 노드
    while(!pq.empty()){
        int w=pq.top().first;
        int next=pq.top().second;
        pq.pop();
        if(visit[next]) continue;
        visit[next]=true;
        ans+=w;
        for(int i=0;i&amp;lt;node[next].size();i++){
            int nextw=node[next][i].second;
            int nextnode=node[next][i].first;
            pq.push({nextw,nextnode});
        }
    }
    cout &amp;lt;&amp;lt;ans;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>백준 코딩</category>
      <category>1197번</category>
      <category>백준</category>
      <category>최소신장트리</category>
      <category>프림알고리즘</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/130</guid>
      <comments>https://aimk12.tistory.com/130#entry130comment</comments>
      <pubDate>Sun, 21 Aug 2022 00:22:55 +0900</pubDate>
    </item>
    <item>
      <title>10830번 : 행렬 제곱</title>
      <link>https://aimk12.tistory.com/129</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/10830&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/10830&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1658637536175&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;10830번: 행렬 제곱&quot; data-og-description=&quot;크기가 N*N인 행렬 A가 주어진다. 이때, A의 B제곱을 구하는 프로그램을 작성하시오. 수가 매우 커질 수 있으니, A^B의 각 원소를 1,000으로 나눈 나머지를 출력한다.&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/10830&quot; data-og-url=&quot;https://www.acmicpc.net/problem/10830&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cX2T8j/hyPbNKceYB/JYmJXhwlIKbSkPlcQ5Mc11/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/10830&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/10830&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cX2T8j/hyPbNKceYB/JYmJXhwlIKbSkPlcQ5Mc11/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;10830번: 행렬 제곱&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;크기가 N*N인 행렬 A가 주어진다. 이때, A의 B제곱을 구하는 프로그램을 작성하시오. 수가 매우 커질 수 있으니, A^B의 각 원소를 1,000으로 나눈 나머지를 출력한다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 &lt;span style=&quot;background-color: #ffffff; color: #222222;&quot;&gt;100,000,000,000번 &lt;/span&gt;곱해야하는 문제이다 . 즉 시간복잡도가 O(log n)이 아니면 불가능 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 분할 정복을 생각하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 풀이는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제곱수가 n이라 하고 행렬 a가 있다고 할 때,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex)n=10이라고 하자. 나는 재귀로 풀었기에 n은 1,2,4,5,10으로 올라가는 형태이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;즉 n=1일때 A&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;n=2일때 A*A=A^2&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;n=4일 떄 는&amp;nbsp; (A^2)*(A^2)=A^4&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;n=5일 때 는 기본행렬 곱이므로&amp;nbsp; (A^4)*A&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;n=10일 떄는 ((A^4)*A)*((A^4)*A)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;즉 n%2==1이면 제곱 행렬에 기본행렬을 곱하고&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;n%2==0이면 제곱행렬을 두번 곱한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 보면 이해가 될 것 이다.&lt;/p&gt;
&lt;pre id=&quot;code_1658638112929&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;
#define mod 1000
long long n,m;
long long matrix[6][6];
long long temp[6][6];
long long ans[6][6];
void divide(long long x){
    if(x==1){
        for(int i=0;i&amp;lt;n;i++){
            for(int k=0;k&amp;lt;n;k++){
                ans[i][k]=temp[i][k]%mod;
        }
    }
        return;
    }
    if(x%2==1){
        divide(x-1);
        for(int i=0;i&amp;lt;n;i++){
            for(int j=0;j&amp;lt;n;j++){
                ans[i][j]=0;
                for(int t=0;t&amp;lt;n;t++){
                    ans[i][j]+=temp[i][t]*matrix[t][j];              //홀수 이면 기본 행렬 곱해주기
                    
                }
                ans[i][j]%=mod;
            }
        }
        for(int i=0;i&amp;lt;n;i++){
            for(int k=0;k&amp;lt;n;k++){
                temp[i][k]=ans[i][k];                             //결과값 저장
        }
    }
        return;
    }
    divide(x/2);
    for(int i=0;i&amp;lt;n;i++){
        for(int j=0;j&amp;lt;n;j++){
            ans[i][j]=0;
            for(int t=0;t&amp;lt;n;t++){
                ans[i][j]+=temp[i][t]*temp[t][j];                       //짝수이면 거듭곱 행렬 곱하기
            }
            ans[i][j]%=mod;
        }
    }
    for(int i=0;i&amp;lt;n;i++){
        for(int k=0;k&amp;lt;n;k++){
            temp[i][k]=ans[i][k];
        }
    }
    
}
int main(){
    cin &amp;gt;&amp;gt;n&amp;gt;&amp;gt;m;
    for(int i=0;i&amp;lt;n;i++){
        for(int k=0;k&amp;lt;n;k++){
            cin&amp;gt;&amp;gt;matrix[i][k];
            temp[i][k]=matrix[i][k];
        }
    }
    divide(m);
    for(int i=0;i&amp;lt;n;i++){
        for(int k=0;k&amp;lt;n;k++){
            cout &amp;lt;&amp;lt;ans[i][k]&amp;lt;&amp;lt;' ';
        }
        cout&amp;lt;&amp;lt;'\n';
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>백준 코딩</category>
      <category>10830</category>
      <category>거듭제곱</category>
      <category>백준</category>
      <category>분할 정복</category>
      <category>재귀</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/129</guid>
      <comments>https://aimk12.tistory.com/129#entry129comment</comments>
      <pubDate>Sun, 24 Jul 2022 13:49:27 +0900</pubDate>
    </item>
    <item>
      <title>Mysql 기본기능들 정리</title>
      <link>https://aimk12.tistory.com/128</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/functions.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://dev.mysql.com/doc/refman/8.0/en/functions.html&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1658423469397&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;MySQL :: MySQL 8.0 Reference Manual :: 12 Functions and Operators&quot; data-og-description=&quot;Chapter 12 Functions and Operators Expressions can be used at several points in SQL statements, such as in the ORDER BY or HAVING clauses of SELECT statements, in the WHERE clause of a SELECT, DELETE, or UPDATE statement, or in SET statements. Expressions &quot; data-og-host=&quot;dev.mysql.com&quot; data-og-source-url=&quot;https://dev.mysql.com/doc/refman/8.0/en/functions.html&quot; data-og-url=&quot;https://dev.mysql.com/doc/refman/8.0/en/functions.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/functions.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.mysql.com/doc/refman/8.0/en/functions.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;MySQL :: MySQL 8.0 Reference Manual :: 12 Functions and Operators&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Chapter 12 Functions and Operators Expressions can be used at several points in SQL statements, such as in the ORDER BY or HAVING clauses of SELECT statements, in the WHERE clause of a SELECT, DELETE, or UPDATE statement, or in SET statements. Expressions&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.mysql.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(참고 자료)&lt;/b&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1.연산자 기능들&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연산자&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;의미&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;+&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;-&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;*&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;/&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;각각 더하기, 빼기, 곱하기, 나누기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;%&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;MOD&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;나머지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;IS&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;양쪽이 모두 TRUE 또는 FALSE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;IS NOT&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;한쪽은 TRUE, 한쪽은 FALSE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;AND&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&amp;amp;&amp;amp;&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;양쪽이 모두 TRUE일 때만 TRUE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;OR&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;||&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;한쪽은 TRUE면 TRUE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;=&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;양쪽 값이 같음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;!=&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&amp;lt;&amp;gt;&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;양쪽 값이 다름&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;&amp;gt;&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&amp;lt;&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;(왼쪽, 오른쪽) 값이 더 큼&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;&amp;gt;=&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&amp;lt;=&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;(왼쪽, 오른쪽) 값이 같거나 더 큼&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;BETWEEN&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;{MIN}&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;AND&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;{MAX}&lt;/td&gt;
&lt;td&gt;두 값 사이에 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;NOT BETWEEN&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;{MIN}&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;AND&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;{MAX}&lt;/td&gt;
&lt;td&gt;두 값 사이가 아닌 곳에 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;IN&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(...)&lt;/td&gt;
&lt;td&gt;괄호 안의 값들 가운데 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;NOT IN&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(...)&lt;/td&gt;
&lt;td&gt;괄호 안의 값들 가운데 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;LIKE&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;'...&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;%&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;...'&lt;/td&gt;
&lt;td&gt;0~N개 문자를 가진 패턴&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;LIKE&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;'...&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;_&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;...'&lt;/td&gt;
&lt;td&gt;_ 갯수만큼의 문자를 가진 패턴&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2.숫자와 문자열을 다루는 함수들&lt;/b&gt;&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;ROUND&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;반올림&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;CEIL&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;올림&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;FLOOR&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;내림&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;ABS&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;절대값&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;GREATEST&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;(괄호 안에서) 가장 큰 값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;LEAST&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;(괄호 안에서) 가장 작은 값&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;MAX&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;가장 큰 값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;MIN&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;가장 작은 값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;COUNT&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;갯수 (NULL값 제외)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;SUM&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;총합&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;AVG&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;평균 값&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;POW&lt;/b&gt;(A, B),&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;POWER&lt;/b&gt;(A, B)&lt;/td&gt;
&lt;td&gt;A를 B만큼 제곱&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;SQRT&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;제곱근&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;TRUNCATE&lt;/b&gt;(N, n)&lt;/td&gt;
&lt;td&gt;N을 소숫점 n자리까지 선택&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;UCASE&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;UPPER&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;모두 대문자로&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;LCASE&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;LOWER&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;모두 소문자로&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;CONCAT&lt;/b&gt;(...)&lt;/td&gt;
&lt;td&gt;괄호 안의 내용 이어붙임&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;CONCAT_WS&lt;/b&gt;(S, ...)&lt;/td&gt;
&lt;td&gt;괄호 안의 내용 S로 이어붙임&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;SUBSTR&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;SUBSTRING&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;주어진 값에 따라 문자열 자름&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;LEFT&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;왼쪽부터 N글자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;RIGHT&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;오른쪽부터 N글자&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;LENGTH&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;문자열의 바이트 길이&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;CHAR_LENGTH&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;CHARACTER_LEGNTH&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;문자열의 문자 길이&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;TRIM&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;양쪽 공백 제거&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;LTRIM&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;왼쪽 공백 제거&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;RTRIM&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;오른쪽 공백 제거&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;LPAD&lt;/b&gt;(S, N, P)&lt;/td&gt;
&lt;td&gt;S가 N글자가 될 때까지 P를 이어붙임&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;RPAD&lt;/b&gt;(S, N, P)&lt;/td&gt;
&lt;td&gt;S가 N글자가 될 때까지 P를 이어붙임&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;REPLACE(S, A, B)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;S중 A를 B로 변경&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;INSTR&lt;/b&gt;(S, s)&lt;/td&gt;
&lt;td&gt;S중 s의 첫 위치 반환, 없을 시 0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;CAST&lt;/b&gt;(A, T)&lt;/td&gt;
&lt;td&gt;A를 T 자료형으로 변환&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 시간/날짜 관련 함수들&lt;/b&gt;&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;CURRENT_DATE&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;CURDATE&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;현재 날짜 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;CURRENT_TIME&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;CURTIME&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;현재 시간 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;CURRENT_TIMESTAMP&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;NOW&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;현재 시간과 날짜 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DATE&lt;/td&gt;
&lt;td&gt;문자열에 따라 날짜 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TIME&lt;/td&gt;
&lt;td&gt;문자열에 따라 시간 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;YEAR&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;주어진 DATETIME값의 년도 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;MONTHNAME&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;주어진 DATETIME값의 월(영문) 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;MONTH&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;주어진 DATETIME값의 월 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;WEEKDAY&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;주어진 DATETIME값의 요일값 반환(월요일: 0)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;DAYNAME&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;주어진 DATETIME값의 요일명 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;DAYOFMONTH&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;DAY&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;주어진 DATETIME값의 날짜(일) 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;HOUR&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;주어진 DATETIME의 시 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;MINUTE&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;주어진 DATETIME의 분 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;SECOND&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;주어진 DATETIME의 초 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;ADDDATE&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;DATE_ADD&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;시간/날짜 더하기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;SUBDATE&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;DATE_SUB&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;시간/날짜 빼기&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;DATE_DIFF&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;두 시간/날짜 간 일수차&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;TIME_DIFF&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;두 시간/날짜 간 시간차&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;LAST_DAY&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;해당 달의 마지막 날짜&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DATE_FORMAT&lt;/td&gt;
&lt;td&gt;시간/날짜를 지정한 형식으로 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 형식 문법&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;%Y&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;년도 4자리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;%y&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;년도 2자리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;%M&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;월 영문&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;%m&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;월 숫자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;%D&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;일 영문(1st, 2nd, 3rd...)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;%d&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;%e&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;일 숫자 (01 ~ 31)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;%T&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;hh:mm:ss&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;%r&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;hh:mm:ss AM/PM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;%H&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;%k&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;시 (~23)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;%h&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;%l&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;시 (~12)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;%i&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;분&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;%S&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;%s&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;초&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;%p&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;AM/PM&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시)&lt;/p&gt;
&lt;pre id=&quot;code_1658423621958&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT
  DATE_FORMAT(NOW(), '%M %D, %Y %T'),
  DATE_FORMAT(NOW(), '%y-%m-%d %h:%i:%s %p'),
  DATE_FORMAT(NOW(), '%Y년 %m월 %d일 %p %h시 %i분 %s초');&lt;/code&gt;&lt;/pre&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;STR _ TO _ DATE&lt;/b&gt;(S, F)&lt;/td&gt;
&lt;td&gt;S를 F형식으로 해석하여 시간/날짜 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. 기타 함수들&lt;/b&gt;&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;IF&lt;/b&gt;(조건, T, F)&lt;/td&gt;
&lt;td&gt;조건이 참이라면 T, 거짓이면 F 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;IFNULL&lt;/b&gt;(A, B)&lt;/td&gt;
&lt;td&gt;A가 NULL일 시 B 출력&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. 그룹으로 묶기&lt;/b&gt;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;GROUP BY&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;- 조건에 따라 집계된 값을 가져옵니다.&lt;/h2&gt;
&lt;pre id=&quot;code_1658423737413&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT
  COUNT(*), OrderDate
FROM Orders
GROUP BY OrderDate;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1468&quot; data-origin-height=&quot;381&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l6F94/btrHSK216xE/Zbx8mEripY1fgemFGdzO3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l6F94/btrHSK216xE/Zbx8mEripY1fgemFGdzO3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l6F94/btrHSK216xE/Zbx8mEripY1fgemFGdzO3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl6F94%2FbtrHSK216xE%2FZbx8mEripY1fgemFGdzO3k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1468&quot; height=&quot;381&quot; data-origin-width=&quot;1468&quot; data-origin-height=&quot;381&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 것은 orderdate 마다 그룹된 행들을 카운트 하는 것이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;WITH ROLLUP&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;- 전체의 집계값&lt;/h3&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;HAVING&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;- 그룹화된 데이터 걸러내기&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;WHERE&lt;/b&gt;는 그룹하기 전 데이터,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;HAVING&lt;/b&gt;은 그룹 후 집계에 사용&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1658423859082&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT
  COUNT(*) AS Count, OrderDate
FROM Orders
WHERE OrderDate &amp;gt; DATE('1996-12-31')
GROUP BY OrderDate
HAVING Count &amp;gt; 2;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;DISTINCT&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;- 중복된 값들을 제거합니다.&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시)&lt;/p&gt;
&lt;pre id=&quot;code_1658423897978&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT
  Country,
  COUNT(DISTINCT CITY)
FROM Customers
GROUP BY Country;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드로 country로 묶은 것 중에 중복되지 않는 city만 센다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;740&quot; data-origin-height=&quot;277&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c3PYYy/btrHUK8Oihr/KVmt2wKvuekKJmD0dGUe30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c3PYYy/btrHUK8Oihr/KVmt2wKvuekKJmD0dGUe30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c3PYYy/btrHUK8Oihr/KVmt2wKvuekKJmD0dGUe30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc3PYYy%2FbtrHUK8Oihr%2FKVmt2wKvuekKJmD0dGUe30%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;740&quot; height=&quot;277&quot; data-origin-width=&quot;740&quot; data-origin-height=&quot;277&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약에 DISTINCT가 없으면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1191&quot; data-origin-height=&quot;338&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDWGbX/btrHTEhdjPC/Nd3XOgx9kpozz5VK50YQQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDWGbX/btrHTEhdjPC/Nd3XOgx9kpozz5VK50YQQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDWGbX/btrHTEhdjPC/Nd3XOgx9kpozz5VK50YQQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDWGbX%2FbtrHTEhdjPC%2FNd3XOgx9kpozz5VK50YQQK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1191&quot; height=&quot;338&quot; data-origin-width=&quot;1191&quot; data-origin-height=&quot;338&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>데이터베이스</category>
      <category>MySQL</category>
      <category>데이터베이스</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/128</guid>
      <comments>https://aimk12.tistory.com/128#entry128comment</comments>
      <pubDate>Fri, 22 Jul 2022 02:20:13 +0900</pubDate>
    </item>
    <item>
      <title>Git rebase 이용</title>
      <link>https://aimk12.tistory.com/127</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;commit여러개 있을 떄 basecommit 바꾸는 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;basecommit: 내 로컬에 저장된 commit&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.git log &amp;mdash;oneline 으로 commit 목록 확인&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;770&quot; data-origin-height=&quot;291&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l9Ole/btrGWyIs2sO/00tf4a8xNuJylIsRjZHBw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l9Ole/btrGWyIs2sO/00tf4a8xNuJylIsRjZHBw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l9Ole/btrGWyIs2sO/00tf4a8xNuJylIsRjZHBw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl9Ole%2FbtrGWyIs2sO%2F00tf4a8xNuJylIsRjZHBw1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;770&quot; height=&quot;291&quot; data-origin-width=&quot;770&quot; data-origin-height=&quot;291&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.git rebase -i -root (root부터 commit 확인)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;684&quot; data-origin-height=&quot;109&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJGw2m/btrGVlvQ8y4/xwjlk6TNGAS14tQic5KNO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJGw2m/btrGVlvQ8y4/xwjlk6TNGAS14tQic5KNO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJGw2m/btrGVlvQ8y4/xwjlk6TNGAS14tQic5KNO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJGw2m%2FbtrGVlvQ8y4%2Fxwjlk6TNGAS14tQic5KNO1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;684&quot; height=&quot;109&quot; data-origin-width=&quot;684&quot; data-origin-height=&quot;109&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3.basecommit 로 두고자하는 commit에 pick &amp;rarr;edit으로 바꿈&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;835&quot; data-origin-height=&quot;484&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SlHaK/btrGVkKrHVo/LTiX0vMQcBsRHy0ESlCJak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SlHaK/btrGVkKrHVo/LTiX0vMQcBsRHy0ESlCJak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SlHaK/btrGVkKrHVo/LTiX0vMQcBsRHy0ESlCJak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSlHaK%2FbtrGVkKrHVo%2FLTiX0vMQcBsRHy0ESlCJak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;835&quot; height=&quot;484&quot; data-origin-width=&quot;835&quot; data-origin-height=&quot;484&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4, 그럼 commit 목록이 edit부터 나옴&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;468&quot; data-origin-height=&quot;110&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O00F2/btrGQczPmP0/FGqm6iSxElypWxCtF0slg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O00F2/btrGQczPmP0/FGqm6iSxElypWxCtF0slg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O00F2/btrGQczPmP0/FGqm6iSxElypWxCtF0slg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO00F2%2FbtrGQczPmP0%2FFGqm6iSxElypWxCtF0slg1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;468&quot; height=&quot;110&quot; data-origin-width=&quot;468&quot; data-origin-height=&quot;110&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5.git rebase &amp;mdash;continue ( 원래 있던 commit들 다시 되돌리기)-&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;382&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzH72U/btrGTwkmR5t/b6EzNMh0Kpe2ioCvR4FZSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzH72U/btrGTwkmR5t/b6EzNMh0Kpe2ioCvR4FZSk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzH72U/btrGTwkmR5t/b6EzNMh0Kpe2ioCvR4FZSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzH72U%2FbtrGTwkmR5t%2Fb6EzNMh0Kpe2ioCvR4FZSk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;798&quot; height=&quot;382&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;382&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 과정을 통해 basecommit 위치를 마음대로 바꾸고 중간에 삽입도 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git rebase -i (interative 기능 사용하는 상황) &amp;mdash;rewind 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) rebase 취소하는 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;rebase &amp;mdash;abort&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2)히스토리 전체 원상 복구 하는 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git reset &amp;mdash;hard origin/master&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>GitHub,Git</category>
      <category>GIT</category>
      <category>rebase</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/127</guid>
      <comments>https://aimk12.tistory.com/127#entry127comment</comments>
      <pubDate>Mon, 11 Jul 2022 01:11:14 +0900</pubDate>
    </item>
    <item>
      <title>Git 추가된 최신 commit 로컬로 가져오기</title>
      <link>https://aimk12.tistory.com/126</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;git remote add upstream [git url]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git fetch upstream master (.git 히스토리에만 저장)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(pull=fetch+merge)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;upstream/master 브랜치명 자동생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 base를 최신으로 갱신&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git rebase upstream/master&lt;/p&gt;
&lt;h1&gt;PR하는 도중 기존 저장소가 다른 Commit을 받아들여 내 로컬 Commot이랑 달라 질때 (같은 파일 수정 인 경우)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.내가 추가한 커밋을 rewind (따로 뺴두고)한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.fetch를 이용해 변경된 commit을 내 로컬에 가져온다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3.git rebase --continue 통해 따로 빼낫던 내 commit을 다시 위에 올린다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4.완성된 commit을 push 한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) README.md 파일이 같이 수정되면서 겹칠경우&lt;/p&gt;
&lt;pre id=&quot;code_1657468986751&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; git fetch upstream master
 git rebase upstream/master 
 git status
 git diff 
 nano README.md
 git add . 
 git rebase --continue 
 git push origin master -f&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>GitHub,Git</category>
      <category>GIT</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/126</guid>
      <comments>https://aimk12.tistory.com/126#entry126comment</comments>
      <pubDate>Mon, 11 Jul 2022 01:04:29 +0900</pubDate>
    </item>
    <item>
      <title>Git add,commit 삭제 및 수정</title>
      <link>https://aimk12.tistory.com/125</link>
      <description>&lt;h1&gt;5.git add,commit 삭제 ,수정, (라이센스 서명 넣는법)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;git diff - 바뀐 내용 확인&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;git stash -임시 저장(수정 결과 체크용)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;323&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cZq1rw/btrGS5tKJIW/gtjjrcH87qUNjKX3kIip3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cZq1rw/btrGS5tKJIW/gtjjrcH87qUNjKX3kIip3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cZq1rw/btrGS5tKJIW/gtjjrcH87qUNjKX3kIip3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcZq1rw%2FbtrGS5tKJIW%2FgtjjrcH87qUNjKX3kIip3K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;880&quot; height=&quot;323&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;323&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;변경된거 원상 복구&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git checkout &amp;mdash; mnist/main.py&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git checkout &amp;mdash; ./ (폴도 원상복구 전체)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;881&quot; data-origin-height=&quot;42&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L3OeZ/btrGTwR9oXA/9pu39xG7GyxXKoG9bwjgxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L3OeZ/btrGTwR9oXA/9pu39xG7GyxXKoG9bwjgxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L3OeZ/btrGTwR9oXA/9pu39xG7GyxXKoG9bwjgxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL3OeZ%2FbtrGTwR9oXA%2F9pu39xG7GyxXKoG9bwjgxK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;881&quot; height=&quot;42&quot; data-origin-width=&quot;881&quot; data-origin-height=&quot;42&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;checkout vs stash 차이&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;stash 임시 저장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;checkout 뜻- 히스토리 창고(.git) 에서 가져온다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;git add 명령 취소하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git reset&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;728&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ig73o/btrGS5mXkZs/Ql76Hnkr1Vkw0ukwOWmfW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ig73o/btrGS5mXkZs/Ql76Hnkr1Vkw0ukwOWmfW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ig73o/btrGS5mXkZs/Ql76Hnkr1Vkw0ukwOWmfW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIg73o%2FbtrGS5mXkZs%2FQl76Hnkr1Vkw0ukwOWmfW1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;880&quot; height=&quot;728&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;728&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;커밋 삭제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git reset &amp;mdash;hard HEAD~1 (여기서 HEAD~1 은 위에서 한칸 삭제)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;871&quot; data-origin-height=&quot;58&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6SnDL/btrG0CQGnet/tLNBlEavK4WbNaEB8N1YKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6SnDL/btrG0CQGnet/tLNBlEavK4WbNaEB8N1YKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6SnDL/btrG0CQGnet/tLNBlEavK4WbNaEB8N1YKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6SnDL%2FbtrG0CQGnet%2FtLNBlEavK4WbNaEB8N1YKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;871&quot; height=&quot;58&quot; data-origin-width=&quot;871&quot; data-origin-height=&quot;58&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git &lt;b&gt;reset --soft HEAD~1 설명:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;-hard와는 다르게 commit 정보만 삭제하고 파일 변경분은 남겨둔다.&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;884&quot; data-origin-height=&quot;137&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Hca4H/btrGS5tKLJ7/dNSJEJIO3ulzUmGXBfZsK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Hca4H/btrGS5tKLJ7/dNSJEJIO3ulzUmGXBfZsK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Hca4H/btrGS5tKLJ7/dNSJEJIO3ulzUmGXBfZsK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHca4H%2FbtrGS5tKLJ7%2FdNSJEJIO3ulzUmGXBfZsK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;884&quot; height=&quot;137&quot; data-origin-width=&quot;884&quot; data-origin-height=&quot;137&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;라이센스 서명 넣어서 커밋&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git commit -sm &amp;ldquo; &amp;ldquo; (signed-off-by 가 들어감) -물론 git config로 username,email 설정 후&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;869&quot; data-origin-height=&quot;622&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WUNz6/btrGSx411rw/fdP2XjxQ7dLCi6uLAQBYy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WUNz6/btrGSx411rw/fdP2XjxQ7dLCi6uLAQBYy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WUNz6/btrGSx411rw/fdP2XjxQ7dLCi6uLAQBYy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWUNz6%2FbtrGSx411rw%2FfdP2XjxQ7dLCi6uLAQBYy0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;869&quot; height=&quot;622&quot; data-origin-width=&quot;869&quot; data-origin-height=&quot;622&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;커밋 수정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;mdash;amend 커밋 수정 - 최신 커밋 수정 가능 (최신 커밋에 흡수 된다)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;709&quot; data-origin-height=&quot;418&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/by5I9w/btrGVj5SwUG/SUBdN7sTA3PwqHVeU4OPMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/by5I9w/btrGVj5SwUG/SUBdN7sTA3PwqHVeU4OPMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/by5I9w/btrGVj5SwUG/SUBdN7sTA3PwqHVeU4OPMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fby5I9w%2FbtrGVj5SwUG%2FSUBdN7sTA3PwqHVeU4OPMK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;709&quot; height=&quot;418&quot; data-origin-width=&quot;709&quot; data-origin-height=&quot;418&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;893&quot; data-origin-height=&quot;811&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ciKOWh/btrGWyV0g99/yJrmVBcEa39nKDJ3S4KkI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ciKOWh/btrGWyV0g99/yJrmVBcEa39nKDJ3S4KkI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ciKOWh/btrGWyV0g99/yJrmVBcEa39nKDJ3S4KkI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FciKOWh%2FbtrGWyV0g99%2FyJrmVBcEa39nKDJ3S4KkI0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;893&quot; height=&quot;811&quot; data-origin-width=&quot;893&quot; data-origin-height=&quot;811&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>GitHub,Git</category>
      <category>commit</category>
      <category>GIT</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/125</guid>
      <comments>https://aimk12.tistory.com/125#entry125comment</comments>
      <pubDate>Mon, 11 Jul 2022 00:58:03 +0900</pubDate>
    </item>
    <item>
      <title>Git 설정 및 브랜치 생성</title>
      <link>https://aimk12.tistory.com/124</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;*git 설정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git config &amp;mdash;global &lt;a href=&quot;http://user.name&quot;&gt;user.name&lt;/a&gt; &amp;ldquo;이름&amp;rdquo;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git config &amp;mdash;global user.email &amp;ldquo;이메일&amp;rdquo;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git config --global core.editor nano&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git config &amp;mdash;list (git 설정 확인)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;4.git 참여&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.notion.so/2fc9ec7b43904be1b97f51a94dc7cf0e&quot;&gt;브랜츠란? &amp;ldquo;작업의 단위&amp;rdquo;&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;브랜치 생성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git checkout -b fix-mnist(브랜치 이름)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;브랜치 이동&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git checkout master(다른 브랜치 이름도 가능)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;브랜치 삭제&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git branch -D fix-mnist&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;푸쉬 레포지토리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git push origin [브랜치 이름]&lt;/p&gt;</description>
      <category>GitHub,Git</category>
      <category>GIT</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/124</guid>
      <comments>https://aimk12.tistory.com/124#entry124comment</comments>
      <pubDate>Mon, 11 Jul 2022 00:50:22 +0900</pubDate>
    </item>
    <item>
      <title>Git commit정보 얻기</title>
      <link>https://aimk12.tistory.com/123</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1.commit 개수 알아내기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git log &amp;mdash;oneline | wc -l 커밋 갯수 워드카운트로 라인 출력&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;| wc -l 은 워드카운트 를 라인으로 출력한다는 의미 다른 명령어에도 사용가능!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;846&quot; data-origin-height=&quot;70&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beglfC/btrGSUYZhqm/3gOGEHUiftmi4yMlze6gQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beglfC/btrGSUYZhqm/3gOGEHUiftmi4yMlze6gQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beglfC/btrGSUYZhqm/3gOGEHUiftmi4yMlze6gQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeglfC%2FbtrGSUYZhqm%2F3gOGEHUiftmi4yMlze6gQ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;846&quot; height=&quot;70&quot; data-origin-width=&quot;846&quot; data-origin-height=&quot;70&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git log &amp;mdash;oneline &amp;mdash;after=2020-06-01 &amp;mdash;before=2020-06-30 &amp;mdash;mnist&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;(시간)&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;(폴더)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;폴더 시간 별로 제어 가능!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;2.commit 리스트와 커밋 아이디 확인&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git log --oneline (커밋 리스트 띄우기)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git log --oneline --no-merges(병합 commit)- 즉 병합했다는 표시 수정내역아님)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;882&quot; data-origin-height=&quot;437&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q3xTG/btrGY2vaPPd/ePP8yYlqHAcqUCtlXmWRA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q3xTG/btrGY2vaPPd/ePP8yYlqHAcqUCtlXmWRA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q3xTG/btrGY2vaPPd/ePP8yYlqHAcqUCtlXmWRA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ3xTG%2FbtrGY2vaPPd%2FePP8yYlqHAcqUCtlXmWRA1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;882&quot; height=&quot;437&quot; data-origin-width=&quot;882&quot; data-origin-height=&quot;437&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 처음 커밋한 것을 확인 (거꾸로 확인)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git log --oneline --reverse (물론 날짜 폴더 제한 가능!)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;3.커밋 정보 확인&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git show (최신 커밋 확인)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git show 6c8e2ba(커밋 id)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;858&quot; data-origin-height=&quot;462&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FCG5D/btrGXgAM1bX/7ZfvUgjnuy8dwmcSA5a8D0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FCG5D/btrGXgAM1bX/7ZfvUgjnuy8dwmcSA5a8D0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FCG5D/btrGXgAM1bX/7ZfvUgjnuy8dwmcSA5a8D0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFCG5D%2FbtrGXgAM1bX%2F7ZfvUgjnuy8dwmcSA5a8D0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;858&quot; height=&quot;462&quot; data-origin-width=&quot;858&quot; data-origin-height=&quot;462&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git log -p 더 세부적으로 확인&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;678&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dNZIPR/btrG0B5ip9X/MovlK7x9n5wiCkXbvB0nO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dNZIPR/btrG0B5ip9X/MovlK7x9n5wiCkXbvB0nO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dNZIPR/btrG0B5ip9X/MovlK7x9n5wiCkXbvB0nO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdNZIPR%2FbtrG0B5ip9X%2FMovlK7x9n5wiCkXbvB0nO1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;879&quot; height=&quot;678&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;678&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4, 어느 개발자가 commit을 많이했는지 알아내기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git shortlog -sn &amp;mdash;after=2018-01-01 &amp;mdash;mnist/ (폴더 시간 별로 구분가능) (before도 가능)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;(시간 )&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (폴더)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git shortlog -sn &amp;mdash;mnist/ (폴더 별로 구분 가능)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (폴더)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git shortlog -sn | nl&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;857&quot; data-origin-height=&quot;435&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/daVDSy/btrGYyHYr0a/1bm64VB0etj9Yt4Uo0arS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/daVDSy/btrGYyHYr0a/1bm64VB0etj9Yt4Uo0arS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/daVDSy/btrGYyHYr0a/1bm64VB0etj9Yt4Uo0arS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdaVDSy%2FbtrGYyHYr0a%2F1bm64VB0etj9Yt4Uo0arS0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;857&quot; height=&quot;435&quot; data-origin-width=&quot;857&quot; data-origin-height=&quot;435&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>GitHub,Git</category>
      <category>commit</category>
      <category>GIT</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/123</guid>
      <comments>https://aimk12.tistory.com/123#entry123comment</comments>
      <pubDate>Mon, 11 Jul 2022 00:45:25 +0900</pubDate>
    </item>
    <item>
      <title>백준 10986번: 나머지 합</title>
      <link>https://aimk12.tistory.com/122</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/10986&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/10986&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1657207203774&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;10986번: 나머지 합&quot; data-og-description=&quot;수 N개 A1, A2, ..., AN이 주어진다. 이때, 연속된 부분 구간의 합이 M으로 나누어 떨어지는 구간의&amp;nbsp;개수를 구하는 프로그램을 작성하시오. 즉, Ai + ... + Aj (i &amp;le; j) 의 합이 M으로 나누어 떨어지는 (i, j)&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/10986&quot; data-og-url=&quot;https://www.acmicpc.net/problem/10986&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/1s4M2/hyO1YqpLj1/xDrXkrduhJHJv8goARQVGK/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/10986&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/10986&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/1s4M2/hyO1YqpLj1/xDrXkrduhJHJv8goARQVGK/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;10986번: 나머지 합&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;수 N개 A1, A2, ..., AN이 주어진다. 이때, 연속된 부분 구간의 합이 M으로 나누어 떨어지는 구간의&amp;nbsp;개수를 구하는 프로그램을 작성하시오. 즉, Ai + ... + Aj (i &amp;le; j) 의 합이 M으로 나누어 떨어지는 (i, j)&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 누적합 으로 접근해서 풀어야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난 처음에 누적합으로 접근하는 건 알겠는데 (i,j)의 쌍들을 구하는 것을 구현하면 시간제한을 초과할 것 같았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 다른 방식으로 접근을 해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 방법은 d[i]의 배열이 문제에서 주어진 배열의 누적합이라고 하고 A[i]를 문제에서 주어진 배열이라고 할 때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A[i]에서 A[j]의 구간합은 d[j]-d[i-1] 임을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제에서 주어진 답은 (d[j]-d[i])%mod =0 인 구간 (i,j)의 쌍을 구하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;즉&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt; d[j]%mod=d[i]%mod 인 구간 i,j를 구하면 된다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백준에서 주어진 예를 들어 보면&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 배열&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;A&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;index&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;누적합 배열&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;d&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;index&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;6&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;7&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;누적합 배열 %mod&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;d%mod(= 3)&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;index&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 나머지 m으로 나누어 떨어지는 구간합 (i,j)은 위의 조건 &lt;b&gt;d[j]%mod=d[i]%mod 에 따라서&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1로 같은것 (1,4)&amp;nbsp; (여기서는 1을 포함안하고 누적합 한다는 의미)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0으로 같은 것(2,3),(2,5),(3,4) 이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 또 추가해야하는 것이 있는데 (0,2),(0,3),(0,5) 이다 (이유는 0이 곧 첫번째 원소를 포함하고 누적합이다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 코드를 보자&lt;/p&gt;
&lt;pre id=&quot;code_1657208106786&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
using namespace std;
int n,m;
long long cnt[1001];
long long ans,sum;
int main(){
    cin.tie(NULL);
	cout.tie(NULL);
	ios_base::sync_with_stdio(false);
    cin &amp;gt;&amp;gt;n&amp;gt;&amp;gt;m;
    for(int i=1;i&amp;lt;=n;i++){
        int a;
        cin&amp;gt;&amp;gt;a;
        sum+=a;    //누적합에서 m을 나눈값 
        cnt[sum%m]++;           //개수 늘리기
    }
    for(int i=0;i&amp;lt;=m;i++){
        ans+=(cnt[i]*(cnt[i]-1))/2;
    }
    cout&amp;lt;&amp;lt;ans+cnt[0];

}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>백준 코딩</category>
      <category>10986</category>
      <category>나머지 합</category>
      <category>누적합</category>
      <category>백준</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/122</guid>
      <comments>https://aimk12.tistory.com/122#entry122comment</comments>
      <pubDate>Fri, 8 Jul 2022 00:35:30 +0900</pubDate>
    </item>
    <item>
      <title>백준 12865번: 평범한 배낭</title>
      <link>https://aimk12.tistory.com/121</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/12865&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/12865&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1656865162012&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;12865번: 평범한 배낭&quot; data-og-description=&quot;첫 줄에 물품의 수 N(1 &amp;le; N &amp;le; 100)과 준서가 버틸 수 있는 무게 K(1 &amp;le; K &amp;le; 100,000)가 주어진다. 두 번째 줄부터 N개의 줄에 거쳐 각 물건의 무게 W(1 &amp;le; W &amp;le; 100,000)와 해당 물건의 가치 V(0 &amp;le; V &amp;le; 1,000)&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/12865&quot; data-og-url=&quot;https://www.acmicpc.net/problem/12865&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/hsYME/hyOYhx24fy/qaPwhlR9GiDPYQ7TR0KFuk/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/12865&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/12865&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/hsYME/hyOYhx24fy/qaPwhlR9GiDPYQ7TR0KFuk/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;12865번: 평범한 배낭&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;첫 줄에 물품의 수 N(1 &amp;le; N &amp;le; 100)과 준서가 버틸 수 있는 무게 K(1 &amp;le; K &amp;le; 100,000)가 주어진다. 두 번째 줄부터 N개의 줄에 거쳐 각 물건의 무게 W(1 &amp;le; W &amp;le; 100,000)와 해당 물건의 가치 V(0 &amp;le; V &amp;le; 1,000)&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 처음 접했을 떄 가장 떠오른 것은 백트래킹이었다. 아직 다이나믹프로그래밍을 모르는 것 같다...(dp문제 풀 떄마다 좌절감을 느끼는 중..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 코드는 백트래킹으로 푼 코드이다 넘어가도 좋당... 나같은 행동은 하지 마세용.. (시간초과로 틀린 코드)&lt;/p&gt;
&lt;pre id=&quot;code_1656865253334&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;vector&amp;gt;
using namespace std;
int n;
int k;
int ans;
int temp;
int value;
vector&amp;lt;pair&amp;lt;int,int&amp;gt;&amp;gt; v;
bool check[101];
void dfs(int num,int cnt){
    if(cnt==n){
        return;
    }
    for(int i=num;i&amp;lt;n;i++){
        if(!check[i]&amp;amp;&amp;amp;(temp+v[i].first&amp;lt;=k)){
            check[i]=true;
            value+=v[i].second;
            temp+=v[i].first;
            if(ans&amp;lt;value){
                ans=value;
            }
            dfs(i+1,cnt+1);
            check[i]=false;
            value-=v[i].second;
            temp-=v[i].first;
        }
    }
}
int main(){
    cin&amp;gt;&amp;gt;n&amp;gt;&amp;gt;k;
    for(int i=0;i&amp;lt;n;i++){
        int a,b;
        cin&amp;gt;&amp;gt;a&amp;gt;&amp;gt;b;
        v.push_back(make_pair(a,b));
    }
    dfs(0,0);
    cout&amp;lt;&amp;lt;ans;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이 문제를 푸는 방법은 당연히 dp이고 식부터 말하자면 (이해가 안되면 맨 아래코드부터 보자)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경우의 수:1. 배낭을 넣을 것인가 2.배낭을 안 넣을 것인가&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656865303023&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;arr[i][j]=max(arr[i-1][j],arr[i-1][j-w[i]]+v[i]);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 식이 핵심이다.&amp;nbsp; i는 몇번쨰 배낭인지 j는 무게,w[i],v[i]는 각각 [i]번째 배낭 무게와 값이다. 난 무게를 조건식으로 풀 생각을 해서 못 푼 거 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정답은 배낭의 무게도 배열에 넣어버리는 것이다. 저 식을 해석 하자면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;i번쨰 배낭을 탐색할때 j 무게 인 경우 최선을 구하는 것이다.(i번쨰 배낭을 안넣는게 최선이면 arr[i-1][j] , i번쨰 배낭을 넣는게 최선이면 arr[i-1][j-w[i]]+v[i] 즉 현재 배낭 무게를 뻇을 때 값에다가 현재 배낭 값을 더하는 것이다 (현재 배낭을 넣기 떄문)&lt;/p&gt;
&lt;pre id=&quot;code_1656865637105&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;vector&amp;gt;
using namespace std;
int n,k;
int arr[101][100001];
int w[101];
int v[101];
int main(){
    cin&amp;gt;&amp;gt;n&amp;gt;&amp;gt;k;
    for(int i=1;i&amp;lt;=n;i++){
        cin&amp;gt;&amp;gt;w[i]&amp;gt;&amp;gt;v[i];
    }
    for(int i=1;i&amp;lt;=n;i++){
        for(int j=1;j&amp;lt;=k;j++){         //매번 무게별로 최선을 고른다고 가정
            if(j&amp;gt;=w[i]){
                arr[i][j]=max(arr[i-1][j],arr[i-1][j-w[i]]+v[i]);        //현 배낭 선택 한것과 안 한 것중 큰 값 넣기 
            }
            else{
                arr[i][j]=arr[i-1][j];           //배낭 선택을 안했으므로 전에 값 가져오기
            }
        }
    }
    cout &amp;lt;&amp;lt; arr[n][k];
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진짜 DP가 익숙해지기 너무 어렵다...평소에 생각하는 회로랑 다르게 흘러가는 거 같다..기계처럼 풀어서 그런듯요..&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;niniz&quot; data-emoticon-name=&quot;003&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/niniz/large/003.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/niniz/large/003.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>백준 코딩</category>
      <category>12865</category>
      <category>DP</category>
      <category>다이나믹프로그래밍</category>
      <category>백준</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/121</guid>
      <comments>https://aimk12.tistory.com/121#entry121comment</comments>
      <pubDate>Mon, 4 Jul 2022 01:28:21 +0900</pubDate>
    </item>
    <item>
      <title>백준 9251번 :LCS</title>
      <link>https://aimk12.tistory.com/120</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/9251&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/9251&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1656841715374&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;9251번: LCS&quot; data-og-description=&quot;LCS(Longest Common Subsequence, 최장 공통 부분 수열)문제는 두 수열이 주어졌을 때, 모두의 부분 수열이 되는 수열 중 가장 긴 것을 찾는 문제이다. 예를 들어, ACAYKP와 CAPCAK의 LCS는 ACAK가 된다.&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/9251&quot; data-og-url=&quot;https://www.acmicpc.net/problem/9251&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/FwWOP/hyOYeHQn0A/LOKX9EYxOHDAL0k5aX66G0/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/9251&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/9251&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/FwWOP/hyOYeHQn0A/LOKX9EYxOHDAL0k5aX66G0/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;9251번: LCS&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;LCS(Longest Common Subsequence, 최장 공통 부분 수열)문제는 두 수열이 주어졌을 때, 모두의 부분 수열이 되는 수열 중 가장 긴 것을 찾는 문제이다. 예를 들어, ACAYKP와 CAPCAK의 LCS는 ACAK가 된다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이 문제는 다이나믹 프로그래밍으로 푸는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라고 생각해서 접근했지만 후...모르겠어서 다른 글을 참고했다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;풀이는 말그대로 다이나믹 프로그래밍으로 푸는 것이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 문자열&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ACAYKP&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CAPCAK&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가 있다고 하였을 때,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맨 처음 부분 문자열 A,AC,ACA... 와 C,CA,CAP.. 로 비교해가면서 푸는 것이다. 즉 부분 집합에서 최적해를 찾아가는 방식이다.( 라고 말은하지만 생각이 들기 어려웠고 푸는 방법은 더욱더 안떠올랐다...)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;풀이 방법은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;&lt;b&gt;1)문자 값이 같으면 좌대각 값+1&amp;nbsp; &amp;nbsp;&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유는 좌대각이 부분순열에 영향을 안받는 값이고 같으면 거기서 +1을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;밑에 테이블을 보고 생각을 하면 ACA와 CA에서 값은&amp;nbsp; 좌대각 AC와 C에서 구한 값에다가 뒤에 더해지는 A가 값이 겹치므로+1 이 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;2)문자 값이 다르면 MAX(위쪽 값,왼쪽 값) 이다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유는 간단하게 문자 값이 다르므로 부분수열 수에 영향을 미치지 않는다 .&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉) ACAY 와 CA에서 값은 ACA와 CA 또는 ACAY와 C에서&amp;nbsp; 가장 큰 값을 그대로 사용하면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 20.9302%; height: 119px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.5833%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;A&lt;/td&gt;
&lt;td style=&quot;width: 14.5833%; height: 17px;&quot;&gt;C&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;A&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;Y&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;K&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;P&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.5833%; height: 17px;&quot;&gt;C&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 14.5833%; height: 17px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.5833%; height: 17px;&quot;&gt;A&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 14.5833%; height: 17px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.5833%; height: 17px;&quot;&gt;P&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.5833%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.5833%; height: 17px;&quot;&gt;C&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.5833%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.5833%; height: 17px;&quot;&gt;A&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.5833%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.5833%; height: 17px;&quot;&gt;K&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.5833%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.0625%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 테이블에서 보듯이 원래는 각 테두리에 0을 넣으면 구현하기 편하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계산을 끝까지 하게되면&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 23.2558%; height: 240px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;A&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;C&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;A&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;Y&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;K&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;P&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;C&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;A&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;P&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;C&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;A&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;K&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;width: 14.2857%;&quot;&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 이 예의 답은 4이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 보자&lt;/p&gt;
&lt;pre id=&quot;code_1656842684427&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;string&amp;gt;
using namespace std;
string s1;
string s2;
int arr[1002][1002];
int main(){
    cin &amp;gt;&amp;gt;s1;
    cin&amp;gt;&amp;gt;s2;
    int len1=s1.size();
    int len2=s2.size();
    for(int i=0;i&amp;lt;len1;i++){
        for(int k=0;k&amp;lt;len2;k++){
            if(s1[i]==s2[k]){
                arr[i+1][k+1]=arr[i][k]+1;       //같으면 좌대각 에서 +1 
            }else{
                arr[i+1][k+1]=max(arr[i][k+1],arr[i+1][k]); //다르면 왼쪽이랑 위쪽중에 큰 값 채우기
            }
        }
    }
    cout &amp;lt;&amp;lt;arr[len1][len2];
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>백준 코딩</category>
      <category>9251</category>
      <category>LCS</category>
      <category>다이나믹 프로그래밍</category>
      <category>백준</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/120</guid>
      <comments>https://aimk12.tistory.com/120#entry120comment</comments>
      <pubDate>Sun, 3 Jul 2022 19:05:15 +0900</pubDate>
    </item>
    <item>
      <title>백준 14888: 연산자 끼워넣기</title>
      <link>https://aimk12.tistory.com/118</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/14888&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/14888&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1656256728017&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;14888번: 연산자 끼워넣기&quot; data-og-description=&quot;첫째 줄에 수의 개수 N(2 &amp;le; N &amp;le; 11)가 주어진다. 둘째 줄에는 A1, A2, ..., AN이 주어진다. (1 &amp;le; Ai &amp;le; 100) 셋째 줄에는 합이 N-1인 4개의 정수가 주어지는데, 차례대로 덧셈(+)의 개수, 뺄셈(-)의 개수,&amp;nbsp;&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/14888&quot; data-og-url=&quot;https://www.acmicpc.net/problem/14888&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bPUrYh/hyOUZJKtv4/uKcTf8i9c4g1NY3KbZEIbK/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/14888&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/14888&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bPUrYh/hyOUZJKtv4/uKcTf8i9c4g1NY3KbZEIbK/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;14888번: 연산자 끼워넣기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에 수의 개수 N(2 &amp;le; N &amp;le; 11)가 주어진다. 둘째 줄에는 A1, A2, ..., AN이 주어진다. (1 &amp;le; Ai &amp;le; 100) 셋째 줄에는 합이 N-1인 4개의 정수가 주어지는데, 차례대로 덧셈(+)의 개수, 뺄셈(-)의 개수,&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 백트래킹 관련 문제이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;풀이과정은 단순한데 연산자 4개를 일일이 다 탐색하면서 최대값 최소값을 구하면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 탈출 조건은 탐색 깊이가 연산자 개수랑 일치하면 탈출하고 재귀를 돌린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정에서 백트래킹이 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 보는게 이해가 빠르다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 보자&lt;/p&gt;
&lt;pre id=&quot;code_1656257463158&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;
int n;
int arr[101];
int oper[4];
int minindex=1000000001;
int maxindex=-1000000001;
void dfs(int result,int cnt){      //백트래킹 이용
    if(n==cnt){
        if(result&amp;gt;maxindex){
            maxindex=result;
        }
        if(result&amp;lt;minindex){
            minindex=result;
        }
        return;
    }
    for(int i=0;i&amp;lt;4;i++){
        if(oper[i]!=0){
            oper[i]--; //연산자 수 제거
            if(i==0){
                dfs(result+arr[cnt],cnt+1);
            }
            if(i==1){
                dfs(result-arr[cnt],cnt+1);
            }
            if(i==2){
                dfs(result*arr[cnt],cnt+1);
            }
            if(i==3){
                dfs(result/arr[cnt],cnt+1);
            }
            oper[i]++;  //다른 계산값 구하기 위해 연산자 갯수 다시 추가해야함 
        }
    }
}
int main(){
    cin&amp;gt;&amp;gt;n;
    for(int i=0;i&amp;lt;n;i++){
        cin&amp;gt;&amp;gt;arr[i];
    }
    for(int i=0;i&amp;lt;4;i++){
        cin&amp;gt;&amp;gt;oper[i];
    }
    dfs(arr[0],1);
    cout &amp;lt;&amp;lt; maxindex&amp;lt;&amp;lt;'\n';
    cout&amp;lt;&amp;lt;minindex;

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>백준 코딩</category>
      <category>14888</category>
      <category>백준</category>
      <category>백트래킹</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/118</guid>
      <comments>https://aimk12.tistory.com/118#entry118comment</comments>
      <pubDate>Mon, 27 Jun 2022 00:32:51 +0900</pubDate>
    </item>
    <item>
      <title>백준 10816번: 숫자 카드2</title>
      <link>https://aimk12.tistory.com/117</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/10816&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/10816&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1654412421750&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;10816번: 숫자 카드 2&quot; data-og-description=&quot;첫째 줄에 상근이가 가지고 있는 숫자 카드의 개수 N(1 &amp;le; N &amp;le; 500,000)이&amp;nbsp;주어진다. 둘째 줄에는 숫자 카드에 적혀있는 정수가 주어진다. 숫자 카드에 적혀있는 수는 -10,000,000보다 크거나 같고, 10,&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/10816&quot; data-og-url=&quot;https://www.acmicpc.net/problem/10816&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ZnNc4/hyOEdXq87H/QFjtPZmoX8e8EbS3jEqUpK/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/10816&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/10816&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ZnNc4/hyOEdXq87H/QFjtPZmoX8e8EbS3jEqUpK/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;10816번: 숫자 카드 2&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에 상근이가 가지고 있는 숫자 카드의 개수 N(1 &amp;le; N &amp;le; 500,000)이&amp;nbsp;주어진다. 둘째 줄에는 숫자 카드에 적혀있는 정수가 주어진다. 숫자 카드에 적혀있는 수는 -10,000,000보다 크거나 같고, 10,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 보통 방법으로 풀면 시간 초과가 난다. 이분탐색을 이용해&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중복된 값에서 첫 위치와 끝 위치를 구하는게 중요하다.(시간초과로 고생한건 안비밀..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쨋든 값진 경험이라 블로그에 남긴당&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 풀면서 upper_bound와 rower_bound 에 대해서 알게 되었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘 다 정렬을 기본 전제로 간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 간단하게 upper_bound 는 중복된 값 중에서 마지막 원소 값을 가리키는 인덱스 반환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;rower_bound 는 중복된 값 중에서 첫번째 원소 값을 가리키는 인덱스 반환이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이를 빠르게 참조하기위해 이분탐색을 이용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 rower_bound&lt;/p&gt;
&lt;pre id=&quot;code_1654412695411&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int rower_bound(vector&amp;lt;int&amp;gt; &amp;amp;v1,int target,int size){ //탐색 중복 값 중 가장 맨 앞쪽 출력
    int start=0;
    int end=size-1;
    int mid;
    while(end&amp;gt;start){
        mid=(start+end)/2;
        if(v1[mid]&amp;gt;=target){  //중복된 값들은 다 end에 넣음 이러면 중복 된 값이 걸려도 mid 값은 앞으로 가면서 맨앞으로 가게됨
            end=mid;
        }
        else{
            start=mid+1;
        }
    }
    return end;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;upper_bound&lt;/p&gt;
&lt;pre id=&quot;code_1654412806673&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int upper_bound(vector&amp;lt;int&amp;gt; &amp;amp;v1,int target, int size){  //중복된 값 바로 다음 값 위치 찾기
    int start=0;
    int end=size-1;
    int mid;
    while(end&amp;gt;start){
        mid=(start+end)/2;
        if(v1[mid]&amp;gt;target){   //탐색 값이 타겟 값보다 크면 끝을 중간값 넣기 즉, 탐색값 보다 큰 다음 값 위치로 맞추어짐
            end=mid;
        }
        else{
            start=mid+1;
        }
    }
    return end;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;upper_bound에서 중복된 값 다음 인덱스를 가리키는 함수다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;헷갈리면 안되는 것은 start=mid+1은 필수 이다. mid값이 나누기 2로 구해지는데 3/2=1이 듯이 1.5에서 내림으로 받는다.즉 end에서 -1은 안해도 나누면 저절로 내려가지는데 start는 +1을 안하면 잘못하다가는 무한루프에 빠지게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저 upper_bound에서 한가지 예외가 존재하는데 그것은 마지막 중복 인덱스 값이다.마지막은 그 다음 인덱스를 가리킬수 없으므로 예외처리를 해줘야 한다. 코드를 봅시당&lt;/p&gt;
&lt;pre id=&quot;code_1654412895664&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
vector&amp;lt;int&amp;gt; v;
int upper_bound(vector&amp;lt;int&amp;gt; &amp;amp;v1,int target, int size){  //중복된 값 바로 다음 값 위치 찾기
    int start=0;
    int end=size-1;
    int mid;
    while(end&amp;gt;start){
        mid=(start+end)/2;
        if(v1[mid]&amp;gt;target){   //탐색 값이 타겟 값보다 크면 끝을 중간값 넣기 즉, 탐색값 보다 큰 다음 값 위치로 맞추어짐
            end=mid;
        }
        else{
            start=mid+1;
        }
    }
    return end;
}

int rower_bound(vector&amp;lt;int&amp;gt; &amp;amp;v1,int target,int size){ //탐색 중복 값 중 가장 맨 앞쪽 출력
    int start=0;
    int end=size-1;
    int mid;
    while(end&amp;gt;start){
        mid=(start+end)/2;
        if(v1[mid]&amp;gt;=target){  //중복된 값들은 다 end에 넣음 이러면 중복 된 값이 걸려도 mid 값은 앞으로 가면서 맨앞으로 가게됨
            end=mid;
        }
        else{
            start=mid+1;
        }
    }
    return end;
}

int main(){
    cin.tie(NULL);
	cout.tie(NULL);
	ios_base::sync_with_stdio(false);
    int n,m;
    cin&amp;gt;&amp;gt;n;
    int t;
    for(int i=0;i&amp;lt;n;i++){
        cin&amp;gt;&amp;gt;t;
        v.push_back(t);
    }
    sort(v.begin(),v.end());
    cin&amp;gt;&amp;gt;m;
    for(int i=0;i&amp;lt;m;i++){
        cin&amp;gt;&amp;gt;t;
        int start =rower_bound(v,t,n);
        int end=upper_bound(v,t,n);
        if(end==n-1&amp;amp;&amp;amp;v[end]==t){     // 마지막 값이 중복되면 upper_bound가 그 다음 위치를 못 가져오므로 예외처리
            end++;
        }
        cout &amp;lt;&amp;lt; end-start&amp;lt;&amp;lt;' ';
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>백준 코딩</category>
      <category>10816번</category>
      <category>백준</category>
      <category>이분 탐색</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/117</guid>
      <comments>https://aimk12.tistory.com/117#entry117comment</comments>
      <pubDate>Sun, 5 Jun 2022 16:09:22 +0900</pubDate>
    </item>
    <item>
      <title>백준 1904번 : 01타일</title>
      <link>https://aimk12.tistory.com/116</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1904&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/1904&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1654152741139&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;1904번: 01타일&quot; data-og-description=&quot;지원이에게 2진 수열을 가르쳐 주기 위해, 지원이 아버지는 그에게 타일들을 선물해주셨다. 그리고 이 각각의 타일들은 0 또는 1이 쓰여 있는 낱장의 타일들이다. 어느 날 짓궂은 동주가 지원이&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/1904&quot; data-og-url=&quot;https://www.acmicpc.net/problem/1904&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/hQ2VQ/hyOCGj90vD/wVAK4wpibGrrSUHu1JCrP0/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1904&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/1904&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/hQ2VQ/hyOCGj90vD/wVAK4wpibGrrSUHu1JCrP0/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;1904번: 01타일&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;지원이에게 2진 수열을 가르쳐 주기 위해, 지원이 아버지는 그에게 타일들을 선물해주셨다. 그리고 이 각각의 타일들은 0 또는 1이 쓰여 있는 낱장의 타일들이다. 어느 날 짓궂은 동주가 지원이&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 실버 3 문제이고 다이나믹 알고리즘을 통해 부는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엄청 오랜만에 알고리즘 문제를 보니 순간 머리가 띵햇다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진짜 엄청 고민한거 같넹... (이제 부터 스프링 공부랑 병행하면서 해야할듯욤..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 사실 피보나치랑 같은 개념이다.&amp;nbsp; 천천히 생각해보자 (뒤에만 타일을 붙인다고 해도 무방) 괜히 앞에다가 붙이고 복잡하게 생각하지말자...&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건 1. 00타일만 붙일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건 2 , 1 타일만 붙일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 f(n) 이 할 수 있는 모든 타일 갯수라고 했을 때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건 1은 f(n-2) 에서 적용이 가능하고&amp;nbsp; 여기서 f(n-1)도 모든 타일 갯수 즉 최적의 해다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건 2는 f(n-1) 에서 적용이 가능하다.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;여기서 f(n-1)도 모든 타일 갯수 즉 최적의 해다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고로 f(n) = f(n-1)+f(n-1) 이다 물론 이런 재귀는 부담되는 연산이 되므로 메모라이징으로 계산된 값을 기억하자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 코드를 보자&lt;/p&gt;
&lt;pre id=&quot;code_1654153126648&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;
int d[1000001];

int fibonacci(int n){
    if(d[n]!=0){
        return d[n];
    }
    if(n&amp;lt;=1){                     //1일 떄는 타일 갯수 1  
        d[1]=1;
        return d[1];
    }
    if(n==2){                 //2일떄는 타일 갯수 2
        d[2]=2;
        return d[2];
    }
    d[n]=(fibonacci(n-1)+fibonacci(n-2))%15746;      //피보나치 수열이랑 똑같음
    return d[n];
}
int main(){
    int t;
    cin&amp;gt;&amp;gt; t;
    int ans = fibonacci(t)%15746;
    cout &amp;lt;&amp;lt;ans;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>백준 코딩</category>
      <category>1904번</category>
      <category>다이나믹 프로그래밍</category>
      <category>백준</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/116</guid>
      <comments>https://aimk12.tistory.com/116#entry116comment</comments>
      <pubDate>Thu, 2 Jun 2022 15:59:03 +0900</pubDate>
    </item>
    <item>
      <title>spring 토이 프로젝트 -로그인 기능, 검증 기능 ,jpa</title>
      <link>https://aimk12.tistory.com/115</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;김영한의 spring 강의 MVC2편과 JPA활용 1편을 듣고 나름대로 정리하면서 토이프로젝트를 진행해 보았다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(프론트는 문외한이라 거의 코드 복사..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 나는 jpa와 평상시에 궁금증이 많았던 로그인 기능,검증 기능을 도입해보고 싶었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/MyunghyunNero/health-management-service&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/MyunghyunNero/health-management-service&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1654076616271&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - MyunghyunNero/health-management-service&quot; data-og-description=&quot;Contribute to MyunghyunNero/health-management-service development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/MyunghyunNero/health-management-service&quot; data-og-url=&quot;https://github.com/MyunghyunNero/health-management-service&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/brB6VL/hyOBGk8TS5/obRKeQClLnGsUgLsKJIGe1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/MyunghyunNero/health-management-service&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/MyunghyunNero/health-management-service&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/brB6VL/hyOBGk8TS5/obRKeQClLnGsUgLsKJIGe1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - MyunghyunNero/health-management-service&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to MyunghyunNero/health-management-service development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에 결과물이 있다..(완전 허접..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 이번에 이 토이 프로젝트의 목적은 강의에서 배운 것들을 직접 적용해 보는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 헬스기능 이라는 객체를 만들고 이를 이용해서 멤버 객체와 1 대 다 관계로 만들었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 프로젝트는 jpa 개념 데이터 베이스 개념이 거의 없는데 일단 그냥 머리박치기하는 야생 느낌으로가봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맨 처음에 강의 내용대로 H2데이터베이스를 이용해서 할 까 라는 생각을 가지다가 mysql을 이용해서 해볼까 생각을 하게 되었다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흐아..역시 오류가 뜬다. 이 떄 오류는 mysql의 서버를 잡지 못하는 것이었다.그 이유를 계속 찾았다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 내가 이 프로젝트 전에 mariadb를 깔았었다. 그리고 mysql을 깔았는데 여기서 문제가 생겼다.포트번호가 겹쳐서 어느 서버를 고르는지 못잡 는 거였다. 해결법은 간단하게 작업관리자에서 사용안할 서버를 끄면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;437&quot; data-origin-height=&quot;656&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6cVBn/btrDIn395rP/KRRS9SxvRuG4XXtFrkEiEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6cVBn/btrDIn395rP/KRRS9SxvRuG4XXtFrkEiEk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6cVBn/btrDIn395rP/KRRS9SxvRuG4XXtFrkEiEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6cVBn%2FbtrDIn395rP%2FKRRS9SxvRuG4XXtFrkEiEk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;437&quot; height=&quot;656&quot; data-origin-width=&quot;437&quot; data-origin-height=&quot;656&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 두 번째 오류 헬스 클래스 데이터가 @entity 값이 있음에도 불구하고 들어가지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@entity 는 create테이블을 해주는 걸로 아는데 들어가지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;심지어 @entity가 붙어있는 다른 클래스들은 테이블로 잘 들어갔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[Error executing DDL &quot;create table] 이런 오류가 뜨면서 테이블이 안 들어 간 것을 찾았다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;427&quot; data-origin-height=&quot;570&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wUYJ9/btrDGJ0VDzD/8NRyeJs3Djjqci0JJmd3hK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wUYJ9/btrDGJ0VDzD/8NRyeJs3Djjqci0JJmd3hK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wUYJ9/btrDGJ0VDzD/8NRyeJs3Djjqci0JJmd3hK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwUYJ9%2FbtrDGJ0VDzD%2F8NRyeJs3Djjqci0JJmd3hK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;327&quot; height=&quot;437&quot; data-origin-width=&quot;427&quot; data-origin-height=&quot;570&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 문제점은 변수명으로 설정에 문제가 있었다. 여기서 내가 정한 변수 datatime,set,count 가 데이터베이스에서 사용되는 예약어 이기 때문이다.즉 테이블로 생성이 불가능 했었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;549&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bk7dkN/btrDJwGzKRM/DhAxuk5hWYlxPebKwtXaj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bk7dkN/btrDJwGzKRM/DhAxuk5hWYlxPebKwtXaj0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bk7dkN/btrDJwGzKRM/DhAxuk5hWYlxPebKwtXaj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbk7dkN%2FbtrDJwGzKRM%2FDhAxuk5hWYlxPebKwtXaj0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;425&quot; height=&quot;476&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;549&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수 수정을 하니 잘 작동하였다.( 이때 jpa 하지 말걸만 10번 넘게 생각한듯욤..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것보다 오류를 경험한 것들은 더 많았다... 하지만 이 오류들을 그냥 해결만 하면 그만이지 라는 생각을 가졌고 해결하고 넘어갔었다.아주 후회하는중... 이제부터는 오류가 생기면 어떤 오류이고 어떻게 해결해야하는지 기록을 할 예정이다. 이유는 같은 오류를 범하는 멍청한 짓을 하지 않기 위해서다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쨋거나 저쨋거나 토이 프로젝트도 끝내고 이제는 jpa에 대해 공부를 실시하고 더 나은 프로젝트를 하는 것을 목표로 할 것이다! 물론 알고리즘 공부도 틈틈이!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>백 엔드/spring</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/115</guid>
      <comments>https://aimk12.tistory.com/115#entry115comment</comments>
      <pubDate>Wed, 1 Jun 2022 19:26:58 +0900</pubDate>
    </item>
    <item>
      <title>스프링 - 필터 , 인터셉터</title>
      <link>https://aimk12.tistory.com/114</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;김영한의 MVC2편 정리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필터와 인터셉터는 로그인시 필요한 기능이다. 로그인해야 접근이 가능한 페이지와 안그런 페이지를 구분하기 위해서 필터와 인터셉터가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;&lt;b&gt;필터&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;필터 흐름 &lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 요청 -&amp;gt; WAS -&amp;gt; 필터 -&amp;gt; 서블릿 -&amp;gt; 컨트롤러&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;필터 제한&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 요청 -&amp;gt; WAS -&amp;gt; 필터 -&amp;gt; 서블릿 -&amp;gt; 컨트롤러//로그인 사용자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 요청 -&amp;gt; WAS -&amp;gt; 필터(적절하지 않은 요청이라 판단, 서블릿 호출X) //비 로그인 사용자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;필터 체인 &lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 요청 -&amp;gt; WAS -&amp;gt; 필터1 -&amp;gt; 필터2 -&amp;gt; 필터3 -&amp;gt; 서블릿 -&amp;gt; 컨트롤러&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;i&gt;&lt;b&gt;필터 인터페이스&lt;/b&gt;&lt;/i&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1652525297009&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface Filter {
 public default void init(FilterConfig filterConfig) throws ServletException
{}
 public void doFilter(ServletRequest request, ServletResponse response,
 FilterChain chain) throws IOException, ServletException;
 public default void destroy() {}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;init(): 필터 초기화 메서드, 서블릿 컨테이너가 생성될 때 호출된다. &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;doFilter(): 고객의 요청이 올 때 마다 해당 메서드가 호출된다. 필터의 로직을 구현하면 된다. &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;destroy(): 필터 종료 메서드, 서블릿 컨테이너가 종료될 때 호출된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;WebConfig - &lt;b&gt;필터 설정&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1652527478180&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
public class WebConfig {
 @Bean
 public FilterRegistrationBean logFilter() {
 FilterRegistrationBean&amp;lt;Filter&amp;gt; filterRegistrationBean = new
FilterRegistrationBean&amp;lt;&amp;gt;();
 filterRegistrationBean.setFilter(new LogFilter());
 filterRegistrationBean.setOrder(1);
 filterRegistrationBean.addUrlPatterns(&quot;/*&quot;);
 return filterRegistrationBean;
 }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;setFilter(new LogFilter()) : 등록할 필터를 지정한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; setOrder(1) : 필터는 체인으로 동작한다. 따라서 순서가 필요하다. 낮을 수록 먼저 동작한다. &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;addUrlPatterns(&quot;/*&quot;) : 필터를 적용할 URL 패턴을 지정한다. 한번에 여러 패턴을 지정할 수 있다&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;필터를 이용한 인증체크 코드&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1652528360285&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class LoginCheckFilter implements Filter {
 private static final String[] whitelist = {&quot;/&quot;, &quot;/members/add&quot;, &quot;/login&quot;,
&quot;/logout&quot;,&quot;/css/*&quot;};
 @Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
 HttpServletRequest httpRequest = (HttpServletRequest) request;
 String requestURI = httpRequest.getRequestURI();
 HttpServletResponse httpResponse = (HttpServletResponse) response;
 try {
 log.info(&quot;인증 체크 필터 시작 {}&quot;, requestURI);
 if (isLoginCheckPath(requestURI)) {
 log.info(&quot;인증 체크 로직 실행 {}&quot;, requestURI);
 HttpSession session = httpRequest.getSession(false);
 if (session == null ||
session.getAttribute(SessionConst.LOGIN_MEMBER) == null) {
 log.info(&quot;미인증 사용자 요청 {}&quot;, requestURI);
 //로그인으로 redirect
 httpResponse.sendRedirect(&quot;/login?redirectURL=&quot; +
requestURI);
 return; //여기가 중요, 미인증 사용자는 다음으로 진행하지 않고 끝!
 }
 }
 chain.doFilter(request, response);
 } catch (Exception e) {
 throw e; //예외 로깅 가능 하지만, 톰캣까지 예외를 보내주어야 함
 } finally {
 log.info(&quot;인증 체크 필터 종료 {}&quot;, requestURI);
 }
 }
 /**
 * 화이트 리스트의 경우 인증 체크X
 */
 private boolean isLoginCheckPath(String requestURI) {
 return !PatternMatchUtils.simpleMatch(whitelist, requestURI);
 }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;whitelist = {&quot;/&quot;, &quot;/members/add&quot;, &quot;/login&quot;, &quot;/logout&quot;,&quot;/css/*&quot;}; &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인증 필터를 적용해도 홈, 회원가입, 로그인 화면, css 같은 리소스에는 접근할 수 있어야 한다. 이렇게 화이트 리스트 경로는 인증과 무관하게 항상 허용한다. 화이트 리스트를 제외한 나머지 모든 경로에는 인증 체크 로직을 적용한다. isLoginCheckPath(requestURI) 화이트 리스트를 제외한 모든 경우에 인증 체크 로직을 적용한다. &lt;b&gt;httpResponse.sendRedirect(&quot;/login?redirectURL=&quot; + requestURI); &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미인증 사용자는 로그인 화면으로 리다이렉트 한다. 그런데 로그인 이후에 다시 홈으로 이동해버리면, 원하는 경로를 다시 찾아가야 하는 불편함이 있다. 예를 들어서 상품 관리 화면을 보려고 들어갔다가 로그인 화면으로 이동하면, 로그인 이후에 다시 상품 관리 화면으로 들어가는 것이 좋다. 이런 부분이 개발자 입장에서는 좀 귀찮을 수 있어도 사용자 입장으로 보면 편리한 기능이다. 이러한 기능을 위해 현재 요청한 경로인 requestURI 를 /login 에 쿼리 파라미터로 함께 전달한다. 물론 /login 컨트롤러에서 로그인 성공시 해당 경로로 이동하는 기능은 추가로 개발해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; return;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기가 중요하다. 필터를 더는 진행하지 않는다. 이후 필터는 물론 서블릿, 컨트롤러가 더는 호출되지 않는다. 앞서 redirect 를 사용했기 때문에 redirect 가 응답으로 적용되고 요청이 끝난다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;&lt;b&gt;스프링 인터셉터 &lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;스프링 인터셉터 흐름 &lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 요청 -&amp;gt; WAS -&amp;gt; 필터 -&amp;gt; 서블릿(디스패처 서블릿) -&amp;gt; 스프링 인터셉터 -&amp;gt; 컨트롤러&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;스프링 인터셉터 제한&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 요청 -&amp;gt; WAS -&amp;gt; 필터 -&amp;gt; 서블릿 -&amp;gt; 스프링 인터셉터 -&amp;gt; 컨트롤러 //로그인 사용자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 요청 -&amp;gt; WAS -&amp;gt; 필터 -&amp;gt; 서블릿 -&amp;gt; 스프링 인터셉터(적절하지 않은 요청이라 판단, 컨트롤러 호출 X) // 비 로그인 사용자&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;스프링 인터셉터 체인 &lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 요청 -&amp;gt; WAS -&amp;gt; 필터 -&amp;gt; 서블릿 -&amp;gt; 인터셉터1 -&amp;gt; 인터셉터2 -&amp;gt; 컨트롤러&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;i&gt;&lt;b&gt;스프링 인터셉터 인터페이스&lt;/b&gt;&lt;/i&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1652527747903&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse
response,
 Object handler) throws Exception {}
default void postHandle(HttpServletRequest request, HttpServletResponse
response,
 Object handler, @Nullable ModelAndView modelAndView)
throws Exception {}
default void afterCompletion(HttpServletRequest request, HttpServletResponse
response,
 Object handler, @Nullable Exception ex) throws
Exception {}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터셉터는 컨트롤러 호출 전( preHandle ), 호출 후( postHandle ), 요청 완료 이후( afterCompletion )와 같이 단계적으로 잘 세분화 되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터셉터는 어떤 컨트롤러( handler )가 호출되는지 호출 정보도 받을 수 있다. 그리고 어떤 modelAndView 가 반환되는지 응답 정보도 받을 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;777&quot; data-origin-height=&quot;454&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ber9ZP/btrB8QTVJwj/KDPXZiTjGabZWR0oDVGAY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ber9ZP/btrB8QTVJwj/KDPXZiTjGabZWR0oDVGAY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ber9ZP/btrB8QTVJwj/KDPXZiTjGabZWR0oDVGAY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fber9ZP%2FbtrB8QTVJwj%2FKDPXZiTjGabZWR0oDVGAY0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;777&quot; height=&quot;454&quot; data-origin-width=&quot;777&quot; data-origin-height=&quot;454&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;정상 흐름&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;preHandle : 컨트롤러 호출 전에 호출된다. (더 정확히는 핸들러 어댑터 호출 전에 호출된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;preHandle 의 응답값이 true 이면 다음으로 진행하고, false 이면 더는 진행하지 않는다. false 인 경우 나머지 인터셉터는 물론이고, 핸들러 어댑터도 호출되지 않는다. 그림에서 1번에서 끝이 나버린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;postHandle : 컨트롤러 호출 후에 호출된다. (더 정확히는 핸들러 어댑터 호출 후에 호출된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;afterCompletion : 뷰가 렌더링 된 이후에 호출된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;예외흐름&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예외가 발생시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;preHandle : 컨트롤러 호출 전에 호출된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;postHandle : 컨트롤러에서 예외가 발생하면 postHandle 은 호출되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;afterCompletion : afterCompletion 은 항상 호출된다. 이 경우 예외( ex )를 파라미터로 받아서 어떤 예외가 발생했는지 로그로 출력할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;afterCompletion은 예외가 발생해도 호출된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예외가 발생하면 postHandle() 는 호출되지 않으므로 예외와 무관하게 공통 처리를 하려면 afterCompletion() 을 사용해야 한다. 예외가 발생하면 afterCompletion() 에 예외 정보( ex )를 포함해서 호출된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;WebConfig -&lt;b&gt; 인터셉터 등록&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1652527988980&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
public class WebConfig implements WebMvcConfigurer {
 @Override
 public void addInterceptors(InterceptorRegistry registry) {
 registry.addInterceptor(new LogInterceptor())
 .order(1)
 .addPathPatterns(&quot;/**&quot;)
 .excludePathPatterns(&quot;/css/**&quot;, &quot;/*.ico&quot;, &quot;/error&quot;);
 }
 //...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WebMvcConfigurer 가 제공하는 addInterceptors() 를 사용해서 인터셉터를 등록할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;registry.addInterceptor(new LogInterceptor()) : 인터셉터를 등록한다. &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;order(1) : 인터셉터의 호출 순서를 지정한다. 낮을 수록 먼저 호출된다. &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;addPathPatterns(&quot;/**&quot;) : 인터셉터를 적용할 URL 패턴을 지정한다. &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;excludePathPatterns(&quot;/css/**&quot;, &quot;/*.ico&quot;, &quot;/error&quot;) : 인터셉터에서 제외할 패턴을 지정한다&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(filter처럼 따로 제외할 url을 만들고 체크 안해도 됨)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;인터셉터를 이용한 인증체크 코드&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1652528304773&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class LoginCheckInterceptor implements HandlerInterceptor {
 @Override
 public boolean preHandle(HttpServletRequest request, HttpServletResponse
response, Object handler) throws Exception {
 String requestURI = request.getRequestURI();
 log.info(&quot;인증 체크 인터셉터 실행 {}&quot;, requestURI);
 HttpSession session = request.getSession(false);
 if (session == null || session.getAttribute(SessionConst.LOGIN_MEMBER)
== null) {
 log.info(&quot;미인증 사용자 요청&quot;);
 //로그인으로 redirect
 response.sendRedirect(&quot;/login?redirectURL=&quot; + requestURI);
 return false;
 }
 return true;
 }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;return 이 false면 종료 true면 컨트롤러 실행&lt;/p&gt;</description>
      <category>백 엔드/spring</category>
      <category>스프링</category>
      <category>인터셉터</category>
      <category>필터</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/114</guid>
      <comments>https://aimk12.tistory.com/114#entry114comment</comments>
      <pubDate>Sat, 14 May 2022 20:42:12 +0900</pubDate>
    </item>
    <item>
      <title>스프링 -쿠키,세션</title>
      <link>https://aimk12.tistory.com/113</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;김영한 강의 MVC 2편 정리&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;쿠키&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;쿠키는&amp;nbsp; 클라이언트가 서버에 접속할때 로그인 상태인지 아닌지 구별하기 위해 존재한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;클라이언트가 서버에 요청을 보내면 서버는 쿠키값을 준다. 그리고 그 이후의 클라이언트 요청에 쿠키값과 서버에 저장한 쿠키랑 비교하면서 일치하면 로그인한 결과창을 보내준다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;로그인 시 쿠키 생성코드&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1652418203794&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Cookie idCookie = new Cookie(&quot;memberId&quot;, String.valueOf(loginMember.getId()));
response.addCookie(idCookie);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠키에는 영속 쿠키와 세션 쿠키가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영속 쿠키: 만료 날짜를 입력하면 해당 날짜까지 유지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세션 쿠키: 만료 날짜를 생략하면 브라우저 종료시 까지만 유지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;로그아웃 기능&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;세션 쿠키이므로 웹 브라우저 종료시 서버에서 해당 쿠키의 종료 날짜를 0으로 지정&lt;/p&gt;
&lt;pre id=&quot;code_1652418336329&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Cookie cookie = new Cookie(cookieName, null);
 cookie.setMaxAge(0);
 response.addCookie(cookie);&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;보안 문제&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt; 쿠키 값은 임의로 변경할 수 있다.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트가 쿠키를 강제로 변경하면 다른 사용자가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 웹브라우저 개발자모드 Application Cookie 변경으로 확인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Cookie: memberId=1 Cookie: memberId=2 (다른 사용자의 이름이 보임)&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;쿠키에 보관된 정보는 훔쳐갈 수 있다. &lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 쿠키에 개인정보나, 신용카드 정보가 있다면?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 정보가 웹 브라우저에도 보관되고, 네트워크 요청마다 계속 클라이언트에서 서버로 전달된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠키의 정보가 나의 로컬 PC가 털릴 수도 있고, 네트워크 전송 구간에서 털릴 수도 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;해커가 쿠키를 한번 훔쳐가면 평생 사용할 수 있다. &lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해커가 쿠키를 훔쳐가서 그 쿠키로 악의적인 요청을 계속 시도할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 해결하려면 결국 중요한 정보를 모두 서버에 저장해야 한다. 그리고 클라이언트와 서버는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;추정 불가능한 임의의 식별자 값으로 연결&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/span&gt;해야 한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;세션&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;세션 ID를 생성하는데, &lt;span style=&quot;color: #ee2323;&quot;&gt;추정 불가능&lt;/span&gt;&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UUID는 추정이 불가능하다. ex)Cookie: mySessionId=zz0101xx-bab9-4b92-9b32-dadb280f4b61&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성된 세션 ID와 세션에 보관할 값( memberA )을 서버의 세션 저장소에 보관한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 중요한 포인트는 회원과 관련된 정보는 전혀 클라이언트에 전달하지 않는다는 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 쿠키를 탈취 당한다면?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠키 탈취 후 사용 해커가 토큰을 털어가도 시간이 지나면 사용할 수 없도록 서버에서 세션의 만료시간을 짧게(예: 30분) 유지한다. 또는 해킹이 의심되는 경우 서버에서 해당 세션을 강제로 제거하면 된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;i&gt;&lt;b&gt;HttpSession 기능&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1652418726305&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; //세션이 있으면 있는 세션 반환, 없으면 신규 세션 생성
 HttpSession session = request.getSession();
 //세션에 로그인 회원 정보 보관
 session.setAttribute(SessionConst.LOGIN_MEMBER, loginMember);&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;세션 생성과 조회&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세션을 생성하려면&lt;b&gt; request.getSession(true)&lt;/b&gt; 를 사용하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;public HttpSession getSession(boolean create);&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세션의 create 옵션에 대해 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; request.getSession(true)&lt;/b&gt; -세션이 있으면 기존 세션을 반환한다. 세션이 없으면 새로운 세션을 생성해서 반환한다. &lt;b&gt;request.getSession(false)&lt;/b&gt; -세션이 있으면 기존 세션을 반환한다. 세션이 없으면 새로운 세션을 생성하지 않는다. null 을 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;request.getSession()&lt;/b&gt; : 신규 세션을 생성하는 request.getSession(true) 와 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;세션에 로그인 회원 정보 보관 &lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;session.setAttribute(SessionConst.LOGIN_MEMBER, loginMember); &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세션에 데이터를 보관하는 방법은 request.setAttribute(..) 와 비슷하다. 하나의 세션에 여러 값을 저장할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세션의 값에 쿠키이름과 쿠키 값을 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조회는 세션의 값으로 조회&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;세션 삭제 기능&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1652418999743&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//세션을 삭제한다.
 HttpSession session = request.getSession(false);
 if (session != null) {
 session.invalidate();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;session.invalidate() : 세션을 제거한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;세션값과 쿠키이름에 해당하는 객체 찾기&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;session.getAttribute(SessionConst.LOGIN_MEMBER) : 로그인 시점에 세션에 보관한 회원 객체를 찾는다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;스프링에서 지원하는 기능&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 로그인 된 사용자를 찾을 때는 다음과 같이 사용하면 된다. 참고로 이 기능은 &lt;b&gt;&lt;u&gt;세션을 생성하지 않는다&lt;/u&gt;&lt;/b&gt;.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1652419156486&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@SessionAttribute(name = SessionConst.LOGIN_MEMBER, required = false)
Member loginMember,Model model)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;URL에 세션값 담기는거 뺴기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTPSession기능은 처음 세션을 보낼때 URL에 세션값도 같이 보냈다. 이 이유는 최초에 서버 입장에서 웹브라우저가 쿠키를&amp;nbsp; 지원하는지 안하는지 판단이 불가능 하기 떄문이다. 이 전달 방식을 끄기 위해서는&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;application.properties파일에&lt;/p&gt;
&lt;pre id=&quot;code_1652419482973&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;server.servlet.session.tracking-modes=cookie&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이&amp;nbsp; 코드를 추가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;세션정보와 타임아웃설정&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;세션정보&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;sessionId : 세션Id, JSESSIONID 의 값이다&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;. 예) 34B14F008AA3527C9F8ED620EFD7A4E1 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;maxInactiveInterval : 세션의 유효 시간, 예) 1800초, (30분)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; creationTime : 세션 생성일시 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;lastAccessedTime : 세션과 연결된 사용자가 최근에 서버에 접근한 시간, 클라이언트에서 서버로 sessionId ( JSESSIONID )를 요청한 경우에 갱신된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; isNew : 새로 생성된 세션인지, 아니면 이미 과거에 만들어졌고, 클라이언트에서 서버로 sessionId ( JSESSIONID )를 요청해서 조회된 세션인지 여부&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;타임아웃 설정-(타임아웃이란-&amp;gt; 세션 유지시간)&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;글로벌&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;application.properties파엘에&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;server.servlet.session.timeout=60(초단위,최소 60)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;특정세션 설정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;session.setMaxInactiveInterval(1800); //1800초&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>백 엔드/spring</category>
      <category>HttpSession</category>
      <category>세션</category>
      <category>스프링</category>
      <category>쿠키</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/113</guid>
      <comments>https://aimk12.tistory.com/113#entry113comment</comments>
      <pubDate>Fri, 13 May 2022 14:33:28 +0900</pubDate>
    </item>
    <item>
      <title>스프링 Bean Validation</title>
      <link>https://aimk12.tistory.com/112</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;i&gt;&lt;b&gt;김영한선생님의 MVC2편&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;i&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Bean Validaiton&lt;/b&gt;&lt;/span&gt;&lt;/i&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전 글에서 봤듯이 검증기능 코드들은 상당히 길고 복잡하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 또한 중복되어서 쓰이는 기능들이 많이 보인다. 이를 애노테이션으로 쉽게 지원을 해주는 것이 Bean Validaiton이다. 아래에서 예시를 보자&lt;/p&gt;
&lt;pre id=&quot;code_1652026338254&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Item {
 private Long id;
 @NotBlank
 private String itemName;
 @NotNull
 @Range(min = 1000, max = 1000000)
 private Integer price;
 @NotNull
 @Max(9999)
 private Integer quantity;
 /&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드는 이렇게 해석이 가능하다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@NotBlank : 빈값 + 공백만 있는 경우를 허용하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@NotNull : null 을 허용하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Range(min = 1000, max = 1000000) : 범위 안의 값이어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Max(9999) : 최대 9999까지만 허용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;i&gt;&lt;b&gt;검증 순서 &lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. @ModelAttribute 각각의 필드에 타입 변환 시도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1. 성공하면 다음으로 2. 실패하면 typeMismatch 로 FieldError 추가)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Validator 적용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@ModelAttribute 각각의 필드 타입 변환시도 변환에 성공한 필드만 BeanValidation 적용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bean Validation을 적용하고 bindingResult 에 등록된 검증 오류 코드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@NotBlank&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NotBlank.item.itemName&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NotBlank.itemName&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NotBlank.java.lang.String&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NotBlank&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Range&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Range.item.price&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Range.price&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Range.java.lang.Integer&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Range&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메시지 코드&lt;/p&gt;
&lt;pre id=&quot;code_1652026828656&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#Bean Validation 추가
NotBlank={0} 공백X
Range={0}, {2} ~ {1} 허용
Max={0}, 최대 {1}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;{0} 은 필드명이고, {1} , {2} ...은 각 애노테이션 마다 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;BeanValidation 메시지 찾는 순서&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 생성된 메시지 코드 순서대로 messageSource 에서 메시지 찾기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 애노테이션의 message 속성 사용 @NotBlank(message = &quot;공백! {0}&quot;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 라이브러리가 제공하는 기본 값 사용 공백일 수 없습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt; 동일한 모델 객체를 각각 다르게 검증&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/span&gt;해야 할떄&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴때 구분지으면서 구분할수 있는 방법이 2가지 있다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.BeanValidation의 groups 기능을 사용한다. &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2.Item을 직접 사용하지 않고, ItemSaveForm, ItemUpdateForm 같은 폼 전송을 위한 별도의 모델 객체를 만들어서 사용한다&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;&lt;b&gt;1번째 방법-groups기능 (savecheck,updatecheck 빈 인터페이스 생성후)&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1652026999021&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Data
public class Item {
 @NotNull(groups = UpdateCheck.class) //수정시에만 적용
 private Long id;
 @NotBlank(groups = {SaveCheck.class, UpdateCheck.class})
 private String itemName;
 @NotNull(groups = {SaveCheck.class, UpdateCheck.class})
 @Range(min = 1000, max = 1000000, groups = {SaveCheck.class,
UpdateCheck.class})
 private Integer price;
 @NotNull(groups = {SaveCheck.class, UpdateCheck.class})
 @Max(value = 9999, groups = SaveCheck.class) //등록시에만 적용
 private Integer quantity;
 public Item() {
 }
 public Item(String itemName, Integer price, Integer quantity) {
 this.itemName = itemName;
 this.price = price;
 this.quantity = quantity;
 }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1652027031060&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@PostMapping(&quot;/add&quot;)
public String addItemV2(@Validated(SaveCheck.class) @ModelAttribute Item item,
BindingResult bindingResult, RedirectAttributes redirectAttributes) {
 //...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드들은 주어진 인터페이스에 따라 객체다르게 검증하는 방법이다. 하지만 위와 같은 방법은 복잡하다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;&lt;b&gt;2번쨰 방법 Form 전송 객체 분리&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;i&gt;&lt;b&gt;폼 데이터 전달에 Item 도메인 객체 사용 &lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML Form -&amp;gt; Item -&amp;gt; Controller -&amp;gt; Item -&amp;gt; Repository&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장점: Item 도메인 객체를 컨트롤러, 리포지토리 까지 직접 전달해서 중간에 Item을 만드는 과정이 없어서 간단하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단점: 간단한 경우에만 적용할 수 있다. 수정시 검증이 중복될 수 있고, groups를 사용해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;i&gt;&lt;b&gt;폼 데이터 전달을 위한 별도의 객체 사용 &lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML Form -&amp;gt; ItemSaveForm -&amp;gt; Controller -&amp;gt; Item 생성 -&amp;gt; Repository&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장점: 전송하는 폼 데이터가 복잡해도 거기에 맞춘 별도의 폼 객체를 사용해서 데이터를 전달 받을 수 있다. 보통 등록과, 수정용으로 별도의 폼 객체를 만들기 때문에 검증이 중복되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단점: 폼 데이터를 기반으로 컨트롤러에서 Item 객체를 생성하는 변환 과정이 추가된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 처럼 별도의 전송객체 만들기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1652027311580&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Data
public class ItemSaveForm {
 @NotBlank
 private String itemName;
 @NotNull
 @Range(min = 1000, max = 1000000)
 private Integer price;
 @NotNull
 @Max(value = 9999)
 private Integer quantity;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1652027344354&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Data
public class ItemUpdateForm {
 @NotNull
 private Long id;
 @NotBlank
 private String itemName;
 @NotNull
 @Range(min = 1000, max = 1000000)
 private Integer price;
 //수정에서는 수량은 자유롭게 변경할 수 있다.
 private Integer quantity;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 아래는 컨트롤러 코드 (전달 객체에서 받은 데이터 본 객체로 전달하기 위한 생성 코드 필요)&lt;/p&gt;
&lt;pre id=&quot;code_1652027397618&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@PostMapping(&quot;/add&quot;)
 public String addItem(@Validated @ModelAttribute(&quot;item&quot;) ItemSaveForm form,
BindingResult bindingResult, RedirectAttributes redirectAttributes) {
 //특정 필드 예외가 아닌 전체 예외
 if (form.getPrice() != null &amp;amp;&amp;amp; form.getQuantity() != null) {
 int resultPrice = form.getPrice() * form.getQuantity();
 if (resultPrice &amp;lt; 10000) {
 bindingResult.reject(&quot;totalPriceMin&quot;, new Object[]{10000,
resultPrice}, null);
 }
 }
 if (bindingResult.hasErrors()) {
 log.info(&quot;errors={}&quot;, bindingResult);
 return &quot;validation/v4/addForm&quot;;
 }
 //성공 로직
 Item item = new Item();
 item.setItemName(form.getItemName());
 item.setPrice(form.getPrice());
 item.setQuantity(form.getQuantity());
 Item savedItem = itemRepository.save(item);
 redirectAttributes.addAttribute(&quot;itemId&quot;, savedItem.getId());
 redirectAttributes.addAttribute(&quot;status&quot;, true);
 return &quot;redirect:/validation/v4/items/{itemId}&quot;;
 }&lt;/code&gt;&lt;/pre&gt;</description>
      <category>백 엔드/spring</category>
      <category>Bean Validation</category>
      <category>스프링</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/112</guid>
      <comments>https://aimk12.tistory.com/112#entry112comment</comments>
      <pubDate>Mon, 9 May 2022 01:32:20 +0900</pubDate>
    </item>
    <item>
      <title>스프링 vaildation</title>
      <link>https://aimk12.tistory.com/111</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;김영한 선생님의 MVC2편 정리&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;&lt;b&gt;검증&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 요청이 정상인지 우리의 요구랑 다른 값들이 들어오는지 검증하는 단계이고 스프링에서 도와주는 기능들이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오류 처리 방법을 도와주는&amp;nbsp; BindingResult&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BindingResult bindingResult 파라미터의 위치는 @ModelAttribute Item item 다음에 와야 한다 이렇게 하면 BIndingResult는 객체 item을 알고 있고 사용이 가능하다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;필드오류(fielderror)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1652024255349&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (!StringUtils.hasText(item.getItemName())) {
 bindingResult.addError(new FieldError(&quot;item&quot;, &quot;itemName&quot;, &quot;상품 이름은
필수입니다.&quot;));
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파라미터 목록&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;objectName : 오류가 발생한 객체 이름&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;field : 오류 필드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;rejectedValue : 사용자가 입력한 값(거절된 값)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;bindingFailure : 타입 오류 같은 바인딩 실패인지, 검증 실패인지 구분 값&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;codes : 메시지 코드&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-메시지 코드는 전에 했던 메시지,국제화 사용하듯이 errors.properties에 넣어서 사용함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;arguments : 메시지에서 사용하는 인자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;defaultMessage : 기본 오류 메시지&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;글로벌 오류 - ObjectError&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1652024277456&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;bindingResult.addError(new ObjectError(&quot;item&quot;, &quot;가격 * 수량의 합은 10,000원 이상이어야
합니다. 현재 값 = &quot; + resultPrice));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 필드를 넘어서는 오류가 있으면 ObjectError 객체를 생성해서 bindingResult 에 담아두면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파라미터는 필드오류 랑 유사하다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;타임리프 스프링 검증 오류 통합 기능&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타임리프는 스프링의 BindingResult 를 활용해서 편리하게 검증 오류를 표현하는 기능을 제공한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;#fields : #fields 로 BindingResult 가 제공하는 검증 오류에 접근할 수 있다.&lt;/li&gt;
&lt;li&gt;th:errors : 해당 필드에 오류가 있는 경우에 태그를 출력한다. th:if 의 편의 버전이다.&lt;/li&gt;
&lt;li&gt;th:errorclass : th:field 에서 지정한 필드에 오류가 있으면 class 정보를 추가한다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;BindingResult에 검증 오류를 적용하는 3가지 방법&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@ModelAttribute 의 객체에 타입 오류 등으로 바인딩이 실패하는 경우 스프링이 FieldError 생성해서 BindingResult 에 넣어준다.&lt;/li&gt;
&lt;li&gt;개발자가 직접 넣어준다.&lt;/li&gt;
&lt;li&gt;Validator 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;오류 발생시 사용자 입력 값 유지&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;new FieldError(&quot;item&quot;, &quot;price&quot;, item.getPrice(), false, null, null, &quot;가격은 1,000 ~ 1,000,000 까지 허용합니다.&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이럴 경우 타입이 안 맞으면 객체에 저장이 불가능 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 th:field=&quot;*{price}&quot; 타임리프의 th:field 는 매우 똑똑하게 동작하는데, 정상 상황에는 모델 객체의 값을 사용하지만, 오류가 발생하면 FieldError 에서 보관한 값을 사용해서 값을 출력한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 위와 같은 필드 오류와 글로벌 오류를 다루기는 인자가 많기도 하고 중복이 많다 이를 편히 만든게&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;rejectValue()&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BindingResult 가 제공하는 rejectValue()를 사용하면 FieldError , ObjectError 를 직접 생성하지 않고, 깔끔하게 검증 오류를 다룰 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1652025071723&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void rejectValue(@Nullable String field, String errorCode,
@Nullable Object[] errorArgs, @Nullable String defaultMessage);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;field : 오류 필드명&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;errorCode : 오류 코드(이 오류 코드는 메시지에 등록된 코드가 아니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;errorArgs : 오류 메시지에서 {0} 을 치환하기 위한 값&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;defaultMessage : 오류 메시지를 찾을 수 없을 때 사용하는 기본 메시지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에가 가능한 이유는 BindingResult가 이미 바인딩할 객체를 알고 있고 위의 오류코드를 단순하게&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FieldError rejectValue(&quot;itemName&quot;, &quot;required&quot;) 적용이 가능하다 .이유는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 4가지 오류 코드를 자동으로 생성하고 위에서 부터 우선순위가 적용이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;required.item.itemName&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;required.itemName&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;required.java.lang.String&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;required&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ObjectError reject(&quot;totalPriceMin&quot;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 2가지 오류 코드를 자동으로 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;totalPriceMin.item&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;totalPriceMin&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 위의 기능들은 타입이 다른것들을 오류처리할 수 없다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;스프링은 타입 오류가 발생하면 typeMismatch&lt;/b&gt; &lt;/i&gt;&lt;/u&gt;라는 오류 코드를 사용한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;typeMismatch.item.price&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;typeMismatch.price&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;typeMismatch.java.lang.Integer&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;typeMismatch&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 메시지 코드를 정리하면 타입이 다른 것들도 오류처리가 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;검증 부분 분리하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이떄 쓰이는 인터페이스&lt;/p&gt;
&lt;pre id=&quot;code_1652025976625&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface Validator {
boolean supports(Class&amp;lt;?&amp;gt; clazz);
void validate(Object target, Errors errors);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;supports() {} : 해당 검증기를 지원하는 여부 확인(뒤에서 설명)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;validate(Object target, Errors errors) : 검증 대상 객체와 BindingResult&amp;nbsp; &amp;nbsp;(errors가 binding Result 상위클래스)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WebDataBinder 는 스프링의 파라미터 바인딩의 역할을 해주고 검증 기능도 내부에 포함한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨트롤러에 포함하면 검증기 전부 사용가능&lt;/p&gt;
&lt;pre id=&quot;code_1652026055814&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@InitBinder
public void init(WebDataBinder dataBinder) {
 log.info(&quot;init binder {}&quot;, dataBinder);
 dataBinder.addValidators(itemValidator);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;@Validated&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/span&gt; 는 검증기를 실행하라는 애노테이션이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 애노테이션이 붙으면 앞서 WebDataBinder 에 등록한 검증기를 찾아서 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 여러 검증기를 등록한다면 그 중에 어떤 검증기가 실행되어야 할지 구분이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 supports() 가 사용된다. 여기서는 supports(Item.class) 호출되고, 결과가 true 이므로 ItemValidator 의 validate() 가 호출된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1652026143499&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@PostMapping(&quot;/add&quot;)
public String addItem(@Validated @ModelAttribute(&quot;item&quot;) ItemSaveForm form,
BindingResult bindingResult, RedirectAttributes redirectAttributes) {
 //...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드처럼 검증할 객체앞에 @vaildated 붙이기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>백 엔드/spring</category>
      <category>vaildation</category>
      <category>스프링</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/111</guid>
      <comments>https://aimk12.tistory.com/111#entry111comment</comments>
      <pubDate>Mon, 9 May 2022 01:11:27 +0900</pubDate>
    </item>
    <item>
      <title>스프링 메시지,국제화</title>
      <link>https://aimk12.tistory.com/110</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;i&gt;&lt;b&gt;김영한 선생님의 MVC2편 정리&lt;/b&gt;&lt;/i&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;메시지&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상품명이라는 단어를 모두 상품이름으로 고쳐달라고 하면 어떻게 해야할까?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴떄 필요한게 메시지다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메시지를 한 곳에서 관리하도록 하는 기능을 메시지 기능이라 한다&lt;/p&gt;
&lt;pre id=&quot;code_1651812717966&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;item=상품
item.id=상품 ID
item.itemName=상품명
item.price=가격
item.quantity=수량&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1651812751592&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;label for=&quot;itemName&quot; th:text=&quot;#{item.itemName}&quot;&amp;gt;&amp;lt;/label&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드는 메시지에 있는 값들로 변경되어 상품명이 출력이 되게한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예외 파라미터 제공도 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hello.name=안녕 {0}&lt;/p&gt;
&lt;pre id=&quot;code_1651848568508&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;p th:text=&quot;#{hello.name(${item.itemName})}&quot;&amp;gt;&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 경우에는 저렇게 파라미터값을 넣는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;스프링이 제공하는 메시지 소스&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MessageSource ms;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ms.getMessage(&quot;hello&quot;, null, null)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;code: hello&amp;nbsp; &amp;nbsp; &amp;nbsp; // hello라는 변수 찾기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;args: null&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;locale: null&amp;nbsp; &amp;nbsp;//null은 기본 base조회&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 단순한 테스트는 메시지 코드로 hello 를 입력하고 나머지 값은 null 을 입력했다. locale 정보가 없으면 basename 에서 설정한 기본 이름 메시지 파일을 조회한다. basename 으로 messages 를 지정 했으므로 messages.properties 파일에서 데이터 조회한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;국제화&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영어로 읽는 사람은 영어로 보여주고 한글로 읽는 사람은 한글로 보여주는 시스템이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;messages_en.propertis 는 메시지 라벨이 영어로 저장되어 있는것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;messages_ko.propertis 는 메시지 라벨이 한글로 저장되어 있는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한국에서 접근한 것인지 영어에서 접근한 것인지는 인식하는 방법은 HTTP accept-language 해더 값을 사용하거나 사용자가 직접 언어를 선택하도록 하고, 쿠키 등을 사용해서 처리하면 된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;스프링에서 메시지 소스 설정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;application.properties 파일에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;spring.messages.basename=messages 를 적으면 기본 으로 제공되는 것이 messages가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 국제화가 하고 싶으면 messages_en.propertis messages_ko.propertis를 추가해서 사용하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;locale 정보를 기반으로 국제화 파일을 선택한다. Locale이 en_US 의 경우 messages_en_US messages_en messages 순서로 찾는다. Locale 에 맞추어 구체적인 것이 있으면 구체적인 것을 찾고, 없으면 디폴트를 찾는다고 이해하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex)ms.getMessage(&quot;hello&quot;, null, null) : locale 정보가 없으므로 messages 를 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ms.getMessage(&quot;hello&quot;, null, Locale.KOREA) : locale 정보가 있지만, message_ko 가 없으므로 messages 를 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ms.getMessage(&quot;hello&quot;, null, Locale.ENGLISH) : locale 정보가 Locale.ENGLISH 이므로 messages_en 을 찾아서 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;스프링도 Locale 정보를 알아야 언어를 선택할 수 있는데, 스프링은 언어 선택시 기본으로 AcceptLanguage 헤더의 값을 사용한다&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LocaleResolver 스프링은 Locale 선택 방식을 변경할 수 있도록 LocaleResolver 라는 인터페이스를 제공하는데, 스프링 부트는 기본으로 Accept-Language 를 활용하는 AcceptHeaderLocaleResolver 를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex)쿠키나 세션 기반의 Locale 선택 기능을 사용할 수 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>백 엔드/spring</category>
      <category>메시지</category>
      <category>스프링</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/110</guid>
      <comments>https://aimk12.tistory.com/110#entry110comment</comments>
      <pubDate>Fri, 6 May 2022 23:57:00 +0900</pubDate>
    </item>
    <item>
      <title>스프링 타임리프 스프링 통합기능</title>
      <link>https://aimk12.tistory.com/109</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;i&gt;&lt;b&gt;김영한 선생님의 MVC2편 정리&lt;/b&gt;&lt;/i&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;스프링 통합으로 추가되는 기능들 &lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;스프링의 SpringEL 문법 통합&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;${@myBean.doSomething()} 처럼 스프링 빈 호출 지원&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;편리한 폼 관리를 위한 추가 속성 &lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;th:object (기능 강화, 폼 커맨드 객체 선택)&lt;/li&gt;
&lt;li&gt;th:field , th:errors , th:errorclass&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;폼 컴포넌트 기능 &lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;checkbox, radio button, List 등을 편리하게 사용할 수 있는 기능 지원&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;스프링의 메시지, 국제화 기능의 편리한 통합&lt;/b&gt;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt; 스프링의 검증, 오류 처리 통합 &lt;/b&gt;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;스프링의 변환 서비스 통합(ConversionService)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;입력폼 기능&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;th:object : 커맨드 객체를 지정한다.&lt;/li&gt;
&lt;li&gt;*{...} : 선택 변수 식이라고 한다.&lt;/li&gt;
&lt;li&gt;th:object 에서 선택한 객체에 접근한다&lt;/li&gt;
&lt;li&gt;. th:field HTML 태그의 id , name , value 속성을 자동으로 처리해준다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;th:object=&quot;${item}&quot; : 에서 사용할 객체를 지정한다. &lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;선택 변수 식( *{...} )을 적용할 수 있다.&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt; th:field=&quot;*{itemName}&quot; &lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;*{itemName} 는 선택 변수 식을 사용했는데, ${item.itemName} 과 같다. 앞서 th:object 로 item 을 선택했기 때문에 선택 변수 식을 적용할 수 있다. &lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;th:field 는 id , name , value 속성을 모두 자동으로 만들어준다. &lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;id : th:field 에서 지정한 변수 이름과 같다. id=&quot;itemName&quot; &lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;name : th:field 에서 지정한 변수 이름과 같다. name=&quot;itemName&quot;&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt; value : th:field 에서 지정한 변수의 값을 사용한다. value=&quot;&quot; &lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 해당 예제에서 id 속성을 제거해도 th:field 가 자동으로 만들어준다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;체크박스&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;단일&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;체크 박스를 체크하면 HTML Form에서 (변수 boolean)open=on 이라는 값이 넘어간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링은 on 이라는 문자를 true 타입으로 변환해준다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML checkbox는 선택이 안되면 클라이언트에서 &lt;b&gt;&lt;u&gt;서버로 값 자체를 보내지 않는다&lt;/u&gt;&lt;/b&gt;. 수정의 경우에는 상황에 따라서 이 방식이 문제가 될 수 있다. 사용자가 의도적으로 체크되어 있던 값을 체크를 해제해도 저장시 아무 값도 넘어가지 않기 때문에, 서버 구현에 따라서 값이 오지 않은 것으로 판단해서 값을 변경하지 않을 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 해결하기 위해&lt;u&gt;&lt;b&gt; 히든 필드&lt;/b&gt;&lt;/u&gt;가 사용이 된다. 체크되지 않으면 반드시 넘어온다 그리고 이것이 넘어오면 true가 아닌 false로바뀐다.&lt;/p&gt;
&lt;pre id=&quot;code_1651765632708&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;input type=&quot;hidden&quot; name=&quot;_open&quot; value=&quot;on&quot;/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이 히든필드를 자꾸 넣어주면 귀찮다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴 떄 타임리프의&lt;u&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt; th:field&lt;/span&gt; &lt;/b&gt;&lt;/u&gt;가 효력을 발휘한다&lt;/p&gt;
&lt;pre id=&quot;code_1651766530550&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;input type=&quot;checkbox&quot; id=&quot;open&quot; th:field=&quot;*{open}&quot; class=&quot;form-checkinput&quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;이 기능을 사용하면 히든필드가 자동으로 삽입이 된다.&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;checked=&quot;checked&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;체크 박스에서 판매 여부를 선택해서 저장하면, 조회시에 checked 속성이 추가된 것을 확인할 수 있다. 이런 부분을 개발자가 직접 처리하려면 상당히 번거롭다. 타임리프의 th:field 를 사용하면, &lt;u&gt;&lt;b&gt;값이 true 인 경우 체크를 자동으로 처리해준다.&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;&lt;b&gt;멀티&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;@ModelAttribute의 특별한 사용법&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예)&lt;/p&gt;
&lt;pre id=&quot;code_1651767433704&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@ModelAttribute(&quot;regions&quot;)
public Map&amp;lt;String, String&amp;gt; regions() {
 Map&amp;lt;String, String&amp;gt; regions = new LinkedHashMap&amp;lt;&amp;gt;();
 regions.put(&quot;SEOUL&quot;, &quot;서울&quot;);
 regions.put(&quot;BUSAN&quot;, &quot;부산&quot;);
 regions.put(&quot;JEJU&quot;, &quot;제주&quot;);
 return regions;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@ModelAttribute 는&amp;nbsp; 컨트롤러에 있는 별도의 메서드에 적용할 수 있다. 이렇게하면 해당 컨트롤러를 요청할 때 regions 에서 반환한 값이 자동으로 모델( model )에 담기게 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;체크박스 멀티로 만들기&lt;/p&gt;
&lt;pre id=&quot;code_1651767478391&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div th:each=&quot;region : ${regions}&quot; class=&quot;form-check form-check-inline&quot;&amp;gt;
 &amp;lt;input type=&quot;checkbox&quot; th:field=&quot;*{regions}&quot; th:value=&quot;${region.key}&quot;
class=&quot;form-check-input&quot;&amp;gt;
 &amp;lt;label th:for=&quot;${#ids.prev('regions')}&quot;
 th:text=&quot;${region.value}&quot; class=&quot;form-check-label&quot;&amp;gt;서울&amp;lt;/label&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1651767520213&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;th:for=&quot;${#ids.prev('regions')}&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멀티 체크박스는 같은 이름의 여러 체크박스를 만들 수 있다. 그런데 문제는 이렇게 반복해서 HTML 태그를 생성할 때, 생성된 HTML 태그 속성에서 name 은 같아도 되지만, id 는 모두 달라야 한다. &lt;span&gt;위의 기능은&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&amp;nbsp;체크박스를 each 루프 안에서 반복해서 만들 때 임의로 1 , 2 , 3 숫자를 뒤에 붙여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서울, 부산 선택&amp;nbsp; regions=SEOUL&amp;amp;_regions=on(선택)&amp;amp;regions=BUSAN&amp;amp;_regions=on(선택)&amp;amp;_regions=on (선택안됨)로그 이걸로 체크 되었는지 판단 히든필드 삽입된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;라디오버튼&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;enum 배열&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1651769034268&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@ModelAttribute(&quot;itemTypes&quot;)
public ItemType[] itemTypes() {
 return ItemType.values();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ItemType.values() 를 사용하면 해당 ENUM의 모든 정보를 배열로 반환한다&lt;/p&gt;
&lt;pre id=&quot;code_1651769082367&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hello.itemservice.domain.item;
public enum ItemType {
    BOOK(&quot;도서&quot;), FOOD(&quot;식품&quot;), ETC(&quot;기타&quot;);
    private final String description;
    ItemType(String description) {
        this.description = description;
    }
    public String getDescription() {
        return description;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;열거형 생성자를 이용해서 만들었다. 생성하면 description에는 한글로 되어있는부분이 담긴다.&lt;/p&gt;
&lt;pre id=&quot;code_1651769068535&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div&amp;gt;
 &amp;lt;div&amp;gt;상품 종류&amp;lt;/div&amp;gt;
 &amp;lt;div th:each=&quot;type : ${itemTypes}&quot; class=&quot;form-check form-check-inline&quot;&amp;gt;
 &amp;lt;input type=&quot;radio&quot; th:field=&quot;*{itemType}&quot; th:value=&quot;${type.name()}&quot;
class=&quot;form-check-input&quot;&amp;gt;
 &amp;lt;label th:for=&quot;${#ids.prev('itemType')}&quot; th:text=&quot;${type.description}&quot;
class=&quot;form-check-label&quot;&amp;gt;
 BOOK
 &amp;lt;/label&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;description은 타임리프 특성상 type.getdescription 으로 된다. 그래서 한글로 나오게 된다 . name()은 book,food 같은 열거형 변수들을 string으로 변환하여 나오게 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;셀렉트 박스&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;밑에 코드들을 보자&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1651769592823&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@ModelAttribute(&quot;deliveryCodes&quot;)
public List&amp;lt;DeliveryCode&amp;gt; deliveryCodes() {
 List&amp;lt;DeliveryCode&amp;gt; deliveryCodes = new ArrayList&amp;lt;&amp;gt;();
 deliveryCodes.add(new DeliveryCode(&quot;FAST&quot;, &quot;빠른 배송&quot;));
 deliveryCodes.add(new DeliveryCode(&quot;NORMAL&quot;, &quot;일반 배송&quot;));
 deliveryCodes.add(new DeliveryCode(&quot;SLOW&quot;, &quot;느린 배송&quot;));
 return deliveryCodes;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1651769622067&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div&amp;gt;
 &amp;lt;div&amp;gt;배송 방식&amp;lt;/div&amp;gt;
 &amp;lt;select th:field=&quot;*{deliveryCode}&quot; class=&quot;form-select&quot;&amp;gt;
 &amp;lt;option value=&quot;&quot;&amp;gt;==배송 방식 선택==&amp;lt;/option&amp;gt;
 &amp;lt;option th:each=&quot;deliveryCode : ${deliveryCodes}&quot; th:value=&quot;$
{deliveryCode.code}&quot;
 th:text=&quot;${deliveryCode.displayName}&quot;&amp;gt;FAST&amp;lt;/option&amp;gt;
 &amp;lt;/select&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;checked=&quot;checked&quot; 나 selected=&quot;selected&quot; 는 th:field와 th:value 값을 비교해서 있으면 저 구문이 형성이 된다.&lt;/p&gt;</description>
      <category>백 엔드/spring</category>
      <category>Spring</category>
      <category>Thymeleaf</category>
      <category>스프링</category>
      <category>타임리프</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/109</guid>
      <comments>https://aimk12.tistory.com/109#entry109comment</comments>
      <pubDate>Fri, 6 May 2022 02:06:16 +0900</pubDate>
    </item>
    <item>
      <title>spring 타임리프 기본기능</title>
      <link>https://aimk12.tistory.com/108</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;i&gt;&lt;b&gt;김영한 선생님의 MVC2편 정리&lt;/b&gt;&lt;/i&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;텍스트 - text,utext&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타임리프는 기본적으로 HTML 테그의 속성에 기능을 정의해서 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML의 콘텐츠(content)에 데이터를 출력할 때는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 th:text 를 사용하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1651642873887&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;span th:text=&quot;${data}&quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML 테그의 속성이 아니라 HTML 콘텐츠 영역안에서 직접 데이터를 출력하고 싶으면 다음과 같이 [[...]] 를 사용하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1651642940439&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;컨텐츠 안에서 직접 출력하기 = [[${data}]]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;th:utext 와 [(...)]는 data값에 들어가 있는 속성을 적용시켜서 내보낸다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex)&lt;/p&gt;
&lt;pre id=&quot;code_1651644168421&quot; class=&quot;xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Hello &amp;lt;b&amp;gt;Spring!&amp;lt;/b&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문장이 data값에 들어가 있으면 th:utext,[(...)]은 태그 속성을 적용시켜서 내보내고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;th:text , [[...]] 은 태그 속성을 적용시키지 않는다.&lt;/p&gt;
&lt;pre id=&quot;code_1651644267074&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Hello &amp;amp;lt;b&amp;amp;gt;Spring!&amp;amp;lt;/b&amp;amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 값으로 내보내진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;변수&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Object &lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;user.username : user의 username을 프로퍼티 접근&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;user.getUsername() user['username'] : 위와 같음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;user.getUsername() user.getUsername() : user의 getUsername() 을 직접 호출&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;List &lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;users[0].username : List에서 첫 번째 회원을 찾고 username 프로퍼티 접근-&amp;gt; list.get(0).getUsername()&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;users[0]['username'] : 위와 같음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;users[0].getUsername() : List에서 첫 번째 회원을 찾고 메서드 직접 호출&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;Map &lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;userMap['userA'].username : Map에서 userA를 찾고, username 프로퍼티 접근 -&amp;gt;map.get(&quot;userA&quot;).getUsername() userMap['userA']['username'] : 위와 같음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;userMap['userA'].getUsername() : Map에서 userA를 찾고 메서드 직접 호출&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지역변수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;th:with 를 사용하면 지역 변수를 선언해서 사용할 수 있다. 지역 변수는 선언한 테그 안에서만 사용할 수 있다&lt;/p&gt;
&lt;pre id=&quot;code_1651645356258&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;h1&amp;gt;지역 변수 - (th:with)&amp;lt;/h1&amp;gt;
&amp;lt;div th:with=&quot;first=${users[0]}&quot;&amp;gt;
 &amp;lt;p&amp;gt;처음 사람의 이름은 &amp;lt;span th:text=&quot;${first.username}&quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 위의 코드는 first지역변수는 &amp;lt;div&amp;gt;태그 안에서만 사용가능하다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;기본 객체들&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;${#request}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;${#response}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;${#session}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;${#servletContext}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;${#locale}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 #request 는 HttpServletRequest 객체가 그대로 제공되기 때문에 데이터를 조회하려면 request.getParameter(&quot;data&quot;) 처럼 불편하게 접근해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 해결하기 위한 편의 기능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 요청 파라미터 접근: param&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예) ${param.paramData}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 세션 접근: session&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예) ${session.sessionData}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 빈 접근: @&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예) ${@helloBean.hello('Spring!')}&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;유틸리티 객체들&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타임리프는 문자, 숫자, 날짜, URI등을 편리하게 다루는 다양한 유틸리티 객체들을 제공한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;타임리프 유틸리티 객체들&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;#message : 메시지, 국제화 처리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;#uris : URI 이스케이프 지원&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;#dates : java.util.Date 서식 지원&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;#calendars : java.util.Calendar 서식 지원&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;#temporals : 자바8 날짜 서식 지원&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;#numbers : 숫자 서식 지원&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;#strings : 문자 관련 편의 기능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;#objects : 객체 관련 기능 제공&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;#bools : boolean 관련 기능 제공&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;#arrays : 배열 관련 기능 제공&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;#lists , #sets , #maps : 컬렉션 관련 기능 제공&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;#ids : 아이디 처리 관련 기능 제공, 뒤에서 설명&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#expression-utility-objects&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#expression-utility-objects&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1651648842464&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Tutorial: Using Thymeleaf&quot; data-og-description=&quot;1 Introducing Thymeleaf 1.1 What is Thymeleaf? Thymeleaf is a modern server-side Java template engine for both web and standalone environments, capable of processing HTML, XML, JavaScript, CSS and even plain text. The main goal of Thymeleaf is to provide a&quot; data-og-host=&quot;www.thymeleaf.org&quot; data-og-source-url=&quot;https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#expression-utility-objects&quot; data-og-url=&quot;https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#expression-utility-objects&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/sbau6/hyOgruG6zM/4BC9J6MsQA3zugI4xlfT11/img.png?width=944&amp;amp;height=411&amp;amp;face=0_0_944_411,https://scrap.kakaocdn.net/dn/cFEj6T/hyOgs1rMJH/sFvxbTBcEdHiesHKEaMROK/img.png?width=576&amp;amp;height=530&amp;amp;face=0_0_576_530&quot;&gt;&lt;a href=&quot;https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#expression-utility-objects&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#expression-utility-objects&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/sbau6/hyOgruG6zM/4BC9J6MsQA3zugI4xlfT11/img.png?width=944&amp;amp;height=411&amp;amp;face=0_0_944_411,https://scrap.kakaocdn.net/dn/cFEj6T/hyOgs1rMJH/sFvxbTBcEdHiesHKEaMROK/img.png?width=576&amp;amp;height=530&amp;amp;face=0_0_576_530');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Tutorial: Using Thymeleaf&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;1 Introducing Thymeleaf 1.1 What is Thymeleaf? Thymeleaf is a modern server-side Java template engine for both web and standalone environments, capable of processing HTML, XML, JavaScript, CSS and even plain text. The main goal of Thymeleaf is to provide a&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.thymeleaf.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 곳에서 필요한 것들 찾아서 쓰자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;URL&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단순한 URL&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@{/hello} /hello&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;쿼리 파라미터 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@{/hello(param1=${param1}, param2=${param2})} /hello?param1=data1&amp;para;m2=data2 () 에 있는 부분은 쿼리 파라미터로 처리된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;경로 변수 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@{/hello/{param1}/{param2}(param1=${param1}, param2=${param2})} /hello/data1/data2 URL 경로상에 변수가 있으면 () 부분은 경로 변수로 처리된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 경로 변수 + 쿼리 파라미터 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@{/hello/{param1}(param1=${param1}, param2=${param2})} /hello/data1?param2=data2 경로 변수와 쿼리 파라미터를 함께 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*상대경로, 절대경로, 프로토콜 기준을 표현할 수 도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/hello : 절대 경로 hello : 상대 경로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;리터럴&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타임리프에서 문자 리터럴은 항상 ' (작은 따옴표)로 감싸야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1651650254849&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;span th:text=&quot;'hello'&quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; 그런데 문자를 항상 ' 로 감싸는 것은 너무 귀찮은 일이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; 공백 없이 쭉 이어진다면 하나의 의미있는 토큰으로 인지해서 다음과 같이 작은 따옴표를 생략할 수 있다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;룰: A-Z , a-z , 0-9 , [] , . , - , _&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1651650214800&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;span th:text=&quot;hello&quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;연산&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비교연산: HTML 엔티티를 사용해야 하는 부분을 주의하자, &amp;gt; (gt), &amp;lt; (lt), &amp;gt;= (ge), &amp;lt;= (le), ! (not), == (eq), != (neq, ne) 조건식: 자바의 조건식과 유사하다.&lt;/li&gt;
&lt;li&gt;Elvis 연산자: 조건식의 편의 버전&lt;/li&gt;
&lt;li&gt;No-Operation: _ 인 경우 마치 타임리프가 실행되지 않는 것 처럼 동작한다. 이것을 잘 사용하면 HTML 의 내용 그대로 활용할 수 있다. 마지막 예를 보면 데이터가 없습니다. 부분이 그대로 출력된다&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;속성&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;속성 설정 &lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;th:* 속성을 지정하면 타임리프는 기존 속성을 th:* 로 지정한 속성으로 대체한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 속성이 없다면 새로 만든다.&lt;/p&gt;
&lt;pre id=&quot;code_1651652075638&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;input type=&quot;text&quot; name=&quot;mock&quot; th:name=&quot;userA&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타임리프 렌더링 후&lt;/p&gt;
&lt;pre id=&quot;code_1651652089977&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;input type=&quot;text&quot; name=&quot;userA&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;속성 추가&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;th:attrappend : 속성 값의 뒤에 값을 추가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;th:attrprepend : 속성 값의 앞에 값을 추가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;th:classappend : class 속성에 자연스럽게 추가한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt; checked 처리&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML에서는&lt;/p&gt;
&lt;pre id=&quot;code_1651652108951&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;input type=&quot;checkbox&quot; name=&quot;active&quot; checked=&quot;false&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우에도 checked 속성이 있기 때문에 checked 처리가 되어버린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML에서 checked 속성은 checked 속성의 값과 상관없이 checked 라는 속성만 있어도 체크가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 부분이 true , false 값을 주로 사용하는 개발자 입장에서는 불편하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타임리프의 th:checked 는 값이 false 인 경우 checked 속성 자체를 제거한다.&lt;/p&gt;
&lt;pre id=&quot;code_1651652128464&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;input type=&quot;checkbox&quot; name=&quot;active&quot; th:checked=&quot;false&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타임리프 렌더링 후:&lt;/p&gt;
&lt;pre id=&quot;code_1651652140060&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;input type=&quot;checkbox&quot; name=&quot;active&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;반복&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;반복시 오른쪽 컬렉션( ${users} )의 값을 하나씩 꺼내서 왼쪽 변수( user )에 담아서 태그를 반복 실행합니다.&lt;/li&gt;
&lt;li&gt;th:each 는 List 뿐만 아니라 배열, java.util.Iterable , java.util.Enumeration 을 구현한 모든 객체를 반복에 사용할 수 있습니다. Map 도 사용할 수 있는데 이 경우 변수에 담기는 값은 Map.Entry 입니다&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;반복 상태 유지 &lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반복의 두번째 파라미터를 설정해서 반복의 상태를 확인 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두번째 파라미터는 생략 가능한데, 생략하면 지정한 변수명( user ) + Stat 가 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 user + Stat = userStat 이므로 생략 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;반복 상태 유지 기능&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;index : 0부터 시작하는 값&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;count : 1부터 시작하는 값&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;size : 전체 사이즈&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;even , odd : 홀수, 짝수 여부( boolean )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;first , last :처음, 마지막 여부( boolean )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;current : 현재 객체&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;조건부 연산&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;if, unless &lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타임리프는 해당 조건이 맞지 않으면 태그 자체를 렌더링하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 다음 조건이 false 인 경우&lt;/p&gt;
&lt;pre id=&quot;code_1651673612233&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;span&amp;gt;...&amp;lt;span&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;부분 자체가 렌더링 되지 않고 사라진다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1651673644720&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;span th:text=&quot;'미성년자'&quot; th:if=&quot;${user.age lt 20}&quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;switch &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;* 은 만족하는 조건이 없을 때 사용하는 디폴트이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;주석&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 표준 HTML 주석 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트의 표준 HTML 주석은 타임리프가 렌더링 하지 않고, 그대로 남겨둔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 2. 타임리프 파서 주석 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타임리프 파서 주석은 타임리프의 진짜 주석이다. 렌더링에서 주석 부분을 제거한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 3. 타임리프 프로토타입 주석 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타임리프 프로토타입은 약간 특이한데, HTML 주석에 약간의 구문을 더했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML 파일을 웹 브라우저에서 그대로 열어보면 HTML 주석이기 때문에 이 부분이 웹 브라우저가 렌더링하지 않는다. 타임리프 렌더링을 거치면 이 부분이 정상 렌더링 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 이야기해서 HTML 파일을 그대로 열어보면 주석처리가 되지만, 타임리프를 렌더링 한 경우에만 보이는 기능이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;th:block 기능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 기능은 속성을 여러개를 th:each 로 반복을 하고 싶을때 사용한다. 렌더링시 block안에 있는 속성들을 반복횟수만큼 늘어나게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;자바 스크립트 인라인&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;텍스트 렌더링&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;var username = [[${user.username}]];&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인라인 사용 전 var username = userA;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인라인 사용 후 var username = &quot;userA&quot;;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인라인 사용 전 렌더링 결과를 보면 userA 라는 변수 이름이 그대로 남아있다. 타임리프 입장에서는 정확하게 렌더링 한 것이지만 아마 개발자가 기대한 것은 다음과 같은 &quot;userA&quot;라는 문자일 것이다. 결과적으로 userA가 변수명으로 사용되어서 자바스크립트 오류가 발생한다. 다음으로 나오는 숫자 age의 경우에는 &quot; 가 필요 없기 때문에 정상 렌더링 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인라인 사용 후 렌더링 결과를 보면 문자 타입인 경우 &quot; 를 포함해준다. 추가로 자바스크립트에서 문제가 될 수 있는 문자가 포함되어 있으면 이스케이프 처리도 해준다. 예) &quot; \&quot;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;자바스크립트 내추럴 템플릿 &lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타임리프는 HTML 파일을 직접 열어도 동작하는 내추럴 템플릿 기능을 제공한다. 자바스크립트 인라인 기능을 사용하면 주석을 활용해서 이 기능을 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;var username2 = /*[[${user.username}]]*/ &quot;test username&quot;;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인라인 사용 전 var username2 = /*userA*/ &quot;test username&quot;;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인라인 사용 후 var username2 = &quot;userA&quot;;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인라인 사용 전 결과를 보면 정말 순수하게 그대로 해석을 해버렸다. 따라서 내추럴 템플릿 기능이 동작하지 않고, 심지어 렌더링 내용이 주석처리 되어 버린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인라인 사용 후 결과를 보면 주석 부분이 제거되고, 기대한 &quot;userA&quot;가 정확하게 적용된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;객체 &lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타임리프의 자바스크립트 인라인 기능을 사용하면 객체를 JSON으로 자동으로 변환해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;var user = [[${user}]];&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인라인 사용 전 var user = BasicController.User(username=userA, age=10);&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인라인 사용 후 var user = {&quot;username&quot;:&quot;userA&quot;,&quot;age&quot;:10};&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인라인 사용 전은 객체의 toString()이 호출된 값이다. 인라인 사용 후는 객체를 JSON으로 변환해준다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;템플릿 조각&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 페이지를 개발할 때는 공통 영역이 많이 있다. 예를 들어서 상단 영역이나 하단 영역, 좌측 카테고리 등등 여러 페이지에서 함께 사용하는 영역들이 있다. 이런 부분을 코드를 복사해서 사용한다면 변경시 여러 페이지를 다 수정해야 하므로 상당히 비효율 적이다. 타임리프는 이런 문제를 해결하기 위해 템플릿 조각과 레이아웃 기능을 지원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;부분포함 insert&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1651676069058&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div th:insert=&quot;~{template/fragment/footer :: copy}&quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;template/fragment/footer.html 템플릿에 있는 th:fragment=&quot;copy&quot; 라는 부분을 템플릿 조각으로 가져와서 사용한다는 의미이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;th:insert 를 사용하면 현재 태그( div ) 내부에 추가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;부분포함 replace&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1651676126751&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div th:replace=&quot;~{template/fragment/footer :: copy}&quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;th:replace 를 사용하면 현재 태그( div )를 대체한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;파라미터 사용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 파라미터를 전달해서 동적으로 조각을 렌더링 할 수도 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1651676172214&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div th:replace=&quot;~{template/fragment/footer :: copyParam ('데이터1', '데이터2')}&quot;&amp;gt;&amp;lt;/
div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;템플릿 레이아웃&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&amp;lt;head&amp;gt;에 공통으로 사용하는 css , javascript 같은 정보들이 있는데, 이러한 공통 정보들을 한 곳에 모아두고, 공통으로 사용하지만, 각 페이지마다 필요한 정보를 더 추가해서 사용하고 싶다면 다음과 같이 사용하면 된다&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1651676675541&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;head th:replace=&quot;template/layout/base :: common_header(~{::title},~{::link})&quot;&amp;gt;
 &amp;lt;title&amp;gt;메인 타이틀&amp;lt;/title&amp;gt;
 &amp;lt;link rel=&quot;stylesheet&quot; th:href=&quot;@{/css/bootstrap.min.css}&quot;&amp;gt;
 &amp;lt;link rel=&quot;stylesheet&quot; th:href=&quot;@{/themes/smoothness/jquery-ui.css}&quot;&amp;gt;
&amp;lt;/head&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;common_header(~{::title},~{::link})&lt;/span&gt; 이 부분이 핵심이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;::title 은 현재 페이지의 title 태그들을 전달한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;::link 는 현재 페이지의 link 태그들을 전달한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메인 타이틀이 전달한 부분으로 교체되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공통 부분은 그대로 유지되고, 추가 부분에 전달한 들이 포함된 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;lt;html&amp;gt; 에 th:fragment 속성이 정의되어 있다. 이 레이아웃 파일을 기본으로 하고 여기에 필요한 내용을 전달해서 부분부분 변경하는 것으로 이해하면 된다.&lt;/p&gt;</description>
      <category>백 엔드/spring</category>
      <category>Spring</category>
      <category>Thymeleaf</category>
      <category>스프링</category>
      <category>타임리프</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/108</guid>
      <comments>https://aimk12.tistory.com/108#entry108comment</comments>
      <pubDate>Thu, 5 May 2022 00:13:11 +0900</pubDate>
    </item>
    <item>
      <title>백준 13305번: 주유소</title>
      <link>https://aimk12.tistory.com/107</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/13305&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/13305&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1650880822471&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;13305번: 주유소&quot; data-og-description=&quot;표준 입력으로 다음 정보가 주어진다. 첫 번째 줄에는 도시의 개수를 나타내는 정수 N(2 &amp;le; N &amp;le; 100,000)이 주어진다. 다음 줄에는 인접한 두 도시를 연결하는 도로의 길이가 제일 왼쪽 도로부터 N-1&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/13305&quot; data-og-url=&quot;https://www.acmicpc.net/problem/13305&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/13305&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/13305&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;13305번: 주유소&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;표준 입력으로 다음 정보가 주어진다. 첫 번째 줄에는 도시의 개수를 나타내는 정수 N(2 &amp;le; N &amp;le; 100,000)이 주어진다. 다음 줄에는 인접한 두 도시를 연결하는 도로의 길이가 제일 왼쪽 도로부터 N-1&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 그리드 알고리즘 문제이다. 나는 재귀를 이용해서 풀었다. 풀이는 가격이 낮은 주유소를 들르면서 가는 것이 최선이기 떄문에 가격낮은 주유소 까지만 갈 수 있을만큼만 기름을 사고 목적지까지 간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 보자&lt;/p&gt;
&lt;pre id=&quot;code_1650880903988&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
using namespace std;
vector&amp;lt;long long&amp;gt; city;
vector&amp;lt;long long&amp;gt; len;
long long n, sum;
int check;
void add(int a, int n) {
    
    long long lensum = 0;
    for (int i = a + 1; i &amp;lt; n; i++) {
        if (city[a] &amp;gt; city[i]) {          //값이 작은 게 나오면 거기까지 가격 구하기
            lensum += len[i - 1];
            sum += (lensum * city[a]);
            add(i, n);                    //그리고 재귀
            return;
        }
        lensum += len[i - 1];
    }
    sum+= (lensum * city[a]);                  //작은게 없을경우 
    return;

}
int main() {
    cin &amp;gt;&amp;gt; n;
    for (int i = 0; i &amp;lt; n - 1; i++) {
        long long temp;
        cin &amp;gt;&amp;gt; temp;
        len.push_back(temp);
    }
    for (int i = 0; i &amp;lt; n; i++) {
        long long temp;
        cin &amp;gt;&amp;gt; temp;
        city.push_back(temp);
    }
    add(0, n);
    cout &amp;lt;&amp;lt; sum;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>백준 코딩</category>
      <category>13305</category>
      <category>그리드</category>
      <category>그리디</category>
      <category>백준</category>
      <author>까르르꿍꿍</author>
      <guid isPermaLink="true">https://aimk12.tistory.com/107</guid>
      <comments>https://aimk12.tistory.com/107#entry107comment</comments>
      <pubDate>Mon, 25 Apr 2022 19:02:12 +0900</pubDate>
    </item>
  </channel>
</rss>