<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>아쿠의 블로그입니다</title>
    <link>https://acuworld.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sun, 28 Jun 2026 07:45:18 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Acu</managingEditor>
    <item>
      <title>Korg 건반 어댑터 규격은 무엇인가?</title>
      <link>https://acuworld.tistory.com/74</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Korg Kross 건반의 어댑터가 고장났다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;750&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bj3cXY/btsEnWYXCDS/4iIzmCMfae6r4hbLKe9qz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bj3cXY/btsEnWYXCDS/4iIzmCMfae6r4hbLKe9qz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bj3cXY/btsEnWYXCDS/4iIzmCMfae6r4hbLKe9qz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbj3cXY%2FbtsEnWYXCDS%2F4iIzmCMfae6r4hbLKe9qz0%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;1000&quot; height=&quot;750&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;750&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;9V 센터플러스 어댑터를 쓰면 될 것 같은데, 집에 있는 9V 어댑터들은 전부 안들어간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전원 구멍이 너무 작다. 대체 어떤 크기의 어댑터를 사야하는가?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;750&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5eSHY/btsEnSvvIjP/KKG0HZ9CkQ0I60Cm2C9RvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5eSHY/btsEnSvvIjP/KKG0HZ9CkQ0I60Cm2C9RvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5eSHY/btsEnSvvIjP/KKG0HZ9CkQ0I60Cm2C9RvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5eSHY%2FbtsEnSvvIjP%2FKKG0HZ9CkQ0I60Cm2C9RvK%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;1000&quot; height=&quot;750&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;750&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;대중적이지 않은지라 &quot;Korg 어댑터&quot; 로 검색하면 일단 나오는 게 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어댑터 주제에 건방진 가격들이 해외배송 딱지를 붙이고 기세등등하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;971&quot; data-origin-height=&quot;896&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BrPWz/btsElLEeoLV/vnWBZKpIX7CRpcm2fXds9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BrPWz/btsElLEeoLV/vnWBZKpIX7CRpcm2fXds9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BrPWz/btsElLEeoLV/vnWBZKpIX7CRpcm2fXds9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBrPWz%2FbtsElLEeoLV%2FvnWBZKpIX7CRpcm2fXds9K%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;971&quot; height=&quot;896&quot; data-origin-width=&quot;971&quot; data-origin-height=&quot;896&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;결론은 4.8x1.8mm 규격으로 미션 성공했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;국내 모든 어댑터는 5.5x2.1~2.5mm 로 규격화 된 것으로 보인다. 추가로 Korg에 맞는 변환 젠더를 사면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래에서 구입했으니 필요한 사람에게 도움이 되길 바란다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(&lt;a href=&quot;https://smartstore.naver.com/mhe/products/5210803573&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://smartstore.naver.com/mhe/products/5210803573&lt;/a&gt;) (옵션: 노트북규격4.8x1.8mm)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;221&quot; data-origin-height=&quot;306&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpuUq8/btsEqXW7syU/E9VIuuv6ls4lZiuCsvXMfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpuUq8/btsEqXW7syU/E9VIuuv6ls4lZiuCsvXMfk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpuUq8/btsEqXW7syU/E9VIuuv6ls4lZiuCsvXMfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpuUq8%2FbtsEqXW7syU%2FE9VIuuv6ls4lZiuCsvXMfk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;221&quot; height=&quot;306&quot; data-origin-width=&quot;221&quot; data-origin-height=&quot;306&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>살면서 겪는 일들</category>
      <category>korg</category>
      <category>어답터</category>
      <category>어댑터</category>
      <author>Acu</author>
      <guid isPermaLink="true">https://acuworld.tistory.com/74</guid>
      <comments>https://acuworld.tistory.com/74#entry74comment</comments>
      <pubDate>Mon, 5 Feb 2024 00:29:21 +0900</pubDate>
    </item>
    <item>
      <title>웹 관련 분야로 취업을 준비하며... (포트폴리오, Front-end, Back-end)</title>
      <link>https://acuworld.tistory.com/70</link>
      <description>&lt;h1&gt;개요&lt;/h1&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;h1&gt;웹기술 관련 업계 동향&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹만큼 빠르게 변화하는 업계는 없는 것 같다. 개인적으로 생각하는 업계 동향을 적어본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Front-end&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프론트라는 개념이 나온 건 얼마 안됐다. 모든 마크업은 원래 서버의 담당이었다. 브라우저는 그저 그려낼 뿐.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동적인 웹의 필요성을 충족하기 위해 Javascript가 존재하긴 했지만 지금처럼 고도화 된 목적은 아니었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 브라우저에서 점점 많은 걸 하게 되고 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Ajax, jQuery 등을 거치면서&lt;span&gt; &lt;/span&gt;&lt;/span&gt;결국 프레임워크까지 오게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Angular(구글), React(페이스북)가 시작을 끊었고, 이보다 더 가벼움을 추구하는 Vue, Backbone등도 등장했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Back-end&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 소규모 사이트는 PHP로, 좀 규모가 좀 된다 하면 ASP/JSP로 개발하는 것이 오랜 시간 지속되어 왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 ASP는 IIS를 위해 돈이 좀 들어가므로 JSP 또는 Java 기반(EJB, ...)으로 작성하는 것이 선호되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러다 로드 존슨이 Java Enterprise의 단점들을 극복하는 책을 내면서 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Java Spring이&lt;span&gt; 등장했다.&lt;/span&gt;&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;PHP(Laravel 또는 Codeigniter), Python(Django), Ruby(Ruby on Rails) 등...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정점으로 Google V8 Engine이 퍼블릭으로 공개되면서 Javascript 또한 Node.js도 백엔드 대전에 참여했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;포트폴리오 준비 계획&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kakao, Naver,&amp;nbsp;LINE&amp;nbsp;채용 페이지에서 과연 어떤 경력직을 모집중인지 조사했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Web 기술이 아닌 것들은 배제했다. (핀테크, Video Streaming, Machine Learning 등)&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;style3&quot;&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;RESTful API 개념, MSA 개념, MVC 패턴&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;형상관리 (Git)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Single Page Application (SPA) 개념&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Linux, Shell Script, MySQL, NoSQL&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[JavaScript]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ECMAScript5 (2015),&amp;nbsp;TypeScript&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node.js, MongoDB, Express&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;jQuery, Backbone.js, React(+Redux), Angular, Vue.js&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;webpack, Electron&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bootstrap&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[PHP]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Laravel&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[Java]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring, Playframework(Scala)&lt;/p&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;얼추 프론트는 React, Angular, Vue 세 가지를 골고루 채용하고 있었고, 백엔드는 Spring과 Laravel을 채용하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나에게 주어진 한달 남짓의 기간에 이걸 전부 공부하기에는 시간이 모자라다는 판단이 든다. 선택과 집중의 시간.&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프론트와 백엔드에서 결정하기가 어렵다. 둘 다 취업을 열어놓고 공부를 해야 할 것 같고...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 Node.js로 백엔드 공부를, &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;빠르게 배울 수 있는 Vue로 입문을 하고자 한다. 언어가 같아서 효율적이기도 하고.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;웹 관련 개념&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;RESTful API&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP Request의 &lt;b&gt;GET/POST/PUT/DELETE&lt;/b&gt;를 이용해서 &lt;b&gt;CRUD(Create, Read, Update, Delete)&lt;/b&gt; 기능을 구현하는 것이다.&lt;/p&gt;
