<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>다락방</title>
    <link>https://hojunking.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Fri, 17 Apr 2026 03:43:33 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>호준송</managingEditor>
    <image>
      <title>다락방</title>
      <url>https://tistory1.daumcdn.net/tistory/6056696/attach/69fc38b9bd0649239b3cf9a1adff7d6a</url>
      <link>https://hojunking.tistory.com</link>
    </image>
    <item>
      <title>Ncloud 크레딧 사용 후기</title>
      <link>https://hojunking.tistory.com/129</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멋쟁이사자처럼 3기 백엔드 스쿨을 수강하면서, 웹 배포 분야도 배우게 되었다. 이와 관련해서 Naver Cloud Platform 에서 예비/주니어 개발자를 위해 크레딧을 지급하는 서비스에 대해 소개받았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소개받기 전에는 AWS 에 대해서만 알고 있었는데, AWS 프리티어를 사용 하고 요금 폭탄을 맞았다는 말을 많이 들어 조심스러웠다. 네이버 클라우드 플랫폼의 크레딧 덕분에 요금 폭탄 걱정 없이 배포를 진행했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;신규 가입 10만원 크레딧을 제공했고, 이후 20만원의 크레딧이 제공되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;20만원의 크레딧은 아마 멋쟁이사자처럼 측과 연계하여 지급되는 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 70만 크레딧을 추가로 제공한다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;사용 내용&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멋사 수업기간 중 4주 프로젝트를 2회 진행했는데, 두 프로젝트 모두 내가 배포를 맡게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요금 부담 없이 네이버 클라우드 플랫폼을 통해 배포를 진행했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;프로젝트1 - CodiCaster&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 프로젝트는 날씨에 맞춘 코디 추천 플랫폼인 &amp;ldquo;코디캐스터&amp;rdquo;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4인 팀 프로젝트로, 프로젝트에 대한 상세 내용은 아래 링크를 참고하길 바란다.&lt;/p&gt;
&lt;figure id=&quot;og_1690441194251&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 - CodiCaster/CodiCaster:  ️ 코디 캐스터 (Codi Caster)&quot; data-og-description=&quot; ️ 코디 캐스터 (Codi Caster). Contribute to CodiCaster/CodiCaster development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/CodiCaster/CodiCaster&quot; data-og-url=&quot;https://github.com/CodiCaster/CodiCaster&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/gDf6Z/hyTrOR5ZZb/48BIksDykuNCKFv6Eo3Bj0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/CodiCaster/CodiCaster&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/CodiCaster/CodiCaster&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/gDf6Z/hyTrOR5ZZb/48BIksDykuNCKFv6Eo3Bj0/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 - CodiCaster/CodiCaster:  ️ 코디 캐스터 (Codi Caster)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt; ️ 코디 캐스터 (Codi Caster). Contribute to CodiCaster/CodiCaster 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;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Server&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;팀원 모두 처음 진행하는 협업 프로젝트였기에, 완성도가 조금 부족했다.&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~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;&amp;ldquo;코디캐스터&amp;rdquo;는 이미지가 핵심 요소인데, Naver Cloud Platform에 서버 외 또다른 기능들을 사용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Object Storage&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, 이미지 저장소인 Object Storage를 사용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지 파일을 서버 로컬에 저장하지 않고, 따로 이미지 저장소를 두어 관리했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Amazon S3 와 비슷한 형태인데, Amazon S3 관련 라이브러리가 기본적으로 제공되고 있고, Naver Object Storage는 이 라이브러리를 활용할 수 있게 구성되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, S3 라이브러리를 활용하여 Object Storage에 이미지를 저장할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;CDN+&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 Naver CDN+ 를 이용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CDN은 이미지, 동영상 등 다양한 데이터에 대해 일종의 캐시역할을 하는 프록시 서버로 알고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어려운 작업이라고 생각했는데, 네이버에서 제공하는 CDN+를 사용할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;사실, CDN+ 를 사용하지 않은 채로 Object Storage만 사용하는 것이 가능한 지 확실하지 않다.&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CDN endPoint를 설정하고 이를 이용해서 이미지를 서버에 가져와 웹 페이지에 띄워줄 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용 방법 역시 네이버에서 제공하는 가이드라인을 따르면 간단했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Image Optimizer&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지 파일의 크기를 조정하는 방법에 대해 찾아봤었는데, Naver Image Optimizer를 통해 해당 기능을 구현할 수 있었다.&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;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;프로젝트2 - MyPill&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째 프로젝트는 영양제 이커머스 플랫폼인 &amp;ldquo;MyPill&amp;rdquo;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3인 프로젝트로, 자세한 내용은 마찬가지로 링크를 참고하길 바란다.&lt;/p&gt;
&lt;figure id=&quot;og_1690441204062&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 - MyPill2023/MyPill:   영양제 추천 이커머스 플랫폼&quot; data-og-description=&quot;  영양제 추천 이커머스 플랫폼. Contribute to MyPill2023/MyPill development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/MyPill2023/MyPill&quot; data-og-url=&quot;https://github.com/MyPill2023/MyPill&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b7Tlhy/hyTrTFR0ou/Wy1InPGGHpTkDLvNU2Cb50/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/MyPill2023/MyPill&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/MyPill2023/MyPill&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b7Tlhy/hyTrTFR0ou/Wy1InPGGHpTkDLvNU2Cb50/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 - MyPill2023/MyPill:   영양제 추천 이커머스 플랫폼&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;  영양제 추천 이커머스 플랫폼. Contribute to MyPill2023/MyPill 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;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Server&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;이전 프로젝트보다 오랜기간 서버를 운영했고, 현재까지 여전히 운영하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전보다 익숙해져 서버의 성능에 대해 찾아봤었는데, 추후 개선작업으로 보류하고 기본 설정을 이용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Object Storage, CDN+&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 프로젝트 역시 이미지를 사용하였는데, Object Storage 와 CDN+ 를 이용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 다른 팀원분이 이미지 처리 작업을 맡아 진행했고, Object Storage와 CDN+까지 맡아주셨다.&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;1차 프로젝트와 비슷한 작업을 진행했기에, 서비스에 대한 소개는 넘어가도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&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;가이드라인이 잘 나와있기도 하고, 서비스의 UI가 이해하기 쉽게 잘 되어있었다.&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;아무래도 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;크레딧도 제공되니, 부담 없이 이용할 수 있을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차로 진행한 &amp;ldquo;MyPill&amp;rdquo;은 지속적으로 개선작업을 진행하고 있고, 서버 역시 계속 운영하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로, 개인 프로젝트를 진행하려고 하는데 이 역시 NCP를 이용하려고 한다.&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로젝트/팀 프로젝트 - MyPill</category>
      <category>ncp</category>
      <category>네이버 클라우드 플랫폼</category>
      <author>호준송</author>
      <guid isPermaLink="true">https://hojunking.tistory.com/129</guid>
      <comments>https://hojunking.tistory.com/129#entry129comment</comments>
      <pubDate>Thu, 27 Jul 2023 16:02:37 +0900</pubDate>
    </item>
    <item>
      <title>[트러블 슈팅] - MultipartFile 테스트 케이스</title>
      <link>https://hojunking.tistory.com/128</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;배경&lt;/h2&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;이전에 언급한 MultipartFile 처리와 연결되는 이슈다.&lt;/p&gt;