&lt;div&gt;기능적인 측면만 봤을 때는 위와 같고, 사실 그 뒷면에 이념이나 규칙 등은 조금 더 자세하다. 그 내용은 아래 소스들 참고.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;div&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://nesoy.github.io/articles/2017-02/REST&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://nesoy.github.io/articles/2017-02/REST&lt;/a&gt;&amp;nbsp;(RESTful이란?)&lt;/div&gt;
&lt;div&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://gmlwjd9405.github.io/2018/09/21/rest-and-restful.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://gmlwjd9405.github.io/2018/09/21/rest-and-restful.html&lt;/a&gt;&amp;nbsp;(REST란? REST API란? RESTful이란?)&lt;/div&gt;
&lt;div&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://meetup.toast.com/posts/92&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://meetup.toast.com/posts/92&lt;/a&gt;&amp;nbsp;(REST API 제대로 알고 사용하기)&lt;/div&gt;
&lt;/blockquote&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;CRUD를 테스트하는 툴로 Postman을 많이 사용한다. (&lt;a class=&quot;tx-link&quot; href=&quot;https://www.getpostman.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.getpostman.com&lt;/a&gt;)&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;MSA (Microservice Architecture)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스를 작은 단위로 쪼개서 운영하는 구조. 반대말은 Monolithic Architecture이다. (앞으로 Mono와 Micro라고 하겠다.)&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;Monolithic 아키텍처는 쉽게 말하면 한 웹서버 안에 모든 기능을 다 때려박은 구조이다. 단순하므로 개발이 빠르고 쉽다. 장점들은 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 몇 가지 문제가 있다. (쿠팡 블로그에서 참조함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 일부가 전체에 영향을 미친다. 코드에 메모리 누수가 발생하면 그 서버 전체가 다운되는 수가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 부분적인 Scale-out이 안된다. 일부 서비스에만 오버로드가 발생한다 해도 전체의 스케일을 키워야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) 여러 컴포넌트가 강하게 연결되어 있어, 변경이 어렵다. 강결합의 단점은 코드 수정 시 다른 코드에도 영향이 갈 수 있고, 그 정도를 모른다는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) 일부 수정에도 높은 테스트 비용이 든다. 특정 부분만 수정해도 테스트는 전체 서비스에 대해 이뤄지므로 비용이 비싸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5) 서비스 규모가 커질 수록 배포 시간이 오래 걸린다.&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;따라서 서비스를 작은 단위로 쪼개고, 물리적인 서버도 분리하고, 각 서비스끼리는 Message Queue를 두어 통신하게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이외에 자세한 내용은 아래 소스들 참고.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://alwayspr.tistory.com/20&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://alwayspr.tistory.com/20&lt;/a&gt;&amp;nbsp;(Microservice Architecture 란?)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://jason-lim.tistory.com/1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://jason-lim.tistory.com/1&lt;/a&gt;&amp;nbsp;(Microservice Architecture에 대한 이야기 - Integration)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://medium.com/coupang-tech/%ED%96%89%EB%B3%B5%EC%9D%84-%EC%B0%BE%EA%B8%B0-%EC%9C%84%ED%95%9C-%EC%9A%B0%EB%A6%AC%EC%9D%98-%EC%97%AC%EC%A0%95-94678fe9eb61&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/coupang-tech/행복을-찾기-위한-우리의-여정&lt;/a&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://medium.com/coupang-tech/%ED%96%89%EB%B3%B5%EC%9D%84-%EC%B0%BE%EA%B8%B0-%EC%9C%84%ED%95%9C-%EC%9A%B0%EB%A6%AC%EC%9D%98-%EC%97%AC%EC%A0%95-94678fe9eb61&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;-94678fe9eb61&lt;/a&gt;&amp;nbsp;(쿠팡의 MSA &amp;mdash; Part 1)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;MVC 패턴&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발할 때&amp;nbsp;Model-View-Controller 3가지 형태로 역할을 분리하여 개발하는 방법론.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 '왜 굳이 번거롭게?' 라는 생각이 들 수 있으나, 나중에는 합리적이라는 생각이 든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 개발 과정이 기존처럼&amp;nbsp;파일 하나에 다 때려박던 것보다&amp;nbsp;번거로운건 사실인데, 이렇게 분리함으로써 나중에 관리하기가 편해진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[Model]&lt;/b&gt; 내부 비즈니스 로직을 맡는 역할. 알고리즘, DB, 데이터 관리 등&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[Controller]&lt;/b&gt; Model과 View를 연결, 또는 유저와 연결되는 역할. 유저의 명령을 받아&amp;nbsp;Model에게 일을 넘겨주고 그 결과를 View를 통해 보여줌.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[View]&lt;/b&gt; 화면에 무언가 보여주기 위한 역할.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각자 하는 역할이&amp;nbsp;분리된다. 좀 더 자세히 설명하자면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Model&lt;/b&gt;은 데이터 혹은 작업 요청서(?)만 받아서 자기 일을 하고 Controller에게 주면 된다. 사용자랑 무슨 일이 벌어지는지는 관심 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;View&lt;/b&gt;는 Controller가 요청하면 자신의 모양대로 데이터를 그려내면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Controller&lt;/b&gt;는 Model-View를 중간에서 관리하면서, 유저와 연결되어 있기도 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자는 Controller에게 요청을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Controller는 필요에 따라 Model 에게 작업 혹은 데이터를 주어 처리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 그 결과를 View에게 전달하여 사용자에게 화면을 보여준다.&lt;/p&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&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;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://medium.com/@jang.wangsu/%EB%94%94%EC%9E%90%EC%9D%B8%ED%8C%A8%ED%84%B4-mvc-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80-1d74fac6e256&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/@jang.wangsu/디자인패턴&lt;/a&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://medium.com/@jang.wangsu/%EB%94%94%EC%9E%90%EC%9D%B8%ED%8C%A8%ED%84%B4-mvc-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80-1d74fac6e256&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;-mvc-패턴이란-1d74fac6e256&lt;/a&gt;&amp;nbsp;([디자인패턴] MVC 패턴이란?)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://jayzzz.tistory.com/40&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://jayzzz.tistory.com/40&lt;/a&gt;&amp;nbsp;(MVC패턴 모델, 뷰, 컨트롤러)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Single Page Application (SPA)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름 그대로 페이지 하나에 모든 기능을 때려박는(?) 접근 방법이다. 모던 웹의 패러다임이라고 할 수 있다. 페이스북이 이런 식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장점은 페이지 로드 처음에 일단 모든 리소스를 다운받고, 이후에는 변하는 부분만 서버에서 내용을 받아와 표시한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 새로고침이 발생하지 않으므로 Native App과 같은 사용자 경험을 줄 수 있다. 트래픽이&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;단점은 최초 1회 로딩에 대하여 많은 양의 리소스를 받아야 하므로 초기로딩속도가 느려지게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더불어 내용이 상황에 따라 동적으로 변하기 때문에, 검색엔진에서 크롤링이 불가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이외에 장단점이 더 많이 있다. 역시나 아래 소스들 참고.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://poiemaweb.com/js-spa&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://poiemaweb.com/js-spa&lt;/a&gt;&amp;nbsp;(Single Page Application &amp;amp; Routing)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://medium.com/@bbirec/spa-single-page-application-%EA%B0%9C%EB%B0%9C%EC%97%90%EC%84%9C-%EA%B3%A0%EB%A0%A4%ED%95%A0-%EC%82%AC%ED%95%AD-eedcb7cb618f&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/@bbirec/spa-single-page-application-개발에서-고려할-사항-eedcb7cb618f&lt;/a&gt;&amp;nbsp;(SPA&amp;nbsp;개발에서 고려할 사항)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://m.mkexdev.net/374?fbclid=IwAR3H9b90QaKAuuNPgJMfoXnWwfsnU4glF4uBp0QSDhAlnBJ8gNb8D5cdeKQ&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://m.mkexdev.net/374?fbclid=IwAR3H9b90QaKAuuNPgJMfoXnWwfsnU4glF4uBp0QSDhAlnBJ8gNb8D5cdeKQ&lt;/a&gt;&amp;nbsp;(SPA 단점에 대한 단상)&lt;/p&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;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;웹 기술 공부&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Node.js (Back-End)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Server-Side에서 동작하며 Network Application을 제작할 수 있는 플랫폼이다. 언어는 JavaScript를 사용한다. (Google V8 엔진 기반)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;혼동하지 말 점은, Node.js는 Web Server가 아니라는 점이다. (Apache가 아니다!)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그냥 &lt;/span&gt;JavaScript를&amp;nbsp;&lt;b&gt;실행(Run)&lt;/b&gt;할 수 있게 해 주는&amp;nbsp;&lt;b&gt;런타임(runtime)&lt;/b&gt;이다. 마치 Python처럼 말이다.&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;Node.js가 웹 서버로서 동작하려면 라이브러리(주로 Express)를 이용하여&amp;nbsp;&lt;b&gt;&lt;u&gt;HTTP 서버 코드를 직접 작성&lt;/u&gt;&lt;/b&gt;해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서&amp;nbsp;&lt;u&gt;직접 작성한다&lt;/u&gt;는 말은,&amp;nbsp;Apache가 FTP로 파일을 툭 올렸을 때&amp;nbsp;폴더&amp;nbsp;기반으로 파일의&amp;nbsp;URL을&amp;nbsp;알아서 처리해 줬던 것과는 달리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node.js는 URI를 해석하는 것부터, 어떤 파일과 매칭시킬 지&amp;nbsp;혹은 어떤 코드를 실행시킬 지를&amp;nbsp;코드로 일일이&amp;nbsp;&lt;b&gt;라우팅(Routing)&lt;/b&gt;&amp;nbsp;해 주어야 한다.&lt;/p&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;기존 Apache+PHP 환경에 익숙한 사람은 Node.js가 다소 불편할 수도 있다. 지향하는 바가 조금 다른 것 같다.&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;Apache는 FTP로 올린 파일의&amp;nbsp;경로가 URL에도 1:1로 매칭되는 시스템이다. 즉, 파일 위치가 곧 URL이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node.js는 파일의 위치와 URI가 다른 경우가 허다하다. URI와 파일을 직접 매칭 시켜줘야 한다. 그래서 번거로울 수도 있다.&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;앗, URL과 URI라고 다르게 표기한 것을 눈치챘는가?&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;URL과 URI의 차이&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;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;URL의 L은 Locator, 다시 말하면&amp;nbsp;URL이&amp;nbsp;&lt;b&gt;&lt;u&gt;파일의 위치&lt;/u&gt;&lt;/b&gt;를 나타내는 의미를 갖는다.&lt;/p&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;URI의 I는 Identifier, 위치가 아니라&amp;nbsp;&lt;b&gt;&lt;u&gt;식별(?)&lt;/u&gt;&lt;/b&gt;&amp;nbsp;역할을 하게 된다.&lt;/p&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;URI의 예시:&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;http://daum.net/login 에서, login 부분은 '기능'을 나타낸다. login 이라는 파일은 없다!&lt;/p&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;https://www.facebook.com/acuworld 에서, 아이디 부분은 당연히 파일이 아닐 것이다. acuworld는 '정보'를 의미한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;URI를 사용하여 파일과는 상관 없이 기능을 자유자재로 매핑시킬 수 있다는 점은 Node.js의 장점이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;(물론 Apache에서도 rewrite 모듈을 사용하면 가능하긴 하다...)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;입문(Tutorial)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node.js는 공식적인 튜토리얼이 없고, API 문서만 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 외부 튜토리얼로 공부해야 한다. 나는 다음 2개의 튜토리얼을 통해 학습하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://www.w3schools.com/nodejs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.w3schools.com/nodejs&lt;/a&gt;&amp;nbsp;(영문)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://velopert.com/node-js-tutorials&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://velopert.com/node-js-tutorials&lt;/a&gt;&amp;nbsp;(한글)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://backend-intro.vlpt.us&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://backend-intro.vlpt.us&lt;/a&gt; (백엔드 기초 다지기, 프로젝트 시작하기)&lt;/p&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;설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학습을 위해 Amazon AWS에 가입하고 프리티어(1년)를 받아 가상서버에서 진행하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Red Hat 리눅스에 설치하였고, 버전은 &lt;b&gt;Node.js&amp;nbsp;11.10.0 (npm 6.7.0)&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔터프라이즈(RedHat, CentOS, Fedora)는 NodeSource라는 곳에서 바이너리를 배포한다고 한다. (공식 사이트의 안내사항이다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 링크에서 쉽게 설치하는 쉘스크립트를 제공하고 있다. 명령어 한 줄로 Node.js를 설치할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://github.com/nodesource/distributions/blob/master/README.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/nodesource/distributions/blob/master/README.md&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Hello World 찍어보기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 코드를 hello.js에 작성해본다. (vim 이용)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;console.log(&quot;Hello, World!&quot;);&lt;/p&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;node를 실행하는 명령어는&amp;nbsp;&lt;span style=&quot;background-color: #848484; color: #ffffff;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #848484; color: #ffffff;&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;background-color: #848484; color: #ffffff;&quot;&gt; &lt;/span&gt;이다. hello.js를 실행하려면&amp;nbsp;&lt;span style=&quot;background-color: #848484; color: #ffffff;&quot;&gt; node hello.js &lt;/span&gt;를 입력하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;아주 간단한 웹서버 만들기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹서버를 만들기 전에, HTTP 프로토콜에 대한 기반 지식이&amp;nbsp;필요하다. 특히 헤더의 구조에 대해 알고 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 코드는 http 모듈을 불러오고, 8080 포트에 http 서버를 오픈하는 예제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 어떤 URI로 접속하던지 동일한 결과를 출력할 것이다. Header에 Response Code: 200(성공)을 보내고, Body는&amp;nbsp;Hello World.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;var http = require(&quot;http&quot;);&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;http.createServer(function(request,response) {&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; response.writeHead(200, {'Content-Type': 'text/plain'});&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; response.end(&quot;Hello World\n&quot;);&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;}).listen(8080);&lt;/p&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;코드를 해석한다. createServer()는 웹서버 객체(Object)를 만든다. 그리고 객체를 만들 때 익명 함수를 작성하여&amp;nbsp;전달했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더불어 웹서버 객체에 대해 8080 포트로 요청을 받아들이도록 listen() 메소드를 호출했다.&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;이제 해당 웹서버는 8080 포트로 접속이 들어올 때마다, 등록한 익명 함수를 호출할 것이다.&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;웹서버 예제는 더 복잡한 거 말고 여기까지만 하는 게 좋다. 어차피 Express 모듈을 써서 웹서버를 만들 것이기 때문.&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;Node Package Manager (NPM)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NPM은 패키지/모듈을 쉽게 설치하고 관리할 수 있도록 해 주는 명령어이다. (RedHat의 yum, Ubuntu의 apt-get과 같은 역할)&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;Node.js로 사이트(프로젝트)를 만들 때&amp;nbsp;수많은 모듈을 짜집기해서 만들게 된다. 따라서 필연적으로 다음과 같은 2개의 문제점이 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1)&amp;nbsp;프로젝트마다 필요한 모듈이 다를 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 프로젝트의 개발 시점에 따라서 사용한 모듈의 버전이 달라질 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 이 프로젝트에 어떤 모듈이 사용됐는지, 모듈의 버전이 무엇인지를 프로젝트 내 package.json 파일에 기록해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 package.json은 NPM에 의해 자동으로 관리된다. 그런 역할을 NPM이 해 주고 있다.&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;NPM에서 제공하는&amp;nbsp;간단한 명령어 2~3줄로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 프로젝트의 의존성(Dependency) 패키지들을 한 번에 설치하고, 프로젝트를 바로 실행할 수 있다.&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;blockquote data-ke-style=&quot;style3&quot;&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;npm init&lt;/p&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;/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;blockquote data-ke-style=&quot;style3&quot;&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;npm install [모듈명]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# 현재 프로젝트의 모든 Dependencies 모듈 설치&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm install&lt;/p&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;모듈 파일을 다운받아 프로젝트 폴더에 설치해 주지만, package.json에는 기록하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0055ff;&quot;&gt;--save&lt;/span&gt;&lt;/b&gt; 옵션을&amp;nbsp;주어야 package.json에 &quot;Dependencies&quot; 항목으로 기록된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0055ff;&quot;&gt;&lt;b&gt;--save-dev&lt;/b&gt;&lt;/span&gt; 옵션을 주면 &quot;DevDependencies&quot; 항목으로 기록된다. (음... 쉽게 얘기하면 개발용과 배포용을 따로 사용할 수 있다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0055ff;&quot;&gt;--dev&lt;/span&gt;&lt;/b&gt; 옵션을 주면 &quot;DevDependencies&quot; 항목의 패키지를 설치한다. 옵션 안주면 일반 Dependencies만 설치된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0055ff;&quot;&gt;&lt;b&gt;-g&lt;/b&gt;&lt;/span&gt; 옵션을 주면 글로벌로 설치한다. 기본값은 로컬 설치(현재 프로젝트 폴더에만 설치)이다. 글로벌 설치는 아예 시스템에 파일이 박힌다. (sudo 필요)&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;이외에도 NPM의 다양한 기능들이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 npm run-script 명령어는&amp;nbsp;아주 편하고 많이 사용되는 기능이다. script 관련 내용은 아래 package.json에서 익힐 수 있다.&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;package.json&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다음 블로그에서 잘 설명해 주고 있다:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://programmingsummaries.tistory.com/385&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://programmingsummaries.tistory.com/385&lt;/a&gt; (모두 알지만 모두 모르는 package.json)&lt;/p&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;Callback Function(콜백 함수) 개념&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 개념을 받아들이기 어려워 하는 사람도 있다. 생소하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자세한 설명은 다른 블로그가 더 잘 해주고 있고, 여기서는 개요만 설명하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;기존 Blocking 코딩에서, get_number() 함수가 처리에 5초 걸린다고 가정해 보겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;var a = get_number(); // 5초 걸리는 놈&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;console.log(a); // get_number()의 결과를 출력&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;next_function();&lt;/p&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;get_number() 호출 --&amp;gt; &lt;span style=&quot;color: #0055ff;&quot;&gt;5초 대기(blocking)&lt;/span&gt; --&amp;gt; a 출력 --&amp;gt; next_function(); 실행&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;즉, next_function() 입장에서는 앞 코드 실행이 끝날 때까지&amp;nbsp;기다려야&amp;nbsp;자기가 실행될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 예제는 Node.js가 익명 함수를 사용하여 Blocking을 없애고 있는 모습이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;get_number(&amp;nbsp; &lt;span style=&quot;color: #ff0000;&quot;&gt;function(req,res) { console.log(req);&amp;nbsp;}&lt;/span&gt;&amp;nbsp; );&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;next_function();&lt;/p&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;get_number() 호출 --&amp;gt; next_function() 호출 --&amp;gt; &lt;span style=&quot;color: #0055ff;&quot;&gt;5초 후&lt;/span&gt; --&amp;gt; &lt;span style=&quot;color: #ff0000;&quot;&gt;익명 함수(function)를 호출해서 결과 출력&lt;/span&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;next_function()은 아무런 대기 시간 없이 즉시 실행될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;get_number() 함수가 끝났을 때 무슨 코드를 실행할 지를, 익명 함수를 통해 작성하면 된다. (Non-blocking 구현)&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;자, 지금까지는 기존 언어(Java 등)에 익숙했기 때문에 &lt;b&gt;'익명 함수'&lt;/b&gt; 라고 불렀지만, 사실은 이게&amp;nbsp;&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;h3 data-ke-size=&quot;size23&quot;&gt;모듈 시스템&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JavaScript는 모듈 시스템이 없었다. &amp;lt;script src=&quot;jquery.js&quot;&amp;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;ECMAScript 2015(ES6)부터 모듈 개념이 도입되었다. 모듈은 각각이 개별 프로그램이라는 느낌이 든다. 변수나 패키지도 그 안에서만 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 Node.js의 모듈 시스템과 ES6의 모듈 시스템이 호환이 안된다는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정확하게는 &lt;b&gt;Node.js&amp;nbsp;모듈 시스템(require)&lt;/b&gt;이 자체적으로 먼저 가지고 있었고, &lt;b&gt;ES6 모듈 시스템(import)&lt;/b&gt;이 나중에 나온 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재까지도 Node.js는 ES6의 모듈(import) 문법을 지원하지 않는다. Node.js에서 import 문법을 쓰려면 Babel 툴로 컴파일을 해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Babel&lt;/b&gt;은 ES6/ES7 문법을 ES5로 transpiling 해 주는 컴파일러이다. 일부 브라우저에서 ES5 까지밖에 지원을 안하므로 이런 툴을 써야 하는 것이다.&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;hr class=&quot;tx-hr-border-3&quot; style=&quot;display: block; border: black 0 none; border-top: black 1px dotted; height: 1px;&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Express 모듈&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node.js로 웹 어플리케이션을 만들기 위한 프레임워크이다. 다양한 웹 관련 기능들을 제공한다.&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #848484; color: #ffffff;&quot;&gt;&amp;nbsp;npm install express --save &lt;/span&gt;&amp;nbsp;으로 간단하게 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;입문(Tutorial)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 내용은 아래 소스를 통해 공부하였고, 본 블로그에는 생소한 개념이나 어려웠던 점 위주로만 기록하고자 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://expressjs.com/ko/starter/hello-world.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://expressjs.com/ko/starter/hello-world.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://velopert.com/node-js-tutorials&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://velopert.com/node-js-tutorials&lt;/a&gt;&lt;/p&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;p data-ke-size=&quot;size16&quot;&gt;새로운 개념이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 Apache+PHP를 사용할 때는 코드를 PHP 파일로 작성하고 FTP로 서버에 올리면 끝이었다. &lt;u&gt;FTP에 올린 경로가 곧 URL&lt;/u&gt;이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Apache는 URL을 해석하여 해당 위치의 파일을 PHP 런타임에 전달하고, 결과로 출력된 HTML 코드를 그대로 사용자에게 보내주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node.js에서는 &lt;u&gt;URL이 파일의 위치를 의미하지 않는다&lt;/u&gt;. &lt;span style=&quot;color: #8c8c8c;&quot;&gt;(물론 파일을 의미하게 할 수도 있지만...)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 직접 URL을 분석하여, 어떤 행동을 할 지 또는 어떤 파일을 출력할 지를 일일이 결정해 주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 메소드(GET/POST/PUT/DELETE)의 종류에 따라 라우팅이 가능하다.&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;예를 들어 다음 코드는 GET 명령으로 &quot;/&quot; URI가 들어왔을 때, 어떤 함수를 실행할 지를 등록하는 코드이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;app.get('/', function (req, res) {&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; res.send('Hello World!');&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;});&lt;/p&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;Express 애플리케이션 생성기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예제를 풀거나 공부를 할 때는 Single File에서 코드를 작성하였다. 실제로 서비스를 개발하려면 파일을 역할별로 분리하여 관리하는 게 합리적일 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Express 앱 생성기를 이용하면 기본적인 폴더 구조를&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;폴더는 public(정적 파일), routes, views, bin 으로 나눠진다.&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;span style=&quot;background-color: #848484; color: #ffffff;&quot;&gt;&amp;nbsp;express --view=pug myapp&amp;nbsp;&lt;/span&gt; 명령을 입력하면&amp;nbsp;myapp 디렉토리가 생성되며 Express App이 생성된다. (템플릿 엔진으로 pug를 설정)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 디렉토리로 이동 후&amp;nbsp;&lt;span style=&quot;background-color: #848484; color: #ffffff;&quot;&gt; npm install&amp;nbsp;&lt;/span&gt; 로 기본적인 패키지를 설치한다. 이후&amp;nbsp;&lt;span style=&quot;background-color: #848484; color: #ffffff;&quot;&gt; DEBUG=myapp:* npm start&amp;nbsp;&lt;/span&gt; 명령어로 프로젝트를 실행해 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;자세한 내용은 다음 링크 참고: &lt;/b&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://expressjs.com/ko/starter/generator.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://expressjs.com/ko/starter/generator.html&lt;/a&gt;&lt;/p&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;템플릿 엔진(Template Engine)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각종 설명들을 요약하면 HTML 부분과 DATA 부분을 분리하기 위해 사용한다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과를 어떻게 표시할지를 Template으로&amp;nbsp;만들어두고, 여기에 Data만 집어넣으면 HTML 결과가 나오는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0055ff;&quot;&gt;사람의 입장&lt;/span&gt;에서 보면, 웹 퍼블리셔와 백엔드 개발자의 역할을 분리할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;웹 퍼블리셔&lt;/u&gt;는 HTML/CSS로만 디자인을 하고, 데이터가 들어갈 곳에는 &amp;lt;% 변수명 %&amp;gt; 등의 문법으로 자리만 잡아주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;백엔드 개발자&lt;/u&gt;는 Database에 쿼리를 쏴 데이터를 추출하고, 변수명만 잘 맞춰서 Template에 입력하기만 하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0055ff;&quot;&gt;브라우저 입장&lt;/span&gt;에서 보면, 쓸데없는 데이터 재전송을 막을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사이트에서 일부 내용만 바뀌는 경우(예: 페이스북) 기존 방식대로라면&amp;nbsp;페이지 전체를 다시 렌더링 해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;템플릿을 적용하면 데이터가 변한 그 부분만 내용을 수정할 수 있어 렌더링 시간과 네트워크 대역폭을 절약할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;자세한 내용은 다음 소스들 참고:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://gmlwjd9405.github.io/2018/12/21/template-engine.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://gmlwjd9405.github.io/2018/12/21/template-engine.html&lt;/a&gt;&amp;nbsp;(템플릿 엔진(Template Engine)이란)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://show-me-the-money.tistory.com/56&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://show-me-the-money.tistory.com/56&lt;/a&gt;&amp;nbsp;(템플릿 엔진이란 무엇인가?)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://nesoy.github.io/articles/2017-03/web-template&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://nesoy.github.io/articles/2017-03/web-template&lt;/a&gt;&amp;nbsp;(웹 템플릿 엔진(Template Engine) 이란?)&lt;/p&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;hr class=&quot;tx-hr-border-3&quot; style=&quot;display: block; border: black 0 none; border-top: black 1px dotted; height: 1px;&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;MongoDB&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MySQL은 &lt;span style=&quot;color: #0055ff;&quot;&gt;&lt;b&gt;Relational Database&lt;/b&gt;&lt;/span&gt;이다. 데이터의 규격 및 관계가 명확하게 정의된 채 사용되는 데이터베이스이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 관계형 DB는 SQL(Structured Query Language) 이라는 언어를 사용하며,&amp;nbsp;ACID(Atomic, Consistency, Integrity, Duarabity) 특성을 지원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ㅋ... 쉽게 말하면 데이터의 신뢰가 보장되지만 구조의 유연성이 떨어진다고 요약할 수 있다. &lt;u&gt;정확한 데이터 처리&lt;/u&gt;를 요하는 은행, ERP 등에는 필수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시대가 흐르면서 &lt;span style=&quot;color: #0055ff;&quot;&gt;&lt;b&gt;Non-&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #0055ff;&quot;&gt;&lt;b&gt;Relational Database&lt;/b&gt;&lt;/span&gt;가 등장한다. 비정형 데이터를 쉽게 담아서 쓰는&amp;nbsp;NoSQL 이라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;차이점은 관계형 DB보다 융통성 있고 유연한 데이터 모델을 사용하며, 데이터의 저장 및 탐색에 특화된 알고리즘을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ㅋ... 이것도 요약하면 관계성을 포기한 대신 &lt;u&gt;단순 저장&amp;amp;탐색에는 아주 빠른 성능&lt;/u&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;MongoDB는 NoSQL에 해당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NoSQL에는 여러 종류의 데이터 모델(Model)이 존재하는데, Key Value DB, Big Table DB, Document DB, Graph DB 등이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 중 MongoDB는 DocumentDB에 해당한다. DocumentDB는 데이터가 JSON, XML 등의 Document로 모델링 되어있는 형태이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다양한 NoSQL별 특징 및 성능 비교 등등 정보는 다음 링크 참고:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://www.samsungsds.com/global/ko/support/insights/1195843_2284.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.samsungsds.com/global/ko/support/insights/1195843_2284.html&lt;/a&gt;&amp;nbsp;(NoSQL이란 무엇인가? 대량데이터 동시처리위한 DBMS 종류와 특징)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://www.mongodb.com/compare/mongodb-mysql&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.mongodb.com/compare/mongodb-mysql&lt;/a&gt;&amp;nbsp;(MongoDB and MySQL Compared)&lt;/p&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;입문(Tutorial)&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;공식 튜토리얼(영문):&lt;/b&gt;&amp;nbsp;&lt;a class=&quot;tx-link&quot; href=&quot;https://mongoosejs.com/docs/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://mongoosejs.com/docs/index.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;한국어 강좌 링크:&lt;/b&gt;&amp;nbsp;&lt;a class=&quot;tx-link&quot; href=&quot;https://velopert.com/mongodb-tutorial-list&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://velopert.com/mongodb-tutorial-list&lt;/a&gt;&lt;/p&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;우선 용어가 조금 다른데, MySQL의 테이블, 로우, 컬럼을 MongoDB에서는 컬렉션, 도큐먼트, 필드 라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 자세한 개념은 위 링크들 참고.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;간단한 커맨드들&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치 후&amp;nbsp;&lt;span style=&quot;background-color: #848484; color: #ffffff;&quot;&gt; mongo&amp;nbsp;&lt;/span&gt; 명령어로 Command Line에 접속할 수 있다.&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;Database를 생성하려면&amp;nbsp;&lt;span style=&quot;background-color: #848484; color: #ffffff;&quot;&gt; use 디비명&amp;nbsp;&lt;/span&gt; 을 이용하면 된다. 왜 커맨드가 use인가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 DB가 존재한다면 있던 걸 사용하고, 없으면 새로 생성한다. 단, Document를 하나 이상 생성해야 DB도 생성된다.&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;Database 목록은&amp;nbsp;&lt;span style=&quot;background-color: #848484; color: #ffffff;&quot;&gt;&amp;nbsp;show dbs&amp;nbsp;&lt;/span&gt; 를 통해 확인하며, 사용중인 디스크 용량까지 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;관리 도구: Compass&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식 사이트에서 MongoDB를 관리할 수 있는 GUI 프로그램을 제공하고 있다. (MySQL의 Workbench 같은 느낌)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다운로드 링크:&lt;/b&gt; https://www.mongodb.com/products/compass&lt;/p&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;Mongoose&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node.js의 모듈이다. 역시&amp;nbsp;&lt;span style=&quot;background-color: #848484; color: #ffffff;&quot;&gt; npm install mongoose --save&amp;nbsp;&lt;/span&gt; 로 설치할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Mongoose는 MongoDB에서 부족한 부분들을 다양한 자체 기능으로 메꾸고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;스키마(Schema)&lt;/b&gt; 기능을 제공한다. NoSQL의 장점이자 단점은 Document에 넣는대로 들어간다는 것이다.&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;(MySQL에서 Table을 만들 때 column을 미리 정하듯이, Schema를 통해 Document의 field를&amp;nbsp;미리 정하게 된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Populate&lt;/b&gt;라는 기능도 있다. 쉽게 말하면 MySQL의 JOIN을 구현한 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 어떤 Document가 다른 Document의 ID를 갖고 있을 때, MySQL에서는 JOIN을 통해 두 Document의 내용을 한 번에 가져올 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MongoDB에서는 두 번의 Read를 거쳐야 한다. 첫 번째 Document를 먼저 가져오고, 두 번째 Document를 ID로 조회해서 또 가져와야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 Mongoose가 알아서 해 주는 것이다. 다만 MySQL의 JOIN과는 달리 그냥 대신 해 주는 것에 불과하므로, 남발하면 성능 하락이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이외에도 &lt;b&gt;Promise&lt;/b&gt;나 &lt;b&gt;Query Builder&lt;/b&gt; 등의 좋은 기능들도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자세한 내용은 다음 링크 참고:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://www.zerocho.com/category/MongoDB/post/5963b908cebb5e001834680e&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.zerocho.com/category/MongoDB/post/5963b908cebb5e001834680e&lt;/a&gt;&amp;nbsp;(Mongoose(몽구스) 시작하기)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://velopert.com/594&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://velopert.com/594&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;(Express와 Mongoose를 통해 MongoDB와 연동하여 RESTful API 만들기)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;간단한 예제 1 (DB에 데이터 넣어보기)&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 언급한 공식 사이트(영문)에서 다양한 개념을 잘 설명해 주고 있으니 건너 뛰었다면 한 번 정도는 보기를 권한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 Mongoose 기능 전반에 대해 한 페이지로 요약 설명한 &lt;u&gt;Getting Started&lt;/u&gt;&amp;nbsp;의&amp;nbsp;내용이 좋다. (&lt;a class=&quot;tx-link&quot; href=&quot;https://mongoosejs.com/docs/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://mongoosejs.com/docs/index.html&lt;/a&gt;)&lt;/p&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;먼저 다양한 세부 개념에 대한 설명은 다음 링크 참조:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://www.zerocho.com/category/MongoDB/post/59a1870210b942001853e250&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.zerocho.com/category/MongoDB/post/59a1870210b942001853e250&lt;/a&gt;&amp;nbsp;(Mongoose 스키마(Schema))&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://dalkomit.tistory.com/112&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://dalkomit.tistory.com/112&lt;/a&gt;&amp;nbsp;(Mongoose 모델의 강점)&lt;/p&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;Schema는 Document의 필드들을 정의한다. MySQL에서 Table의 Column을 정하는 것이라고 보면 된다. &lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;b&gt;그런데 Table을 만든 것은 아니다!&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그저&amp;nbsp;&lt;b&gt;Rule&lt;/b&gt;을 만든 것이다. 아직까지는 Collection(Table)과는 아무런 관련이 없이,&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;방금 만든 Schema를 Model이라는 것으로 컴파일 해야 비로소 Collection의 역할을 하는 것이다. (처음엔 이해가 안될 수도 있음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예제는&amp;nbsp;심플함을 위해 &lt;b&gt;싱글 파일&lt;/b&gt;로 작성하고 실행하였다. 뭔 말이냐면 Express Generator를 쓰지 않았다는 소리다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm start니 app.js니... 겨우 예제 푸는데 귀찮게 그러지 않고&amp;nbsp;&lt;span style=&quot;background-color: #848484; color: #ffffff;&quot;&gt; node example.js&amp;nbsp;&lt;/span&gt; 이런 식으로 싱글 파일로 실행했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(아 물론 npm install로 mongoose나 express 등 모듈들은&amp;nbsp;설치해 줘야 한다.)&lt;/p&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;다음 코드의 예제를 보도록 하자. (공식 사이트의 Getting Started를 다듬었다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-comment&quot;&gt;/* Mongoose 객체를 생성함 */&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; mongoose = &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-built_in&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-string&quot;&gt;'mongoose'&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-comment&quot;&gt;/* 서버에 접속 시도 */&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-comment&quot;&gt;// connect() 두 번째 인자로 옵션 준 거는 그냥 주라고 해서 준 거임. 생략해도 무방&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; mongoose.connect(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-string&quot;&gt;'mongodb://localhost/portfolio'&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;, { &lt;/span&gt;&lt;span style=&quot;color: #ff0000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-attr&quot;&gt;useNewUrlParser&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; }); &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-comment&quot;&gt;/* 객체에서 커넥션 정보 가져오기 */&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-comment&quot;&gt;// 접속 실패 시 에러 메시지 띄우기&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; db = mongoose.connection; db.on(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-string&quot;&gt;'error'&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-built_in&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;.error.bind(&lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-built_in&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-string&quot;&gt;'connection error:'&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;)); db.once(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-string&quot;&gt;'open'&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-function&quot;&gt;&lt;span style=&quot;color: #0000ff; background-color: #eaeaea;&quot; class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;background-color: #eaeaea;&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #eaeaea;&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-comment&quot;&gt;// Connected!&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; }); &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-comment&quot;&gt;/* 스키마(Schema) 생성 */&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; personSchema = &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; mongoose.Schema({ &lt;/span&gt;&lt;span style=&quot;color: #ff0000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-attr&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-built_in&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #ff0000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-attr&quot;&gt;age&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-built_in&quot;&gt;Number&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;, }); &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-comment&quot;&gt;/* 모델(Model) 생성 */&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-comment&quot;&gt;// Collection을 만들었다고 보면 됨&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; Person = mongoose.model(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-string&quot;&gt;'Person'&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;, personSchema); &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-comment&quot;&gt;/* 모델을 이용하여 Document 생성 */&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; acu = &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; Person({ &lt;/span&gt;&lt;span style=&quot;color: #ff0000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-attr&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-string&quot;&gt;'Acu'&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #ff0000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-attr&quot;&gt;age&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-number&quot;&gt;26&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; }); &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-comment&quot;&gt;// Document를 객체로써 취급한다. (ODM 개념)&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-built_in&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;.log(acu.name); &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-comment&quot;&gt;// 'Acu'&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-built_in&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;.log(acu.age); &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-comment&quot;&gt;// 26&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-comment&quot;&gt;/* 모델을 실제 DB에 반영 */&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; acu.save();&lt;/span&gt;&lt;/p&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;느낌은 마치 C++에서 클래스를 만들고 객체로 이것저것 데이터 처리를 하는 느낌이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 MySQL의 데이터를 객체 쓰듯이 쓸 수 있도록 한 ORM(Object Relational Mapper)이 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얘도 마찬가지로 똑같은데, 이름은 살짝 다르게 ORM(Object &lt;u&gt;Document&lt;/u&gt; Mapper)이다. 즉 객체처럼 쓰는 게 맞다는 것ㅎㅎ&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;코드를 정리하자면, Schema를 만들어서 규칙을 생성하고, 이 규칙을 토대로 Model을 만들어 Collection을 담당하게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Model을 기반으로 Document를 만들어 데이터를 넣는다. 마지막으로 실제 DB에 save()로 적용하면 된다.&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;리눅스 MongoDB에서 다음 커맨드로 위 코드의 결과를 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;gt; &lt;b&gt;show dbs&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;admin&amp;nbsp; &amp;nbsp; &amp;nbsp; 0.000GB&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;config&amp;nbsp; &amp;nbsp; &amp;nbsp;0.000GB&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;local&amp;nbsp; &amp;nbsp; &amp;nbsp; 0.000GB&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;portfolio&amp;nbsp; 0.000GB&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;gt; &lt;b&gt;use portfolio&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;switched to db portfolio&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;gt; &lt;b&gt;show collections&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;people&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;gt; &lt;b&gt;db.people.find({})&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;{ &quot;_id&quot; : ObjectId(&quot;5c7fd76db6c337600a1b7c14&quot;), &quot;name&quot; : &quot;Acu&quot;, &quot;age&quot; : 26, &quot;__v&quot; : 0 }&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Model로 컴파일하면서 Collection의 이름을 지정하게 된다. 예를 들어 var Person = mongoose.model('모델 이름', 스키마);&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 모델 이름이 자동으로 Collection의 이름이 되는데, 특이한 점은 자동으로 영어 복수형으로 변환된다.&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;뭔 소리냐? 예를 들어 mongoose.model('Car', carSchema); 를 실행하면 실제 MongoDB에는 Cars 컬렉션이 생성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Person을 입력하면 People이 된다(...).&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;이렇게 Document와 Collection의 이름이 연동되는게&amp;nbsp;싫으면 별도로 옵션을 주면 된다는데 그것까진 굳이 안찾아봤음.&lt;/p&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;간단한 예제 2 (RESTful API 만들기)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 예제도 역시나 싱글 파일로 작성했다. 하지만 나중에는 Router 파일을&amp;nbsp;분리하는 등 코드를 체계적으로 관리해야 할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 사이트: &lt;a class=&quot;tx-link&quot; href=&quot;https://velopert.com/594&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://velopert.com/594&lt;/a&gt; (Express와 Mongoose를 통해 MongoDB와 연동하여 RESTful API 만들기)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[사전지식: URL을 통한 정보 전달]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로&amp;nbsp;http://google.com/?&lt;u&gt;first=512&amp;amp;second=12512&lt;/u&gt; 이런 식으로 URL에 데이터를 전달한다. 이런 걸 &lt;b&gt;Query String&lt;/b&gt; 이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정보는 key=value 형식으로 되어 있고, 각 데이터는 &amp;amp;로 구분된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 방식으로도 전달이 가능한데, http://blog.com/&lt;u&gt;view/12345/mobile&lt;/u&gt;&amp;nbsp;이런 식이다. 이런 걸 &lt;b&gt;Semantic URL&lt;/b&gt; 이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정보는 value의 나열로 되어 있고, 각 데이터는 /로 구분된다. 그럼 key는??? 프로그래머가 결정한다.&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;라우팅 시 app.get('/view/:id/:mode') 형태로 받으면 id=12345, mode='mobile' 을 의미하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;내용 출처:&lt;/b&gt; &lt;a class=&quot;tx-link&quot; href=&quot;https://wayhome25.github.io/nodejs/2017/02/18/nodejs-11-express-query-string/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://wayhome25.github.io/nodejs/2017/02/18/nodejs-11-express-query-string/&lt;/a&gt; (Express-URL을 이용한 정보의 전달)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[사전지식: JSON Parsing]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REST API는 Header로 GET/POST/PUT/DELETE 중 1개가 오고, Body에는 &lt;u&gt;JSON 데이터&lt;/u&gt;가 온다. (안올수도 있지만;;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 말은, Body를 파싱할 필요가 있다는 뜻이다. JSON Parser를 이용해서 데이터를 객체(Object)로 만드는 과정이 필요하다.&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;예를 들어 { name: &quot;Acu&quot;, age: 50 } 이라는 JSON 데이터가 Body로 도착한 경우, JSON Parser를 통해 파싱을 거치면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;body.acu 라던지 body.age 처럼 파싱된 데이터를 body라는 객체에 담아 편리하게 쓸 수 있다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&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;원래는 JSON Body를 파싱하기 위해&amp;nbsp;&lt;u&gt;body-parser&lt;/u&gt; 모듈을 사용하는게 정석이었으나,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Express v4.16.0 부터 &lt;u&gt;Body Parser를 내장&lt;/u&gt;했기 때문에 body-parser 모듈이 더 이상 필요치 않다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;var bodyParser = require('body-parser')&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;app.use(bodyParser().json())&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;app.post('/', function(req, res) =&amp;gt; {&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; console.log(&lt;b&gt;req.body&lt;/b&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;})&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 썼던 기존 코드를&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;app.use(express.json())&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;app.post('/', function(req, res) =&amp;gt; {&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; console.log(&lt;b&gt;req.body&lt;/b&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;})&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 내장 Parser를 이용하여 파싱된 req.body를 얻을 수 있다. (Parser를 쓰지 않으면 req.body는 Undefined 임)&lt;/p&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;코드가 좀 길어서 부분별로 나눴다. 전부 한 파일로 합치면 RESTful API 서버가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;패키지 로드, Express 객체 생성, JSON Parsing&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;/* 패키지 로드 */&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; express = &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-built_in&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-string&quot;&gt;'express'&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; mongoose = &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-built_in&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-string&quot;&gt;'mongoose'&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;/* Express 객체 생성 */&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; app = express(); app.use(express.json()); &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// JSON Body Parsing&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;MongoDB 접속, Scheme와 Model 생성&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;/* Mongoose 접속 */&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; db = mongoose.connection; db.on(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-string&quot;&gt;'error'&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-built_in&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;.error); &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// 에러 났을 때 뭐할지 등록&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; db.once(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-string&quot;&gt;'open'&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-function&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot; class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; (&lt;span class=&quot;hljs-params&quot;&gt;&lt;/span&gt;) &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// 접속 시 뭐할지 등록&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-built_in&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;.log(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-string&quot;&gt;'Connected to mongod server.'&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;); }); mongoose.connect(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-string&quot;&gt;'mongodb://localhost/portfolio'&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;, { &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// 서버 접속&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; useNewUrlParser: &lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; }); &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;/* Mongoose Scheme &amp;amp; Model 생성 */&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; personSchema = &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; mongoose.Schema({ &lt;/span&gt;&lt;span style=&quot;color: #ff0000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-attr&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-built_in&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #ff0000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-attr&quot;&gt;age&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-built_in&quot;&gt;Number&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;, }); &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; Person = mongoose.model(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-string&quot;&gt;'Person'&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;, personSchema);&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;Routing &amp;amp; CRUD 구현: 1. Create&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;/* 라우팅(Routing) */&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; app.post(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-string&quot;&gt;'/'&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-function&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot; class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; (&lt;span class=&quot;hljs-params&quot;&gt;req, res&lt;/span&gt;) &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// Body에 {&quot;name&quot;:&quot;Hong&quot;, &quot;Age&quot;:30} 과 같은 JSON이 온다.&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// 새로운 document 생성&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; person = &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; Person(); person.name = req.body.name; &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// JSON Parser가 req.body에 담아주었다.&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; person.age = req.body.age; &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// 실제로 db 서버에 반영&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; person.save(&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-function&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot; class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; (&lt;span class=&quot;hljs-params&quot;&gt;err&lt;/span&gt;) &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; (err) { &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-built_in&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;.error(err); res.json({ &lt;/span&gt;&lt;span style=&quot;color: #ff0000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-attr&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; }); &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// 성공 혹은 실패를 0,1로 반환&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;; } res.json({ &lt;/span&gt;&lt;span style=&quot;color: #ff0000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-attr&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; }); &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// 성공 혹은 실패를 0,1로 반환&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; }); });&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;Routing &amp;amp; CRUD 구현: 2. Read&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;app.get(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-string&quot;&gt;'/'&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-function&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot; class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; (&lt;span class=&quot;hljs-params&quot;&gt;req, res&lt;/span&gt;) &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// 별도의 Data를 받지 않는다. DB의 모든 데이터를 출력&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// find()에 아무런 쿼리가 없으면 모든 document를 가져온다&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; Person.find(&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-function&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot; class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; (&lt;span class=&quot;hljs-params&quot;&gt;err, data&lt;/span&gt;) &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; (err) &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; res.status(&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-number&quot;&gt;500&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;).send({ &lt;/span&gt;&lt;span style=&quot;color: #ff0000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-attr&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-string&quot;&gt;'fail.'&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; }); res.json(data); }) }); app.get(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-string&quot;&gt;'/:name'&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-function&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot; class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; (&lt;span class=&quot;hljs-params&quot;&gt;req, res&lt;/span&gt;) &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// Semantic URL 방식으로 name을 받았다. DB에서 name을 찾아 정보를 출력&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// 1번째 인자는 쿼리, 2번째 인자는 Projection(어떤 필드를 보이고 숨길 지)&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; Person.find({ &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// (1)쿼리&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; name: req.params.name }, { &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// (2)프로젝션&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; _id: &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #ff0000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-attr&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #ff0000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-attr&quot;&gt;age&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; }, &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-function&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot; class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; (&lt;span class=&quot;hljs-params&quot;&gt;err, data&lt;/span&gt;) &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// (3)콜백 함수&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; (err) &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; res.status(&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-number&quot;&gt;500&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;).send({ &lt;/span&gt;&lt;span style=&quot;color: #ff0000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-attr&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-string&quot;&gt;'fail.'&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; }); res.json(data); }); });&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;Routing &amp;amp; CRUD 구현: 3. Update&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;app.put(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-string&quot;&gt;'/:name/:new_age'&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-function&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot; class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; (&lt;span class=&quot;hljs-params&quot;&gt;req, res&lt;/span&gt;) &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// 먼저 name에 해당하는 document를 찾는다&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; Person.findOne({ &lt;/span&gt;&lt;span style=&quot;color: #ff0000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-attr&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;: req.params.name }, &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-function&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot; class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; (&lt;span class=&quot;hljs-params&quot;&gt;err, data&lt;/span&gt;) &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; (err) &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; res.status(&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-number&quot;&gt;500&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;).send({ &lt;/span&gt;&lt;span style=&quot;color: #ff0000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-attr&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-string&quot;&gt;'fail.'&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; }); &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; (!data) &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; res.status(&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-number&quot;&gt;404&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;).json({ &lt;/span&gt;&lt;span style=&quot;color: #ff0000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-attr&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-string&quot;&gt;'data not found'&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; }); &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// document를 새 데이터로 Update&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; data.age = req.params.new_age; &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// document 저장&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; data.save(&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-function&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot; class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; (&lt;span class=&quot;hljs-params&quot;&gt;err&lt;/span&gt;) &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; (err) res.status(&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-number&quot;&gt;500&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;).json({ &lt;/span&gt;&lt;span style=&quot;color: #ff0000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-attr&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-string&quot;&gt;'failed to update'&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; }); res.json({ &lt;/span&gt;&lt;span style=&quot;color: #ff0000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-attr&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-string&quot;&gt;'data updated'&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; }); }); }); &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// 만약 Person.find()로 찾으면 data는 Array로 반환되기 때문에 data.save()가 불가능하다. (1개 고르면 되긴 함)&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// Person.findOne()을 쓰면 data는 1개의 Document기 때문에 data.save()가 가능하다.&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// find() 후 save() 하는 방법 이외에도&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;// Person.update()나 Person.findOneAndUpdate() 등 업데이트 방법은 다양하게 있다.&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; });&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;Routing &amp;amp; CRUD 구현: 4. Delete&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;app.delete(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-string&quot;&gt;'/:name'&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-function&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot; class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; (&lt;span class=&quot;hljs-params&quot;&gt;req, res&lt;/span&gt;) &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;{ Person.remove({ &lt;/span&gt;&lt;span style=&quot;color: #ff0000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-attr&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;: req.params.name }, &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-function&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot; class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; (&lt;span class=&quot;hljs-params&quot;&gt;err, output&lt;/span&gt;) &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; (err) &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; res.status(&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-number&quot;&gt;500&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;).json({ &lt;/span&gt;&lt;span style=&quot;color: #ff0000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-attr&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-string&quot;&gt;&quot;fail&quot;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; }); res.status(&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-number&quot;&gt;204&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;).end(); }) });&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;Express 웹서버 시작&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;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-comment&quot;&gt;/* Port 3000에 웹서버 시작 */&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt; app.listen(&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-number&quot;&gt;3000&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-function&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot; class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; (&lt;span class=&quot;hljs-params&quot;&gt;&lt;/span&gt;) &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-built_in&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;.log(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-string&quot;&gt;'Listening on port 3000!'&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #ffffff;&quot;&gt;);&amp;nbsp;&lt;/span&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot;&gt;});&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 보면 알겠지만, 데이터를 전달하는 방법으로 두 가지가 있는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 1. Body에&amp;nbsp;JSON으로&amp;nbsp;전달하는 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 2. URL에 Param으로 전달하는 방법 (Semantic URL)&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마침 비슷한 고민을 한 사람이 있다:&amp;nbsp;&lt;a class=&quot;tx-link&quot; href=&quot;https://blog.outsider.ne.kr/1116&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://blog.outsider.ne.kr/1116&lt;/a&gt; (Stackoverflow, Twitter, Github, Medium의 URL 패턴 간단 정리)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr class=&quot;tx-hr-border-3&quot; style=&quot;display: block; border: black 0 none; border-top: black 1px dotted; height: 1px;&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;실제로 뭔가를 만들기 위해 필요한 개념들&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Token 기반 REST API&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에는 서버 구현 시 사용자의&amp;nbsp;로그인 정보를 서버가 가지고 있었다. 이를&amp;nbsp;&lt;u&gt;세션(Session)&lt;/u&gt;이라고&amp;nbsp;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세션 방식은 서버가 계속 사용자의 정보를 들고 있어야 하므로,&amp;nbsp;서버를 확장하기 어려운 등 유연성이 제한되는 문제가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비슷하게 브라우저에서도&amp;nbsp;&lt;u&gt;쿠키(Cookie)&lt;/u&gt;를 가지고 자신의 상태를 보관하거나 서버에게서 받은 정보를 담아두었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠키의 단점은 단일 도메인 혹은 서브 도메인까지만 작동하므로, 도메인이 여러 개인 서비스를 운영 시 쿠키 관리가 어렵다는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리하자면 &lt;u&gt;세션(Session)&lt;/u&gt;이나 &lt;u&gt;쿠키(Cookie)&lt;/u&gt; 모두 '현재 상태', 즉 &lt;b&gt;State&lt;/b&gt;를 보관하는 용도로 대부분 사용되기 때문에 단점과 한계점이&amp;nbsp;많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 &lt;u&gt;Token 기반&lt;/u&gt;으로 API를 짜면 &lt;b&gt;Stateless&lt;/b&gt;로 동작한다. 사용자가 로그인 되어 있는지 등의 상태 관련 정보를 서버가 몰라도 된다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;더 자세한 개념들은 다음 링크 참고:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://velopert.com/2350&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://velopert.com/2350&lt;/a&gt; ([JWT] 토큰(Token) 기반 인증에 대한 소개)&lt;/p&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;음... 간단하게 토큰(Token)을 찜질방 비유로 생각해 보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0055ff;&quot;&gt;[로그인]:&lt;/span&gt;&lt;/b&gt; 찜질방에 입장할 때 &lt;u&gt;내 이름&lt;/u&gt;을 적고, &lt;u&gt;옷장키(Token)&lt;/u&gt;를 받는다. 옷장키는 찜질방 내 결제에 사용할 것이다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #22741c;&quot;&gt;&amp;nbsp; [Token 생성]:&lt;/span&gt;&lt;/b&gt; 옷장키(Token) 안에는 &lt;u&gt;(1)내 이름&lt;/u&gt;과 &lt;u&gt;(2)찜질방 주인의 서명&lt;/u&gt;이 들어있다. 서명으로 인해 찜질방 주인만 키&amp;nbsp;생성 가능.&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0055ff;&quot;&gt;[API 이용]:&lt;/span&gt;&lt;/b&gt; 찜질방에서 계란을 사려고 한다. &lt;u&gt;카운터(Server)&lt;/u&gt;에 &lt;u&gt;(1)계란을 사겠다는 주문(API)&lt;/u&gt;과 &lt;u&gt;(2)옷장키(Token)&lt;/u&gt;를 전달한다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #22741c;&quot;&gt;&amp;nbsp; [Token 검증]:&lt;/span&gt;&lt;/b&gt; 찜질방 주인은 &lt;u&gt;옷장키(Token)&lt;/u&gt;에 적힌 &lt;u&gt;(1)사람 이름&lt;/u&gt;과 &lt;u&gt;(2)서명&lt;/u&gt;을 본다. 서명이 올바르면 &lt;u&gt;키에 적힌&amp;nbsp;이름&lt;/u&gt;으로 구입 내역을 기록한다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;[Token 위조]:&lt;/span&gt;&lt;/b&gt; 누군가 내 이름으로 라면을 사먹으려 시도한다. 빈 옷장키(Token)에 &lt;u&gt;내 이름&lt;/u&gt;은 적었으나, &lt;span style=&quot;color: #cc3d3d;&quot;&gt;찜질방 주인의 &lt;/span&gt;&lt;span style=&quot;color: #cc3d3d;&quot;&gt;서명을 할 수 없어 실패&lt;/span&gt;&lt;span style=&quot;color: #cc3d3d;&quot;&gt;한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;[Token 탈취]:&lt;/span&gt;&lt;/b&gt; 내가 실수로 옷장키(Token)를 두고 자리를 비웠다. 누군가 &lt;u&gt;그 키를 주워&lt;/u&gt; 식혜를 사먹었다. &lt;span style=&quot;color: #cc3d3d;&quot;&gt;옷장키(Token)는 정상이므로 막을 수 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹으로 다시 말하면, 유저는 로그인 시 서버로부터 Token을 발급받는다. 그리고 이후부터는 API 사용 시마다 Token을 같이 전달하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버는 유저의 로그인 사실을 기억할 필요 없이 API 호출 시마다 Token의 유효성(Valid)만 확인하면 된다. 유저 또한 쿠키 등을 보관할 필요가 없다.&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;문제는, Token&amp;nbsp;구현에 기본적으로 암호화가 없기 때문에 Token을 탈취 당하면 공격자가 사칭을&amp;nbsp;할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 Token을 별도로 암호화 하는 기술을 사용하거나, Token의 유효 시간(Expire Time)을 짧게 하여 탈취당한 Token이 빨리 만료되도록 한다.&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;JSON Web Token (JWT)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 실제로 Token을 어떻게 구현하고 이를 REST API에 적용할 수 있는가? 웹표준으로 JWT라는 것이 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다음 사이트에서 Token의 개념을 익힐 수 있다:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://jwt.io&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://jwt.io&lt;/a&gt; (JSON Web Tokens)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://velopert.com/2389&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://velopert.com/2389&lt;/a&gt; ([JWT] JSON Web Token 소개 및 구조)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://hycszero.tistory.com/108&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://hycszero.tistory.com/108&lt;/a&gt; (JWT(JSON Web Token)로 로그인 / 로그아웃 구현하면서...)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://victorydntmd.tistory.com/115&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://victorydntmd.tistory.com/115&lt;/a&gt; ([HTTP/인증] JWT ( JSON Web Token ))&lt;/p&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;JWT는 REST API를 호출할 때 Token을 Header에 낑겨 보내는 방식을 취한다. (별도의 JSON으로 Token을 주는 것이 아니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP Header에 실으려면 JSON 형태보다는 단일 String 형태가 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 Token의 내용은 비록&amp;nbsp;JSON으로 작성되지만 최종 단계에서 이를 Base64로 인코딩하여 1개의 String으로 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JWT는 3부분으로 이뤄진다:&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Header:&lt;/b&gt; 이 Token의 정보를 담고 있다. Token의 해싱 알고리즘이 무엇인지 기록한다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Payload:&lt;/b&gt; 실제 Token의 데이터이다. 사용자 정보, 토큰 생성 시간, 만료 시간 등을 기록한다.&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Signature:&lt;/b&gt; 서버의 비밀키를 이용해&amp;nbsp;Header,Payload에 대해 해싱함으로 서명을 만든다. 따라서 비밀키가 없는 외부 공격자는 서명 생성이 불가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;----------&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭐 해싱하고 검증하고 이런 작업들이 복잡한데, 우리가 직접 할 필요는 없다. jsonwebtoken 모듈을 사용해서 실습해 볼 것이다.&lt;br /&gt;아래 코드는 Token을 생성하는 코드이다. URL에&amp;nbsp;원하는 아이디를 입력하면 토큰을 생성한다. (예: http://localhost/create/my_id)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; express = &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-built_in&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-string&quot;&gt;'express'&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; jwt = &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-built_in&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-string&quot;&gt;'jsonwebtoken'&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; app = express(); &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; secretKey = &lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-string&quot;&gt;'aw35gvaw5aw35h112'&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;; app.get(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-string&quot;&gt;'/create/:userid'&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-function&quot;&gt;&lt;span style=&quot;color: #0000ff; background-color: #eaeaea;&quot; class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;background-color: #eaeaea;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;background-color: #eaeaea;&quot; class=&quot;hljs-params&quot;&gt;req, res&lt;/span&gt;&lt;span style=&quot;background-color: #eaeaea;&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; payload = { &lt;/span&gt;&lt;span style=&quot;color: #ff0000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-attr&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;: req.params.userid }; &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; token = jwt.sign(payload, secretKey); &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-comment&quot;&gt;// Token 생성&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; res.send(token); &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-comment&quot;&gt;// Token 출력&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; }); &amp;nbsp;&lt;/span&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;app.listen(&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-number&quot;&gt;3000&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-function&quot;&gt;&lt;span style=&quot;color: #0000ff; background-color: #eaeaea;&quot; class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;background-color: #eaeaea;&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #eaeaea;&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;{});&lt;/span&gt;&lt;/p&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;핵심은 jwt.sign() 함수이다. 원래 비밀키는 길이가 길 수록 좋고 512비트 이상을 권장하지면 여기서는 편하게 아무거나 쳤다.&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;Token의 Payload는 id라는 항목만&amp;nbsp;집어넣었다. 보이진 않지만 iat(Issued At)라는 이름의 '토큰 생성 시간' 항목이&amp;nbsp;자동으로 들어가게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 위의 웹 페이지를 들어가 계속 새로고침하면 Token 내용이 시간에 따라 변하는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://jwt.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://jwt.io/&lt;/a&gt; 사이트에 들어가서 왼쪽 Encoded 칸에 우리가 만든 Token을 넣고, 오른쪽에는 Secret Key를 입력하면 즉석 Verification을 해볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;----------&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 Token 검증을 해보려 한다. 위의 코드에서 라우팅 하나만 추가하도록 하자. (예: http://localhost/verify/eyJhbGciOiJIUzI1NiIsInR5........)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;app.get(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-string&quot;&gt;'/verify/:token'&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot; class=&quot;hljs-function&quot;&gt;&lt;span style=&quot;color: #0000ff; background-color: #eaeaea;&quot; class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;background-color: #eaeaea;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;background-color: #eaeaea;&quot; class=&quot;hljs-params&quot;&gt;req, res&lt;/span&gt;&lt;span style=&quot;background-color: #eaeaea;&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; token = jwt.verify(req.params.token, secretKey); &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-comment&quot;&gt;// Token 검증&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; (token) res.send(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-string&quot;&gt;'valid!'&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; res.send(&lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-string&quot;&gt;'invalid!'&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;);&amp;nbsp;&lt;/span&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #eaeaea; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap;&quot;&gt;});&lt;/span&gt;&lt;/p&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;핵심은 jwt.verify() 함수이다. 검증 결과를 boolean으로 출력한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;----------&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 여기서 Token에 Expire Time을 10초로 하고 싶다면 Token 생성 부분에 다음과 같이 코드를 바꾸면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;jwt.sign()의 3번째 인자로 Option을 새로 준 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; options = { &lt;/span&gt;&lt;span style=&quot;color: #ff0000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-attr&quot;&gt;expiresIn&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #a31515; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-string&quot;&gt;'10s'&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; };&amp;nbsp;&lt;/span&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0000ff; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot;&gt; token = jwt.sign(payload, secretKey, options); &lt;/span&gt;&lt;span style=&quot;color: #008000; font-family: Monaco, 'Andale Mono', 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; background-color: #eaeaea;&quot; class=&quot;hljs-comment&quot;&gt;// Token 생성&lt;/span&gt;&lt;/p&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;위 코드로 생성된 Token은 10초 뒤 Verify를 해 보면 Expired 라고 뜰 것이다.&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;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;더 자세한 실습 등은 다음 링크 참고:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://victorydntmd.tistory.com/116&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://victorydntmd.tistory.com/116&lt;/a&gt; ([Node.js] JWT 기반으로 사용자 인증 구현하기 ( jsonwebtoken 모듈 ))&lt;/p&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;로그인/회원가입 기능 구현&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 Front-end는 고려하지 않고,&amp;nbsp;Back-end에서 REST API로 만들 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node에서도 세션과 쿠키를 이용한 전통적 로그인을 구현할 수 있다. cookie-parser, express-session 모듈을 사용하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 여기선 Web Token 기반 로그인을 구현할 것이다. 로그인 시 Token을 발행해 주고, 이후 API 사용 시마다 해당 Token을&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;Token은 탈취당할 수 있기 때문에 Expire Time을 짧게 하고, 대신 Refresh가 가능하도록 할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(참고로 `자동 로그인` 기능은 Token의 Expire Time을 없애는 것으로 구현할 수 있다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;만든 API를 이쁘게 Document로 적고 싶으면, 다음 레퍼런스들 참고:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://bocoup.com/blog/documenting-your-api&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://bocoup.com/blog/documenting-your-api&lt;/a&gt; (REST API DOCUMENTATION BEST PRACTICES)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;http://apidocjs.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://apidocjs.com&lt;/a&gt; (Inline Documentation for RESTful web APIs)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://trello.com/c/lBnwdKRj/22-rest-api-문서화로-어떻게-남길까&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://trello.com/c/lBnwdKRj/22-rest-api-문서화로-어떻게-남길까&lt;/a&gt; (REST API 문서화로 어떻게 남길까)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://sanghaklee.tistory.com/50&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://sanghaklee.tistory.com/50&lt;/a&gt; ([Swagger] RESTful API 문서 만들기)&lt;/p&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;다음과 같은 API를 만들 것이다. 간단한 몇 개만 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Title:&lt;/b&gt; 회원 가입&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;URL:&lt;/b&gt; http://localhost:3000/users&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Method:&lt;/b&gt; POST&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Data params:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;{&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &quot;u&quot; : {&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;username&quot;: [string],&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;password&quot;: [string],&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;name&quot;: [string],&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;email&quot;: [string]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; }&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Success Response:&lt;/b&gt; Code: 200, Content: { result: 1 }&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Error Response:&lt;/b&gt; Code 422, Content: { msg: [string] }&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Title:&lt;/b&gt; 로그인 (Token 받기)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;URL:&lt;/b&gt; http://localhost:3000/users&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Method:&lt;/b&gt; GET&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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;이제 슬슬 번듯한 사이트를 만들 것이므로 Express Generator로 프로젝트를 만들고 구조를 따라가려 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마침 기본으로 users라는 이름의 라우터가 들어 있으므로, routes/users.js에 우리의 API를 구현하면 된다. app.js에 Mongoose 모듈 로드만 해 주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하 귀찮네&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(공부하면서 계속 내용 추가 중)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(Last Update: 2019/03/11 월요일)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아아~~ IT기업 상반기에 뽑는데가 없어서 때려침ㅎㅎ 삼성가야지~&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;심심하면 글 계속 씀&lt;/p&gt;</description>
      <category>컴퓨터 공학도의 삶</category>
      <author>Acu</author>
      <guid isPermaLink="true">https://acuworld.tistory.com/70</guid>
      <comments>https://acuworld.tistory.com/70#entry70comment</comments>
      <pubDate>Thu, 21 Feb 2019 20:42:55 +0900</pubDate>
    </item>
    <item>
      <title>[취업] 2018 하반기 NC소프트 공채 1차 면접 후기</title>
      <link>https://acuworld.tistory.com/69</link>
      <description>&lt;p&gt;NC도 1차 면접에서 떨어졌다. 너무 어려웠다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;2:1 면접&lt;/b&gt;이었고, 내 지원 직무는 &lt;b&gt;게임개발&lt;/b&gt;이다.&lt;/p&gt;&lt;p&gt;서버/클라이언트 구분이 없어서, 나는 양 쪽 다 해본 경험을 어필하고 포트폴리오를 구성했다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;전반적으로 질문이&amp;nbsp;&lt;b&gt;문제해결능력&lt;/b&gt;과 &lt;b&gt;창의성&lt;/b&gt;을 보려고 했던 것 같다.&lt;/p&gt;&lt;p&gt;문제를 몇 개 예로 들면&lt;/p&gt;&lt;p&gt;- 3D 맵디자이너가 맵을 만들어왔는데, 떨어지면 가파라서 다시 올라올 수 없는 지형을 프로그래머 입장에서 어떻게 찾아낼 것인가? (구체적으로)&lt;/p&gt;&lt;p&gt;- 동접자가 100만명이 들어왔을 때, 접속중인 유저의 정보를 담은 클래스를&amp;nbsp;어떤 자료구조로 관리할 것인가? (DB 문제가 아님)&lt;/p&gt;&lt;p&gt;- 이외에도 문제 다수&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;다 현업에서 부딪히고 있는&amp;nbsp;듯한 시나리오였고, 학부생으로서는 당연히 접해보지 못한 문제이기에 그냥 내 생각대로 말했다.&lt;/p&gt;&lt;p&gt;그리고 해시함수나 트리를 이용한 서버 운영 시나리오도 몇 개 질문받았는데, 그 내용은 복잡해서 생략하겠다. 굉장히 어려웠다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;학부 기초 내용에 관한 질문도 있긴 있었는데, 서버와 클라이언트를 구성할 때 TCP/UDP 중 무엇을 쓸 것이고&amp;nbsp;그 이유를 물어봤다.&lt;/p&gt;&lt;p&gt;그리고 TCP의 특징 3가지와 같은 아느냐/모르느냐의 문제여서 전부 답했다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;결국 떨어졌는데, 여기는 그냥 실력부족으로 떨어졌다. 너무 어려웠다.&lt;/p&gt;&lt;p&gt;공부를 더 해야겠다는 생각이 든다. 포트폴리오도 부실했고.&lt;/p&gt;</description>
      <category>컴퓨터 공학도의 삶</category>
      <author>Acu</author>
      <guid isPermaLink="true">https://acuworld.tistory.com/69</guid>
      <comments>https://acuworld.tistory.com/69#entry69comment</comments>
      <pubDate>Sun, 9 Dec 2018 02:12:05 +0900</pubDate>
    </item>
    <item>
      <title>[취업] 2018 하반기 LINE 공채 1차 면접 후기</title>
      <link>https://acuworld.tistory.com/68</link>
      <description>&lt;p&gt;1차 면접에 떨어진 후기를 써본다. 떨어졌으므로 간단하게 써야지&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;3:1 면접이고 분위기는 아주 편했다. 좁은 테이블에 4명이 바싹 붙어서 팀플하는 느낌.&lt;/p&gt;&lt;p&gt;들어가면 1분 자기소개 하고, 풀었던 코딩테스트 문제에서 뭐가 인상깊거나 아쉬웠는지 간단히 물어본다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;면접은 100% 자기소개서만 가지고 하는 것 같다. 그러니까 서류 쓸 때 면접까지 생각해서 신경썼어야 했다.&lt;/p&gt;&lt;p&gt;&lt;b&gt;자기소개서에 쓰여진 경험, 팀플, 프로젝트&lt;/b&gt;에 대해서 아주 자세하게 물어본다.&lt;/p&gt;&lt;p&gt;&lt;b&gt;어떤 역할을 맡았고, 무슨 기술을 썼으며, 어떤 어려움이 있었고 어떻게 해결했는지&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그리고 &lt;b&gt;꼬리물기 질문&lt;/b&gt;이 어렵게 들어온다.&lt;/p&gt;&lt;p&gt;예를 들면 &lt;b&gt;&lt;span style=&quot;color: rgb(0, 85, 255);&quot;&gt;내가&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 85, 255);&quot;&gt;홈페이지를 만들었었다&lt;/span&gt;&lt;/b&gt; -&amp;gt; &lt;b&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;로그인 보안은?&lt;/span&gt;&lt;/b&gt; -&amp;gt; &lt;b&gt;&lt;span style=&quot;color: rgb(0, 85, 255);&quot;&gt;SSL을 썼다&lt;/span&gt;&lt;/b&gt; -&amp;gt; &lt;b&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;SSL도 뚫리는 거 알고 있느냐?&lt;/span&gt;&lt;/b&gt; -&amp;gt;&lt;span style=&quot;color: rgb(0, 85, 255);&quot;&gt; &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: rgb(0, 85, 255);&quot;&gt;모른다 첨듣는다...&lt;/span&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt; &lt;b&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;ㅇㅇ수고&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;이런 식으로 내가 모르는 내용이 나올 때까지 긁고, 면접관이 실망하는 것이 반복되었다.&lt;/p&gt;&lt;p&gt;근데 억울한게... 나도 꽤나 많이 알고있다고 생각했는데 진짜 듣도보도 못한 걸 갖고와서 물어본다ㅜ...&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그래놓고 내가 시무룩하면 &lt;b&gt;아, 어차피 학부생들한테 별로 기대하는 거 없어요&lt;/b&gt; 라고 말을 해 준다. (위로인가?)&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;일단 면접 떨어진 이유는 확실히 짐작이 간다. 내가 서류 쓸 때 생각 없이 썼다.&lt;/p&gt;&lt;p&gt;포트폴리오에 Server 관련 내용을 잔뜩 써놓고,&amp;nbsp;정작 지원 분야는 Client로 썼다. 그래서 직무가 맞질 않았다. (면접관이 직접 묻기도 했다)&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;말실수로 대답&amp;nbsp;잘못한 것도 몇 개 기억나는데, 지금 생각해보면 면접관이 전부 기회를 줬던 것이고&amp;nbsp;내가 잡지 못했다.&lt;/p&gt;&lt;p&gt;이번 하반기 첫 면접이어서 멋도 모르고 멍청하게 망쳤다. 담엔 잘하지 뭐...&lt;/p&gt;</description>
      <category>컴퓨터 공학도의 삶</category>
      <author>Acu</author>
      <guid isPermaLink="true">https://acuworld.tistory.com/68</guid>
      <comments>https://acuworld.tistory.com/68#entry68comment</comments>
      <pubDate>Mon, 3 Dec 2018 02:34:34 +0900</pubDate>
    </item>
    <item>
      <title>[취업] 2018 하반기 NC TEST 후기</title>
      <link>https://acuworld.tistory.com/67</link>
      <description>&lt;p&gt;도대체가 NC TEST 라는것은 구글에 쳐도 정보가 몇 개 없다. 내가 정보를 하나 남긴다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;NC는 수년째 NC TEST를 개포고등학교에서 보고 있는 듯하다. 구룡역이 더럽게 깊으므로 빠져나오는데 다소 오래 걸린다. 엘베 이용 바람.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;내 지원 분야는 게임개발이다.&lt;/p&gt;&lt;p&gt;&lt;b&gt;오전 인적성&lt;/b&gt; / 점심 식사 /&amp;nbsp;&lt;b&gt;오후 직무적성검사&lt;/b&gt; 시험을 보았다. 시험 응시인원은 통합 1,000명 정도 되어보였다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99637F4C5BDD589D35&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99637F4C5BDD589D35&quot; width=&quot;900&quot; height=&quot;675&quot; filename=&quot;IMG_6131.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;점심엔 도시락을 주는데 이 메뉴도 수년 째 동일한 것 같다. 제조사는 Welstory. (학식으로 지겹게 먹은...)&lt;/p&gt;&lt;p&gt;메뉴 구성은 도시락에선&amp;nbsp;호화로운 편이다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 896px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/997BE54D5BDD578B2E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F997BE54D5BDD578B2E&quot; width=&quot;896&quot; height=&quot;562&quot; filename=&quot;IMG_6132.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/990F704D5BDD578C28&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F990F704D5BDD578C28&quot; width=&quot;900&quot; height=&quot;675&quot; filename=&quot;IMG_6135.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이제 시험 얘기를 해본다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;인적성&lt;/b&gt;은 &lt;b&gt;아모레퍼시픽&lt;/b&gt;과 유형이 동일하다. 같은 연구소에서 만들었다고 한다.&lt;/p&gt;&lt;p&gt;NC TEST 문제집이 없으니 아모레 문제집을 사서 공부해야 한다. 그리고 NC는 &lt;b&gt;한국사를 제외&lt;/b&gt;했으므로 암기 부담이 적다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;나는 다음 책을 보았다: &lt;u&gt;&lt;a href=&quot;http://book.interpark.com/product/BookDisplay.do?_method=detail&amp;amp;sc.shopNo=0000400000&amp;amp;sc.prdNo=294483267&amp;amp;pis1=book&amp;amp;pis2=product&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;&lt;b&gt;2018 하반기 합격이 답이다 아모레퍼시픽그룹 인적성검사 - 종합편&lt;/b&gt;&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;&lt;p&gt;졸업논문때문에 바빠서 전날에 책을 처음 폈다. 그것도 각 유형별 연습문제만 풀고 모의고사는 안풀었다.&lt;/p&gt;&lt;p&gt;총 공부시간은 3시간 정도? 많이 푼다고 실력이 늘어나지 않을 거란&amp;nbsp;생각이 들어서 많은 시간을&amp;nbsp;들이지 않았다.&lt;/p&gt;&lt;p&gt;이럴거면 책값이 좀 아깝다... 그래도 유형 미리 알아간다는 것 정도는 도움되었다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;인적성은 딱히 팁을 줄 게 없다. 그냥 잠 푹&amp;nbsp;자고 맑은 정신으로 가는 게 좋을 것 같다.&lt;/p&gt;&lt;p&gt;그리고 볼펜/샤프 등을&amp;nbsp;쓸 수 없게 했다. 컴퓨터용 싸인펜만 사용이 허가되었다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;오후에는 &lt;b&gt;직무적성검사&lt;/b&gt;를 보았다. 이게 참 정보도 없고 해서 뭘 공부해 갈 지 몰라 이것저것 해갔는데, 결국 별 도움 안됐다.&lt;/p&gt;&lt;p&gt;다음 시험 보는 사람은 이 글을 보고 감이라도 잡고 시험장에 들어가길 바란다...&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;문제가 총 50문제였던 것 같은데 앞에 10문제 정도가 NC 회사 관련된 문제다.&lt;/p&gt;&lt;p&gt;예를 들면 &lt;b&gt;NC의 기업문화(홈페이지에 있는), NC가 만든 게임과 각 게임의 설명, 상 받은 게임, 해외 진출 현황 등등...&lt;/b&gt; 싹 다 공부해 가야 한다.&lt;/p&gt;&lt;p&gt;&lt;b&gt;NC 다이노스 문제&lt;/b&gt;도 하나 나온다. 창단일이나 연고지, 최근 성적 등등 죄다 두루두루 알아가면 될 듯.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;20문제는 &lt;b&gt;컴퓨터공학&lt;/b&gt;에 대한 내용이다. 아주 깊게는 안 물어본다. 그냥 IT기업들 필기시험 대비 하듯이 다 공부해 가면 된다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;20문제는 &lt;b&gt;C++로 된 코드&lt;/b&gt;를 주고 문제를 푸는 유형이 출제되었다. C++의 언어 자체를 아주 자세하게 물어보는&amp;nbsp;문제가 많이 나왔다.&lt;/p&gt;&lt;p&gt;예를 들면 클래스 구조, 클래스의 크기 측정(sizeof), 생성자와 파괴자의 호출 순서, 어느 시점에 객체가 자동으로 사라지는지, cout &amp;lt;&amp;lt; 함수1() &amp;lt;&amp;lt; 함수2() 같은 형태에서 호출 순서 문제 등등...&amp;nbsp;&lt;/p&gt;&lt;p&gt;그니까 C++의 어려운 응용이 아니라, '기본기'를&amp;nbsp;'아주 자세하게' 물어보는 것이다.&lt;/p&gt;&lt;p&gt;C++를 오래 전에 마지막으로 공부한 사람은 반드시 공부를 하고 가야 할 것이다. 안그러면 손도 못댈 것...&amp;nbsp;(내 얘긴가??)&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;NC TEST 결과 발표는 5일 뒤에 해 준다고 한다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그리고 합격자에 한해 온라인 코딩테스트가 추가로 있다고 한다. 코딩테스트는 올해부터 추가되었다고 한다.&lt;/p&gt;&lt;p&gt;긍정적으로 생각하면 NC TEST 합격자 배수가 늘어날 것 같고... 나쁜 점은 절차가 하나 늘었다는 거...&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;어렵다 어려워.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;&lt;b&gt;(2018.11.08 추가)&lt;/b&gt;&amp;nbsp;직무적성 망쳤는데 합격!&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;&lt;b&gt;(2018.11.15 추가)&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;&amp;nbsp;코딩테스트는 그냥 면접 때 참고하려고 하는 것&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;같다. 못 본다고 면접 떨어지는 그런게&amp;nbsp;아닌 것 같다.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;- 시간은 3문제에 1시간 30분. 난이도는&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;&amp;nbsp;카카오/라인보다 훨씬 쉬웠다.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;- 채점 기능&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;&amp;nbsp;없이 코드 저장&amp;nbsp;제출 방식이라서, Test Case를 직접 만들고&amp;nbsp;반례를 찾아야&amp;nbsp;한다.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;- 프로그래머스 사이트 이용해서 진행됨. 언어는 C/C++/Python&lt;/p&gt;</description>
      <category>컴퓨터 공학도의 삶</category>
      <author>Acu</author>
      <guid isPermaLink="true">https://acuworld.tistory.com/67</guid>
      <comments>https://acuworld.tistory.com/67#entry67comment</comments>
      <pubDate>Sat, 3 Nov 2018 17:30:47 +0900</pubDate>
    </item>
    <item>
      <title>[신호 처리] Matched Filter (Cross Correlation)</title>
      <link>https://acuworld.tistory.com/66</link>
      <description>&lt;p&gt;&lt;b&gt;Matched Filter, 정합 필터&lt;/b&gt;&lt;/p&gt;&lt;p&gt;원본 신호를 알고 있을 때, 수신된 신호에서 어느 부분이 원본 신호 부분인지 찾아낼 때 사용&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Matched Filter는 수신된 신호 중 원본 신호가 위치한 곳에서 최대가 된다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;목적은 두 신호의 유사도를 구하는 게 아니라 원본 신호 지점에서&amp;nbsp;SNR(Signal-to-Ratio)를 최대로 만드는 것인 듯&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Matched Filter의 구현은 한 쪽 신호를 뒤집어서 두 개를 Convolution한다. 그러면 두 신호가 최대로 유사한 지점에서 최대값을 가지게 됨.&lt;/p&gt;&lt;p&gt;(링크에서 Matched Filter 파트의 그림을 참고할 것:&amp;nbsp;http://blog.naver.com/PostView.nhn?blogId=moony6463&amp;amp;logNo=220072038153)&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Cross Correlation&lt;/b&gt;과 같다고 볼 수 있는데 차이점은 CC가 0을 기준으로 좌우 대칭 모양이 나오는 반면에&lt;/p&gt;&lt;p&gt;Matched Filter는 입력 소스만큼의 길이만 나온다. 즉 CC가 두 배 더 긴 결과를 출력함.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;매트랩으로 해 본 결과, Matched Filter와 Cross Correlation은 같은 결과를 내었다.&lt;/p&gt;&lt;p&gt;Cross Correlation은 Correlation이고, Matched Filter는 Reversed Signal을 Convolution 하는 것이라서&lt;/p&gt;&lt;p&gt;수식적으로 풀어보면 같은 효과라고 어디서 줏어들었음&lt;/p&gt;</description>
      <category>컴퓨터 공학도의 삶</category>
      <author>Acu</author>
      <guid isPermaLink="true">https://acuworld.tistory.com/66</guid>
      <comments>https://acuworld.tistory.com/66#entry66comment</comments>
      <pubDate>Tue, 16 Oct 2018 23:20:35 +0900</pubDate>
    </item>
    <item>
      <title>[취업] 2018 하반기 신입 LINER 코딩테스트 2차 후기</title>
      <link>https://acuworld.tistory.com/65</link>
      <description>&lt;p&gt;라인 플러스 2차 시험에 응시한 후기를 남겨본다.&lt;/p&gt;&lt;p&gt;강남 멀티캠퍼스 건물에서 시험을 봤다. 삼성에서 운영하는 컴퓨터학원(?)이라는 듯 싶다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;코딩시험 120분 + 필기 90분&lt;/b&gt; 시험을 보았다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;먼저 코딩은 &lt;b&gt;4문제&lt;/b&gt;가 나왔다. 배점은 [20,25,25,30] (의미 없지않나?) 난이도는 중간&amp;nbsp;정도.&lt;/p&gt;&lt;p&gt;대회 수준까지는 아니지만 연습 없이 가면 한 개도 못풀 것 같다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;문제가 대략 기억나는것이&lt;/p&gt;&lt;p&gt;- infix 수식 계산 문제 (stack을 이용한 문제. postfix로 변환해서 계산하면 쉽다)&lt;/p&gt;&lt;p&gt;- 주어진 문자열의 substring 중에서,&amp;nbsp;조건에 맞는 것 중&amp;nbsp;가장 긴 길이를 구하는&amp;nbsp;문제&amp;nbsp;(greedy 접근법을 써야 한다)&lt;/p&gt;&lt;p&gt;- 3번 개같은거&amp;nbsp;말로 설명안됨 -_-; 여기서 시간 다 뺏김&lt;/p&gt;&lt;p&gt;- 최단 경로 찾는 문제인데, 조건이 살짝 성가심 (DFS&amp;nbsp;쓰면 됐을 것&amp;nbsp;같은데 시간이 없어서 못풀었다)&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;필기는 &lt;b&gt;서술형 5문제&lt;/b&gt; + &lt;b&gt;빈칸 채우기 3문제&lt;/b&gt;였다.&lt;/p&gt;&lt;p&gt;&lt;b&gt;서술형&lt;/b&gt;은 주어진 코드의 출력 쓰기 문제와&amp;nbsp;암호학, 컴퓨터네트워크, Garbage Collection, Thread&amp;amp;Mutex 관련으로 나왔다.&lt;/p&gt;&lt;p&gt;&lt;b&gt;빈칸 채우기&lt;/b&gt;는&amp;nbsp;이미 대부분의 코드가 주어진 상태에서 빈 칸이 뚫려있고 그 곳에 내용을 채우는 식이었다.&lt;/p&gt;&lt;p&gt;문제 주제로는&amp;nbsp;Max-Heap과 Tree Inorder, 그리고&amp;nbsp;Compare-and-Swap (CAS) 관련 문제가 나왔다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;정말 다행히도 필기는 대략 공부했던 내용이라 일단 채워넣긴 했는데&lt;/p&gt;&lt;p&gt;코드가 일반적인 버전이 아니고 공부했던거랑 다르게 생겨서 이해를 좀 해야 했다.&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;근데 코딩을 2문제밖에 못푼 건 너무 아쉽다. 3문제면 무난하게 합격할 것 같은데 불안하네..&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;(2018.10.25 추가) 다행히 붙었다. 면접 ㄱㄱ&lt;/p&gt;</description>
      <category>컴퓨터 공학도의 삶</category>
      <author>Acu</author>
      <guid isPermaLink="true">https://acuworld.tistory.com/65</guid>
      <comments>https://acuworld.tistory.com/65#entry65comment</comments>
      <pubDate>Tue, 9 Oct 2018 22:51:29 +0900</pubDate>
    </item>
    <item>
      <title>[취업] 2018 하반기 신입 LINER 코딩테스트 1차 후기</title>
      <link>https://acuworld.tistory.com/64</link>
      <description>&lt;p&gt;9.29(토)에 라인 1차 코딩테스트+필기테스트(온라인)를 봤다.&lt;/p&gt;&lt;p&gt;시험 시간은 &lt;b&gt;코딩 2시간, 필기 1시간.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;코딩테스트&lt;/b&gt;는 2시간 4문제로 주어졌다. (작년엔 5문제였을건데?) 문제 배점은 [10,30,30,30].&lt;/p&gt;&lt;p&gt;문제 난이도는&amp;nbsp;그다지 어렵지 않았다. 4문제 전부 Python 코드 30줄 이내로 풀 수 있는 수준?&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;상세 내용은 저작권이 있어서 대략 기억나는게...&lt;/p&gt;&lt;p&gt;- Stack을 이용해 방문 노드를 기록하고, 노드 재방문 시 프로그램 종료&lt;/p&gt;&lt;p&gt;- 주어진 쿼리 String을 파싱하고,&amp;nbsp;그에 따른 적절한 행동 하기&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;근데 위 2문제 풀고 서버가 다운돼서 코테가 취소됐다. 이런...&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;필기&lt;/b&gt;는 20문제가 주어졌는데, 1시간이 빠듯했다. 객관식, 단답형, O/X 세 유형으로 나왔다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;문제 유형별로 문제 스타일은&lt;/p&gt;&lt;p&gt;- &lt;b&gt;단답형&lt;/b&gt;:&amp;nbsp;주어진 코드의 결과가 무엇인가 / 주어진 코드에서 특정 함수는 몇 번 실행되는가 등등&lt;/p&gt;&lt;p&gt;- &lt;b&gt;객관식&lt;/b&gt;: 이 개념에 대해 맞는 설명을 모두 골라라 / 주어진 코드에서 빈 칸 뚫어놓고 여기에 적합한 코드를 골라라&lt;/p&gt;&lt;p&gt;- &lt;b&gt;O/X&lt;/b&gt;: 주어진 설명이 맞는지 틀린지 골라라&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;출제 범위&lt;/b&gt;가 데이터베이스부터 네트워크와 컴퓨터구조까지 엄청 넓은데, 꽤나 깊이 있는 난이도로 물어봤다.&lt;/p&gt;&lt;p&gt;문제 하나하나가 수준이 높아서 바로 풀 수 있는 기본적인 내용은 하나도 없었던 것 같다.&amp;nbsp;&lt;strike&gt;(결국 누가누가 구글 빨리 찾나)&lt;/strike&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;결국 20문제 중 17문제밖에 못풀었는데 하필 코딩테스트가 취소돼서...&lt;/p&gt;&lt;p&gt;필기에서 걸러지지 않을까 매우 걱정이다. 3일 뒤에 결과 발표해준다는데, 부디 합격하길ㅎㅎ&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;(2018.10.05 추가)&lt;/b&gt; 붙었다~ 2차 시험을 공부해본다.&lt;/p&gt;</description>
      <category>컴퓨터 공학도의 삶</category>
      <author>Acu</author>
      <guid isPermaLink="true">https://acuworld.tistory.com/64</guid>
      <comments>https://acuworld.tistory.com/64#entry64comment</comments>
      <pubDate>Tue, 2 Oct 2018 20:31:45 +0900</pubDate>
    </item>
    <item>
      <title>[통신] OFDM(Orthogonal Frequency Division Multiplexing, 직교 주파수 분할 다중화)</title>
      <link>https://acuworld.tistory.com/63</link>
      <description>&lt;p&gt;어쩌다보니 연구에 OFDM을 써야하게 되었다. 조사한 내용을 정리해본다.&lt;/p&gt;&lt;p&gt;내 사용 목적은 (1)소리로 데이터를 전송하는 것과, (2)녹음된 소리의 Time Sync를 정확하게 맞추기 위함이다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;&lt;b&gt;&lt;span style=&quot;background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial;&quot;&gt;OFDM (Orthogonal Frequency Division Multiplexing, &lt;/span&gt;&lt;span style=&quot;background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial;&quot;&gt;직교 주파수 분할 다중화&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;&lt;p class=&quot;MsoNoSpacing&quot;&gt;직교하는 부반송파(sub-carrier)를 수십~수천 개씩 사용해서 병렬로 정보를 전송하는 기술&lt;/p&gt;&lt;p class=&quot;MsoNoSpacing&quot;&gt;기존 기법들은 Single Carrier로써, 주파수 하나만 잡고(예: FM 라디오 등등)데이터를 전송했으나, 단점이 많이 있었음&lt;/p&gt;&lt;p class=&quot;MsoNoSpacing&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;MsoNoSpacing&quot;&gt;(carrier와 channel 용어는 서로 섞여서 쓰인다)&lt;/p&gt;&lt;p class=&quot;MsoNoSpacing&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;MsoNoSpacing&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;MsoNoSpacing&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/h2&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;Multipath 환경에 강하다.&lt;/li&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;주변 사물에 부딪혀서 여러 번 겹쳐 녹음될 경우, 신호 분리가 까다로운데 이를 해결할 수 있음.&lt;/li&gt;&lt;li&gt;Single Carrier&amp;nbsp;쓸 때는&amp;nbsp;데이터를 많이 전송하려면 Higher Rate를 썼어야 했고&lt;br /&gt;그러면 Multipath 환경에서 신호가 너무 쉽게 겹친다. (목욕탕에서 말을 빨리 하는 것과 같음)&lt;/li&gt;&lt;/ul&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;OFDM은 여러 Carrier에서 데이터를 나눠서 Lower Rate로 전송한다.&lt;br /&gt;=&amp;gt; 한 비트가 오래 유지되니까 알아듣기 쉽고, 앞 신호랑 조금 겹쳐도 그 부분 걍&amp;nbsp;잘라내면 된다.&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;특정 채널의 상태가 좋지 않아도, 병렬 전송이라서 영향이 크지 않다.&lt;/li&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;SIngle Channel 였다면 신호가 아예 죽었을 것&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;대역폭을 굉장히 효율적으로 사용한다&lt;/li&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;Sub-carrier를 겹치게 배치할 수 있으므로&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;p class=&quot;MsoNoSpacing&quot;&gt;(더 많은 장점은 위키를 참고:&amp;nbsp;&lt;a href=&quot;https://ko.wikipedia.org/wiki/직교_주파수_분할_다중_방식&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://ko.wikipedia.org/wiki/직교_주파수_분할_다중_방식&lt;/a&gt;)&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;p class=&quot;MsoNoSpacing&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;&lt;b&gt;왜 Orthogonal인가?&lt;/b&gt;&lt;/h2&gt;&lt;p class=&quot;MsoNoSpacing&quot;&gt;병렬 전송에 대한 개념으로 FDM이&amp;nbsp;먼저 나왔으나 단점이 존재했다. 각 sub-carrier들이 겹치지 않아야 했으므로&amp;nbsp;Guard Band가 필요했다.&lt;/p&gt;&lt;p class=&quot;MsoNoSpacing&quot;&gt;결과적으로 대역폭(Bandwidth)를 많이 차치하여 비효율적인 배치가 된다.&lt;/p&gt;&lt;p class=&quot;MsoNoSpacing&quot; style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 597px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/994E383A5B4B646F18&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F994E383A5B4B646F18&quot; width=&quot;597&quot; height=&quot;160&quot; filename=&quot;1.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class=&quot;MsoNoSpacing&quot; style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;MsoNoSpacing&quot; style=&quot;text-align: left; clear: none; float: none;&quot;&gt;근데 어찌어찌 '직교성' 이라는것을 잘 이용하면 sub-carrier들을 겹치게 배치해도 잘 동작하게 된다. 아래처럼...&lt;/p&gt;&lt;p class=&quot;MsoNoSpacing&quot; style=&quot;text-align: left; clear: none; float: none;&quot;&gt;FDM과 비교했을 때 훨씬 많은 sub-carrier를 이용할 수 있음을 알 수 있다. Guard Band도 없다.&lt;/p&gt;&lt;p class=&quot;MsoNoSpacing&quot; style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 588px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/991E3B3C5B4B64E30E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F991E3B3C5B4B64E30E&quot; width=&quot;588&quot; height=&quot;119&quot; filename=&quot;2.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class=&quot;MsoNoSpacing&quot; style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;MsoNoSpacing&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;MsoNoSpacing&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;&lt;b&gt;OFDM 채널&amp;nbsp;배치 구조&lt;/b&gt;&lt;/h2&gt;&lt;p class=&quot;MsoNoSpacing&quot;&gt;한 Carrier의 Amplitude가 최대일 때, 다른 Carrier들의 Amplitude는 0이 되도록 스펙트럼이 절묘하게 겹쳐져 있다. (직교성)&lt;/p&gt;&lt;p class=&quot;MsoNoSpacing&quot;&gt;&lt;img src=&quot;https://i.stack.imgur.com/AeFWL.png&quot; alt=&quot;Theoretical BPSK OFDM spectrum&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;h2&gt;Guard Interval&lt;/h2&gt;&lt;div&gt;위에서 Guard Band라는 용어가 쓰였는데, 채널 사이를 분리해 주는 역할이었다. (Frequency domain)&lt;/div&gt;&lt;div&gt;이번 용어는 Guard Interval로 전혀 다른 개념이며, 전송하는 데이터 사이를 분리해 준다. (Time domain)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;예를 들어, 사우나에서 한 단어를 말하고 연달하서 다음 단어를 말하면 Multipath에 의해 첫 단어와 두 번째 단어가 겹쳐서 들린다.&lt;/div&gt;&lt;div&gt;그래서 첫 단어를 말하고 잠깐 쉬어주면(Guard Interval)&amp;nbsp;첫 단어의 Echo가 완전히 사그라 들게 되고, 이 때 두 번째 단어를 말한다.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;즉 Guard Interval은 Echo들이 완전히(혹은 충분히) 사그라 들 때까지&amp;nbsp;기다리는 시간을 의미한다.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;아래 그림은 Signal이 Multipath에 의해 3번 수신된 상황을 예시로 든 것이다.&amp;nbsp;마지막 Reflection까지를 Guard Interval로 설정했다.&lt;/div&gt;&lt;div&gt;물론 Guard Interval은 환경에 따라 매 번 개발자가&amp;nbsp;직접 지정해 줘야 하는 부분이다. 동굴 안에서는 충분히 길게 해야 할 것이고...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 300px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9925594C5B4B685133&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9925594C5B4B685133&quot; width=&quot;300&quot; height=&quot;200&quot; filename=&quot;guard_interval.gif&quot; filemime=&quot;image/gif&quot;/&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;h2&gt;&lt;b&gt;주로 쓰이는 OFDM 송수신부 구조&lt;/b&gt;&lt;/h2&gt;&lt;div&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99D24B395B4B657918&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99D24B395B4B657918&quot; width=&quot;500&quot; height=&quot;320&quot; filename=&quot;3.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;위 구조에서 Time Sync와 Cyclic Prefix 등은 빠져있음. 실제 구현하려면 위 구조보다 조금 더 복잡함.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;h2&gt;Cyclic Prefix&lt;/h2&gt;&lt;p&gt;Cyclic Extension (순환 확장)은 Multipath로 인해 발생하는 ISI(Inter Symbol Interference)를 극복하기 위해 고안된 방법이다.&lt;/p&gt;&lt;p&gt;목적은 Sub-carrier 사이의 직교성(Orthogonality)의 파괴를 방지하기 위함이다.&lt;/p&gt;&lt;p&gt;방식은 Cyclic Prefix의 경우&amp;nbsp;유효 신호의 마지막 부분 신호를 일정 부분&amp;nbsp;복사해서 앞에다가 삽입한다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;아래와 같은 데이터를 전송한다고 해보자. 3개의 Symbol이 있다.&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 447px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99D840465B4C070728&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99D840465B4C070728&quot; width=&quot;447&quot; height=&quot;91&quot; filename=&quot;3.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이를 전송하면 Multipath로 인해서 Delay를 가진 신호들이 여러 번 들어오게 된다. 아래는 Original과 2개의 Multipath를 예로 들었다.&lt;/p&gt;&lt;p&gt;잘 보면 S2의 앞부분이 S1의 Echo와 겹치기 때문에 Inter Symbol Interference가 발생하여 S2를 추출해 낼 수 없게 된다.&lt;/p&gt;&lt;p&gt;따라서 결과를 보면 S2의 앞부분이 손실되고 뒷 부분만 얻어내게 된다.&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 426px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/992A7D4B5B4C075F2B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F992A7D4B5B4C075F2B&quot; width=&quot;426&quot; height=&quot;382&quot; filename=&quot;1.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그래서 Cyclic Prefix를 두게 된다. 어려운 개념은 아니고 Symbol의 뒷부분 일부를 앞에다가 복사하는 것이다.&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 167px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99ADA64B5B4C07AA21&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99ADA64B5B4C07AA21&quot; width=&quot;167&quot; height=&quot;126&quot; filename=&quot;4.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;그리고 신호를 전송해 보면... Multipath로 겹치는 부분이 발생하더라도 결국은 S2 안에서 일어나는 일이기 때문에&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;Symbol간의 Inter Symbol Interference는 발생하지 않는다는 것을 알 수 있다.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 485px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99237A4C5B4C07F82D&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99237A4C5B4C07F82D&quot; width=&quot;485&quot; height=&quot;351&quot; filename=&quot;2.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;h2&gt;&lt;b&gt;자주 쓰이는 용어 및 개념&lt;/b&gt;&lt;/h2&gt;&lt;ul style=&quot;list-style-type: square;&quot;&gt;&lt;li&gt;FFT (Fast Fourier Transform)&lt;/li&gt;&lt;ul style=&quot;list-style-type: square;&quot;&gt;&lt;li&gt;시간 도메인 신호를 주파수 도메인으로 바꿔주는 것&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;IFFT (Inverse Fast Fourier Transform)&lt;/li&gt;&lt;ul style=&quot;list-style-type: square;&quot;&gt;&lt;li&gt;FFT를 역으로 하는것&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;ISI(Inter Symbol Interference), ICI(Inter Channel Interference)&lt;/li&gt;&lt;ul style=&quot;list-style-type: square;&quot;&gt;&lt;li&gt;Multipath로 인해 신호가 겹쳐 들리는 현상&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Modulation&lt;/li&gt;&lt;ul style=&quot;list-style-type: square;&quot;&gt;&lt;li&gt;신호를 잘 전달하기 위해 적절히 데이터를 변조하는 것 (전자쪽 용어, 신호처리 분야)&lt;/li&gt;&lt;li&gt;QPSK, 16-QAM 등등 주로 사용됨&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Cyclic Prefix&lt;/li&gt;&lt;ul style=&quot;list-style-type: square;&quot;&gt;&lt;li&gt;Guard Interval(최대 지연시간)동안의 신호를 복사해서 앞에 갖다붙이는 것&lt;/li&gt;&lt;li&gt;Guard Interval을 쓰는 이유? Multipath로 신호가 겹쳐봤자 최대 이 시간까지만 겹칠 것이라고 가정하는 것&lt;/li&gt;&lt;li&gt;쉽게 말하면 뒷쪽 신호를 짤라서 앞에 갖다붙이는 것&lt;/li&gt;&lt;li&gt;Inter Symbol Interference를 극복하기 위함 - 신호가 어느정도 겹쳐도 걍&amp;nbsp;CP를 잘라버림 (어차피 뒤에 또 나올거니까)&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;h2&gt;&lt;b&gt;[출처]&lt;/b&gt;&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%A7%81%EA%B5%90_%EC%A3%BC%ED%8C%8C%EC%88%98_%EB%B6%84%ED%95%A0_%EB%8B%A4%EC%A4%91_%EB%B0%A9%EC%8B%9D&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://ko.wikipedia.org/wiki/직교_주파수_분할_다중_방식&lt;/a&gt;&amp;nbsp;(OFDM 기본 설명 및 장단점)&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.whydsp.org/209&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://www.whydsp.org/209&lt;/a&gt; (OFDM과 CP에 대한 이해가 쉬운 설명)&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.csie.ntu.edu.tw/~hsinmu/courses/_media/wn_11fall/ofdm_new.pdf&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://www.csie.ntu.edu.tw/~hsinmu/courses/_media/wn_11fall/ofdm_new.pdf&lt;/a&gt; (영문)(설명이 그림과 함께 아주 잘 되어있음)&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://dsp.stackexchange.com/questions/20132/ofdm-transmitter-bandwidth&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://dsp.stackexchange.com/questions/20132/ofdm-transmitter-bandwidth&lt;/a&gt;&amp;nbsp;(영문)(그림 출처)&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://caesarhks.blog.me/70133244891&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://caesarhks.blog.me/70133244891&lt;/a&gt; (OFDM에 대한 간단한 설명)&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.ni.com/white-paper/3370/ko&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://www.ni.com/white-paper/3370/ko&lt;/a&gt;&amp;nbsp;(영문)(OFDM에 대한 간단한 설명)&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.radio-electronics.com/info/rf-technology-design/ofdm/ofdm-basics-tutorial.php&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://www.radio-electronics.com/info/rf-technology-design/ofdm/ofdm-basics-tutorial.php&lt;/a&gt; (영문)(OFDM 설명)&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.ktword.co.kr/abbr_view.php?m_temp1=3164&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://www.ktword.co.kr/abbr_view.php?m_temp1=3164&lt;/a&gt; (Cyclic Prefix 용어 설명)&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.telecomhall.com/what-is-cp-cyclic-prefix-in-lte.aspx&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://www.telecomhall.com/what-is-cp-cyclic-prefix-in-lte.aspx&lt;/a&gt; (영문)(Cyclic Prefix 기본 개념 설명)&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;[좋은 코드 예시들]&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;http://blog.naver.com/PostView.nhn?blogId=ykryu7&amp;amp;logNo=221256145776&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://blog.naver.com/PostView.nhn?blogId=ykryu7&amp;amp;logNo=221256145776&lt;/a&gt;&amp;nbsp;(MATLAB. 예시 코드와 설명)(실수, 허수 구조)&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.rfwireless-world.com/source-code/MATLAB/OFDM-matlab-code.html&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://www.rfwireless-world.com/source-code/MATLAB/OFDM-matlab-code.html&lt;/a&gt;&amp;nbsp;(영문)(MATLAB. 단순하며 직관적인 4-channel 코드 예시)&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.skydsp.com/publications/4thyrthesis/code.html&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://www.skydsp.com/publications/4thyrthesis/code.html&lt;/a&gt;&amp;nbsp;(MATLAB. WAV 소리 파일로 생성하는 코드. 논문에 사용된 코드라 다소 복잡함)&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://dspillustrations.com/pages/posts/misc/python-ofdm-example.html&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://dspillustrations.com/pages/posts/misc/python-ofdm-example.html&lt;/a&gt; (Python. 단계별로 아주 자세히 설명해 주는 코드 예시)&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://wisechoding.tistory.com/41&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://wisechoding.tistory.com/41&lt;/a&gt; (MATLAB, 단계별 OFDM 시뮬레이션)&lt;/p&gt;</description>
      <category>컴퓨터 공학도의 삶</category>
      <author>Acu</author>
      <guid isPermaLink="true">https://acuworld.tistory.com/63</guid>
      <comments>https://acuworld.tistory.com/63#entry63comment</comments>
      <pubDate>Mon, 16 Jul 2018 00:31:46 +0900</pubDate>
    </item>
    <item>
      <title>[머신러닝] Windows에 TensorFlow 설치하기</title>
      <link>https://acuworld.tistory.com/60</link>
      <description>&lt;p&gt;공식 설치 메뉴얼:&amp;nbsp;https://www.tensorflow.org/install/install_windows&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;TensorFlow 설치 전에 먼저 깔아야 하는 것들(Requirements)&lt;/p&gt;&lt;p&gt;- CUDA Toolkit 8.0&lt;/p&gt;&lt;p&gt;- cuDNN v6.1&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;주의할 점은 위&amp;nbsp;requirement들을 최신 버전으로 깔면 TensorFlow가 지원을 안함 ㅡㅡ;;&lt;/p&gt;&lt;p&gt;현재 CUDA 9.1과 cuDNN 7이 최신이라 홈페이지 메인에 떡하니 있는데, 좋다고 넙죽 받아서 설치하면 당연 안되고&lt;/p&gt;&lt;p&gt;꽁꽁 숨어있는 Legacy 다운로드 메뉴로 들어가서 굳이 구버전을 깔아야 함&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;CUDA Toolkit은 크기가 좀 커서 그렇지(1.5GB) 그냥 깔면 되고&lt;/p&gt;&lt;p&gt;cuDNN은 받아서 압축 풀면 dll이 튀어나오는데, 적절히 원하는 폴더에 넣고 환경 변수에 해당 경로를 박아야 함&lt;/p&gt;&lt;p&gt;예를 들어&amp;nbsp;C:\Program Files\cudnn 폴더 만들고 그 안에&amp;nbsp;cudnn64_5.dll를 넣었으면 그 경로를&amp;nbsp;%PATH%에 박고 재부팅ㄱ&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;TensorFlow가 잘 깔렸는지 확인하는 파이썬 스크립트:&lt;/p&gt;&lt;p&gt;https://gist.github.com/mrry/ee5dbcfdd045fa48a27d56664411d41c#file-tensorflow_self_check-py&lt;/p&gt;</description>
      <category>컴퓨터 공학도의 삶</category>
      <author>Acu</author>
      <guid isPermaLink="true">https://acuworld.tistory.com/60</guid>
      <comments>https://acuworld.tistory.com/60#entry60comment</comments>
      <pubDate>Thu, 4 Jan 2018 15:11:59 +0900</pubDate>
    </item>
    <item>
      <title>[소리/음향] 샘플링(Sampling) 및 관련 이론</title>
      <link>https://acuworld.tistory.com/59</link>
      <description>&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[Sampling]&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이 세상의 소리(Sound)라는 것은 아날로그이기에 Linear 하다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;그런데 컴퓨터는 디지털이므로 이 Linear한 소리를 Discrete 한&amp;nbsp;데이터로 변환해야 한다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;아날로그는 거의 무한대의 해상도를 가지므로 이것을 그대로 디지털로 표현하는 건 불가능하다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 그 일부분만 채취(샘플링)하여 최대한 원본과 유사한 디지털 데이터를 만들어야 한다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이러한 과정 또는&amp;nbsp;행위를 샘플링이라 한다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;용어가 몇 개 있다:&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;(1) 샘플링 레이트(Sampling Rate) : 1초에 몇 개의 샘플을 추출할 것인지&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;(2) Bit Depth : 한 개의 샘플이 얼마만큼의 정확도/단계를 가지는지&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;샘플링 레이트가 높을 수록 아날로그와 유사한 모양의 데이터를 얻을 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;아래 그림은 샘플링 레이트에 따른 디지털 데이터의 모양을 나타낸다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;잘게 쪼갤 수록 아날로그의 것과 같이 부드러운 곡선이 되는 것(=원본에 가까움)을 확인할 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;더불어서 각 샘플(sample)이 표현할 수 있는 값의 범위를 sample size 라고 한다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;하나의 샘플이 0부터 1까지의 값을 표현할 것인데 이를 얼마나 정밀하게 표현할 것인가...&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 샘플 사이즈가 3 bit라면 8단계로 표현 가능할 것이다. (0.0, 0.125, 0.25, 0.375, ...)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;438&quot; data-origin-height=&quot;506&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/2110004358CA7A720A?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/2110004358CA7A720A?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/2110004358CA7A720A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F2110004358CA7A720A&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;438&quot; height=&quot;506&quot; data-origin-width=&quot;438&quot; data-origin-height=&quot;506&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;(출처: http://www.morphfx.co.uk/music/edu-sampling.htm)&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 아날로그를 디지털로 샘플링 시 필요한 용량은 Sample Rate와 Sample Size의 곱이다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어보자. 우리가 일반적으로 구입할 수 있는 음반 CD의 스펙은 44,100 Hz, 16-bit 이다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이는 1초에 44100개의 샘플을 추출하고, 각 샘플의 크기는 16 bit 라는 것이다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 둘을 곱하면 705,600 bit가 1초를 표현하는 데 사용된다. (88,200 byte = 86.13 KB)&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이론상 4분짜리 곡은 20.15 MB가 필요할 것이다. 실제로 WAV, PCM 등의 무손실이면 이 용량이 나온다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[나이퀴스트 샘플링 이론(Nyquist&amp;ndash;Shannon sampling theorem)]&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;왜 대부분의 MP3 파일, 혹은 하드웨어들이 44,100 hz 스펙을 가지고 있는지 대충 납득할 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이 이론의 결론을 요약하면 다음과 같다:&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em;&quot; data-ke-size=&quot;size16&quot;&gt;A sufficient sample-rate is therefore 2B samples/second, or anything larger.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;margin-left: 2em;&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;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;p data-ke-size=&quot;size16&quot;&gt;우선 앨리어싱(Aliasing)이라는 개념이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원본을 샘플링하여 새로이 구성된 데이터가 &lt;u&gt;원본과 다를 때&lt;/u&gt;&lt;u&gt; 발생하는 왜곡&lt;/u&gt;이나 아티팩트를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;샘플링 레이트가 충분히 높지 않다면 샘플된 데이터는 원본 데이터를 충분히 표현하지 못한다. &lt;span style=&quot;caret-color: auto; letter-spacing: 0px;&quot;&gt;당연한 말이다.&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;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;296&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/2548483658CA7F2039?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/2548483658CA7F2039?original&quot; data-alt=&quot;충분히 큰 해상도로 촬영하여, 벽돌의 규칙적인 모양을 잘 표현한 사진&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/2548483658CA7F2039&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F2548483658CA7F2039&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;296&quot; height=&quot;360&quot; data-origin-width=&quot;296&quot; data-origin-height=&quot;360&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;충분히 큰 해상도로 촬영하여, 벽돌의 규칙적인 모양을 잘 표현한 사진&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p style=&quot;text-align: left; clear: none; float: none;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;205&quot; data-origin-height=&quot;250&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/272C5B3658CA7F203C?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/272C5B3658CA7F203C?original&quot; data-alt=&quot;낮은 해상도로 촬영하였기에 벽돌의 연속적인 패턴을 제대로 표현하지 못하는 모습&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/272C5B3658CA7F203C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F272C5B3658CA7F203C&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;205&quot; height=&quot;250&quot; data-origin-width=&quot;205&quot; data-origin-height=&quot;250&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;낮은 해상도로 촬영하였기에 벽돌의 연속적인 패턴을 제대로 표현하지 못하는 모습&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 건물은 벽돌이 연속성을 가지고 배치되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 낮은 해상도로 사진을 찍을 경우 벽돌의 연속성을 제대로 표현하지 못하고 원본과 다른 왜곡된 모습을 표현하게 된다. 마치 시멘트가 좀 더 많이 발려진 것 같이 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유는 갈색 벽돌 부분과 흰색 시멘트라는 두 요소를 조화롭게 샘플링해야 하는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;샘플링 비율이 한 쪽에 치우치게 되면 원래의 모양이 왜곡된 것처럼 보이는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;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;혹은 눈속임으로 샘플들 사이를 비벼버리는 테크닉도 있다. (anti-aliasing)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시그널 프로세싱은 이러한 아다리를 지향한다고 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떻게 하면 최대한 적은 샘플링으로 원본의 특징을 그대로 살릴 수 있을지...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 관련하여 나이퀴스트는 Aliasing이 발생하지 않는 샘플링 레이트를 대역폭의 2배라고 제시한 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련해서 자세한 내용은 관련&amp;nbsp;논문 참고:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;http://medialab.sjtu.edu.cn/teaching/DIP/Projects/chapter_bas/ShannonTheoremTutorial.pdf&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;사람이 소리로 들을 수 있는 가청 주파수의 범위는 20~20,000 Hz 으로 알려져 있다. (나는 16,000 까지밖에 안들리던데...)&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;즉 데이터의 대역폭이 20 KHz라는 것인데, 이를 왜곡(Aliasing 등)&amp;nbsp;없이 샘플링 하려면&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;대역폭의 2배인 40 KHz 샘플링 레이트 이상으로 샘플링 해야한다는 이론이다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 이론상의 최소 요구가 2배라는 것이고, real-world에서는 8배 정도가 안전하다는 얘기를 엔지니어들이 종종 한다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;그렇기 때문에 192 kHz 까지 사용하는 Hi-Fi 업계가 존재하는 것으로 보인다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;현재는 44,100Hz와 48,000Hz가 범용적으로 가장 많이 사용되고 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: left; margin-left: 2em;&quot; data-ke-size=&quot;size16&quot;&gt;44,100hz : 25FPS PAL, 30FPS NTSC&lt;/p&gt;
&lt;p style=&quot;text-align: left; margin-left: 2em;&quot; data-ke-size=&quot;size16&quot;&gt;48,000hz : 29.97FPS NTSC&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[Sources]&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;https://en.wikipedia.org/wiki/Sampling_(signal_processing)&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;https://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;https://en.wikipedia.org/wiki/Aliasing&lt;/p&gt;</description>
      <category>컴퓨터 공학도의 삶</category>
      <author>Acu</author>
      <guid isPermaLink="true">https://acuworld.tistory.com/59</guid>
      <comments>https://acuworld.tistory.com/59#entry59comment</comments>
      <pubDate>Thu, 16 Mar 2017 21:16:43 +0900</pubDate>
    </item>
    <item>
      <title>TS140 전원 버튼 고장 시 대처법</title>
      <link>https://acuworld.tistory.com/58</link>
      <description>&lt;p&gt;최근 서버가 자꾸 shutdown 되는 상황이 발생하여 로그를 살펴보았습니다.&lt;/p&gt;&lt;p&gt;사용중인 운영체제는 CentOS 7 64비트입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border-style: solid; border-width: 1px; border-color: rgb(203, 203, 203); background-color: rgb(255, 255, 255); padding: 10px;&quot;&gt;&lt;p&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;;&quot;&gt;cat /var/log/messages | grep 'System is powering down.'&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;불규칙적으로 서버가 꺼지는 현상이 발생했는데, 신기하게도 비정상 종료가 아니라 정상 종료(Shutdown)였습니다.&lt;/p&gt;&lt;p&gt;파워나 보드 등의 부품 문제로 인한 갑작스런 전원 종료는&amp;nbsp;아닌 것입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;누군가 리눅스를 일부러 끄고 있다는 생각이 들어 해킹을 의심했으나, 로그에서 다음과 같은 부분을 발견했습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border-style: solid; border-width: 1px; border-color: rgb(203, 203, 203); background-color: rgb(255, 255, 255); padding: 10px;&quot;&gt;&lt;p&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;;&quot;&gt;Jan 10 22:23:31 localhost systemd-logind: &lt;b&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;Power key pressed.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;;&quot;&gt;Jan 10 22:23:31 localhost systemd-logind: &lt;b&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;Powering Off...&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;놀랍게도 &lt;b&gt;전원 버튼이 눌려&lt;/b&gt; 시스템이 꺼지고 있었습니다. 그런데 주변에 물어봐도 아무도 누른 사람이 없습니다.&lt;/p&gt;&lt;p&gt;이 상태로 한 2주 지나니까 이젠 시스템을 켜면 3초 안에 자동으로 꺼집니다. 그리고 다시 알아서 켜지고,&amp;nbsp;반복됩니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;전원 버튼 고장으로 결론을 내릴 수밖에 없는 상황입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그런데 이미 제 TS140은 구입 후 1년이 경과하여 무상 RMA 불가하고, 해외 수입 제품이므로 국내 유상 A/S도 불가능합니다.&lt;/p&gt;&lt;p&gt;TS140 Front Bezel을 구입하여 교체하면 되지만 일단 당장 서버를 살리고 봐야 하니 나중으로 미룹니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;메인보드의 우측하단에 전면부 패널과의 연결 케이블이 있습니다.&lt;/p&gt;&lt;p&gt;이 케이블을 Plug-Out 하였더니&amp;nbsp;시스템이 꺼졌다 켜졌다 하는 일은 사라졌습니다.&lt;/p&gt;&lt;p&gt;아무래도 전원 버튼 고장이 확실해 보입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 541px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/2648DA465878588F0A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F2648DA465878588F0A&quot; width=&quot;541&quot; height=&quot;362&quot; filename=&quot;IMG_0089.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그런데 전원 버튼 연결선을 뽑아버렸으니 컴퓨터를 켤 방법이 없어졌습니다.&lt;/p&gt;&lt;p&gt;전원 시그널 핀 2개를 드라이버로 쇼트 내면 켜지긴 합니다만, 이걸 매 번 옆커버 따서 할 수는 없는 일입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그래서 꼼수를 써 봅니다. 부팅 시 F1을 눌러 CMOS를 들어가면 파워 설정이 있습니다.&lt;/p&gt;&lt;p&gt;이 중에서 '전원 케이블이 연결되면 자동으로 시스템이 켜지도록' 하는 옵션이 존재합니다.&lt;/p&gt;&lt;p&gt;이 옵션을 ON으로 하여, 전원선을 뽑았다 꽂으면 시스템이 켜지도록 하였습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/244E8B465878591F1B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F244E8B465878591F1B&quot; width=&quot;700&quot; height=&quot;241&quot; filename=&quot;IMG_0117.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;전원을 끄는 것은 문제가 없습니다.&amp;nbsp;리눅스에서 shutdown 명령어로 종료하도록 합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;일단 이렇게 조치하여, Front Bezel이 도착할 때까지는 운영이 가능하겠습니다.&lt;/p&gt;</description>
      <category>컴퓨터 공학도의 삶</category>
      <author>Acu</author>
      <guid isPermaLink="true">https://acuworld.tistory.com/58</guid>
      <comments>https://acuworld.tistory.com/58#entry58comment</comments>
      <pubDate>Fri, 13 Jan 2017 13:36:34 +0900</pubDate>
    </item>
    <item>
      <title>Mac OS X에 Java 8 설치하기</title>
      <link>https://acuworld.tistory.com/56</link>
      <description>&lt;p&gt;맥(Mac OS X)에 Java 8 (JRE, JDK, jdk1.8) 설치하는 방법입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;기존에 Legacy Java 6(2015-001)을 설치했더라도 상관 없습니다.&lt;/p&gt;&lt;p&gt;두 Java는 서로 영향 없이 맥에 공존하게 됩니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 12pt;&quot;&gt;1. &lt;/span&gt;&lt;span style=&quot;font-size: 12pt;&quot;&gt;다운로드 및 설치&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;우선 말씀드릴 점은, 여러가지 사유로 인해 JRE보다 JDK를 설치하는게 일이 간단합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;어차피 Java 8 설치하시는 분들은 Eclipse 혹은 관련 개발을 위함이라 생각되기 때문에&lt;/p&gt;&lt;p&gt;JRE는 건너뛰고 JDK를 설치하도록 합니다. (JDK는 JRE를 포함하고 있습니다.)&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 12pt;&quot;&gt;2. 터미널 명령어 java를 jre1.8로 연결&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;현재 상태에서 터미널에&amp;nbsp;&lt;span style=&quot;font-family: Menlo; font-size: 11px;&quot;&gt;java -version&lt;/span&gt;&amp;nbsp;을 치면 두 가지 케이스로 나눠지는데&lt;/p&gt;&lt;p&gt;&amp;nbsp; 첫째는, 아무런 Java를 설치하지 않아 설치 창이 튀어나오는 경우&lt;/p&gt;&lt;p&gt;&amp;nbsp; 둘째는, java 1.6.0이 설치되어 있다고 나오는 경우&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;어쨌거나 두 케이스 다 Java 8과는 연결되지 않기 때문에 새로이 연결하도록 합시다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;본 작업은 /usr/bin 디렉토리 내의 파일을 변경하므로, rootless 기능을 꺼야 가능합니다.&lt;/p&gt;&lt;p&gt;끄는 방법은 구글링을 하시기 바랍니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-right: 0px; margin-left: 0px; font-size: 11px; line-height: normal; font-family: Menlo;&quot;&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures&quot;&gt;ls /Library/Java/JavaVirtualMachines&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-right: 0px; margin-left: 0px; font-size: 11px; line-height: normal; font-family: Menlo;&quot;&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;위 명령어로 현재 설치된 jdk1.8의 폴더명을 알아냅니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-right: 0px; margin-left: 0px; font-size: 11px; line-height: normal; font-family: Menlo;&quot;&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures&quot;&gt;sudo rm /usr/bin/java&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;margin-right: 0px; margin-left: 0px; font-size: 11px; line-height: normal; font-family: Menlo;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;margin-right: 0px; margin-left: 0px; font-size: 11px; line-height: normal; font-family: Menlo;&quot;&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures&quot;&gt;sudo ln -s /Library/Java/JavaVirtualMachines/&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;jdk1.8.0_91.jdk&lt;/span&gt;/Contents/Home/bin/java /usr/bin/java&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-size: 12pt;&quot;&gt;3. 끝&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;연결이 끝났습니다.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: Menlo; font-size: 11px;&quot;&gt;java -version &lt;/span&gt;을 쳐서 Java 1.8.0 버전을 확인하고 기분 좋아하도록 합니다.&lt;/p&gt;</description>
      <category>컴퓨터 공학도의 삶</category>
      <author>Acu</author>
      <guid isPermaLink="true">https://acuworld.tistory.com/56</guid>
      <comments>https://acuworld.tistory.com/56#entry56comment</comments>
      <pubDate>Mon, 6 Jun 2016 16:28:38 +0900</pubDate>
    </item>
    <item>
      <title>StartSSL에서 발급받은 SSL 인증서 아파치(Apache) 서버에 적용하기</title>
      <link>https://acuworld.tistory.com/55</link>
      <description>&lt;p&gt;StartSSL에서 인증서 발급 받는 방법은 &lt;b&gt;&lt;a href=&quot;http://blog.acu.pe.kr/54&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;&lt;u&gt;해당 글&lt;/u&gt;&lt;/a&gt;&lt;/b&gt;에서 확인하시기 바랍니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;- 본 글은 RedHat 계열 기준으로 작성되었습니다. Debian, Ubuntu는 내용이 다릅니다.&lt;/p&gt;&lt;p&gt;- 본 글은 CentOS 7 기준으로 작성되었으며, 아파치는 yum 기반 설치를 가정합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;1. 아파치 SSL 모듈 설치&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(243, 197, 52); background-color: rgb(254, 254, 184); padding: 10px;&quot;&gt;&lt;p&gt;yum -y install mod_ssl&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;2. 서버에&amp;nbsp;인증서 저장&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(243, 197, 52); background-color: rgb(254, 254, 184); padding: 10px;&quot;&gt;&lt;p&gt;mkdir /etc/httpd/conf/ssl&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;# /etc/httpd/conf/ssl 경로에 아래의&amp;nbsp;인증서 파일들을&amp;nbsp;저장합니다.&lt;/p&gt;&lt;p&gt;# 경로는 바뀌어도 상관 없습니다. 아래 4번 항목에서 해당 경로를 수정해 주면 됩니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;# 넣어야 하는 인증서 관련 파일:&lt;/p&gt;&lt;p&gt;# &amp;nbsp; &amp;nbsp;&amp;nbsp;acu.pe.kr.crt (도메인&amp;nbsp;인증서)&amp;nbsp;&lt;span style=&quot;color: rgb(140, 140, 140);&quot;&gt;(StartSSL에서 제공하는 zip 파일에 동봉)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;# &amp;nbsp; &amp;nbsp; private.key (비밀키)&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;# 인증서 파일들에 대한 권한 설정&lt;/p&gt;&lt;p&gt;chown -R root.root /etc/httpd/conf/ssl&lt;/p&gt;&lt;p&gt;chmod -R 644 /etc/httpd/conf/ssl&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;3. 아파치 설정 파일(httpd.conf)에&amp;nbsp;SSL 모듈 로드,&amp;nbsp;옵션 파일&amp;nbsp;추가&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(243, 197, 52); background-color: rgb(254, 254, 184); padding: 10px;&quot;&gt;&lt;p&gt;vi /etc/httpd/conf/httpd.conf&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;# 아래 내용 추가 (빨간 부분을 서버에 맞게 수정)&lt;/p&gt;&lt;p&gt;LoadModule ssl_module modules/mod_ssl.so&lt;/p&gt;&lt;p&gt;Listen 443&lt;/p&gt;&lt;p&gt;&amp;lt;VirtualHost *:443&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; ServerName &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;acu.pe.kr&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; ServerAlias &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;www.acu.pe.kr&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; DocumentRoot &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;/var/www/html&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; SSLEngine on&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; SSLCertificateFile&amp;nbsp;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;/etc/httpd/conf/ssl/&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;acu.pe.kr.cr&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;t&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; SSLCertificateKeyFile&amp;nbsp;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;/etc/httpd/conf/ssl&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;/private.key&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;lt;/VirtualHost&amp;gt;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;4. 아파치 재시작&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(243, 197, 52); background-color: rgb(254, 254, 184); padding: 10px;&quot;&gt;&lt;p&gt;systemctl restart httpd&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;# 아파치 실행 시 비밀키(private.key)의 pass phrase를 물어봅니다.&lt;/p&gt;&lt;p&gt;# 비밀키를 생성할 때 입력했던 비밀번호를 입력하시면 됩니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;# 아파치를&amp;nbsp;실행할&amp;nbsp;때마다 pass pharase를 입력하기가 귀찮으시면&lt;/p&gt;&lt;p&gt;# 인증서에 아예 비밀번호를 입력시킬 수 있습니다.&lt;/p&gt;&lt;p&gt;openssl rsa -in /etc/httpd/conf/ssl/private.key -out /etc/httpd/conf/ssl/private.key&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;# 단, 이렇게 되면 이제부터&amp;nbsp;개인키 파일이 외부로 노출되어서는 절대 안됩니다.&lt;/p&gt;&lt;p&gt;# 또한 작업하기 전의 원본 파일을 별도로 백업해 두시기 바랍니다. (갱신 시 필요)&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;5. SSL 적용 테스트&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;테스트 사이트:&amp;nbsp;&lt;a href=&quot;https://www.digicert.com/help/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://www.digicert.com/help/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;*. 에러 발생 시&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(254, 137, 67); background-color: rgb(254, 222, 199); padding: 10px;&quot;&gt;&lt;p&gt;이런 메시지가 출력되면 실행에 실패한 것임:&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;Job for httpd.service failed because the control process exited with error code.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;왜 실행이 실패했는 지 로그 확인:&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;systemctl status -l httpd&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;txc-textbox&quot; style=&quot;border: 1px dashed rgb(159, 211, 49); background-color: rgb(231, 253, 181); padding: 10px;&quot;&gt;&lt;p&gt;&lt;b&gt;문제:&lt;/b&gt; (98)Address already in use: AH00072: make_sock: could not bind to address [::]:443&lt;/p&gt;&lt;p&gt;&lt;b&gt;이유:&lt;/b&gt; 다른 프로세스가 443 포트를 이미 사용중이므로, 해당 프로세스를 종료해야 함&lt;/p&gt;&lt;p&gt;&lt;b&gt;해결:&lt;/b&gt; netstat -tunap | grep 443 명령어로 어떤 프로세스가 사용중인지 확인 후 종료&lt;/p&gt;&lt;p&gt;&lt;b&gt;해결:&lt;/b&gt;&amp;nbsp;해결이 안되면 아파치 설정에 Listen 443이 중복 선언된 것, 따라서 주석 처리&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;문제:&lt;/b&gt; 홈페이지 접속 시 신뢰할 수 없는 인증서 메시지가 출력됨&lt;/p&gt;&lt;p&gt;&lt;b&gt;증상:&lt;/b&gt; 서버의 인증서(crt)와 브라우저에 나타난 인증서의 지문(fingerprint)이&amp;nbsp;같지 않음&lt;/p&gt;&lt;p&gt;&lt;b&gt;증상:&lt;/b&gt;&amp;nbsp;Common Name(CA)에 이상한 랜덤 숫자가 표시됨&lt;/p&gt;&lt;p&gt;&lt;b&gt;이유:&lt;/b&gt;&amp;nbsp;인증서가 아파치에 제대로 로드되지 않아 엉뚱한 인증서를 클라이언트에 제공함&lt;/p&gt;&lt;p&gt;&lt;b&gt;해결:&lt;/b&gt;&amp;nbsp;httpd.conf의 VirtualHost 443이&amp;nbsp;도메인을 잘 낚아채도록 수정&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>컴퓨터 공학도의 삶</category>
      <author>Acu</author>
      <guid isPermaLink="true">https://acuworld.tistory.com/55</guid>
      <comments>https://acuworld.tistory.com/55#entry55comment</comments>
      <pubDate>Tue, 12 Apr 2016 12:25:22 +0900</pubDate>
    </item>
    <item>
      <title>StartSSL 무료 인증서 발급 방법</title>
      <link>https://acuworld.tistory.com/54</link>
      <description>&lt;p&gt;StartSSL 사이트에서&amp;nbsp;무료로 1년 사용 가능한 SSL 인증서를 발급받을 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;1. 사이트 접속 (&lt;a href=&quot;https://www.startssl.com&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://www.startssl.com&lt;/a&gt;) 및 회원&amp;nbsp;가입&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;오른쪽 상단의 Sign-up을 눌러 회원 가입을 진행합니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/241D2134570C4C6930&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F241D2134570C4C6930&quot; width=&quot;500&quot; height=&quot;313&quot; filename=&quot;스크린샷 2016-04-12 오전 9.33.45.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;StartSSL 사이트는&amp;nbsp;흔히 알던 &lt;b&gt;아이디-비밀번호&lt;/b&gt; 방식이 아닌 &lt;b&gt;이메일-인증서&lt;/b&gt; 방식입니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;이메일을 입력하고 인증번호 단계를 거치면 브라우저에 인증서를 발급하여 저장해 줍니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;인증서가 곧 ID와 같은 역할을 해 줍니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/271D6534570C4C6B30&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F271D6534570C4C6B30&quot; width=&quot;500&quot; height=&quot;175&quot; filename=&quot;스크린샷 2016-04-12 오전 9.34.05.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;인증번호 입력 과정이 끝나면 브라우저에 인증서가 발급됩니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;(주의: 포멧 등의 사유로 인증서가 브라우저에서 삭제되지 않도록 주의 바랍니다.)&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;Login Now 버튼을 눌러 로그인에 진입합니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/2355D734570C4C6B01&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F2355D734570C4C6B01&quot; width=&quot;500&quot; height=&quot;230&quot; filename=&quot;스크린샷 2016-04-12 오전 9.35.50.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;2. 로그인&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;브라우저의 인증서를 통해 1차로 인증이 완료되면 OTP 단계에 진입합니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;인증서를 선택하고 로그인을 시도하면, 이메일로 일회용 비밀번호가 발급됩니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;이메일로 전송된&amp;nbsp;일회용 비밀번호를 입력하여 로그인합니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/2255DC34570C4C6C01&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F2255DC34570C4C6C01&quot; width=&quot;500&quot; height=&quot;145&quot; filename=&quot;스크린샷 2016-04-12 오전 9.36.27.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;3. 도메인 인증 (소유권 주장)&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;SSL 인증서를 발급받기 전에, 먼저 해야 하는 단계가 있습니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;인증서를 발급받고자 하는 도메인에 대한 소유권을 인증해야&amp;nbsp;해야 합니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;도메인의 소유자만 해당&amp;nbsp;도메인에 대해 인증서를 발급할 수 있습니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;제3자가 내 도메인 이름으로 인증서를 발급하고,&amp;nbsp;피싱 페이지를 만들 수도 있기 때문이죠.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;Validations Wizard 버튼을 눌러 해당 메뉴로 진입합니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/27132334570C4C6D37&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F27132334570C4C6D37&quot; width=&quot;500&quot; height=&quot;313&quot; filename=&quot;스크린샷 2016-04-12 오전 9.37.09.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;맨 위의 '도메인 인증'을 선택하고 진행합니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/231BCE34570C4C6E31&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F231BCE34570C4C6E31&quot; width=&quot;500&quot; height=&quot;113&quot; filename=&quot;스크린샷 2016-04-12 오전 9.37.13.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;인증받고자 하는 도메인을 입력합니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/2154BA34570C4C6F02&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F2154BA34570C4C6F02&quot; width=&quot;500&quot; height=&quot;166&quot; filename=&quot;스크린샷 2016-04-12 오전 9.37.43.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;해당 도메인을 소유하고 있는지를 도메인 메일 인증을 통해 처리합니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;부득이하게 도메인 메일이 없거나, webmaster같은 이메일 계정이 없어서 인증이 어렵다면&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;또 다른 인증 방식인 website control validation을 통해&amp;nbsp;인증 가능합니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;(주어지는&amp;nbsp;html 파일을 웹사이트 루트에 업로드하여 이를 검사하는&amp;nbsp;방식입니다.)&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/2618D834570C4C6F34&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F2618D834570C4C6F34&quot; width=&quot;500&quot; height=&quot;252&quot; filename=&quot;스크린샷 2016-04-12 오전 9.58.20.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;도메인에 대한 인증(소유권)이 완료되었습니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;Order SSL 버튼을 통해 인증서 발급 단계로 진입합니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/2153C234570C4C7003&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F2153C234570C4C7003&quot; width=&quot;500&quot; height=&quot;92&quot; filename=&quot;스크린샷 2016-04-12 오전 9.58.50.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;4. 인증서 발급&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;호스트네임을 입력합니다. 무료 인증서는 5개까지 입력 가능합니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;첫 번째 줄에 입력된 호스트네임이 인증서의 common name이 됩니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;일반적으로&amp;nbsp;www를 포함한 도메인과 포함하지 않은 도메인을 입력합니다. (총 2개)&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/25714049570C75E82C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F25714049570C75E82C&quot; width=&quot;500&quot; height=&quot;213&quot; filename=&quot;스크린샷 2016-04-12 오전 10.05.59.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;SSL/TLS는 공개키 암호 방식을 사용하기 때문에 &lt;b&gt;공개키&lt;/b&gt;와 &lt;b&gt;비밀키&lt;/b&gt;를 생성해야 합니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;더불어서 인증서에 &lt;b&gt;추가 정보&lt;/b&gt;(회사명, 기관명, 회사 주소, 이메일 등)를 입력해야 합니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;공개키와 추가 정보를 합친 파일을 &lt;b&gt;Certificate Signing Request(CSR)&lt;/b&gt; 이라고 합니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;이 파일은 우리가 손으로 직접 만들 수는 없고 Tool을 사용하여 생성해야 합니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;b&gt;비밀키&lt;/b&gt;를 먼저 만들고, 비밀키를 사용하여 &lt;b&gt;공개키&lt;/b&gt;를 생성하게 됩니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;일반적으로&amp;nbsp;비밀키는&amp;nbsp;&lt;u&gt;랜덤한 값&lt;/u&gt;으로 만들기 때문에, 이 역시 Tool이 알아서 해 줄 것입니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;리눅스에서는 빨간 글씨로 제공된 openssl 명령어를 통해,&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;윈도우 상에서는 제공되는 StartComTool.exe 프로그램을 통해 생성 가능합니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;위 Tool을 사용한다면 &lt;b&gt;비밀키(key)&lt;/b&gt; 파일과 &lt;b&gt;공개키+추가 정보(csr)&lt;/b&gt; 파일이 생성됩니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;비밀키 파일은 서버 내의 안전한 곳에 잘 보관하시고 유출되지 않도록 해야 합니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;생성된 &lt;b&gt;CSR&lt;/b&gt; 파일의 내용을 복사하여 홈페이지에 입력하고 다음 단계로 진행합니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/25181F34570C4C7236&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F25181F34570C4C7236&quot; width=&quot;500&quot; height=&quot;286&quot; filename=&quot;스크린샷 2016-04-12 오전 10.07.20.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;인증서 발급이 성공적으로 완료되었습니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/2728A734570C4C7326&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F2728A734570C4C7326&quot; width=&quot;500&quot; height=&quot;68&quot; filename=&quot;스크린샷 2016-04-12 오전 10.07.55.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;5. 인증서 다운로드&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;Tool Box 메뉴 최상단의 인증서 목록(Certificate List) 메뉴로 진입합니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/242D0634570C4C7322&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F242D0634570C4C7322&quot; width=&quot;500&quot; height=&quot;307&quot; filename=&quot;스크린샷 2016-04-12 오전 10.08.07.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;목록에 2개의 인증서가 보일 것입니다 (Products 항목으로 구분하세요)&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;- 하나는 방금 만든 SSL 인증서입니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;- 하나는 StartSSL 사이트에 로그인 할 때 사용하는 Client 인증서입니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;SSL 인증서 우측의 Retrieve 버튼을 누르면 &lt;b&gt;crt 인증서&lt;/b&gt;를 다운받을 수 있습니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;작은 역삼각형 버튼을 누르면 &lt;b&gt;pem 인증서&lt;/b&gt;를 다운받을 수 있습니다.&lt;/p&gt;&lt;p style=&quot;margin-left: 2em;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/221B4F34570C4C7432&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F221B4F34570C4C7432&quot; width=&quot;500&quot; height=&quot;222&quot; filename=&quot;스크린샷 2016-04-12 오전 10.08.13.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>컴퓨터 공학도의 삶</category>
      <author>Acu</author>
      <guid isPermaLink="true">https://acuworld.tistory.com/54</guid>
      <comments>https://acuworld.tistory.com/54#entry54comment</comments>
      <pubDate>Tue, 12 Apr 2016 10:35:04 +0900</pubDate>
    </item>
  </channel>
</rss>