&lt;figure id=&quot;og_1690220745407&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;[트러블 슈팅] - MultipartFile 예외 처리&quot; data-og-description=&quot;배경 프로젝트에서 게시글 작성 시 이미지를 첨부하는 기능을 추가했다. 이미지는 MultipartFile의 형태로, 프론트로부터 받아왔다. 기존 게시글 작성 메서드에 매개변수로 MultipartFile을 추가했고, &quot; data-og-host=&quot;hojunking.tistory.com&quot; data-og-source-url=&quot;https://hojunking.tistory.com/126&quot; data-og-url=&quot;https://hojunking.tistory.com/126&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/iH5LW/hyTo7SXltY/yLgPKUtPOQyrIWvxVxEAbk/img.png?width=765&amp;amp;height=267&amp;amp;face=0_0_765_267,https://scrap.kakaocdn.net/dn/hgpGR/hyTqxCtf6z/7ZcNTYVpsGXF6AYYbjxoy0/img.png?width=765&amp;amp;height=267&amp;amp;face=0_0_765_267,https://scrap.kakaocdn.net/dn/cBitBk/hyTqpRX7mx/JK6T0MR9xBe7On4wOX0k2k/img.png?width=750&amp;amp;height=261&amp;amp;face=0_0_750_261&quot;&gt;&lt;a href=&quot;https://hojunking.tistory.com/126&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hojunking.tistory.com/126&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/iH5LW/hyTo7SXltY/yLgPKUtPOQyrIWvxVxEAbk/img.png?width=765&amp;amp;height=267&amp;amp;face=0_0_765_267,https://scrap.kakaocdn.net/dn/hgpGR/hyTqxCtf6z/7ZcNTYVpsGXF6AYYbjxoy0/img.png?width=765&amp;amp;height=267&amp;amp;face=0_0_765_267,https://scrap.kakaocdn.net/dn/cBitBk/hyTqpRX7mx/JK6T0MR9xBe7On4wOX0k2k/img.png?width=750&amp;amp;height=261&amp;amp;face=0_0_750_261');&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;[트러블 슈팅] - MultipartFile 예외 처리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;배경 프로젝트에서 게시글 작성 시 이미지를 첨부하는 기능을 추가했다. 이미지는 MultipartFile의 형태로, 프론트로부터 받아왔다. 기존 게시글 작성 메서드에 매개변수로 MultipartFile을 추가했고,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hojunking.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지 첨부 기능을 추가하면서, 게시물을 작성하는 create 메소드에 MultipartFile을 매개변수로 추가되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;create 메소드에 대한 기존 테스트 케이스는 이미지 첨부 기능 이전에 작성하였기에 수정이 필요했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제 상황&lt;/h2&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;이전에 작성한 글에 나오는 이슈와 마찬가지로 null 값을 매개변수로 전달하는 방식을 시도했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, 게시물 작성 메소드 create는 multipartFile.isEmpty()를 통해 경우를 구분하고 있었다.&lt;/p&gt;
&lt;pre id=&quot;code_1690220518055&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Transactional
public RsData&amp;lt;Post&amp;gt; create(PostRequest postRequest, Member member, MultipartFile multipartFile) {
    if (member == null) {
        return RsData.of(&quot;F-1&quot;, &quot;존재하지 않는 회원입니다.&quot;);
    }
    Post post = new Post(postRequest, member.getId(), new ArrayList&amp;lt;&amp;gt;());
    if (!multipartFile.isEmpty()) {
        AmazonS3Dto amazonS3ImageDto = imageService.saveImageOnServer(multipartFile, post);
        Image image = new Image(amazonS3ImageDto, multipartFile, post);
        post.addImage(image);
    }
    postRepository.save(post);
    return RsData.of(&quot;S-1&quot;, &quot;질문 등록이 완료되었습니다.&quot;, post);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 null.isEmpty() 를 시도한 형태가 되었고, 당연하게도 NullPointException이 발생했다.&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;이를 해결하기 위해 null 이 아니면서, isEmpty() = true를 반환하는 MultipartFile 을 만들어야 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;해결&lt;/h2&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;검색을 통해 MockMultipartFile을 활용하는 방법을 찾았다.&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;단기간에 해결을 해야했고, 해결 방법이 바로 떠오르지 않아서 MockMultipartFile 을 사용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기존 코드&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Test
@DisplayName(&quot;게시글 작성 테스트(구매자 회원)&quot;)
void createTest() {
    // WHEN
    Post post = postService.create(postRequest, buyer, null).getData();

    // THEN
    assertTrue(postRepository.findById(post.getId()).isPresent());
    assertThat(postRepository.findById(post.getId()).get().getPosterId()).isEqualTo(buyer.getId());
    assertThat(postRepository.findById(post.getId()).get().getTitle()).isEqualTo(postRequest.getTitle());
    assertThat(postRepository.findById(post.getId()).get().getContent()).isEqualTo(postRequest.getContent());
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;수정 후 코드&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Test
@DisplayName(&quot;게시글 작성 테스트(구매자 회원)&quot;)
void createTest() {
    // GIVEN
    MockMultipartFile emptyFile = new MockMultipartFile(&quot;imageFile&quot;, new byte[0]);

    // WHEN
    Post post = postService.create(postRequest, buyer, emptyFile).getData();

    // THEN
    assertTrue(postRepository.findById(post.getId()).isPresent());
    assertThat(postRepository.findById(post.getId()).get().getPosterId()).isEqualTo(buyer.getId());
    assertThat(postRepository.findById(post.getId()).get().getTitle()).isEqualTo(postRequest.getTitle());
    assertThat(postRepository.findById(post.getId()).get().getContent()).isEqualTo(postRequest.getContent());
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알아본 바로는, 테스트를 위한 가짜 이미지 객체(MockMultipartFile)를 만들어 사용하는 방식이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체를 생성할 때, isEmpty() = true 를 반환하도록 적절한 값을 매개변수에 넣었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 이미지를 첨부하지 않은 상황에 대한 테스트가 가능해졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로젝트/팀 프로젝트 - MyPill</category>
      <category>MockMultipartFile</category>
      <category>MultipartFile</category>
      <category>트러블 슈팅</category>
      <author>호준송</author>
      <guid isPermaLink="true">https://hojunking.tistory.com/128</guid>
      <comments>https://hojunking.tistory.com/128#entry128comment</comments>
      <pubDate>Tue, 25 Jul 2023 02:45:51 +0900</pubDate>
    </item>
    <item>
      <title>[리팩토링] @NotNull vs @Column(nullable = false)</title>
      <link>https://hojunking.tistory.com/127</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;배경&lt;/b&gt;&lt;/h2&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;프로젝트 MyPill은 도메인을 나누었고, 독립적으로 개발을 진행했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 리팩토링 과정에서 살펴보니 &lt;b&gt;@NotNull&lt;/b&gt; 과 &lt;b&gt;@Column(nullable = false)&lt;/b&gt; 를 혼용해서 사용하고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필드에 &lt;b&gt;Null 값이 들어올 수 없다&lt;/b&gt;는 공통적인 목적을 가진 것인데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;통일시키기 이전에 두 방식의 차이가 궁금해 찾아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;공통 환경&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;엔티티&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Entity
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Table(name = &quot;categories&quot;)
public class Category {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = &quot;category_id&quot;)
    private Long id;

    //이 컬럼에 not null 조건을 추가한다.
    @Column(name = &quot;name&quot;)
    private String name;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실제 프로젝트에 쓰인 Category 엔티티(Categories 테이블)를 생성한 후 not null을 가지는 두 방식을 비교했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;DB 저장 메소드&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public void nullTest() {
        categoryRepository.save(new Category());
    }&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;name = null 인 객체를 저장하는 메소드를 실행해 디버깅하며 로그를 살펴봤다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size14&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;로컬 dev 환경으로, ddl-auto : create 인 상황이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;@NotNull&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@NotNull
@Column(name = &quot;name&quot;)
private String name;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;name 컬럼에 &lt;b&gt;@NotNull&lt;/b&gt;을 추가한 경우이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;프로젝트 실행 시 스키마 생성&lt;br /&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;111.png&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;153&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tOiXx/btsoDJNgjZE/sinrdLSa2wB3yKYHv8tuu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tOiXx/btsoDJNgjZE/sinrdLSa2wB3yKYHv8tuu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tOiXx/btsoDJNgjZE/sinrdLSa2wB3yKYHv8tuu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtOiXx%2FbtsoDJNgjZE%2FsinrdLSa2wB3yKYHv8tuu1%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;700&quot; height=&quot;255&quot; data-filename=&quot;111.png&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;153&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;DDL에 의해 name 컬럼에 &lt;b&gt;not null 제약조건이 설정&lt;/b&gt;된 것을 확인할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;null 값 저장 메서드 실행 시&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;112.png&quot; data-origin-width=&quot;1245&quot; data-origin-height=&quot;286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLZPXc/btsoEp8Z1vX/aU1I3muNkn4WlSy8KKh2v0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLZPXc/btsoEp8Z1vX/aU1I3muNkn4WlSy8KKh2v0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLZPXc/btsoEp8Z1vX/aU1I3muNkn4WlSy8KKh2v0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLZPXc%2FbtsoEp8Z1vX%2FaU1I3muNkn4WlSy8KKh2v0%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;700&quot; height=&quot;161&quot; data-filename=&quot;112.png&quot; data-origin-width=&quot;1245&quot; data-origin-height=&quot;286&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;&lt;b&gt;jakarta.validation.ConstraintViolationException이 발생&lt;/b&gt;한 것을 확인할 수 있다.&lt;/li&gt;
&lt;li&gt;save 메소드에 해당하는 &lt;b&gt;insert 쿼리가 실행되지 않았다&lt;/b&gt;는 것을 확인할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;@Column(nullable = false)&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Column(name = &quot;name&quot;, nullable = false)
private String name;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;name 컬럼에 &lt;b&gt;nullable = false&lt;/b&gt;를 추가한 경우이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size14&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;222.png&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;153&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmf9Lg/btsoxwhwZ88/HY65aNu6KppgLiBpsELT1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmf9Lg/btsoxwhwZ88/HY65aNu6KppgLiBpsELT1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmf9Lg/btsoxwhwZ88/HY65aNu6KppgLiBpsELT1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbmf9Lg%2FbtsoxwhwZ88%2FHY65aNu6KppgLiBpsELT1K%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;700&quot; height=&quot;255&quot; data-filename=&quot;222.png&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;153&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;&lt;b&gt;@NotNull과 동일&lt;/b&gt;하게 name 컬럼에 &lt;b&gt;not null 제약조건&lt;/b&gt;이 설정된 것을 확인할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;null 값 저장 메서드 실행 시&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;223.png&quot; data-origin-width=&quot;1236&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0PjxO/btsoEq08PDu/DQNRUF8eCutNHU7AUjJFG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0PjxO/btsoEq08PDu/DQNRUF8eCutNHU7AUjJFG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0PjxO/btsoEq08PDu/DQNRUF8eCutNHU7AUjJFG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0PjxO%2FbtsoEq08PDu%2FDQNRUF8eCutNHU7AUjJFG1%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;700&quot; height=&quot;199&quot; data-filename=&quot;223.png&quot; data-origin-width=&quot;1236&quot; data-origin-height=&quot;352&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;&lt;b&gt;@NotNull 과 달리&lt;/b&gt;, &lt;b&gt;insert 문이 실행&lt;/b&gt;되었다.&lt;/li&gt;
&lt;li&gt;이후 &lt;b&gt;SQLIntegrityConstraintViolationException&lt;/b&gt; &lt;b&gt;이 발생&lt;/b&gt;한 것을 확인할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;정리&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;865&quot; data-origin-height=&quot;152&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n7iHy/btsoyoDkxQm/IQDqhqKRXVxr5SVJnqU4RK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n7iHy/btsoyoDkxQm/IQDqhqKRXVxr5SVJnqU4RK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n7iHy/btsoyoDkxQm/IQDqhqKRXVxr5SVJnqU4RK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn7iHy%2FbtsoyoDkxQm%2FIQDqhqKRXVxr5SVJnqU4RK%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;700&quot; height=&quot;123&quot; data-origin-width=&quot;865&quot; data-origin-height=&quot;152&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;두 방식 모두 null 값에 대해 오류를 발생시킨다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;@NotNull이 더 추천&lt;/b&gt;된다고 한다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;더 앞선 단계에서 예외를 검출하기 때문에 안전하다고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&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;a href=&quot;https://www.baeldung.com/hibernate-notnull-vs-nullable&quot;&gt;Hibernate @NotNull vs @Column(nullable = false) | Baeldung&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hyeon9mak.github.io/not-null-vs-column-nullable-false/&quot;&gt;@NotNull vs @Column(nullable = false)&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로젝트/팀 프로젝트 - MyPill</category>
      <category>Column(nullable = false)</category>
      <category>notnull</category>
      <category>트러블 슈팅</category>
      <author>호준송</author>
      <guid isPermaLink="true">https://hojunking.tistory.com/127</guid>
      <comments>https://hojunking.tistory.com/127#entry127comment</comments>
      <pubDate>Sat, 22 Jul 2023 18:11:15 +0900</pubDate>
    </item>
    <item>
      <title>[트러블 슈팅] - MultipartFile 예외 처리</title>
      <link>https://hojunking.tistory.com/126</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;배경&lt;/h2&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지는 MultipartFile의 형태로, 프론트로부터 받아왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;기존 게시글 작성 메서드에 매개변수로 MultipartFile을 추가했고, &lt;/span&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;p data-ke-size=&quot;size16&quot;&gt;그러나, 코드가 원하는 방식으로 작동하지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제 상황&lt;/h2&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;이미지를 처리하지 않았을 때 MultipartFile 이 null 값을 반환할 것이라고 예상했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 예외 처리를 위해 다음과 같은 코드를 추가하였다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;if(multipartFile != null){
	//이미지 처리 작업
}&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;디버깅을 해보니, multipartFile은 null이 아니었다.&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;a1.png&quot; data-origin-width=&quot;765&quot; data-origin-height=&quot;267&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PqDCc/btsopXSxZhw/KZQgqzKUmTYp6QVAMTmjD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PqDCc/btsopXSxZhw/KZQgqzKUmTYp6QVAMTmjD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PqDCc/btsopXSxZhw/KZQgqzKUmTYp6QVAMTmjD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPqDCc%2FbtsopXSxZhw%2FKZQgqzKUmTYp6QVAMTmjD0%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;700&quot; height=&quot;244&quot; data-filename=&quot;a1.png&quot; data-origin-width=&quot;765&quot; data-origin-height=&quot;267&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;예외 상황을 null 값이 아닌 다른 기준으로 처리해야 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;해결&lt;/h2&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;기본적으로 제공하는 MultipartFile 인터페이스에 들어가서 살펴봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;getName(), getSize()등 다양한 메서드가 존재했는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 boolean 값으로 선언된 isEmpty()를 사용하기로 했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;a2.png&quot; data-origin-width=&quot;617&quot; data-origin-height=&quot;83&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsVyjr/btsonSrqaT7/0hwmzSpvueHe7HKSjzjyTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsVyjr/btsonSrqaT7/0hwmzSpvueHe7HKSjzjyTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsVyjr/btsonSrqaT7/0hwmzSpvueHe7HKSjzjyTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsVyjr%2FbtsonSrqaT7%2F0hwmzSpvueHe7HKSjzjyTk%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;700&quot; height=&quot;94&quot; data-filename=&quot;a2.png&quot; data-origin-width=&quot;617&quot; data-origin-height=&quot;83&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MultipartFile의 content가 없거나 파일이 비어있을 경우 0을 반환한다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;null값을 비교하는 대신에 isEmpty()를 사용하여 해결했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기존 코드&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Transactional
    public RsData&amp;lt;Post&amp;gt; create(PostRequest postRequest, Member member, MultipartFile multipartFile) {
        if (member == null) {
            return RsData.of(&quot;F-1&quot;, &quot;존재하지 않는 회원입니다.&quot;);
        }
        Post post = new Post(postRequest, member.getId(), new ArrayList&amp;lt;&amp;gt;());
        if (multipartFile != null) {
            AmazonS3Dto amazonS3ImageDto = imageService.saveImageOnServer(multipartFile, post);
            Image image = new Image(amazonS3ImageDto, multipartFile, post);
            post.addImage(image);
        }
        postRepository.save(post);
        return RsData.of(&quot;S-1&quot;, &quot;질문 등록이 완료되었습니다.&quot;, post);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;수정 후 코드&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Transactional
    public RsData&amp;lt;Post&amp;gt; create(PostRequest postRequest, Member member, MultipartFile multipartFile) {
        if (member == null) {
            return RsData.of(&quot;F-1&quot;, &quot;존재하지 않는 회원입니다.&quot;);
        }
        Post post = new Post(postRequest, member.getId(), new ArrayList&amp;lt;&amp;gt;());
        if (!multipartFile.isEmpty()) {
            AmazonS3Dto amazonS3ImageDto = imageService.saveImageOnServer(multipartFile, post);
            Image image = new Image(amazonS3ImageDto, multipartFile, post);
            post.addImage(image);
        }
        postRepository.save(post);
        return RsData.of(&quot;S-1&quot;, &quot;질문 등록이 완료되었습니다.&quot;, post);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로젝트/팀 프로젝트 - MyPill</category>
      <category>MultipartFile</category>
      <category>트러블 슈팅</category>
      <author>호준송</author>
      <guid isPermaLink="true">https://hojunking.tistory.com/126</guid>
      <comments>https://hojunking.tistory.com/126#entry126comment</comments>
      <pubDate>Thu, 20 Jul 2023 19:57:11 +0900</pubDate>
    </item>
    <item>
      <title>[개선 작업] @Value &amp;rarr; @ConfigurationProperties</title>
      <link>https://hojunking.tistory.com/125</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;배경&lt;/b&gt;&lt;/h2&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Untitled.png&quot; data-origin-width=&quot;685&quot; data-origin-height=&quot;49&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJSLIq/btsoezsAzbI/KFHVPd4sJ3eBIbzHk0dLaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJSLIq/btsoezsAzbI/KFHVPd4sJ3eBIbzHk0dLaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJSLIq/btsoezsAzbI/KFHVPd4sJ3eBIbzHk0dLaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJSLIq%2FbtsoezsAzbI%2FKFHVPd4sJ3eBIbzHk0dLaK%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;685&quot; height=&quot;49&quot; data-filename=&quot;Untitled.png&quot; data-origin-width=&quot;685&quot; data-origin-height=&quot;49&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;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;1. 테스트가 실패했다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;2. &lt;b&gt;@Value&lt;/b&gt; 대신 &lt;b&gt;@ConfigurationProperties&lt;/b&gt; 사용을 고려해 봐라&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로, 시크릿 키를 담은 &lt;b&gt;&amp;ldquo;Application-secret.yml&amp;rdquo;&lt;/b&gt;이 없을 때 테스트가 실패했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 실패 원인은 &lt;b&gt;@Value&lt;/b&gt; 때문이 아니었고, 간단하게 해결했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, &lt;b&gt;@ConfigurationProperties&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;추가 학습&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;@Value&amp;nbsp; VS&amp;nbsp; @ConfigurationProperties&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;1408&quot; data-origin-height=&quot;290&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgHjZG/btsoeJPCpCU/AAHCDWsHpzZx5PS62KIyE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgHjZG/btsoeJPCpCU/AAHCDWsHpzZx5PS62KIyE1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgHjZG/btsoeJPCpCU/AAHCDWsHpzZx5PS62KIyE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgHjZG%2FbtsoeJPCpCU%2FAAHCDWsHpzZx5PS62KIyE1%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;700&quot; height=&quot;144&quot; data-origin-width=&quot;1408&quot; data-origin-height=&quot;290&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Relaxed Binding&lt;/b&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;b&gt;@Value&lt;/b&gt;는 정확히 일치하게 적어야 해당 값을 매칭할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;@Configuration&lt;/b&gt;은 정확히 일치하지 않아도 특정 규칙을 통해 해당 값을 매칭한다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1689789536054&quot; class=&quot;php&quot; data-ke-language=&quot;php&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;api:
	business-register-number: 'SECRET KEY'&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 .yml 코드에 대해 다음 4가지 규칙이 허용된다.&lt;br /&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;api.business-register-number&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;text-align: left;&quot;&gt;properties, yml 권장 표기법&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;api.businessRegisterNumbe&lt;/td&gt;
&lt;td&gt;표준 카멜 케이스 문법&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;api.business_register_number&lt;/td&gt;
&lt;td&gt;properties, yml 에서 사용 가능한 표기법&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API_BUSINESS_REGISTER_NUMBER&lt;/td&gt;
&lt;td&gt;시스템 환경 변수일 경우 권장 표기법&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;SpEL&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SpEL은 꽤 복잡하고 다양하다.&lt;/li&gt;
&lt;li&gt;주제와 관련이 거의 없기에 링크로 남긴다.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1690221463722&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;SpEL(Spring Expression Language)에 대해서 간단하게 아라보자!&quot; data-og-description=&quot;객체 그래프를 조회하고 조작하는 기능을 제공Unified El과 비슷하지만, 메소드 호출을 지원하며 ,문자열 템플릿 기능도 제공OGNL, MVEL, JBOss EL 등 자바에서 사용할 수 있는 여러 EL이 있지만 SpEL은 모&quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@probsno/SpELSpring-Expression-Language%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C-%EA%B0%84%EB%8B%A8%ED%95%98%EA%B2%8C-%EC%95%84%EB%9D%BC%EB%B3%B4%EC%9E%90&quot; data-og-url=&quot;https://velog.io/@probsno/SpELSpring-Expression-Language에-대해서-간단하게-아라보자&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/blYonN/hyTpbA3pRj/7sr7OZV1JSbP6cj2En175k/img.png?width=950&amp;amp;height=500&amp;amp;face=0_0_950_500,https://scrap.kakaocdn.net/dn/bGmWay/hyTpavmDGP/7OpzHPb08EqySOuQtDz6dk/img.jpg?width=319&amp;amp;height=430&amp;amp;face=0_0_319_430&quot;&gt;&lt;a href=&quot;https://velog.io/@probsno/SpELSpring-Expression-Language%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C-%EA%B0%84%EB%8B%A8%ED%95%98%EA%B2%8C-%EC%95%84%EB%9D%BC%EB%B3%B4%EC%9E%90&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@probsno/SpELSpring-Expression-Language%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C-%EA%B0%84%EB%8B%A8%ED%95%98%EA%B2%8C-%EC%95%84%EB%9D%BC%EB%B3%B4%EC%9E%90&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/blYonN/hyTpbA3pRj/7sr7OZV1JSbP6cj2En175k/img.png?width=950&amp;amp;height=500&amp;amp;face=0_0_950_500,https://scrap.kakaocdn.net/dn/bGmWay/hyTpavmDGP/7OpzHPb08EqySOuQtDz6dk/img.jpg?width=319&amp;amp;height=430&amp;amp;face=0_0_319_430');&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;SpEL(Spring Expression Language)에 대해서 간단하게 아라보자!&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;객체 그래프를 조회하고 조작하는 기능을 제공Unified El과 비슷하지만, 메소드 호출을 지원하며 ,문자열 템플릿 기능도 제공OGNL, MVEL, JBOss EL 등 자바에서 사용할 수 있는 여러 EL이 있지만 SpEL은 모&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;size18&quot;&gt;&amp;nbsp;&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;개선 내역&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;yml 파일&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;api:
	business-register-number: 'SECRET KEY'
	nutrient-business-register-number: 'SECRET KEY'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;@Value&lt;/b&gt; 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Service
public class CertificationService {

    @Value(&quot;${api.business-register-number}&quot;)
    private String BUSINESS_SERVICE_KEY;

    @Value(&quot;${api.nutrient-business-register-number}&quot;)
    private String NUTRIENT_BUSINESS_SERVICE_KEY;

		/*
		나머지 동작 코드
		*/
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;@ConfigurationProperties &lt;/b&gt;적용&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Getter
@Setter
@RequiredArgsConstructor
@Component
@ConfigurationProperties(prefix = &quot;custom.api&quot;)
public class CertificateProperties {
	  private String businessRegisterNumber;
		private String nutrientBusinessRegisterNumber;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&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;b&gt;@ConfigurationProperties(prefix = &quot;custom.api&quot;)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;해당 어노테이션을 사용해도 스프링 빈으로 등록되지 않는다.&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;다음 두 가지 방법 중 하나만 사용해도 된다.
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;해당 properties 클래스에 &lt;b&gt;@Component&lt;/b&gt; 추가&lt;/li&gt;
&lt;li&gt;메인 클래스에 &lt;b&gt;@EnableConfigurationProperties(CertificateProperties.class)&lt;/b&gt; 추가&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;@Getter&lt;/b&gt; &amp;amp; &lt;b&gt;@Setter&lt;/b&gt; 추가&lt;/li&gt;
&lt;li&gt;&lt;b&gt;@RequiredArgsConstructor&lt;/b&gt; 추가&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size14&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 class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Service
@RequiredArgsConstructor
public class CertificationService {
		private final CertificateProperties certificateProperties;

		/*
		나머지 동작 코드
		*/
}&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;CertificateProperties&lt;/b&gt; 클래스 주입&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Getter&lt;/b&gt; 사용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;certificateProperties.getBucketName()&lt;/b&gt; 형식으로 값 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;참고&lt;/b&gt;&lt;/h2&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;a href=&quot;https://hyena.oopy.io/30512502-06ee-408e-99b3-3af44d24c5e0&quot;&gt;Spring, Spring Boot와 Properties ? 외부 설정&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://mangkyu.tistory.com/207&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://mangkyu.tistory.com/207&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로젝트/팀 프로젝트 - MyPill</category>
      <category>@ConfigurationProperties</category>
      <category>@Value</category>
      <category>스프링부트</category>
      <category>트러블 슈팅</category>
      <author>호준송</author>
      <guid isPermaLink="true">https://hojunking.tistory.com/125</guid>
      <comments>https://hojunking.tistory.com/125#entry125comment</comments>
      <pubDate>Thu, 20 Jul 2023 03:14:50 +0900</pubDate>
    </item>
    <item>
      <title>[JAVA/자바][프로그래머스 181893] 배열 조각하기</title>
      <link>https://hojunking.tistory.com/124</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/181893&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/181893&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1682047085750&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;프로그래머스&quot; data-og-description=&quot;코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/181893&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ea7zg4/hySlAgS9RS/2bxd5KvBq1VZs4bfwei9k0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bp3vjt/hySlyXHfJP/gZSlwyF3olNWC9ZkluM0S0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/181893&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/181893&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ea7zg4/hySlAgS9RS/2bxd5KvBq1VZs4bfwei9k0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bp3vjt/hySlyXHfJP/gZSlwyF3olNWC9ZkluM0S0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;접근 방법&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;인덱스가 헷갈려서 노트에 적어가며 풀었다.&lt;/p&gt;
&lt;p style=&quot;text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;접근 방법 1&lt;/h4&gt;
&lt;p style=&quot;text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;매 query 작업마다 배열을 갱신한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 작업마다 O(N)의 시간이 소요된다.&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 style=&quot;text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;접근 방법 2&lt;/h4&gt;
&lt;p style=&quot;text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;단순하게 매 작업마다 시작점 포인터(start)와 끝점 포인터(end)를 갱신 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 작업마다 O(1)의 시간 이 소요된다.&lt;/li&gt;
&lt;li&gt;시간 소요가 적고 코드도 간단하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: start;&quot; 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;접근 방법 2로 진행하였다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;시작 포인터를 start, 끝 포인터를 end 로 선언하고 초기화한다.&lt;/li&gt;
&lt;li&gt;반복문을 돌린다.
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;query의 인덱스(i)가 &lt;b&gt;짝수&lt;/b&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;b&gt;시작 포인터에서 query[i] - 1 만큼 떨어 진 곳&lt;/b&gt;에 위치하게 된다.&lt;/li&gt;
&lt;li&gt;각 query[i] 값은 남아있는 arr의 길이 보다 작다고 제한되어 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;query의 인덱스(i)가 &lt;b&gt;홀수&lt;/b&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;b&gt;이전 시작 포인터에서 query[i] 만큼 떨어진 곳&lt;/b&gt;에 위치하게 된다.&lt;/li&gt;
&lt;li&gt;각 query[i] 값은 0보다 크거나 같다고 제한되어 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Arrays.copyOfRange() 를 사용해 배열을 복사&lt;/b&gt;한다.&lt;/li&gt;
&lt;/ol&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;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;코드&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;pre id=&quot;code_1682047110157&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.*;

class Solution {
    public int[] solution(int[] arr, int[] query) {
        int start = 0;
        int end = arr.length - 1;
        for (int i = 0; i &amp;lt; query.length; i++) {
            if (i % 2 == 0) {
                end = start + query[i] - 1;
            } else {
                start += query[i];
            }
        }

        if (start &amp;gt; end) {
            return new int[]{-1};
        }
        return Arrays.copyOfRange(arr, start, end + 1);
    }
}&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>Algorithm Practice/Programmers</category>
      <category>181893</category>
      <category>Java</category>
      <category>배열 조각하기</category>
      <category>알고리즘</category>
      <category>자바</category>
      <category>프로그래머스</category>
      <author>호준송</author>
      <guid isPermaLink="true">https://hojunking.tistory.com/124</guid>
      <comments>https://hojunking.tistory.com/124#entry124comment</comments>
      <pubDate>Fri, 21 Apr 2023 12:37:37 +0900</pubDate>
    </item>
    <item>
      <title>[JAVA/자바][프로그래머스 12946] 하노이의 탑</title>
      <link>https://hojunking.tistory.com/123</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12946&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/12946&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1681867052442&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;프로그래머스&quot; data-og-description=&quot;코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12946&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bMuLs2/hySkLoUygS/eURGU784TzBD6SjLiihNck/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/6y0m5/hySkQcCfgt/gDGqNgcu6Lu6mjybhkqJik/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12946&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12946&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bMuLs2/hySkLoUygS/eURGU784TzBD6SjLiihNck/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/6y0m5/hySkQcCfgt/gDGqNgcu6Lu6mjybhkqJik/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;접근 방법&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&quot;하노이의 탑&quot;은 규칙이 존재하는 대표적인 재귀 문제다.&lt;/p&gt;
&lt;p style=&quot;text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;점화식을 세워서 설계하면 쉽게 구현할 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;(출발지, 경유지, 도착지) 3개의 위치를 선언한다.&lt;/p&gt;
&lt;p style=&quot;text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&quot;N개, 출발지 -&amp;gt; 도착지&quot;&lt;/span&gt;&lt;/b&gt;의 경우&lt;/p&gt;
&lt;p style=&quot;text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;&quot;N-1개, 출발지 -&amp;gt; 경유지&quot;&lt;/b&gt;&lt;/span&gt; &lt;b&gt;+ &quot;1개, 출발지 -&amp;gt; 도착지&quot; +&lt;/b&gt; &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&quot;N-1개, 경유지 -&amp;gt; 도착지&quot;&lt;/b&gt;&lt;/span&gt;의 규칙을 가진다.&lt;/p&gt;
&lt;p style=&quot;text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이를 점화식으로 표현하고 코드로 구현한다.&lt;/p&gt;
&lt;p style=&quot;text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;이동 정보를 저장할 자료형 &lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ef5369; background-color: #dddddd;&quot;&gt;List&amp;lt;int[]&amp;gt; arr&lt;/span&gt;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;을 선언한다.&lt;/li&gt;
&lt;li&gt;이동을 의미하는 메소드 &lt;b&gt;&lt;span style=&quot;color: #ef5369; background-color: #dddddd;&quot;&gt;move(int cnt, int start, int mid, int end){}&lt;/span&gt;&lt;/b&gt; 를 선언한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;cnt&lt;/b&gt;개를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;start&lt;/b&gt;에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;end&lt;/b&gt;로 이동한다(필요 시&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;mid&lt;/b&gt;를 경유하며)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;cnt&lt;/b&gt; : 이동할 원판 개수&lt;/li&gt;
&lt;li&gt;&lt;b&gt;start&lt;/b&gt; : 출발지&lt;/li&gt;
&lt;li&gt;&lt;b&gt;mid&lt;/b&gt; : 경유지&lt;/li&gt;
&lt;li&gt;&lt;b&gt;end&lt;/b&gt; : 도착지&lt;/li&gt;
&lt;/ul&gt;
&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;&lt;span style=&quot;color: #ef5369; background-color: #dddddd;&quot;&gt;&lt;b&gt;move(cnt - 1, start, end, mid);&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ef5369; background-color: #dddddd;&quot;&gt;&lt;b&gt;arr.add(new int[]{start, end});&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ef5369; background-color: #dddddd;&quot;&gt;&lt;b&gt;move(cnt - 1, mid, start, end);&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 코드를 완성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;코드&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;pre id=&quot;code_1681867959449&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.*;

class Solution {
    private static List&amp;lt;int[]&amp;gt; arr = new ArrayList&amp;lt;&amp;gt;();

    public int[][] solution(int n) {
        move(n, 1, 2, 3);
        int[][] answer = arr.stream()
                .toArray(int[][]::new);
        return answer;
    }

    private static void move(int cnt, int start, int mid, int end) {
        if (cnt == 0) {
            return;
        }
        move(cnt - 1, start, end, mid);
        arr.add(new int[]{start, end});
        move(cnt - 1, mid, start, end);
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm Practice/Programmers</category>
      <category>12946</category>
      <category>Java</category>
      <category>알고리즘</category>
      <category>자바</category>
      <category>프로그래머스</category>
      <category>하노이의 탑</category>
      <author>호준송</author>
      <guid isPermaLink="true">https://hojunking.tistory.com/123</guid>
      <comments>https://hojunking.tistory.com/123#entry123comment</comments>
      <pubDate>Wed, 19 Apr 2023 10:33:10 +0900</pubDate>
    </item>
    <item>
      <title>[JAVA/자바][백준 14939] 불 끄기</title>
      <link>https://hojunking.tistory.com/122</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제&lt;/h2&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/14939&quot;&gt;https://www.acmicpc.net/problem/14939&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1681786573285&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;14939번: 불 끄기&quot; data-og-description=&quot;전구 100개가 10&amp;times;10 정사각형 모양으로 늘어서 있다. 전구에 달린 스위치를 누르면 그 전구와 위, 아래, 왼쪽, 오른쪽에 있는 전구의 상태도 바뀐다. 전구 100개의 상태가 주어지면 모든 전구를 끄&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/14939&quot; data-og-url=&quot;https://www.acmicpc.net/problem/14939&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/n570p/hySi01ppXZ/6MEpKC4KCRLWZ2STgY8Qi1/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/14939&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/14939&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/n570p/hySi01ppXZ/6MEpKC4KCRLWZ2STgY8Qi1/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;14939번: 불 끄기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;전구 100개가 10&amp;times;10 정사각형 모양으로 늘어서 있다. 전구에 달린 스위치를 누르면 그 전구와 위, 아래, 왼쪽, 오른쪽에 있는 전구의 상태도 바뀐다. 전구 100개의 상태가 주어지면 모든 전구를 끄&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;접근 방법&lt;/b&gt;&lt;/h2&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;/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;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: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;같은 행위를 반복하면 최적의 해를 구할 수 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;완전 탐색으로 100개의 전구를 켜고 끄는 경우를 찾으면 O(2^100)이다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;시간초과가 발생한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;한 가로 줄은 맞닿아 있는 가로 줄에만 직접적으로 영향을 끼친다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&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;따라서, 첫 가로 줄의 행동이 정해지면 자동으로 2번째 가로 줄의 행동이 정해지고, 10번째 줄까지 정해지게 된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 경우에는 O(2^10) * 나머지 줄 계산(= O(90) * 한 칸 계산)으로, 완전 탐색에 비해 시간을 많이 단축한다.&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;/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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;첫 번째 줄의 모든 경우의 수를 구해 List에 저장한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;makeFirstLine()&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;첫 번째 가로 줄의 모든 경우의 수(2^10 = 1024)에 대해 탐색한다.&lt;/li&gt;
&lt;li&gt;각 탐색의 경우는 독립적이므로, tmpBoard에 board를 복사한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;copy()&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;해당하는 경우에 맞게 1번째 가로줄의 스위치를 누른다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;cnt++를 통해 스위치 클릭 수 계산&lt;/li&gt;
&lt;li&gt;pushSwitch()
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;dX, dY 배열을 통해 주변 전구 상태 갱신&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;2 ~ 10 번째 줄에서 이전 줄에 대한 소등 작업을 진행한다.&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;cannotMake 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;3 ~ 6 번 작업을 2번에 해당하는 경우만큼 모두 탐색한다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;코드&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Main {
    private static int[] dX = {0, -1, 0, 1, 0};
    private static int[] dY = {0, 0, -1, 0, 1};
    private static char[][] board;
    private static char[][] tmpBoard;
    private static List&amp;lt;String&amp;gt; firstLine = new ArrayList&amp;lt;&amp;gt;();

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        board = new char[10][10];
        for (int i = 0; i &amp;lt; 10; i++) {
            board[i] = br.readLine().toCharArray();
        }
        tmpBoard = new char[10][10];

        int answer = 101;

        makeFirstLine(1, &quot;&quot;, 1);
        makeFirstLine(1, &quot;&quot;, 2);

        for (String e : firstLine) {
            int cnt = 0;
            copy();

//1번째 줄 선택for (int i = 0; i &amp;lt; 10; i++) {
                if (e.charAt(i) == 'O') {
                    pushSwitch(0, i);
                    cnt++;
                }
            }

//2~9번쨰 줄 선택for (int i = 1; i &amp;lt; 10; i++) {
                for (int j = 0; j &amp;lt; 10; j++) {
                    if (tmpBoard[i - 1][j] == 'O') {
                        pushSwitch(i, j);
                        cnt++;
                    }
                }
            }

//10번째 줄 확인if (!cannotMake()) {
                answer = Math.min(answer, cnt);
            }
        }
        if (answer == 101) {
            System.out.println(-1);
            return;
        }
        System.out.println(answer);
    }

    private static void makeFirstLine(int depth, String output, int mode) {
        if (mode == 1) {
            output += 'O';
        } else {
            output += 'X';
        }
        if (depth == 10) {
            firstLine.add(output);
            return;
        }
        for (int i = 0; i &amp;lt; 2; i++) {
            makeFirstLine(depth + 1, output, i);
        }
    }

    private static void copy() {
        for (int i = 0; i &amp;lt; 10; i++) {
            for (int j = 0; j &amp;lt; 10; j++) {
                tmpBoard[i][j] = board[i][j];
            }
        }
    }

    private static void pushSwitch(int x, int y) {
        for (int k = 0; k &amp;lt; 5; k++) {
            int nextX = x + dX[k];
            int nextY = y + dY[k];
            if (nextX &amp;gt;= 0 &amp;amp;&amp;amp; nextX &amp;lt; 10 &amp;amp;&amp;amp; nextY &amp;gt;= 0 &amp;amp;&amp;amp; nextY &amp;lt; 10) {
                if (tmpBoard[nextX][nextY] == 'O') {
                    tmpBoard[nextX][nextY] = '#';
                } else {
                    tmpBoard[nextX][nextY] = 'O';
                }
            }
        }
    }

    private static boolean cannotMake() {
        boolean flag = false;
        for (int i = 0; i &amp;lt; 10; i++) {
            if (tmpBoard[9][i] == 'O') {
                flag = true;
                break;
            }
        }
        return flag;
    }
}
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm Practice/Baekjoon</category>
      <category>14939</category>
      <category>Java</category>
      <category>백준</category>
      <category>알고리즘</category>
      <category>자바</category>
      <author>호준송</author>
      <guid isPermaLink="true">https://hojunking.tistory.com/122</guid>
      <comments>https://hojunking.tistory.com/122#entry122comment</comments>
      <pubDate>Tue, 18 Apr 2023 11:39:15 +0900</pubDate>
    </item>
    <item>
      <title>브라우저 URL 검색 과정</title>
      <link>https://hojunking.tistory.com/121</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;www.github.com을 브라우저에 입력하고 엔터를 쳤을 때, 네트워크 상 어떤 일이 일어나는가?&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;756&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvJZMR/btr9QTRqMsi/UsZVWQa0WKPa1trguaIS1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvJZMR/btr9QTRqMsi/UsZVWQa0WKPa1trguaIS1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvJZMR/btr9QTRqMsi/UsZVWQa0WKPa1trguaIS1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvJZMR%2Fbtr9QTRqMsi%2FUsZVWQa0WKPa1trguaIS1K%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;600&quot; height=&quot;432&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;756&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;&lt;b&gt;캐싱&lt;/b&gt;, &lt;b&gt;DNS&lt;/b&gt;, &lt;b&gt;라우팅&lt;/b&gt;, &lt;b&gt;ARP&lt;/b&gt;, &lt;b&gt;초기연결&lt;/b&gt;을 거쳐 &lt;b&gt;컨텐츠를 다운&lt;/b&gt;받게 되고 이 후 &lt;b&gt;브라우저 렌더링 과정&lt;/b&gt;을 거쳐 깃허브 화면이 나타나게 된다.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;&lt;b&gt;캡슐화&lt;/b&gt;&amp;rdquo;, &amp;ldquo;&lt;b&gt;비캡슐화&lt;/b&gt;&amp;rdquo; 과정을 거쳐서 이뤄지게 된다.&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;Web Cache&lt;/h3&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;b&gt;같은 웹 페이지를 여러 번 요청할 경우&lt;/b&gt;, 브라우저는 이미 다운로드한 자원을 다시 서버에서 &lt;b&gt;다운로드하지 않고&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;페이지 로딩 속도가 빨라지고, 네트워크 대역폭을 절약할 수 있다.&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;1. Browser Cache(사설 브라우저 캐시)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;544&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0GIeR/btr9N9AFOft/N4DcdjWvb8teTzAcxHnA6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0GIeR/btr9N9AFOft/N4DcdjWvb8teTzAcxHnA6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0GIeR/btr9N9AFOft/N4DcdjWvb8teTzAcxHnA6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0GIeR%2Fbtr9N9AFOft%2FN4DcdjWvb8teTzAcxHnA6K%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;400&quot; height=&quot;241&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;544&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;&lt;b&gt;클라이언트 로컬 컴퓨터에 저장&lt;/b&gt;되는 캐싱 방식이다.&lt;/li&gt;
&lt;li&gt;방문한 웹 페이지의 이미지, 스크립트, 스타일 시트 등의 자원들을 저장하여 캐싱역할을 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;한 개인에 한정&lt;/b&gt;되어 있어 자원을 공유하지않는다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;캐시가 쌓여서 로컬 디스크 공간을 많이 차지할 수 있어 개인이 삭제할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;ldquo;뒤로 가기&amp;rdquo;에 많이 사용된다.&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;2. Proxy Cache(프록시 캐시)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;550&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXc0v3/btr9NBROPTx/eVkAgdEHEgkq3Jbhdmh630/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXc0v3/btr9NBROPTx/eVkAgdEHEgkq3Jbhdmh630/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXc0v3/btr9NBROPTx/eVkAgdEHEgkq3Jbhdmh630/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXc0v3%2Fbtr9NBROPTx%2FeVkAgdEHEgkq3Jbhdmh630%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;400&quot; height=&quot;244&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;550&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;&lt;b&gt;클라이언트와 서버 사이에 위치한 네트워크 상(프록시 서버)&lt;/b&gt;에서 동작하는 캐시이다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;클라이언트의 요청을 대신 받아 서버로 전달한다.&lt;/li&gt;
&lt;li&gt;서버의 응답을 클라이언트에게 전달한다.&lt;/li&gt;
&lt;li&gt;동일한 요청이 올 시 캐시 데이터를 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다수의 웹 브라우저&lt;/b&gt;가 공유하여 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CDN(Content Delivery Network)&lt;/b&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;&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(Domain Name System)&lt;/h3&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;b&gt;DNS 서버를 통해 도메인 주소에 해당하는 IP주소를 받는다.&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;캐시를 먼저 확인한 후 Cache Miss가 발생하면 DNS 서버에 접근한다.&lt;/li&gt;
&lt;li&gt;일반적으로 UDP를 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  &lt;b&gt;Domain(도메인) 주소&lt;/b&gt; : IP주소를 다른 이름(닉네임)으로 바꾼 주소&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt; &amp;nbsp;&lt;b&gt;DNS&lt;/b&gt; 상세 내용은 추후 업로드 예정&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;라우팅(Routing)&lt;/h3&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;DNS에서 받은 &lt;b&gt;IP주소를 기반으로 해당 목적지까지&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;hop by hop 통신이라고 부르기도 한다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;hop(홉) : &amp;lsquo;건너뛰는 모습&amp;rsquo;이라는 뜻을 가진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  자세한 &lt;b&gt;라우팅 과정&lt;/b&gt;, &lt;b&gt;알고리즘&lt;/b&gt;은 추후에 업로드 예정&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;ARP(Address Resolution Protocol)&lt;/h3&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;라우팅을 통해 찾은 IP(논리 주소)를 바탕으로 ARP를 통해 서버의 MAC 주소(물리 주소)를 찾는다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;모든 장치는 MAC 주소를 가지고 있다.&lt;br /&gt;전송의 마지막 과정은 IP주소가 아닌, MAC 주소를 통해 이루어진다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;ARP는 IP 주소를 바탕으로 MAC 주소를 찾는 프로토콜을 말한다.&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ARP Request - ARP Reply 단계를 거친다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;ARP Request&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;621&quot; data-origin-height=&quot;302&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WLOEL/btr9SkgV3qv/Spw0riAR3o4JEWkTmnAsW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WLOEL/btr9SkgV3qv/Spw0riAR3o4JEWkTmnAsW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WLOEL/btr9SkgV3qv/Spw0riAR3o4JEWkTmnAsW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWLOEL%2Fbtr9SkgV3qv%2FSpw0riAR3o4JEWkTmnAsW0%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;621&quot; height=&quot;302&quot; data-origin-width=&quot;621&quot; data-origin-height=&quot;302&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;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd; color: #ee2323;&quot;&gt;A&lt;/span&gt;&lt;/b&gt;(송신자)가 목적지 IP Address를 지정해 &lt;b&gt;BroadCast&lt;/b&gt; 방식으로 패킷을 보낸다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd; color: #ee2323;&quot;&gt;D&lt;/span&gt;&lt;/b&gt;(IP Address에 해당하는 컴퓨터)에게 &lt;b&gt;MAC 주소를 요청&lt;/b&gt;한다.&lt;/li&gt;
&lt;li&gt;응답이 오기 전까지 &lt;b&gt;&lt;span style=&quot;background-color: #dddddd; color: #ee2323;&quot;&gt;D&lt;/span&gt;&lt;/b&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;ARP Reply&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;644&quot; data-origin-height=&quot;255&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xZxhi/btr9QVoaryE/0AUkUs2l456oz2uFec8PXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xZxhi/btr9QVoaryE/0AUkUs2l456oz2uFec8PXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xZxhi/btr9QVoaryE/0AUkUs2l456oz2uFec8PXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxZxhi%2Fbtr9QVoaryE%2F0AUkUs2l456oz2uFec8PXk%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;644&quot; height=&quot;255&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;255&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&lt;span style=&quot;background-color: #dddddd; color: #ee2323;&quot;&gt;D&lt;/span&gt;&lt;/b&gt;(목적지 IP에 해당하는 컴퓨터)는 패킷을 수신 후 자신의 MAC 주소를 &lt;b&gt;&lt;span style=&quot;background-color: #dddddd; color: #ee2323;&quot;&gt;A&lt;/span&gt;&lt;/b&gt;에게 전송한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Unicast&lt;/b&gt; 방식을 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd; color: #ee2323;&quot;&gt;A&lt;/span&gt;&lt;/b&gt;는 받은 &lt;b&gt;MAC 주소를&lt;/b&gt; 자신의 &lt;b&gt;ARP 테이블에 저장&lt;/b&gt;한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이후 ARP 테이블의 물리 주소를 이용하여 데이터를 전송한다.&lt;/li&gt;
&lt;/ul&gt;
&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;&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;/h3&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;TCP 3-Way Handshake, SSL, TLS 연결 등을 통해 &lt;b&gt;연결을 설정&lt;/b&gt;한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  &lt;b&gt;TCP 3-Way Handshake&lt;/b&gt;와 &lt;b&gt;SSL&lt;/b&gt;, &lt;b&gt;TLS&lt;/b&gt;는 추후 업로드 예정&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  TCP 3-Way Handshake는 업로드 완료&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  SSL, TLS 연결은 업로드 예정&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;/h3&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;연결 후 브라우저는 서버에게 HTTP 요청을 보낸다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP 메소드와 요청 URI, HTTP 버전을 포함한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;브라우저로부터 요청을 받으면,웹서버는 페이지의 로직이나 데이터베이스(DB)의 연동을 위해 &lt;b&gt;WAS에게 이들의 처리를 요청&lt;/b&gt;한다.&lt;/li&gt;
&lt;li&gt;WAS는 이 요청을 받아 &lt;b&gt;동적인 페이지처리를 담당&lt;/b&gt;하고, DB에서 필요한 데이터 정보를 받아서 파일을 생성한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;작업처리 결과를 웹서버로 전송&lt;/b&gt;하고, &lt;b&gt;웹서버는 브라우저에게 리소스(컨텐츠)를 전송&lt;/b&gt;한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  WAS는 &lt;b&gt;사용자의 컴퓨터나 장치에 웹어플리케이션을 수행해주는 미들웨어&lt;/b&gt;를 말한다.&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt; Web Server/WAS 에 대한 추가 설명은 하단의 질문을 참고하길 바란다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;/h3&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;HTML, CSS, JS, 이미지 등 웹 페이지에 포함된 &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;/li&gt;
&lt;li&gt;Rendering Engine에 의해 동작한다.&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;1282&quot; data-origin-height=&quot;642&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kwHTr/btr9NAMa83J/CA3MMSX95NtFQOoBkp1Lp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kwHTr/btr9NAMa83J/CA3MMSX95NtFQOoBkp1Lp0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kwHTr/btr9NAMa83J/CA3MMSX95NtFQOoBkp1Lp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkwHTr%2Fbtr9NAMa83J%2FCA3MMSX95NtFQOoBkp1Lp0%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;600&quot; height=&quot;300&quot; data-origin-width=&quot;1282&quot; data-origin-height=&quot;642&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;h4 data-ke-size=&quot;size20&quot;&gt;1. DOM(Document Object Model) Tree 생성&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;956&quot; data-origin-height=&quot;450&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ypEmg/btr9GgOs5m6/6ItTDr1xFrA5emAKOpmKt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ypEmg/btr9GgOs5m6/6ItTDr1xFrA5emAKOpmKt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ypEmg/btr9GgOs5m6/6ItTDr1xFrA5emAKOpmKt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FypEmg%2Fbtr9GgOs5m6%2F6ItTDr1xFrA5emAKOpmKt1%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;600&quot; height=&quot;282&quot; data-origin-width=&quot;956&quot; data-origin-height=&quot;450&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;어휘와 구문을 분석하여 &lt;b&gt;HTML 문서를 파싱&lt;/b&gt;하고, &lt;b&gt;파싱 트리를 생성&lt;/b&gt;한다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Parsing : 브라우저가 코드를 이해하고 사용할 수 있는 구조로 변환하는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;파싱 트리를 기반으로 DOM 요소와 속성 노드를 가지는 &lt;b&gt;DOM 트리를 생성&lt;/b&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;2. CSSOM(CSS Object Model) Tree 생성&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;954&quot; data-origin-height=&quot;494&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nO8dH/btr9SkBd4V7/Cmzgk716prSDNhFJ1T2z91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nO8dH/btr9SkBd4V7/Cmzgk716prSDNhFJ1T2z91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nO8dH/btr9SkBd4V7/Cmzgk716prSDNhFJ1T2z91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnO8dH%2Fbtr9SkBd4V7%2FCmzgk716prSDNhFJ1T2z91%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;600&quot; height=&quot;311&quot; data-origin-width=&quot;954&quot; data-origin-height=&quot;494&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;어휘와 구문을 분석하여 CSS &lt;b&gt;문서를 파싱한다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CSSOM 트리를 생성&lt;/b&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;3. Render Tree(DOM+CSSOM) 생성&lt;/h4&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;334&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IFy4b/btr9MpRQ3mD/BYkbCqoNSph7rnrSKcCClk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IFy4b/btr9MpRQ3mD/BYkbCqoNSph7rnrSKcCClk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IFy4b/btr9MpRQ3mD/BYkbCqoNSph7rnrSKcCClk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIFy4b%2Fbtr9MpRQ3mD%2FBYkbCqoNSph7rnrSKcCClk%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;600&quot; height=&quot;155&quot; data-origin-width=&quot;1294&quot; data-origin-height=&quot;334&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;1, 2단계에서 생성된 &lt;b&gt;DOM Tree와 CSSOM Tree를 매칭&lt;/b&gt;시켜 &lt;b&gt;Render Tree를 구성&lt;/b&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;4. Layout&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Layout 단계에서는 Render Tree를 &lt;b&gt;화면에 어떻게 배치해야 할 것인지&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;루트부터 노드를 순회하면서 &lt;b&gt;노드의 정확한 크기와 위치를 계산&lt;/b&gt;하고 &lt;b&gt;Render Layout을 생성&lt;/b&gt;한다.&lt;/li&gt;
&lt;li&gt;만약 크기 값을 %로 지정하였다면, Layout 단계에서 % 값을 계산해서 픽셀 단위로 변환한다.&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;5. Paint&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Paint 단계에서는 Layout을 이용해 요소의 색상,배경, 글꼴 등을 고려하여 &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;/li&gt;
&lt;li&gt;스타일이 복잡할수록 Paint 시간이 늘어난다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6. Composite&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Composite 단계에서는 Paint 단계에서 생성된 &lt;b&gt;레이어들을 합성하여&lt;/b&gt; &lt;b&gt;하나의 이미지로 렌더링&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;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;캡슐화 &amp;amp; 비캡슐화&lt;/h2&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1340&quot; data-origin-height=&quot;1006&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chsvgM/btr9MeCOXX8/JekEgpDZe3RlCfBOis31L1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chsvgM/btr9MeCOXX8/JekEgpDZe3RlCfBOis31L1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chsvgM/btr9MeCOXX8/JekEgpDZe3RlCfBOis31L1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchsvgM%2Fbtr9MeCOXX8%2FJekEgpDZe3RlCfBOis31L1%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;600&quot; height=&quot;450&quot; data-origin-width=&quot;1340&quot; data-origin-height=&quot;1006&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;데이터를 송신할 때 여러 네트워크 Layer를 거치면서 캡슐화된다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 Layer에서 헤더 필드가 추가 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;데이터를 수신할 때 여러 네트워크 Layer를 거치면서 비캡슐화된다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 Layer에서 헤더 필드를 해석하며 데이터를 추출한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;자세한 내용은 &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;a href=&quot;https://hojunking.tistory.com/112&quot;&gt;https://hojunking.tistory.com/112&lt;/a&gt; 참고&lt;/span&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;질문&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Q. Web Server와 Web Application Server의 차이에 대해 설명해 주세요.&lt;/h3&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Web Server&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;Web Server의 개념&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&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;Web Server가 설치되어 있는 컴퓨터&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;정적인 컨텐츠( .html, .jpeg, .css 등)을 제공하는 컴퓨터 프로그램&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;Web Server의 기능&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP 프로토콜을 기반으로 하여 클라이언트의 요청을 서비스하는 기능을 담당한다.&lt;/li&gt;
&lt;li&gt;기능 1
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;정적인 컨텐츠를 제공한다.&lt;/li&gt;
&lt;li&gt;WAS를 거치지않고 바로 자원을 제공한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;기능 2
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;동적인 컨텐츠 제공을 위한 요청을 전달한다.&lt;/li&gt;
&lt;li&gt;요청을 WAS에 보내고, WAS가 처리한 결과를 Client에게 전달(응답)한다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; 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;Apache Server, Nginx 등&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;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;WAS(Web Application Server)&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;WAS의 개념&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;DB 조회나 다양한 로직 처리를 요구하는 동적인 컨텐츠를 제공하기 위해 만들어진 Application Server를 말한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP를 통해 컴퓨터나 장치에 애플리케이션을 수행해주는 미들웨어(소프트웨어 엔진)이다.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;웹 컨테이너(Web Container)&amp;rdquo; 혹은 &amp;ldquo;서블릿 컨테이너(Servlet Container)&amp;rdquo;라고도 불린다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Container란 JSP, Servlet을 실행시킬 수 있는 소프트웨어를 말한다.&lt;/li&gt;
&lt;li&gt;즉, WAS는 JSP, Servlet 구동 환경을 제공한다.&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;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;WAS의 역할&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Web Server 기능들을 구조적으로 분리하여 처리하고자하는 목적으로 제시되었다.&lt;/li&gt;
&lt;li&gt;분산 트랜잭션, 보안, 메시징, 쓰레드 처리 등의 기능을 처리하는 분산 환경에서 사용된다.&lt;/li&gt;
&lt;li&gt;주로 DB 서버와 같이 수행된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;WAS의 주요 기능&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그램 실행 환경과 DB 접속 기능 제공&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 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;WAS의 예&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Tomcat, JBoss, Jeus, Web Sphere 등&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;Web Server가 필요한 이유?&lt;/h4&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: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;이미지 파일과 같은 정적인 파일들은 웹 문서(HTML 문서)가 클라이언트로 보내질 때 함께 가는 것이 아니다.&lt;/li&gt;
&lt;li&gt;클라이언트는 HTML 문서를 먼저 받고 그에 맞게 필요한 이미지 파일들을 다시 서버로 요청하면 그때서야 이미지 파일을 받아온다.&lt;/li&gt;
&lt;li&gt;Web Server를 통해 정적인 파일들을 Application Server까지 가지 않고 앞단에서 빠르게 보내줄 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;따라서 Web Server에서는 정적 컨텐츠만 처리하도록 기능을 분배하여 서버의 부담을 줄일 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;WAS가 필요한 이유?&lt;/h4&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: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;사용자의 요청에 맞게 적절한 동적 컨텐츠를 만들어서 제공해야 한다.&lt;/li&gt;
&lt;li&gt;이때, Web Server만을 이용한다면 사용자가 원하는 요청에 대한 결과값을 모두 미리 만들어 놓고 서비스를 해야 한다.&lt;/li&gt;
&lt;li&gt;하지만 이렇게 수행하기에는 자원이 절대적으로 부족하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;따라서 WAS를 통해 요청에 맞는 데이터를 DB에서 가져와서 비즈니스 로직에 맞게 그때 그때 결과를 만들어서 제공함으로써 자원을 효율적으로 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;그렇다면 WAS가 Web Server의 기능도 모두 수행하면 되지 않을까?&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&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;WAS는 DB 조회나 다양한 로직을 처리하느라 바쁘기 때문에 단순한 정적 컨텐츠는 Web Server에서 빠르게 클라이언트에 제공하는 것이 좋다.&lt;/li&gt;
&lt;li&gt;WAS는 기본적으로 동적 컨텐츠를 제공하기 위해 존재하는 서버이다.&lt;/li&gt;
&lt;li&gt;만약 정적 컨텐츠 요청까지 WAS가 처리한다면 정적 데이터 처리로 인해 부하가 커지게 되고, 동적 컨텐츠의 처리가 지연됨에 따라 수행 속도가 느려진다.&lt;/li&gt;
&lt;li&gt;즉, 이로 인해 페이지 노출 시간이 늘어나게 될 것이다.&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;SSL에 대한 암복호화 처리에 Web Server를 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;여러 대의 WAS를 연결 가능
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Load Balancing을 위해서 Web Server를 사용&lt;/li&gt;
&lt;li&gt;fail over(장애 극복), fail back 처리에 유리&lt;/li&gt;
&lt;li&gt;특히 대용량 웹 어플리케이션의 경우(여러 개의 서버 사용) Web Server와 WAS를 분리하여 무중단 운영을 위한 장애 극복에 쉽게 대응할 수 있다.&lt;/li&gt;
&lt;li&gt;예를 들어, 앞 단의 Web Server에서 오류가 발생한 WAS를 이용하지 못하도록 한 후 WAS를 재시작함으로써 사용자는 오류를 느끼지 못하고 이용할 수 있다.&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;예를 들어, 하나의 서버에서 PHP Application과 Java Application을 함께 사용하는 경우&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;접근 허용 IP 관리, 2대 이상의 서버에서의 세션 관리 등도 Web Server에서 처리하면 효율적이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;즉, 자원 이용의 효율성 및 장애 극복, 배포 및 유지보수의 편의성 을 위해 Web Server와 WAS를 분리한다.&lt;/h4&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;Web Server를 WAS 앞에 두고 필요한 WAS들을 Web Server에 플러그인 형태로 설정하면 더욱 효율적인 분산 처리가 가능하다.&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&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;a href=&quot;https://www.youtube.com/watch?v=GAyZ_QgYYYo&quot;&gt;웹 브라우저에 URL 입력하면 일어나는 일 - 인프라 위주&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=5MM8NDzWHdE&quot;&gt;[CS전공지식면접] www.naver.com을 주소창에 치면 어떻게 될까요?&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.naver.com/jhc9639/222700552159&quot;&gt;[CS전공지식면접] www.naver.com을 주소창에 치면 어떻게 될까요?&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@xortm854/HTTP-Caching&quot;&gt;HTTP Caching&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.inflearn.com/course/http-%EC%9B%B9-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC&quot;&gt;모든 개발자를 위한 HTTP 웹 기본 지식 - 인프런 | 강의&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://all-young.tistory.com/22&quot;&gt;브라우저와 렌더링 엔진 동작 원리&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://tecoble.techcourse.co.kr/post/2021-10-24-browser-rendering/&quot;&gt;브라우저 렌더링 과정 이해하기.&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://gmlwjd9405.github.io/2018/10/27/webserver-vs-was.html&quot;&gt;[Web] Web Server와 WAS의 차이와 웹 서비스 구조 - Heee's Development Blog&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://symfony.com/doc/6.3/http_cache.html&quot;&gt;HTTP Cache (Symfony 6.3 Docs)&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@eassy/www.google.com%EC%9D%84-%EC%A3%BC%EC%86%8C%EC%B0%BD%EC%97%90%EC%84%9C-%EC%9E%85%EB%A0%A5%ED%95%98%EB%A9%B4-%EC%9D%BC%EC%96%B4%EB%82%98%EB%8A%94-%EC%9D%BC&quot;&gt;'www.google.com'을 주소창에서 입력하면 일어나는 일&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Computer Science/Computer Network</category>
      <category>CS 스터디</category>
      <category>브라우저 검색 시 작동 과정</category>
      <category>브라우저 렌더링</category>
      <category>컴퓨터 네트워크</category>
      <author>호준송</author>
      <guid isPermaLink="true">https://hojunking.tistory.com/121</guid>
      <comments>https://hojunking.tistory.com/121#entry121comment</comments>
      <pubDate>Thu, 13 Apr 2023 10:37:52 +0900</pubDate>
    </item>
    <item>
      <title>URI, URL, URN</title>
      <link>https://hojunking.tistory.com/120</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;URI(Uniform Resource Identifier)&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;U&lt;/b&gt;niform : 리소스를 식별하는 통일된 방식&lt;/li&gt;
&lt;li&gt;&lt;b&gt;R&lt;/b&gt;esource : 자원, URI로 식별할 수 있는 모든 것(제한 없음)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;I&lt;/b&gt;dentifier : 다른 항목과 구분하는데 필요한 정보&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 인터넷 상에서 특정 자원(파일)을 나타내는 유일한 주소를 의미한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  URI는 URL, URN을 하위 개념으로 가진다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;URL(Uniform Resource Locator)&lt;/h2&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;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;/li&gt;
&lt;li&gt;대부분의 경우에서 &lt;b&gt;URI&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;URL 기본 구조&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;scheme://[userinfo@]host[:port][/path][?query][#fragment]&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/hojunking96/Problem-Solving-Practice/pulls?q=화이팅**&quot;&gt;https://github.com/hojunking96/Problem-Solving-Practice/pulls?q=화이팅&lt;/a&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;scheme&lt;/b&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;ftp, http, https 등이 있다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;https : http에 보안 추가(HTTP Secure)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;예시에서 https 에 해당한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;userinfo&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;URL에 사용자정보를 포함해서 인증할 때 사용한다.&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;b&gt;host&lt;/b&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;도메인명 또는 IP 주소를 직접 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;예시에서 github.com 에 해당한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;port&lt;/b&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;http는 80 포트, https는 443 포트를 주로 사용한다.&lt;/li&gt;
&lt;li&gt;포트는 생략 가능하다.&lt;/li&gt;
&lt;li&gt;예시(https)에서는 :443이 생략 되어 있다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;~~//github.com:443/~~ 처럼 :443을 넣어 검색해도 같은 주소가 나온다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;path&lt;/b&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;보통 계층적 구조로 되어 있다.&lt;/li&gt;
&lt;li&gt;예시에서 /hojunking96/Problem-Solving-Practice/pulls 에 해당한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;query&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;key=value 형태&lt;/li&gt;
&lt;li&gt;?로 시작, &amp;amp;로 추가 가능&lt;/li&gt;
&lt;li&gt;query parameter, query string 등으로 부른다.&lt;/li&gt;
&lt;li&gt;q=화이팅 에 해당한다.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;화이팅&amp;rdquo; 데이터를 pulls에 넘겨준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;fragment&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;html 내부 북마크 등에 사용한다.&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 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;URN(Uniform Resource Name)&lt;/h2&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;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;/li&gt;
&lt;li&gt;URN 이름만으로 실제 리소스를 찾을 수 있는 방법이 보편화 되지 않았다.
&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;/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;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&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;a href=&quot;https://www.inflearn.com/course/http-%EC%9B%B9-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC&quot;&gt;모든 개발자를 위한 HTTP 웹 기본 지식 - 인프런 | 강의&lt;/a&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Computer Science/Computer Network</category>
      <category>CS스터디</category>
      <category>URI</category>
      <category>URL</category>
      <category>URN</category>
      <author>호준송</author>
      <guid isPermaLink="true">https://hojunking.tistory.com/120</guid>
      <comments>https://hojunking.tistory.com/120#entry120comment</comments>
      <pubDate>Thu, 13 Apr 2023 02:06:29 +0900</pubDate>
    </item>
  </channel>
</rss>