<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>솔적솔적</title>
    <link>https://thfdl0317.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 30 Jun 2026 13:47:16 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>카드값줘체리</managingEditor>
    <image>
      <title>솔적솔적</title>
      <url>https://tistory1.daumcdn.net/tistory/5184070/attach/9911f623fb404a1fac7cab9a11bf6b1e</url>
      <link>https://thfdl0317.tistory.com</link>
    </image>
    <item>
      <title>구름톤 인 제주 16기 후기</title>
      <link>https://thfdl0317.tistory.com/entry/%EC%A0%9C%EC%A3%BC-%EA%B5%AC%EB%A6%84%ED%86%A4-16%EA%B8%B0-%ED%9B%84%EA%B8%B0</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1201&quot; data-origin-height=&quot;628&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ao06F/dJMcagxfXxC/bcOvTwXWvTpl45sB49JgG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ao06F/dJMcagxfXxC/bcOvTwXWvTpl45sB49JgG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ao06F/dJMcagxfXxC/bcOvTwXWvTpl45sB49JgG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAo06F%2FdJMcagxfXxC%2FbcOvTwXWvTpl45sB49JgG0%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;1201&quot; height=&quot;628&quot; data-origin-width=&quot;1201&quot; data-origin-height=&quot;628&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;필자는&amp;nbsp;12월2일&amp;nbsp;~&amp;nbsp;12월&amp;nbsp;5일&amp;nbsp;구름톤&amp;nbsp;16기를&amp;nbsp;진행하였음을&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 구름톤 신청&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구름톤은 아마 14기 때부터 신청했었는데 &lt;br /&gt;14, 15기에 탈락되어서 마지막으로 신청했더니 드디어 합격되어가게 되었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;991&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vszdo/dJMcaihxNtM/hKJKrbuZBHhNJQUhP80Ym0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vszdo/dJMcaihxNtM/hKJKrbuZBHhNJQUhP80Ym0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vszdo/dJMcaihxNtM/hKJKrbuZBHhNJQUhP80Ym0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvszdo%2FdJMcaihxNtM%2FhKJKrbuZBHhNJQUhP80Ym0%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;272&quot; height=&quot;250&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;991&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항상 신청할 때마다 정성껏 썼었지만, 매번 탈락되니 시무룩된 마음으로 이번에 안되면&amp;nbsp; &lt;br /&gt;인연이&amp;nbsp;아닌가보다..대학생들&amp;nbsp;위주로&amp;nbsp;뽑아서&amp;nbsp;난&amp;nbsp;어려운가보다&amp;nbsp;생각했는데,&amp;nbsp;그건&amp;nbsp;아닌듯하다. &lt;br /&gt;&lt;br /&gt;되었을&amp;nbsp;때&amp;nbsp;드디어&amp;nbsp;갈&amp;nbsp;수&amp;nbsp;있다니하며&amp;nbsp;얼마나&amp;nbsp;기뻤던지..!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 구름톤 준비&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구름톤은&amp;nbsp;합격문자&amp;nbsp;받은&amp;nbsp;후,&amp;nbsp;하루&amp;nbsp;지난&amp;nbsp;뒤&amp;nbsp;쯤에&amp;nbsp;슬랙과&amp;nbsp;노션에&amp;nbsp;초대되어지며&amp;nbsp;오기&amp;nbsp;전&amp;nbsp;안내를&amp;nbsp;진행해주는&amp;nbsp;방식이었으며,&amp;nbsp;첫&amp;nbsp;날은&amp;nbsp;숙소&amp;nbsp;지원이&amp;nbsp;안됨으로&amp;nbsp;신청자들은&amp;nbsp;각자&amp;nbsp;숙소를&amp;nbsp;그&amp;nbsp;때만은&amp;nbsp;알아봐야한다는&amp;nbsp;것. &lt;br /&gt;&lt;br /&gt;참여하신&amp;nbsp;분들&amp;nbsp;이야기를&amp;nbsp;들어보면 &lt;br /&gt;시작&amp;nbsp;하루&amp;nbsp;전에&amp;nbsp;오신&amp;nbsp;분들도(나도)&amp;nbsp;있으시고,&amp;nbsp;당일날&amp;nbsp;부랴랴&amp;nbsp;오신&amp;nbsp;분들도&amp;nbsp;계셨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;3. 구름톤에서 이루고자하는 목표 &amp;amp; 성장&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하루만에 기획, 디자인, 개발을 구현하여 한 서비스를 만들어내는 것에 있어 엄청 들뜬 마음이었다. &lt;br /&gt;사람이&amp;nbsp;뜻을&amp;nbsp;합치고&amp;nbsp;목표하고자하는&amp;nbsp;것이&amp;nbsp;있으면&amp;nbsp;뭔들못하리.하는&amp;nbsp;모토라&amp;nbsp;못&amp;nbsp;되어도&amp;nbsp;최소한의&amp;nbsp;기능과&amp;nbsp;소통으로&amp;nbsp;만들어낸다면&amp;nbsp;간단한&amp;nbsp;원싸이클&amp;nbsp;구현에서&amp;nbsp;우리의&amp;nbsp;주제를&amp;nbsp;잘&amp;nbsp;표현한다면&amp;nbsp;적어도&amp;nbsp;멋드러진&amp;nbsp;프로젝트가&amp;nbsp;만들어질&amp;nbsp;것이다&amp;nbsp;생각하였고,&amp;nbsp;그&amp;nbsp;안에서&amp;nbsp;다양한&amp;nbsp;소통과&amp;nbsp;개발&amp;nbsp;속도를&amp;nbsp;향상시키고&amp;nbsp;싶었다.&lt;/p&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;br /&gt;구름톤은&amp;nbsp;3박4일로&amp;nbsp;진행되었으며 &lt;br /&gt;1, 2일차는 &lt;span style=&quot;background-color: #f8f8f8; color: #1d1c1d; text-align: left;&quot;&gt;구름스퀘어&lt;/span&gt;에서 교육듣고 점심 때쯤 성산 플레이스 캠프로 이동 &lt;br /&gt;3, 4일차에 성산플레이스 캠프에서 진행 후 단체버스로 제주시청   제주 공항 이렇게 데려다 주셨다.&lt;/p&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;h4 data-ke-size=&quot;size20&quot;&gt;구름톤 &lt;span style=&quot;color: #f89009;&quot;&gt;1일차&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;nbsp;아이스브레이킹&amp;nbsp;타임&amp;nbsp;+&amp;nbsp;각자&amp;nbsp;자기소개&amp;nbsp;발표 &lt;br /&gt;-&amp;nbsp;기획,&amp;nbsp;프로젝트를&amp;nbsp;만들&amp;nbsp;시에&amp;nbsp;전략 &lt;br /&gt;-&amp;nbsp;GDS(Goorm&amp;nbsp;Design&amp;nbsp;System)&amp;nbsp;교육, &lt;br /&gt;- 구름톤 배포 강의 및 실습에 대해알려주셨다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVnva9/dJMcaaX6jBj/8vb9UjXIj2ralEQbpyJ2aK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVnva9/dJMcaaX6jBj/8vb9UjXIj2ralEQbpyJ2aK/img.png&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot; data-is-animation=&quot;false&quot; style=&quot;width: 63.2558%; margin-right: 10px;&quot; data-widthpercent=&quot;64&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVnva9/dJMcaaX6jBj/8vb9UjXIj2ralEQbpyJ2aK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVnva9%2FdJMcaaX6jBj%2F8vb9UjXIj2ralEQbpyJ2aK%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;4032&quot; height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqtEkg/dJMcai9BIby/vhB48uSJZgfyHW1XkQ0xK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqtEkg/dJMcai9BIby/vhB48uSJZgfyHW1XkQ0xK0/img.png&quot; width=&quot;241&quot; height=&quot;321&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; style=&quot;width: 35.5814%;&quot; data-widthpercent=&quot;36&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqtEkg/dJMcai9BIby/vhB48uSJZgfyHW1XkQ0xK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqtEkg%2FdJMcai9BIby%2FvhB48uSJZgfyHW1XkQ0xK0%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;3024&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bouqju/dJMcaf6aQd8/RlE9xleXb2lGAkHKhlFAkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bouqju/dJMcaf6aQd8/RlE9xleXb2lGAkHKhlFAkK/img.png&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; width=&quot;275&quot; height=&quot;367&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bouqju/dJMcaf6aQd8/RlE9xleXb2lGAkHKhlFAkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbouqju%2FdJMcaf6aQd8%2FRlE9xleXb2lGAkHKhlFAkK%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;3024&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEsSTi/dJMcabQeKUc/n3MjCrtTWN9wGy9A20lzlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEsSTi/dJMcabQeKUc/n3MjCrtTWN9wGy9A20lzlK/img.png&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; width=&quot;297&quot; height=&quot;396&quot; data-widthpercent=&quot;33.33&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEsSTi/dJMcabQeKUc/n3MjCrtTWN9wGy9A20lzlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEsSTi%2FdJMcabQeKUc%2Fn3MjCrtTWN9wGy9A20lzlK%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;3024&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nBtNS/dJMcadmVK2T/QxSoYk817yYfFNERQ5k0D0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nBtNS/dJMcadmVK2T/QxSoYk817yYfFNERQ5k0D0/img.png&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; width=&quot;409&quot; height=&quot;545&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nBtNS/dJMcadmVK2T/QxSoYk817yYfFNERQ5k0D0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnBtNS%2FdJMcadmVK2T%2FQxSoYk817yYfFNERQ5k0D0%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;3024&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BpmkE/dJMcadAs4sE/s8KDZl1hkA9gJcNeE7Hd7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BpmkE/dJMcadAs4sE/s8KDZl1hkA9gJcNeE7Hd7K/img.png&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot; data-is-animation=&quot;false&quot; width=&quot;405&quot; height=&quot;304&quot; style=&quot;width: 63.2558%; margin-right: 10px;&quot; data-widthpercent=&quot;64&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BpmkE/dJMcadAs4sE/s8KDZl1hkA9gJcNeE7Hd7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBpmkE%2FdJMcadAs4sE%2Fs8KDZl1hkA9gJcNeE7Hd7K%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;4032&quot; height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1VuAy/dJMcadNZ9jM/CCBokwJyRoulWNyaD8SJ0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1VuAy/dJMcadNZ9jM/CCBokwJyRoulWNyaD8SJ0K/img.png&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; width=&quot;348&quot; height=&quot;464&quot; style=&quot;width: 35.5814%;&quot; data-widthpercent=&quot;36&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1VuAy/dJMcadNZ9jM/CCBokwJyRoulWNyaD8SJ0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1VuAy%2FdJMcadNZ9jM%2FCCBokwJyRoulWNyaD8SJ0K%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;3024&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bu6WqA/dJMcagjHUfq/lVk5jv0s7qKqkyhZwjmE0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bu6WqA/dJMcagjHUfq/lVk5jv0s7qKqkyhZwjmE0k/img.png&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1920&quot; data-is-animation=&quot;false&quot; width=&quot;292&quot; height=&quot;519&quot; style=&quot;width: 29.3023%; margin-right: 10px;&quot; data-widthpercent=&quot;30&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bu6WqA/dJMcagjHUfq/lVk5jv0s7qKqkyhZwjmE0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbu6WqA%2FdJMcagjHUfq%2FlVk5jv0s7qKqkyhZwjmE0k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;1920&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JCpVc/dJMcai2QMmJ/LwVWoYz0IsRKtwRkDQykUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JCpVc/dJMcai2QMmJ/LwVWoYz0IsRKtwRkDQykUK/img.png&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1920&quot; data-is-animation=&quot;false&quot; width=&quot;387&quot; height=&quot;688&quot; style=&quot;width: 29.3023%; margin-right: 10px;&quot; data-widthpercent=&quot;30&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JCpVc/dJMcai2QMmJ/LwVWoYz0IsRKtwRkDQykUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJCpVc%2FdJMcai2QMmJ%2FLwVWoYz0IsRKtwRkDQykUK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;1920&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/elk9vo/dJMcaiPjWy7/skLwNPD1CnynuqZZv3wzq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/elk9vo/dJMcaiPjWy7/skLwNPD1CnynuqZZv3wzq1/img.png&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; width=&quot;390&quot; height=&quot;520&quot; style=&quot;width: 39.0698%;&quot; data-widthpercent=&quot;40&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/elk9vo/dJMcaiPjWy7/skLwNPD1CnynuqZZv3wzq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Felk9vo%2FdJMcaiPjWy7%2FskLwNPD1CnynuqZZv3wzq1%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;3024&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdwlyg/dJMcaajuB2V/URENWk4YkdgQGP2ckrkBwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdwlyg/dJMcaajuB2V/URENWk4YkdgQGP2ckrkBwK/img.png&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; width=&quot;409&quot; height=&quot;545&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdwlyg/dJMcaajuB2V/URENWk4YkdgQGP2ckrkBwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcdwlyg%2FdJMcaajuB2V%2FURENWk4YkdgQGP2ckrkBwK%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;3024&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7chjM/dJMcacn5LTE/NyPxp4PGDbrgtXyTRtHLi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7chjM/dJMcacn5LTE/NyPxp4PGDbrgtXyTRtHLi1/img.png&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; width=&quot;420&quot; height=&quot;560&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7chjM/dJMcacn5LTE/NyPxp4PGDbrgtXyTRtHLi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7chjM%2FdJMcacn5LTE%2FNyPxp4PGDbrgtXyTRtHLi1%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;3024&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;제주톤에 오기 전에 노션에 초대해주셨는데, 자기 PR 란에다 참가자들은 각각 자신에 대한 자기소개란을 쓰게되어있는데, 그걸&amp;nbsp;발표하는&amp;nbsp;시간이였다.&lt;br /&gt;&lt;br /&gt;이&amp;nbsp;자기소개PR은&amp;nbsp;팀빌딩&amp;nbsp;때&lt;br /&gt;구름톤에서&amp;nbsp;어떤&amp;nbsp;주제로&amp;nbsp;프로젝트를&amp;nbsp;만들고&amp;nbsp;싶은지,&lt;br /&gt;어떤&amp;nbsp;성향의&amp;nbsp;사람과&amp;nbsp;힘을&amp;nbsp;합쳐&amp;nbsp;만들고&amp;nbsp;싶은지&lt;br /&gt;나는&amp;nbsp;이런&amp;nbsp;강점이&amp;nbsp;있고&amp;nbsp;이런&amp;nbsp;부분은&amp;nbsp;맞춰가자.&amp;nbsp;라는&amp;nbsp;어필도&amp;nbsp;될&amp;nbsp;수&amp;nbsp;있으니,&amp;nbsp;&lt;br /&gt;정성스럽게&amp;nbsp;준비해가는&amp;nbsp;것이&amp;nbsp;좋을&amp;nbsp;것같다.&lt;br /&gt;발표&amp;nbsp;시간은&amp;nbsp;3분이었으며&amp;nbsp;막상&amp;nbsp;앞에&amp;nbsp;나가서&amp;nbsp;발표하면&amp;nbsp;떨리니,&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;구름톤 합격되셔서 가시는 분들은 연습 많이하고 가시는 것을 추천한다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;구름톤&lt;span style=&quot;color: #f89009;&quot;&gt; 2일차&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2일차에는 &lt;br /&gt;각자&amp;nbsp;준비했던&amp;nbsp;아이디어&amp;nbsp;발표(2분)&amp;nbsp;이후&amp;nbsp;바로&amp;nbsp;팀빌딩하며&amp;nbsp;성산&amp;nbsp;플레이스캠프로&amp;nbsp;이동하였습니다. &lt;br /&gt;&lt;br /&gt;1일차에&amp;nbsp;과제를&amp;nbsp;주시는데,&amp;nbsp; &lt;br /&gt;구름톤&amp;nbsp;주제를&amp;nbsp;알려주시고&amp;nbsp;그&amp;nbsp;주제에&amp;nbsp;맞게&amp;nbsp; &lt;br /&gt;2일차&amp;nbsp;때&amp;nbsp;각자의&amp;nbsp;아이디어&amp;nbsp;발표를&amp;nbsp;하며&amp;nbsp;자신이&amp;nbsp;만들고&amp;nbsp;싶어하는&amp;nbsp;서비스에&amp;nbsp;대해서&amp;nbsp; &lt;br /&gt;PDF파일&amp;nbsp;1장으로&amp;nbsp;2분안에&amp;nbsp;발표해야한다. &lt;br /&gt;&lt;br /&gt;각자&amp;nbsp;참여자분들&amp;nbsp;중에&amp;nbsp;내가&amp;nbsp;생각지&amp;nbsp;못했던&amp;nbsp;아이디어를&amp;nbsp;발표하시는&amp;nbsp;분도&amp;nbsp;계셨고 &lt;br /&gt;나와&amp;nbsp;비슷한&amp;nbsp;제주도민&amp;nbsp;+&amp;nbsp;제주&amp;nbsp;여행자&amp;nbsp;+&amp;nbsp;제주를&amp;nbsp;방문한&amp;nbsp;외국인을&amp;nbsp;이어주는&amp;nbsp;매칭&amp;nbsp;서비스를 &lt;br /&gt;생각하시는&amp;nbsp;분들도&amp;nbsp;계셨다.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;*발표 순서는 PDF 제출을 제일 늦게한 사람부터 발표 시작하니, 참고하시길.&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;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HDPCX/dJMcagcW9ri/hTtV5RsVwX3kBIEiH7Dle1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HDPCX/dJMcagcW9ri/hTtV5RsVwX3kBIEiH7Dle1/img.png&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HDPCX/dJMcagcW9ri/hTtV5RsVwX3kBIEiH7Dle1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHDPCX%2FdJMcagcW9ri%2FhTtV5RsVwX3kBIEiH7Dle1%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;3024&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BWGBw/dJMcagcX1vy/7UTDSjSjQj51DY8H0ZbAPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BWGBw/dJMcagcX1vy/7UTDSjSjQj51DY8H0ZbAPk/img.png&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; width=&quot;288&quot; height=&quot;384&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BWGBw/dJMcagcX1vy/7UTDSjSjQj51DY8H0ZbAPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBWGBw%2FdJMcagcX1vy%2F7UTDSjSjQj51DY8H0ZbAPk%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;3024&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oiYFg/dJMcah3Zlrr/tQv8DuW4JYlif8HrKIP4gK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oiYFg/dJMcah3Zlrr/tQv8DuW4JYlif8HrKIP4gK/img.png&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; width=&quot;264&quot; height=&quot;352&quot; data-widthpercent=&quot;33.34&quot; style=&quot;width: 32.5581%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oiYFg/dJMcah3Zlrr/tQv8DuW4JYlif8HrKIP4gK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoiYFg%2FdJMcah3Zlrr%2FtQv8DuW4JYlif8HrKIP4gK%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;3024&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각자&amp;nbsp;아이디어&amp;nbsp;발표가&amp;nbsp;끝나자마자&amp;nbsp;바로&amp;nbsp;팀빌딩이&amp;nbsp;시작되었다.&lt;br /&gt;나는&amp;nbsp;주제가&amp;nbsp;맞는&amp;nbsp;사람들끼리&amp;nbsp;자리를&amp;nbsp;옮겨&amp;nbsp;얘기하거나&amp;nbsp;좀&amp;nbsp;더&amp;nbsp;서로의&amp;nbsp;PR&amp;nbsp;시간을&amp;nbsp;주는&amp;nbsp;줄&amp;nbsp;알았는데,&lt;br /&gt;바로&amp;nbsp;팀을&amp;nbsp;만드는&amp;nbsp;방식..!&lt;br /&gt;&lt;br /&gt;부랴랴&amp;nbsp;일어나서&amp;nbsp;나와&amp;nbsp;주제가&amp;nbsp;맞았던&amp;nbsp;분들을&amp;nbsp;먼저&amp;nbsp;찾았다.&lt;br /&gt;왜냐면 주제, 목표가 같아야 구현 시 되도록 목표점을 찾는데 시간을 단축할 수 있다라고 생각했었기 때문에 벌떡 일어나서, 디자이너분한테&amp;nbsp;&quot;아까 아이디어 발표하신 것 저와 비슷하신 것같은데, 함께 어떠세요? 이 쪽부분에선 제가 이렇게 구현할 수 있고 이 부분을 좀 더 구체화시켜보면 좋은 서비스가 될 것같은데..&quot; 하며 팀원들을 찾아 제안했고 기획자, 백엔드 분도 함께하여 팀이 구성되었다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;팀빌딩&amp;nbsp;후&amp;nbsp;팀이름&amp;nbsp;정하고&amp;nbsp;본격&amp;nbsp;주제에&amp;nbsp;관련된&amp;nbsp;우리&amp;nbsp;팀&amp;nbsp;프로젝트&amp;nbsp;만들기!&lt;br /&gt;&lt;br /&gt;접근&amp;nbsp;방식은&lt;br /&gt;1.&amp;nbsp;문제/니즈&amp;nbsp;발견&amp;nbsp;:&amp;nbsp;제주&amp;nbsp;여행&amp;nbsp;시,&amp;nbsp;이용객&amp;nbsp;3명&amp;nbsp;중&amp;nbsp;1명&amp;nbsp;꼴로,&amp;nbsp;버스&amp;nbsp;배차&amp;nbsp;시간에&amp;nbsp;대한&amp;nbsp;불만이&amp;nbsp;있음&lt;br /&gt;2.&amp;nbsp;목표/타겟&amp;nbsp;정의:&amp;nbsp;대중교통&amp;nbsp;이용&amp;nbsp;관광객(혼자&amp;nbsp;여행에&amp;nbsp;있어&amp;nbsp;면허없이,&amp;nbsp;뚜벅이&amp;nbsp;여행자들)&lt;br /&gt;3.&amp;nbsp;솔루션&amp;nbsp;제시:&amp;nbsp;긴&amp;nbsp;배차시간에&amp;nbsp;즐거움을&amp;nbsp;선사할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;이벤트,&amp;nbsp;퀴즈,&amp;nbsp;제주설화&amp;nbsp;등을&amp;nbsp;앱으로&amp;nbsp;제공.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lpJLW/dJMcafZo57e/vTKbSdtvw3KUm3b9tHHyl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lpJLW/dJMcafZo57e/vTKbSdtvw3KUm3b9tHHyl1/img.png&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; width=&quot;331&quot; height=&quot;441&quot; data-widthpercent=&quot;21.95&quot; style=&quot;width: 21.4407%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lpJLW/dJMcafZo57e/vTKbSdtvw3KUm3b9tHHyl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlpJLW%2FdJMcafZo57e%2FvTKbSdtvw3KUm3b9tHHyl1%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;3024&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pxZHl/dJMcajtU681/0WVkWoBaGmQc2ApYZkoKB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pxZHl/dJMcajtU681/0WVkWoBaGmQc2ApYZkoKB0/img.png&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot; data-is-animation=&quot;false&quot; width=&quot;373&quot; height=&quot;280&quot; style=&quot;width: 38.1168%; margin-right: 10px;&quot; data-widthpercent=&quot;39.02&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pxZHl/dJMcajtU681/0WVkWoBaGmQc2ApYZkoKB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpxZHl%2FdJMcajtU681%2F0WVkWoBaGmQc2ApYZkoKB0%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;4032&quot; height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTu0hO/dJMcaaqgjLl/yp1Ll4BRRbzXrISB2AVNe1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTu0hO/dJMcaaqgjLl/yp1Ll4BRRbzXrISB2AVNe1/img.png&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot; data-is-animation=&quot;false&quot; width=&quot;348&quot; height=&quot;261&quot; style=&quot;width: 38.1168%;&quot; data-widthpercent=&quot;39.03&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTu0hO/dJMcaaqgjLl/yp1Ll4BRRbzXrISB2AVNe1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTu0hO%2FdJMcaaqgjLl%2Fyp1Ll4BRRbzXrISB2AVNe1%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;4032&quot; height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biSjaU/dJMcahpoFEA/TlP8VpUxEMuobUKg9PuCH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biSjaU/dJMcahpoFEA/TlP8VpUxEMuobUKg9PuCH0/img.png&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot; data-is-animation=&quot;false&quot; width=&quot;376&quot; height=&quot;282&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biSjaU/dJMcahpoFEA/TlP8VpUxEMuobUKg9PuCH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiSjaU%2FdJMcahpoFEA%2FTlP8VpUxEMuobUKg9PuCH0%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;4032&quot; height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGaLmB/dJMb99LEBMd/IJP6fWnCbNKvBcNlSjVvx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGaLmB/dJMb99LEBMd/IJP6fWnCbNKvBcNlSjVvx0/img.png&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot; data-is-animation=&quot;false&quot; width=&quot;336&quot; height=&quot;252&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGaLmB/dJMb99LEBMd/IJP6fWnCbNKvBcNlSjVvx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGaLmB%2FdJMb99LEBMd%2FIJP6fWnCbNKvBcNlSjVvx0%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;4032&quot; height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CKkxv/dJMcaaqg3Z4/h03fi3QOnM4RPmxfmMiuvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CKkxv/dJMcaaqg3Z4/h03fi3QOnM4RPmxfmMiuvK/img.png&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; style=&quot;width: 35.5814%; margin-right: 10px;&quot; data-widthpercent=&quot;36&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CKkxv/dJMcaaqg3Z4/h03fi3QOnM4RPmxfmMiuvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCKkxv%2FdJMcaaqg3Z4%2Fh03fi3QOnM4RPmxfmMiuvK%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;3024&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHNkXj/dJMcahppoHv/IMz3eiDMRbzGywSUR9sfKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHNkXj/dJMcahppoHv/IMz3eiDMRbzGywSUR9sfKK/img.png&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;64&quot; style=&quot;width: 63.2558%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHNkXj/dJMcahppoHv/IMz3eiDMRbzGywSUR9sfKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHNkXj%2FdJMcahppoHv%2FIMz3eiDMRbzGywSUR9sfKK%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;4032&quot; height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비어파티에는 뷔페식으로 음식이 차려져 있었고,&lt;br /&gt;랜덤으로&amp;nbsp;다른&amp;nbsp;팀의&amp;nbsp;참가자와&amp;nbsp;이야기를&amp;nbsp;할&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;5명씩&amp;nbsp;한&amp;nbsp;테이블에&amp;nbsp;앉아서&amp;nbsp;이야기할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;구조였다.&lt;br /&gt;&lt;br /&gt;팀빌딩&amp;nbsp;이후로는&amp;nbsp;다른&amp;nbsp;참여자들과&amp;nbsp;친해질&amp;nbsp;기회가&amp;nbsp;없었는데,&amp;nbsp;소통할&amp;nbsp;수&amp;nbsp;있어서&amp;nbsp;되게&amp;nbsp;좋은&amp;nbsp;시간이었다.&lt;br /&gt;&lt;br /&gt;랜덤으로 정해진 팀과의 식사가 끝나면&amp;nbsp;&lt;br /&gt;각&amp;nbsp;멘토분들이&amp;nbsp;나와서&amp;nbsp;구름톤&amp;nbsp;신청&amp;nbsp;시&amp;nbsp;멘토에게&amp;nbsp;질문했던&amp;nbsp;내용의&amp;nbsp;질의응답&amp;nbsp;토크타임이&amp;nbsp;진행되었고&lt;br /&gt;멘토분들한테&amp;nbsp;좋은&amp;nbsp;이야기를&amp;nbsp;들을&amp;nbsp;수&amp;nbsp;있어서&amp;nbsp;동기부여와&amp;nbsp;자극을&amp;nbsp;많이&amp;nbsp;받았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;구름톤&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;span&gt; 3&lt;/span&gt;일차&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3일차에는 본격적인 해커톤이 시작되었다. &lt;br /&gt;주제는&amp;nbsp;이제&amp;nbsp;정했으니&amp;nbsp;나머지는&amp;nbsp;와이어프레임의&amp;nbsp;뼈대에&amp;nbsp;기반하여&amp;nbsp;기능을&amp;nbsp;구현할수&amp;nbsp;있도록&amp;nbsp; &lt;br /&gt;디자이너와&amp;nbsp;기획이&amp;nbsp;설계를&amp;nbsp;진행하는&amp;nbsp;동안&amp;nbsp;개발쪽은&amp;nbsp;배포와&amp;nbsp;프로젝트&amp;nbsp;세팅,&amp;nbsp;기본적인&amp;nbsp;기능&amp;nbsp;구현을&amp;nbsp;각자&amp;nbsp;맡아&amp;nbsp;작업하였다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l8V9Z/dJMcacIo7k4/sTpB6kMAwCewOJbtniMOi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l8V9Z/dJMcacIo7k4/sTpB6kMAwCewOJbtniMOi1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l8V9Z/dJMcacIo7k4/sTpB6kMAwCewOJbtniMOi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl8V9Z%2FdJMcacIo7k4%2FsTpB6kMAwCewOJbtniMOi1%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;4032&quot; height=&quot;3024&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라이즈 산업단에서 저녁식사도 제공해주셔서..(너무 감사합니다. 감동감동.. )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;든든하게 먹으며 해커톤 계속 진행!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;점점 우리의 프로젝트는 만들어지고..&lt;br /&gt;주의하며 구현해나갔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주제에 벗어나지 않도록, 최소한이라도 완성도 있는 플로우가 되도록.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;885&quot; data-origin-height=&quot;494&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1jTpc/dJMcajgoGoa/IBEKDPj79alVT54tKc6ic1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1jTpc/dJMcajgoGoa/IBEKDPj79alVT54tKc6ic1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1jTpc/dJMcajgoGoa/IBEKDPj79alVT54tKc6ic1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1jTpc%2FdJMcajgoGoa%2FIBEKDPj79alVT54tKc6ic1%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;885&quot; height=&quot;494&quot; data-origin-width=&quot;885&quot; data-origin-height=&quot;494&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1377&quot; data-origin-height=&quot;705&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qhAxD/dJMcacn5W8R/YfydT1frKFRcdF40K4K0V0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qhAxD/dJMcacn5W8R/YfydT1frKFRcdF40K4K0V0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qhAxD/dJMcacn5W8R/YfydT1frKFRcdF40K4K0V0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqhAxD%2FdJMcacn5W8R%2FYfydT1frKFRcdF40K4K0V0%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;1377&quot; height=&quot;705&quot; data-origin-width=&quot;1377&quot; data-origin-height=&quot;705&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;982&quot; data-origin-height=&quot;530&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bV75lE/dJMcabQfHRJ/wMPzTSVvGzuW81aUNhGoY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bV75lE/dJMcabQfHRJ/wMPzTSVvGzuW81aUNhGoY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bV75lE/dJMcabQfHRJ/wMPzTSVvGzuW81aUNhGoY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbV75lE%2FdJMcabQfHRJ%2FwMPzTSVvGzuW81aUNhGoY1%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;982&quot; height=&quot;530&quot; data-origin-width=&quot;982&quot; data-origin-height=&quot;530&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;986&quot; data-origin-height=&quot;419&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eSDKhs/dJMcaiV6hxC/mCluI9wf1aC7PNPfCuFpOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eSDKhs/dJMcaiV6hxC/mCluI9wf1aC7PNPfCuFpOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eSDKhs/dJMcaiV6hxC/mCluI9wf1aC7PNPfCuFpOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeSDKhs%2FdJMcaiV6hxC%2FmCluI9wf1aC7PNPfCuFpOK%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;986&quot; height=&quot;419&quot; data-origin-width=&quot;986&quot; data-origin-height=&quot;419&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;구름톤&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;span&gt; 4&lt;/span&gt;일차&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4일차에는 이제 11시까지 발표자료를 제출해야했다. 1분이라도 늦으면 1점이 감점되기 때문에 미리&amp;nbsp;준비하고&amp;nbsp;내는&amp;nbsp;것을&amp;nbsp;추천한다. &lt;br /&gt;시연영상도&amp;nbsp;넣어서&amp;nbsp;제출해야하니,&amp;nbsp;임박했을&amp;nbsp;대&amp;nbsp;내는&amp;nbsp;것은&amp;nbsp;좀&amp;nbsp;아슬아슬하니까말이다. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;우리&amp;nbsp;발표순서는&amp;nbsp;두번째였고&amp;nbsp;PM이&amp;nbsp;발표를&amp;nbsp;했는데,&amp;nbsp;지연이가&amp;nbsp;걱정했던&amp;nbsp;것에&amp;nbsp;비해&amp;nbsp;너무&amp;nbsp;발표를&amp;nbsp;잘해줘서&amp;nbsp;감동받았다..이렇게&amp;nbsp;귀에&amp;nbsp;쏙쏙&amp;nbsp;박히고&amp;nbsp;우리가&amp;nbsp;만든&amp;nbsp;프로젝트를&amp;nbsp;잘&amp;nbsp;설명해줘서&amp;nbsp;너무&amp;nbsp;고마웠다. &lt;br /&gt;&lt;br /&gt;발표가&amp;nbsp;끝나고&amp;nbsp;심사위원분들이&amp;nbsp;우리팀에&amp;nbsp;대해&amp;nbsp;피드백과&amp;nbsp;질문을&amp;nbsp;주셨었는데, &lt;br /&gt;타겟을&amp;nbsp;뚜벅이로만&amp;nbsp;두지않고&amp;nbsp;좀&amp;nbsp;더&amp;nbsp;타겟의&amp;nbsp;범위를&amp;nbsp;넓게&amp;nbsp;잡았으면&amp;nbsp;좋았겠다라는&amp;nbsp;피드백과 &lt;br /&gt;그&amp;nbsp;기능에&amp;nbsp;있어&amp;nbsp;더&amp;nbsp;다양한&amp;nbsp;이벤트와&amp;nbsp;기획들이&amp;nbsp;있었으면&amp;nbsp;이&amp;nbsp;서비스를&amp;nbsp;사용하는&amp;nbsp;유저들에게&amp;nbsp;더&amp;nbsp;참신하게&amp;nbsp;다가오지않았으려나한다는&amp;nbsp;말씀을&amp;nbsp;해주셨다. &lt;br /&gt;&lt;br /&gt;발표가 끝난 후, 시원하기도하고 아쉽기도하고 우리 정말 밤새면서 고생했다라고 팀원가 서로 오고가며 서로&amp;nbsp;격려하며&amp;nbsp;졸기바빴다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQZN4s/dJMcagxfLfS/HWkKklaOwjyvo4qq2EqRt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQZN4s/dJMcagxfLfS/HWkKklaOwjyvo4qq2EqRt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQZN4s/dJMcagxfLfS/HWkKklaOwjyvo4qq2EqRt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQZN4s%2FdJMcagxfLfS%2FHWkKklaOwjyvo4qq2EqRt1%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;4032&quot; height=&quot;3024&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;&lt;br /&gt;아쉽게도 우리팀은 상을 받지 못했다. 심사위원분께선 1점, 2점으로 비등비등하다고 하셨지만,&amp;nbsp; &lt;br /&gt;그래도&amp;nbsp;못내&amp;nbsp;아쉬움은&amp;nbsp;감출&amp;nbsp;수&amp;nbsp;없었음..ㅠㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대상팀이 상 받고 소감발표할 때 뒷자석에서 오열함ㅠㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분하다..분해. 그리 열심히했건만..!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 수상팀들도 열심히하신 결과들이며&amp;nbsp; 다들 정말 헉소리날 정도의 참신한 아이디어들,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI를 접목시킨 방법들이 감탄이 절로 나왔었다. 다른 팀들의 프로젝트를 보면서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;와, AI를 저렇게 활용할 수 있구나, 제주를 주제로 이런 서비스가 구현가능하구나&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;구름톤을 마치며&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구름톤의 일정이 마무리되자마자 바로 셔틀 버스로 이동하며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제주시청 제주공항 까지 데려다주셨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이렇게 3박4일&lt;span&gt; 구름톤을 마무리하며 느낀 점은 &lt;/span&gt;&lt;/span&gt;한 순간마다 알차고 뜻깊은 시간들이었다는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀원과 함께하며 하루만에 힘을 합쳐 프로젝트를 만들 수 있었다는 점, &lt;br /&gt;팀원과&amp;nbsp;소통하며&amp;nbsp;차근차근&amp;nbsp;목표에&amp;nbsp;임박할&amp;nbsp;때까지&amp;nbsp;그&amp;nbsp;누구도&amp;nbsp;도중에&amp;nbsp;포기하지않고&amp;nbsp;하나라도&amp;nbsp;더&amp;nbsp;추가하여 &lt;br /&gt;개선하려했던&amp;nbsp;것들,&amp;nbsp;머리모아&amp;nbsp;우리의&amp;nbsp;서비스가&amp;nbsp;빛을&amp;nbsp;바라길&amp;nbsp;바랬던&amp;nbsp;예리했던&amp;nbsp;피드백들과&amp;nbsp;시행착오들이 &lt;br /&gt;나한테&amp;nbsp;있어&amp;nbsp;너무&amp;nbsp;뜻깊고&amp;nbsp;의미있었으며&amp;nbsp;소통에&amp;nbsp;있어,&amp;nbsp;개발에&amp;nbsp;있어&amp;nbsp;성잘할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;순간들이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 해커톤할 때마다 피드백 주시며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리팀의 주제를 좀 더 차별화하며 전략적으로 접근할 수 있도록 코칭해주신 기획자 윈디님,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카카오 지도 적용 시 갑자기 난 오류에 원인을 다양한 방식으로 접근할 수 있게 알려주신 개발자 로니님,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vapor의 layout 태그 적용 시 화면단에 알 수 없는 공백을 함께 찾아 해결해주신 개발자 맥스님과 리키님,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;젠킨스 파이프라인의 환경변수 누락으로 생긴 카카오키 문제를 피드백 주신 누누님,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리팀의 주제에 맞게 와이어프레임과 디자인 플로우에 대해서 알려주신 오트리님,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일정을 원활하게 이룰 수 있도록 계속 케어해주시며 진행해주신 우디님,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멘토분들 피곤하실텐데 늦은 새벽까지 피드백해주시고 도와주셔서 너무 감사했습니다 &amp;nbsp;&lt;/p&gt;
&lt;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;그리고 올릴까말까했지만 TMI로,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구름톤에서 제공한 옷도 보여드리자면,&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Or44Z/dJMcadHnuuA/18G97dhpT57xdkAojS8G40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Or44Z/dJMcadHnuuA/18G97dhpT57xdkAojS8G40/img.png&quot; width=&quot;305&quot; height=&quot;407&quot; data-is-animation=&quot;false&quot; data-origin-height=&quot;4032&quot; data-origin-width=&quot;3024&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Or44Z/dJMcadHnuuA/18G97dhpT57xdkAojS8G40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOr44Z%2FdJMcadHnuuA%2F18G97dhpT57xdkAojS8G40%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;3024&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnsK2T/dJMcaihEHN9/cQKWOU6vMswKxzKq3v5KQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnsK2T/dJMcaihEHN9/cQKWOU6vMswKxzKq3v5KQ1/img.png&quot; width=&quot;300&quot; height=&quot;400&quot; data-is-animation=&quot;false&quot; data-origin-height=&quot;4032&quot; data-origin-width=&quot;3024&quot; data-widthpercent=&quot;33.33&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnsK2T/dJMcaihEHN9/cQKWOU6vMswKxzKq3v5KQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnsK2T%2FdJMcaihEHN9%2FcQKWOU6vMswKxzKq3v5KQ1%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;3024&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbf11H/dJMcabv39Ip/we2uneXBpWv2muaBBm465k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbf11H/dJMcabv39Ip/we2uneXBpWv2muaBBm465k/img.png&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbf11H/dJMcabv39Ip/we2uneXBpWv2muaBBm465k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcbf11H%2FdJMcabv39Ip%2Fwe2uneXBpWv2muaBBm465k%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;3024&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안엔 기모에 보들보들한 재질이어서 꽤 추운 날씨에 진행한 때였는데, 따듯하게 입으며 작업할 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전 구름톤 가기전에 옷도 궁금했거든요,&lt;/p&gt;
&lt;p 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;다 찍어서 올려놓았습니다. 다음 기수분들, 화이팅입니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>16기</category>
      <category>9oormthon</category>
      <category>goorm</category>
      <category>구름톤</category>
      <category>제주</category>
      <category>프론트엔드</category>
      <category>해커톤</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/151</guid>
      <comments>https://thfdl0317.tistory.com/entry/%EC%A0%9C%EC%A3%BC-%EA%B5%AC%EB%A6%84%ED%86%A4-16%EA%B8%B0-%ED%9B%84%EA%B8%B0#entry151comment</comments>
      <pubDate>Sat, 6 Dec 2025 10:26:02 +0900</pubDate>
    </item>
    <item>
      <title>윈도우 기반 배치 프로그램 구현 방법 정리(JAVA +Jenkins, NSSM, DB 스케줄러)</title>
      <link>https://thfdl0317.tistory.com/entry/%EB%B0%B0%EC%B9%98-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-db-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%9F%AC</link>
      <description>&lt;p data-end=&quot;313&quot; data-start=&quot;140&quot; data-ke-size=&quot;size16&quot;&gt;개발과 운영을 하다 보면 반복적으로 처리해야 하는 작업들이 꼭 생기는데,&lt;/p&gt;
&lt;p data-end=&quot;313&quot; data-start=&quot;140&quot; data-ke-size=&quot;size16&quot;&gt;이걸 데이터 적재, 로그 정리, 특정 시간대에만 실행해야 하는 집계 같은 것들이 있다.&lt;br /&gt;이것과 관련된 프로젝트를 하면서 이런 작업들을 자동화할 필요가 있었고,&lt;/p&gt;
&lt;p data-end=&quot;313&quot; data-start=&quot;140&quot; data-ke-size=&quot;size16&quot;&gt;윈도우 환경에서 배치 프로그램을 구현했던 경험이 있다. 당시 내가 썼던 방법은 크게 세 가지였다.&lt;/p&gt;
&lt;p data-end=&quot;313&quot; data-start=&quot;140&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;313&quot; data-start=&quot;140&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;355&quot; data-start=&quot;320&quot; data-ke-size=&quot;size26&quot;&gt;1. Java 배치 프로그램 + Jenkins 자동화 배포&lt;/h2&gt;
&lt;p data-end=&quot;436&quot; data-start=&quot;357&quot; data-ke-size=&quot;size16&quot;&gt;처음에는 Java로 배치 프로그램을 만들었다. jar 파일로 빌드해서 Jenkins에 등록해두고, 스케줄링과 배포를 자동화하는 방식이었다.&lt;/p&gt;
&lt;p data-end=&quot;436&quot; data-start=&quot;357&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;436&quot; data-start=&quot;357&quot; data-ke-size=&quot;size16&quot;&gt;구현하려했던 방식 java spring boot 프러임워크를 이용하여 정한 시간대마다 주기적으로 도는 배치프로그램을 만들고 MSSQL에 접속하여 만들었던 프로시저를 호출하는 방식,&lt;/p&gt;
&lt;p data-end=&quot;436&quot; data-start=&quot;357&quot; data-ke-size=&quot;size16&quot;&gt;이 접근 방식에 가장 큰 장점은 운영자가 직접 신경쓰지 않아도 정해진 시간에 안정적으로 실행된다는 점,&lt;/p&gt;
&lt;p data-end=&quot;542&quot; data-start=&quot;438&quot; data-ke-size=&quot;size16&quot;&gt;Jenkins의 스케줄러를 이용해 특정 시간마다 실행되도록 설정해두면 매번 콘솔을 열어 수동으로 실행할 필요없는 장점이 있다.&lt;/p&gt;
&lt;p data-end=&quot;542&quot; data-start=&quot;438&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;542&quot; data-start=&quot;438&quot; data-ke-size=&quot;size16&quot;&gt;Java로&amp;nbsp;배치&amp;nbsp;프로그램을&amp;nbsp;만들어&amp;nbsp;Jenkins에&amp;nbsp;등록하면,&amp;nbsp;단순히&amp;nbsp;배포만&amp;nbsp;자동화되는&amp;nbsp;게&amp;nbsp;아니라&amp;nbsp;실행&amp;nbsp;주기까지&amp;nbsp;손쉽게&amp;nbsp;제어할&amp;nbsp;수&amp;nbsp;있다.&lt;/p&gt;
&lt;p data-end=&quot;542&quot; data-start=&quot;438&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;542&quot; data-start=&quot;438&quot; data-ke-size=&quot;size16&quot;&gt;크게 두 가지 방법으로 나눌 수 있다. &lt;br /&gt;&lt;br /&gt;방법1. Jenkins에서 Poll SCM / Build Schedule을 이용해 주기를 정의하는 방법 &lt;br /&gt;&lt;br /&gt;방법2. 애플리케이션 내부에서 @EnableScheduling + @Scheduled 어노테이션으로 주기를 제어하는 방법 &lt;br /&gt;&lt;br /&gt;두 방법 모두 &amp;ldquo;정해진 시간마다 자동 실행&amp;rdquo;이라는 같은 목적을 갖지만, 동작하는 위치와 성격이 다름.&lt;/p&gt;
&lt;p data-end=&quot;542&quot; data-start=&quot;438&quot; data-ke-size=&quot;size16&quot;&gt;Jenkins는 빌드&amp;middot;배포 흐름 전체를 통제하는 데 강점이 있고,&lt;/p&gt;
&lt;p data-end=&quot;542&quot; data-start=&quot;438&quot; data-ke-size=&quot;size16&quot;&gt;Spring Boot 스케줄링은 애플리케이션 내부 로직의 반복 실행에 강하다.&lt;/p&gt;
&lt;p data-end=&quot;542&quot; data-start=&quot;438&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;542&quot; data-start=&quot;438&quot; data-ke-size=&quot;size16&quot;&gt;상황에 따라 하나만 쓰기도 하고, 필요하다면 두 가지를 조합해 쓰기도 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjyd48/btsQZ2GtwUZ/zOIKTKVKpIb5wv3DFsXrfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjyd48/btsQZ2GtwUZ/zOIKTKVKpIb5wv3DFsXrfk/img.png&quot; width=&quot;506&quot; height=&quot;159&quot; data-origin-width=&quot;1021&quot; data-origin-height=&quot;321&quot; data-is-animation=&quot;false&quot; style=&quot;width: 59.2862%; margin-right: 10px;&quot; data-widthpercent=&quot;59.98&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjyd48/btsQZ2GtwUZ/zOIKTKVKpIb5wv3DFsXrfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbjyd48%2FbtsQZ2GtwUZ%2FzOIKTKVKpIb5wv3DFsXrfk%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;1021&quot; height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brfD1e/btsQ2cuybmI/zbT1nn1iIpQmF1j7pZYeCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brfD1e/btsQ2cuybmI/zbT1nn1iIpQmF1j7pZYeCk/img.png&quot; width=&quot;508&quot; height=&quot;239&quot; data-origin-width=&quot;940&quot; data-origin-height=&quot;443&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;40.02&quot; style=&quot;width: 39.551%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brfD1e/btsQ2cuybmI/zbT1nn1iIpQmF1j7pZYeCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrfD1e%2FbtsQ2cuybmI%2FzbT1nn1iIpQmF1j7pZYeCk%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;940&quot; height=&quot;443&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-end=&quot;673&quot; data-start=&quot;670&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;698&quot; data-start=&quot;675&quot; data-ke-size=&quot;size26&quot;&gt;2. NSSM으로 윈도우 서비스 등록&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;a href=&quot;https://nssm.cc/download&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;NSSM&amp;nbsp;다운로드&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;788&quot; data-start=&quot;700&quot; data-ke-size=&quot;size16&quot;&gt;다음으로 시도한 건 NSSM(Non-Sucking Service Manager)이었다. 배치 프로그램을 아예 윈도우 서비스로 등록해버리는 방법이다.&lt;/p&gt;
&lt;p data-end=&quot;788&quot; data-start=&quot;700&quot; data-ke-size=&quot;size16&quot;&gt;이 방식의 가장 큰 장점은 서버가 재부팅되더라도 &lt;b&gt;자동으로 다시 실행된다는 것.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;788&quot; data-start=&quot;700&quot; data-ke-size=&quot;size16&quot;&gt;게다가 Windows Service Manager에서 서비스 상태를 직접 확인하고 재시작할 수 있으니 운영할 때도 마음이 놓였다.&lt;/p&gt;
&lt;p data-end=&quot;1016&quot; data-start=&quot;916&quot; data-ke-size=&quot;size16&quot;&gt;특히 &lt;b&gt;항상 켜져 있어야 하는 프로그램&lt;/b&gt;에는 이게 딱 맞았다. 다만 서비스로 돌리다 보니, 문제 발생 시 즉각적으로 로깅/알림이 필요한데, 그 부분은 별도로 보완해야 했다.&lt;/p&gt;
&lt;hr data-end=&quot;1021&quot; data-start=&quot;1018&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;1047&quot; data-start=&quot;1023&quot; data-ke-size=&quot;size26&quot;&gt;3. 데이터베이스(DB) 스케줄러 활용&lt;/h2&gt;
&lt;p data-end=&quot;1132&quot; data-start=&quot;1049&quot; data-ke-size=&quot;size16&quot;&gt;마지막으로는 &lt;b&gt;DB 자체 스케줄러&lt;/b&gt;를 활용했다. SQL Server Agent 같은 걸 이용해서 저장 프로시저를 주기적으로 실행하는 방식이다.&lt;/p&gt;
&lt;p data-end=&quot;1257&quot; data-start=&quot;1134&quot; data-ke-size=&quot;size16&quot;&gt;이건 주로 &lt;b&gt;데이터 적재나 집계 같은 순수 DB 작업&lt;/b&gt;에 정말 잘 맞았다.&lt;/p&gt;
&lt;p data-end=&quot;1257&quot; data-start=&quot;1134&quot; data-ke-size=&quot;size16&quot;&gt;애플리케이션 레벨을 거치지 않고 바로 DB에서 실행되니 빠르고 단순했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1370&quot; data-start=&quot;1259&quot; data-ke-size=&quot;size16&quot;&gt;나는 이 방식을 쓸 때 중복 실행을 막기 위해 상태 테이블을 두고, 실행 로그를 따로 기록했다. 이렇게 해두니 실패 시점이나 재실행 여부를 바로 파악할 수 있어 나름 안정적으로 관리할 수 있었다.&lt;/p&gt;
&lt;p data-end=&quot;1370&quot; data-start=&quot;1259&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-end=&quot;1375&quot; data-start=&quot;1372&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1384&quot; data-start=&quot;1377&quot; data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배치 시스템을 만드는 방법은 다양했었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 여기서 아무거나 그냥 코카콜라맛있다로 고르는게 아니라,&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1493&quot; data-start=&quot;1386&quot; data-ke-size=&quot;size16&quot;&gt;상황에 따라 &lt;b&gt;Java + Jenkins&lt;/b&gt;로 할건지, &lt;b&gt;윈도우 서비스(NSSM)로 하는게 나은지&lt;/b&gt;, &lt;b&gt;DB 스케줄러가 더 적합한지&lt;/b&gt;를 각각 쓰거나 조합해야 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1605&quot; data-start=&quot;1495&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1524&quot; data-start=&quot;1495&quot;&gt;&lt;b&gt;데이터 집계나 ETL&lt;/b&gt; &amp;rarr; DB 스케줄러&lt;/li&gt;
&lt;li data-end=&quot;1567&quot; data-start=&quot;1525&quot;&gt;&lt;b&gt;외부 API 호출이나 로그 처리&lt;/b&gt; &amp;rarr; Java + Jenkins&lt;/li&gt;
&lt;li data-end=&quot;1605&quot; data-start=&quot;1568&quot;&gt;&lt;b&gt;항상 켜져 있어야 하는 모듈&lt;/b&gt; &amp;rarr; NSSM 서비스 등록&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1715&quot; data-start=&quot;1607&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 적절히 섞어서 사용했던 게 가장 좋은 방법이라 생각한다.&lt;br /&gt;돌아보면, 배치 자체는 단순해 보여도 &lt;b&gt;운영 안정성, 알림 체계, 중복 실행 방지&lt;/b&gt; 같은 세부 요소들이 훨씬 더 중요하여 로그 관리와 기록 체계도 잘 세워야했었다.&lt;/p&gt;</description>
      <category>NSSM</category>
      <category>배치 프로그램</category>
      <category>윈도우기반</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/147</guid>
      <comments>https://thfdl0317.tistory.com/entry/%EB%B0%B0%EC%B9%98-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-db-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%9F%AC#entry147comment</comments>
      <pubDate>Mon, 22 Sep 2025 13:46:46 +0900</pubDate>
    </item>
    <item>
      <title>MSSQL 프로시저 작성하기</title>
      <link>https://thfdl0317.tistory.com/entry/MSSQL-%ED%94%84%EB%A1%9C%EC%8B%9C%EC%A0%80-%EC%9E%91%EC%84%B1%ED%95%98%EA%B8%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- MSSQL&lt;/b&gt;은 T-SQL (Transact-SQL)이라는 자체 문법 사용.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- DECLARE로 변수를 선언하고, SET 또는 SELECT로 값을 할당.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 조건문은 IF ... ELSE를, 반복문은 WHILE을 주로 사용&lt;/p&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;MSSQL:&lt;/b&gt; BEGIN TRY ... END TRY와 BEGIN CATCH ... END CATCH를 사용해 예외를 처리.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러 메시지는 ERROR_MESSAGE()와 같은 내장 함수로 가져온다.&lt;/p&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. CREATE PROC DELETE_BOARDGETTO_LOG 이 DELETE_BOARDGETTO_LOG 라는 이름의 저장 프로시저를 만들겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. AS 정의하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 여러 문장들을 뭉텅이로 관리할 수 있게 BEGIN, END으로 문장을 감싼다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3-1. 여기서, 프로시저, 함수, 트리거의 본문이나 IF, WHILE 같은 제어문 안에서 여러 문장을 쓰고 싶을 때 이 BEGIN...END 블록이 필수.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로시저들의 문장들을 종종 보면 &lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;&lt;span style=&quot;color: #800000;&quot;&gt;SET&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;NOCOUNT&lt;/span&gt; ON;가 BEGIN안에 포함되어 있는 것을 알 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;이 SET NOCOUNT ON는 무엇이냐,&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;이 저장 프로시저를 만들어 호출할 때 결과값들이 출력되는 데 그 결과값에서 만약 10개 행의 값이 나왔다는 거를 알려주는 아웃풋을 생략시켜주는 것이다.&amp;nbsp; 결과 값이 많으면 많을수록, 즉 은 쿼리 실행 후 &lt;b&gt;영향을 받은 행의 개수를 알려주는 메시지&lt;/b&gt;를 생략하는 명령어. 예를 들어, UPDATE 문을 실행했을 때, (10 rows affected)와 같은 메시지가 출력되는데, 이 메시지를 나오지 않게 막아준다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 값을 생략하는 이유&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;성능 최적화:&lt;/b&gt; 프로시저가 수십, 수백 개의 쿼리를 반복적으로 실행할 때, 매번 영향을 받은 행 개수 메시지를 서버에서 클라이언트로 보내는 과정 자체가 불필요한 네트워크 트래픽을 유발한다. 이 때 SET NOCOUNT ON;을 사용하면 이 과정을 생략해 &lt;b&gt;전반적인 성능을 높일 수 있습니다.&lt;/b&gt; 특히 대규모 데이터 처리 작업에서 효과가 크다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;불필요한 출력 제거:&lt;/b&gt; 프로시저를 호출하는 주체가 사람이 아닌 &lt;b&gt;애플리케이션&lt;/b&gt;일 경우, 이 메시지는 오히려 혼란을 주거나 오류의 원인이 될 수 있음. 애플리케이션은 필요한 최종 결과값만 받아야 하는데, 중간에 불필요한 메시지가 끼어들면 프로그램이 제대로 동작하지 않을 수 있기 때문.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 프로시저의 호출 목적은 &lt;b&gt;특정 작업을 수행하는 것&lt;/b&gt;이며, 결과값이 많으면 많을수록 &lt;b&gt;성능 저하&lt;/b&gt;가 발생할 수 있기 때문에 불필요한 출력을 제어하여 효율을 높이는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SET NOCOUNT ON;는 &quot;rows affected&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;의미로 이해하자면, NOCOUNT -&amp;gt; 카운트하지 않겠다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 COUNT는 SQL이 쿼리 실행 후 돌려주는 몇 개의 행이 영향을 받는데 그 메세지를 보여주지 않도록 설정하는 것이다.&lt;/p&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;&quot;1 row affected&quot;, &quot;5 rows affected&quot; 같은 메지시가 계속 뜨면 화면 가독성도 물론이요, 네트워크 부하도 늘어난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알림 설정을 끄는 것과 같다고 생각하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;set transaction isolation level read uncommitted이거.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 가장 낮은 수준의 격리(Isolation):&lt;/b&gt; 트랜잭션 간의 간섭을 최소화하는 다른 격리 수준들과 달리, READ UNCOMMITTED는 간섭을 가장 많이 허용.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 성능 최적화:&lt;/b&gt; 데이터를 읽기 위해 잠금을 기다릴 필요가 없으므로, 대량의 데이터에 대한 읽기 작업 속도가 매우 빠름.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 트랜잭션의 격리 수준을 READ UNCOMMITTED로 설정하겠다는 것.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉즉, 다른 트랜잭션이 아직 커밋(저장)하지 않은 임시 데이터도 읽는 것을 허용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 왜 한다고? 잠금을 기다릴필요 없어 조회 속도가 빨라지지만, 더티리드라고하는 나중에 취소될 수 있는 잘못된 데이터를 읽을 위험이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나씩 이해해보자, READ UNCOMMITTED의 의미&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;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;WITH (NOLOCK)의 역할&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이건은 잠금 회피. NOLOCK 힌트는 SQL Server가 데이터를 읽을 때 공유 잠금을 설정하지 않도록한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 데이터를 읽을 때 다른 트랜잭션이 동시에 그 데이터를 수정하지 못하도록 잠금이 걸린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 NOLOCK을 사용하면 이 잠금을 무시하고 데이터를 바로 읽을 수 있다.&lt;/p&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;gt; 아니다. SQL Server는 기본적으로 자동 커밋모드로 동작하지않는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, BEGIN TRANSACTION으로 트랜잭션을 시작하지 않으면 각 개별 DML문이 자체적인 소규모 트랜잭션으로 처리되고 즉시 커밋된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BEGIN TRANSACTION, COMMIT, ROLLBACK 이 명시적으로 사용되지않는다면 트랜잭션의 원자성을 보장받기 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것을 명시적으로 넣지않는다면 각각 DML문들이 독립적인 트랜잭션으로 실행되거나, 프로시저가 호출되는 환경에 따라 다르게 동작할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 한번 더 말하자면 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;전체 잠금은 아냐!&quot;, 읽기 작업을 실행할 시, 다른 트랜잭션의 잠금을 무시하고 데이터를 읽겠어!&quot;의미다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 읽을 때 잠금 대기 시간을 줄여 성능을 높이기 위한 설정인거다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BEGIN TRY는 오류 처리를 위한 코드 블록의 시작을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시작이 있으면 끝이 있듯, BEGIN TRY는 BEGIN TRY의 짝꿍.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BEGIN TRY와 짝을 이루는 END TRY 사이에는 코드에서 문제가 발생하면 BEGIN CATCH 블록으로 제어가 넘어간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;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;그리고 이 BEGIN과 END쌍은 SQL문장을 하나의 논리적인 코드 블록으로 묶어주는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로시저, 함수, 트리거의 본문, 그리고 IF나 WHITE같은 제어문 안에서 여러 줄의 코드를 실행하고 싶을 때, BEGIN... END 블록이 필수적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- EXEC 명령어는 같은 데이터베이스 내에 있는 저장 프로시저를 호출하여 실행하는 용도로 사용.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EXEC&amp;nbsp;프로시저_이름&amp;nbsp;@매개변수1_이름&amp;nbsp;=&amp;nbsp;값1,&amp;nbsp;@매개변수2_이름&amp;nbsp;=&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;명령문 중 SELETE TOP 1 * FROM 테이블 WITH (NOLOCK) ORDER BY 행 DESC은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내림차순으로 조회할건데&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TOP은 SQL Server의 예약어로,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TOP -&amp;gt; 쿼리 결과의 상위 N개 행만 반환하도록 지정하는 명령어이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 데이터베이스 시스템에서 LIMIT이나 ROWNUM과 유사한 기능이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TOP 1의 의미는&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TOP: 상위 결과를 가져오겠다는 명령이고&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;여기서 주의할 점은 TOP은 반드시 ORDER BY와 함께 사용해야 의미가 있다.&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;IIF는 &lt;b&gt;조건에 따라 두 값 중 하나를 반환하는 함수.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드 IIF(@ID1 &amp;gt; @ID2, @ID1, @ID2)는 다음과 같은 역할을 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;@ID1 &amp;gt; @ID2&lt;/b&gt;: 이 부분이 조건입니다. @ID1이 @ID2보다 큰지 확인.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;@ID1&lt;/b&gt;: 조건이 **참(True)**일 때 반환될 값.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;@ID2&lt;/b&gt;: 조건이 **거짓(False)**일 때 반환될 값.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;@ID1과 @ID2 중 더 큰 값을 @ID 변수에 할당&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;왜 IIF를 사용할까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 함수는 IF...ELSE 문과 동일한 기능을 하지만, 코드를 &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;IIF를 사용한 경우:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;SET @ID = IIF(@ID1 &amp;gt; @ID2, @ID1, @ID2);
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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;p data-ke-size=&quot;size16&quot;&gt;IF...ELSE로 풀어 쓴 경우:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;IF @ID1 &amp;gt; @ID2
BEGIN
    SET @ID = @ID1;
END
ELSE
BEGIN
    SET @ID = @ID2;
END&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 궁금한 건 프로시저 사용할 때만하는건가 아니면 원래 SQL공통적으로 다 사용하는건가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; IIF는 &lt;b&gt;SQL Server&lt;/b&gt;에서 공통적으로 사용할 수 있는 &lt;b&gt;내장 함수&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 프로시저에서만 사용하는 것이 아님.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 프로시저 외에도 SELECT 문이나 UPDATE 문 등 다양한 SQL 문에서 사용가능.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WHILE 1 = 1은 **무한 루프(infinite loop)**를 만드는 SQL 구문.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 무한 루프를 사용하는 것은 자칫 위험할 수 있지만, 효율적으로 사용하기 위해서 루프 안에 IF@@ROWCOUNT=0 BREAK와 같은 탈출 조건이 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 알아야할 점이 BEGIN TRY를 사용하면 반드시 END TRY로 짝을 맞춰야한다는 것,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 BEGIN TRY와 BEGIN은 서로 다른 역할을 하는 명령어이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BEGIN TRY와 END TRY는 오류 처리 블록을 형성한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BEGIN TRY는 &quot;오류 처리를 위한 코드 블록을 시작하겠다&quot;라는 의미를 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 BEGIN은 단순히 &quot;여러개의 SQL 문장을 하나의 논리적인 덩어리(블록)으로 묶겠다&quot;는 의미로 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, '오류 처리'라는 특별한 역할이 더해진 명령어이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글고 반드시 BEGIN TRY를 사용한다면 반드시 END TRY와 BEGIN ... END CATC를 함께 사용해야한다.&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;BEGIN은 IF나 WHITE같은 제어문, 프로시저, 함수 본문을 정의할 때 여러 문장을 묶기 위해 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로시저에서 REPLACE()함수는 주로 동적 SQL을 만들 때 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JS에서는 REPLACE()에서는 매개변수 안에 찾을 값과 바꿀 값을 넣어,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열에서 특정 부분을 찾아 다른 문자열로 바꿔주는 기능을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JS에서는 첫번째로 일치되는 항목만 교체한다. 즉, 가장 먼저 발견되는 한 개만 찾아서 바꿔준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 프로시저의 REPLACE와 다른 점은 JS의 replace()는 SQL과 마찬가지로 두 개의 인자가 필수이며 세번째 인자는 받지않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQL의 REPLACE()함수와 비교한다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQL의 REPLACE()는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;세개의 인자가 필수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 기본적으로 문자열 내의 모든 일치 항목을 찾아서 바꿔준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 주로 SELECT, UPDATE 문 등에서 사용된다.&lt;/p&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;변수를 선언할 시 NVARCHAR는 SQL Server에서 사용되는 데이터 타입 중 하나로, &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;프로시저 명령어 중 TRUNCATE TABLE 테이블명&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;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;삭제하면 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;- TRUNCATE 와 DELETE 의 차이점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스에서 테이블의 내용을 지우는 명령어론 TRUNCATE와 DELETE가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- TRUNCATE&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; &amp;nbsp;데이터 정의 언어(DDL)에 속하며,&lt;span style=&quot;color: #ee2323;&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;- DELETE&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp; 행 단위로 데이터를 삭제&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp; 데이터 조작 언어(DML)에 속하며, where 절을 사용해 특정 조건에 맞는 행만 지우기 가능&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; 각 행의 삭제를 개별적으로 기록하기 때문에 'TRUNCATE' 보다 느리지만, &lt;span style=&quot;color: #ee2323;&quot;&gt;롤백 가능&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, TRUNCATE는 테이블 전체를 빠르고 효율적으로 비울 때 사용하는 명령어이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CONVERT() 는 SQL server에서 데이터 타입을 변환 할 때 사용하는 함수,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;무엇을 변환하는지&quot;에 대해서는 CONVERT() 함수 괄호 안에 있는 인자들이 결정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- CONVERT(데이터타입, 표현식, [스타일]) 형태로 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터타입: 변환하고자 하는 목표 데이터 타입. (예: VARCHAR(10), INT, DATETIME)&lt;/li&gt;
&lt;li&gt;표현식: 변환할 원본 값 (예: GETDATE(), 숫자, 다른 컬럼)&lt;/li&gt;
&lt;li&gt;[스타일]: (선택 사항) 특히 날짜나 시간을 문자열로 변환할 때, 어떤 형식으로 변환할지 지정하는 숫자 코드.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CONVERT(VARCHAR(10), DATEADD(MONTH, -1, GETDATE()), 23)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DATEADD함수: 날짜/시간 값에 특정 시간 간격을 더하거나 빼는 함수이다.&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;SET은 변수에 값을 대입할 때 사용합니다. 프로시저 안에서 선언된 지역 변수에 새로운 값을 넣는 역할.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EXEC 는 다른 프로시저를 실행하거나 동적 SQL을 실행할 때 사용.&amp;nbsp;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예외처리 부분에서는,&lt;/p&gt;
&lt;pre id=&quot;code_1756865795272&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;BEGIN CATCH
	SET	@V_MAINT_VALUE	= ERROR_MESSAGE();
END CATCH;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드에서 ERROR_MESSAGE() 함수는 따로 만들 필요가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ERROR_MESSAGE()는 SQL Server에서 이미 내장되어 있는 함수이기 때문에.&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;IIF는 &lt;b&gt;간단한 IF...ELSE 논리&lt;/b&gt;를 한 줄로 표현하는 SQL Server의 함수.&lt;/p&gt;</description>
      <category>Back-end</category>
      <category>MSSQL</category>
      <category>프로시저</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/145</guid>
      <comments>https://thfdl0317.tistory.com/entry/MSSQL-%ED%94%84%EB%A1%9C%EC%8B%9C%EC%A0%80-%EC%9E%91%EC%84%B1%ED%95%98%EA%B8%B0#entry145comment</comments>
      <pubDate>Mon, 25 Aug 2025 08:32:01 +0900</pubDate>
    </item>
    <item>
      <title>당신이 TS를 사용하시는 이유에 대해 말씀해주세요. 상세히.. JS와 비교해서! </title>
      <link>https://thfdl0317.tistory.com/entry/%EA%B0%95%ED%83%80%EC%9E%85%EA%B3%BC-%EC%95%BD%ED%83%80%EC%9E%85-%EA%B7%B8%EB%A6%AC%EA%B3%A0-ts-%EC%98%B5%EC%85%94%EB%84%90-%EC%82%AC%EC%9A%A9%EB%B2%95%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;왜 TypeScript를 사용할까? 자바스크립트와 비교하며 이해하며 정리하는 것이 오늘의 목표이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프로젝트에 투입되면 어떤 곳은 여전히&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;JavaScript(JS)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;를, 어떤 곳은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;TypeScript(TS)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;를 사용합니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그럼 왜 javaScript 쓰다가 TypeScript로 많이 쓰던데 왜 굳이요? 라고 묻는다면&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;요즘은 대부분의 프론트엔드 프로젝트에서 TS를 사용합니다. 이유는 단순히 &amp;ldquo;타입을 지정할 수 있다&amp;rdquo;라는 말로는 부족합니다. 이번 글에서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;자바스크립트와 타입스크립트의 차이&lt;/b&gt;를 여러 관점에서 풀어보고, 왜 TS를 적극적으로 활용해야 하는지 정리해보겠습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;1. 강타입 vs 약타입&lt;/h3&gt;
&lt;h4 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;종류&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;강타입: C++, JAVA, Haskell, Typescript&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;약타입: C, JavaScript, PHP, Rudy, Pyton&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;강타입이란?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;프로그래밍 언어에서 정수, 문자열과 같이 데이터 타입을 미리 지정하는 언어. 모든 상수 그리고 변수들은 데이터의 타입을 정의해주어야한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;서로 다른 데이터 타입의 혼합에 대해서 확고하게 제한을 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;강타입의 단점과 장점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;단점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;유연성 감소&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;장점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;엄격한 규칙으로 인해 결과의 일관성을 보장한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;컴파일 에러를 통한 런타입 에러 방지&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;타입 에러의 결과를 낳을 수 있는 잘못 사용된 변수들을 모두 골라낼 수 있다는 것&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;컴파일러를 통한 조기 에러 감지, 최적화된 코드를 통한 개발 가속화&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;데이터 타입에 대한 명세를 요구한다면 강타입언어를 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;약타입의 단점과 장점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;단점&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;장점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;별다른 명세를 요구하지 않는다면 약타입 언어, 약타입 언어의 경우 runtime에 암시적으로 타입의 변환을 실행할 수 있기 때문에 잘못되거나 예측 불가능한 결과를 생산할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;어떻게 강, 약 구분하나?&lt;/h4&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 형변환(type conversion) : 캐스팅(casting) 이라고도 하며&amp;nbsp;명시적(explicit) 또는 묵시적(implicit)으로 자료의 형식을 변환하는 것을 말한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 한마디로 type을 변환시킨다는 것.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 강타입과 약타입이란 형변환(Type Casting or Type Conversion)을 기준으로 구분된다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;강타입 언어는 다른 형끼리의 변환이 금지되어있고 변환하고자 한다면 명시적으로 타입을 선언해줘야한다.차이점 강타입 약타입&lt;/p&gt;
&lt;table style=&quot;background-color: #ffffff; color: #333333; text-align: start; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;color: #333333;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;color: #333333;&quot;&gt;형변환 금지&lt;/td&gt;
&lt;td style=&quot;color: #333333;&quot;&gt;형변환이 자유로움 (암묵적으로 변환을 주기도 한다.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;color: #333333;&quot;&gt;에러 검출의 가능 여부&lt;/td&gt;
&lt;td style=&quot;color: #333333;&quot;&gt;타입에러를 항상 검출할 수 있다.&lt;/td&gt;
&lt;td style=&quot;color: #333333;&quot;&gt;타입에러를 항상 검출할 수 없다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트도 변수에 타입을 줄 수 있어서 타입 에러 검출가능하다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;타입의 추론이 사람이아냐 언어가 하냐&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;언어가 알아서 유추한다. 빌드 시점이 아니라 런타임 시점에서 추론하는게&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 자바스크립트(JS)&lt;/b&gt;&lt;span&gt;: 약타입 언어. 숫자 + 문자열 = 문자열 합치기 같은&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;암묵적 형 변환&lt;/b&gt;&lt;span&gt;이 일어나 버그가 생기기 쉽다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 타입스크립트(TS)&lt;/b&gt;: 강타입 체크. 잘못된 타입 조합은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;빌드 타임에 에러&lt;/b&gt;가 나므로 실수를 미리 막는다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;2. 런타임 , 빌드타임 시점의 차이&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;688&quot; data-end=&quot;757&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;688&quot; data-end=&quot;721&quot;&gt;&lt;b&gt;JS&lt;/b&gt;: 실행(런타임) 중에야 오류가 드러난다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;722&quot; data-end=&quot;757&quot;&gt;&lt;b&gt;TS&lt;/b&gt;: 실행 전(빌드타임)에 미리 오류를 잡는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-start=&quot;759&quot; data-end=&quot;808&quot;&gt;즉,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;사용자가 에러를 보기 전에 개발자가 막을 수 있다&lt;/b&gt;는 게 핵심 장점이다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-start=&quot;759&quot; data-end=&quot;808&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-start=&quot;759&quot; data-end=&quot;808&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-start=&quot;759&quot; data-end=&quot;808&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot; data-start=&quot;815&quot; data-end=&quot;841&quot;&gt;3. 인터페이스, enum, extends&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-start=&quot;842&quot; data-end=&quot;922&quot;&gt;TS는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;객체 구조, 상수 집합, 상속&lt;/b&gt;을 명시적으로 표현할 수 있다.&lt;br /&gt;이는 코드의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;문서화 + 자동완성 + 안정성&lt;/b&gt;을 동시에 준다.&lt;/p&gt;
&lt;pre id=&quot;code_1759407013564&quot; class=&quot;routeros&quot; style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;interface User {
  id: number;
  name: string;
}

enum Role {
  Admin,
  User,
}

interface AdminUser extends User {
  role: Role.Admin;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot; data-start=&quot;1079&quot; data-end=&quot;1097&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot; data-start=&quot;1079&quot; data-end=&quot;1097&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot; data-start=&quot;1079&quot; data-end=&quot;1097&quot;&gt;4. 타입 선언 시점의 차이&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;1098&quot; data-end=&quot;1169&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;1098&quot; data-end=&quot;1133&quot;&gt;&lt;b&gt;JS&lt;/b&gt;: 변수에 뭘 넣든 실행할 때만 알 수 있다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;1134&quot; data-end=&quot;1169&quot;&gt;&lt;b&gt;TS&lt;/b&gt;: 변수를 선언할 때 타입을 강제할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-start=&quot;1171&quot; data-end=&quot;1218&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-start=&quot;1171&quot; data-end=&quot;1218&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot; data-start=&quot;1225&quot; data-end=&quot;1245&quot;&gt;5. 제너릭 (Generics)&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-start=&quot;1246&quot; data-end=&quot;1284&quot;&gt;제너릭은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;재사용성&lt;/b&gt;과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;타입 안전성&lt;/b&gt;을 동시에 잡아준다.&lt;/p&gt;
&lt;pre id=&quot;code_1759407013565&quot; class=&quot;fortran&quot; style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;function wrap&amp;lt;T&amp;gt;(value: T): { data: T } {
  return { data: value };
}

const num = wrap(123);     // { data: number }
const str = wrap(&quot;hello&quot;); // { data: string }&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot; data-start=&quot;1466&quot; data-end=&quot;1494&quot;&gt;6. any는 언제 쓰고 왜 남발하면 안될까?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;1495&quot; data-end=&quot;1657&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;1495&quot; data-end=&quot;1541&quot;&gt;&lt;b&gt;any&lt;/b&gt;: 타입 검사를 완전히 무시 &amp;rarr; 다시 자바스크립트와 똑같아진다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;1542&quot; data-end=&quot;1604&quot;&gt;언제 쓰나?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;1555&quot; data-end=&quot;1604&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;1555&quot; data-end=&quot;1581&quot;&gt;외부 라이브러리에서 타입 정의가 없을 때&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;1584&quot; data-end=&quot;1604&quot;&gt;빠른 프로토타이핑이 필요할 때&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;1605&quot; data-end=&quot;1657&quot;&gt;왜 남발하면 안되나?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;1623&quot; data-end=&quot;1657&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;1623&quot; data-end=&quot;1657&quot;&gt;TS의 장점(안전성, 자동완성)을 다 잃어버리기 때문&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;1623&quot; data-end=&quot;1657&quot;&gt;&amp;nbsp;단점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;1673&quot; data-end=&quot;1803&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;1673&quot; data-end=&quot;1728&quot;&gt;&lt;b&gt;타입 유실&lt;/b&gt;: TS는 결국 JS로 컴파일되므로,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;런타임에서는 타입 정보가 없다&lt;/b&gt;.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;1729&quot; data-end=&quot;1768&quot;&gt;&lt;b&gt;러닝 커브&lt;/b&gt;: 초반에는 문법과 타입 정의가 낯설 수 있다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;1769&quot; data-end=&quot;1803&quot;&gt;&lt;b&gt;개발 속도&lt;/b&gt;: 초기 코딩 속도는 느려질 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;1623&quot; data-end=&quot;1657&quot;&gt;&amp;nbsp;장점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;1819&quot; data-end=&quot;1956&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;1819&quot; data-end=&quot;1863&quot;&gt;&lt;b&gt;조기 에러 차단&lt;/b&gt;: 만에 하나 있을 큰 버그를 미리 막을 수 있다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;1864&quot; data-end=&quot;1913&quot;&gt;&lt;b&gt;대규모 프로젝트 유지보수&lt;/b&gt;: 팀원 간 명세가 맞춰지니 협업 효율이 올라간다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;1914&quot; data-end=&quot;1956&quot;&gt;&lt;b&gt;IDE 지원 극대화&lt;/b&gt;: 자동완성, 타입 추론, 안전한 리팩토링.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: left;&quot;&gt;an&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: left;&quot;&gt;y 말고 안정성을 잡는 방법&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: left;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;1987&quot; data-end=&quot;2151&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;1987&quot; data-end=&quot;2032&quot;&gt;unknown: any와 비슷하지만, 사용하려면 타입 체크가 필요하다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;2033&quot; data-end=&quot;2073&quot;&gt;union type (|): 가능한 타입들을 명시적으로 제한.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;2074&quot; data-end=&quot;2102&quot;&gt;never: 발생할 수 없는 값을 표현.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;2103&quot; data-end=&quot;2151&quot;&gt;strictNullChecks: null/undefined를 엄격하게 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;정리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; typeScript는 단순히 &amp;ldquo;타입 있는 자바스크립트&amp;rdquo;가 아님. &lt;b&gt;개발 과정에서 안전망을 제공하는 언어 도구&lt;/b&gt;이며, 특히 규모가 커질수록 그 진가를 발휘한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;1495&quot; data-end=&quot;1657&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;2643&quot; data-end=&quot;2740&quot;&gt;자바스크립트가 자유로운&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;인터프리터 언어&lt;/b&gt;라면, 타입스크립트는 그 자유를 유지하면서도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;안정성과 예측 가능성&lt;/b&gt;을 더해준다는 것.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;2322&quot; data-end=&quot;2380&quot;&gt;때로는 개발자가 컴파일러보다 더 확실히 타입을 아는 경우가 있다. 이럴 때&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;타입 단언&lt;/b&gt;을 사용한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;2322&quot; data-end=&quot;2380&quot;&gt;자바스크립트는 유연하고 빠른 개발이 장점이지만, 그만큼&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;실수에 관대&lt;/b&gt;하다는 단점이 있습니다. TypeScript는 이런 단점을 보완하기 위해 등장한거고. 단순히 &quot;타입 붙이는 언어&quot;가 아니라,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;개발 과정에서 버그를 조기에 차단&lt;/b&gt;하고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;대규모 프로젝트를 더 안전하게 관리&lt;/b&gt;할 수 있게 해주는 도구.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>자바스크립트</category>
      <category>타입스크립트</category>
      <category>프론트엔드</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/139</guid>
      <comments>https://thfdl0317.tistory.com/entry/%EA%B0%95%ED%83%80%EC%9E%85%EA%B3%BC-%EC%95%BD%ED%83%80%EC%9E%85-%EA%B7%B8%EB%A6%AC%EA%B3%A0-ts-%EC%98%B5%EC%85%94%EB%84%90-%EC%82%AC%EC%9A%A9%EB%B2%95%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC#entry139comment</comments>
      <pubDate>Mon, 25 Nov 2024 10:25:25 +0900</pubDate>
    </item>
    <item>
      <title>시간 복잡도와 고차 함수: 실무에서 꼭 함께 생각해야 하는 이유</title>
      <link>https://thfdl0317.tistory.com/entry/React-%EB%AA%A8%EB%8B%AC-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%99%80-%EC%8A%A4%EB%82%B5%EB%B0%94-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EA%B5%AC%ED%98%84</link>
      <description>&lt;p data-end=&quot;219&quot; data-start=&quot;116&quot; data-ke-size=&quot;size16&quot;&gt;개발을 하다 보면 시간복잡도(Big-O)와 고차 함수(map, filter, reduce 등)를 모두 접하게 되는데&lt;/p&gt;
&lt;p data-end=&quot;219&quot; data-start=&quot;116&quot; data-ke-size=&quot;size16&quot;&gt;이전에 언뜻 보기엔 전혀 다른 분야의 개념처럼 보였다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;276&quot; data-start=&quot;220&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;243&quot; data-start=&quot;220&quot;&gt;시간복잡도는 알고리즘 이론의 영역.&lt;/li&gt;
&lt;li data-end=&quot;276&quot; data-start=&quot;244&quot;&gt;고차 함수는 함수형 프로그래밍과 언어 문법의 영역.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;360&quot; data-start=&quot;278&quot; data-ke-size=&quot;size16&quot;&gt;하지만 실제 현업에서는 이 둘을 따로 떼어 생각하기 어렵다.&lt;/p&gt;
&lt;p data-end=&quot;360&quot; data-start=&quot;278&quot; data-ke-size=&quot;size16&quot;&gt;왜냐하면, &lt;b&gt;고차 함수의 사용 자체가 곧 시간복잡도와 직결되기 때문이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;360&quot; data-start=&quot;278&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;360&quot; data-start=&quot;278&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;360&quot; data-start=&quot;278&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;378&quot; data-start=&quot;367&quot; data-ke-size=&quot;size26&quot;&gt;시간복잡도란?&amp;nbsp;&lt;/h2&gt;
&lt;p data-end=&quot;437&quot; data-start=&quot;379&quot; data-ke-size=&quot;size16&quot;&gt;시간복잡도란, 입력 크기에 따라 알고리즘이 얼마나 빠르게 실행되는지를 수학적으로 나타내는 지표.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;536&quot; data-start=&quot;438&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;470&quot; data-start=&quot;438&quot;&gt;O(1): 입력 크기와 관계없이 항상 일정한 시간.&lt;/li&gt;
&lt;li data-end=&quot;501&quot; data-start=&quot;471&quot;&gt;O(n): 입력 크기에 비례해서 시간이 늘어남.&lt;/li&gt;
&lt;li data-end=&quot;536&quot; data-start=&quot;502&quot;&gt;O(n&amp;sup2;): 입력 크기의 제곱에 비례해 시간이 늘어남.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;571&quot; data-start=&quot;538&quot; data-ke-size=&quot;size16&quot;&gt;개발자는 이 복잡도를 바탕으로 코드가 효율적인지 판단한다.&lt;/p&gt;
&lt;p data-end=&quot;571&quot; data-start=&quot;538&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;571&quot; data-start=&quot;538&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;588&quot; data-start=&quot;578&quot; data-ke-size=&quot;size26&quot;&gt;고차 함수란?&lt;/h2&gt;
&lt;p data-end=&quot;634&quot; data-start=&quot;589&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트에서 고차 함수(Higher-Order Function)란 다음 중 하나라도 만족하는 함수를 말한.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;666&quot; data-start=&quot;635&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;650&quot; data-start=&quot;635&quot;&gt;함수를 인자로 받는 함수,&lt;/li&gt;
&lt;li data-end=&quot;650&quot; data-start=&quot;635&quot;&gt;함수를 결과값으로 반환하는 함수&lt;/li&gt;
&lt;li data-end=&quot;650&quot; data-start=&quot;635&quot;&gt;함수를 마치 클래스에서 만들어낸 '인스턴스' 처럼 취급하는 방법&lt;/li&gt;
&lt;li data-end=&quot;650&quot; data-start=&quot;635&quot;&gt;함수를 파라미터로 넘겨줄 수도 있고 결과값으로 반환받을 수도 있는 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 함수를 값처럼 다룰 수 있는 언어적 특성을 활용한 프로그래밍 방식이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;666&quot; data-start=&quot;635&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;650&quot; data-start=&quot;635&quot;&gt;프로그래밍의 단계를 한 단계 높일 수 있는 방법 중 하나&lt;/li&gt;
&lt;li data-end=&quot;650&quot; data-start=&quot;635&quot;&gt;특별 대우를 받는 함수를 일급 객체가 있다.&lt;/li&gt;
&lt;li data-end=&quot;650&quot; data-start=&quot;635&quot;&gt;일급 객체의 세가지 특징
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;650&quot; data-start=&quot;635&quot;&gt;변수에 할당할 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;650&quot; data-start=&quot;635&quot;&gt;다른 함수의 인자로 전달될 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;650&quot; data-start=&quot;635&quot;&gt;다른 함수의 결과로서 리턴될 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 특성 덕분에 map(), filter(), reduce() 같은 고차 함수가 가능해집니다.&lt;br /&gt;내부적으로는 콜백 함수를 실행하며 모든 원소를 순회한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;666&quot; data-start=&quot;635&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;666&quot; data-start=&quot;651&quot;&gt;실제 고차함수 연속된 형태로 많이 쓴다.&lt;/li&gt;
&lt;li data-end=&quot;666&quot; data-start=&quot;651&quot;&gt;맵이 순회된 결과물을 연속성을 가진다. 연속성 하나의 고차함수가 끝난 뒤에 별도에 로직을 통하지 않고 다음 로직으로 가는 것을 연속성이라고한다.&lt;/li&gt;
&lt;li data-end=&quot;666&quot; data-start=&quot;651&quot;&gt;새로운 값을 반환하기 때문에.&lt;/li&gt;
&lt;li data-end=&quot;666&quot; data-start=&quot;651&quot;&gt;실제 내부의 콜백함수가 작동하기 때문에 고차함수 내부인자를 함수로 받거나&amp;nbsp;&lt;/li&gt;
&lt;li data-end=&quot;666&quot; data-start=&quot;651&quot;&gt;객체 리터럴, map()&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;722&quot; data-start=&quot;668&quot; data-ke-size=&quot;size16&quot;&gt;를 뜻한다.&lt;/p&gt;
&lt;p data-end=&quot;722&quot; data-start=&quot;668&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;722&quot; data-start=&quot;668&quot; data-ke-size=&quot;size16&quot;&gt;구글링하면 대표적인 고차함수로 map, filter, reduce 같은 배열 메서드,&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;722&quot; data-start=&quot;668&quot; data-ke-size=&quot;size16&quot;&gt;예시 코드로 간단하게 보이자면&lt;/p&gt;
&lt;pre id=&quot;code_1759662055309&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const arr = [1, 2, 3, 4, 5];

// map: 모든 원소를 2배 &amp;rarr; O(n)
const doubled = arr.map(x =&amp;gt; x * 2);

// filter: 조건에 맞는 원소만 추출 &amp;rarr; O(n)
const evens = arr.filter(x =&amp;gt; x % 2 === 0);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;1087&quot; data-start=&quot;1065&quot; data-ke-size=&quot;size26&quot;&gt;일급 객체와 고차 함수의 관계&lt;/h2&gt;
&lt;p data-end=&quot;1168&quot; data-start=&quot;1089&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트에서 함수는 &lt;b&gt;일급 객체(First-Class Object)&lt;/b&gt;&amp;nbsp;&lt;br /&gt;즉, 함수는 다른 값처럼 자유롭게 다룰 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;1168&quot; data-start=&quot;1089&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1168&quot; data-start=&quot;1089&quot; data-ke-size=&quot;size16&quot;&gt;다시 일급객체의 특징을 보자면,&lt;/p&gt;
&lt;p data-end=&quot;1188&quot; data-start=&quot;1170&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;일급 객체의 세 가지 특징&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1261&quot; data-start=&quot;1189&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1207&quot; data-start=&quot;1189&quot;&gt;변수에 할당할 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;1233&quot; data-start=&quot;1208&quot;&gt;다른 함수의 인자로 전달될 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;1261&quot; data-start=&quot;1234&quot;&gt;다른 함수의 결과값으로 반환될 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;1374&quot; data-start=&quot;1263&quot; data-ke-size=&quot;size16&quot;&gt;이 덕분에 map(), filter(), reduce() 같은 고차 함수가 가능해짐.&lt;br /&gt;내부적으로 &lt;b&gt;콜백 함수가 실행되며&lt;/b&gt;, 그 과정에서 &lt;b&gt;반복문처럼 모든 원소를 순회&lt;/b&gt;합니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;928&quot; data-start=&quot;909&quot; data-ke-size=&quot;size26&quot;&gt;고차 함수와 시간복잡도의 만남&lt;/h2&gt;
&lt;p data-end=&quot;1019&quot; data-start=&quot;929&quot; data-ke-size=&quot;size16&quot;&gt;고차 함수는 내부적으로 &lt;b&gt;반복문을 돌며 배열의 모든 원소를 처리&lt;/b&gt;합니다.&lt;br /&gt;즉, 고차 함수를 쓰는 순간 자연스럽게 &lt;b&gt;시간복잡도 계산이 따라와야 합니다.&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-end=&quot;1030&quot; data-start=&quot;1021&quot; data-ke-size=&quot;size23&quot;&gt;단순 사용&lt;/h3&gt;
&lt;pre id=&quot;code_1759662220122&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const result = arr.map(x =&amp;gt; x * 2); // O(n)&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1095&quot; data-start=&quot;1086&quot; data-ke-size=&quot;size23&quot;&gt;연속 사용&lt;/h3&gt;
&lt;pre id=&quot;code_1759662269024&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const result = arr.filter(x =&amp;gt; x &amp;gt; 10).map(x =&amp;gt; x * 2);
// filter: O(n) + map: O(n) = O(2n) &amp;asymp; O(n)&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1234&quot; data-start=&quot;1207&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;1247&quot; data-start=&quot;1236&quot; data-ke-size=&quot;size23&quot;&gt;비효율적 사용&lt;/h3&gt;
&lt;pre id=&quot;code_1759662290904&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const result = arr.map(x =&amp;gt; arr.filter(y =&amp;gt; y === x));
// map: O(n)
// filter: O(n)
// 전체: O(n&amp;sup2;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 불필요한 중첩 호출로 &lt;b&gt;성능이 급격히 저하&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1387&quot; data-start=&quot;1356&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1387&quot; data-start=&quot;1356&quot; data-ke-size=&quot;size16&quot;&gt;이 외에 자바스크립트 배열 고차함수들&lt;/p&gt;
&lt;p data-end=&quot;1387&quot; data-start=&quot;1356&quot; data-ke-size=&quot;size16&quot;&gt;.forEach(), .reduce(), .filter(), .some(), findIndex(), .map(), .find(), .sort()가 있다.&lt;/p&gt;
&lt;p data-end=&quot;1387&quot; data-start=&quot;1356&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1387&quot; data-start=&quot;1356&quot; data-ke-size=&quot;size18&quot;&gt;.forEach()&lt;/p&gt;
&lt;pre id=&quot;code_1759663518010&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const testArray = [1, 2, 3, 4];

testArray.forEach(Element =&amp;gt; console.log(Element));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;1387&quot; data-start=&quot;1356&quot; data-ke-size=&quot;size16&quot;&gt;여기 코드 보면 배열의 각 요소(1, 2, 3, 4)를 하나씩 꺼내서 console.log(element)를 실행한다.&lt;/p&gt;
&lt;p data-end=&quot;1387&quot; data-start=&quot;1356&quot; data-ke-size=&quot;size16&quot;&gt;forEach는 배열의 각 요소에 대해 element =&amp;gt; console.log(element)라는 함수를 호출한다.&lt;/p&gt;
&lt;p data-end=&quot;1387&quot; data-start=&quot;1356&quot; data-ke-size=&quot;size16&quot;&gt;이 때 forEach는 함수 (element =&amp;gt; console.log(element))를 인자로 받으므로 고차 함수로 분류된다.&lt;/p&gt;
&lt;p data-end=&quot;1387&quot; data-start=&quot;1356&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;1387&quot; data-start=&quot;1356&quot; data-ke-size=&quot;size20&quot;&gt;.reduce()&lt;/h4&gt;
&lt;p data-end=&quot;1387&quot; data-start=&quot;1356&quot; data-ke-size=&quot;size16&quot;&gt;배열의 모든 요소를 원하는 방식으로 결합하여 단 하나의 값을 생성하는 고차함수&lt;/p&gt;
&lt;p data-end=&quot;1387&quot; data-start=&quot;1356&quot; data-ke-size=&quot;size16&quot;&gt;reduce함수는 첫 번째 인자로 함수를 받는다. 이 함수는 배열의 각 요소에 대해 호출되고&lt;/p&gt;
&lt;p data-end=&quot;1387&quot; data-start=&quot;1356&quot; data-ke-size=&quot;size16&quot;&gt;이전에 계산 결과와 현재 요소를 받아서 새로운 결과를 반환한다.&lt;/p&gt;
&lt;pre id=&quot;code_1759664699656&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const array = [1, 2, 3, 4];

const init = 0; // 초기값을 0으로 설정
const sum = array.reduce((test1, currentValue) =&amp;gt; test1 + currentValue, init);

console.log(sum); // 10&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;1387&quot; data-start=&quot;1356&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1387&quot; data-start=&quot;1356&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;1387&quot; data-start=&quot;1356&quot; data-ke-size=&quot;size20&quot;&gt;.filter()&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;filter함수는 배열의 각 요소에 대해 조건을 검사하는 함수(콜백 함수)를 인자로 받는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 콜백 함수는 배열의 각 요소에 대해 실행되며, true를 반환하는 요소들로만 새로운 배열을 만들어 반환.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드에서 filter 함수는 다음과 같이 동작.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;filter는 배열 test의 각 요소에 대해 콜백 함수 item =&amp;gt; item.length를 호출한다.&lt;/li&gt;
&lt;li&gt;이 콜백 함수는 각 요소의 길이(item.length)를 반환. 길이가 0이 아닌 경우에는 true로 간주되므로, 모든 요소가 길이를 가지고 있어서 이 경우 filter는 모든 요소를 결과 배열에 포함시킨다.&lt;/li&gt;
&lt;li&gt;최종적으로 filter는 조건을 만족하는 요소들(여기서는 모든 요소)을 포함하는 새 배열 result를 반환.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;filter가 고차 함수인 이유&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;고차 함수의 정의에 부합&lt;/b&gt;: filter는 &lt;b&gt;함수를 인자로 받기 때문에&lt;/b&gt; 고차 함수이다. 여기서 인자로 받은 함수는 item =&amp;gt; item.length&lt;/li&gt;
&lt;li&gt;이 콜백 함수는 배열의 각 요소에 대해 실행되며, filter 함수 내부에서 처리된 후 결과 배열을 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1759665853837&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const test = ['솔1', '솔2', '솔3', '솔4'];

const result = test.filter(item =&amp;gt; item.length);

console.log(result);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;.some()&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고차함수는 다른 함수를 인자로 받거나 함수를 반환하는 함수를 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;some함수의 동작 방식은 배열에서 적어도 하나의 요소가 주어진 조건을 만족하는지를 확인하는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 함수는 조건을 검사하기 위해 콜백 함수를 인자로 받는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열의 요소 중 하나라도 이 콜백 함수에서 true를 반환하면 some함수는 true를 반환 그렇지 아니하면 false를 반환.&lt;/p&gt;
&lt;pre id=&quot;code_1759666551037&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const numbers = [1, 2, 3, 4, 5];

const hasEvenNumber = numbers.some(num =&amp;gt; num % 2 === 0);

console.log(hasEvenNumber); // true&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;배열 numbers는 [1, 2, 3, 4, 5]&lt;/li&gt;
&lt;li&gt;some() 함수는 배열의 각 요소에 대해 콜백 함수 num =&amp;gt; num % 2 === 0을 호출.&lt;/li&gt;
&lt;li&gt;콜백 함수는 각 요소가 &lt;b&gt;짝수인지&lt;/b&gt;를 확인.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;첫 번째 요소 1은 짝수가 아니므로 false 반환&lt;/li&gt;
&lt;li&gt;두 번째 요소 2는 짝수이므로 true 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;some() 함수는 두 번째 요소에서 true를 반환받았기 때문에, 나머지 요소를 확인하지 않고 바로 true를 반환.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;some()가 고차 함수인 이유&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;some() 함수는 &lt;b&gt;함수를 인자로 받기 때문에&lt;/b&gt; 고차 함수.&lt;/li&gt;
&lt;li&gt;여기서 인자로 받은 함수는 num =&amp;gt; num % 2 === 0이라는 &lt;b&gt;콜백 함수&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;이 콜백 함수는 some() 함수 내부에서 배열의 각 요소에 대해 실행.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;some()는 고차 함수. 그 이유는 some() 함수가 배열의 각 요소에 대해 조건을 검사하기 위해 &lt;b&gt;콜백 함수를 인자로 받기 때문&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 콜백 함수는 some() 함수 내부에서 실행되어, 배열의 요소들이 주어진 조건을 만족하는지 확인하는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;1405&quot; data-start=&quot;1394&quot; data-ke-size=&quot;size26&quot;&gt;실무에서의 교훈&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1615&quot; data-start=&quot;1406&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1462&quot; data-start=&quot;1406&quot;&gt;고차 함수 = 반복문&lt;br /&gt;보기에는 깔끔해 보여도, 결국 모든 원소를 순회합니다.&lt;/li&gt;
&lt;li data-end=&quot;1537&quot; data-start=&quot;1464&quot;&gt;중첩에 주의&lt;br /&gt;filter 안에서 또 map, map 안에서 또 filter 같은 패턴은 성능 저하의 원인.&lt;/li&gt;
&lt;li data-end=&quot;1615&quot; data-start=&quot;1539&quot;&gt;가독성과 성능의 균형&lt;br /&gt;고차 함수는 가독성을 높이지만, 성능이 중요한 구간에서는 시간복잡도를 꼭 고려해야 한다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-end=&quot;1628&quot; data-start=&quot;1622&quot; data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-end=&quot;1694&quot; data-start=&quot;1629&quot; data-ke-size=&quot;size16&quot;&gt;시간복잡도와 고차 함수는 개념적으로는 다른 출발점에서 왔지만, 실무에서는 절대 분리할 수 없는 관계입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1743&quot; data-start=&quot;1695&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1718&quot; data-start=&quot;1695&quot;&gt;시간복잡도는 성능을 평가하는 잣대.&lt;/li&gt;
&lt;li data-end=&quot;1743&quot; data-start=&quot;1719&quot;&gt;고차 함수는 성능 분석의 주요 대상.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1842&quot; data-start=&quot;1745&quot; data-ke-size=&quot;size16&quot;&gt;따라서 개발자가 고차 함수를 쓸 때는 단순히 &quot;코드가 깔끔하다&quot;에서 멈추지 말고,&lt;br /&gt;이 코드의 시간복잡도는 얼마일까?&amp;rdquo;를 항상 함께 고민하는 습관이 필요하다 생각한다.&lt;/p&gt;</description>
      <category>고차함수</category>
      <category>시간복잡도</category>
      <category>자바스크립트</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/137</guid>
      <comments>https://thfdl0317.tistory.com/entry/React-%EB%AA%A8%EB%8B%AC-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%99%80-%EC%8A%A4%EB%82%B5%EB%B0%94-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EA%B5%AC%ED%98%84#entry137comment</comments>
      <pubDate>Tue, 12 Nov 2024 16:06:02 +0900</pubDate>
    </item>
    <item>
      <title>팀원과 협업 시 좋은 코드를 만들기 위한 기본 원칙들을 돌이켜보며</title>
      <link>https://thfdl0317.tistory.com/entry/React-%ED%98%91%EC%97%85%EC%9D%84-%EC%9C%84%ED%95%B4-%EC%A1%B0%EA%B8%88-%EB%8D%94-%EC%8B%A0%EA%B2%BD-%EC%93%B8-%EB%82%B4%EC%9A%A9-%EB%AA%A8%EC%9D%8C1-%ED%8C%8C%EC%9D%BC-%EC%97%85%EB%A1%9C%EB%93%9C-%EC%8B%9C</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;너는 if문을 왜 그렇게 써?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 중첩된 else if,&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;switch문을 사용할 생각은 없는거야?&lt;/p&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;좋은 코드란 것에 대해서 돌이키며 유념하고자 정리하는 글이다.&lt;/p&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;ldquo;가독성&amp;rdquo; &amp;rArr; 변수명, 함수명, 들여쓰기, 구조가 직관적이어야한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Readability&amp;nbsp; &amp;rArr; 읽기 쉬운가?&lt;/p&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;ldquo;유지 보수성&amp;rdquo;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Maintainability &lt;/span&gt;&amp;rArr; 고치기 쉬운가?&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;중복 코드 제거, 모듈화, SRP(단일 책임 원칙) 등을 지키면 좋다. &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;Scalability(확장성) / Extensibility(확장 가능성)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Scalability (확장성)쉽게 말해 &amp;ldquo;사용자가 늘어나도 버틸 수 있냐&amp;rdquo; 하는 개념&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.웹 서비스가 처음엔 100명 접속, 나중엔 10만 명 접속해도 서버 증설이나 아키텍처로 대응 가능해야한다는 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Scalability &amp;rArr; 성능 측면에서의 확장 가능성새로운 기능을 추가하거나 기존 기능을 수정할 때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Extensibility &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt; &amp;rArr; &lt;/span&gt;&lt;/span&gt;&amp;nbsp;새로운 요구사항/기능 추가에 대한 구조적 확장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;소프트웨어 설계의 코딩 원칙&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;솔리드 원칙 SOLID (객체지향 설계의 대표 원칙)
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;단일 책임의 원칙 Single Responsibility Principle (SRP)&lt;/li&gt;
&lt;li&gt;개방 폐쇄의 원칙 open/closed Principle (ocp)&lt;/li&gt;
&lt;li&gt;리스코프 치환의 원칙 Liskov Substitution Principle (LSP)&lt;/li&gt;
&lt;li&gt;인터페이스 분리 원칙 Interface Segregation Principle (ISP)&lt;/li&gt;
&lt;li&gt;의존성 역전의 원칙 Dependency Inversion Principle (DIP)&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;단일 책임의 원칙 &amp;rArr; 하나의 클래스는 하나의 책임만 가져야한다.&lt;/li&gt;
&lt;li&gt;개방폐쇄 원칙 &amp;rArr; 확장에는 열려있어야하고 수정에는 닫혀있어야한다.&lt;/li&gt;
&lt;li&gt;리스코프 치환 원칙 &amp;rArr; 자식 클래스는 부모 클래스를 대체할 수 있어야 한다. (뭔 말이냐면 상위 타입의 객체를 하위 타입 객체로 바꿔도 프로그램의 정상 동작이 깨지지 않아야 한다.)&lt;/li&gt;
&lt;li&gt;인터페이스 분리 원칙 &amp;rArr; 인터페이스는 사용하지 않는 메서드에 의존하지 않아야한다.&lt;/li&gt;
&lt;li&gt;의존성 역전의 원칙 &amp;rArr; 고수준 모듈은 저수준 모듈에 의존하지 않아야한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;클린 코드의 핵심 원칙&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어 개발에서 흔히 말하는 좋은 코드는 clean code나 코딩 원칙 같은 기준에 따라 평가되는데,&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;중복은 피하라. DRY &amp;rArr; don&amp;rsquo;t repeat yourself&lt;/li&gt;
&lt;li&gt;함수는 작고 하나의 작업만하라&lt;/li&gt;
&lt;li&gt;명확한 이름을 사용하라&lt;/li&gt;
&lt;li&gt;주석은 최소화하되, 꼭 필요한 경우는 써라.&lt;/li&gt;
&lt;li&gt;데이터 구조보다 인터페이스를 드러내라.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉,&amp;nbsp; 좋은 코드는 &amp;ldquo;사람이 읽기 쉽고 바꾸기 쉬운 코드&amp;rdquo;다.&lt;/p&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;if else if 중첩문은&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가독성: 조건문이 길어짐&lt;/li&gt;
&lt;li&gt;유지보수성: 역할 하나 추가하려면 코드를 수정해야함&lt;/li&gt;
&lt;li&gt;확장성: 역할별 로직이 많아지면 난장판&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;가독성 저하 - 조건이 많아질수록 코드를 따라가기가 힘들고 구조 파악이 어렵다.&lt;/li&gt;
&lt;li&gt;유지보수 어려움 - 새 조건을 추가하거나 변경할 때 기존 로직을 깨기 쉽다.&lt;/li&gt;
&lt;li&gt;디버깅 어려움 - 어디서 분기 되었는지 추적하기 힘들어진다.&lt;/li&gt;
&lt;li&gt;중복된 조건 평가 - 비효율적인 흐름 제어로 이어질 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rArr; 개선 방법으로&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;조건 분기 함수화&lt;/li&gt;
&lt;li&gt;객체 매핑 방식 사용&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 많이 사용하는 것들 중,&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;switch문과 if문의 성능 차이&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사실 성능 차이는 미세함&lt;/li&gt;
&lt;li&gt;js 엔진이 최적화 해주기 때문에 if-else와 switch는 거의 동일하다.&lt;/li&gt;
&lt;li&gt;그러나! 문자열 비교 가 많은 경우엔 switch가 조금 더 최적화될 수 있다.&lt;/li&gt;
&lt;li&gt;핵심은 성능보다 가독성과 구조화에 있다.if문을 사용하는 대신, switch문을 사용하는 것이 더 최적화스럽다라는 것.&lt;/li&gt;
&lt;li&gt;예를 들면 에러 핸들링 같은 경우에 상태 에러 코드가 뜰 시 클라이언트한테 보여주는 화면에&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건이 늘어날수록 if else 나 switch &amp;rarr; 객체 매핑이나 함수 분리가 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로직 분기 없이 핸들러 객체로 묶는 구조는 매우 추천&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;가독성을 위한 개선 방법&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체 기반 매핑&lt;/li&gt;
&lt;li&gt;함수 분리&lt;/li&gt;
&lt;li&gt;enum 패턴 응용 &amp;rArr; 하지만 이건, 최근에 권장되지않는다한다. (트랜스파일 결과 문제, 트리 쉐이킹 불가, 런타임 값 생성)&amp;nbsp;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;switch 문은 역할 분기, 상수 값 비교 처럼 값 중심의 로직에 적합&lt;/li&gt;
&lt;li&gt;논리적 우선 순위가 중요한 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 switch문이 아닌, if else if가 더 적합할 때는 각 조건이 독립적인 값이 아니라,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선순위 를 갖는 경우 else if 가 더 직관적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end</category>
      <category>SOLID</category>
      <category>솔리드 원칙</category>
      <category>좋은 코드</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/136</guid>
      <comments>https://thfdl0317.tistory.com/entry/React-%ED%98%91%EC%97%85%EC%9D%84-%EC%9C%84%ED%95%B4-%EC%A1%B0%EA%B8%88-%EB%8D%94-%EC%8B%A0%EA%B2%BD-%EC%93%B8-%EB%82%B4%EC%9A%A9-%EB%AA%A8%EC%9D%8C1-%ED%8C%8C%EC%9D%BC-%EC%97%85%EB%A1%9C%EB%93%9C-%EC%8B%9C#entry136comment</comments>
      <pubDate>Tue, 5 Nov 2024 09:59:34 +0900</pubDate>
    </item>
    <item>
      <title>새로 고침 기능 구현 시, window.location.reload() 쓴다고?! 잠깐 </title>
      <link>https://thfdl0317.tistory.com/entry/Reactatomic-design%ED%8C%A8%ED%84%B4%EC%97%90%EC%84%9C-Container-Component%EB%A5%BC-%EB%A7%8C%EB%93%A4%EC%96%B4-%EC%82%AC%EC%9A%A9%ED%95%A0-%EB%95%8C</link>
      <description>&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;오늘의 글은&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;i&gt;window.location.reload()가 위험할 수 있는 이유와,&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;i&gt;React 프로젝트에서의 더 좋은 새로고침 전략에 대해서 정리해보고자한다.&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버튼 클릭 시 &amp;ldquo;새로고침&amp;rdquo;이 필요하다는 요구사항을 종종 만납니다. 흔히 떠올리는 건 바로&lt;/p&gt;
&lt;pre id=&quot;code_1758957453044&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;window.location.reload();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 구현하면서 항상 생각해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드가 우리 프로젝트에 적합한 코드인가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt; 왜 섣부른 전체 리로드가 위험할까&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt; &lt;span style=&quot;color: #1a5490;&quot;&gt;상태 손실이 되어도 괜찮은가:&amp;nbsp;메모리 기반 상태(React state, Zustand 등 사용 시) 전부 초기화된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;277&quot; data-start=&quot;159&quot; data-ke-size=&quot;size16&quot;&gt;현재 참여 중인 프로젝트는 i18n을 적용해 한국어/일본어 다국어 선택 기능을 제공하고 있는데,&lt;/p&gt;
&lt;p data-end=&quot;277&quot; data-start=&quot;159&quot; data-ke-size=&quot;size16&quot;&gt;단순히 window.location.reload()를 사용하면 이 상태들도 모두 초기화될 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;422&quot; data-start=&quot;279&quot; data-ke-size=&quot;size16&quot;&gt;새로고침 버튼의 목적은 &quot;날짜 설정을 오늘 날짜로 되돌리고, 그에 따라 통계 데이터와 리스트를 다시 초기화&quot;하는 것이었는데,&lt;/p&gt;
&lt;p data-end=&quot;422&quot; data-start=&quot;279&quot; data-ke-size=&quot;size16&quot;&gt;겉으로 보면 전체 리로드로 처리하는 게 간단해 보일 수 있습니다. 하지만 그렇게 접근하는 것 자체가 잘못된 선택일 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;620&quot; data-start=&quot;424&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, 사용자가 일본어를 선택해 사용 중인데 초기 언어가 한국어로 설정되어 있다면, 전체 리로드 시 한국어로 되돌아가 버리게 된다. 물론 &lt;b&gt;localStorage, cookie, IndexedDB 같은 영속 저장소에 저장해 둔 값은 리로드 후에도 유지&lt;/b&gt;되지만, 메모리 기반 상태만 의존하고 있다면 언어 설정이 초기화되는 문제가 생긴다.&lt;/p&gt;
&lt;p data-end=&quot;735&quot; data-start=&quot;622&quot; data-ke-size=&quot;size16&quot;&gt;따라서 언어 설정과 같은 값은 반드시 &lt;b&gt;localStorage나 cookie 등 영속 저장소에 보관&lt;/b&gt;하고, 초기화 시점에 이를 읽어 i18n 설정에 반영하는 것이 올바른 접근이라고 생각한다.&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;size18&quot;&gt;  &lt;span style=&quot;color: #1a5490;&quot;&gt;단순히 한번 띡, 갱신되는 것이 아닌, 전체 페이지와 모든 리소스를 서버에 다시 불러오는 것&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 서버에 불러온다는건 뭐다?   불필요한 네트워크 요청이 증가되는 것이다. 이는 과부화로 성능 저하/UX 저하가 되는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 SPA(Single Page Application)구조라면 이런 문제가 더 두드러지는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, React 프로젝트에서 메인 페이지 안에 여러 컴포넌트로 Header, Footer, 통계용 컴포넌트, 사용자 정보 컴포넌트, 리스트 컴포넌트등이 모두 모여 있다고 볼 때, 리로드를 해버리면 이 모든 컴포넌트들이 다시 한 번 전부 서버 요청을 발생시키고, 초기 렌더링부터 다시 시작하게 된다.&lt;/p&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;size18&quot;&gt;  &lt;span style=&quot;color: #1a5490;&quot;&gt;토큰 만료 상태유무 시 보안과 세션 이슈면에서도 괜찮은가&lt;/span&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;새로고침 버튼 하나 때문에 사용자 흐름을 끊어버릴 수도 있으니 이 점 또한 주의해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  &lt;span style=&quot;color: #1a5490;&quot;&gt;화면 깜빡, SPA를 사용하는 장점 상실 -&amp;gt; UX 저하&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;window.location.reload()를 직접 적용해 보면 알 수 있듯,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화면이 &lt;b&gt;순간적으로 깜빡거리고&lt;/b&gt;, 사용자가 내려서 보고 있던 &lt;b&gt;스크롤 위치나 포커스도 초기화&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이로 인해 유저는 불편함을 느끼고, 애플리케이션은 &lt;b&gt;SPA가 가진 매끄러운 화면 전환 장점&lt;/b&gt;을 잃어버린 채&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;전통적인 전체 리로드 방식의 성능 저하&lt;/b&gt;를 감수하게되는데, 이 부분도 괜찮은지 구현 전 확인해봐야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;그럼, window.location.reload()말고 어떻게 구현해야할까.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로고침 기능을 꼭 구현해야 한다면 &lt;b&gt;전체 페이지 리로드 대신 두 가지 방법&lt;/b&gt;을 고려할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 상태 갱신 로직을 직접 구현하는 방법,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터만 다시 fetch해서 화면을 갱산하는 방법이 있다.&lt;/p&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;h4 data-ke-size=&quot;size20&quot;&gt;리액트 환경에서의 대안&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 리액트를 사용하니, 리액트 기준으로만 말하자면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;Zustand&lt;/b&gt;를 사용한다면:&lt;br /&gt;특정 store의 state만 reset시키는 함수를 만들어 필요한 상태만 초기화&lt;br /&gt;&amp;rarr; 전체 상태를 날리지 않고, 원하는 부분만 초기화 가능&lt;/p&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;React Query&lt;/b&gt;를 사용한다면:&lt;br /&gt;queryClient.invalidateQueries()를 활용해 특정 쿼리 데이터를 무효화하고 자동으로 다시 가져오도록 할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1758954368508&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useQueryClient } from &quot;@tanstack/react-query&quot;;

function RefreshButton() {
  const queryClient = useQueryClient();

  const handleRefresh = () =&amp;gt; {
    // 특정 쿼리 키의 데이터만 다시 가져오기끔
    queryClient.invalidateQueries({ queryKey: [&quot;driverList&quot;] });
  };

  return &amp;lt;button onClick={handleRefresh}&amp;gt;새로고침 테스트&amp;lt;/button&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;invalidateQueries : 기존 데이터를 무효화하고, React Query가 알아서 다시 fetch하게끔한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 데이터를 새로 불러오게하고 싶다면 queryclient.invalidateQueres()를 키 없이 호출할 수 있다.&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;과도한, 불필요한 refetch가 발생할 수 있으므로 쿼리 키를 지정하여 불러오는 것이 좋다.&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;b&gt; &lt;span&gt; &lt;/span&gt;&lt;/b&gt;요약하자면,&lt;br /&gt;window.location.reload() 대신 &lt;b&gt;Zustand reset&lt;/b&gt;이나 &lt;b&gt;React Query invalidateQueries&lt;/b&gt;를 활용하면,&lt;br /&gt;필요한 상태나 데이터만 선택적으로 초기화할 수 있고, 불필요한 네트워크 낭비와 UX 저하를 피할 수 있다.&lt;/p&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;  &lt;/b&gt;window.location.reload() 사용 시 주의점 정리&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;# 상태 손실: React state, Zustand/Redux 등 메모리 기반 상태가 전부 초기화된다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;# 전체 리소스 서버에 재요청은 불필요한 네트워크 증가로.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;# SPA의 장점 상실&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;# 인증/세션 이슈 - 토큰 만료 시 예상치 못한 로그인 화면 이동이 발생 가능.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;window.location.reload()는 무조건 전체 리로드라서 부분 갱신이 불가능하기에 간단한 한 줄처럼 보여도 의외로 무서운 함수다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;따라서, 새로고침 요구가 있어도 &lt;b&gt;이 프로젝트에 정말 적절한가&lt;/b&gt;를 먼저 고민하는 것이 중요하다고 생각한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;오늘도 이를 상기하며 글을 남긴다. 도움이 되셨길 바랍니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end</category>
      <category>frontend</category>
      <category>JavaScript</category>
      <category>React</category>
      <category>React Query</category>
      <category>reload함수</category>
      <category>spa</category>
      <category>UX</category>
      <category>window.location.reload()</category>
      <category>상태관리</category>
      <category>새로고침</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/135</guid>
      <comments>https://thfdl0317.tistory.com/entry/Reactatomic-design%ED%8C%A8%ED%84%B4%EC%97%90%EC%84%9C-Container-Component%EB%A5%BC-%EB%A7%8C%EB%93%A4%EC%96%B4-%EC%82%AC%EC%9A%A9%ED%95%A0-%EB%95%8C#entry135comment</comments>
      <pubDate>Wed, 23 Oct 2024 15:37:12 +0900</pubDate>
    </item>
    <item>
      <title>결국 그렇게 저장했는가, 그에 따른 보안은 안전한가(브라우저 저장소 결정2편)</title>
      <link>https://thfdl0317.tistory.com/entry/axios-%EB%AA%A8%EB%93%88%ED%99%94%ED%95%98%EA%B8%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;웹에서 '로그인 상태 유지' 또는 '자동 로그인' 기능을 구현할 때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어느 저장소에 무엇을 두느냐는 보안, 편의성 균형의 문제다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;1편에서 저장소 종류와 특성을 정리했다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2편에서는 공격 벡터인 XXS/CSRF를 기준으로 실전 방어법과&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;(*이건 그저 구현하며 저의 생각을 정리하는 내용이지 정답은 아닙니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Access Token, Refresh Token 같은 것은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가능한 클라이언트쪽에서 JS접근 불가한 HttpOnly 쿠키 + Secure + SameSite 설정으로 관리하는 것으로하는 것이 좋다생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Access Token은 가능한 **메모리(짧은 수명)**에서 관리하고 필요 시 refresh cookie로 재발급한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 비민감한 데이터, 대용량인 데이터를 저장해야할 경우는 IndexedDB가 적합하며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 로컬스토리지는 편할 수 있지만 XXS에 취약하므로 토큰 저장으로는 사용하면 위험, 권장치않는다. 비민감 UI 상태 혹은 편의성 데이터만 사용.&lt;/p&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;h3 data-ke-size=&quot;size23&quot;&gt;위협 모델(무엇을 막아야 하나&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; xxs, csrf, 브라우저 취약점, 물리적 접근 or 공유 기기로 인한 남은 세션으로 계정 탈취 등&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- XXS가 뭔데? Cross Site Scripting - 공격자가 스크립트를 주입해 브라우저 저장소인 로컬, 세션, 인덱스드디비의 데이터와 DOM에 접근하여 토큰 탈취, 조작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- CSRF가 뭔데? Cross-site Request Forgery - 사용자의 인증 쿠키가 자동으로 전송되어 의도치 않은 요청이 서버에서 실행됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저 취약점/확장 - 악성 확장이나 브라우저 취약점으로 저장소 훔침 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물리적 접근/ 공유 기기 - 공용 PC에서 남은 세션 등&lt;/p&gt;
&lt;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;- Access Token은 메모리, Refresh는 HttpOnly&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;=&amp;gt; 이 방식으로 한다면 js로는 refresh token에 접근이 불가하여 XSS로 부터 안전도가 크게 올라간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSRF는 SameSite, CSRF 토큰 또는 doble-submit cookie로 방어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Refresh token도 탈취되면 위험하니 Refresh 시 새 refresh 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;/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;이것 말고도 보안 관련 ESLint 규칙, 정적 분석 도구를 도입하는 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- eslint-plugin-no-unsanitized (Mozilla) &amp;mdash; innerHTML, insertAdjacentHTML 같은 직접 DOM 삽입을 금지하거나 허용된 sanitizer 사용을 강제. XSS 예방에 유용.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- eslint-plugin-xss &amp;mdash; XSS 관련 사용 패턴(예: 위험한 문자열 조작)을 찾아주는 추가 규칙&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- @typescript-eslint + eslint:recommended + eslint-plugin-react 등 기본 룰셋(타입스크립트/React 프로젝트용)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 규칙 추가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;금지: eval, new Function(), document.write, innerHTML&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 참고: ESLint 보안 플러그인은 &lt;b&gt;정적 검사&lt;/b&gt;라서 완벽치 않고, 결과는 반드시 리뷰해야 함 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;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.eslintrc.js 예시&lt;/p&gt;
&lt;pre id=&quot;code_1759760500948&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;module.exports = {
  parser: '@typescript-eslint/parser',
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:react/recommended'
  ],
  plugins: ['no-unsanitized','xss','security'],
  rules: {
    'no-unsanitized/method': 'error',
    'no-unsanitized/property': 'error',
    'security/detect-eval-with-expression': 'error',
    'xss/no-mixed-html': 'warn'
  }
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;운영 모니터링: Sentry 설정, 민감정보 스크럽&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영모니터링으로 Sentry로 수집하여 에러 알림을 통해 로깅 수집이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sentry에는 에러/예외 + 퍼포먼스 트레이싱 + 리치 컨텍스트 제공&lt;/p&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;beforeSend&lt;/b&gt; 훅을 사용해 이벤트가 전송되기 전에 민감정보 제거/마스킹.&lt;/p&gt;
&lt;pre id=&quot;code_1759758243019&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import * as Sentry from '@sentry/react';
import { BrowserTracing } from '@sentry/tracing';

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  integrations: [new BrowserTracing()],
  tracesSampleRate: 0.1,
  environment: process.env.NODE_ENV,
  release: process.env.SENTRY_RELEASE,
  beforeSend(event, hint) {
    // 요청 헤더의 인증 정보 제거
    if (event.request?.headers) {
      delete event.request.headers['authorization'];
      delete event.request.headers['cookie'];
    }
    // event.user 객체에 민감 정보가 있다면 지우기
    if (event.user) {
      delete event.user.email;
      delete event.user.ip_address;
    }
    // 추가: breadcrumbs/extra 에 들어간 민감 데이터 스크럽
    if (event.breadcrumbs) {
      event.breadcrumbs = event.breadcrumbs.map(b =&amp;gt; {
        if (b.data &amp;amp;&amp;amp; b.data.requestBody) {
          // 예시 마스킹
          b.data.requestBody = '[REDACTED]';
        }
        return b;
      });
    }
    return event;
  }
});&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4500&quot; data-start=&quot;4444&quot;&gt;Alert rules: 신규 에러, 급증 에러 알림 설정(Slack/PagerDuty)&lt;/li&gt;
&lt;li data-end=&quot;4534&quot; data-start=&quot;4501&quot;&gt;샘플링/레이트리밋: 비용관리 및 과다수집 방지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;정리&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4661&quot; data-start=&quot;4607&quot;&gt;Refresh Token: HttpOnly + Secure + SameSite 설정&lt;/li&gt;
&lt;li data-end=&quot;4698&quot; data-start=&quot;4662&quot;&gt;Access Token: 메모리(짧은 수명)로 관리&lt;/li&gt;
&lt;li data-end=&quot;4741&quot; data-start=&quot;4699&quot;&gt;local/session storage: 토큰 절대 저장 금지&lt;/li&gt;
&lt;li data-end=&quot;4773&quot; data-start=&quot;4742&quot;&gt;IndexedDB: 비민감 대용량 데이터용&lt;/li&gt;
&lt;li data-end=&quot;4869&quot; data-start=&quot;4817&quot;&gt;CSRF 방어: SameSite + CSRF 토큰 적용&lt;/li&gt;
&lt;li data-end=&quot;4901&quot; data-start=&quot;4870&quot;&gt;토큰 회전 및 서버 무효화(로그아웃) 구현&lt;/li&gt;
&lt;li data-end=&quot;4952&quot; data-start=&quot;4902&quot;&gt;ESLint 보안 플러그인 도입 + Husky + lint-staged 적용&lt;/li&gt;
&lt;li data-end=&quot;5052&quot; data-start=&quot;4996&quot;&gt;Sentry: beforeSend로 PII 제거, sourcemap 업로드, 알림 룰 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고자료&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;5785&quot; data-start=&quot;5243&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;5330&quot; data-start=&quot;5243&quot;&gt;eslint-plugin-security (npm) &amp;mdash; &lt;a href=&quot;https://www.npmjs.com/package/eslint-plugin-security&quot;&gt;https://www.npmjs.com/package/eslint-plugin-security&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;5438&quot; data-start=&quot;5331&quot;&gt;eslint-plugin-no-unsanitized (Mozilla GitHub) &amp;mdash; &lt;a href=&quot;https://github.com/mozilla/eslint-plugin-no-unsanitized&quot;&gt;https://github.com/mozilla/eslint-plugin-no-unsanitized&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;5627&quot; data-start=&quot;5439&quot;&gt;Finding and Fixing DOM-based XSS with Static Analysis (Mozilla 블로그) &amp;mdash;&lt;br /&gt;&lt;a href=&quot;https://blog.mozilla.org/attack-and-defense/2021/11/03/finding-and-fixing-dome-based-xss-with-static-analysis/&quot;&gt;https://blog.mozilla.org/attack-and-defense/2021/11/03/finding-and-fixing-dome-based-xss-with-static-analysis/&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;5686&quot; data-start=&quot;5628&quot;&gt;ESLint &amp;mdash; About &amp;mdash; &lt;a href=&quot;https://eslint.org/docs/latest/about/&quot;&gt;https://eslint.org/docs/latest/about/&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;5785&quot; data-start=&quot;5687&quot;&gt;On Limitations of Modern Static Analysis Tools (연구) &amp;mdash; &lt;a href=&quot;https://par.nsf.gov/servlets/purl/10129360&quot;&gt;https://par.nsf.gov/servlets/purl/10129360&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>csrf</category>
      <category>xxs</category>
      <category>브라우저 저장소</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/134</guid>
      <comments>https://thfdl0317.tistory.com/entry/axios-%EB%AA%A8%EB%93%88%ED%99%94%ED%95%98%EA%B8%B0#entry134comment</comments>
      <pubDate>Tue, 22 Oct 2024 19:11:26 +0900</pubDate>
    </item>
    <item>
      <title>너는 어디에 저장할 것인가, 그 이유는 무엇인가(브라우저 저장소 결정1편)</title>
      <link>https://thfdl0317.tistory.com/entry/Url-%EA%B2%BD%EB%A1%9C%EC%97%90-%EB%94%B0%EB%9D%BC-Header%EC%97%90-%ED%98%84%EC%9E%AC-%ED%99%94%EB%A9%B4%EC%A0%9C%EB%AA%A9-%EB%82%98%EC%98%A4%EA%B2%8C%ED%95%98%EA%B8%B0</link>
      <description>&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;git에 푸시 전에 불안하잖아~&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 이 선택이 맞는지~&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;HTTP의 기본 특성부터&lt;/h4&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;HTTP는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 클라이언트가 request를 보내고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 서버가 클라이언트한테 받은 request대한 response를 보내고 접속을 종료한다.(통신 끝)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 인증에 쓰이는 상태정보를 유지하지 않는 무상태(Stateless) 프로토콜, 비연결성, 무상태성 특징이 있다.&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;속도가 높아지면 비용도 낮아지고 서버로 전송되지않으니 클라이언트에 안전하게 보관된다면 비밀성에 있어서도 좋다.&lt;/p&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;h4 data-ke-size=&quot;size20&quot;&gt;브라우저 저장소의 종류&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹스토리지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 세션 스토리지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 로컬 스토리지&lt;/p&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;- indexedDB&lt;/p&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;쿠키(Cookie) 는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 &amp;harr; 클라이언트에서 주고받는 작은 문자열 파일. 요청 시 Header에 자동 전송.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저에 저장되는 작은 크기의 문자열만 저장됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청 시 header에 전송되며 주로 서버에서 사용된다. 또한 만료 기간 지정 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 쿠키는 '만료 기간' 에 따라 영구 쿠키(Persistent Cookies)와 세션 쿠키(Session Cookie)로 나뉜다.&lt;/p&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;CSRF 사용자의 권한을 이용한 공격, XSS 사용자의 민감한 정보 탈취(토큰),&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부족한 저장 용량 4KB&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 요청 시 자동으로 모든 쿠키에 전송하여 불필요한 트래 필 증가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;매번 서버에 전송이 되고 저장 용량이 작고 보안에 취약하다는 단점이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 HTML5부터는 쿠키의 단점을 보안해 등장한 웹 스토리지를 주로 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠키의 부족한 저장 용량 문제를 해결할 수 있게 5MB의 저장 용량을 가지고 있으며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청 시 Headers에 전송하지 않는다. 이는 쿠키의 CSRF, 트래픽 문제를 해결한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열만 저장가능하여 직렬화를 통해 객체 저장이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹스토리지는 서버로 전송되지 않는다는 다른 점이 있지만 클라이언트에 저장만 할 뿐. 또한 key와 value의 형태로 저장을 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹스토리지는 로컬스토리지와 세션스토리지로 나눠지는데 이 둘은 지속성에 따라 쓰임새가 달라진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로컬스토리지는 브라우저 자체에 반영구적으로 데이터를 저장하고 브라우저를 종료해도 데이터가 유지된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저장 범위에 따라도 다른데 로컬 스토리지는 도메인, 브라우저&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세션스토리지는 도메인, 브라우저, 탭에 저장가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세션 스토리지는 탭 윈도우 단위로 생성되고 탭 윈도우를 닫을 때 데이터가 삭제된다는 특징이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이런 웹스토리지도 문제점이 있느데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XSS 자바스크립트로 접근이 가능하고&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;동기적으로 실행하여 메인 스레드 블로킹, 용량이 크다면 IndexedDB를 고려해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;indexedDB는 저장공간이 각 브라우저에 따라 정책이 다르다. 데이터를 비교적 많이 저장할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠키와 로컬스토리지는 문자열만 저장가능한데 인덱스드디비는 어떤 테이터 타입도 저장가능, 제한이 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동작방법 또한 쿠키나 로컬스토리지는 동기식이지만 indexedDB는 비동기식이다.&lt;/p&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;쿠키나 웹 스토리지같은 경우엔&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;어떤 웹 사이트에 들어가면 나오는 팝업창 중 &quot;7일 동안 보지 않기&quot;,&amp;nbsp; &quot;다시보지 않기&quot; 이런거, 이런거 쿠키로 저장하는 것이 적절하고 각 스토리지의 특성을 살려서 자동 로그인 기능은 로컬 스토리지에&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;h4 data-ke-size=&quot;size20&quot;&gt;보안 강화 방법&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이 쿠키 보안 문제로 해결할 수 있는 방안은 뭘까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XSS 해결 방안은 HttpOnly로 가능하다. 이거는 자바스크립트로 접근이 불가하다,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSRF의 해결 방안으로는 SameStie로 같은 도메인의 요청에만 쿠키를 전송하도록 한다.&lt;/p&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;XSS로는 innerHTML 사용하지 않는 것이다. 이유는 자바스크립트 코드 삽입 불가하기 때문이다.&lt;/p&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;middot;로그인 저장은 단순히 &amp;lsquo;편리함&amp;rsquo;을 위해 구현하는 기능이지만, 잘못된 저장소 선택은 보안 사고로 직결된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>IndexedDB</category>
      <category>로컬스토리지</category>
      <category>브라우저 저장소</category>
      <category>세션스토리지</category>
      <category>웹 스토리지</category>
      <category>쿠키</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/133</guid>
      <comments>https://thfdl0317.tistory.com/entry/Url-%EA%B2%BD%EB%A1%9C%EC%97%90-%EB%94%B0%EB%9D%BC-Header%EC%97%90-%ED%98%84%EC%9E%AC-%ED%99%94%EB%A9%B4%EC%A0%9C%EB%AA%A9-%EB%82%98%EC%98%A4%EA%B2%8C%ED%95%98%EA%B8%B0#entry133comment</comments>
      <pubDate>Fri, 18 Oct 2024 08:50:35 +0900</pubDate>
    </item>
    <item>
      <title>[Next] 중첩된 Button버튼의 태그를 바꿀 때 다양한 방법들</title>
      <link>https://thfdl0317.tistory.com/entry/React-%EC%A4%91%EC%B2%A9%EB%90%9C-Button%EB%B2%84%ED%8A%BC%EC%9D%98-%ED%83%9C%EA%B7%B8%EB%A5%BC-%EB%B0%94%EA%BF%80-%EB%95%8C-%EB%8B%A4%EC%96%91%ED%95%9C-%EB%B0%A9%EB%B2%95%EB%93%A4</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;사이드 프로젝트 '같이행' 퍼블리싱 작업 중 프로필 수정 클릭 시 모달이 나오는 형태인데, 이런 에러가 나왔다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zHPCm/btsHPPvOgsN/qk8sG4PHJQicWdkoMKISy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zHPCm/btsHPPvOgsN/qk8sG4PHJQicWdkoMKISy0/img.png&quot; data-origin-width=&quot;1045&quot; data-origin-height=&quot;711&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.5284%; margin-right: 10px;&quot; data-widthpercent=&quot;50.11&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zHPCm/btsHPPvOgsN/qk8sG4PHJQicWdkoMKISy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzHPCm%2FbtsHPPvOgsN%2Fqk8sG4PHJQicWdkoMKISy0%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;1045&quot; height=&quot;711&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsD5vC/btsHOY8dk7o/wVBGnCi69V7jBO2gVmFcPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsD5vC/btsHOY8dk7o/wVBGnCi69V7jBO2gVmFcPk/img.png&quot; data-origin-width=&quot;1055&quot; data-origin-height=&quot;721&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.3088%;&quot; data-widthpercent=&quot;49.89&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsD5vC/btsHOY8dk7o/wVBGnCi69V7jBO2gVmFcPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsD5vC%2FbtsHOY8dk7o%2FwVBGnCi69V7jBO2gVmFcPk%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;1055&quot; height=&quot;721&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;298&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baujT0/btsHPWn3BAs/IUxv3L6pKhUj31TGAO3Vg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baujT0/btsHPWn3BAs/IUxv3L6pKhUj31TGAO3Vg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baujT0/btsHPWn3BAs/IUxv3L6pKhUj31TGAO3Vg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaujT0%2FbtsHPWn3BAs%2FIUxv3L6pKhUj31TGAO3Vg1%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;670&quot; height=&quot;298&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;298&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해석하면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 한 &amp;lt;button&amp;gt; 요소를 다른 &amp;lt;button&amp;gt; 요소 안에 중첩하려고 할 때 발생하고. HTML은 이러한 중첩을 허용하지 않는다고 한다. 추측되기론, EditProfileModal.tsx 안에 있는 button요소가 중첩되어 에러를 내는 것같다.&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;혹시 이전에 만든 공통 컴포넌트에서 전달하는 props 타입이 이상한 것이 아닐까 먼저 확인해보기&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;673&quot; data-origin-height=&quot;465&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dYlf2S/btsHQUbKpa0/yPtkSEQwiWNN3Gc1KtmlY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dYlf2S/btsHQUbKpa0/yPtkSEQwiWNN3Gc1KtmlY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dYlf2S/btsHQUbKpa0/yPtkSEQwiWNN3Gc1KtmlY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdYlf2S%2FbtsHQUbKpa0%2FyPtkSEQwiWNN3Gc1KtmlY1%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;673&quot; height=&quot;465&quot; data-origin-width=&quot;673&quot; data-origin-height=&quot;465&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;linkText의 타입은 이상이없는 것같고,&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;사실, button이 중첩된다하면 간단히 button인 태그를 다른 태그로 바꾸면된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;허나! &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;직접 DOM 이벤트를 사용하는 경우 TypeScript가 정적분석하기 어려워 핸들러의 타입을 추론하지 못해, &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;빨간줄이 팍!나올껄?&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;654&quot; data-origin-height=&quot;74&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ulAUj/btsHQDg0RzJ/Z3VkMrn78SiOybv3JrUFR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ulAUj/btsHQDg0RzJ/Z3VkMrn78SiOybv3JrUFR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ulAUj/btsHQDg0RzJ/Z3VkMrn78SiOybv3JrUFR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FulAUj%2FbtsHQDg0RzJ%2FZ3VkMrn78SiOybv3JrUFR1%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;654&quot; height=&quot;74&quot; data-origin-width=&quot;654&quot; data-origin-height=&quot;74&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기에 이런 경우 명시적으로 이벤트 핸들러의 타입을 지정해야한다.&lt;/p&gt;
&lt;pre id=&quot;code_1717599917315&quot; class=&quot;django&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;&amp;lt;span onClick={onOpen as React.MouseEventHandler&amp;lt;HTMLDivElement&amp;gt;} &amp;gt; 프로필 수정 &amp;lt;/span&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;onOpen 함수가 HTMLDivElement에 대한 이벤트 핸들러임을 인식한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1717600218577&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  const handleOpenModal = () =&amp;gt; {
    onOpen();
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;span
        onClick={handleOpenModal}
        className='text-secondary-main text-subtitle-02'
      &amp;gt;
        프로필 수정
      &amp;lt;/span&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;typeScript가 handleOpenModal 함수의 타입을 정확하게 추론하여 빨간 줄을 없앨 수 있다. 가독성을 위해서도 명시적으로 이벤트 핸들러의 타입을 지정하는 것보다 깔끔한 방법인 것같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, 빨간줄은 사라지지않는다..!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 방법으로&lt;/p&gt;
&lt;pre id=&quot;code_1718786744359&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  {linkText &amp;amp;&amp;amp; (
          &amp;lt;button
            type='button'
            onClick={onClick}
            className='text-secondary-main text-subtitle-02'
          &amp;gt;
            {linkText}
          &amp;lt;/button&amp;gt;
        )}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 링크텍스트가 있는지에 조건여부를 추가한 뒤 span태그였던 곳을 button태그로 변경하였다.. 근데 해결되었다..&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;</description>
      <category>Front-end</category>
      <category>frontend</category>
      <category>Next13</category>
      <category>React</category>
      <category>마이페이지</category>
      <category>버튼 태그</category>
      <category>사이드프로젝트</category>
      <category>여행 커뮤니티</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/126</guid>
      <comments>https://thfdl0317.tistory.com/entry/React-%EC%A4%91%EC%B2%A9%EB%90%9C-Button%EB%B2%84%ED%8A%BC%EC%9D%98-%ED%83%9C%EA%B7%B8%EB%A5%BC-%EB%B0%94%EA%BF%80-%EB%95%8C-%EB%8B%A4%EC%96%91%ED%95%9C-%EB%B0%A9%EB%B2%95%EB%93%A4#entry126comment</comments>
      <pubDate>Thu, 6 Jun 2024 00:39:27 +0900</pubDate>
    </item>
    <item>
      <title>[next.js] - 툴팁 컴포넌트 만들기</title>
      <link>https://thfdl0317.tistory.com/entry/React-%ED%88%B4%ED%8C%81-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;884&quot; data-origin-height=&quot;490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBapVI/btsHcJKk5qJ/FJBK3vZSrdylX0F4qGoj10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBapVI/btsHcJKk5qJ/FJBK3vZSrdylX0F4qGoj10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBapVI/btsHcJKk5qJ/FJBK3vZSrdylX0F4qGoj10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBapVI%2FbtsHcJKk5qJ%2FFJBK3vZSrdylX0F4qGoj10%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;480&quot; height=&quot;266&quot; data-origin-width=&quot;884&quot; data-origin-height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마이페이지 디자인 안에 들어있는 helpbox, 공통 컴포넌트로 만들기 위해 따로 빼서 작업준비!&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;- 페이지가 렌더링될 때마다 helpbox는 화면에 나오도록(초기 상태값 true로)하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- close 버튼 클릭 시 helpbox는 사라지게, helpbox와 관련된 텍스트 클릭 시 다시 helpbox보이게(toggle형식으로)하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- helpbox안에 들어가는 내용은 각각 중요내용, 보충내용으로 나눠서 입력할 수 있게하기.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 helpbox를 컴포넌트로 뺀 후 마이페이지에도 적용할 수 있도록 해보려한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;292&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cpafXD/btsHdx35uNR/K8xpGd78H6lkgoOF5fArv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cpafXD/btsHdx35uNR/K8xpGd78H6lkgoOF5fArv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cpafXD/btsHdx35uNR/K8xpGd78H6lkgoOF5fArv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcpafXD%2FbtsHdx35uNR%2FK8xpGd78H6lkgoOF5fArv1%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;648&quot; height=&quot;292&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;292&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 props로 전달할 데이터론 '화살표의 위치표시'와 '핵심내용', '핵심내용'을 보충할 내용&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;제일 아리송가리송했던 부분, 화살표를 left1/4, right1/4를 해도 피그마의 디자인처럼 옆으로 가지않아 계속 끙끙거렸었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;right-5인가, 아닌데.. left를 써야하는 부분인가.. 라 생각하다. 단순한 부분에서 전혀다른 부분을 건드리고 있었다는 걸 깨달았다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cYGHsG/btsHe5lDX4a/iBllejKEwtnkkcxJsfxbCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cYGHsG/btsHe5lDX4a/iBllejKEwtnkkcxJsfxbCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cYGHsG/btsHe5lDX4a/iBllejKEwtnkkcxJsfxbCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcYGHsG%2FbtsHe5lDX4a%2FiBllejKEwtnkkcxJsfxbCk%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;620&quot; height=&quot;335&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;466&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;426&quot; data-origin-height=&quot;159&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lJdX5/btsHgAe1cS9/a0677LVkeJjJUFf4VLKfGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lJdX5/btsHgAe1cS9/a0677LVkeJjJUFf4VLKfGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lJdX5/btsHgAe1cS9/a0677LVkeJjJUFf4VLKfGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlJdX5%2FbtsHgAe1cS9%2Fa0677LVkeJjJUFf4VLKfGK%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;426&quot; height=&quot;159&quot; data-origin-width=&quot;426&quot; data-origin-height=&quot;159&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 몸집을 조정해야했었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;415&quot; data-origin-height=&quot;152&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uS0yA/btsHiDaKIR8/PQ6b1biKz4fN3f3zkkl7W0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uS0yA/btsHiDaKIR8/PQ6b1biKz4fN3f3zkkl7W0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uS0yA/btsHiDaKIR8/PQ6b1biKz4fN3f3zkkl7W0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuS0yA%2FbtsHiDaKIR8%2FPQ6b1biKz4fN3f3zkkl7W0%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;415&quot; height=&quot;152&quot; data-origin-width=&quot;415&quot; data-origin-height=&quot;152&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;933&quot; data-origin-height=&quot;150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o2HJy/btsHfA7QM4s/lWruRcdvDbTdbK0pndQJ1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o2HJy/btsHfA7QM4s/lWruRcdvDbTdbK0pndQJ1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o2HJy/btsHfA7QM4s/lWruRcdvDbTdbK0pndQJ1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo2HJy%2FbtsHfA7QM4s%2FlWruRcdvDbTdbK0pndQJ1K%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;933&quot; height=&quot;150&quot; data-origin-width=&quot;933&quot; data-origin-height=&quot;150&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;coreText가&amp;nbsp;없을&amp;nbsp;경우도&amp;nbsp;포함하여&amp;nbsp;툴팁컴포넌트&amp;nbsp;완료!&amp;nbsp;뿌듯하다 &lt;/p&gt;</description>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/120</guid>
      <comments>https://thfdl0317.tistory.com/entry/React-%ED%88%B4%ED%8C%81-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0#entry120comment</comments>
      <pubDate>Wed, 8 May 2024 12:56:14 +0900</pubDate>
    </item>
    <item>
      <title>[React] 배포 자동화 Github actions, terraform, AWS S3</title>
      <link>https://thfdl0317.tistory.com/entry/CICD-React-%EB%B0%B0%ED%8F%AC-%EC%9E%90%EB%8F%99%ED%99%94-Github-actions-terraform-AWS-S3</link>
      <description>&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;월간CS에서 1주차 react, next 배포, 배포 자동화 A부터 Z까지 수업을 참여하였습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;직접 실습하며 배웠던 내용, 실습 중 막혔던 부분과 해결과정들을 적어보려합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;347&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YQW7F/btsGyQJhbq0/Twwoqi3Foy70ZAmqSYsPw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YQW7F/btsGyQJhbq0/Twwoqi3Foy70ZAmqSYsPw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YQW7F/btsGyQJhbq0/Twwoqi3Foy70ZAmqSYsPw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYQW7F%2FbtsGyQJhbq0%2FTwwoqi3Foy70ZAmqSYsPw1%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;344&quot; height=&quot;239&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;347&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;testt.png&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;988&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EACrE/btsGAMHwLcB/8MmmCEX1NO8ywUi5kJzkf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EACrE/btsGAMHwLcB/8MmmCEX1NO8ywUi5kJzkf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EACrE/btsGAMHwLcB/8MmmCEX1NO8ywUi5kJzkf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEACrE%2FbtsGAMHwLcB%2F8MmmCEX1NO8ywUi5kJzkf1%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;714&quot; height=&quot;353&quot; data-filename=&quot;testt.png&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;988&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt; &lt;span&gt;&lt;span&gt; CI/CD란?&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;https://inblog.ai/unchaptered/cicd%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-17669&quot;&gt;링크 클릭&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt; &lt;/span&gt;&lt;span&gt; GitHub Flow 전략에 대한 이해 &lt;/span&gt;&lt;a href=&quot;https://inblog.ai/unchaptered/github-flow-%EC%A0%84%EB%9E%B5%EC%97%90-%EB%8C%80%ED%95%9C-%EC%9D%B4%ED%95%B4-18020&quot;&gt;링크 클릭&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt; GitHub Action에 대한 이해 &lt;a href=&quot;https://inblog.ai/unchaptered/github-action&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;링크 클릭 &lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;  CloudFront, S3 배포하기&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt; &lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt; &lt;span&gt; &lt;/span&gt;&lt;/span&gt;aws cli&lt;/span&gt; &amp;nbsp;&lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;링크 클릭&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt; &lt;/span&gt; terraform &lt;a title=&quot;링크 클릭&quot; href=&quot;https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;링크 클릭&lt;/a&gt;&lt;/p&gt;
&lt;h4 style=&quot;background-color: #ffffff; color: #09090b; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;  terraform이란?&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f8f9fa; color: #343a40; text-align: start;&quot;&gt;클라우드 인프라스트럭처 자동화 도구&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f8f9fa; color: #343a40; text-align: start;&quot;&gt;인프라를 구축, 변경, 버전관리위한도구로 코드로 인프라를 관리할 수 있게 한다. &lt;/span&gt;&lt;span style=&quot;background-color: #f8f9fa; color: #343a40; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;  Github Action&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;github action용 폴더를 만들고 꼭! .github &amp;gt; workflows &amp;gt; .yaml 순으로 생성해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;deploy.yml파일 안에 내용 넣기&lt;/p&gt;
&lt;pre id=&quot;code_1712994015704&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;name: 배포 자동화   action의 이름

on:   action의 기능은 이벤트 기반, user 커밋을 푸시할 때 밑에 있는 내용들이 실행된다.
  push:
    branches: [&quot;*&quot;]

jobs:
  build:
    runs-on: ubuntu-latest  action이 실행될 때 구동되는 컴퓨터가 우분투면 좋겠다라는 것.
    steps:   실제로 벌어지는일들나열할 때 사용
      - name: Checkout   step의 이름,  *앞에 #사용 -&amp;gt; 구동되지않도록하는 것 
        uses: actions/checkout@v4
    	run : pwd   실제 동작하는 코드
      - name: Check Node v
        run: node -v
    
      - name: setup-node
        uses: actions/setup-node@v3
        with:
          node-version: 20
          
      - name: Install Dependencies
        run : yarn install
      
      - name: Build 
        run : yarn build
      
      - name: Upload to S3 
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY  }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY  }}
        run:
          aws s3 cp --recursive --region us-east-1 ./build s3://${{ secrets.AWS_S3_BUCKET  }}

      - name: Invalidate CloudFront Cache
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_EC2_METADATA_DISABLED: true
        run: aws cloudfront create-invalidation --distribution-id ${{ secrets.AWS_CF_DIST_ID  }} --paths &quot;/*&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내용을 넣은 후 main 브런치에 푸시.&lt;/p&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;Action 탭을 클릭하여 배포 자동화 상황을 확인할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;412&quot; data-origin-height=&quot;143&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnYlhz/btsGBvFbn1B/RH9YX0KXbgKIfwvKVK3oXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnYlhz/btsGBvFbn1B/RH9YX0KXbgKIfwvKVK3oXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnYlhz/btsGBvFbn1B/RH9YX0KXbgKIfwvKVK3oXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnYlhz%2FbtsGBvFbn1B%2FRH9YX0KXbgKIfwvKVK3oXk%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;317&quot; height=&quot;143&quot; data-origin-width=&quot;412&quot; data-origin-height=&quot;143&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1480&quot; data-origin-height=&quot;207&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bB62pT/btsGBhUwz7H/SUl8AWP7yQviSvujqWlwSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bB62pT/btsGBhUwz7H/SUl8AWP7yQviSvujqWlwSk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bB62pT/btsGBhUwz7H/SUl8AWP7yQviSvujqWlwSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbB62pT%2FbtsGBhUwz7H%2FSUl8AWP7yQviSvujqWlwSk%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;1480&quot; height=&quot;207&quot; data-origin-width=&quot;1480&quot; data-origin-height=&quot;207&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;  실습 중 막혔던 부분과 해결했던 내용들&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;가비아에서 구매한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;도메인&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;의 NS 수정하기   수정하는 곳이 안보일 때?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #242424;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;My가비아 클릭 후 구매한 도메인을 확인하고 네임서버 옆 설정 버튼을 누르면&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1555&quot; data-origin-height=&quot;526&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/skk6R/btsGC2BN5Vd/OQ93kz4CXdKHoOJ63XXkok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/skk6R/btsGC2BN5Vd/OQ93kz4CXdKHoOJ63XXkok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/skk6R/btsGC2BN5Vd/OQ93kz4CXdKHoOJ63XXkok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fskk6R%2FbtsGC2BN5Vd%2FOQ93kz4CXdKHoOJ63XXkok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;591&quot; height=&quot;200&quot; data-origin-width=&quot;1555&quot; data-origin-height=&quot;526&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위처럼 호스트명을 넣을 input란이 보이는데, 나 같은 경우는 '안전 장금 해지 버튼' 만 보여서 막히는 상황 발생했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럴 땐, '안전 장금 해지 버튼'을 클릭하여 해지 후 네임서버 탭을 다시 누르면 위 같은 input란을 볼 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에 &lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;dns_ns_record배열에 나온 4개의 문자열들을 차례대로 입력하면 되었다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;아마 '안전 잠금 해지 버튼은 도메인 구매 시 설정했던 부분인 듯하다'&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;2. gh 설치 했는데, &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;gh:&amp;nbsp;comm&lt;/span&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;and not found&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt; &lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt; &lt;/span&gt; GH cli 설치 &lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;&lt;a title=&quot;링크 클릭&quot; href=&quot;https://github.com/cli/cli#installation&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;&amp;nbsp;링크 클릭&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;나같은 경우 window를 사용해서, 설치했는데 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;gh:&amp;nbsp;comm&lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt;and not found&amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;문구가 자꾸 나오는 상황이었다. vscode 터미널에서 진행 중이었음. 그런데, vscode 창 끄고 cmd 창에서 진행하니 잘 되었다. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3. terraform 실행 중 에러발생, DNS 리소스 배포할 때, 하기의 코드 입력 시 이런 오류가 나왔다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1712992396573&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;terraform apply -var=&quot;profile=monthly-cs&quot; -var=&quot;domain_name=&amp;lt;가비아에서 구매한 도메인&amp;gt;&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1495&quot; data-origin-height=&quot;148&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Peq64/btsGyfWNCgU/e8fLU3gqg0oYap6hV1s7ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Peq64/btsGyfWNCgU/e8fLU3gqg0oYap6hV1s7ck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Peq64/btsGyfWNCgU/e8fLU3gqg0oYap6hV1s7ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPeq64%2FbtsGyfWNCgU%2Fe8fLU3gqg0oYap6hV1s7ck%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;1781&quot; height=&quot;176&quot; data-origin-width=&quot;1495&quot; data-origin-height=&quot;148&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;오류: AWS 계정 세부 정보 검색 중: 공급자 자격 증명 확인 중: STS에서 호출자 신원 검색 중: 작업 오류 STS...&lt;/span&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #24292f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;credentials문제인 부분으로 확인, &lt;span style=&quot;background-color: #ffffff; color: #24292f; text-align: start;&quot;&gt;AWS_ACCESS_KEY와 AWS_SECRET_ACCESS_KEY를 새로 발급받아 오류를 해결하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #24292f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #24292f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #24292f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end</category>
      <category>AWS CloudFront</category>
      <category>ci/cd</category>
      <category>dns</category>
      <category>Github Actions</category>
      <category>GitHub-Flow</category>
      <category>React</category>
      <category>s3</category>
      <category>terraform</category>
      <category>가비아</category>
      <category>자동화 배포</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/112</guid>
      <comments>https://thfdl0317.tistory.com/entry/CICD-React-%EB%B0%B0%ED%8F%AC-%EC%9E%90%EB%8F%99%ED%99%94-Github-actions-terraform-AWS-S3#entry112comment</comments>
      <pubDate>Thu, 11 Apr 2024 23:00:04 +0900</pubDate>
    </item>
    <item>
      <title>ESLint 셋팅, 제대로 알고 세팅해보자.</title>
      <link>https://thfdl0317.tistory.com/entry/ESLint-%EC%85%8B%ED%8C%85-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EC%95%8C%EA%B3%A0-%EC%84%B8%ED%8C%85%ED%95%B4%EB%B3%B4%EC%9E%90</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재, 팀원들과 vue3 프로젝트에서 React18, next13버전으로 변경하여 리액트를 사용하기로했고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 초기셋팅 시점에 ESLint와 prettier를 통일해서 셋팅하기로했고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 제목그대로 ESLint 세팅 시&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 어떤 설정을 적용한건지 하나씩 상세히 확인해보는 시간을 가져보려합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘의 목표 &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 1. ESLint란 무엇인지 알기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 2. ESLint 규칙&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 3. ESLint를 프로젝트에 설정하는 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 4. ESLint가 제대로 작동되는지 확인해보기&lt;/p&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;1. ESLint란 무엇인가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- ESLint는 오픈소스 자바스크립트 및 타입스크립트 코드 정적 분석 도구.&lt;/p&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; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- 버그 및 오류 방지,&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - 팀 협업 강화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;2. ESLint의 규칙&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ESLint는 규칙에 레벨을 정할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;off, warn, error 이렇게 3단계로 이루어집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;off or 0 -&amp;gt; 규칙을 해제, 해당 규칙 사용 안함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;warn or 1 -&amp;gt; 규칙을 경고로 설정, 경고만 해줌&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;error or 2 -&amp;gt; 규칙을 에러로 설정, 통합 테스트, pr등의 경우에 에러발생하게 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ESLint룰의 규칙들&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;412&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOsZY0/btsE0sJgFRs/RFyK3LJskutJtRwE6VUY60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOsZY0/btsE0sJgFRs/RFyK3LJskutJtRwE6VUY60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOsZY0/btsE0sJgFRs/RFyK3LJskutJtRwE6VUY60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOsZY0%2FbtsE0sJgFRs%2FRFyK3LJskutJtRwE6VUY60%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;528&quot; height=&quot;412&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;412&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 기본적인 규칙&lt;/p&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;3. 프로젝트에서 ESLint 설정 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm init @eslint/config&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;589&quot; data-origin-height=&quot;391&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rwdiG/btsE2A7W85i/dvN5ITdAjkgsWSpuPFhij1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rwdiG/btsE2A7W85i/dvN5ITdAjkgsWSpuPFhij1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rwdiG/btsE2A7W85i/dvN5ITdAjkgsWSpuPFhij1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrwdiG%2FbtsE2A7W85i%2FdvN5ITdAjkgsWSpuPFhij1%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;589&quot; height=&quot;391&quot; data-origin-width=&quot;589&quot; data-origin-height=&quot;391&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ESlint-config-prettier&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ESlint 설정 중 Prettier와 충돌하는 부분을 비활성화 시키는 명령어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm install --save-dev eslint-config-prettier&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ESlint 동작 확인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. lint 명령어를 통한 수동확인 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. vsCode 에서 린트를 동작시켜서 실시간 확인 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/100</guid>
      <comments>https://thfdl0317.tistory.com/entry/ESLint-%EC%85%8B%ED%8C%85-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EC%95%8C%EA%B3%A0-%EC%84%B8%ED%8C%85%ED%95%B4%EB%B3%B4%EC%9E%90#entry100comment</comments>
      <pubDate>Sun, 18 Feb 2024 12:39:12 +0900</pubDate>
    </item>
    <item>
      <title>[패스트캠퍼스] 웹퍼블리싱 완전 정복 : 모션 디자인으로 완성하는 반응형 웹 디자인 웹퍼블리싱 학습일지</title>
      <link>https://thfdl0317.tistory.com/entry/%ED%8C%A8%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%8D%BC%EC%8A%A4-%EC%9B%B9%ED%8D%BC%EB%B8%94%EB%A6%AC%EC%8B%B1-%EC%99%84%EC%A0%84-%EC%A0%95%EB%B3%B5-%EB%AA%A8%EC%85%98-%EB%94%94%EC%9E%90%EC%9D%B8%EC%9C%BC%EB%A1%9C-%EC%99%84%EC%84%B1%ED%95%98%EB%8A%94-%EB%B0%98%EC%9D%91%ED%98%95-%EC%9B%B9-%EB%94%94%EC%9E%90%EC%9D%B8-%EC%9B%B9%ED%8D%BC%EB%B8%94%EB%A6%AC%EC%8B%B1-%ED%95%99%EC%8A%B5%EC%9D%BC%EC%A7%80</link>
      <description>&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;b&gt;[패스트캠퍼스] 웹퍼블리싱 완전 정복 : 모션 디자인으로 완성하는 반응형 웹 디자인 웹퍼블리싱&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이며 사용자가 스크롤할 때, 클릭할 때와 같은 상황에서 좀 더 재미를 줄 수 있는 UI를 만들고 싶어,&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;학습일지의 내용으로 가져오려 했던 것은 바로&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;먼저 css의 커서는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요소위에 마우스를 올릴 때 hover 시 커서 모양을 변경합니다.&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;cursor의 기본 값은 auto, 이 auto는 브라우저가 현재상황맞에 어떤 커서를 띄워야 할지 결정해 줍니다. (즉, 기본적으로 정의되어 있다는 뜻입니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/cursor&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/CSS/cursor&lt;/a&gt;에 구체적으로 설명이 나와있죠&lt;/p&gt;
&lt;figure id=&quot;og_1705815246615&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;cursor - CSS: Cascading Style Sheets | MDN&quot; data-og-description=&quot;The cursor CSS property sets the mouse cursor, if any, to show when the mouse pointer is over an element.&quot; data-og-host=&quot;developer.mozilla.org&quot; data-og-source-url=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/cursor&quot; data-og-url=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/cursor&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/lEbN2/hyU5UYNq8h/xECqgbFjNiFncPGz5HSY30/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/cursor&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/cursor&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/lEbN2/hyU5UYNq8h/xECqgbFjNiFncPGz5HSY30/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;cursor - CSS: Cascading Style Sheets | MDN&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The cursor CSS property sets the mouse cursor, if any, to show when the mouse pointer is over an element.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.mozilla.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;932&quot; data-origin-height=&quot;327&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/H8DFo/btsDJksUoMG/ok74PeobHF3CYFiSOSjupK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/H8DFo/btsDJksUoMG/ok74PeobHF3CYFiSOSjupK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/H8DFo/btsDJksUoMG/ok74PeobHF3CYFiSOSjupK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FH8DFo%2FbtsDJksUoMG%2Fok74PeobHF3CYFiSOSjupK%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;458&quot; height=&quot;161&quot; data-origin-width=&quot;932&quot; data-origin-height=&quot;327&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;832&quot; data-origin-height=&quot;574&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EOljU/btsDKPyU9iv/h0hkqn2urTBIH5JYHz5kaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EOljU/btsDKPyU9iv/h0hkqn2urTBIH5JYHz5kaK/img.png&quot; data-alt=&quot;이런식으로 나와있으니 참고하시고~ &quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EOljU/btsDKPyU9iv/h0hkqn2urTBIH5JYHz5kaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEOljU%2FbtsDKPyU9iv%2Fh0hkqn2urTBIH5JYHz5kaK%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;464&quot; height=&quot;320&quot; data-origin-width=&quot;832&quot; data-origin-height=&quot;574&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이런식으로 나와있으니 참고하시고~ &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1705815463848&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;button {
	cursor:url(path/to/cursor.png), auto;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 위처럼 커서에 이미지를 사용하여 커스텀할 수 있죠,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 본격 마우스 커서를 커스텀해볼게요,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 커스텀할 폴더 만들고, html, css파일을 각각 만들어줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- html&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;447&quot; data-origin-height=&quot;136&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5nsLL/btsDNpNhEzR/bkbDiRk8SxdV79LXaBkksK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5nsLL/btsDNpNhEzR/bkbDiRk8SxdV79LXaBkksK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5nsLL/btsDNpNhEzR/bkbDiRk8SxdV79LXaBkksK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5nsLL%2FbtsDNpNhEzR%2FbkbDiRk8SxdV79LXaBkksK%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;447&quot; height=&quot;136&quot; data-origin-width=&quot;447&quot; data-origin-height=&quot;136&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- css&lt;/p&gt;
&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #d7ba7d;&quot;&gt;.cursor&lt;/span&gt;&lt;span style=&quot;color: #cccccc;&quot;&gt; {&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #cccccc;&quot;&gt;&amp;nbsp; &lt;/span&gt;&lt;span style=&quot;color: #9cdcfe;&quot;&gt;position&lt;/span&gt;&lt;span style=&quot;color: #cccccc;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;fixed&lt;/span&gt;&lt;span style=&quot;color: #cccccc;&quot;&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #cccccc;&quot;&gt;&amp;nbsp; &lt;/span&gt;&lt;span style=&quot;color: #9cdcfe;&quot;&gt;top&lt;/span&gt;&lt;span style=&quot;color: #cccccc;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #b5cea8;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #cccccc;&quot;&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #cccccc;&quot;&gt;&amp;nbsp; &lt;/span&gt;&lt;span style=&quot;color: #9cdcfe;&quot;&gt;left&lt;/span&gt;&lt;span style=&quot;color: #cccccc;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #b5cea8;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #cccccc;&quot;&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #cccccc;&quot;&gt;&amp;nbsp; &lt;/span&gt;&lt;span style=&quot;color: #9cdcfe;&quot;&gt;right&lt;/span&gt;&lt;span style=&quot;color: #cccccc;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #b5cea8;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #cccccc;&quot;&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #cccccc;&quot;&gt;&amp;nbsp; &lt;/span&gt;&lt;span style=&quot;color: #9cdcfe;&quot;&gt;bottom&lt;/span&gt;&lt;span style=&quot;color: #cccccc;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #b5cea8;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #cccccc;&quot;&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #cccccc;&quot;&gt;&amp;nbsp; &lt;/span&gt;&lt;span style=&quot;color: #9cdcfe;&quot;&gt;z-index&lt;/span&gt;&lt;span style=&quot;color: #cccccc;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #b5cea8;&quot;&gt;9999&lt;/span&gt;&lt;span style=&quot;color: #cccccc;&quot;&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #cccccc;&quot;&gt;&amp;nbsp; &lt;/span&gt;&lt;span style=&quot;color: #9cdcfe;&quot;&gt;background-color&lt;/span&gt;&lt;span style=&quot;color: #cccccc;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;antiquewhite&lt;/span&gt;&lt;span style=&quot;color: #cccccc;&quot;&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #cccccc;&quot;&gt;}&lt;/span&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;스크롤이 생기더라도 항상 고정되어 있기 때문에, 화면 전체에 늘 있게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화살표모양의 아이콘 말고 동그라미로 바꿔&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;379&quot; data-origin-height=&quot;319&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5f6bF/btsDGJtrw0n/17ja2YqeTocVQWyM13J9Nk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5f6bF/btsDGJtrw0n/17ja2YqeTocVQWyM13J9Nk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5f6bF/btsDGJtrw0n/17ja2YqeTocVQWyM13J9Nk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5f6bF%2FbtsDGJtrw0n%2F17ja2YqeTocVQWyM13J9Nk%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;379&quot; height=&quot;319&quot; data-origin-width=&quot;379&quot; data-origin-height=&quot;319&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마우스가 움직일 때 마우스의 정보를 가지고 마우스가 움직이는 위치를 알아냅니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;444&quot; data-origin-height=&quot;115&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sKnkj/btsDJV7AyoL/p6Tsk4uBnpLJc3iwpfxotk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sKnkj/btsDJV7AyoL/p6Tsk4uBnpLJc3iwpfxotk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sKnkj/btsDJV7AyoL/p6Tsk4uBnpLJc3iwpfxotk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsKnkj%2FbtsDJV7AyoL%2Fp6Tsk4uBnpLJc3iwpfxotk%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;444&quot; height=&quot;115&quot; data-origin-width=&quot;444&quot; data-origin-height=&quot;115&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1151&quot; data-origin-height=&quot;831&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bD4Uq6/btsDLMaZ6HO/V3sIBod1N9xz8DxUJ86zCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bD4Uq6/btsDLMaZ6HO/V3sIBod1N9xz8DxUJ86zCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bD4Uq6/btsDLMaZ6HO/V3sIBod1N9xz8DxUJ86zCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbD4Uq6%2FbtsDLMaZ6HO%2FV3sIBod1N9xz8DxUJ86zCk%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;444&quot; height=&quot;321&quot; data-origin-width=&quot;1151&quot; data-origin-height=&quot;831&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 움직이면서 각 x, y의 값이 나옵니다. 이 값을 활용하여 스타일을 변경해 봅니다.&lt;/p&gt;
&lt;pre id=&quot;code_1705856554445&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; // '마우스 움직임'에 대한 동작
    document.addEventListener(&quot;mousemove&quot;, (e) =&amp;gt; {
      const cursorDefaultInner = document.querySelector(
        &quot;.cursor__default__inner&quot;
      );

      const cursorTraceInner = document.querySelector(&quot;.cursor__trace__inner&quot;);

      cursorDefaultInner.style.top = e.clientY + &quot;px&quot;;
      cursorDefaultInner.style.left = e.clientX + &quot;px&quot;;

    });&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마우스가 움직이면 움직이는 위치정보에 따라서 커서와 같이 이동할 수 있게 만들었습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1705856631405&quot; class=&quot;css&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;.cursor__default__inner {
  /* 커서 움직임에 따라 이동시킬 거임 */
  position: absolute;

  display: inline-block;
  width: 20px;
  height: 20px;

  background-color: rgba(10, 27, 16, 2.5);
  border: 2px solid pink;

  border-radius: 50%;

  transform: translate(-50%, -50%);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 브라우저의 커서를 없앱니다.&lt;/p&gt;
&lt;pre id=&quot;code_1705856836040&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;body {
  cursor: none !important;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 기본적으로&amp;nbsp; 화면에 보이는 화살표 아이콘이 사라지고 내가 만든 스타일만 보이게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이번엔 클릭 시 추가한 스타일들이 늘어났다 작아졌다 하는 것을 만들어봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마우스가 눌렸을 때 스타일이 작아지게, 마우스를 다시 떼면 스타일이 다시 커지도록!&lt;/p&gt;
&lt;pre id=&quot;code_1705858653501&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  const cursor = document.querySelector(&quot;.cursor&quot;);

    //마우스를 눌렀을 때
    document.addEventListener(&quot;mousedown&quot;, () =&amp;gt; {
      cursor.classList.add(&quot;cursor--active&quot;);
    });

    //마우스를 땠을 때
    document.addEventListener(&quot;mouseup&quot;, () =&amp;gt; {
      cursor.classList.remove(&quot;cursor--active&quot;);
    });&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1705858747813&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.cursor__trace__inner {
  position: absolute;
  display: inline-block;

  width: 40px;
  height: 40px;

  border-radius: 50%;
  background-color: rgba(0, 0, 0, 0.25);

  transform: translate(-50%, -50%);

  transition: all 0.04s ease;
}

.cursor--active .cursor__trace__inner {
  transform: scale(0.5) translate(-100%, -100%);

  transition: transform 0.3s ease;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;넣어주면 마우스가 이동할 때 기본값이 아닌 내가 원하는 스타일을 반영할 수 있고 클릭 시 스타일에서 정해진 속도, 크기대로 애니메이션 효과를 줄 수 있게 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;강의를 들으면서 기본적인 웹앱 페이지를 퍼블리싱했을 때와 달리, 특이한 효과를 낼 수 있는 방법을 알게 되는 내용들이 많았으며 강의의 난이도가 생각보다 어렵고(수학적인 계산도 나오고), 화면에 보였을 때 많은 경우들을 고려해야 하는, 기존에 간과했었던 접근방법을 배울 수 있었던 시간이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배우면서 또 스쳐갔던 생각 중 하나는 퍼블리싱을 의외로 간단하게 생각하는 개발자들이 많았었다는 것이었는데,&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;이거 왼쪽으로 그냥 이동시키면 안 돼?&quot;, &quot;이거 이런 효과를 냈으면 좋겠는데 그렇게 오래 걸리나?&quot; 이런 말들을 옆에서 들을 때면 생각보다 퍼블리싱을 단순하게 생각하시는 발언들을 접했었습니다.&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;앞으로는 더 강의를 들으며 재밌었던 부분은 이렇게 공유해보고 싶습니다.&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;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/cursor&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/CSS/cursor&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end</category>
      <category>반응형 웹 디자인</category>
      <category>웹퍼블리싱 완전 정복 : 모션 디자인으로 완성하는 반응형 웹 디자인 : [패스트캠퍼스] 웹퍼블리싱 강의</category>
      <category>패스트캠퍼스</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/99</guid>
      <comments>https://thfdl0317.tistory.com/entry/%ED%8C%A8%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%8D%BC%EC%8A%A4-%EC%9B%B9%ED%8D%BC%EB%B8%94%EB%A6%AC%EC%8B%B1-%EC%99%84%EC%A0%84-%EC%A0%95%EB%B3%B5-%EB%AA%A8%EC%85%98-%EB%94%94%EC%9E%90%EC%9D%B8%EC%9C%BC%EB%A1%9C-%EC%99%84%EC%84%B1%ED%95%98%EB%8A%94-%EB%B0%98%EC%9D%91%ED%98%95-%EC%9B%B9-%EB%94%94%EC%9E%90%EC%9D%B8-%EC%9B%B9%ED%8D%BC%EB%B8%94%EB%A6%AC%EC%8B%B1-%ED%95%99%EC%8A%B5%EC%9D%BC%EC%A7%80#entry99comment</comments>
      <pubDate>Sun, 21 Jan 2024 15:14:02 +0900</pubDate>
    </item>
    <item>
      <title>Vue.js- 02. 개발환경 셋팅과 Vue 3버전 설치</title>
      <link>https://thfdl0317.tistory.com/entry/Vuejs-%EA%B0%9C%EB%B0%9C%ED%99%98%EA%B2%BD-%EC%85%8B%ED%8C%85%EA%B3%BC-Vue-3%EB%B2%84%EC%A0%84-%EC%84%A4%EC%B9%98</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;목표&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 개발환경 셋팅&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Vue&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.&amp;nbsp;&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;&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;3. vsCode 에디터 설치&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에디터설치가 완료된다면 터미널을 열어서&lt;/p&gt;
&lt;pre id=&quot;code_1663203271383&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install -g @vue/cli&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 에디터 부가기능 설치&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- vetur 설치&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;125&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bU4VkE/btrMadllmh0/s5GFvK4bKymD3noqKBx2nK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bU4VkE/btrMadllmh0/s5GFvK4bKymD3noqKBx2nK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bU4VkE/btrMadllmh0/s5GFvK4bKymD3noqKBx2nK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbU4VkE%2FbtrMadllmh0%2Fs5GFvK4bKymD3noqKBx2nK%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;604&quot; height=&quot;125&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;125&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;- html css support&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;131&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nkTpR/btrL8ToaXkz/K8YWesjDD6J2JWRnvUKr0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nkTpR/btrL8ToaXkz/K8YWesjDD6J2JWRnvUKr0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nkTpR/btrL8ToaXkz/K8YWesjDD6J2JWRnvUKr0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnkTpR%2FbtrL8ToaXkz%2FK8YWesjDD6J2JWRnvUKr0K%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;599&quot; height=&quot;131&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;131&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;- Vue 3 Snippets&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;122&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/M7XUO/btrL7uvjPTU/q6mS7HQ883FPxlHfaGenu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/M7XUO/btrL7uvjPTU/q6mS7HQ883FPxlHfaGenu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/M7XUO/btrL7uvjPTU/q6mS7HQ883FPxlHfaGenu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FM7XUO%2FbtrL7uvjPTU%2Fq6mS7HQ883FPxlHfaGenu1%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;545&quot; height=&quot;122&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;122&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발환경 셋팅 끝!&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 만약 터미널에 빨간에러가 뜬다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&quot;허가되지 않은 스크립트 입니다~&quot; 그런 에러가 뜨는 경우&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;=&amp;gt; 윈도우 검색메뉴 - Powershell 검색 - 우클릭 - 관리자 권한으로 실행 후&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Set-ExecutionPolicy Unrestricted&lt;/b&gt;입력해보기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end/react.js(리액트) vs Vue.js(뷰)</category>
      <category>vue 3버전설치</category>
      <category>vue.js</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/93</guid>
      <comments>https://thfdl0317.tistory.com/entry/Vuejs-%EA%B0%9C%EB%B0%9C%ED%99%98%EA%B2%BD-%EC%85%8B%ED%8C%85%EA%B3%BC-Vue-3%EB%B2%84%EC%A0%84-%EC%84%A4%EC%B9%98#entry93comment</comments>
      <pubDate>Thu, 15 Sep 2022 10:01:44 +0900</pubDate>
    </item>
    <item>
      <title>Vue.js- 01. Vue.js를 사용하는 이유</title>
      <link>https://thfdl0317.tistory.com/entry/Vusjs%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</link>
      <description>&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;1. 쉽다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뷰.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;React의 state변경, for변경, if 사용들을 보면 알 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 개발할 때 방법이 정해져있다는 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML을 내가 반복적으로 여러개 생성하고 싶다면? 리액트로는 map을 사용할지, forEach를 사용할지, 그냥 일반 for을 사용할지 반복문을 컴포넌트 render()바깥에서 사용할지 안에서 사용할지&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;vue.js는 그렇지 않다. html 여러개를 생성하고 싶다면 이 v-for만 사용하면된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 if문을 이용해서 조건부로 보여주고싶다면 REACT는 &amp;amp;&amp;amp; ||, if else, enum, tenary operator 등등 여러방법들을 사용할 수 있지만 Vue는 v-if v-else만 사용하면 OK,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 볼 때, Vue.js사용한다면 React와 앵귤러보다 &lt;span&gt;협업을 할 때&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; 도움이 많이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀별로 코딩스타일을 훨씬 쉽게 통일시킬 수 있고 코딩을 처음 배우는 아기개발자들이 Vue.js를 사용하여 output을 낼 수 있다. (쌩 자바스크립트 못해도)&lt;/p&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는 &lt;span&gt;쌩 자바스크립트를 잘해야 리액트도 잘 사용할 수 있다고한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;Vue안에서도 React와 같이 JSX, render() function등을 지원해주고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;3. 벤치마크를 돌려봤더니 렌더링 속도가 React보다 더 빠르다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;실시간으로 빨리 바뀌어야할 때 Vue.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;&lt;span&gt;4. 장기적으로 지원이 잘 되는 라이브러리라는 것이다. 꾸준하게 업데이트되어져있는 Vue.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;&lt;span&gt;리액트가 좋냐, Vue.js좋냐 뭐 그런 것을 가려내려는 것이 아니라 각각의 강점들과 차이점이 무엇인지 궁금했던 것!&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end/react.js(리액트) vs Vue.js(뷰)</category>
      <category>React</category>
      <category>vue.js</category>
      <category>앵귤러</category>
      <category>프론트개발자</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/92</guid>
      <comments>https://thfdl0317.tistory.com/entry/Vusjs%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0#entry92comment</comments>
      <pubDate>Thu, 15 Sep 2022 09:44:58 +0900</pubDate>
    </item>
    <item>
      <title>Mongoose는 무엇인가, mongoDB검색하면 자주 등장하던데 써야하나?</title>
      <link>https://thfdl0317.tistory.com/entry/Mongoose%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-mongoDB%EA%B2%80%EC%83%89%ED%95%98%EB%A9%B4-%EC%9E%90%EC%A3%BC-%EB%93%B1%EC%9E%A5%ED%95%98%EB%8D%98%EB%8D%B0-%EC%8D%A8%EC%95%BC%ED%95%98%EB%82%98</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Mongoose란 몽고DB에 데이터를 넣었다가 뺐다가할 때 선택할 수 있는 방법이 2가지있는데,&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;1. MongoDB Native Driver&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 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;이 두개 중에 하나를 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 둘의 관계는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;MonoDB Native&lt;/span&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;vs&lt;/b&gt;&lt;/span&gt; &lt;span style=&quot;background-color: #f6e199;&quot;&gt;Mongoose&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;p data-ke-size=&quot;size16&quot;&gt;제이쿼리 없이 쌩자바스크립트로도 개발을 할 수 있지않은가? (원래 자바스크립트로도 당연~히 기능 구현할 수 있지만)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쌩MonoDB Native 로 데이터입출력을 할 수 있는데 몽구스를 사용하면 더 직관적이여서 편하고 쉽게 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 기본적인 validation을 쉽게할 수 있다.&lt;/p&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: #ef5369;&quot;&gt;validation&lt;/span&gt;&lt;/b&gt;이란?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 아이디 입력란을 만들어서 전송버튼을 누르면 아이디가 서버에 전송이되고 DB에 저장이 되도록 코드를 다 짜놨다고 쳐보자. 근데 아이디input란에&amp;nbsp; 한글을 입력했다치자. 한글아이디는 본 적없잖아. 한글 아이디가 있다? 안됀다.라고 쳐내야하는데 그것을 말하는 것. 간단하게 말하면 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;DB에 저장하기 전에 데이터 검증을 하는 작업을 말한다&lt;/b&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 왜 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;Mongoose&lt;/span&gt;거의 다 사용하냐라고 한다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전엔 MongoDB Native가 되게 좀 불편한 점이 많아가지고 몽구스를 반필수적으로 사용했어야했다한다. 그래서 몽구스를 사용하는 사람들이 아직까지 많다고...&lt;/p&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 Native Driver만으로도 가능하다는!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;validation도 몽구스 처럼 할 수있는데,&amp;nbsp; 로컬PC에서 조작을 할 수 있는 프로그램이 필요하다(MongoDB Compass 을 다운)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 안에 validation 메뉴에 들어가서 입력, 정의가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.mongodb.com/try/download/compass&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.mongodb.com/try/download/compass&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;MongoDB Compass을 설치하기 귀찮다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에서 원격으로 접속할 수 있는 툴도 있다.   MongoDB Shell(Compass와 동일, 터미널에서 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;또한 Mongoose 라이브러리를 설치해서 사용할 때 MongoDB Native Driver와는 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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end/node.js + mongoDB</category>
      <category>MongoDB</category>
      <category>MongoDB Compass</category>
      <category>MongoDB native driver</category>
      <category>Mongoose</category>
      <category>schema</category>
      <category>validation</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/91</guid>
      <comments>https://thfdl0317.tistory.com/entry/Mongoose%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-mongoDB%EA%B2%80%EC%83%89%ED%95%98%EB%A9%B4-%EC%9E%90%EC%A3%BC-%EB%93%B1%EC%9E%A5%ED%95%98%EB%8D%98%EB%8D%B0-%EC%8D%A8%EC%95%BC%ED%95%98%EB%82%98#entry91comment</comments>
      <pubDate>Wed, 14 Sep 2022 03:20:29 +0900</pubDate>
    </item>
    <item>
      <title>Session, JWT, OAuth 등 이해하기</title>
      <link>https://thfdl0317.tistory.com/entry/session-JWT-OAuth-%EB%93%B1-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;세션인, jwt이나 여러 인증방법이 있는데 이걸 들었을 때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버에 요청을하고~ 브라우저에 저장하고~ 요청할 때는~ 에구궁에구궁..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;session방식과 JWT방식등이 헷갈려지지않게&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;딱 정리하여 기록하는 것이 좋겠다 싶어 오늘도 솔적솔적해보려한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;너무 깊이 말고 간단한 이해를 목표로하여 알아가도록하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;| 1. session-based&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 사람이 로그인페이지에서 로그인을 한다. 그러면 서버는 쿠키를 발행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠키가 뭐냐면 브라우저에 몰래 저장할 수 있는 긴 문자 저장공간.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자들을 차례차례 저장할 수 있다.&lt;/p&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;그럼 이제 로그인을 한 상태고 로그인을 한 사람만 이용하는 마이페이지를 보려고 접속요청을 하겠지.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그인한 사람만 이용할 수 있는 마이페이지를 보려면 쿠키 데이터가 서버한테 자동으로 전송한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 사용자의 세션아이디가 쿠키안에 들어있는데 이 아이디를 바탕으로 세션데이터에 아이디를 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 이 세션데이터안에 유저의 아이디가 있다면 마이페이지를 유저에게 갖다주는 것이 &lt;b&gt;session-based-Authentication&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큰 특징은 이 사용자가 로그인을 했다는 정보를 서버에 다 저장을 한다. 그게 장점이자, 단점임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;| 2. &lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;Token-based(JWT)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 사람이 로그인을 한다치자, 그러면 서버에 전송이 되고 서버에서는 웹토큰이라는 것을 발행해준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 사람이 맞는 비밀번호, 아이디를 입력을 하였다하면 JSON WEB 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;그럼 이 토큰을 브라우저한테 전송을하는데 브라우저는 쿠키 아니면 localStorage에 저장을 한다.&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;서버한테 요청을 할 때 웹토큰을 header라는 곳에 포함을 하여 전송을 한다.&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;이런 식으로 인증을 해주는 것이 토큰베이스 방식,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;토큰이라는 글자가 보이면 거의 다 이런 방식으로 진행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹토큰 방식의 가장 큰 특징은 서버가 메모리같은 공간에 사용자가 로그인했다라는 정보를 저장하지않고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(유저들 로그인 상태를 저장할 필요없음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그인했다라는 정보를 웹토큰으로해서 브라우저에 보내는 것,&amp;nbsp;&lt;/p&gt;
&lt;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;옛날에 REST 원칙 중 서버는 stateless해야한다라는 것과 비슷한 것이, 서버가 이사람이 로그인했다라는 정보를 저장하지 않으니 좀 더 restfull한 서버를 만들 수 있다.&lt;/p&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;마지막 세 번째인 Open Authentication (OAuth)을 알아보자&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;| 3.&lt;span&gt; Open Authentication (OAuth)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다른 사이트에서 프로필 정보를 가져오는 것이다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;페이스북인, 구글에서 내가&amp;nbsp; 너희의 프로필정보를 가져와도될까? 물어보고 허락한다면 이 사람의 구글이메일, 이름 등을 그대로 갖다가 내 사이트에 사용할 수 있게, 접근권한을 줄 수 있게 하는 것이 OAuth.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이게 무슨 말이람? 이라고 생각이 들 수 있지만 다들 한 번쯤 보지 않았다면 간첩인 걸 의심해봐야한다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;522&quot; data-origin-height=&quot;85&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/edWSAI/btrL1yxcS22/y6YEYxQoRFJbndAPs201mk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/edWSAI/btrL1yxcS22/y6YEYxQoRFJbndAPs201mk/img.png&quot; data-alt=&quot;요런거요런거&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/edWSAI/btrL1yxcS22/y6YEYxQoRFJbndAPs201mk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FedWSAI%2FbtrL1yxcS22%2Fy6YEYxQoRFJbndAPs201mk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;522&quot; height=&quot;85&quot; data-origin-width=&quot;522&quot; data-origin-height=&quot;85&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;요런거요런거&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;285&quot; data-origin-height=&quot;163&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cX5YV1/btrL23cFhkH/KGqSIzkNhJVuGpPdjKkla1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cX5YV1/btrL23cFhkH/KGqSIzkNhJVuGpPdjKkla1/img.png&quot; data-alt=&quot;요런거 있자나요런거&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cX5YV1/btrL23cFhkH/KGqSIzkNhJVuGpPdjKkla1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcX5YV1%2FbtrL23cFhkH%2FKGqSIzkNhJVuGpPdjKkla1%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;285&quot; height=&quot;163&quot; data-origin-width=&quot;285&quot; data-origin-height=&quot;163&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;요런거 있자나요런거&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 동작방식은 되게 심플해보인다.&lt;/p&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;이걸 받아와서 이 사람의 계정을 만들거나 jwt를 발급, 세션만들면된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것의 장점은 서버입장에서는 비밀번호를 다룰 일이 없는 것. 버튼 하나만 누르면 로그인 까지 완료가되는 것.&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;</description>
      <category>Front-end/Session, Token, Open Authentication 방식</category>
      <category>json web token</category>
      <category>JWT</category>
      <category>Node.js</category>
      <category>oauth</category>
      <category>Open Autentication</category>
      <category>Open Authentication 방식</category>
      <category>Session-based Authentication</category>
      <category>Session방식</category>
      <category>Token방식</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/90</guid>
      <comments>https://thfdl0317.tistory.com/entry/session-JWT-OAuth-%EB%93%B1-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0#entry90comment</comments>
      <pubDate>Tue, 13 Sep 2022 19:46:06 +0900</pubDate>
    </item>
    <item>
      <title>React- 성능개선3. useTransition, useDeferredValue</title>
      <link>https://thfdl0317.tistory.com/entry/React-%EC%84%B1%EB%8A%A5%EA%B0%9C%EC%84%A03-useTransition-useDeferredValue</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;리액트가 업데이트되고 나서 사용할 수 있는 신기능이 있다는데, 그것을 오늘 사용해보려한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;| 1. batch 기능&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;state변경함수들이 쭉 작성이 되어있다면 state변경이 일어날 때마다 재랜더링이 일어나는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연달아서 여러개가있다면 재랜더링이 맨 마지막것만 재렌더링 1번만 일어나게하는 것이다. 이게 batch이라고 하는데,&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;예외가 있다. ajax요청, setTimeout 등의 내부코드라면 batch이 일어나지않았는데,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트 17버전에는 배칭이 일어나지않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트 18버전이후에는 코드가 어디있던간에 잘 일어난다는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;| 2. useTransition&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동작이 느린 컴포넌트들을 빠르게 동작할 수 있게하는 것이다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1662888656320&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {useState} from &quot;react&quot;;

function App2(){
    const [name, setName] = useState('');

    return (
        &amp;lt;&amp;gt;
            &amp;lt;input onChange={(e) =&amp;gt;{setName(e.target.value)}} /&amp;gt;
        &amp;lt;/&amp;gt;
    )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유저가 input에 뭔가 입력을 하면 name란 state에 저장하도록 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 갑자기 성능저하가 일어났다고 가정을 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;div박스를 천개, 만개정도 만들게되었다치자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;div를 여러개 만드려면 반복문을 사용하겠지.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map을 통해서 div박스들을 반복생성하도록하겠지.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1662889019438&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {useState} from &quot;react&quot;;

const divBox = new Array(10000).fill(0);

function App2(){
    const [name, setName] = useState('');

    return (
        &amp;lt;&amp;gt;
            &amp;lt;input onChange={(e) =&amp;gt;{setName(e.target.value)}} /&amp;gt;
            {
                a.map(()=&amp;gt;{
                    return &amp;lt;div&amp;gt;{name}&amp;lt;/div&amp;gt;
                })
            }
        &amp;lt;/&amp;gt;
    )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 코드를 짜고 직접 input란에 입력하여 실행해보면 반응이 느려지는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타이핑을 할 때마다 name란 state가 변경이되고 만개정도 생성을 재랜더링해야하기 때문에 느려지는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 식으로 코드를 짜면 느려지고 문제가 생긴다. 반응이 느린 것을 유저한테 느껴지게한다면 부정적인 효과가 생긴다는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 해결책은 무엇이겠는가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결방법 1 : 10000개를 지워야지모...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결방법 2 : 꼭 만개를 굳이 보여줘야한다면 리액트 18버전 이후 부터 쓸 수 있는 이 useTransition을 import한다음에 사용하도록하는 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1662890451401&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {useState, useTransition} from &quot;react&quot;;

const divBox = new Array(10000).fill(0);

function App2(){
    const [name, setName] = useState('');

    const [isPending, startTransition] = useTransition();

    return (
        &amp;lt;&amp;gt;
            &amp;lt;input onChange={(e) =&amp;gt;{
                startTransition(()=&amp;gt;{
                    setName(e.target.value)
                })
                
                }} /&amp;gt;
            {
                a.map(()=&amp;gt;{
                    return &amp;lt;div&amp;gt;{name}&amp;lt;/div&amp;gt;
                })
            }
        &amp;lt;/&amp;gt;
    )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;startTransition으로 해당 state변경 감싸기를 완료한 뒤&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 실행해보면 아까보다는 성능이 나아진 것을, 빨리 동작하는 것을 느낄 수 있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이 동작원리에 대해서 알아보자.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;| startTransition 동작원리&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, 처음 실행했을 때 왜 늦게 동작을 했었냐면 &lt;b&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;브라우저는 동시작업을 못하기 때문이다.&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;한번에 하나의 작업만 수행할 수 있다는 것(single-threaded)&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 input란에 타이핑을 했을 때 브라우저가 해야할 작업은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;input 에 입력된 것을 보여주고 div박스 만개를 동시에 처리하려고하니 느리게 동작되게 되는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 startTransition()로 감싸면 이 함수 안에있는 것을 늦게 처리하게해준다.&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;&lt;span style=&quot;color: #ef5369;&quot;&gt;다른 중요한 작업들을 먼저하게끔하는 것.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 브라우저는&amp;nbsp; 중요한 작업 이후에 state감싼 것을 이후에 실행되도록하여 성능향상을 올리는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럴 때 갖다쓰면 좋음좋음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;| 3. useDeferredValue를 써도 느린 컴포넌트 성능 향상 가능&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1662891565052&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {useState, useTransition, useDeferredValue} from &quot;react&quot;;

const divBox = new Array(10000).fill(0);

function App2(){
    const [name, setName] = useState('');

    const [isPending, startTransition] = useTransition();

    useDeferredValue();

    return (
        &amp;lt;&amp;gt;
            &amp;lt;input onChange={(e) =&amp;gt;{
                startTransition(()=&amp;gt;{
                    setName(e.target.value)
                })
                
                }} /&amp;gt;
            {
                isPending ? '로딩중입니다' : 
                a.map(()=&amp;gt;{
                    return &amp;lt;div&amp;gt;{name}&amp;lt;/div&amp;gt;
                })
            }
        &amp;lt;/&amp;gt;
    )
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1662891573281&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;useDeferredValue(); // 감싸진 않지만 state, props를 넣어서 사용할 수 있다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 useDeferredValue()에 넣어둔 state는 늦게 처리가 된다. 변동사항이 생겼을 때 늦게 변화한다는 것.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;늦게 처리되길 원하는 state가 있다하면 변수로 빼서 활용하도록한다.&lt;/p&gt;
&lt;pre id=&quot;code_1662891710791&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {useState, useTransition, useDeferredValue} from &quot;react&quot;;

const divBox = new Array(10000).fill(0);

function App2(){
    const [name, setName] = useState('');

    const [isPending, startTransition] = useTransition();

    const state = useDeferredValue(name); // 감싸진 않지만 state, props를 넣어서 사용할 수 있다.

    return (
        &amp;lt;&amp;gt;
            &amp;lt;input onChange={(e) =&amp;gt;{
                startTransition(()=&amp;gt;{
                    setName(e.target.value)
                })
                
                }} /&amp;gt;
            {
                isPending ? '로딩중입니다' : 
                a.map(()=&amp;gt;{
                    return &amp;lt;div&amp;gt;{state}&amp;lt;/div&amp;gt;
                })
            }
        &amp;lt;/&amp;gt;
    )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;name이라는 state가 변할 때마다 늦게 처리하게끔해줌.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중요한 처리를 먼저, 그다음 나중에 실행되게함.&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end/REACT - 성능개선 lazy, memo,  useTransition</category>
      <category>Automatic Batching</category>
      <category>batching</category>
      <category>flushSync</category>
      <category>isPending</category>
      <category>React</category>
      <category>useDeferredValue</category>
      <category>useTransition</category>
      <category>리액트18버전</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/89</guid>
      <comments>https://thfdl0317.tistory.com/entry/React-%EC%84%B1%EB%8A%A5%EA%B0%9C%EC%84%A03-useTransition-useDeferredValue#entry89comment</comments>
      <pubDate>Sun, 11 Sep 2022 19:23:42 +0900</pubDate>
    </item>
    <item>
      <title>REACT- 성능개선2, memo, useMemo 불필요한 재렌더링은 저리가!</title>
      <link>https://thfdl0317.tistory.com/entry/REACT-%EC%84%B1%EB%8A%A5%EA%B0%9C%EC%84%A02-%EB%B6%88%ED%95%84%EC%9A%94%ED%95%9C-%EC%9E%AC%EB%A0%8C%EB%8D%94%EB%A7%81%EC%9D%80-%EC%A0%80%EB%A6%AC%EA%B0%80-memo-useMemo</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 성능향상 2탄,&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;| 재렌더링 막는 방법&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자식컴포넌트를 우선 하나 생성해보고, Cart안에 넣어놓는다.&lt;/p&gt;
&lt;pre id=&quot;code_1662779031214&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Child() {
	return &amp;lt;div&amp;gt;자식컴포넌트&amp;lt;/div&amp;gt;
}


function Cart(){
    return (
        &amp;lt;&amp;gt;
                &amp;lt;Child&amp;gt;&amp;lt;Child/&amp;gt;
                ...
                ...

)}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;state만들기&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1662779325317&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const [count, setCount] = useState(0)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버튼을 눌러 state변경하도록 하기&lt;/p&gt;
&lt;pre id=&quot;code_1662779703947&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Cart(){ 

    const state = useSelector((state)=&amp;gt;{return state})
    const dispatch = useDispatch();//store한테 요청을 보내주는 함수임

    const [count, setCount] = useState(0)

    return (
        &amp;lt;div&amp;gt;
            &amp;lt;Child count={count}/&amp;gt;
            &amp;lt;button onClick={()=&amp;gt;{ setCount(count +1)}}&amp;gt;+&amp;lt;/button&amp;gt;
            &amp;lt;Table&amp;gt;
               
            -- 중간 코드 생략 -- 
    )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버튼을 클릭하면 count가 1이되며 Cart라는 컴포넌트가 재랜더링될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 때 Cart안에 있는 자식 컴포넌트들도 다 재렌더링된다.&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;lt;Child /&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;이게 싫다하면 꼭 필요할 때만 재렌더링하게할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Child라는 컴포넌트를 만들때 memo라는 함수안에 담아서 만들면된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;| 꼭 필요할 때만 재렌더링하게 memo()를 사용하자&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트 만드는 문법을 다르게 작성하여&lt;/p&gt;
&lt;pre id=&quot;code_1662780355115&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const Child = memo(function(){
    console.log('재랜더링됨')
    return &amp;lt;div&amp;gt;자식임&amp;lt;/div&amp;gt;
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트 함수를 memo로 감싸기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;| Memo( )의 원리 그리고 마구잡이로 사용하면 안되는 이유&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 재렌더링을 막아주는 것이아니라 특정 상황에서만 재렌더링을 해주는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Child라는 컴포넌트로 전송되는 props가 변할 때만 실행되어지는 함수인 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데, memo()이거 좋은데? 생각하여 여기썼다가~저기썼다가 마구잡이로 또 쓰면 안되는 것이,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;memo()로 감싸놓은 컴포넌트는 항상재렌더링이 되기 전에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 props, 신규 props와 비교작업이후 재렌더링 여부를 결정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;props가 길고 복잡하다면 오랜시간이 걸리는단점이 있다.&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;그리고 memo와 유사하게 생긴 useMemo()도 있는데, 이것도 재렌더링을 막는 것이긴한데&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;| useMemo 사용법&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1662781205322&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function testUsememo(){
    return  반복문으로 몇천번돌린 결과
  }
  
  
function Cart(){ 

    let result = testUsememo();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하면 Cart라는 컴포넌트가 재렌더링될 때마다 몇천번 돌려진 결과를 진행하게된다.&lt;/p&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;pre id=&quot;code_1662781462325&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const result = useMemo(()=&amp;gt;{ return testUsememo() }, [state])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useMemo()는 useEffect와 사용법이 거의 동일한데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수하나를 return 해줄 수 있는데 Cart컴포넌트가 처음 딱 렌더링될 때만 실행되고 그 이후에는 실행되어지지않는다.&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;[ ]안에 state를 넣어준다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 [ ]안에 넣어둔 state가 변화할 때만 코드가 실행되도록된다.&lt;/p&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;근데 굳이 memo와 useMemo를 왜 나눠놨는가허면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;| useEffect() 와 useMemo() 차이점&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useEffect()는 html이 다 실행이 끝나면 실행되나&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useMemo()는 렌더링될 때 만든 useMemoTest()가 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;실행시점의 차이&lt;/b&gt;&lt;/span&gt;밖에 없다는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end/REACT - 성능개선 lazy, memo,  useTransition</category>
      <category>frontend</category>
      <category>memo()</category>
      <category>React</category>
      <category>useEffect()</category>
      <category>useMemo()</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/88</guid>
      <comments>https://thfdl0317.tistory.com/entry/REACT-%EC%84%B1%EB%8A%A5%EA%B0%9C%EC%84%A02-%EB%B6%88%ED%95%84%EC%9A%94%ED%95%9C-%EC%9E%AC%EB%A0%8C%EB%8D%94%EB%A7%81%EC%9D%80-%EC%A0%80%EB%A6%AC%EA%B0%80-memo-useMemo#entry88comment</comments>
      <pubDate>Sat, 10 Sep 2022 12:50:41 +0900</pubDate>
    </item>
    <item>
      <title>REACT- 성능개선1, lazy loading 성능개선을 위해 해야할 것을 알아보자.</title>
      <link>https://thfdl0317.tistory.com/entry/REACT-lazy-loading-1-%EC%84%B1%EB%8A%A5%EA%B0%9C%EC%84%A0%EC%9D%84-%EC%9C%84%ED%95%B4-%ED%95%B4%EC%95%BC%ED%95%A0-%EA%B2%83%EC%9D%84-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;개발을 하면서 성능개선 힘쓰기에 돌입해보자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 함수나 오브젝트일 경우에는 변수에 담아 쓰는 것이 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름지어서 사용하는 경우가 좋은 이유는 메모리할당 때문인데,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;콜백함수, 오브젝트형식들을 쓰면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사이트 재랜더링, 버튼 누를 때 함수로 쓰면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리할당이되어야하는데 성능적으로 문제가 있을 수 있기 때문,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한&amp;nbsp; 상황에 따라서 애니메이션을 줄 때&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사이트에 레이아웃을 변경하거나 margin , width, padding(레이아웃 잡는 속성들)을 변경시키는데, 브라우저가 랜더링을 힘들어한다.(React뿐만 아니라 css자체의 기본 상식)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 애니메이션을 줄 때 transform 속성을 되도록이면 사용하는 것이 좋다.&lt;/p&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.js에 컴포넌트들을 import할 때 자바스크립트는 위에서부터 한줄씩 읽어내기 때문에,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Cart.js, Detail.js 다 미리 로드가 되기 때문에 힘들어질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따러서 컴포넌를 import할 때 lazy loading란 것을 사용해보자.&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;그전에 lazy loading이 무엇이냐함은,&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;다 미리 랜더링하여 필요없는 것까지 불러들이는 거이아닌 꼭 필요한 것만 import할 수 있도록 해주는 것을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를들어, Detail.js 가 지금 필요치 않을 때 , 꼭 필요한 시점에 import해줘!할 수 있는 것인데, 사용법을 보면서 이해를 해보자구.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333; background-color: #ffc9af;&quot;&gt;&lt;b&gt;| lazy loading 사용&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. lazy, Suspense를 import하기&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;App.js&lt;/p&gt;
&lt;pre id=&quot;code_1662776104967&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import './App.css';

import {useState, lazy, Suspense} from 'react';
// import Detail from './routes/Detail';&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;import Detail from './routes/Detail';   잠깐 주석처리한 후&lt;/p&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1662776428606&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//사이트를 발행할 때도 별도의 js파일로 분리됨
const Detail = lazy( () =&amp;gt; import('./routes/Detail.js') )&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트를 이렇게 import하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;App.js를 방문할 때 먼저 로딩하는 것이아니라 Detail.js가 필요할 때만 로딩되게된다. 천천히 로딩되게해주는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Detail.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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 대부분 Suspense와 같이 씀, Suspense로 Detail 컴포넌트 감싸주기&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662777010166&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;          &amp;lt;Route path=&quot;/detail/:id&quot; element={
            &amp;lt;Suspense fallback={&amp;lt;div&amp;gt;로딩중임&amp;lt;/div&amp;gt;}&amp;gt;
              &amp;lt;Context1.Provider value={{stuff, shoes}}&amp;gt;
                &amp;lt;Detail shoes={shoes} /&amp;gt; 
              &amp;lt;/Context1.Provider&amp;gt;
            &amp;lt;/Suspense&amp;gt;
            } /&amp;gt;
            
            
            -- 밑 코드 생략 --&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1662777226259&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;Suspense fallback={&amp;lt;div&amp;gt;로딩중임&amp;lt;/div&amp;gt;}&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Detail 로 방문을 하면 로딩이 될텐데 그 때 인터넷환경이 느릴 경우 임시 메세지로&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로딩전에 보영줄 html도 만들 수 있다.&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;이 lazy loading을 사용할 때 주의할 점은&lt;/p&gt;
&lt;pre id=&quot;code_1662777410705&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const Detail = lazy(() =&amp;gt; {return import('./routes/Detail.js')});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;return 을 꼭 넣어줘야한 다는 것! &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;| React devtools 설치&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이 lazy 로딩이 잘 되어졌는지 확인하기 위해 React devtools 설치해보자&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://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1221&quot; data-origin-height=&quot;317&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vDCNB/btrLQybCdFh/KIBBbu1YjLtb8PpIFK5LI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vDCNB/btrLQybCdFh/KIBBbu1YjLtb8PpIFK5LI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vDCNB/btrLQybCdFh/KIBBbu1YjLtb8PpIFK5LI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvDCNB%2FbtrLQybCdFh%2FKIBBbu1YjLtb8PpIFK5LI0%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;1221&quot; height=&quot;317&quot; data-origin-width=&quot;1221&quot; data-origin-height=&quot;317&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치하면 개발자도구로 미리보기 가능하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;236&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mcCBy/btrLLgRgddD/Hz1hHn8xkIiUjaL01sHeuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mcCBy/btrLLgRgddD/Hz1hHn8xkIiUjaL01sHeuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mcCBy/btrLLgRgddD/Hz1hHn8xkIiUjaL01sHeuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmcCBy%2FbtrLLgRgddD%2FHz1hHn8xkIiUjaL01sHeuk%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;276&quot; height=&quot;236&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;236&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;components 탭을 누르면 컴포넌트 검사가 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전달받은 props들도 확인가능, state들도 표기되어서확인할 수도 있고.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로바로 수정도 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 돌아가서 lazy loading이 잘 되어지나 확인하려면 타이머 아이콘을 누르면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;592&quot; data-origin-height=&quot;141&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cap5Fu/btrLLfY9G9C/ZsHjI768JaV57MLedg4XSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cap5Fu/btrLLfY9G9C/ZsHjI768JaV57MLedg4XSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cap5Fu/btrLLfY9G9C/ZsHjI768JaV57MLedg4XSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcap5Fu%2FbtrLLfY9G9C%2FZsHjI768JaV57MLedg4XSK%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;592&quot; height=&quot;141&quot; data-origin-width=&quot;592&quot; data-origin-height=&quot;141&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;Suspense fallback={&amp;lt;div&amp;gt;로딩중임&amp;lt;/div&amp;gt;}&amp;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;&lt;b&gt;컴포넌트 렌더링 속도와 단계녹화&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1516&quot; data-origin-height=&quot;86&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/csb4xx/btrLPoNPZ65/C6vA4fQKYqtFTuByzsYFWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/csb4xx/btrLPoNPZ65/C6vA4fQKYqtFTuByzsYFWK/img.png&quot; data-alt=&quot;녹화해주는 profiler&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/csb4xx/btrLPoNPZ65/C6vA4fQKYqtFTuByzsYFWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcsb4xx%2FbtrLPoNPZ65%2FC6vA4fQKYqtFTuByzsYFWK%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;1516&quot; height=&quot;86&quot; data-origin-width=&quot;1516&quot; data-origin-height=&quot;86&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;녹화해주는 profiler&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사이트 컴포넌트들이 많은데 컴포넌트들의 랜더링, 로딩시간들을 측정해준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;214&quot; data-origin-height=&quot;185&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y0BSZ/btrLLXjmXnL/dH9cZR3EJzb6psEm1Q3R5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y0BSZ/btrLLXjmXnL/dH9cZR3EJzb6psEm1Q3R5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y0BSZ/btrLLXjmXnL/dH9cZR3EJzb6psEm1Q3R5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy0BSZ%2FbtrLLXjmXnL%2FdH9cZR3EJzb6psEm1Q3R5k%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;214&quot; height=&quot;185&quot; data-origin-width=&quot;214&quot; data-origin-height=&quot;185&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어느페이지에서 어느페이지로 넘어갔는지에 대해 렌더링된 컴포넌트들을 다 표시해주기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 컴포넌트가 렌더링이 오래걸리나에대해 확인할 수 있다.&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end/REACT - 성능개선 lazy, memo,  useTransition</category>
      <category>Fallback</category>
      <category>lazy loading</category>
      <category>Profiler</category>
      <category>React</category>
      <category>React devtools</category>
      <category>suspense</category>
      <category>성능잡기</category>
      <category>재렌더링</category>
      <category>컴포넌트</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/87</guid>
      <comments>https://thfdl0317.tistory.com/entry/REACT-lazy-loading-1-%EC%84%B1%EB%8A%A5%EA%B0%9C%EC%84%A0%EC%9D%84-%EC%9C%84%ED%95%B4-%ED%95%B4%EC%95%BC%ED%95%A0-%EA%B2%83%EC%9D%84-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90#entry87comment</comments>
      <pubDate>Sat, 10 Sep 2022 11:50:09 +0900</pubDate>
    </item>
    <item>
      <title>REACT- react-query 사용해보기 (실시간데이터가 필요할 때)</title>
      <link>https://thfdl0317.tistory.com/entry/REACT-react-query-%EC%82%AC%EC%9A%A9%ED%95%B4%EB%B3%B4%EA%B8%B0-%EC%8B%A4%EC%8B%9C%EA%B0%84%EB%8D%B0%EC%9D%B4%ED%84%B0%EA%B0%80-%ED%95%84%EC%9A%94%ED%95%A0-%EB%95%8C</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;서버랑 통신하는 코드를 ajax로 짜다보면 여러 기능들이 추가적으로 필요해지게 되는데,&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;앞서 말했듯이 ajax성공 시와 실패시의 경우나&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;몇초마다 자동으로 ajax가 생행되는 것들이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 기능들을 코드를 끄적끄적하여 만들 순 있지만 더 간편하게 할 수 없을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라고 생각한다면 그 방법은 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 리액트 쿼리되시겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;react-query.svg&quot; data-origin-width=&quot;2552&quot; data-origin-height=&quot;498&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1tdt0/btrLNwLF4vq/sQjsu2yPnEljTlroqbfym1/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1tdt0/btrLNwLF4vq/sQjsu2yPnEljTlroqbfym1/tfile.svg&quot; data-alt=&quot;꽃같이 이쁜 로고&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1tdt0/btrLNwLF4vq/sQjsu2yPnEljTlroqbfym1/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1tdt0%2FbtrLNwLF4vq%2FsQjsu2yPnEljTlroqbfym1%2Ftfile.svg&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;804&quot; height=&quot;157&quot; data-filename=&quot;react-query.svg&quot; data-origin-width=&quot;2552&quot; data-origin-height=&quot;498&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;꽃같이 이쁜 로고&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;이 React Query는 자주자주 사용되어지는 것이아니라,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SNS나 돈거래소, (코인, 주식)이런 실시간데이터들을 계속 가져와야하는 경우 사용하는 게 좋다.&lt;/p&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;그럼 이 React Query를 사용해보자.&lt;/p&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;| react-query 설치&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662685786462&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install @tanstack/react-query&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;| 설치 후 index.js에 가서 셋팅&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt; ( import 꼭 )&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662685847160&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query'&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1662686784801&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    &amp;lt;QueryClientProvider client={queryClient} &amp;gt;
      &amp;lt;Provider store={store}&amp;gt;
        &amp;lt;BrowserRouter&amp;gt;
          &amp;lt;App /&amp;gt;
        &amp;lt;/BrowserRouter&amp;gt;
      &amp;lt;/Provider&amp;gt;
    &amp;lt;/QueryClientProvider&amp;gt;
);

serviceWorkerRegistration.register();
reportWebVitals();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버에서 user이름 가져와서 보여주기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;| ajax&amp;nbsp; get 요청&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662687004038&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  axios.get('경로').then((x) =&amp;gt;{
    x.data
  })&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 이렇게 말고 react query를 가지고 ajax 요청을 해보자.&lt;/p&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;react-query 라이브러리에서 제공하는 useQuery() 함수를 import하여 사용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1662687355609&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useQuery } from &quot;react-query&quot;

function App() {

  useQuery()

  return (
    &amp;lt;div className=&quot;App&quot;&amp;gt;

      &amp;lt;header className='header-container'&amp;gt;
        &amp;lt;ul className='nav-ul flex-box'&amp;gt;
         
         
         -- 중간 코드 생략 --&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1662687501604&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;useQuery('작명', ()=&amp;gt;{
	return axios.get('경로').then((x) =&amp;gt;{
    		return x.data
    })
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1662687607606&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const result = useQuery('작명', ()=&amp;gt;{
	return axios.get('경로').then((x) =&amp;gt;{
    		return x.data
    })
})


result.data

result.isLoading

result.error&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수에 저장해서 사용하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장점은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성공했나, 실패했나 변수하나로 쉽게 파악가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로딩중일 때 '로딩중입니다'라고 보여주고 싶을 때는?&lt;/p&gt;
&lt;pre id=&quot;code_1662687751864&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{ result.isLoading ? '로딩중' : result.data.name }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;amp;&amp;amp; 사용해도된다.&lt;/p&gt;
&lt;pre id=&quot;code_1662687824782&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{ result.isLoading &amp;amp;&amp;amp; '로딩중' }
{ result.error &amp;amp;&amp;amp; '에러나고있다' }
{ result.data &amp;amp;&amp;amp; 'result.data.name' }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이거를 react-query를 사용하지 않았다면 그냥 state부터 만들고 시작했어야했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 이 라이브러리는 그럴 필요가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 refatch를 자동으로 해주기 때문에 실시간으로 싱싱한 데이터들을 볼 수 있고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실패 시 자동으로 알아서 retry를 해준다.&lt;/p&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;state공유를 안해도된다는 것!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;props로 전송안해도되고 그냥 부모컴포넌트안에 넣었던 ajax코드 그대로 넣어도 가능하다!&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;굳이 똑같은 요청을 두번이나 하지않는 react query&lt;/p&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;캐싱기능이 있다는 것, 캐싱이란 ajax성공결과를 5분동안 기억을 해준다는 것,&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;redux-toolkit 설치했다면 RTK Query도 자동 설치되어지기 때문에&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;react-query 유사한 기능개발 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end/REACT- react-query (실시간 데이터 중요할 시)</category>
      <category>ajax</category>
      <category>React</category>
      <category>react-query</category>
      <category>redux-toolkit</category>
      <category>STATE</category>
      <category>프론트엔드</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/86</guid>
      <comments>https://thfdl0317.tistory.com/entry/REACT-react-query-%EC%82%AC%EC%9A%A9%ED%95%B4%EB%B3%B4%EA%B8%B0-%EC%8B%A4%EC%8B%9C%EA%B0%84%EB%8D%B0%EC%9D%B4%ED%84%B0%EA%B0%80-%ED%95%84%EC%9A%94%ED%95%A0-%EB%95%8C#entry86comment</comments>
      <pubDate>Fri, 9 Sep 2022 11:03:33 +0900</pubDate>
    </item>
    <item>
      <title>REACT- Redux 3 : store의 state 변경하는 방법을 알아보자</title>
      <link>https://thfdl0317.tistory.com/entry/REACT-Redux-3-store%EC%9D%98-state-%EB%B3%80%EA%B2%BD%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95%EC%9D%84-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Redux에서 state를 변경하는 방법을 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제일 먼저 state 수정해주는 함수를 만들고 함수를 실행해달라고 store.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;1. state 수정하는 함수만들기 : reducers등장&lt;/p&gt;
&lt;pre id=&quot;code_1662602508539&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const user = createSlice({
    name : 'user',  
    initialState : 'kim', 
    reducers : {
      changeName(state){ //--&amp;gt; 위의 state를 수정하는 함수를 요기다가 만드는 것
      	return 'sol' + state
      }
    }
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 함수 만든 것을 사용할 수 있게 export해줘야함&lt;/p&gt;
&lt;pre id=&quot;code_1662602634912&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const user = createSlice({
    name : 'user',  
    initialState : 'kim', 
    reducers : {
      changeName(state){ //--&amp;gt; 위의 state를 수정하는 함수를 요기다가 만드는 것
      	return 'sol' + state
      }
    }
})

export const {changeName, export하고 싶은 함수 다 담기} = user.actions&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 함수를 필요한 곳에갖다 사용할 수 있도록 import하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Cart.js&lt;/p&gt;
&lt;pre id=&quot;code_1662602896391&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {changeName} from &quot;./../store.js&quot;

function Cart(){
	
    const state = useSelector((state)=&amp;gt; state)
    const dispatch = useDispatch(); //store한테 요청을 보내주는 함수임
	
    return (
        &amp;lt;div&amp;gt;
            &amp;lt;button onClick={()=&amp;gt;{}}&amp;gt;+&amp;lt;/button&amp;gt;
            &amp;lt;Table&amp;gt;
            
        -- 밑 코드 생략 --&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dispatch(state변경함수()) 사용&lt;/p&gt;
&lt;pre id=&quot;code_1662603049415&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;button onClick={()=&amp;gt;{dispatch(changeName())}}&amp;gt;+&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하다 문뜩 드는 생각은&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아.. Redux 복잡하다. 수정하기 위해서는 store.js에 있는 것을 export하고 import한 후 꼭 dispatch()로 감싸지 않으면 오류가나고..&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;직접 수정을 하면 편리하지만 프로젝트가 커질 수 있는 상황에서는 Redux를 사용하여 수정을 하는 것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트가 너무 많아서 직접 'kim'이라는 state를 변경하려다가 버그가 발생하면 그 많은 컴포넌트를 하나씩 다 찾아서 봐야하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 Redux로 수정을 할 경우에는 store.js에 미리 만들어둔 뒤 컴포넌트가 실행해달라는 것만 가져와 코드를 짜면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버그발생 시 어떤 문제였나 찾기가 편합니다. 원인이 어딨는지 바로 알아낼테니까요.(Store.js 요놈요놈)&lt;/p&gt;</description>
      <category>Front-end/REACT - Redux 사용해보기(props는 저리가봐!)</category>
      <category>Component</category>
      <category>dispatch()</category>
      <category>frontend</category>
      <category>React</category>
      <category>Redux</category>
      <category>STATE</category>
      <category>useDispatch</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/85</guid>
      <comments>https://thfdl0317.tistory.com/entry/REACT-Redux-3-store%EC%9D%98-state-%EB%B3%80%EA%B2%BD%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95%EC%9D%84-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90#entry85comment</comments>
      <pubDate>Thu, 8 Sep 2022 11:22:37 +0900</pubDate>
    </item>
    <item>
      <title>REACT- Redux4. state object, array일 경우 변경하는 방법을 알아보자.</title>
      <link>https://thfdl0317.tistory.com/entry/REACT-Redux3-state-object-array%EC%9D%BC-%EA%B2%BD%EC%9A%B0-%EB%B3%80%EA%B2%BD%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95%EC%9D%84-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 Redux 안에 있는 state가 object나 array일 경우에 변경하는 법을 알아보려한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;initialState 안을 오브젝트로 변경한다.&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;store.js&lt;/p&gt;
&lt;pre id=&quot;code_1662568780270&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { configureStore, createSlice } from '@reduxjs/toolkit'
import user from '../store/userSlice'

const user = createSlice({
    name : 'user',  // 'state이름',
    initialState : {name : 'kim', age : 20},
    reducers : {
      changeName(state){
        return 'park' + state
        }
    }
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;object로 바꿨기 때문에 state를 데이터바인딩하는 문법도 달라졌을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Cart.js&lt;/p&gt;
&lt;pre id=&quot;code_1662569001934&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Cart(){ 

    let result = useMemo(()=&amp;gt;{ return testUsememo() }, [])
  
    const state = useSelector((state)=&amp;gt;{return state})
    console.log(state.cart)

    const dispatch = useDispatch();//store한테 요청을 보내주는 함수임

    const [count, setCount] = useState(0)

    return (
        &amp;lt;div&amp;gt;
            &amp;lt;p&amp;gt;{state.user.name} {state.user.age}의 장바구니&amp;lt;/p&amp;gt;
            
            
            -- 밑 코드 생략 --&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼, 변경하는 방법을 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;name : 'kim'을 -&amp;gt; name : 'sol'로 바꾸려면&lt;/p&gt;
&lt;pre id=&quot;code_1662569190920&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { configureStore, createSlice } from '@reduxjs/toolkit'
import user from '../store/userSlice'

const user = createSlice({
    name : 'user',  // 'state이름',
    initialState : {name : 'kim', age : 20},
    reducers : {
      changeName(state){
        return {name : 'sol', age : 20}
      }
    }
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기 이 return 부분이 바꿔지도록해야한다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;return문을 안쓰고 직접 수정해도 state변경이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;809&quot; data-origin-height=&quot;381&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpNefW/btrLE2EMOQ4/qppk3XlttRmaVGRYTqv8pk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpNefW/btrLE2EMOQ4/qppk3XlttRmaVGRYTqv8pk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpNefW/btrLE2EMOQ4/qppk3XlttRmaVGRYTqv8pk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpNefW%2FbtrLE2EMOQ4%2Fqppk3XlttRmaVGRYTqv8pk%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;809&quot; height=&quot;381&quot; data-origin-width=&quot;809&quot; data-origin-height=&quot;381&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 파라미터 state가 위에있는 state를 의미하고 state.name = 'sol'인 오브젝트 수정내용이 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;store.js&lt;/p&gt;
&lt;pre id=&quot;code_1662569470112&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { configureStore, createSlice } from '@reduxjs/toolkit'
import user from '../store/userSlice'

const user = createSlice({
    name : 'user',  // 'state이름',
    initialState : {name : 'kim', age : 20},
    reducers : {
      changeName(state){
        state.name = 'park'
        //직접 수정가능 왜냐면 immer.js가 자동으로 되어있기 때문이다.
      }
    }
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이번에 버튼하나 누르면 age : 20가 증가되는 기능을 만들어보자.&lt;/p&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. Store.js 에 increase라는 함수를 먼저만들기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 함수를 동작시키면 age가 +1되도록 만들기&lt;/p&gt;
&lt;pre id=&quot;code_1662570121186&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const user = createSlice({
    name : 'user',
    initialState : {name : 'kim', age : 20},
    reducers : {
      changeName(state){
        state.name = 'park'
      },
      increase(state){ 
        state.age += 1
      },
    }
})

export const { changeName , increase } = user.actions&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이 increase함수가 필요한 곳에서 갖다 쓰도록 Cart.js로 가서 import하고&lt;/p&gt;
&lt;pre id=&quot;code_1662570363519&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {useState, memo, useMemo} from 'react';
import {Table} from 'react-bootstrap';
import { useDispatch, useSelector } from 'react-redux';
import { changeName, increase } from '../store/userSlice.js';

function Cart(){ 

    const state = useSelector((state)=&amp;gt;{return state})

    const dispatch = useDispatch();//store한테 요청을 보내주는 함수임

    return (
        &amp;lt;div&amp;gt;
            &amp;lt;p&amp;gt;{state.user.name} {state.user.age}의 장바구니&amp;lt;/p&amp;gt;
            &amp;lt;button onClick={()=&amp;gt;{dispatch(increase())}}&amp;gt;버튼&amp;lt;/button&amp;gt;
           
           
           -- 밑 코드 생략 --&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 만약, 10개씩, 100개씩 증가하게하고 싶다면?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수에 파라미터문법을 이용하여 쓸 때 마다 각각 다른 기능의 함수를 갖다 쓸 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;| state 변경 함수에 파라미터 뚫는 법&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;store.js&lt;/p&gt;
&lt;pre id=&quot;code_1662570664198&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { configureStore, createSlice } from '@reduxjs/toolkit'
import user from '../store/userSlice'

const user = createSlice({
    name : 'user',  // 'state이름',
    initialState : {name : 'kim', age : 20},
    reducers : {
      changeName(state){
        state.name = 'park'
        //직접 수정가능 왜냐면 immer.js가 자동으로 되어있기 때문이다.
      },
      increase(state, action){ //state변경함수를 action이라한다.
        state.age += action.payload
      }
    }
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1662570693333&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;increase(state, action){ //state변경함수를 action이라한다.
state.age += action.payload // payload를 꼭 넣어주자&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end/REACT - Redux 사용해보기(props는 저리가봐!)</category>
      <category>Dispatch</category>
      <category>frontend</category>
      <category>payload</category>
      <category>React</category>
      <category>Redux</category>
      <category>STATE</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/84</guid>
      <comments>https://thfdl0317.tistory.com/entry/REACT-Redux3-state-object-array%EC%9D%BC-%EA%B2%BD%EC%9A%B0-%EB%B3%80%EA%B2%BD%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95%EC%9D%84-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90#entry84comment</comments>
      <pubDate>Thu, 8 Sep 2022 02:14:44 +0900</pubDate>
    </item>
    <item>
      <title>REACT- Redux2. Store에 state 보관하여 사용해보자.</title>
      <link>https://thfdl0317.tistory.com/entry/REACT-Redux2-Store%EC%97%90-state-%EB%B3%B4%EA%B4%80%ED%95%98%EC%97%AC-%EC%82%AC%EC%9A%A9%ED%95%B4%EB%B3%B4%EC%9E%90</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Store.js를 빼다가 쓰는 법을 알아보자. 그전에 저번 시간에 말했던 것 복습.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux를 왜 사용하는가.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  이유는 컴포넌트간에 state공유가 불편할 때 사용한다.&lt;/p&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: #ef5369;&quot;&gt;&lt;b&gt; redux를 사용하면 redux store.js통 안에 state들을 다 넣고 빼서 사용할 수 있기 때문이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;그럼 props전송이 필요없는 이점이 있기 때문.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리덕스 스토어안에 있던 스테이트들은 모든 컴포넌트들이 직접 통신을 해서 store.js안에 있는 state을 가져가서 쓸 수 있으니 props전송을 안해도된다는 것!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이 store.js 파일에다가 state만드는 법을 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 Store.js 파일안에다가&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;createSlice() 쓰고 import해야한다.&lt;/p&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;useState와 비슷한 용도임&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;store.js&lt;/p&gt;
&lt;pre id=&quot;code_1662545596763&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {configureStore, createSlice} from '@reduxjs/toolkit';

createSlice({ //useState와 같은 용도
    name : 'user',  // 'state이름',
    initialState :'kim'//실제 state값을 적어줌
})


export default configureStore({
	reducer: {
    }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만든 다음, reducer부분에 등록을해야사용이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;| Redux store에 state보관하는 방법&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1662545760740&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {configureStore, createSlice} from '@reduxjs/toolkit';

const user = createSlice({
    name : 'user',  // 'state이름',
    initialState :'kim'
})


export default configureStore({
	reducer: {
    	user : user.reducer
    }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;state하나 만들고 등록을 끝낸 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게하면 아 state를 갖다가 사용할 수 있다는 것이다.&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;| Redux store의 state 꺼내는 방법&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Cart.js로 가서&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1662546093829&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Cart(){ 

	useSelector() // Redux의 state를 가져와준다.
   
 	-- 중간 코드 생략 --   
   
}   
export default Cart;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상단에 import잊지말고!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수화하여 저장하고 자유롭게 갖다쓰자.&lt;/p&gt;
&lt;pre id=&quot;code_1662546375355&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Cart(){ 

	const reduxGo = useSelector((state)=&amp;gt; {return state }) // Redux의 state를 가져와준다.
   
 	-- 중간 코드 생략 --   
   
}   
export default Cart;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;state 더 만들어보면, 요런식으로 등록,&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1662546622545&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const user = createSlice({
    name : 'user',  // 'state이름',
    initialState : {name : 'kim', age : 20}
})

const testNumber = createSlice({
    name : 'testNumber',
    initialState : [10, 11, 12]
})



export default configureStore({
  reducer: {
    user : user.reducer, 
    testNumber : testNumber.reducer
   }
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적으로 더 말한다면 useSelector를 편하게 쓰려면 이렇게 사용하는데, 이게&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;store안에 있는 모든 state라는 것이 되기에 이런 식으로 적고 쓰는 것이 좋다.&lt;/p&gt;
&lt;pre id=&quot;code_1662546767110&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const reduxGo = useSelector((state)=&amp;gt; {return state })&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1662546813350&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const reduxGo = useSelector((state)=&amp;gt; state.testNumber )&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux를 쓰려면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부라이브러리 설치, 셋팅문법필요, store에 state를 등록 해야하기 때문에 번거로운 작업이긴한다.&lt;/p&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;간단한 프로젝트일 경우는 props를 사용하는 것이 낫지만,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트가 30개, 40개 늘어난다면 Redux를 사용하는 것이 더 좋은 방법이 되기 때문이지.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데, 리덕스 쓴다해서 모든 state들을 꼭 Store에 보관할 필요는 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 state가 필요하다면 공유가필요없다. 그러면 굳이 store에 저장할 필요없고 그냥 useState를 사용해도된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end/REACT - Redux 사용해보기(props는 저리가봐!)</category>
      <category>createSlice</category>
      <category>frontend</category>
      <category>props</category>
      <category>React</category>
      <category>Reducer</category>
      <category>Redux</category>
      <category>STATE</category>
      <category>useState</category>
      <category>데이터바인딩</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/83</guid>
      <comments>https://thfdl0317.tistory.com/entry/REACT-Redux2-Store%EC%97%90-state-%EB%B3%B4%EA%B4%80%ED%95%98%EC%97%AC-%EC%82%AC%EC%9A%A9%ED%95%B4%EB%B3%B4%EC%9E%90#entry83comment</comments>
      <pubDate>Wed, 7 Sep 2022 19:40:08 +0900</pubDate>
    </item>
    <item>
      <title>REACT- Redux1.  redux설치와 props대신 Redux를 사용하는 이유</title>
      <link>https://thfdl0317.tistory.com/entry/REACT-Redux1-redux%EC%84%A4%EC%B9%98%EC%99%80-props%EB%8C%80%EC%8B%A0-Redux%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;React를 사용하려면 Redux의 개념과 어떻게 사용하는지에 대해서 알아야한다는데,&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;간단명료하게 설치방법과 셋팅, Redux를 왜 쓰는지에서 알아보고자한다.&lt;/p&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;만들려는 것은 Redux를 이용하여 장바구니만들기이다. (목표목표~)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;| 페이지&amp;nbsp; 이동 경로 설정&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 페이지 이동할 수 있도록 라우터 경로 설정,&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1662540779109&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;Routes&amp;gt;
	&amp;lt; Route path = &quot;/cart&quot; element={&amp;lt;Cart /&amp;gt;} /&amp;gt;
&amp;lt;Routes&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;| 장바구니인 Cart.js 컴포넌트 생성&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Cart.js 컴포넌트를 만들기 ( 디자인은 우선 간단하게 bootstrap 라이브러리의 table 을 사용)&lt;/p&gt;
&lt;pre id=&quot;code_1662540906447&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {useState, memo, useMemo} from 'react';
import {Table} from 'react-bootstrap';

function Cart(){ 

    return (
        &amp;lt;div&amp;gt;
           &amp;lt;Table&amp;gt;
              &amp;lt;thead&amp;gt;
                &amp;lt;tr&amp;gt;
                  &amp;lt;th&amp;gt;#&amp;lt;/th&amp;gt;
                  &amp;lt;th&amp;gt;상품이름&amp;lt;/th&amp;gt;
                  &amp;lt;th&amp;gt;수량&amp;lt;/th&amp;gt;
                  &amp;lt;th&amp;gt;변경버튼&amp;lt;/th&amp;gt;
                &amp;lt;/tr&amp;gt;
              &amp;lt;/thead&amp;gt;
              &amp;lt;tbody&amp;gt;
                &amp;lt;tr&amp;gt;
                  &amp;lt;td&amp;gt;1&amp;lt;/td&amp;gt;
                  &amp;lt;td&amp;gt;안녕&amp;lt;/td&amp;gt;
                  &amp;lt;td&amp;gt;안녕&amp;lt;/td&amp;gt;
                  &amp;lt;td&amp;gt;안녕&amp;lt;/td&amp;gt;
                &amp;lt;/tr&amp;gt;
              &amp;lt;/tbody&amp;gt;
            &amp;lt;/Table&amp;gt; 
        &amp;lt;/div&amp;gt;
    )
}

export default Cart;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하고 , App.js에 export한 것을 import 가져온다.&lt;/p&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;장바구니 데이터를 state에 보관해두고 데이터바인딩하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 이 state를 어디다가 만드는 것이 좋을까? Cart.js안에서 사용해도 괜찮다. 근데 이 Cart.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;App.js, Detail.js , Cart.js도 필요하지않나? 그러면 어디다 만들어야하나?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최상위 컴포넌트인 App.js에다 만들어야한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 그 props를 여기다하고 저기다하고 또 저쪽에다 입력하고..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 힘들다면 다른 방법 Redux가 있다.&lt;/p&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; Redux, 이것을 사용하면 컴포넌트들 간에 props없이 State 공유가 가능하다.&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;Redux를 설치하면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트 파일 안에 state들을 다 보관해둘 수 있고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 컴포넌트들이 이 state들을 다 빼서 사용할 수 있다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 식으로 말이야.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1363&quot; data-origin-height=&quot;906&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caNiN0/btrLD01ANfb/7fcQyXomCVkaX2KrURHnK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caNiN0/btrLD01ANfb/7fcQyXomCVkaX2KrURHnK0/img.png&quot; data-alt=&quot;갖다 빼서 쓸 수 있는 redux, 그러면 props 전송할 필요가 없지.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caNiN0/btrLD01ANfb/7fcQyXomCVkaX2KrURHnK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaNiN0%2FbtrLD01ANfb%2F7fcQyXomCVkaX2KrURHnK0%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;1363&quot; height=&quot;906&quot; data-origin-width=&quot;1363&quot; data-origin-height=&quot;906&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;갖다 빼서 쓸 수 있는 redux, 그러면 props 전송할 필요가 없지.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;| Redux 설치&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하기전에! 우선 package.json으로 가자.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;813&quot; data-origin-height=&quot;246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wir0T/btrLFzIsjqc/WxuRgK2myaklfNMa1uTwaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wir0T/btrLFzIsjqc/WxuRgK2myaklfNMa1uTwaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wir0T/btrLFzIsjqc/WxuRgK2myaklfNMa1uTwaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwir0T%2FbtrLFzIsjqc%2FWxuRgK2myaklfNMa1uTwaK%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;813&quot; height=&quot;246&quot; data-origin-width=&quot;813&quot; data-origin-height=&quot;246&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트와 리액트 돔 버전이 18.0 이상이어야하니, 이것을 확인할 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확인하고나서 터미널에 입력 (설치 후 npm start하여 확인)&lt;/p&gt;
&lt;pre id=&quot;code_1662543123454&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install @reduxjs/toolkit react-redux&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;| 셋팅1. Store.js 파일 생성&lt;/b&gt;&amp;nbsp;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;src안에 Store.js 파일을 만들고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리덕스를 쓰면 state를 보관하는 통을 만들어줘야하기 때문에 Store.js하나를 만들어주고 안에&lt;/p&gt;
&lt;pre id=&quot;code_1662543227963&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { configureStore } from '@reduxjs/toolkit'

export default configureStore({
  reducer: { }
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력하면 스토어 생성 끝,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 두 번째는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;| 셋팅2.&amp;nbsp; 안녕, index.js? 나&amp;nbsp; 이 Store.js좀 선언할게&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;index.js에 가서 &quot;내가 이 Store를 쓰겠습니다.&quot;하고 선언을 해줘야한다. &amp;lt;Provider store={store} &amp;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;index.js&lt;/p&gt;
&lt;pre id=&quot;code_1662543454913&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from 'react';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import store from './store/store.js';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    &amp;lt;Provider store={store}&amp;gt;
      &amp;lt;BrowserRouter&amp;gt;
      &amp;lt;App /&amp;gt;
      &amp;lt;/BrowserRouter&amp;gt;
    &amp;lt;/Provider&amp;gt;
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;import 할 것&lt;/p&gt;
&lt;pre id=&quot;code_1662543512295&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Provider } from 'react-redux';
import store from './store/store.js';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;App이라는 컴포넌트와 그 모든 자식들은 이 store.js에 있는 state를 전부 사용이 가능해진다.&lt;/p&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;이렇게 Redux 설치 시 주의할 점, 셋팅방법, 왜 리덕스를 사용하는지에 대한 이유를 알아보았다.&lt;/p&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;이 셋팅한 Redux을 사용해보려한다.&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end/REACT - Redux 사용해보기(props는 저리가봐!)</category>
      <category>Bootstrap</category>
      <category>frontend</category>
      <category>JavaScript</category>
      <category>React</category>
      <category>Redux</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/82</guid>
      <comments>https://thfdl0317.tistory.com/entry/REACT-Redux1-redux%EC%84%A4%EC%B9%98%EC%99%80-props%EB%8C%80%EC%8B%A0-Redux%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0#entry82comment</comments>
      <pubDate>Wed, 7 Sep 2022 18:41:23 +0900</pubDate>
    </item>
    <item>
      <title>중첩되는 컴포넌트가 많다? props대신 Context API를 사용해보자</title>
      <link>https://thfdl0317.tistory.com/entry/%EC%A4%91%EC%B2%A9%EB%90%98%EB%8A%94-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EA%B0%80-%EB%A7%8E%EB%8B%A4-props%EB%8C%80%EC%8B%A0-Context-API%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%B4%EB%B3%B4%EC%9E%90</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 개발하면서 느끼셨겠지만 리액트는 Single Page Application임으로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발 시 단점이 많이 보이게되는데 그 단점은 state간의 공유가 참으로 어렵다는 사실,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;state를 갖다 쓸 수 있는 방법은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부모 컴포넌트&amp;nbsp;   자식 컴포넌트로 전달하기 위해서 props 전송을 해야한다는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래, props가 있다, props를 사용하면되겠지. 근데!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;628&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bU7BSL/btrLy2yIG2E/FFzvzjLr6SU7sI06GQJkDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bU7BSL/btrLy2yIG2E/FFzvzjLr6SU7sI06GQJkDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bU7BSL/btrLy2yIG2E/FFzvzjLr6SU7sI06GQJkDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbU7BSL%2FbtrLy2yIG2E%2FFFzvzjLr6SU7sI06GQJkDK%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;673&quot; height=&quot;469&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;628&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;data라는 state를&amp;nbsp; DetailContent컴포넌트에서 사용하려할 때 중간의 Detail 컴포넌트를 건너 뛰어서 사용할 수 없다는 불편함이 있다.&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;예를들어 컴포넌트가 20번 중첩이 된다면 props를 10번 이상 입력해야하는데,&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;&lt;b&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;첫 번째 방법&lt;/span&gt;은 리액트 기본 문법인 Context API 를 사용하는 것,&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;두 번째 방법&lt;/span&gt;은 외부 라이브러리를 사용하는 Redux를 사용하는 것.&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;지금은 Context API를 사용하는 방법을 알아볼 것이다.&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;Context API는 props없이 state 공유가능하다.&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;셋팅문법은 3개정도인데,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 함수 바깥에다가&lt;/p&gt;
&lt;pre id=&quot;code_1662525519944&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {createContext, useState} from 'react';

export const Context1 = createContext(); 

-- 나머지 코드 생략 --&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;const Context1 = createContext() 이거는&amp;nbsp; state 의 보관함으로 Context하나 만들어준다는 것.&lt;/p&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;state공유를 원하는 것을 감싸준다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1662525757742&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; {/* 페이지를 여러개 만들고 싶다면 : URL파라미터 써도 가능 */}
          
          &amp;lt;Route path=&quot;/detail/:id&quot; element={
              &amp;lt;Context1.Provider value={{data1, data2}}&amp;gt;
                &amp;lt;Detail shoes={shoes} /&amp;gt;  
                {/* &amp;lt;- 여기 안에 있는 모든 컴포넌트는 value값에 있는 거 사용가능 */}
              &amp;lt;/Context1.Provider&amp;gt;
            } /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 갖다 쓰기위해서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 import하기. 갖다 쓰기 위해&lt;/p&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;App.js&lt;/p&gt;
&lt;pre id=&quot;code_1662525888460&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export const Context1 = createContext(); //state보관함임&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Detail.js&lt;/p&gt;
&lt;pre id=&quot;code_1662525914258&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {Context1} from './../App.js'; //지금 경로에서 한폴더 위로간다음에 app.js를 찾을거임&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오브젝트 형식으로&amp;nbsp; state들이 보관되어있다.&lt;/p&gt;
&lt;pre id=&quot;code_1662526155088&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Detail(props) {

	useContext(Context1) 
    //보관함 해체, 여기 자리에 {state1, state2} 오브젝트 형식으로 남는다.


	-- 나머지 코드 생략 --&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료를 쉽게 꺼내 쓸 수 있도록&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1662526249587&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const {data, data2} = useContext(Context1)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1662526332787&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;functon Detail(props){
	const {data1, data2} = useContext(Context1)
    
    
    -- 중간 코드 생략 -- 
    
    &amp;lt;p&amp;gt;{data}&amp;lt;/p&amp;gt;
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 Detail뿐만 아니라 자식 컴포넌트들도 props 없이 사용이 가능해진다.&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;근데 Context API 을 안쓰는 이유가 있다는데~ 그것은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. state 변경 시 쓸데 없이는 것까지 무조건 재렌더링되므로 효율적인 부분에서 떨어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 자식 컴포넌트가 컨텍스트 문법을 쓰고 있다면 나중에 다른 페이지에서 재사용할 시 이상해질 수 있다.&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;따라서 Context API보다 외부 라이브러리를 거의 사용하는 편이다.&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;zwj;♀️오늘 정리&lt;/p&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;lt;Single&amp;nbsp;Page&amp;nbsp;Application&amp;nbsp;단점&amp;nbsp;:&amp;nbsp;&amp;gt; &lt;br /&gt;-&amp;nbsp;컴포넌트&amp;nbsp;간&amp;nbsp;state&amp;nbsp;공유&amp;nbsp;어려움 &lt;br /&gt;-&amp;nbsp;부모&amp;nbsp;컴포넌트&amp;nbsp;-&amp;gt;&amp;nbsp;컴포넌트&amp;nbsp;(props로) &lt;br /&gt;&lt;br /&gt; &amp;lt;컴포넌트가&amp;nbsp;여러개&amp;nbsp;중접되는&amp;nbsp;것말고&amp;nbsp;다른&amp;nbsp;방법&amp;gt; &lt;br /&gt;prop가&amp;nbsp;싫다면 &lt;br /&gt;1.&amp;nbsp;Context&amp;nbsp;API&amp;nbsp;리액트&amp;nbsp;기본문법&amp;nbsp;-&amp;nbsp;context&amp;nbsp;API를&amp;nbsp;쓰면&amp;nbsp;props&amp;nbsp;전송없이&amp;nbsp;state&amp;nbsp;공유&amp;nbsp;가능하다 &lt;br /&gt;2.&amp;nbsp;Redux등&amp;nbsp;외부&amp;nbsp;라이브러리&amp;nbsp;설치 &lt;br /&gt;&lt;br /&gt; &amp;lt;&amp;nbsp;Context&amp;nbsp;API&amp;nbsp;사용법&amp;nbsp;&amp;gt; &lt;br /&gt;셋팅&amp;nbsp;1.&amp;nbsp;createContext() &lt;br /&gt;셋팅&amp;nbsp;2.&amp;nbsp;&amp;lt;Context&amp;gt;로&amp;nbsp;원하는&amp;nbsp;컴포넌트&amp;nbsp;감싸기&amp;nbsp;-&amp;gt;&amp;nbsp;&amp;nbsp;&amp;lt;Context1.Provider&amp;gt;&amp;lt;/Context1.Provider&amp;gt; &lt;br /&gt;셋팅&amp;nbsp;3.&amp;nbsp;value={{state1,&amp;nbsp;state2...}}&amp;nbsp;공유원하는&amp;nbsp;거&amp;nbsp;넣기 &lt;br /&gt;&lt;br /&gt; &amp;lt;Context&amp;nbsp;API&amp;nbsp;특징&amp;gt; &lt;br /&gt;1.&amp;nbsp;state&amp;nbsp;변경&amp;nbsp;시&amp;nbsp;쓸데없는&amp;nbsp;것까지&amp;nbsp;제렌더링 &lt;br /&gt;2.&amp;nbsp;나중에&amp;nbsp;컴포넌트&amp;nbsp;재사용이&amp;nbsp;어려움&lt;/p&gt;</description>
      <category>Front-end/REACT -  Context API 사용해보기(props말고)</category>
      <category>context api</category>
      <category>createContext()</category>
      <category>props</category>
      <category>React</category>
      <category>Redux</category>
      <category>useContext()</category>
      <category>useState</category>
      <category>컴포넌트 중첩</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/81</guid>
      <comments>https://thfdl0317.tistory.com/entry/%EC%A4%91%EC%B2%A9%EB%90%98%EB%8A%94-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EA%B0%80-%EB%A7%8E%EB%8B%A4-props%EB%8C%80%EC%8B%A0-Context-API%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%B4%EB%B3%B4%EC%9E%90#entry81comment</comments>
      <pubDate>Wed, 7 Sep 2022 13:30:28 +0900</pubDate>
    </item>
    <item>
      <title>React Ajax 요청방법에 대해 알아보자!</title>
      <link>https://thfdl0317.tistory.com/entry/React-Ajax-%EC%9A%94%EC%B2%AD%EB%B0%A9%EB%B2%95%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 리액트에서 Ajax의 요청방법은 어떻게 하나? 에대해서 알아보고자합니다만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그전에 Ajax에 대한 개념과 Ajax를 사용하려할 때 알아야 할 요청방법들에 대해서도 살펴보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 그럼 먼저 오늘 목표로 하려하는 Ajax, 요녀석은 뭘까요?&lt;/p&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;h1&gt;&lt;b&gt;| Ajax 란?&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ajax란 Asynchronous JavaScript and XML의 약자로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 페이지 전체를 다시 로딩하지 않고도, 웹 페이지의 일부분만을 갱신할 수 있는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ajax를 이용하면 백그라운드 영역에서 서버와 통신하여, 그 결과를 웹 페이지의 일부분에만 표시할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를들어, 홈페이지에 3영역으로 나눠져있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 검색하고 싶은 것을 검색할 수 있는 검색 영역,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검색해서 나오는 목록 수(조회영역)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검색해서 나온 목록 중 하나를 누르면 그 하나의 데이터 내용들을 더 상세하게 볼 수 있도록하는 상세영역&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 검색을 할 때마다마다 조회영역에서는 검색란에 입력한 것에 따라 데이터가 나올텐데 이게 계속 새로고침하여 깜빡깜빡 화면에 나와 눈을 따갑따갑하게 한다고 생각해보십시오. 너무 아프겠죠,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 이 Ajax는 위에서 말했듯이 웹 페이지의 일부분만 표시, 즉, UI화면에 사용자가 요청한 데이터를 조회영역쪽에만 보내게하는 것입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 말하자면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버에 새로고침없이 요청을 할 수 있게 해주는 것이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 하나의 정의로는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 아범이 naver에 들어가려면 주소창에 &lt;a href=&quot;http://naver.com&quot;&gt;naver.com&lt;/a&gt; 이라고 쳐야 나옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 네이버 서버에 요청해서 메인 페이지가 띵 하고 나온것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 나 이거 열고 싶어!하면 자, 여기!하고 갖다주는 것이라고 생각하시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런 이 ajax를 사용할 때의 요청은 두가지 방법이 있는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저에 직접 입력하는 요청은 get 요청 : 자료를 읽고 싶을 때 많이 사용,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나머지 요청 방법에서 Post 요청이 있습니다. Post 요청은 아이디, 비밀번호를 입력할 때 URL에다 입력하는 것이 아니라 정보를 숨겨서 요청할 때 Post요청으로 이용하기도 합니다. 중요 정보를 전달할 때 사용하죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Get방식, Post방식이 있다는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 Get방식은 어떠할 때 사용하고 Post방식은 어떠할 때 사용을 해야하는가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;| &lt;span data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;Get방식 vs Post 방식&lt;/span&gt;&lt;/b&gt;&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;859&quot; data-origin-height=&quot;415&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o17NB/btrLAycoS20/eokNQ1Tl67hz0rmFKLnDRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o17NB/btrLAycoS20/eokNQ1Tl67hz0rmFKLnDRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o17NB/btrLAycoS20/eokNQ1Tl67hz0rmFKLnDRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo17NB%2FbtrLAycoS20%2FeokNQ1Tl67hz0rmFKLnDRK%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;859&quot; height=&quot;415&quot; data-origin-width=&quot;859&quot; data-origin-height=&quot;415&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 다시 Ajax는? 서버에 요청을 하되 새로고침없이 요청할 수 있게 도와주는 코드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GET이나 POST 요청방식을 할 땐 새로고침을 하는데 Ajax는 필요치 않다는 것!&lt;/p&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;Ajax를 쓰는 방법은&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바스크립트의 fetch()를 사용해서 2. 제이쿼리를 설치하여 $.ajax()라든가 3. axios를 설치해서 axios.get()를 사용하는 방법이 있는데 이 중 아범은 리액트에 3번째 방법인 axios를 설치하여 리액트에서 ajax 요청을 해보도록하겠습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;| React에서 Ajax 요청방법&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;설치시작! 먼저 axios 라이브러리 설치&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;467&quot; data-origin-height=&quot;35&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ENV6Y/btrLxZPBtSU/wzSwq0kQEsZFfPKeVuKYn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ENV6Y/btrLxZPBtSU/wzSwq0kQEsZFfPKeVuKYn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ENV6Y/btrLxZPBtSU/wzSwq0kQEsZFfPKeVuKYn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FENV6Y%2FbtrLxZPBtSU%2FwzSwq0kQEsZFfPKeVuKYn0%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;467&quot; height=&quot;35&quot; data-origin-width=&quot;467&quot; data-origin-height=&quot;35&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새터미널열고 yarn add axios 입력&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;import axios from 'axios'; 위에 입력하여 이제 내가 ajax하려고 axios를 설치했어~라고 알려줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 더보기 버튼을 눌렀을 때 서버에 Ajax 요청을 하여 상품 데이터를 더 가져올 예정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버튼을 눌렀을 때 요청이 될 수 있도록&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;Button variant=&quot;secondary&quot; onClick={()=&amp;gt;{ axios.get(); }}&amp;gt;더보기&amp;lt;/Button&amp;gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;axios.get('Get 요청할URL입력');&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 연습으로 &lt;a href=&quot;https://www.naver.com/&quot;&gt;https://www.naver.com/&lt;/a&gt; 을 넣어 잘 정용되는지 테스트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;axios.get( '&lt;a href=&quot;https://www.naver.com/&quot;&gt;https://www.naver.com/&lt;/a&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;axios.get( '&lt;a href=&quot;https://www.naver.com/&quot;&gt;https://www.naver.com/&lt;/a&gt;' ).then().catch() 이렇게 입력하여 요청이 정상적으로 실행될 경우와 실패할 경우 실행할 코드를 각 담을 수 있도록합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;303&quot; data-origin-height=&quot;140&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OKGsa/btrLDkkn8pg/TprUywgd37y5q7ie1grKu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OKGsa/btrLDkkn8pg/TprUywgd37y5q7ie1grKu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OKGsa/btrLDkkn8pg/TprUywgd37y5q7ie1grKu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOKGsa%2FbtrLDkkn8pg%2FTprUywgd37y5q7ie1grKu1%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;303&quot; height=&quot;140&quot; data-origin-width=&quot;303&quot; data-origin-height=&quot;140&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하고 실행한다면 F12에 '성공' 또는 '실패' 가 뜹니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 성공했을 때 ajax로 가져온 자료를 출력해봅시다.&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;254&quot; data-origin-height=&quot;76&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GqTUn/btrLu1Hk1Ri/il8Sxw5ZYOpuwuqjPsgb2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GqTUn/btrLu1Hk1Ri/il8Sxw5ZYOpuwuqjPsgb2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GqTUn/btrLu1Hk1Ri/il8Sxw5ZYOpuwuqjPsgb2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGqTUn%2FbtrLu1Hk1Ri%2Fil8Sxw5ZYOpuwuqjPsgb2k%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;254&quot; height=&quot;76&quot; data-origin-width=&quot;254&quot; data-origin-height=&quot;76&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fetch();를 사용하면 비슷하게 fetch('여기 안에 요청해서 보일 URL 입력').then();&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;224&quot; data-origin-height=&quot;338&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1zyln/btrLzldBzrX/nlcKRKI8TbqKXyrK7nq0oK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1zyln/btrLzldBzrX/nlcKRKI8TbqKXyrK7nq0oK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1zyln/btrLzldBzrX/nlcKRKI8TbqKXyrK7nq0oK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1zyln%2FbtrLzldBzrX%2FnlcKRKI8TbqKXyrK7nq0oK%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;224&quot; height=&quot;338&quot; data-origin-width=&quot;224&quot; data-origin-height=&quot;338&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 잠깐 알아두어야할 점은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가져온 데이터를 살펴보면 &quot; &quot; 따음표가 쳐져있습니다. 근데 오브잭트 자료형은 따옴표가 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot; &quot; 쳐져있는 것은 JSON !!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;246&quot; data-origin-height=&quot;59&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lIRAO/btrLDjeInpY/32Gn1c6IFw0lceHJSw8wEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lIRAO/btrLDjeInpY/32Gn1c6IFw0lceHJSw8wEK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lIRAO/btrLDjeInpY/32Gn1c6IFw0lceHJSw8wEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlIRAO%2FbtrLDjeInpY%2F32Gn1c6IFw0lceHJSw8wEK%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;246&quot; height=&quot;59&quot; data-origin-width=&quot;246&quot; data-origin-height=&quot;59&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;axios를 쓰면 json을 object로 알아서 바꿔줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 fetch(); 같은 경우에는 json을 그대로 가져온다는 것 따라서 json을 가져와서 object로 바꿔주는 작업을 또 해야한다는 것, 따라서 axios를 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼, ajax를 이용하여 받아온 상품데이터들을 더보기를 눌렀을 때 추가하여 보여주는 작업을 해봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 &amp;lt;Card&amp;gt;라는 컴포넌트를 각각의 상품들은 반복문으로 만들어졌다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;457&quot; data-origin-height=&quot;132&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVwGHt/btrLzEKOecR/Ysk0o8VNk9x9SSc5pVuKOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVwGHt/btrLzEKOecR/Ysk0o8VNk9x9SSc5pVuKOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVwGHt/btrLzEKOecR/Ysk0o8VNk9x9SSc5pVuKOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVwGHt%2FbtrLzEKOecR%2FYsk0o8VNk9x9SSc5pVuKOk%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;457&quot; height=&quot;132&quot; data-origin-width=&quot;457&quot; data-origin-height=&quot;132&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 game라는 데이터를 조작해야한다든 것 더보기를 클릭해서 기존 데이터보다 더 보여준다?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼, game에 데이터를 더 추가하면됀다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버튼 누르면 ajax 요청으로 데이터를 가져오고 그것을 game 이라는 state에 추가하는 방법&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;81&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWO1e1/btrLzlrawl5/I6e2uM855WE5oGw5tPB1J1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWO1e1/btrLzlrawl5/I6e2uM855WE5oGw5tPB1J1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWO1e1/btrLzlrawl5/I6e2uM855WE5oGw5tPB1J1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWO1e1%2FbtrLzlrawl5%2FI6e2uM855WE5oGw5tPB1J1%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;623&quot; height=&quot;81&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;81&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더보기 버튼을 누르면 &quot;로딩중&quot; 표시해봅니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;430&quot; data-origin-height=&quot;256&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O93b2/btrLx0OrScG/6futYixKTE1yfHdDbKFCd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O93b2/btrLx0OrScG/6futYixKTE1yfHdDbKFCd0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O93b2/btrLx0OrScG/6futYixKTE1yfHdDbKFCd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO93b2%2FbtrLx0OrScG%2F6futYixKTE1yfHdDbKFCd0%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;430&quot; height=&quot;256&quot; data-origin-width=&quot;430&quot; data-origin-height=&quot;256&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청이 성공 시 로딩 중 UI&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실패 시 로딩 중 UI처리하도록,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 데이터 가져오는 것도 있지만 보내는 것도 있습니다,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;post요청으로 정보를 전달해서 데이터를 보낼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Post요청하는 방법&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;60&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lVPU3/btrLAyQYOWp/I786xGfbdabvgWJW8iIxlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lVPU3/btrLAyQYOWp/I786xGfbdabvgWJW8iIxlK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lVPU3/btrLAyQYOWp/I786xGfbdabvgWJW8iIxlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlVPU3%2FbtrLAyQYOWp%2FI786xGfbdabvgWJW8iIxlK%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;528&quot; height=&quot;60&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;60&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;post 안에 이 '서버URL' 로 id : '아범', pw: 'tiger' 을 전달할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 기본적인 React에서 ajax 요청방법에 대해서 알아보았습니다.&lt;/p&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;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;  ajax는 ajax가 무엇인지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  왜 사용하는지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  GET방식과 Post방식은 어떤 상황에서 사용하는지에 대해서 명확하게 알고계신다면!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 React에서나 제이쿼리나 어느 방면에서도 간단하게 개발하실 수 있을 것같아요!&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;</description>
      <category>Front-end/REACT - Basic</category>
      <category>ajax</category>
      <category>fetch()</category>
      <category>frontend</category>
      <category>Get</category>
      <category>JavaScript</category>
      <category>JSON</category>
      <category>post</category>
      <category>React</category>
      <category>XML</category>
      <category>새로고침없이</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/80</guid>
      <comments>https://thfdl0317.tistory.com/entry/React-Ajax-%EC%9A%94%EC%B2%AD%EB%B0%A9%EB%B2%95%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90#entry80comment</comments>
      <pubDate>Wed, 7 Sep 2022 12:52:15 +0900</pubDate>
    </item>
    <item>
      <title>React의 Lifecycle, useEffect 사용하기</title>
      <link>https://thfdl0317.tistory.com/entry/React%EC%9D%98-Lifecycle-useEffect-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;| &lt;span style=&quot;color: #282828;&quot;&gt;Lifecycle이란&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를들어서 detail페이지있잖아요,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화면에 detail페이지가&amp;nbsp; 보이는 순간 이 때를 페이지에 장착이 된다. 또는 마운트(mount)된다라고도하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트 안에서 state 조작을하면 update되는 과정도 있고,&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;컴포넌트가 쓸모가 없어지는 경우, 이 경우 컴포넌트 제거되는데 이게 unmount 라고한다.&lt;/p&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;mount&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;update&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;unmount&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 라이프사이클을 알고 있다면, 중간중간 내가 코드에 간섭을 하여,&amp;nbsp; 특정코드를 실행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;update될 때 특정 코드 실행할 수 있고, unmount될 때 중간에 코드를 넣어 실행할 수 있다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 function들 안에서 기본적으로 쓸 수 있는 함수, useEffect가 있는데,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이&amp;nbsp;useEffect를 사용해보자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 useEffect의 Effect란&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그래밍할 때쓰는 용어 중에 sideEffect가 있는데,&amp;nbsp;이게 함수의 핵심기능, 부가기능들을 담당하는 얘들이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그거에서 따온 것이라고한다. useEffect에 들어갈 것들은 함수의 핵심기능이 아닌 그 외의 것들이기 때문에&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;pre id=&quot;code_1662518109771&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Detail(props) {

    useEffect(()=&amp;gt;{
     여기에 mount, update시 코드를 넣어 실행시킴 
    });&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재렌더링을 시켜보자. (update 시켜보자)&lt;/p&gt;
&lt;pre id=&quot;code_1662518470864&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Detail(props) {

    const [count, setCount] = useState(0);

    useEffect(()=&amp;gt;{
      console.log('하이')
    });

    return (
        &amp;lt;div className='flex-box'&amp;gt;
          &amp;lt;h1 className='green'&amp;gt;상세페이지&amp;lt;/h1&amp;gt;
          &amp;lt;p&amp;gt;{count}&amp;lt;/p&amp;gt;
          &amp;lt;button onClick={()=&amp;gt;{setCount(count + 1)}}&amp;gt;버튼&amp;lt;/button&amp;gt;
          
        --  뒤 코드 생략생략 --&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼, 화면의 F12를 확인하면 누를 때 마다 업데이트되어 '하이' 가 나오는 것을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이걸 왜 쓰느냐?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;| useEffect을 사용하는 이유&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한마디로 요약한다면 실행시점이 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;랜더링이 다 되고 나서야 실행된다는 것이다( = useEffect안에 있는 코드는 html 렌더링 후에 동작)&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;만약 반복문을 이 detail 안에서 사용하려한다해보자.&lt;/p&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;자바스크립트는 html 이 나중에 보여지게된다.&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;gt; html 을 읽게되는데,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반복문의 실행시간이 1초, 2초걸린다면 그 후에 html이 보이겠지.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데, 이 반복문을 useErrect안에 넣게되면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 더 효율적으로 동작가능하고 유저한테도 더 빠르게 보여줄 수 있다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서버에서 데이터를 가져오는 작업,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어려운 연산이나,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타이머를 장착하거나 할 때 useEffect를 사용한다.&lt;/p&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;그럼, 간단하게 setTimeout()를 사용하여 3초 뒤에 화면에서 사라지는 할인문구를 만들어보도록하자.&lt;/p&gt;
&lt;pre id=&quot;code_1662519876224&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Detail(props) {

    const [alert, setAlert] = useState(true); //UI 상태저장할 state

    useEffect(()=&amp;gt;{
      const timeAlert = setTimeout(()=&amp;gt;{
        setAlert(false)
      }, 3000);
      return ()=&amp;gt;{clearTimeout(timeAlert)}
    }, [alert]);


    const [inputValue, setInputValue] = useState()

    return (
        &amp;lt;div className='flex-box'&amp;gt;
          &amp;lt;h1 className='green'&amp;gt;상세페이지&amp;lt;/h1&amp;gt;
        		
                -- 중간 코드 생략 -- 
        &amp;lt;/div&amp;gt;
            
            {
              alert === true ?&amp;lt;Alert/&amp;gt;:null 
            }
          &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
    )
}


function Alert(){
  return (
    &amp;lt;div className='alert2'&amp;gt;
      &amp;lt;p&amp;gt;30초후 구매시 할인 30%&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;241&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NFTse/btrLDjZYRWW/c7VyXK6Kg8PkbXkBizaU5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NFTse/btrLDjZYRWW/c7VyXK6Kg8PkbXkBizaU5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NFTse/btrLDjZYRWW/c7VyXK6Kg8PkbXkBizaU5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNFTse%2FbtrLDjZYRWW%2Fc7VyXK6Kg8PkbXkBizaU5K%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;612&quot; height=&quot;241&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;241&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;여기는 useEffect의 실행조건을 넣을 수 있는 곳이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;513&quot; data-origin-height=&quot;200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LF4xG/btrLAzhXZcy/oarFyZa5nrrzsgrkSqBrqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LF4xG/btrLAzhXZcy/oarFyZa5nrrzsgrkSqBrqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LF4xG/btrLAzhXZcy/oarFyZa5nrrzsgrkSqBrqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLF4xG%2FbtrLAzhXZcy%2FoarFyZa5nrrzsgrkSqBrqK%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;513&quot; height=&quot;200&quot; data-origin-width=&quot;513&quot; data-origin-height=&quot;200&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 이걸 쓰지않을 때는 컴포넌트가 로드될 때 monut, update시 실행되는데,&amp;nbsp;&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;변화할 때마다 즉, &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;[ ]안에있는 state가 변할 때만 실행된다는 것&lt;/b&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;p data-ke-size=&quot;size16&quot;&gt;또한 useEffect에서 쓸 수 있는 추가 문법이 있는데, 그것은 return.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;336&quot; data-origin-height=&quot;180&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dfa38D/btrLDjeCF95/WZwkuK5KAb7LkZCY1AbjuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dfa38D/btrLDjeCF95/WZwkuK5KAb7LkZCY1AbjuK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dfa38D/btrLDjeCF95/WZwkuK5KAb7LkZCY1AbjuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdfa38D%2FbtrLDjeCF95%2FWZwkuK5KAb7LkZCY1AbjuK%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;336&quot; height=&quot;180&quot; data-origin-width=&quot;336&quot; data-origin-height=&quot;180&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useEffect동작 전에 실행되는 return () =&amp;gt;{ }&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;385&quot; data-origin-height=&quot;178&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vt6T7/btrLzkTcYWx/kzYAgJWvdoCpgucooy2u40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vt6T7/btrLzkTcYWx/kzYAgJWvdoCpgucooy2u40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vt6T7/btrLzkTcYWx/kzYAgJWvdoCpgucooy2u40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvt6T7%2FbtrLzkTcYWx%2FkzYAgJWvdoCpgucooy2u40%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;385&quot; height=&quot;178&quot; data-origin-width=&quot;385&quot; data-origin-height=&quot;178&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;기존 타이머를 제거한 상태에서 내가 필요한 타이머만 장착하여 실행할 수 있기 때문에 clean up function을 이용한다.&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;참고할 점은 clean up function은 mount시 실행되지않고 unmount시 실행된다.&lt;/p&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;  재렌더링마다 코드를 실행하고 싶다?   useEffect(()=&amp;gt;{ })&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  mount시 1회 코드를 실행하고 싶다?   useEffect(()=&amp;gt;{ }, [] )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  unmount시 1회 코드를 싱행하고 싶다?   useEffect(()=&amp;gt;{&amp;nbsp; return () =&amp;gt; { }}, [])&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end/REACT - Basic</category>
      <category>clearTimeout</category>
      <category>JavaScript</category>
      <category>Mount</category>
      <category>React</category>
      <category>setTimeout</category>
      <category>unmount</category>
      <category>useEffect</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/79</guid>
      <comments>https://thfdl0317.tistory.com/entry/React%EC%9D%98-Lifecycle-useEffect-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0#entry79comment</comments>
      <pubDate>Wed, 7 Sep 2022 11:58:18 +0900</pubDate>
    </item>
    <item>
      <title>React Router(리액트 라우터) 사용하기</title>
      <link>https://thfdl0317.tistory.com/entry/React-Router%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%9D%BC%EC%9A%B0%ED%84%B0-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
      <description>&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; ️ 목표1. 리액트 라우터 설치 그리고 셋팅방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; ️ 목표2. 페이지를 이동 작성방법, 버튼 만들기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; ️ 목표3. 라우터 6버전에서는 navigate 함수를 사용하자. 의 방법 정리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; ️ 목표4. nested routes 사용하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;| 라우터 사용1. &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라우터 라이브러리 설치&lt;/p&gt;
&lt;pre id=&quot;code_1662440328020&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install react-router-dom@6&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;|&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;라우터 사용2.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;index.js 파일에 BrowserRouter로 &amp;lt;App /&amp;gt;감싸기&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662440835668&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { BrowserRouter } from &quot;react-router-dom&quot;;


const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  &amp;lt;React.StrictMode&amp;gt;
      &amp;lt;BrowserRouter&amp;gt;
        &amp;lt;App /&amp;gt;
      &amp;lt;/BrowserRouter&amp;gt;
  &amp;lt;/React.StrictMode&amp;gt;
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;| 라우터로 페이지 나누기&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662441222573&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Routes, Route} from 'react-router-dom'

function App(){
  return (
    &amp;lt;Routes&amp;gt;
      &amp;lt;Route path=&quot;/home&quot; element={ &amp;lt;HOME /&amp;gt; } /&amp;gt;
      &amp;lt;Route path=&quot;/detail&quot; element={ &amp;lt;DETAIL /&amp;gt; } /&amp;gt;
    &amp;lt;/Routes&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;&amp;lt;Route path=&quot;/url경로&quot; element={ &amp;lt;이동할 컴포넌트 /&amp;gt; } /&amp;gt;&amp;nbsp; 작성하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;| 페이지 이동 버튼은 'Link to'로&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;각각 url 경로로 이동하는 링크를 생성할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662441674400&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;Link to=&quot;/&quot;&amp;gt;HOME&amp;lt;/Link&amp;gt;
&amp;lt;Link to=&quot;/detail&quot;&amp;gt;DETAIL&amp;lt;/Link&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위처럼&lt;/p&gt;
&lt;pre id=&quot;code_1662442147312&quot; class=&quot;clean&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Routes, Route} from 'react-router-dom'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 Routes와 Route 를 사용하지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것말고도 페이지 이동에관련된 다양하게 import할 수 있는 것들이있다.&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;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;useNavigate()&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662442385059&quot; class=&quot;javascript&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function App(){
  let navigate = useNavigate()
  
  return (
    &amp;lt;button onClick={()=&amp;gt;{ navigate('/detail') }}&amp;gt;detail의 이동버튼&amp;lt;/button&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이지를 이동시켜주는 함수로,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;navigate('/detail') 이런 코드가 실행되면 /detail 페이지로 이동이 가능해집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;navigate() 안에다가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-1 넣으면 뒤로 1번 가기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2 넣으면 앞으로 2번 가기&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;b&gt;nested routes&lt;/b&gt;&lt;span style=&quot;color: #6a9955;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;span style=&quot;color: #6a9955;&quot;&gt;장점1. route작성이 조금 간단해진다.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #6a9955;&quot;&gt;장점2.Nested route 접속시엔 element 2개나 보임&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #6a9955;&quot;&gt;nested routes는 언제쓰는가? 여러 유사한 페이지가 필요할 때 사용한다.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #6a9955;&quot;&gt;App.js&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1662442996336&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;Route path=&quot;/about&quot; element={&amp;lt;About/&amp;gt;} &amp;gt;
     &amp;lt;Route path=&quot;member&quot; element={&amp;lt;div&amp;gt;팀원들&amp;lt;/div&amp;gt;} /&amp;gt;   {/*about/member*/}
     &amp;lt;Route path=&quot;location&quot; element={&amp;lt;div&amp;gt;내위치정보&amp;lt;/div&amp;gt;} /&amp;gt; {/*about/location*/}
&amp;lt;/Route&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;/about/member&lt;/b&gt;로 접속시 &amp;lt;About&amp;gt; &amp;amp;&amp;lt;div&amp;gt;팀원들&amp;lt;/div&amp;gt; 가 보여지고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;/about/location&lt;/b&gt;으로 접속시 &amp;lt;About&amp;gt; &amp;amp; &amp;lt;div&amp;gt;내 위치 정보&amp;lt;/div&amp;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;About.js (컴포넌트)&lt;/p&gt;
&lt;pre id=&quot;code_1662443132651&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function About(){
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;나의 대한 정보&amp;lt;/p&amp;gt;
      &amp;lt;Outlet&amp;gt;&amp;lt;/Outlet&amp;gt;{/* nested routes의 element보여주는 곳&amp;lt;Outlet&amp;gt; */}
    &amp;lt;/div&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Front-end/REACT - Basic</category>
      <category>BrowserRouter</category>
      <category>Link to</category>
      <category>React</category>
      <category>react-router-dom</category>
      <category>Router</category>
      <category>Routes</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/73</guid>
      <comments>https://thfdl0317.tistory.com/entry/React-Router%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%9D%BC%EC%9A%B0%ED%84%B0-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0#entry73comment</comments>
      <pubDate>Tue, 6 Sep 2022 14:47:58 +0900</pubDate>
    </item>
    <item>
      <title>Nodemon으로 자동화하기 그리고 이걸 왜 할까?</title>
      <link>https://thfdl0317.tistory.com/entry/Nodemon%EC%9C%BC%EB%A1%9C-%EC%9E%90%EB%8F%99%ED%99%94%ED%95%98%EA%B8%B0-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EC%9D%B4%EA%B1%B8-%EC%99%9C-%ED%95%A0%EA%B9%8C</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;왜 nodemon을 설치하려하냐면&lt;br /&gt;서버 껐다가 켜는 작업을 자동으로 재실행하게끔하기 위해&lt;br /&gt;(껐다가 켰다가 하는게 너무 시간, 힘이 드니)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자동화를(nodemon)를 하려하는 것!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널을 켜고 나서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f8f9fa; color: #212529;&quot;&gt;| npm&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662383709553&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; npm install -g nodemon&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f8f9fa; color: #212529;&quot;&gt;| yarn&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #e9ecef; color: #212529;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662383740715&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; yarn add global nodemon&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;| 실행 명령어&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;axapta&quot;&gt;&lt;code&gt;nodemon server.js&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;근데, 만약 이렇게 실행 명령어를 입력했는데 &lt;span style=&quot;color: #ee2323;&quot;&gt;빨간 오류가 주루룩 나온다면&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. powerShell 관리자로 실행을 들어가자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;350&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YEtpI/btrLuxENPUq/aalmznlvoJvFvVpbcIBisk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YEtpI/btrLuxENPUq/aalmznlvoJvFvVpbcIBisk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YEtpI/btrLuxENPUq/aalmznlvoJvFvVpbcIBisk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYEtpI%2FbtrLuxENPUq%2FaalmznlvoJvFvVpbcIBisk%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;791&quot; height=&quot;350&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;350&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;1. executionpolicy&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;dsconfig&quot;&gt;&lt;code&gt;2. set-executionpolicy unrestricted&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;3. y 입력하고 엔터&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;4. 다시 vsCode 터미널로 가서 nodemon server.js 명령어 입력&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 또 오류가 난다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 줄이 이것부터 시작해서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;node:events:505 throw er; // Unhandled 'error' event&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;514&quot; data-origin-height=&quot;86&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5RO1Y/btrLuBf6C2e/JsvldyOfHWD5MKrRdGbKCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5RO1Y/btrLuBf6C2e/JsvldyOfHWD5MKrRdGbKCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5RO1Y/btrLuBf6C2e/JsvldyOfHWD5MKrRdGbKCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5RO1Y%2FbtrLuBf6C2e%2FJsvldyOfHWD5MKrRdGbKCk%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;514&quot; height=&quot;86&quot; data-origin-width=&quot;514&quot; data-origin-height=&quot;86&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;이미 로컬에 띄워져있다는건데,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;cmd에서 포트 죽여보려고 했는데 8080은 보이지도 않는다면&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;2-재부팅을-해보기&quot; data-ke-size=&quot;size20&quot;&gt;2 .재부팅을 해보기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;그럼 잘 실행되어집니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Front-end/node.js + mongoDB</category>
      <category>ExecutionPolicy</category>
      <category>frontend</category>
      <category>JavaScript</category>
      <category>Node.js</category>
      <category>nodemon</category>
      <category>nodemon server.js</category>
      <category>npm</category>
      <category>Yarn</category>
      <category>자동화</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/71</guid>
      <comments>https://thfdl0317.tistory.com/entry/Nodemon%EC%9C%BC%EB%A1%9C-%EC%9E%90%EB%8F%99%ED%99%94%ED%95%98%EA%B8%B0-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EC%9D%B4%EA%B1%B8-%EC%99%9C-%ED%95%A0%EA%B9%8C#entry71comment</comments>
      <pubDate>Mon, 5 Sep 2022 22:19:30 +0900</pubDate>
    </item>
    <item>
      <title>node.js + 망고DB</title>
      <link>https://thfdl0317.tistory.com/entry/nodejs-%EB%A7%9D%EA%B3%A0DB</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;node.js + mongoDB를 이용하여 투두리스트를 만드는 것을 목표 진행하기전에&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;&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;목표1.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;node.js는 무엇인지 이해하기&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;목표2.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;node.js로 서버를 만드는 이유는?&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 id=&quot;nodejs란&quot;&gt;node.js란&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;javascript를 브라우저말고도 로컬pc에서도 실행시킬 수 있는 실행환경&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 javascript란 뭐죠?&lt;br /&gt;네, 자바스크립트는 html에 종속된 언어로 웹페이지안에서 바꿔주는 기능을 합니다.&lt;br /&gt;그럼 이 html조작과 변경이 가능한 자바스크립트는 누가 실행시키는지 아십니까?&lt;br /&gt;맞아요, 브라우저예요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요 브라우저가 자바스크립트 해석을 담당하지요.&lt;br /&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;javascript의 해석엔진&lt;/b&gt;들은&lt;br /&gt;크롬   V8&lt;br /&gt;모질라   SpiderMonkey&lt;br /&gt;익스플로우   chakra&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서&lt;br /&gt;자바스트립트 해석빠른 크롬의 V8을&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;node.js&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;node.js는 원래 크롬의 자바스크립트의 해석엔진&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 따로 node.js는&lt;br /&gt;js언어를 꼭 브라우저 내에서 사용하는 것이 아닌, 다른 환경에서도 실행할 수 있게 하기 위해만들어졌습니다.&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;Node.js 덕분에 JavaScript를 프로그래밍 언어처럼 사용하기 시작함(서버도 만들 수 있음)&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;&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;br /&gt;그럼 왜 node.js로 서버를 만들까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그건 바로&lt;span&gt;&amp;nbsp;&lt;/span&gt;Non-blocking I/O&lt;span&gt;&amp;nbsp;&lt;/span&gt;의 장점 때문입니다.&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;일반 서버&lt;span&gt;&amp;nbsp;&lt;/span&gt;vs&lt;span&gt;&amp;nbsp;&lt;/span&gt;node.js로 만든 서버를 비교해봅시다.&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;933&quot; data-origin-height=&quot;199&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IxmZe/btrLufxzj9C/U0baqYanKk01xVopppNuAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IxmZe/btrLufxzj9C/U0baqYanKk01xVopppNuAK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IxmZe/btrLufxzj9C/U0baqYanKk01xVopppNuAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIxmZe%2FbtrLufxzj9C%2FU0baqYanKk01xVopppNuAK%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;933&quot; height=&quot;199&quot; data-origin-width=&quot;933&quot; data-origin-height=&quot;199&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&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;저, 샌드위치 300개 포장&lt;span&gt;&amp;nbsp;&lt;/span&gt;을 요청하면 그 응답대로 걸리는 시간이 많이듭니다.&lt;br /&gt;그럼, 그 50개 포장하는 사람의 다음 사람은 그 걸리는 시간을 같이 기다려야하는 것이고요,&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;706&quot; data-origin-height=&quot;292&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rNkfO/btrLqX5vwHR/K5Ev8LDwiLV1IxPJwQ32Y0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rNkfO/btrLqX5vwHR/K5Ev8LDwiLV1IxPJwQ32Y0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rNkfO/btrLqX5vwHR/K5Ev8LDwiLV1IxPJwQ32Y0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrNkfO%2FbtrLqX5vwHR%2FK5Ev8LDwiLV1IxPJwQ32Y0%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;706&quot; height=&quot;292&quot; data-origin-width=&quot;706&quot; data-origin-height=&quot;292&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중간에 버거운 요청을 만나면, 서버가 다른 요청을 받을 수 없는 단점이 보이지요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이제 노드.js로 만든 서버, 샌드위치가게가 있어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 가게는 요청을 먼저 다 받습니다.&lt;br /&gt;그 후 처리하는 것이 빠른 것부터 응답해주고 어려운 작업들은 나중에 처리하게하죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 바로 Node.js의 non-blocking i/o특징입니다.&lt;/p&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;요즘은 SNS, 채팅서비스개발을 많이하는데 이 특징은 서버가 몇 십만개의 요청을 처리할 수 있어야합니다. 이 몇십만건의 데이터요청을 처리해야하는데, 그럴려면 전통적인 서버인 경우에 서버가 멈출 수 있으나,&lt;br /&gt;node.js의 경우에는 무거운 요청, 오래걸리는 요청이 있어도 멈추거나 요청 대기시간이 없다는 장점이 있다는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 사실 이런 SNS,채팅 서비스 작업을 꼭 node.js만 할 수 있다는 것은 아닙니다.&lt;br /&gt;서버 스케일링 or 멀티 쓰레딩으로 동시응답처리를 할 수 있어요.&lt;/p&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;논블로킹 덕분에 채팅/SNS에 요즘 자주 이 node.js를 쓴다하며&lt;br /&gt;또 다른 강점은 몇줄만 입력하면 비교적 쉽게 개발할 수 있는 다는 것입니다. (코드가 매우 짧고 쉬움)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 node.js는&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빠르게 시범을 보여야할 때도 특히 프로토타입을 만들기에도 좋습니다.&lt;/li&gt;
&lt;li&gt;자바스크립트 문법만으로 프론트와 백엔드를 전부 할 수 있다는 것과&lt;/li&gt;
&lt;li&gt;비교적 코드들이 짧기 때문에 초보단계에서 쉽게 접할 수 있으며,&lt;/li&gt;
&lt;li&gt;갑자기 유저의 대량 요청이 들어와도 서버가 꼴까닥 죽지않고 감당가능하지요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이렇게 다양한 장점을 가지고 있는 node.js.&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;&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;lt; 오늘의 기억거리 &amp;gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  목표1.&lt;span&gt;&amp;nbsp;&lt;/span&gt;node.js는 무엇인지 이해하기&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;   자바스크립트를 브라우저 없이 사용할 수 있는 실행창, 실행환경이며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;원래 각 크롬안의 자바스크립트 해석엔진(V8)이었으나 해석능력이 출중하여&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;따로 똑 떼어서 만들어낸 v8의 진화버전&lt;/p&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;  목표2.&lt;span&gt;&amp;nbsp;&lt;/span&gt;node.js로 서버를 만드는 이유는?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;node.js는 무거운 요청, 오래걸리는 요청이 있어도 멈추거나&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 요청 대기시간이 없다는 장점과 몇줄만 입력하면 비교적 쉽게 개발할 수 있다. (코드가 매우 짧고 쉬움)&lt;/p&gt;</description>
      <category>Front-end/node.js + mongoDB</category>
      <category>frontend</category>
      <category>JavaScript</category>
      <category>JS</category>
      <category>MongoDB</category>
      <category>Node.js</category>
      <category>non-blocking</category>
      <category>sever</category>
      <category>일반서버</category>
      <category>자바스크립트</category>
      <category>프론트엔드</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/70</guid>
      <comments>https://thfdl0317.tistory.com/entry/nodejs-%EB%A7%9D%EA%B3%A0DB#entry70comment</comments>
      <pubDate>Mon, 5 Sep 2022 21:18:46 +0900</pubDate>
    </item>
    <item>
      <title>Spring Boot 를 배우기 전 알아야 할 개념 정리 1탄</title>
      <link>https://thfdl0317.tistory.com/entry/Spring-Boot-%EB%A5%BC-%EB%B0%B0%EC%9A%B0%EA%B8%B0-%EC%A0%84-%EC%95%8C%EC%95%84%EC%95%BC-%ED%95%A0-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC-1%ED%83%84</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Boot를 사용하여 개발을 하려할 때 기본적으로 알고있어야하는 Spring의 핵심들,&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;spring boot를 사용하기 전에 알아야할 것은 spring FrameWork.&lt;/p&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링이란1?&lt;/b&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #6164c6;&quot;&gt;&lt;u&gt;스프링은 &lt;b&gt;FrameWork다.&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;FrameWork란?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;말 그대로 직역해본다. 그 말 그대로다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Frame : 틀 + Work : 동작하다 = 틀 안에서 동작한다는 것&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;449&quot; data-origin-height=&quot;331&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bI1geW/btruTiYSQLo/IXMRMTSc0T1qq5zqadoEHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bI1geW/btruTiYSQLo/IXMRMTSc0T1qq5zqadoEHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bI1geW/btruTiYSQLo/IXMRMTSc0T1qq5zqadoEHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbI1geW%2FbtruTiYSQLo%2FIXMRMTSc0T1qq5zqadoEHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;449&quot; height=&quot;331&quot; data-origin-width=&quot;449&quot; data-origin-height=&quot;331&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 틀을 벗어날 수 없는, 너는 이 틀 안에서 개발해. 이게 프레임워크입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링이란2?&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #6164c6;&quot;&gt;&lt;u&gt;스프링은 &lt;b&gt;오픈소스&lt;/b&gt;이다.&lt;/u&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오픈소스는 소스코드가 공개되어있다는 것, 그말은? =&amp;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;불편한 부분은 고쳐서 새롭게 설정할 수 있지요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링이란3?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스프링은&lt;span&gt; IOC컨테이너를 가진다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IOC란?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Inversion of controll : 이것도 직역해보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Inversion&lt;span&gt; 역전 +of ~의+ controll 제어 = 제어의 역전.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;제어의 역전이라... 이말은&lt;/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;&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;class, object, Instance가 있지요?&lt;/p&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;오브젝트를 직접 new라해서 heap이란 메모리공간에 올리게되면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;817&quot; data-origin-height=&quot;418&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWqYMS/btruWkuWyrE/xLakS8ltwRqpdtWibE0Kn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWqYMS/btruWkuWyrE/xLakS8ltwRqpdtWibE0Kn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWqYMS/btruWkuWyrE/xLakS8ltwRqpdtWibE0Kn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWqYMS%2FbtruWkuWyrE%2FxLakS8ltwRqpdtWibE0Kn1%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;817&quot; height=&quot;418&quot; data-origin-width=&quot;817&quot; data-origin-height=&quot;418&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책상 t = new 책상();&amp;nbsp; new 했기에 실체화가 되는 것이고 (책상을) 그럼 이 주소를 t가 들고 있고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 t는 매서드가 실행되는 순간에만 떠있어서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 메서드에서 책상을 사용하고 싶다면 그 다른 매서드 안에 책상&amp;nbsp; t = new 책상();을 한다?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 새로 만든 매서드 안에 넣은 t가 위 그림의 t와 같을까? 아닙니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;871&quot; data-origin-height=&quot;475&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvpM5K/btruRL78B6u/KElANkcGBdOTVzxaHHL330/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvpM5K/btruRL78B6u/KElANkcGBdOTVzxaHHL330/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvpM5K/btruRL78B6u/KElANkcGBdOTVzxaHHL330/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvpM5K%2FbtruRL78B6u%2FKElANkcGBdOTVzxaHHL330%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;871&quot; height=&quot;475&quot; data-origin-width=&quot;871&quot; data-origin-height=&quot;475&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공유하는 것이 힘들죠, 나는 여기이 새로운 메소드에서도 쓰고 싶은데,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 스프링은 이렇게 해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 오브젝트들 ex) 사슴, 토끼.. 사자 이것을 클래스로 만들어놓고 -&amp;gt; 스프링이 다 읽고 파악해서 직접 스프링이 heap 메모리 안에 띄웁니다. 그럼, 스프링이 이 여러 클래스들을 읽어서 내보내줍니다. heap 메모리 안에 다 띄어줌으로 공유가 될 수 있게 스프링에 만들어 준 것. (IoC덕에 스프링이 내가 만든 인스턴스들을 옮겨서 올려준 것)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;스프링이란3?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;u&gt;&lt;span style=&quot;color: #6164c6;&quot;&gt;스프링은 DI 지원한다.&lt;/span&gt;&lt;/u&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dependeny Injection를 말하는 것인데 이 뜻은 '의존성 주입'이란 뜻입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 내가 new를 해서 객체의 주소를 개발자가 관리를 했다면 이제는 spring이 파악해서 메모리에 띄웠기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;spring이 이제 관리를 하게됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼, 이제 내가 원하는 모든 곳에서 모든 클래스의 메소드에서 heap메모리에 만든 클래스들을 가져와서 사용할 수 있게되는 겁니다.&amp;nbsp; 위의 그림과 같이 t 가 다른 것이아니라 같은 것이 된다는 뜻이죠. 공유를 할 수 있는 것. 그게 Dependeny Injection이라고 합니다.&lt;/p&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;spring의 개념 파파팍~ &lt;/p&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;</description>
      <category>Back-end/Spring Boot</category>
      <category>di</category>
      <category>Framework</category>
      <category>IOC</category>
      <category>spring boot</category>
      <category>백엔드 개발자</category>
      <category>스프링의 핵심</category>
      <category>의존성 주입</category>
      <category>프레임워크</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/67</guid>
      <comments>https://thfdl0317.tistory.com/entry/Spring-Boot-%EB%A5%BC-%EB%B0%B0%EC%9A%B0%EA%B8%B0-%EC%A0%84-%EC%95%8C%EC%95%84%EC%95%BC-%ED%95%A0-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC-1%ED%83%84#entry67comment</comments>
      <pubDate>Thu, 3 Mar 2022 06:16:52 +0900</pubDate>
    </item>
    <item>
      <title>SpringBoot기반으로 Security 개발(자세히 파해쳐보자)_3</title>
      <link>https://thfdl0317.tistory.com/entry/SpringBoot%EA%B8%B0%EB%B0%98%EC%9C%BC%EB%A1%9C-Security-%EA%B0%9C%EB%B0%9C%EC%9E%90%EC%84%B8%ED%9E%88-%ED%8C%8C%ED%95%B4%EC%B3%90%EB%B3%B4%EC%9E%903</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;✊ 학습목표&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&amp;nbsp;1) 동시 세션 제어, 세션 고정 보호, 세션 정책&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&amp;nbsp;2) 세션 제어 필터 - SessionManagementFilter, ConcurrentSessionFilter&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;&amp;nbsp;3) &lt;span data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;권한설정과 표현식&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;span data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;1) 동시 세션 제어, 세션 고정 보호, 세션 정책&lt;/span&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;사용자1이 로그인하여 서버에 접속하면 세션 생성된 것임&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자2가 동일한 계정으로 로그인한다. 세션2개 생성&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;이전 사용자의 세션 만료를 설정시키는 것이다.&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껀 사용되게 되며 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;사용자1 서버 접속해 세션 생성,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자2 서버 접속 시 인증에 성공못하고 세션이 생성되지 못하도록 차단시키는 전략으로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최대 세션 허용 개수를 초과안하게 1개만 유지하게하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;http.sessionManagement():세션 관리 기능이 작동함&lt;/p&gt;
&lt;pre id=&quot;code_1645457886117&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;protected void configure(HttpSecurity http) throws Exception{
	http.sessionMnagement()
		.maximumSessions(1)             //최대 허용 가능 세션 수, -1 : 무제한 로그인 세션 허용
		.maxSessionsPreventsLogin(ture) //동시 로그인 차단함, false: 기존 세션 만료(default)
		.invalidSessionUrl(&quot;/invalid&quot;)  //세션이 유효하지 않을 때 이동할 페이지
		.expiredUrl(&quot;/expired&quot;)         //세션이 만료된 경우 이동할 페이지
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1645457931419&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
	
	@Autowired
	UserDetailsService userDetailsService;

	protected void configure(HttpSecurity http, UserDetailsService userDetailsService) throws Exception {
		http
		.authorizeRequests()
		.anyRequest().authenticated();
		
		http
		.formLogin();
		
		http
			.sessionManagement()
			.maximumSessions(1)
			.maxSessionsPreventsLogin(true); //세션으 초과됐을 때 로그인을 아예 못하게하는 전략
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;| 세션 고정 보호&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자, 공격자, webApp가 있다고 치자&lt;/p&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에 접속하여 쿠키를 발급해주는 webapp,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 공격자는 자신이 발급받은 쿠키를 사용자에게 심어놓고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자는 가지고 있게된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 사용자는 공격자가 심어놓은 쿠키를 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 인증을받을 때 그 쿠키로 접근을 하고 그 쿠키에 해당하는 세션은 인증받은 상태이기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자나 공격자가 서버에 접근하게 되면 둘이 서버를 사용하게되는 일이 벌어지게된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공격자 쿠키 값으로 인증되어 버리기 때문에 공격자는 사용자 정보를 공유하게 된다는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세션 고정 공격이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 방지하기 위해 시큐리티는 세션고정보호의 기능을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 비록 공격자가 심어놓은 쿠키로 시도하더라도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인증할 때마다 새로운 세션이 생성되면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 쿠키도 생성되어서 공격자는 사용자의 정보를 공유할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 어떻게 제공이 되는 지 살펴보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;http.sessionManagement() : 세션 관리 기능이 작동함&lt;/p&gt;
&lt;pre id=&quot;code_1645458080875&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;protected void configure(HttpSecurity http) throws Exception{
		http.sessionManagement()
			.sessionRixation().changeSessionId() //기본값, non, migrateSession, new Session
    
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.sessionRixation().changeSessionId() &amp;rarr; 기본값이면 세션아이디만 변경된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;migrateSession : 새로운 세션발급, 세션고정보호&lt;/li&gt;
&lt;li&gt;new Session : 새션에서 설정한 여러가지 속성의 값들을 사용못하고 새로 생성하는 것&lt;/li&gt;
&lt;li&gt;none : 공격그대로 당하게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;292&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NPmbK/btrtYWad7K8/V2FxM0ooLVbdQU3ieuTWx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NPmbK/btrtYWad7K8/V2FxM0ooLVbdQU3ieuTWx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NPmbK/btrtYWad7K8/V2FxM0ooLVbdQU3ieuTWx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNPmbK%2FbtrtYWad7K8%2FV2FxM0ooLVbdQU3ieuTWx1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;505&quot; height=&quot;227&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;292&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;| 인증 API - 세션 정책&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;http.sessionManagement() : 세션 관리 기능이 작동함&lt;/p&gt;
&lt;pre id=&quot;code_1645458169413&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;protected void configure(HttpSecurity http) throws Exception{
	http.sessionManagement()
			.sessionCreationPolicy(SessionCreationPoliy.If_Required)
}

SessioncreationPolicy.Always : 스프링 시큐리티가 항상 세션 생성
SessionCreationPolicy.If_Required : 스프링 시큐리티가 필요시 생성(기본값)
SessionCreationPolicy.Never : 스프링 시큐리티가 생성하지 않지만 이미 존재하면 사용
SessionCreationPolicy.Stateless : 스프링 시큐리티가 생성하지 않고 존재해도 사용하지 않음&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;span data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;2) &lt;span data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;세션 제어 필터 : SessionManagementFilter, ConcurrentSessionFilter&lt;/span&gt;&lt;/span&gt;&lt;/h1&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;| 인증 API - SessionManagementFilter&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;세션 관리 - 인증 시 사용자의 세션 정보를 등록, 조회, 삭제 등의 세션 이력을 관리&lt;/li&gt;
&lt;li&gt;동시적 세션 제어 - 동일 계정으로 접속이 허용되는 최대 세션수를 제한&lt;/li&gt;
&lt;li&gt;세션 고정 보호 - 인증할 때마다 세션 쿠키를 새로 발급하여 공격자의 쿠키 조작을 방지&lt;/li&gt;
&lt;li&gt;세션 생성 정책 - Always, If_Required, Never, Stateless&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;| 인증 API - concurrentSessionFilter&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동시적 세션제어에 관여하는 &lt;b&gt;ConcurrentSessionFilter&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;매 요청 마다 현재 사용자의 세션 만료 여부 체크&lt;/li&gt;
&lt;li&gt;세션이 만료되었을 경우 즉시 만료 처리&lt;/li&gt;
&lt;li&gt;Session.isExpired() == true
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로그아웃 처리&lt;/li&gt;
&lt;li&gt;즉시 오류 페이지 응답 &amp;ldquo;This session has been expired&amp;rdquo;&amp;nbsp;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1459&quot; data-origin-height=&quot;1002&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baQM8k/btrtOzgcdWy/d6K63aKQA0pnF4Gdgh8OTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baQM8k/btrtOzgcdWy/d6K63aKQA0pnF4Gdgh8OTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baQM8k/btrtOzgcdWy/d6K63aKQA0pnF4Gdgh8OTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaQM8k%2FbtrtOzgcdWy%2Fd6K63aKQA0pnF4Gdgh8OTK%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;520&quot; height=&quot;357&quot; data-origin-width=&quot;1459&quot; data-origin-height=&quot;1002&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&lt;span data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;3)&amp;nbsp;&lt;span data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;&lt;span data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;권한설정과 표현식&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h1&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;| 인가 API - 권한 설정&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선언적 방식 과 동적인 방식이 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;선언적 방식
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;URL
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;http.antMatchers(&amp;rdquo;/users/**&amp;rdquo;).hasRole(&amp;rdquo;USER&amp;rdquo;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Method
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@PreAuthorize(&amp;rdquo;hasRole(&amp;rsquo;USER&amp;rsquo;)&amp;rdquo;)&lt;/li&gt;
&lt;li&gt;public void user() {System.out.println(&amp;rdquo;user&amp;rdquo;)}&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동적 방식 - DB 연동 프로그래밍
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;url&lt;/li&gt;
&lt;li&gt;Method&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;authenticated() : 인증된 사용자의 접근을 허용&lt;/li&gt;
&lt;li&gt;fullyAuthenticated() : 인증된 사용자의 접근을 허용, rememeber Me 인증 제외&lt;/li&gt;
&lt;li&gt;permitAll() :무조건 겁근 허용&lt;/li&gt;
&lt;li&gt;denyAll() : 무조건 접근을 허용하지 않음&lt;/li&gt;
&lt;li&gt;anonymous() : 익명사용자의 접근을 허용&lt;/li&gt;
&lt;li&gt;rememberMe() : 기억하기를 통해 인증된 사용자의 접근을 허용&lt;/li&gt;
&lt;li&gt;access(String) : 주어진 SpEL표현식의 평가 결과가 true이면 접근을 허용&lt;/li&gt;
&lt;li&gt;hasRole(String) 사용자가 주어진역할이 있다면 접근을 허용&lt;/li&gt;
&lt;li&gt;hasAuthority(String) : 사용자가 주어진 권한이 있다면&lt;/li&gt;
&lt;li&gt;hasAnyRole(String...) : 사용자가 주어진 권한이 있다면 접근을 허용&lt;/li&gt;
&lt;li&gt;hasAnyAuthority(String...) : 사용자가 주어진 권한 중 어떤 것이라도 있다면 접근을 허용&lt;/li&gt;
&lt;li&gt;haslpAddress(String) : 주어진 IP로부터 요청이 왔다면 접근을 허용&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1645458914772&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
	
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.inMemoryAuthentication().withUser(&quot;user&quot;).password(&quot;{noop}1111&quot;).roles(&quot;USER&quot;);
		auth.inMemoryAuthentication().withUser(&quot;sys&quot;).password(&quot;{noop}1111&quot;).roles(&quot;SYS&quot;, &quot;USER&quot;);
		auth.inMemoryAuthentication().withUser(&quot;admin&quot;).password(&quot;{noop}1111&quot;).roles(&quot;ADMIN&quot;, &quot;SYS&quot;, &quot;USER&quot;);
		
	}
	
	protected void configure(HttpSecurity http) throws Exception{
		http
		.authorizeHttpRequests()
		.antMatchers(&quot;/user&quot;).hasRole(&quot;USER&quot;)
		.antMatchers(&quot;/admin/pay&quot;).hasRole(&quot;ADMIN&quot;)
		//.antMatchers(&quot;/admin/**&quot;).access(&quot;hasRole('ADMIN')or hasRole('SYS')&quot;)
		.anyRequest().authenticated();
		
		http
		.formLogin();
		}
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;controller&lt;/p&gt;
&lt;pre id=&quot;code_1645458956322&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package com.sole.security;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class securityController {

	@GetMapping(&quot;/&quot;)
	public String index() {
		return &quot;home&quot;;
	}
	
	//@GetMapping(&quot;loginPage&quot;)
	//public String loginPage() {
	//	return &quot;loginPage&quot;;
	//}
	
	@GetMapping(&quot;/user&quot;)
	public String user() {
		return &quot;user&quot;;
	}
	
	@GetMapping(&quot;/admin/Pay&quot;)
	public String adminPay() {
		return &quot;adminPay&quot;;
	}
	
	@GetMapping(&quot;/admin/**&quot;)
	public String admin() {
		return &quot;admin&quot;;
	}
	
	
	
	
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;[참고 강의] 인프런 -&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555;&quot;&gt;스프링 시큐리티 - Spring Boot 기반으로 개발하는 Spring Security&lt;/span&gt;&lt;/p&gt;</description>
      <category>Back-end/Spring Boot Security</category>
      <category>ConcurrentSessionFilter</category>
      <category>It</category>
      <category>Remember Me 인증 필터</category>
      <category>sessionManagement()</category>
      <category>SessionManagementFilter</category>
      <category>Spring Security</category>
      <category>동시 세션 제어</category>
      <category>세션 고정 보호</category>
      <category>세션 정책</category>
      <category>익명사용자 인증 필터</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/64</guid>
      <comments>https://thfdl0317.tistory.com/entry/SpringBoot%EA%B8%B0%EB%B0%98%EC%9C%BC%EB%A1%9C-Security-%EA%B0%9C%EB%B0%9C%EC%9E%90%EC%84%B8%ED%9E%88-%ED%8C%8C%ED%95%B4%EC%B3%90%EB%B3%B4%EC%9E%903#entry64comment</comments>
      <pubDate>Tue, 22 Feb 2022 00:57:48 +0900</pubDate>
    </item>
    <item>
      <title>SpringBoot기반으로 Security 개발(자세히 파해쳐보자)_2</title>
      <link>https://thfdl0317.tistory.com/entry/SpringBoot%EA%B8%B0%EB%B0%98%EC%9C%BC%EB%A1%9C-Security-%EA%B0%9C%EB%B0%9C1-1</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;✊ 학습목표&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&amp;nbsp;1) &lt;span data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;UsernamePasswordAuthenticationFilter 알아보기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&amp;nbsp;2) &lt;span data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;LogoutFilter 알아보기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;&amp;nbsp;3) &lt;span data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;Remember Me 인증&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;&amp;nbsp;4) RememberMeAuthenticationFilter&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;&amp;nbsp;5) &lt;span data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;AnonymousAuthenticationFilter - 인증 사용자필터 알아보기&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;1) &lt;span data-token-index=&quot;1&quot; data-reactroot=&quot;&quot;&gt;Form Login 인증 필터 : UsernamePasswordAuthenticationFilter&lt;/span&gt;&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1328&quot; data-origin-height=&quot;1017&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgr4rv/btrtOyVUh4j/cVzgLKakLQMUAPP6vKQXBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgr4rv/btrtOyVUh4j/cVzgLKakLQMUAPP6vKQXBk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgr4rv/btrtOyVUh4j/cVzgLKakLQMUAPP6vKQXBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbgr4rv%2FbtrtOyVUh4j%2FcVzgLKakLQMUAPP6vKQXBk%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;572&quot; height=&quot;438&quot; data-origin-width=&quot;1328&quot; data-origin-height=&quot;1017&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;h1&gt;&lt;span data-token-index=&quot;1&quot; data-reactroot=&quot;&quot;&gt;&lt;span data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;2) Logout 처리, LogoutFilter&lt;/span&gt;&lt;/span&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;세션 무효화, 인증토큰삭제, 쿠키정보 삭제, 로그인 페이지로 다이렉트로간다.&lt;/p&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.logout() : 로그아웃 기능이 작동함&lt;/p&gt;
&lt;pre id=&quot;code_1645454779633&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;protected void configure(HttpSecurity http) throws Exception{
		http.logout()                                     //로그아웃 처리
		.logoutUrl(&quot;/logout&quot;)                           //로그아웃 처리 URL
		.logoutSuccessUrl(&quot;/login&quot;)                     //로그아웃 성공 후 이동페이지
		.deleteCookes(&quot;JSESSIONID&quot;, &quot;remember-me&quot;)      //로그아웃 쿠키삭제
		.addLogoutHandler(logoutHandler())              //로그아웃 핸들러
		.logoutSuccessHandler(logoutSuccessHandler())   //로그아웃 성공 후 핸들러
	
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직접 작성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SecurityConfig&lt;/p&gt;
&lt;pre id=&quot;code_1645455053769&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
		.authorizeRequests()
		.anyRequest().authenticated();
		
		http
		.formLogin();
		
		http
		.logout()
		.logoutUrl(&quot;/logout&quot;)
		.logoutSuccessUrl(&quot;/login&quot;)
		.addLogoutHandler(new LogoutHandler() {
			
			@Override
			public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
				HttpSession session = request.getSession();
				session.invalidate();
			}
		})
		.logoutSuccessHandler(new LogoutSuccessHandler() {
			
			@Override
			public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
					throws IOException, ServletException {
				response.sendRedirect(&quot;/login&quot;);
				
			}
		})
		
		.deleteCookies(&quot;remember-me&quot;);
		
	}
	
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1063&quot; data-origin-height=&quot;245&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnL1sY/btrtOzUK5QE/lUVixGBKDbQpWANSXAEXck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnL1sY/btrtOzUK5QE/lUVixGBKDbQpWANSXAEXck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnL1sY/btrtOzUK5QE/lUVixGBKDbQpWANSXAEXck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnL1sY%2FbtrtOzUK5QE%2FlUVixGBKDbQpWANSXAEXck%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;492&quot; height=&quot;114&quot; data-origin-width=&quot;1063&quot; data-origin-height=&quot;245&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;1012&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQT1eD/btrtYVWHavJ/4IUm7RZo00QAnXy5Asoso1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQT1eD/btrtYVWHavJ/4IUm7RZo00QAnXy5Asoso1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQT1eD/btrtYVWHavJ/4IUm7RZo00QAnXy5Asoso1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQT1eD%2FbtrtYVWHavJ%2F4IUm7RZo00QAnXy5Asoso1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;658&quot; height=&quot;489&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;1012&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;3) &lt;span data-token-index=&quot;1&quot; data-reactroot=&quot;&quot;&gt;Remember Me 인증&lt;/span&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;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버에서 Remember Me 인증을 게속 사용할 수 있도록 쿠키를 발급 &amp;rarr; 우리는 계속 접근 할 수 있는 것이다.&lt;/li&gt;
&lt;li&gt;(세션이 만료되고 웹 브라우저가 종료된 후에도 어플리케이션이 사용자를 기억하는 기능)&lt;/li&gt;
&lt;li&gt;Remember-Me 쿠키에 대한 Http요청을 확인한 후 토큰 기반인증을 사용해 유효성을 검사하고 토큰이 검증되면 사용자는 로그인 된다.&lt;/li&gt;
&lt;li&gt;사용자 라이프 사이클
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인증성공 (Remember-Me 쿠키 설정)&lt;/li&gt;
&lt;li&gt;인증실패 (쿠키가 존재하면쿠키 무효화)&lt;/li&gt;
&lt;li&gt;로그아웃 (로크아웃 존재하면 쿠키 무효화)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;http.remeberMe() : rememberMe 기능이 작동함&lt;/p&gt;
&lt;pre id=&quot;code_1645455141240&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;protected void configure(HttpSecurtiy http) throws Exception{
	http.rememberMe()
		.rememberMeParameter(&quot;remember&quot;) //기본 파라미터명은 remember-me
		.tokenValiditySeconds(3600)      // Default는 14일
		.alwaysRemember(true)            //리멤버 미 기능이 활성화 되지 않아도 항상 실행
		.userDetailsService(userDetailsService)
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1645453959946&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
	
	@Autowired
	UserDetailsService userDetailsService;

	protected void configure(HttpSecurity http, UserDetailsService userDetailsService) throws Exception {
		http
		.authorizeRequests()
		.anyRequest().authenticated();
		
		http
		.formLogin();
		
		http
		.logout()
		.logoutUrl(&quot;/logout&quot;)
		.logoutSuccessUrl(&quot;/login&quot;)
		.addLogoutHandler(new LogoutHandler() {
			
			@Override
			public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
				HttpSession session = request.getSession();
				session.invalidate();
			}
		})
		.logoutSuccessHandler(new LogoutSuccessHandler() {
			
			@Override
			public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
					throws IOException, ServletException {
				response.sendRedirect(&quot;/login&quot;);
				
			}
		})
		.and()
		.rememberMe()
		.rememberMeParameter(&quot;remeber&quot;)
		.tokenValiditySeconds(3600)
		.userDetailsService(userDetailsService);
		
	}
	
}&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;4)&lt;span data-token-index=&quot;1&quot; data-reactroot=&quot;&quot;&gt;Remember Me 인증 필터 : RememberMeAuthenticationFilter&lt;/span&gt;&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1392&quot; data-origin-height=&quot;1017&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbhPtG/btrtVoFxWX4/KwBqbC6C4QAduZibiKrKjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbhPtG/btrtVoFxWX4/KwBqbC6C4QAduZibiKrKjk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbhPtG/btrtVoFxWX4/KwBqbC6C4QAduZibiKrKjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbhPtG%2FbtrtVoFxWX4%2FKwBqbC6C4QAduZibiKrKjk%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;525&quot; height=&quot;384&quot; data-origin-width=&quot;1392&quot; data-origin-height=&quot;1017&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;h1&gt;&lt;span data-token-index=&quot;1&quot; data-reactroot=&quot;&quot;&gt;&lt;span data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;5) 익명사용자 인증 필터 : AnonymousAuthenticationFilter&lt;/span&gt;&lt;/span&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;rarr; 사용자가 어떤 자원에 접근하려할 시 세션에서 유저객체가 존재? 아님? 하는 것 중 null이면 그 자원에 접근 못하게,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아닐 시 접근 가능하도록 구분하는처리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인증객체가 있는지 Authentiation에서 유무를 확인&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;익명 사용자 인증 처리 필터&lt;/li&gt;
&lt;li&gt;익명 사용자와 인증 사용자를 구분해서 처리하기 위한 용도로 사용&lt;/li&gt;
&lt;li&gt;화면에서 인증 여부를 구현할 때 isAnonymous()와 isAuthenticated()로 구분해서 사용&lt;/li&gt;
&lt;li&gt;인증객체를 세션에 저장하지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;span style=&quot;background-color: #ffffff;&quot;&gt;스프링 시큐리티 - Spring Boot 기반으로 개발하는 Spring Security&lt;/span&gt;&lt;/p&gt;</description>
      <category>Back-end/Spring Boot Security</category>
      <category>It</category>
      <category>security</category>
      <category>spring</category>
      <category>spring boot</category>
      <category>백엔드</category>
      <category>스프링 시큐리티</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/63</guid>
      <comments>https://thfdl0317.tistory.com/entry/SpringBoot%EA%B8%B0%EB%B0%98%EC%9C%BC%EB%A1%9C-Security-%EA%B0%9C%EB%B0%9C1-1#entry63comment</comments>
      <pubDate>Mon, 21 Feb 2022 23:46:40 +0900</pubDate>
    </item>
    <item>
      <title>SpringBoot기반으로 Security 개발(자세히 파해쳐보자)_1</title>
      <link>https://thfdl0317.tistory.com/entry/SpringBoot%EA%B8%B0%EB%B0%98%EC%9C%BC%EB%A1%9C-Security-%EA%B0%9C%EB%B0%9C1</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;스프링시큐리티를 공부하다가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 API를 사용하는지, 모르는 코드구문도 하나씩 나오고,&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;목표는 스프링 부트를 이용해 개발하는 시큐리티를 더 자세히 파해져보기!이다.&lt;/p&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;size18&quot;&gt;&lt;b&gt;&amp;nbsp;1) 프로젝트 구성 및 의존성 추가&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&amp;nbsp;2) 사용자 정의보안 기능 구현&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;&amp;nbsp;3) Form Login 인증&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;1) 프로젝트 구성 및 의존성 추가&lt;/h1&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로젝트 생성&lt;/li&gt;
&lt;li&gt;의존성 주입
&lt;pre id=&quot;code_1645454641601&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- 주입 시 보안설정 작동 --&amp;gt;
		&amp;lt;dependency&amp;gt;
			&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
			&amp;lt;artifactId&amp;gt;spring-boot-starter-security&amp;lt;/artifactId&amp;gt;
		&amp;lt;/dependency&amp;gt;​&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&amp;nbsp;내용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스프링 시큐리티 의존성 추가 시 일어나는 일들&lt;/li&gt;
&lt;li&gt;서버가 기동되면 스프링 시큐리티의 초기화 작업 및 보안 설정이 이루어진다&lt;/li&gt;
&lt;li&gt;별도의 설정이나 구현을 안해도 기본적인 웹 보안 기능이 현재 시스템에 연동되어 작동함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인증 방식은 폼 로그인 방식과 httpBasic 로그인 방식을 제공함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;2) 사용자 정의보안 기능 구현&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;추가, 변경 기능도 없음&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;인증 API - 사용자 정의 보안 기능 구현&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1520&quot; data-origin-height=&quot;692&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C3PxV/btrtOzHhedd/KKCK1GwdwuxDIdamPmKHzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C3PxV/btrtOzHhedd/KKCK1GwdwuxDIdamPmKHzK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C3PxV/btrtOzHhedd/KKCK1GwdwuxDIdamPmKHzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC3PxV%2FbtrtOzHhedd%2FKKCK1GwdwuxDIdamPmKHzK%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;1520&quot; height=&quot;692&quot; data-origin-width=&quot;1520&quot; data-origin-height=&quot;692&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;WebSecurtiyConfigurerAdapter 안에 있는 메소드 중에서 HttpSecurity http를 파라미터로 전달받는 오버라이딩을 하고 그 안에 보안기능들을 설정할 것이다.
&lt;pre id=&quot;code_1645453959946&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package com.sole.security.config;

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
		.authorizeRequests()
		.anyRequest().authenticated()
		.and()
		.formLogin();
	}
}​&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1645454053978&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring.security.user.name=user
spring.security.user.password=1111​&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;3) &lt;b&gt;Form Login 인증&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;http.formLogin() : Form 로그인 인증 기능이 작동함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SecurityConfig&lt;/p&gt;
&lt;pre id=&quot;code_1645454316770&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
		.authorizeRequests()
		.anyRequest().authenticated();
		http
		.formLogin()
		.loginPage(&quot;/loginPage&quot;)
		.defaultSuccessUrl(&quot;/&quot;)
		.failureUrl(&quot;/loginPage&quot;)
		.usernameParameter(&quot;userId&quot;)
		.passwordParameter(&quot;passwd&quot;)
		.loginProcessingUrl(&quot;/login_proc&quot;)
		.successHandler(new AuthenticationSuccessHandler() {
			
			@Override
			public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
					Authentication authentication) throws IOException, ServletException {
				System.out.println(&quot;authentication&quot;+ authentication.getName());
				response.sendRedirect(&quot;/&quot;);
			}
		})
		.failureHandler(new AuthenticationFailureHandler() {
			
			@Override
			public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
					org.springframework.security.core.AuthenticationException exception) throws IOException, ServletException {

				System.out.println(&quot;excception&quot;+ exception.getMessage());
				response.sendRedirect(&quot;/login&quot;);
			}
		}).permitAll();
	}
	
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Contorller&lt;/p&gt;
&lt;pre id=&quot;code_1645454358833&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package com.sole.security;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class securityController {

	@GetMapping(&quot;/&quot;)
	public String index() {
		return &quot;home&quot;;
	}
	
	@GetMapping(&quot;loginPage&quot;)
	public String loginPage() {
		return &quot;loginPage&quot;;
	}
	
	
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[참고 강의] 인프런 -&amp;nbsp; &lt;span style=&quot;background-color: #ffffff;&quot;&gt;스프링 시큐리티 - Spring Boot 기반으로 개발하는 Spring Security&lt;/span&gt;&lt;/p&gt;</description>
      <category>Back-end/Spring Boot Security</category>
      <category>It</category>
      <category>security</category>
      <category>spring</category>
      <category>spring boot</category>
      <category>백엔드</category>
      <category>스프링 시큐리티</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/62</guid>
      <comments>https://thfdl0317.tistory.com/entry/SpringBoot%EA%B8%B0%EB%B0%98%EC%9C%BC%EB%A1%9C-Security-%EA%B0%9C%EB%B0%9C1#entry62comment</comments>
      <pubDate>Mon, 21 Feb 2022 23:42:19 +0900</pubDate>
    </item>
    <item>
      <title>정보처리기사 실기 08단원 - 서버 프로그램 구현</title>
      <link>https://thfdl0317.tistory.com/entry/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%EC%8B%A4%EA%B8%B0-8%EB%8B%A8%EC%9B%90-%EC%84%9C%EB%B2%84-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%EA%B5%AC%ED%98%84</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;목차&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;01. 개발환경 구축&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;02. 공통 모듈 구현&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;03. 서버 프로그램 구현&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;04. 배치 프로그램 구현&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;01. 개발환경 구축&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;[1] 개발환경 구축&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(1) 개발환경 구축의 개념&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 개발환경 구성 시 구현될 시스템 요구사항의 명확한 이해가 필요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p 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;span style=&quot;color: #000000;&quot;&gt;(2) 개발 도구의 분류&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 개발환경 구성을 위한 도구는 아래와 같이 크게 4가지로 분류할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;개발 도구 분류&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;구현 도구&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;테스트 도구&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;형상관리 도구&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;빌드 도구&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발 도구의 분류&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 29.0698%;&quot;&gt;구분&lt;/td&gt;
&lt;td style=&quot;width: 70.9302%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 29.0698%;&quot;&gt;빌드 도구&lt;/td&gt;
&lt;td style=&quot;width: 70.9302%;&quot;&gt;- 작성한 코드의 빌드 및 배포를 수행하는 도구&lt;br /&gt;- 각각의구성요소와 모듈에 대한 의존성 관리를 지원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 29.0698%;&quot;&gt;구현 도구&lt;/td&gt;
&lt;td style=&quot;width: 70.9302%;&quot;&gt;- 개발자의 코드 작성과 디버깅, 수정 등과 같은 작업을 지원하는 도구&lt;br /&gt;- 프로그램을 개발할 때 가장 많이 사용되는 도구&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 29.0698%;&quot;&gt;테스트 도구&lt;/td&gt;
&lt;td style=&quot;width: 70.9302%;&quot;&gt;코드의 테스트, 테스트에 대한 계획, 수행 및 분석 등의 작업 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 29.0698%;&quot;&gt;형상 관리 도구&lt;/td&gt;
&lt;td style=&quot;width: 70.9302%;&quot;&gt;- 개발자들이 작성한 코드와 리소스 등 산출물에 대한 버전 관리를 위한도구&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(3) 개발환경 구성요소&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1) 서버 하드웨어 개발환경&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 프로젝트 구성에 따라 웹 서버, 웹 애플리케이션 서버, 데이터베이스 서버, 파일서버로 구분한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;서버하드웨어 개발환경&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.6745%;&quot;&gt;구분&lt;/td&gt;
&lt;td style=&quot;width: 77.3255%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.6745%;&quot;&gt;웹 서버&lt;/td&gt;
&lt;td style=&quot;width: 77.3255%;&quot;&gt;- HTTP를 이용한요청/ 응답을 처리&lt;br /&gt;- 웹 상의 정적 콘텐츠 처리&lt;br /&gt;- Apache 웹 서버, IIS 웹 서버, Google Web Server, Nginx 등 존재&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.6745%;&quot;&gt;웹 애플리케이션 서버&lt;/td&gt;
&lt;td style=&quot;width: 77.3255%;&quot;&gt;- 동적 콘텐츠를 처리하기 위해 사용&lt;br /&gt;- 주요 제품으로 Tomcat, Weblogic, Jeus, Resin 등 존재&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.6745%;&quot;&gt;데이터베이스 서버&lt;/td&gt;
&lt;td style=&quot;width: 77.3255%;&quot;&gt;- 데이터 수집, 저장을 위한 용도로 사용&lt;br /&gt;- 연계되는 주요 DBMS로 MySql, Oracle, MS-SQL, DB2 등 존재&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.6745%;&quot;&gt;파일 서버&lt;/td&gt;
&lt;td style=&quot;width: 77.3255%;&quot;&gt;- 파일 저장 하드웨어로 물리 저장장치를 활용한 서버&lt;br /&gt;- 대용량 HDD, SSD 등의 장치가존재&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2) 클라이언트 하드웨어 개발환경&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 서버 개발환경에서제공된 서비스를 사용하기 위해 UI를 제공한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 클라이언트 프로그램, 웹 브라우저, 모바일 앱, 모바일 웹으로 구분한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;클라이언트 하드웨어 개발환경&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.7675%;&quot;&gt;구분&lt;/td&gt;
&lt;td style=&quot;width: 80.2325%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.7675%;&quot;&gt;클라이언트 프로그램&lt;/td&gt;
&lt;td style=&quot;width: 80.2325%;&quot;&gt;- 설치를 통해 사용자와 커뮤니케이션하는 프로그램&lt;br /&gt;- Visual Basic, C#, Delphi 등으로 개발되어 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.7675%;&quot;&gt;웹 브라우저&lt;/td&gt;
&lt;td style=&quot;width: 80.2325%;&quot;&gt;- 웹 서비스의 형태로 서버에서 웹 애플리케이션을 응답 시 브라우저를 통해 사용자와 커뮤니케이션&lt;br /&gt;- 일반적인 형태의 웹 사이트가 해당&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.7675%;&quot;&gt;모바일 앱&lt;/td&gt;
&lt;td style=&quot;width: 80.2325%;&quot;&gt;- 모바일 디바이스에 설치되어 활용되는 애플리케이션&lt;br /&gt;- 앱 스토어, 안드로이드 마켓 등을 통해 다운로드 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.7675%;&quot;&gt;모바일 웹&lt;/td&gt;
&lt;td style=&quot;width: 80.2325%;&quot;&gt;- 웹 브라우저와 동일한 형태로 모바일 상 웹 브라우저를 통해 서비스를 제공&lt;br /&gt;- 모바일에 최적화되어 제공되는 웹 사이트가 해당&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) 소프르퉤어 개발환경&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 개발을 위한 기본적인 소프트웨어 개발환경을 선택 및 구성한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 큰 틀에서 프로젝트 요구사항에 부합한 운영체제, 미들웨어 , 데이터베이스 시스템을 선정한다.&lt;/p&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;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;운영체제&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;미들웨어&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;DBMS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제 : Windows, Unix, Linux&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미들웨어 : Weblogic, Websphere, Jeus, Tomcat&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DBMS : Oracle, MySQL, MS-SQL, PostgreSQL&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(3) 형상관리(Configuration Management)&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;- SW 생명 주기 동안 형상 관리를 통해 산출물을 체계적으로 관리학여 SW의 가시성, 추적성, 무결성 등의 품질 보증을 보장할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 형상 관리의 목적&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 프로젝트 생명주기 동안 제품의 무결성과 변경에 대한 추적성을 확보가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 프로젝트변경이 발생 되었을 때 처리하는 매커니즘을 제공&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 대표적인 메커니즘으로 형상 관리 대상 파악, 베이스라인 지정, 형상관리, 접근제어 등이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) 형상 관리의 절차&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 다음과 같은 절차를 통해 품질 보증의 목적으로 수행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;형상 관리의 절차&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 120px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 14.8837%; height: 20px;&quot;&gt;절차&lt;/td&gt;
&lt;td style=&quot;width: 85.1163%; height: 20px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 14.8837%; height: 20px;&quot;&gt;형상 식별&lt;/td&gt;
&lt;td style=&quot;width: 85.1163%; height: 20px;&quot;&gt;- 형상 관리 대상을 정의 및 식별하는 활동&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 14.8837%; height: 20px;&quot;&gt;형상 통제&lt;/td&gt;
&lt;td style=&quot;width: 85.1163%; height: 20px;&quot;&gt;- 베이스라인에 대한 관리 및 형상 통제 수행가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 14.8837%; height: 20px;&quot;&gt;형상 감사&lt;/td&gt;
&lt;td style=&quot;width: 85.1163%; height: 20px;&quot;&gt;- 베이스라인 변경 시 요구사항과 일치 여부 검토&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 14.8837%; height: 40px;&quot;&gt;형상 기록&lt;/td&gt;
&lt;td style=&quot;width: 85.1163%; height: 40px;&quot;&gt;소프트웨어 형상 및 변경관리에 대한 각종 수행결과를 기록&lt;br /&gt;- 형상결과 보고서 작성&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) 소프트웨어 형상관리 도구 유형&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기의 소프트웨어 형상 관리 도구는 공유 폴더 방식을 많이 활용하였지만,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;촤ㅣ근에는 클라이언트/서버 방식과 저장소 방식이 많이 활용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어 형상관리 도구 유형&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 29.3023%;&quot;&gt;형상 관리 도구 유형&lt;/td&gt;
&lt;td style=&quot;width: 70.6977%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 29.3023%;&quot;&gt;공유 폴더 방식(RCS, SCCS)&lt;/td&gt;
&lt;td style=&quot;width: 70.6977%;&quot;&gt;- 매일 개발이 완료된 파일은약속된 위치의 공유 폴더에 복사하는방식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 29.3023%;&quot;&gt;클라이언트/서버 방식(CVS, SVN)&lt;/td&gt;
&lt;td style=&quot;width: 70.6977%;&quot;&gt;- 중앙에 버전 관리 시스템을 항시 동작하는 방식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 29.3023%;&quot;&gt;분산 저장소 방식(Git 등)&lt;/td&gt;
&lt;td style=&quot;width: 70.6977%;&quot;&gt;- 로컬 저장소와 원격 저장소로 분리되어 분산 저장하는 방식&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5) 소프트웨어 형상 관리 도구별 특징&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 현재 국내 개별 프로젝트에서는 SVN을 가장 많이 사용하고 있으나, 전 세계적으로는 오픈 소스 기반의 소프트웨어 형상 관리 도구인 Git을 가장 많이 사용&lt;/p&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;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.5116%;&quot;&gt;형상 관리 도구&lt;/td&gt;
&lt;td style=&quot;width: 83.4884%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.5116%;&quot;&gt;CVS&lt;/td&gt;
&lt;td style=&quot;width: 83.4884%;&quot;&gt;- 서버와 클라이언트로 구성&lt;br /&gt;- 다수 인원이 동시에 범용적인 운영체제로 접근 가능한 형상관리도구&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.5116%;&quot;&gt;SVN&lt;/td&gt;
&lt;td style=&quot;width: 83.4884%;&quot;&gt;- 하나의 서버에서 소스를 쉽고 유용하게 관리할 수 있게 도와주는 도구&lt;br /&gt;- 저장소를 만들어 그곳에 소스를 저장해 소스 중복이나 여러 문제를 해결하기 위한 도구&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.5116%;&quot;&gt;RCS&lt;/td&gt;
&lt;td style=&quot;width: 83.4884%;&quot;&gt;- CVS와 달리 소스 파일의 수정을 한 사람만으로 제한하여 다수의 사람이 파일의 수정을 동시에 할 수 없도록 파일 잠금 방식으로 형상ㅇ르고나리하는 도구&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.5116%;&quot;&gt;BitKeeper&lt;/td&gt;
&lt;td style=&quot;width: 83.4884%;&quot;&gt;- SVN과 비슷한 중앙 통제 방식으로 대규모 프로젝트에서 빠른속도를 내도록 개발된 형상관리 도구&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.5116%;&quot;&gt;Git&lt;/td&gt;
&lt;td style=&quot;width: 83.4884%;&quot;&gt;- Git의 속도에 중점을둔 분산형 버전관리 시스템이며, 대형 프로젝트에서 효과적으로 활용&lt;br /&gt;- 로컬 저장소에서 작업이 이루어져 매우 빠른 응답을 받을 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.5116%;&quot;&gt;Clear Case&lt;/td&gt;
&lt;td style=&quot;width: 83.4884%;&quot;&gt;- 복수 서버, 복수 클라이언트 구조이며 서버가 부족할 때 필요한 서버를 하나씩 추가하여 확장성을 기할 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6) 소프트웨어 형상 관리 도구 사용 시 유의사항&lt;/p&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;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 32.2093%;&quot;&gt;유의사항&lt;/td&gt;
&lt;td style=&quot;width: 67.7907%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 32.2093%;&quot;&gt;버전에 대한 쉬운 정보 접근성&lt;/td&gt;
&lt;td style=&quot;width: 67.7907%;&quot;&gt;- 형상 관리 지침에 의한 버번에 대한 정보를 언제든지 접근가능&lt;br /&gt;- 프로젝트 단위 접근이든, 파일 단위 접근이든 간에 개발자가 원할 때 원하는 모습을 다시 구성할 수 있어야함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 32.2093%;&quot;&gt;불필요한 사용자에 대한 접근 제어&lt;/td&gt;
&lt;td style=&quot;width: 67.7907%;&quot;&gt;- 제품 소프트웨어 개발자, 배포자 이외의 불필요한 사용자가 소스를 슈ㅜ정할 수 없도록해야 함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 32.2093%;&quot;&gt;동일 프로젝트에 대한 동시 사용성&lt;/td&gt;
&lt;td style=&quot;width: 67.7907%;&quot;&gt;- 동일한 프로젝트에 대해서 여러 개발자가 동시에 개발할 수 있어야함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 32.2093%;&quot;&gt;빠른 오류 복구&lt;/td&gt;
&lt;td style=&quot;width: 67.7907%;&quot;&gt;- 에러 발생 시 최대한 빠른 시간 내에 복구가 가능해야 함&lt;br /&gt;- 과거 버전의 소스를 가지고 신속하게 원복할 수 있어야함&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(4) 개발환경 구축 절차&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;p data-ke-size=&quot;size16&quot;&gt;개발환경 구축 절차&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 180px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 18.1395%; height: 20px;&quot;&gt;절차&lt;/td&gt;
&lt;td style=&quot;width: 81.8605%; height: 20px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 60px;&quot;&gt;
&lt;td style=&quot;width: 18.1395%; height: 60px;&quot;&gt;통합 개발&amp;nbsp;&lt;br /&gt;환경 설치&lt;/td&gt;
&lt;td style=&quot;width: 81.8605%; height: 60px;&quot;&gt;- 통합 개발환경 도구로 Eclipse, IntelliJ, Android Studio 등 존재&lt;br /&gt;- 이클립스는 오픈 소스로 자바 환경에서 보편적으로 사용 중&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 60px;&quot;&gt;
&lt;td style=&quot;width: 18.1395%; height: 60px;&quot;&gt;형상 관리&lt;br /&gt;도구 설치&lt;/td&gt;
&lt;td style=&quot;width: 81.8605%; height: 60px;&quot;&gt;- 형상 관리 도구로는 Git, SVN, CVS 등이 있으며 현재는 깃허브 등을 통해 Git이 각광&lt;br /&gt;- Git 설치 후 사용자 정보 설정 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 18.1395%; height: 40px;&quot;&gt;빌드&amp;nbsp;&lt;br /&gt;도구 설치&lt;/td&gt;
&lt;td style=&quot;width: 81.8605%; height: 40px;&quot;&gt;- 빌드 도구로 Ant, Maven, Gradle등이 있음&lt;br /&gt;- Maven Repository기반의 Maven, Android Studio에 탑재된 Gradle이 자주 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;형상 관리 도구(Git, SVN)주요 명령어&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;실행 동작&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;Git&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;SVN&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 190px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;저장소 생성&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;git init&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;svn import&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;저장소 복제&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;git clone&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;svn checkout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;커밋&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;git commit&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;svn commit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;변경 내용 확인&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;git diff&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;svn diff&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;추가&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;git add&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;svn add&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;이동/삭제&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;git mv / git rm&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;svn mv / svn rm&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;브랜치 생성&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;git branch&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;svn copy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;병합&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;git merge&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;svn merge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 10px;&quot;&gt;원격 저장소 반영&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 10px;&quot;&gt;git push&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 10px;&quot;&gt;svn commit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;설정 확인&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;git config&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;svn info&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;02. 공통 모듈 구현&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;[1] 공통 모듈 구현&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(1) 공통 모듈 구현의 개념&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1) 모듈의 개념&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 모듈은 그 자체로 하나의 완전한 기능을 수행할 수 있는 독립된 실체이다.&lt;/span&gt;&lt;/p&gt;
&lt;p 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;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2) 모듈의 특징&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 각각의 모듈은 상대적으로 독립성을 가지고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p 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;&lt;span style=&quot;color: #000000;&quot;&gt;- 모듈의 독립성은 결합도와 응집도에 의해 측정, 독립성을높이려면 모듈의 결합도는 약하게 응집도는강하게 모듈의 크기는 작게 만들어야한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3) 모듈화의 개념 및 기법&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 모듈화는 소프트웨어의 성능을향상시키거나 복잡한 시스템의 수정, 재사용, 유지 관리 등이 용이하도록 기능 단위의 모듈로 분해하는 설계 및 구현 기법이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;모듈화 기법&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.3953%;&quot;&gt;기법&lt;/td&gt;
&lt;td style=&quot;width: 78.6047%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.3953%;&quot;&gt;루틴&lt;/td&gt;
&lt;td style=&quot;width: 78.6047%;&quot;&gt;- 소프트웨어에서 특정 동작을 수행하는 일련의 코드로 기능을 가진 명령들의 모임&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.3953%;&quot;&gt;메인루틴&lt;/td&gt;
&lt;td style=&quot;width: 78.6047%;&quot;&gt;- 프로그램의 주요한 부분이며, 전제의 개략적인 동작 절차를 표시하도록 만들어진 루틴&lt;br /&gt;- 메인 루틴은 서브루틴을 호출&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.3953%;&quot;&gt;서브루틴&lt;/td&gt;
&lt;td style=&quot;width: 78.6047%;&quot;&gt;- 메인 루틴에 의해 필요할 때마다 호출되는 루틴&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;4) 공통 모듈 구현의 개념&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 소프트웨어 개발에 있어 기능을 분할하고 추상화하여 성능을 향상시키고 유지보수를 효과적으로 하기 위한 공통 컴포넌트 구현 기법&lt;/span&gt;&lt;/p&gt;
&lt;p 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;&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;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(2) 소프트웨어 모듈 응집도&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1) 응집도(Cohesion)의 개념&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 응집도는 모듈의 독립성을 나타내는 정도, 모듈 내부 구성 요소 간 연관 정도&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 하나의 모듈은 하나의 기능을 수행할수록 응집도가 높다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2) 응집도의 유형&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;우연적, 논리적, 시간적, 절차적, 통신적, 순차적, 기능적 응집도 순서대로 응집도가 높아진다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 222px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25.2326%; height: 20px;&quot;&gt;유형&lt;/td&gt;
&lt;td style=&quot;width: 74.7674%; height: 20px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25.2326%; height: 20px;&quot;&gt;Conincidental Cohesion&lt;/td&gt;
&lt;td style=&quot;width: 74.7674%; height: 20px;&quot;&gt;모듈 내부의 각 구성요소가 연관이 없을 경우의 응집도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 25.2326%; height: 40px;&quot;&gt;Logical Cohesion&lt;/td&gt;
&lt;td style=&quot;width: 74.7674%; height: 40px;&quot;&gt;유사한 성격을 갖거나 특정 형태로 분류되는 처리 요소들이 한 모듈에서 처리되는 경우의 응집도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 25.2326%; height: 40px;&quot;&gt;Temporal Cohesion&lt;/td&gt;
&lt;td style=&quot;width: 74.7674%; height: 40px;&quot;&gt;연관된 기능이라기보다는 특정 시간에 처리되어야하는 활동들을 한 모듈에서 처리할 경우의 응집도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 25.2326%; height: 40px;&quot;&gt;Procedural Cohesion&lt;/td&gt;
&lt;td style=&quot;width: 74.7674%; height: 40px;&quot;&gt;모듈이 다수의 관련 기능을 가질 대 모듈 안의 구성요소들이 그 기능을 순차적으로 수행할 경우의 응집도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 25.2326%; height: 22px;&quot;&gt;Communication Cohesion&lt;/td&gt;
&lt;td style=&quot;width: 74.7674%; height: 22px;&quot;&gt;동일한 입력과 출력을 사용하여다른 기능을 수행하는 활동들이 있을 경우의 응집도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25.2326%; height: 20px;&quot;&gt;SequentialCohesion&lt;/td&gt;
&lt;td style=&quot;width: 74.7674%; height: 20px;&quot;&gt;모듈 내에서 한활동으로부터 나온 출력값을 다른 활동이 사용할 경우의 응집도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25.2326%; height: 20px;&quot;&gt;Functional Cohesion&lt;/td&gt;
&lt;td style=&quot;width: 74.7674%; height: 20px;&quot;&gt;모듈 내부의 모든 기능이 단일한 목적을위해 수행되는 경우의 응집도&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 응집도가 높을수록 품질이 좋아진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(3) 소프트웨어 모듈 결합도&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1) 결합도(Coupling)의 개념&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 모듈 내부가 아닌외부의 모듈과의 연관도 또는 모듈간의 상호의존성&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 소프트웨어 구조에서 모듈간의 관련성을 측정하는 척도&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2) 결합도의 유형&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 결합도의 유형은 내용, 공통, 외부, 제어, 스탬프, 자료 결합도 순으로 결합도가 낮아진다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.1395%;&quot;&gt;유형&lt;/td&gt;
&lt;td style=&quot;width: 76.8605%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.1395%;&quot;&gt;Content Coupling&lt;/td&gt;
&lt;td style=&quot;width: 76.8605%;&quot;&gt;다른 모듈 내부에 있는 변수나 기능을 다른 모듈에서사용하는 경우의 결합도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.1395%;&quot;&gt;Common Coupling&lt;/td&gt;
&lt;td style=&quot;width: 76.8605%;&quot;&gt;파라미터가 아닌 다른모듈 밖에 선언되어 있는 전역 변수를 참조하고 전역 변수를 참조하고 전역 변수를 갱신하는식으로 상호작용하는 경우의 결합도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.1395%;&quot;&gt;External Coupling&lt;/td&gt;
&lt;td style=&quot;width: 76.8605%;&quot;&gt;단순 처리할 대상인 값만 전달되는 게 아니라 어떻게 처리를 해야한다는 제어요소가 전달되는 경우의 결합도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.1395%;&quot;&gt;Control Coupling&lt;/td&gt;
&lt;td style=&quot;width: 76.8605%;&quot;&gt;모듈 간의 인터페이스로 배열이나 객체, 구조 등이 전달되는 경우의 결합도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.1395%;&quot;&gt;Stamp Coupling&lt;/td&gt;
&lt;td style=&quot;width: 76.8605%;&quot;&gt;모듈 간의 인터페이스로 전달되는 파라미터를 통해서만 모듈 간의 상호 작용이 일어나는 경우의 결합도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.1395%;&quot;&gt;Data Coupling&lt;/td&gt;
&lt;td style=&quot;width: 76.8605%;&quot;&gt;모듈 간의 인터페이스 전달되는 파라미터를 통해서만 모듈 간의 상호 작용이 일어나는 경우의 결합도&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 결합도가 낮을수록 품질이 좋아진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(4) 공통 모듈 구현대상&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 공통 모듈은 화면 모듈, 화면에서 입력받은 데이터 처리를 위한 서비스 컴포넌트, 비즈니스 트랜잭션 컴포넌트 등이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 통합 구현에서 공통모듈 구현은 상세설계된 공통 모듈, 환경변수를 실제 프로그래밍 언어로 구현하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(5) 공통 모듈 구현 절차&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 공통 모듈은 DTO/VO &amp;rarr; SQL &amp;rarr; DAO &amp;rarr; Service &amp;rarr; Controller &amp;rarr;화면 구현 순으로 진행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 공통 모듈의 구현을 위한 공통 모둘 구현 절차에 MVC 패턴을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(6) 팬인(Fan-In) 및 팬 아웃(Fan-Out)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1) 팬인(Fan-In) 및 팬아웃(Fan-Out) 개념&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 소프트웨어의 구성요소인 모듈은 계층적으로 분석하기 위해서 팬인, 팬아웃을 활용한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 팬인과 팬아웃 분석을 통하여 시스템의 복잡도를 측정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 시스템 복잡도를 최적화 하기 위해서는 팬인은 높게, 팬아웃은 낮게 설계해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;[2] 공통 모듈 테스트&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(1) 공통 모듈 테스트의 개념&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 공통 모듈 테스트를 위해 IDE도구를 활용하여 개별 공통모듈에 대한 디버깅을 수행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 공통 모듈 테스트는 화이트 기법을 활용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 대표적인 단위테스트 도구인 JUnit을 활용하여 테스트 코드를 구현한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(2) 공통 모둘 테스트의 종류&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;공통 모듈 테스트의 종류&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 38.1395%;&quot;&gt;종류&lt;/td&gt;
&lt;td style=&quot;width: 61.8605%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 38.1395%;&quot;&gt;화이트박스 테스트&lt;/td&gt;
&lt;td style=&quot;width: 61.8605%;&quot;&gt;- 응용 프로그램의 내부 구조와 동작을 검사하는 소프트웨어 테스트 방식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 38.1395%;&quot;&gt;메서드기반 테스트&lt;/td&gt;
&lt;td style=&quot;width: 61.8605%;&quot;&gt;- 공통 모듈의 외부에공개된 메서드 기반의 테스트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 38.1395%;&quot;&gt;화면 기반 테스트&lt;/td&gt;
&lt;td style=&quot;width: 61.8605%;&quot;&gt;- 사용자용 화면이 있는 겨우, 각각의 화면단위로 단위모듈을 개발 후에 화면에 직접 데이터를 입력하여 테스트를 수행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 38.1395%;&quot;&gt;테스트 드라이버(Driver) / 테스트 스텁(Stub)&lt;/td&gt;
&lt;td style=&quot;width: 61.8605%;&quot;&gt;- 기능을 테스트할 수 잇는 화면 또는 하위 모듈이 구현되지 않은 경우 테스트 드라이버, 테스트 스텁을 통해 테스트를 수행&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(3) 공통 모듈 테스트 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 테스트 코드를 쉽게 작성하고 자동화하기 위해 JUnit을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;공통 모듈 테스트 구현 절차&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.9768%;&quot;&gt;단계&lt;/td&gt;
&lt;td style=&quot;width: 78.0232%;&quot;&gt;세부 내역&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.9768%;&quot;&gt;JUnit 생성&lt;/td&gt;
&lt;td style=&quot;width: 78.0232%;&quot;&gt;소스 코드 선택&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.9768%;&quot;&gt;JUnit 코드 생성&lt;/td&gt;
&lt;td style=&quot;width: 78.0232%;&quot;&gt;실제 메서드를 호출해 결과와 비교하는코드를작성&lt;br /&gt;&lt;br /&gt;import org.junit.Test;&lt;br /&gt;public class CalTest{&lt;br /&gt;&amp;nbsp; @Test&lt;br /&gt;&amp;nbsp; public void testSum(){&lt;br /&gt;&amp;nbsp; &amp;nbsp; Calculator calc = new Calculator();&lt;br /&gt;&amp;nbsp; &amp;nbsp; int result = calc.sum(10, 10);&lt;br /&gt;&amp;nbsp; &amp;nbsp; assertEquals(20, result);&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.9768%;&quot;&gt;JUnit 실행&lt;/td&gt;
&lt;td style=&quot;width: 78.0232%;&quot;&gt;테스트 코드 작성완료 시 테스트를 실행해 결과 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.9768%;&quot;&gt;JUnit 결과 확인&lt;/td&gt;
&lt;td style=&quot;width: 78.0232%;&quot;&gt;테스트 코드 결과를 통해 코드 이상 유무 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JUnit주요 어노테이션&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.3721%;&quot;&gt;어노테이션&lt;/td&gt;
&lt;td style=&quot;width: 86.6278%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.3721%;&quot;&gt;@Test&lt;/td&gt;
&lt;td style=&quot;width: 86.6278%;&quot;&gt;테스트 메서드를 선언&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.3721%;&quot;&gt;@Before&lt;/td&gt;
&lt;td style=&quot;width: 86.6278%;&quot;&gt;@Test 실행 전 실행되는 코드를 작성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.3721%;&quot;&gt;@After&lt;/td&gt;
&lt;td style=&quot;width: 86.6278%;&quot;&gt;@Test 실행 후 실행되는 코드를 작성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.3721%;&quot;&gt;@BeforeClass&lt;/td&gt;
&lt;td style=&quot;width: 86.6278%;&quot;&gt;@Test 메서드보다 먼저 딱 한 번 수행되어야 할 경우 지정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.3721%;&quot;&gt;@AfterClass&lt;/td&gt;
&lt;td style=&quot;width: 86.6278%;&quot;&gt;단위 테스트 맨 마지막에 수행되어야 할 경우 지정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.3721%;&quot;&gt;@Ignore&lt;/td&gt;
&lt;td style=&quot;width: 86.6278%;&quot;&gt;테스트에서 제외할 메서드 선언&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Assert 메서드 설명&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.5117%;&quot;&gt;문법&lt;/td&gt;
&lt;td style=&quot;width: 78.4883%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.5117%;&quot;&gt;assertEquals(a, b);&lt;/td&gt;
&lt;td style=&quot;width: 78.4883%;&quot;&gt;객체 a와 b가 일치함을 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.5117%;&quot;&gt;assertEquals(a, b, c);&lt;/td&gt;
&lt;td style=&quot;width: 78.4883%;&quot;&gt;객체 a와 b가 일치함을 확인&lt;br /&gt;a: 예상값, b : 결괏값, c: 오차범위&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.5117%;&quot;&gt;assertSame(a, b);&lt;/td&gt;
&lt;td style=&quot;width: 78.4883%;&quot;&gt;객체 a와 b가 같은 객체임을 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.5117%;&quot;&gt;assertTrue(a);&lt;/td&gt;
&lt;td style=&quot;width: 78.4883%;&quot;&gt;조건 a가 참인지 여부를 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.5117%;&quot;&gt;assertNotNull(a);&lt;/td&gt;
&lt;td style=&quot;width: 78.4883%;&quot;&gt;객체 a가 null이 아님을 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.5117%;&quot;&gt;assertArrayEquals(a, b);&lt;/td&gt;
&lt;td style=&quot;width: 78.4883%;&quot;&gt;배열 a와 b가 일치함을 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. 서버 프로그램 구현&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[1] 서버 프로그램 구현&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;- 웹 서비스 기반의 회원 정보를 조회하고 등록하는 서버 프로그램을 차례대로 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) 서버 프로그램 구현 절차&lt;/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;(3) 서버 프로그램 세부 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 서버 프로그램의 VO, SQL문, DAO, Service, Controller를 순서대로 구현한다.&lt;/p&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) DTO(Data Transfer Object) , VO(Value Object) 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화면에서 전달받은 회원정보를 데이터베이스에 저장하는 객체를 구현한다.&lt;/p&gt;
&lt;pre id=&quot;code_1645331971962&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class JoinVO{

    String id; //회원아이디
    String pw; //회원비밀번호
    String name; //회원이름
    
    public void setId(String id){ // 회원 아이디 설정 setter
    	this.id = Id;
    }
    
    public String getId(){ //회원 아이디 getter
    	return id;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) SQL문 구현&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;- VO에서 정의한 객체 정보에 맞춰 정보가 저장될 테이블 정보를 생성한다.&lt;/p&gt;
&lt;pre id=&quot;code_1645332185189&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Create table CUSTOMER(
ID varchar(20) NOT NULL COMMENT '아이디',
PW varchar(20) COMMENT '패스워드',
NAME VARCHAR(10) COMMENT '이름',
primarty key(ID)
) COMMENT '회원정보';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) Mybatis XML구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 회원 이름 검색 및 입력을 위한 SQL문을 Mybatis XML로 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) 데이터 접근 객체(DAO; Data Access Object) 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- DAO를 통해 SQL을 구현한 XML id를 호출하여 조작을 수행한다.&lt;/p&gt;
&lt;pre id=&quot;code_1645332687490&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class JoinDAO{
//회원가입 데이터 접근 오브젝트 프로토타입
public int selectJoin(JoinVO vo) throws Exception{
 reutrn sqlSession.selection(&quot;com.soojebi.sql.selectJoin&quot;,. vo);
 //회원가입 데이터 조회 프로토타입
 
  }
 
public void insertJoin(JoinVo vo){
 sqlSession.insertJoin(&quot;com.soojebi.sql.insertJoin&quot;, vo);
 //회원가입 데이터 입력
}
{&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) 서비스(Service) 클래스 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 회원 등록응 위해 JoinDAO를 호출하는 JoinService를 선언 및 구현한다.&lt;/p&gt;
&lt;pre id=&quot;code_1645332981956&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
public class JoinService implements IMemberService{
	@Autowired
    JoinDAL dao;
    
    @Override
    public void insertJoin(JoinVo join){
    JoinVO member = dao.selectJoin(join); //회원 조회 후 결과 저장
    dao.insertJoin(member); //회원등록
    
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5) 컨트롤러(Controller) 클래스 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-핵심이 되는 컨트롤러에 회원가입 단위 모듈의메인 로직을 구현한다.&lt;/p&gt;
&lt;pre id=&quot;code_1645333492455&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class CreateController extends HttpServlet{
	@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse res)
    					throws ServletException, IOException{
                        
                        JoinVO vo = new JoinVO();
                        JoinDAO dao = new JoinDAO();
                        PrintWriter out = res.getWriter();
                        String result;
                        
                        vo.setId(req.getParameter(&quot;id&quot;));
                        vo.setId(req.getParameter(&quot;pw&quot;));
                        vo.setId(req.getParameter(&quot;name&quot;));
                        
                        SimpleDataFormat sdf = new SimpleDateFormat(&quot;yyyymmdd&quot;);
                        Date date = null;
                        
                        try{
                        //입력값을 date포맷으로 변경
                        date = sdf.parse(req.getParameter(&quot;year&quot;)+&quot;-&quot;+req.getParameter(&quot;month&quot;)
                        +&quot;-&quot;+req.getParameter(&quot;day&quot;));
                        }
                        catch(ParesException e){
                        	e.printStackTrace();
                        }                        
                        }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6) 입/출력 검증(Validation) 로직 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 회원가입이 성공/실패 시 다른 메세지를 호출하는 검증 로직을 구현한다.&lt;/p&gt;
&lt;pre id=&quot;code_1645333751658&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class CreateController extends HttpServlet{
	@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse res)
    					throws ServletException, IOException{
                        
                        result = dao.insertJoin(req);
                        if(result ==&quot;success&quot;){
                        System.out.println(&quot;회원가입 성공&quot;); //회원가입 성공 시 메시지 출력
                        }
                        else{
                        System.out.println(&quot;회원가입 실패&quot;); //나머지 조건 실패 메시지 출력
                        }
                        }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;04. 배치 프로그램&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[1] 배치 프로그램&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) 배치 프로그램(Batch Program)의 개념&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;(2) Batch Program의 유형&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 정기 배치 : 사전에 정의해 둔 조건 충족 시 자동으로 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이벤트 배치 : 사용자의 명시적 요구가 있을때 마다 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 정기 배치 : 정해진 시점(주로 야간)에 정기적으로 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(3) 배치 스케줄러&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;일괄처리(Batch procession)를 위해 주기적으로 발생하거나 반복적으로 발생하는 작업을 지원하는 도구이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 배치 스케줄러의 종류&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.6279%;&quot;&gt;종류&lt;/td&gt;
&lt;td style=&quot;width: 78.3721%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.6279%;&quot;&gt;Spring Batch&lt;/td&gt;
&lt;td style=&quot;width: 78.3721%;&quot;&gt;스프링 프레임워크의 DI, AOP, 서비스 추상화 등 스프링 프페임 워크의 3대 요소를 모두 사용할 수 있는 대용량 처리를제공하는 스케줄러 배치 애플리케이션&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.6279%;&quot;&gt;Quartz Scheduler&lt;/td&gt;
&lt;td style=&quot;width: 78.3721%;&quot;&gt;스프링 프레임워크에 플러그인되어 수행하는 작업(Job)과 실행 스케줄을 정의하는 트리거를 분리하여 유연성을 제공하는 오픈소스 기반 스케줄러&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) Cron 표현식&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;Cron 표현식 특수문자 의미&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 6.86049%;&quot;&gt;기호&lt;/td&gt;
&lt;td style=&quot;width: 93.1395%;&quot;&gt;의미&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 6.86049%;&quot;&gt;*&lt;/td&gt;
&lt;td style=&quot;width: 93.1395%;&quot;&gt;모든 수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 6.86049%;&quot;&gt;?&lt;/td&gt;
&lt;td style=&quot;width: 93.1395%;&quot;&gt;해당 항목을 미사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 6.86049%;&quot;&gt;-&lt;/td&gt;
&lt;td style=&quot;width: 93.1395%;&quot;&gt;기간 설정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 6.86049%;&quot;&gt;,&lt;/td&gt;
&lt;td style=&quot;width: 93.1395%;&quot;&gt;특정 기간 설정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 6.86049%;&quot;&gt;/&lt;/td&gt;
&lt;td style=&quot;width: 93.1395%;&quot;&gt;시작시간과 반복간격 설정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 6.86049%;&quot;&gt;L&lt;/td&gt;
&lt;td style=&quot;width: 93.1395%;&quot;&gt;마지막 기간에 동작&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 6.86049%;&quot;&gt;W&lt;/td&gt;
&lt;td style=&quot;width: 93.1395%;&quot;&gt;가장 가까운 평일에 동작&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 6.86049%;&quot;&gt;#&lt;/td&gt;
&lt;td style=&quot;width: 93.1395%;&quot;&gt;몇 번째 주, 요일 설정&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Cron 표현식 특수문자 의미&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 200px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25.3488%; height: 20px;&quot;&gt;0 0 12 ** ?&lt;/td&gt;
&lt;td style=&quot;width: 74.6512%; height: 20px;&quot;&gt;매일 12시에 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25.3488%; height: 20px;&quot;&gt;0 15 10 **?&lt;/td&gt;
&lt;td style=&quot;width: 74.6512%; height: 20px;&quot;&gt;매일 오전 10시 15분에 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25.3488%; height: 20px;&quot;&gt;0 * 14 ** ?&lt;/td&gt;
&lt;td style=&quot;width: 74.6512%; height: 20px;&quot;&gt;오후 14시에서 15시 사이에 매 분마다 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25.3488%; height: 20px;&quot;&gt;0 0/5 14,20 ** ?&lt;/td&gt;
&lt;td style=&quot;width: 74.6512%; height: 20px;&quot;&gt;매일 14시에 시작하여 14시 55분까지 5분마다 실행, 20시 정각부터 20시 55분마다 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25.3488%; height: 20px;&quot;&gt;0 0 20 ? * MON-FRI&lt;/td&gt;
&lt;td style=&quot;width: 74.6512%; height: 20px;&quot;&gt;매주 월요일과 금요일 사이 20시에 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25.3488%; height: 20px;&quot;&gt;0 15 10 15 * ?&lt;/td&gt;
&lt;td style=&quot;width: 74.6512%; height: 20px;&quot;&gt;매달 15일 10시 15분에 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25.3488%; height: 20px;&quot;&gt;0 15 10 L * ?&lt;/td&gt;
&lt;td style=&quot;width: 74.6512%; height: 20px;&quot;&gt;매달 마지막 날 10시 15분에 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25.3488%; height: 20px;&quot;&gt;0 15 10 ? * 6L 2020-2021&lt;/td&gt;
&lt;td style=&quot;width: 74.6512%; height: 20px;&quot;&gt;2020년부터 2021년 매달 마지막 금요일 10시 15분에 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25.3488%; height: 20px;&quot;&gt;0 15 10 15 * ?&lt;/td&gt;
&lt;td style=&quot;width: 74.6512%; height: 20px;&quot;&gt;매달 15일 10시 15분에 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25.3488%; height: 20px;&quot;&gt;0 11 11 1 1 ?&lt;/td&gt;
&lt;td style=&quot;width: 74.6512%; height: 20px;&quot;&gt;1월 1일 11시 11분마다 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(4) 배치 프로그램 설계&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;2) 배치 설계서 확인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 프로그램 관리 대장의 ID와 일치하는 배치 설계서를 확인한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배치 설계서를 통해 작업 내역을 참고하여 배치 프로그램을 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;1) DTO(Data Transfer Object), VO(Value Object) 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전달하려는 푸시 메시지 내용을 데이터베이스에 저장할 갤체를 구현한다.&lt;/p&gt;
&lt;pre id=&quot;code_1645337170263&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class PushMessageVO{
	//푸시 발송마스터
    private String pushSeqCd;   //푸시 순차코드
    private String sendSubject; //발송 제목
    private String sendContent; //발송 내용
    private Stirng sndrEmpNo;   //발신자 사원번호
    private sndrNm;             //발신자 이름
    private String arrayEmpNo;  //사원 리스트
    private String getPushSeqCd();{
    	return pushSeqCd;
    }
    
    public void setPushSeqCd(String pushSeqCd){
    this.pushSeqCd = pushSeqCd;}
}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) SQL문 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) 데이터 접근 객체(DAO : Data Access 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;4) 서비스(Service) 클래스 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;푸시발송 대상조회를 위해 PushMessageDAO&lt;br /&gt;를 호출하는 PushServixce를 선언 및 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;- 작성한 배치 프로그램을 정기적으로 실행하는 쿼츠 스케줄러를등록한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[출처] 수제비 2021...! 정보처리기사 실기&amp;nbsp;&lt;/p&gt;</description>
      <category>정보처리기사</category>
      <category>개발환경</category>
      <category>정보처리기사</category>
      <category>정보처리기사 실기</category>
      <category>큐넷</category>
      <category>형상관리</category>
      <category>형상통제</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/60</guid>
      <comments>https://thfdl0317.tistory.com/entry/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%EC%8B%A4%EA%B8%B0-8%EB%8B%A8%EC%9B%90-%EC%84%9C%EB%B2%84-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%EA%B5%AC%ED%98%84#entry60comment</comments>
      <pubDate>Sun, 20 Feb 2022 01:41:16 +0900</pubDate>
    </item>
    <item>
      <title>정보처리기사 실기 07단원 - SQL 응용</title>
      <link>https://thfdl0317.tistory.com/entry/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%EC%8B%A4%EA%B8%B0-07-SQL-%EC%9D%91%EC%9A%A9-01-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4%EC%9D%98-%EA%B8%B0%EB%B3%B8</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;목차&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;01. 데이터베이스 기본&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;02. 응용 SQL 작성하기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;03. 절차형 SQL 활용하기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;04. 데이터 조작 프로시저 최적화&lt;/b&gt;&lt;/span&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;01. 데이터베이스 기본&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;[1] 트랜잭션&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(1) 트랜잭션의 개념&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; &amp;nbsp; 인가받지 않은 사용자로 부터 데이터를 보장하기 위해 DBMS가 가져야하는 특성이자, 데이터베이스 시스템에서 하나의 논리적 기능을 정상적으로 수행하기 위한 작업의 기본 단위&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(2) 트랜잭션의 특성&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.5193%;&quot;&gt;특성&lt;/td&gt;
&lt;td style=&quot;width: 44.1473%;&quot;&gt;설명&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;주요기법&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.5193%;&quot;&gt;Atomicity (원자성)&lt;/td&gt;
&lt;td style=&quot;width: 44.1473%; text-align: left;&quot;&gt;- 분해가 불가능한 작업의 최소단위&lt;br /&gt;- 연산 전체가 성공 또는 실패&lt;br /&gt;- 하나라도 실패할 경우 전체가 취소되어야하는특성&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: left;&quot;&gt;- Commit / Rollback&lt;br /&gt;- 회복성 보장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.5193%;&quot;&gt;Consistency (일관성)&lt;/td&gt;
&lt;td style=&quot;width: 44.1473%; text-align: left;&quot;&gt;트랜잭션이 실행 성공 후 항상 일관된 데이터베이스 상태를 보존해야하는 특성&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: left;&quot;&gt;- 무결성 제약 조건&lt;br /&gt;- 동시성 제어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.5193%;&quot;&gt;Isolation (격리성)&lt;/td&gt;
&lt;td style=&quot;width: 44.1473%; text-align: left;&quot;&gt;트랜잭션 실행 중 생성하는 연산의 중간 결과를 다른 트랜잭션이 접근 불가한 특성&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: left;&quot;&gt;- Read Uncomited&lt;br /&gt;- Read Commited&lt;br /&gt;- Repeatable Read&lt;br /&gt;- Serializable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.5193%;&quot;&gt;Durability (영속성)&lt;/td&gt;
&lt;td style=&quot;width: 44.1473%; text-align: left;&quot;&gt;성공이 완료된 트랜잭션의 결과는 영속적으로 데이터 베이스에 저장하는 특성&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: left;&quot;&gt;회복기법&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(3) 트랜잭션의 상태 변화&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 31.9767%;&quot;&gt;상태&lt;/td&gt;
&lt;td style=&quot;width: 68.0233%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 31.9767%;&quot;&gt;Active (활동 상태)&lt;/td&gt;
&lt;td style=&quot;width: 68.0233%;&quot;&gt;초기 상태, 트랜잭션이 실행 중일 때 가지는 상태&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 31.9767%;&quot;&gt;Partially Committed (부분 완료 상태)&lt;/td&gt;
&lt;td style=&quot;width: 68.0233%;&quot;&gt;마지막 명령문이 실행된 후에 가지는 상태&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 31.9767%;&quot;&gt;Committed (완료 상태)&lt;/td&gt;
&lt;td style=&quot;width: 68.0233%;&quot;&gt;트랜잭션이 성공적으로 완료된 후 가지는 상태&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 31.9767%;&quot;&gt;Failed (실패 상태)&lt;/td&gt;
&lt;td style=&quot;width: 68.0233%;&quot;&gt;정상적인 실행이 더 이상 진행될 수 없을 때 가지는 상태&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 31.9767%;&quot;&gt;Aborted (철회 상태)&lt;/td&gt;
&lt;td style=&quot;width: 68.0233%;&quot;&gt;트랜잭션이 취소되고 데이터베이스가 트랜잭션 시작 전 상태로 환원된 상태&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(4) 트랜잭션 제어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- TCL(Transaction Control Language) 라고도 하며 트랜잭션 결과를 허용하거나 취소하는 목적으로 사용되는 언어를 지칭&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TCL 명령어&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.6124%;&quot;&gt;명령어&lt;/td&gt;
&lt;td style=&quot;width: 20.0775%;&quot;&gt;핵심&lt;/td&gt;
&lt;td style=&quot;width: 60.31%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.6124%;&quot;&gt;Commit&lt;/td&gt;
&lt;td style=&quot;width: 20.0775%;&quot;&gt;트랜잭션 확정&lt;/td&gt;
&lt;td style=&quot;width: 60.31%;&quot;&gt;트랜잭션을 메모리에 영구적으로 저장하는 명령어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.6124%;&quot;&gt;Rollback&lt;/td&gt;
&lt;td style=&quot;width: 20.0775%;&quot;&gt;트랜잭션 취소&lt;/td&gt;
&lt;td style=&quot;width: 60.31%;&quot;&gt;트랜잭션 내역을 저장 무효화 시키는 명령어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.6124%;&quot;&gt;Check Point&lt;/td&gt;
&lt;td style=&quot;width: 20.0775%;&quot;&gt;저장 시기 설정&lt;/td&gt;
&lt;td style=&quot;width: 60.31%;&quot;&gt;Rollback 을 위한 시점을 지정하는 명령어&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(5) 병행 제어(일관성 주요 기법)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) Concurrency Control개념&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;2) 병행 제어의 목적&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터베이스의 공유를 최대화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 시스템의 활용도를 최대화&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;3) 병행 제어 미보장 시 문제점&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 142px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 28.721%; height: 20px;&quot;&gt;문제점&lt;/td&gt;
&lt;td style=&quot;width: 71.279%; height: 20px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 28.721%; height: 20px;&quot;&gt;Lost Update (갱신 손실)&lt;/td&gt;
&lt;td style=&quot;width: 71.279%; height: 20px;&quot;&gt;먼저 설행된 트랜잭션의 결과를 나중에 실행된 트랜잭션이 텊어쓸 때 발생하는 오류&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 28.721%; height: 20px;&quot;&gt;Dirty Read (현황 파악 오류)&lt;/td&gt;
&lt;td style=&quot;width: 71.279%; height: 20px;&quot;&gt;트랜잭션의 중간 수행 결과를 다른 트랜잭션이 참조하여 발생하는 오류&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 28.721%; height: 20px;&quot;&gt;Inconsistency (모순성)&lt;/td&gt;
&lt;td style=&quot;width: 71.279%; height: 20px;&quot;&gt;두 트랜잭션이 동시에 실행되어 데이터베이스의 일관성이 결여되는 오류&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 28.721%; height: 22px;&quot;&gt;Cascading Rollback (연쇄복구)&lt;/td&gt;
&lt;td style=&quot;width: 71.279%; height: 22px;&quot;&gt;복수의 트랜잭션이 데이터 공유 시 특정 트랜잭션이 처리 취소할 경우 트랜잭션이 처리한 곳의 부분을 취소하지 못하는 오류&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;- 병행 제어 기법에는 로킹, 타임 스탬프 순서가 있다.&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;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.9767%;&quot;&gt;기법&lt;/td&gt;
&lt;td style=&quot;width: 78.0233%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.9767%;&quot;&gt;Locking&lt;/td&gt;
&lt;td style=&quot;width: 78.0233%;&quot;&gt;- 같은 자원을 액세스하는 다중 트랜잭션 환경에서 DB의 일관성에 무결성을 유지하기 위해 트랜잭션의 순차적 진행을 보장하는 직렬화 기법&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.9767%;&quot;&gt;낙관적 검증&lt;/td&gt;
&lt;td style=&quot;width: 78.0233%;&quot;&gt;- 트랜잭션이 어떠한 검증도 수행하지 않고 일단 트랜잭션을 수행하고, 트랜잭션 종료 시 검증을 수행하여 데이터베이스에 반영하는 기법&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.9767%;&quot;&gt;타임 스탬프 순서&lt;/td&gt;
&lt;td style=&quot;width: 78.0233%;&quot;&gt;- 트랜잭션과 트랜잭션이 읽거나 갱신한 데이터에 대해 트랜잭션이 실행을 시작하기 전에 타임 스탬프를부여하여 부여된 시간에 따라 트랜잭션 작업을 수행하는 기법&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.9767%;&quot;&gt;다중 버전 동시성 제어&lt;/td&gt;
&lt;td style=&quot;width: 78.0233%;&quot;&gt;- 트랜잭션의 타임스탬프와 접근하려는 테이터의 타임스탬프를 비교하여 직렬가능성이 보장되는 적절한 버전을 선택하여 접근하도록 하는 기법&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(6) 데이터 베이스 고립화 수준(격리성 주요 기법)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) lsolation Level 개념&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;2) 고립화 수준 종류&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Read Uncommitted, Read Committed, Repeatable Read, Serializable Read가 있다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 100px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 22.5581%; height: 20px;&quot;&gt;수준&lt;/td&gt;
&lt;td style=&quot;width: 77.4419%; height: 20px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 22.5581%; height: 20px; text-align: left;&quot;&gt;Read Uncommitted&lt;/td&gt;
&lt;td style=&quot;width: 77.4419%; height: 20px; text-align: left;&quot;&gt;한 트랜잭션에서 연산(갱신) 중인 데이터를 다른 트랜잭션이 읽는 것을 허용하는 수준&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 22.5581%; height: 20px; text-align: left;&quot;&gt;Read Committed&lt;/td&gt;
&lt;td style=&quot;width: 77.4419%; height: 20px; text-align: left;&quot;&gt;- 한 트랜잭션에서 연산을 수행할 때 연산이 완료될 때가지 연산 대상 데이터에 대한 읽기를 제한하는 수준&lt;br /&gt;&lt;br /&gt;- 연산이 완료되어 커밋된 데이터는 다른 트랜잭션이 읽는 것을 허용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 22.5581%; height: 20px; text-align: left;&quot;&gt;Repeatable Read&lt;/td&gt;
&lt;td style=&quot;width: 77.4419%; height: 20px; text-align: left;&quot;&gt;- 선행 트랜잭션이 특정 데이터를 읽을 때 트랜잭션 종료 시까지 해당 데이터에 대한 갱신, 삭제를 제한하는 수준&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 22.5581%; height: 20px; text-align: left;&quot;&gt;Serializable Read&lt;/td&gt;
&lt;td style=&quot;width: 77.4419%; height: 20px; text-align: left;&quot;&gt;- 선행 트랜잭션이 특정 데이터 영역을 순차적으로 읽을 때, 해당 데이터 영역 전체에 대한 접근 제한하는 수준&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(7) 회복 기법(영속성 주요 기법)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) Recovery 개념&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;2) 회족 기법 종류&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;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.9768%;&quot;&gt;기법&lt;/td&gt;
&lt;td style=&quot;width: 78.0232%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.9768%;&quot;&gt;로그 기반 회복 기법&lt;/td&gt;
&lt;td style=&quot;width: 78.0232%;&quot;&gt;지연 갱신 회복 기법과 즉각 갱신 회복 기법이 있음&lt;br /&gt;&lt;br /&gt;- 지연 갱신 회복 기법(Deferred Update): 트랜잭션이 완료되기 전까지 데이터베이스에 기록하지 않은 기법&lt;br /&gt;&lt;br /&gt;- 즉각 갱신 회복 기법(Immediate Update) : 트랜잭션 수행 중 갱신 결과를 바로 DB에 반영하는 기법&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.9768%;&quot;&gt;체크 포인트 회복 기법&lt;/td&gt;
&lt;td style=&quot;width: 78.0232%;&quot;&gt;장애 발생 시 검사점 이후에 처리된 트랜잭션에 대해서만 장애 발생 이전의 상태로 복원시키는 회복 기법&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.9768%;&quot;&gt;그림자 페이징 회복 기법&lt;/td&gt;
&lt;td style=&quot;width: 78.0232%;&quot;&gt;데이터베이스 트랜잭션 수행 시 복제본을 생성하여 데이터베이스 장애 시 이를 이용해 복구하는 기법&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(2) DDL&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(1) 데이터 정의어 (DDL : Data Definition Language)의 개념&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 데이터 정의어는 데이터의 정의하는 언어로서 '데이터를 담는 그릇을 정의하는 언어'&lt;/span&gt;&lt;/p&gt;
&lt;p 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;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(2) DDL의 대상&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인, 스키마, 데이블, 뷰, 인덱스&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.6279%;&quot;&gt;DDL 대상&lt;/td&gt;
&lt;td style=&quot;width: 88.3721%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.6279%;&quot;&gt;Domain&lt;/td&gt;
&lt;td style=&quot;width: 88.3721%;&quot;&gt;- 하나의 속성이 가질 수 있는 원자값들의 집합&lt;br /&gt;- 속성의 데이터 타입과 크기, 제약조건 등의 정보&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.6279%;&quot;&gt;Schema&lt;/td&gt;
&lt;td style=&quot;width: 88.3721%;&quot;&gt;- 데이터베이스의 구조, 제약조건 등의 정보를 담고 있는 기본적인 구조&lt;br /&gt;- 스키마는 외부/개념/내부 3계층으로 구성되어있음&lt;br /&gt;&lt;br /&gt;- External Schema (외부 스키마)&lt;br /&gt;: 사용자나 개발자의 관점에서 필요로하는 db의 논리적 구조&lt;br /&gt;: 사용자 뷰를 나타냄, 서브 스키마로 불림&lt;br /&gt;&lt;br /&gt;- Conceptual Schema (개념 스키마)&amp;nbsp;&lt;br /&gt;: 데이터베이스의 전체적인 논리적 구조&lt;br /&gt;: 전체적인 뷰를 나타냄&lt;br /&gt;: 개체 간의 관계, 재약조건, 접근 권한, 무결성, 보안에 대해 정의&amp;nbsp;&lt;br /&gt;&lt;br /&gt;- Internal Scema (내부 스키마)&lt;br /&gt;: 물리적 저장 장치의 관점에ㅓㅅ 보는 데이터베이스 구조&lt;br /&gt;: 실제로 데이터베이스에 저장될 레코드의 형식을 정의하고 저장 데이터 항목의 표현 방법, 내부 레코드의 물리적 순서등을 표현&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.6279%;&quot;&gt;Table&lt;/td&gt;
&lt;td style=&quot;width: 88.3721%;&quot;&gt;데이터 저장공간&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.6279%;&quot;&gt;View&lt;/td&gt;
&lt;td style=&quot;width: 88.3721%;&quot;&gt;하나 이상의 물리 테이블에서 유도되는 가상의 테이블&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.6279%;&quot;&gt;Index&lt;/td&gt;
&lt;td style=&quot;width: 88.3721%;&quot;&gt;검색을 빠르게 하기 위한 데이터 구조&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) Table&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;하나의 db 내에 여러 개의 테이블을 구성될 수 잇고, Relation 또는 Entity 라고도 부른다.&lt;/p&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;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.1162%;&quot;&gt;용어&lt;/td&gt;
&lt;td style=&quot;width: 79.8838%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.1162%;&quot;&gt;Tuple / Row&lt;/td&gt;
&lt;td style=&quot;width: 79.8838%;&quot;&gt;- 테이블 내의 행을 의미하며 레코드라고도 함&lt;br /&gt;- 튜플은 릴레이션에서 같은 값을 가질 수 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.1162%;&quot;&gt;Attribute / Column&lt;/td&gt;
&lt;td style=&quot;width: 79.8838%;&quot;&gt;- 테이블 내의 열을 의미&lt;br /&gt;- 열의 개수를 디그리라고 함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.1162%;&quot;&gt;Identifier&lt;/td&gt;
&lt;td style=&quot;width: 79.8838%;&quot;&gt;- 여러 개의 집합체를 담고 있는 관계형 데이터 베이스에서 각각의 구분할 수 있는 논리적인 개념&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.1162%;&quot;&gt;Cardinality&lt;/td&gt;
&lt;td style=&quot;width: 79.8838%;&quot;&gt;- 튜플의 개수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.1162%;&quot;&gt;Degree&lt;/td&gt;
&lt;td style=&quot;width: 79.8838%;&quot;&gt;- Attribute의 개수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.1162%;&quot;&gt;Domain&lt;/td&gt;
&lt;td style=&quot;width: 79.8838%;&quot;&gt;- 하나의 애트리뷰트가 취할 수 잇는 같은 타입의 원자값 들의 집합&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 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;뷰는 논리 테이블, 사용자에게 (사용 관점에서) 테이블과 동일하다&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;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 24.7675%;&quot;&gt;특징&lt;/td&gt;
&lt;td style=&quot;width: 75.2325%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 24.7675%;&quot;&gt;논리적 데이터 독립성 제공&lt;/td&gt;
&lt;td style=&quot;width: 75.2325%;&quot;&gt;데이터베이스에 영향을 주지않고 애플리케이션이 원하는 형태로 데이터에 접근 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 24.7675%;&quot;&gt;데이터 조작 연산 간소화&lt;/td&gt;
&lt;td style=&quot;width: 75.2325%;&quot;&gt;애플리케이션이 원하는 형태의 논리적 구조를 형성하여 데이터 조작 연산을 간소화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 24.7675%;&quot;&gt;보안 기능(접근제어)제공&lt;/td&gt;
&lt;td style=&quot;width: 75.2325%;&quot;&gt;특정 필드만의 선택해 뷰를 생성할 경우 애플리케이션은 선택되지 않은 필드의 조회 및 접근 불가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 24.7675%;&quot;&gt;뷰 변경 불가&lt;/td&gt;
&lt;td style=&quot;width: 75.2325%;&quot;&gt;뷰 정의는 Alter문을 이용하여 변경할 수 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 뷰의 목적&lt;/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; &amp;nbsp;- From 절에 있는 하나의 뷰를 통해 뷰를 구성하는 복수의 테이블을 대체하는 단순성에 그 의의가 있다.&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;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;장점&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;단점&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;- 논리적 독립성제공 : 뷰는 논리 테이블&lt;br /&gt;- 사용자 데이터 관리 용이 : &lt;br /&gt;복수 테이블에 존재하는 여러 종류의 데이터에 대해 단순한 질의어 사용이 가능&lt;br /&gt;- 데이터 보안의 용이 : 보안 데이터에 대한 접근 제어 가능&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;- 뷰 자체 인덱스 불가 : 인덱스는 물리적으로 저장된 데이터를 대상으로 하기에 논리적 구성인 뷰 자체는 인덱스를 가지지 못함&amp;nbsp;&lt;br /&gt;- 뷰 정의 변경 불가 : 뷰의 정의를 변경하려면 뷰를 삭제하고 재생성&lt;br /&gt;- 데이터 변경 제약 존재 : 뷰의 내용에 대한 삽입, 삭제, 변경 제약이 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) 인덱스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 인덱스의 개념&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인덱스는 데이터를 빠르게 찾을 수 있는 수단으로서, 테이블에 대한 조회 속도를 높여 주는 자료 구조&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인덱스는 테이블의 특정 레코드 위치를 알려주는 용도로 사용한다.&lt;/p&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; - 조건절에 &quot;=&quot;로 비교되는 컬럼을 대상으로 인덱스를 생성하면 검색 속도를 높일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 인덱스의 종류&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.093%;&quot;&gt;유형&lt;/td&gt;
&lt;td style=&quot;width: 77.907%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.093%;&quot;&gt;Order Index&lt;/td&gt;
&lt;td style=&quot;width: 77.907%;&quot;&gt;- 데이터가 정렬된 순서로 생성되는 인덱스&lt;br /&gt;- B -tree 알고리즘 활용(오름차순/내림차순 지정가능)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.093%;&quot;&gt;Hash Index&lt;/td&gt;
&lt;td style=&quot;width: 77.907%;&quot;&gt;- 해시 함수에 의해 직접 데이터에 키 값으로 접근하는 인덱스&lt;br /&gt;- 데이터 접근 비용이 균일, 튜플양에 무관&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.093%;&quot;&gt;Bitmap Index&lt;/td&gt;
&lt;td style=&quot;width: 77.907%;&quot;&gt;- 각 컬럼에 적은 개수 값이 저장된 경우 선택하는 인덱스&lt;br /&gt;- 수정변경이 적을 경우 유용(생년월일, 상품정보 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.093%;&quot;&gt;Functional Index&lt;/td&gt;
&lt;td style=&quot;width: 77.907%;&quot;&gt;- 수식이나 함수를 적용하여 만든 인덱스&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.093%;&quot;&gt;Singled Index&lt;/td&gt;
&lt;td style=&quot;width: 77.907%;&quot;&gt;- 하나의 컬럼으로만 구서한 인덱스&lt;br /&gt;- 주 사용 컬럼이 하나일 경우 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.093%;&quot;&gt;Concatenated Index&lt;/td&gt;
&lt;td style=&quot;width: 77.907%;&quot;&gt;- 두 개 이상의 컬러으로 구성 인덱스&amp;nbsp;&lt;br /&gt;- where 조건으로 사용하는 빈도가 높은 경우 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.093%;&quot;&gt;Clutered Index&lt;/td&gt;
&lt;td style=&quot;width: 77.907%;&quot;&gt;- 기본 키 기준으로 레코드를 묶어서 저장하는 인덱스&lt;br /&gt;- 저장 데이터의 물리적 순서에 따라 인덱스가 생성&lt;br /&gt;- 특정 범위 검색 시 유리함&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 인덱스의 스캔 방식&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.3333%;&quot;&gt;구분&lt;/td&gt;
&lt;td style=&quot;width: 53.3333%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.3333%;&quot;&gt;Index Range Scan&lt;/td&gt;
&lt;td style=&quot;width: 53.3333%;&quot;&gt;인덱스 루트 블록에서 리프 블록까지 수직적으로 탐색한 후에 리프 블록을 필요한 범위만 스캔하는 방식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.3333%;&quot;&gt;Index Full Scan&lt;/td&gt;
&lt;td style=&quot;width: 53.3333%;&quot;&gt;수직적 탐색 없이 인덱스 리프 블록을 처음부터 끝가지 수평적으로 탐색하는 방식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.3333%;&quot;&gt;Index Unique Scan&lt;/td&gt;
&lt;td style=&quot;width: 53.3333%;&quot;&gt;수직적 탐색만으로 데이터를 찾는 스캔 방식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.3333%;&quot;&gt;Index Skip Scan&lt;/td&gt;
&lt;td style=&quot;width: 53.3333%;&quot;&gt;선두 컬럼이 조건 절에 빠졌어도 인덱스를 활용하는 스캔방식&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- DDL 명령어 : CREATE, ALTER, DROP, TRUNCATE&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 100px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 13.5659%; height: 20px;&quot;&gt;구분&lt;/td&gt;
&lt;td style=&quot;width: 16.0076%; height: 20px;&quot;&gt;DDL 명령어&lt;/td&gt;
&lt;td style=&quot;width: 70.4264%; height: 20px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 13.5659%; height: 20px;&quot;&gt;생성&lt;/td&gt;
&lt;td style=&quot;width: 16.0076%; height: 20px;&quot;&gt;CREATE&lt;/td&gt;
&lt;td style=&quot;width: 70.4264%; height: 20px;&quot;&gt;DB 오브젝트 생성하는 명령어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 13.5659%; height: 20px;&quot;&gt;수정&lt;/td&gt;
&lt;td style=&quot;width: 16.0076%; height: 20px;&quot;&gt;ALTER&lt;/td&gt;
&lt;td style=&quot;width: 70.4264%; height: 20px;&quot;&gt;DB 오브젝트 변경하는 명령어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 13.5659%; height: 20px;&quot;&gt;삭제&lt;/td&gt;
&lt;td style=&quot;width: 16.0076%; height: 20px;&quot;&gt;DROP&lt;/td&gt;
&lt;td style=&quot;width: 70.4264%; height: 20px;&quot;&gt;DB 오브젝트 삭제하는 명령어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 13.5659%; height: 20px;&quot;&gt;삭제&lt;/td&gt;
&lt;td style=&quot;width: 16.0076%; height: 20px;&quot;&gt;TRUNCATE&lt;/td&gt;
&lt;td style=&quot;width: 70.4264%; height: 20px;&quot;&gt;DB 오브젝트 내용 삭제하는 명령어&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- TABLE 관련 DDL&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) CREATE TABLE : 테이블을 생성하는 명령&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) ALTER TABLE : 테이블을 수정하는 명령&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) DROP TABLE : 테이블을 삭제하는 명령&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) TRUNCATE 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;- VIEW 관련 DDL&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) CREATE VIEW : 뷰를 생성하는 명령이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) CREATE OR REPLACE VIEW&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) DROP VIEW&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- INDEX 관련 DDL&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) CREATE INDEX&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- CREATE INDEX 는 인덱스를 생성하는 명령이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- UNIQUE는 생략 가능하고 인덱스 걸린 컬럼에 중복 값을 허용하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 복수 컬럼을 인덱스로 걸 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;create [unique] index 인덱스명 on 테이블명(컬럼명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;2) ALTER INDEX&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- ALTER INDEX는 인덱스를 수정하는 명령어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 일부 DBMS는 ALTER INDEX를 제공하지 않는다.&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;ALTER INDEX 문법&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ALTER [UNIQUE] INDEX 인덱스명 ON 테이블명(컬럼명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;3) DROP INDEX : 인덱스를 삭제하는 명령어이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DORP INDEX 인덱스명;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(3) DML&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터 조작어 : 데이터 조작어는 데이터베이스에 저장된 자료들을 입력, 수정,삭제, 조회하는 언어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- DML 명령어 : 데이터조작어의 유형에는 SELECT, INSERT, UPDATE, 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;DML의 유형&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.9147%;&quot;&gt;유형&lt;/td&gt;
&lt;td style=&quot;width: 14.496%;&quot;&gt;동작&lt;/td&gt;
&lt;td style=&quot;width: 71.5892%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.9147%;&quot;&gt;SELECT&lt;/td&gt;
&lt;td style=&quot;width: 14.496%;&quot;&gt;조회&lt;/td&gt;
&lt;td style=&quot;width: 71.5892%;&quot;&gt;테이블 내 칼럼에 저장된 데이터를 조회&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.9147%;&quot;&gt;INSERT&lt;/td&gt;
&lt;td style=&quot;width: 14.496%;&quot;&gt;삽입&lt;/td&gt;
&lt;td style=&quot;width: 71.5892%;&quot;&gt;테이블 내칼럼에 데이터를 추가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.9147%;&quot;&gt;UPDATE&lt;/td&gt;
&lt;td style=&quot;width: 14.496%;&quot;&gt;갱신&lt;/td&gt;
&lt;td style=&quot;width: 71.5892%;&quot;&gt;테이블 내 칼럼에 저장된 데이터를 수정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.9147%;&quot;&gt;DELETE&lt;/td&gt;
&lt;td style=&quot;width: 14.496%;&quot;&gt;삭제&lt;/td&gt;
&lt;td style=&quot;width: 71.5892%;&quot;&gt;테이블 내 칼럼에 저장된 데이터를 삭제&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- SELECT 명령어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) SELECT 명령어 개념 : 데이터의 내용을 조회할 때 사용하는 명령어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 조인(JOIN) : 두 개 이상의 테이블을 연결하여 데이터를 검색하는 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) 서브쿼리(Sub-Query) : SQL문 안에 포함된 또 다른 SQL문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) 집합 연산자(Set Operator) ;&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;(4) INSERT(데이터 삽입) 명령어 : 데이터의 내용을 삽입할 때 사용하는 명령어이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(5) UPDATE(데이터 변경) 명령어 : 데이터의 내용을 변경할 때 사용하는 명령어이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(6) DELETE(데이터 삭제) 명령어 : 데이터의 내용을 삭제할 때 사용하는 명령어이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(4) DCL&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 제어어(DCL : Data Control Language)의 개념&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;- 데이터 제어어의 유형에는 GRANT, REVOKE 가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) GRANT(권한 부여) 명령어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) REVOKE(권한 회수) 명령어&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;02. 응용 SQL 작성하기&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[1] 집계성 SQL 작성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(1) 데이터 분석 함수의 개념&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 총합, 평균 드으이 데이터 분석을 위해서는 복수행기준의 데이터를 모아서 처리하느 ㄴ거을 목적으로 하는 다중 행 함수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(2) 데이터 분석 함수의 종류&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- SQL 표준에서는 데이터 튜플 간의 상호 연관 및 게산 분석을 위한 세 가지 함수가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;데이터 분석 함수 종류&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.2791%;&quot;&gt;함수&lt;/td&gt;
&lt;td style=&quot;width: 83.7209%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.2791%;&quot;&gt;집계 함수&lt;/td&gt;
&lt;td style=&quot;width: 83.7209%;&quot;&gt;여러 행 또는 테이블 전체 행으로부터 하나의 결괏값을 반환하는 함수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.2791%;&quot;&gt;그룹 함수&lt;/td&gt;
&lt;td style=&quot;width: 83.7209%;&quot;&gt;소그룹 간의 소계 및 중계 등의 중간 합계 분석 데이터를 산출하는 함수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.2791%;&quot;&gt;윈도 함수&lt;/td&gt;
&lt;td style=&quot;width: 83.7209%;&quot;&gt;데이터 베이스를 사용한 온라인 분석 처리 용도로 사용하기 위해서 표준 SQL에 추가된 기능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(3) 집계 함수&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(4) 그룹 함수&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(5) 윈도 함수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;03 절차형 SQL 활용하기&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[1] 절차형 SQL&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) 절차형 SQL(Procedural Language) 개념&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 절차형 SQl은 일반적인 개발 언어처럼 SQL언어에서도 절차 지향적인 프로그램이 가능하도록 하는 트랜잭션 언어이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) 절차형 SQL 종류&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;절차형 SQL종류&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.7674%;&quot;&gt;종류&lt;/td&gt;
&lt;td style=&quot;width: 65.2326%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.7674%;&quot;&gt;Procedure (프로시저)&lt;/td&gt;
&lt;td style=&quot;width: 65.2326%;&quot;&gt;일련의 쿼리들을 마치 하나의 함수처럼 실행하기 위한 쿼리의 집합&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.7674%;&quot;&gt;User-Defined Function) 사용자 정의함수&lt;/td&gt;
&lt;td style=&quot;width: 65.2326%;&quot;&gt;일련의 SQl처리를 수행하고 수행결과를 단일 값으로 반환할 수 있는 절차형 SQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.7674%;&quot;&gt;트리거 (Tirgger)&lt;/td&gt;
&lt;td style=&quot;width: 65.2326%;&quot;&gt;데이터베이스 시스템에서 삽입, 갱신, 삭제 등의 이벤트가 발생할 때마다 관련 작업이 자동으로 수행되는 절차형 SQL&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(3) 출력부&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) DBMS_OUTPUT패키지 개념&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- DBMS_OUTPUT은 메세지를 버퍼에 저장하고 버퍼로부터 메시지를 읽어오기 위한 인터페이스 패키지이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- DBMS_OUTPUT은 절차형 SQL이 정상적으로 구현되었는지 테스트하기 위한 목적으로 많이 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) DBMS_OUTPUT 패키지 종류&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DBMS_OUTPUT 패키지 종류&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.4186%;&quot;&gt;명령어&lt;/td&gt;
&lt;td style=&quot;width: 65.5814%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.4186%;&quot;&gt;DBMS_OUTPUT.PUT(문자열);&lt;/td&gt;
&lt;td style=&quot;width: 65.5814%;&quot;&gt;개행 없이 문자열을 출력하는 프로시저&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.4186%;&quot;&gt;DBMS_OUTPUT.PUT_LINE(문자열);&lt;/td&gt;
&lt;td style=&quot;width: 65.5814%;&quot;&gt;문자열을 출력 후 개행하는 프로시저&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(4) 제어부(CONTROL)&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;(1) IF문 - 조건이 참인지 것인지에 따라 경로를 선택하는 조건문이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ng5XH/btrtH0S5zDr/S1Wf6bcNPb90klshHL4vG1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ng5XH/btrtH0S5zDr/S1Wf6bcNPb90klshHL4vG1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ng5XH/btrtH0S5zDr/S1Wf6bcNPb90klshHL4vG1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fng5XH%2FbtrtH0S5zDr%2FS1Wf6bcNPb90klshHL4vG1%2Fimg.jpg&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;361&quot; height=&quot;361&quot; data-filename=&quot;1.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IF문&lt;/p&gt;
&lt;pre id=&quot;code_1645275871598&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;IF 조건 THEN 문장;

ELSIF 조건 THEN 문장;
...
ELSE 문장;

END IF;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) 간단한 케이스 문(Simple Case Expression)&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;- 범위 같은 더 복잡한 매칭을 수행하려면, 검색된 CASE문을 사용해야한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1254&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bK20jQ/btrtMJI67jx/91N4AS0NjYQSNvKKF9p3Ak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bK20jQ/btrtMJI67jx/91N4AS0NjYQSNvKKF9p3Ak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bK20jQ/btrtMJI67jx/91N4AS0NjYQSNvKKF9p3Ak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbK20jQ%2FbtrtMJI67jx%2F91N4AS0NjYQSNvKKF9p3Ak%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;375&quot; height=&quot;327&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1254&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 케이스 문&lt;/p&gt;
&lt;pre id=&quot;code_1645276252397&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CASE 변수
  WHEN 값1 THEN
   SET 명령어;
 
  WHEN 값2 THEN
   SET 명령어;
   
  ...
  
  ELSE
   SET 명령어;
 END CASE;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(3) 검색된 케이스 문(Searched Case Expression)&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;1383&quot; data-origin-height=&quot;1440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cXOvpp/btrtHVcD1dD/8PNmdzaiAjrxvap5bBSDX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cXOvpp/btrtHVcD1dD/8PNmdzaiAjrxvap5bBSDX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cXOvpp/btrtHVcD1dD/8PNmdzaiAjrxvap5bBSDX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcXOvpp%2FbtrtHVcD1dD%2F8PNmdzaiAjrxvap5bBSDX0%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;364&quot; height=&quot;379&quot; data-origin-width=&quot;1383&quot; data-origin-height=&quot;1440&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;pre id=&quot;code_1645276577885&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CASE 변수
 WHEN 조건1 THEN
  SET 명령어;
 WHEN 조건2 THEN
  SET 명령어;
...
 ELSE
  SET 명령어;
END CASE;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 반복문&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1096&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzaQlx/btrtIlbyEw7/h8iBcvVHaLErdBoHN0M1Jk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzaQlx/btrtIlbyEw7/h8iBcvVHaLErdBoHN0M1Jk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzaQlx/btrtIlbyEw7/h8iBcvVHaLErdBoHN0M1Jk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzaQlx%2FbtrtIlbyEw7%2Fh8iBcvVHaLErdBoHN0M1Jk%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;460&quot; height=&quot;350&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1096&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) LOOP 문&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- LOOP 문을 특정 조건이 만족될 때까지 반복해서 문장을 실행하는 반복문이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- EXIT WHEN에 반복문 탈출 조건을 작성한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LOOP문&lt;/p&gt;
&lt;pre id=&quot;code_1645278065970&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;LOOP
 문장;
 EXIT WHEN 탈출조건;
END LOOP;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) WHILE 문&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- WHLE 문은 시작과 종료 조건을 지정하여 참인 동안에는 해당 문장을 반복해서 실행하는 명령문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- WHILE 문은 조건이 참일 경우 반복하고 조건이 거짓이거나 EXIT 조건이 만족하는 경우 반복문을 빠져나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WHILE 문&lt;/p&gt;
&lt;pre id=&quot;code_1645278204714&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;WHILE 반복조건 LOOP
 문장;
EXIT WHEN 탈출조건;

END LOOP;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(3) FOR LOOP문&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- FOR LOOP 문을 시작 값과 끝값을 지정하여 해당 값이 그 구간 내에 있을 때 반복하는 반목문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FOR LOOP문&lt;/p&gt;
&lt;pre id=&quot;code_1645278286435&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FOR 인덱스 IN 시작값 ... 종료값
LOOP 문장;
END LOOP;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(5) 예외부(EXCEPTION)&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;pre id=&quot;code_1645278453818&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;EXCEPTION
  WHEN 조건 THEN
    SET명령어;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[2] 프로시저&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) Procedure 개념&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;(2) 프로시저 구성&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.4651%;&quot;&gt;구성요소&lt;/td&gt;
&lt;td style=&quot;width: 79.5349%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.4651%;&quot;&gt;DECLARE (선언부)&lt;/td&gt;
&lt;td style=&quot;width: 79.5349%;&quot;&gt;- 프로시저의 명칭, 변수와 인수, 그에 대한데이터 타입을 정의하는 부분&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.4651%;&quot;&gt;BEGIN/END &lt;br /&gt;(시작/종료부)&lt;/td&gt;
&lt;td style=&quot;width: 79.5349%;&quot;&gt;- 프로시저의 시작, 종료를 표현&lt;br /&gt;- 다수 실행을 제어하는 기본적 단위가 되며 논리적 프로세스를 구성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.4651%;&quot;&gt;SQL&lt;/td&gt;
&lt;td style=&quot;width: 79.5349%;&quot;&gt;- DML을 주로 사용&lt;br /&gt;- 자주 사용되지 않지만 DDL중 TRUNCATE 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.4651%;&quot;&gt;EXCEPTION (예외부)&lt;/td&gt;
&lt;td style=&quot;width: 79.5349%;&quot;&gt;BEGIN~END 절에서 실행되는 SQL문이 실행될 때 예외 발생 시 예외 처리 방법을 정리하는 처리부&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.4651%;&quot;&gt;TRANSACTION &lt;br /&gt;(실행부)&lt;/td&gt;
&lt;td style=&quot;width: 79.5349%;&quot;&gt;- 프로시저에서 수행된 DML 수행 내역의 DBMS의 적용 또는 취소 여부를 결정하는 처리부&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(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;pre id=&quot;code_1645278996345&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE [OR REPLACE] 프로시저_명
(파라미터_명 [IN | OUT | INOUT] 데이터_타입, ...)
IS
 변수 선언
BEGIN
 명령어;
[COMMIT | ROLLBACK]

END;&lt;/code&gt;&lt;/pre&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.7208%;&quot;&gt;구성&lt;/td&gt;
&lt;td style=&quot;width: 76.2792%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.7208%;&quot;&gt;[OR REPLACE]&lt;/td&gt;
&lt;td style=&quot;width: 76.2792%;&quot;&gt;기존 프로시저 존재 시에 현재 컴파일하는 내용으로 덮어씀&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.7208%;&quot;&gt;모드 ([IN | OUT | INOUT])&lt;/td&gt;
&lt;td style=&quot;width: 76.2792%;&quot;&gt;변수의 입출력을 구분하고 IN/OUT/ 3가지로 구성&lt;br /&gt;&lt;br /&gt;IN : 운영체제에서 프로시저로 값을 전달하는 모드&lt;br /&gt;OUT : 프로시저에서 처리된 결과를 운영체제로 전달하는 모드&lt;br /&gt;INOUT : IN 과 OUT의 두가지 기능을동시에 수행하는 모드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.7208%;&quot;&gt;BEGIN&lt;/td&gt;
&lt;td style=&quot;width: 76.2792%;&quot;&gt;프로시저의 시작을 알려주는 키워드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.7208%;&quot;&gt;COMMIT&lt;/td&gt;
&lt;td style=&quot;width: 76.2792%;&quot;&gt;하나의 트랜잭션이 성공적으로 끝내고 데이터베이스가 일관성 있는상태에 있을 때&amp;nbsp;&lt;br /&gt;하나의 트랜잭션이 끝났을 때 사용하는 연산&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.7208%;&quot;&gt;ROLLBACK&lt;/td&gt;
&lt;td style=&quot;width: 76.2792%;&quot;&gt;하나의 트랜잭션이 비정상적으로 종료되어 트랜잭션 원자성이 깨질 경우 처음부터&lt;br /&gt;다시 시작하거나 부분적으로 연산을 취소하는 연산&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.7208%;&quot;&gt;END&lt;/td&gt;
&lt;td style=&quot;width: 76.2792%;&quot;&gt;프로시저의 끝을 알려주는 키워드&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(4) 프로시저 호출문 작성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- SQL TOOL 을 활용하여 직접 실행시키는 경우에는 EXECUTE 또는 EXEC 명령어를 이용하여 프로시저를 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 프로시저에 입출력 변수가 존재하는 경우 변수를 입력하여 실행해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터 유형의 경우 자동 변환이 되어 별도 오류가 발생하지 않은 경우가 많지만 가급적 프로시저에서선언한 데이터 타입과 동일하게 입출력 벼수를넣어서 실행하는 것이 좋다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로시저 호출문 작성&lt;/p&gt;
&lt;pre id=&quot;code_1645280880038&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SQL &amp;gt; EXECUTE 프로시저_명 (파라미터_1, 파라미터_2, ...);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[3] 사용자 정의함수&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) 사용자 정의 함수(User-Defined Function) 개념&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 사용자 정의함수는 일련의 SQL처리를 수행하고, 수행 결과를 단일 값으로 반환할 수 있는 절차형 SQL이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;- 기본적인 사항은 프로시저와 동일하고 반환에서의 부분만 프로시저와 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 사용자 정의함수의 호출을 통해 실행되며, 바환되는 단일 값을 조회 또는 삽입, 수정 작업에 이용하는 것이 일반적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 기본적인 개념 및 사용법, 문법 등은 프로시저와 동일하며, 종료 시 단일 값을 반환한다는 것이 프로시저와의 가장 큰 차이점이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자 정의함수 구성&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.8373%;&quot;&gt;구성요소&lt;/td&gt;
&lt;td style=&quot;width: 76.1627%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.8373%;&quot;&gt;선언부(DECLARE)&lt;/td&gt;
&lt;td style=&quot;width: 76.1627%;&quot;&gt;- 사용자 정의함수의 명칭, 변수와 인수 그리고 그에 대한 데이타입을 정하는 부분&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.8373%;&quot;&gt;시작/종료부(BEGIN/END)&lt;/td&gt;
&lt;td style=&quot;width: 76.1627%;&quot;&gt;- 사용자 정의함수의 시작과 종료를 표현하는데 필수적이며, BEGIN/END가 쌍을 이루어 추가되므로 블록으로 구성&lt;br /&gt;&lt;br /&gt;- 다수 실행을 제어하는 기본적 단위가되며논리적 프로세스를 구성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.8373%;&quot;&gt;제어부(CONTROL)&lt;/td&gt;
&lt;td style=&quot;width: 76.1627%;&quot;&gt;- 기본적으로는 순차적으로 처리&lt;br /&gt;- 비교 조건에 따라 블록 또는 문장을 실행&lt;br /&gt;- 조건에 따라 반복 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.8373%;&quot;&gt;SQL&lt;/td&gt;
&lt;td style=&quot;width: 76.1627%;&quot;&gt;- 조회 용도로 SELECT 문을 사용&lt;br /&gt;- 데이터를 조작하는 INSERT, DELETE, UPDATE는 사용할 수 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.8373%;&quot;&gt;예외부(EXCEPTION)&lt;/td&gt;
&lt;td style=&quot;width: 76.1627%;&quot;&gt;- BEGIN~END 절에서 실행되는 SQL 문이 실행될 때 예외 발생 시 예외 처리하는 방법을정의하는 처리부&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.8373%;&quot;&gt;반환부(RETURN)&lt;/td&gt;
&lt;td style=&quot;width: 76.1627%;&quot;&gt;- 호출문에 대한 함숫값을 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(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;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[4] 트리거&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) Trigger 개념&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 트리거는 데이터베이스 시스템에서 삽입, 갱신, 삭제 등의 이벤트가 발생할 때마다 관련 작업이 자동으로 수행되는 절차형SQL이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이벤트는 전체 트랜잭션 대상과 각행에 의해 발생하는 경우 모두를 포함할 수 있으며 테이블과 뷰, DB 작업을 대상으로 정의할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) 트리거의 목적&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 특정 테이블에 대한 데이터 변경을 시작점으로 설정하고, 그와 관련된 작업을 자동적으로 수행하기 위해 트리거를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 일반적으로 이벤트와 관련된 테이블의 데이터 삽입, 추가, 삭제 작업을 DBMS가 자동적으로 실행시키는 데 활용한다.&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;(3) 트리거의 종류&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-트리거의 종류는 행 트리거 , 문장 트리거가 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;(4) 트리거의 구성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 프로시저나 사용자 정의함수와 기본적 문법은 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 반환 값이 없다는 점, DML을 주된 목적으로 한다는 점에서는 프로시저와 유사하다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- EVENT 명령어를 통해 트리거 실행을 위한 이벤트를 인지한다는 점, 외부 변수 IN/OUT이 없다는 점은 프로시저나 사용자 정의함수와 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;트리거 문법&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.1395%;&quot;&gt;구성&lt;/td&gt;
&lt;td style=&quot;width: 76.8605%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.1395%;&quot;&gt;[OR REPLACE]&lt;/td&gt;
&lt;td style=&quot;width: 76.8605%;&quot;&gt;기존 트리거 존재 시에 현재 컴파일하는 내용으로 덮어씀&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.1395%;&quot;&gt;순서 ([BEFORE | AFTER])&lt;/td&gt;
&lt;td style=&quot;width: 76.8605%;&quot;&gt;DML과 트리거가 실행되는 순서의 전후 관계를 BEFORE, AFTER키워드를 이용하여 결정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.1395%;&quot;&gt;유형&lt;/td&gt;
&lt;td style=&quot;width: 76.8605%;&quot;&gt;- DML에 해당되는 INSERT, UPDATE, DELETE 중 트리거를 수행할 명령어 유행을 선택&lt;br /&gt;- INSERT, UPDATE, DELETE는 여러 개 중복으로 선택이 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.1395%;&quot;&gt;FOR EACH ROW&lt;/td&gt;
&lt;td style=&quot;width: 76.8605%;&quot;&gt;매번 변경되는 데이터 행의 수만큼 실행을 위한 명령어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.1395%;&quot;&gt;BEGIN&lt;/td&gt;
&lt;td style=&quot;width: 76.8605%;&quot;&gt;트리거의 시작을 알려주는 키워드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.1395%;&quot;&gt;END&lt;/td&gt;
&lt;td style=&quot;width: 76.8605%;&quot;&gt;트리거의 끝을 알려주는 키워드&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 행 트리거 안에서 OLD 및 NEW 수식자 접두어를 붙여 데이터 변경 전후 열의 값을 참조한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리거 SQL중 접두어&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.9612%;&quot;&gt;데이터 작업&lt;/td&gt;
&lt;td style=&quot;width: 22.7519%;&quot;&gt;OLD&lt;/td&gt;
&lt;td style=&quot;width: 57.2868%;&quot;&gt;NEW&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.9612%;&quot;&gt;INSERT&lt;/td&gt;
&lt;td style=&quot;width: 22.7519%;&quot;&gt;NULL&lt;/td&gt;
&lt;td style=&quot;width: 57.2868%;&quot;&gt;삽입된 값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.9612%;&quot;&gt;UPDATE&lt;/td&gt;
&lt;td style=&quot;width: 22.7519%;&quot;&gt;갱신 전의 값&lt;/td&gt;
&lt;td style=&quot;width: 57.2868%;&quot;&gt;갱신 후의 값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.9612%;&quot;&gt;DELETE&lt;/td&gt;
&lt;td style=&quot;width: 22.7519%;&quot;&gt;삭제 전의 값&lt;/td&gt;
&lt;td style=&quot;width: 57.2868%;&quot;&gt;NULL&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(6) 트리거 작성 시 주의 사항&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 15.5814%;&quot;&gt;주의사항&lt;/td&gt;
&lt;td style=&quot;width: 84.4186%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 15.5814%;&quot;&gt;TCL 사용 불가&lt;/td&gt;
&lt;td style=&quot;width: 84.4186%;&quot;&gt;트리거 내에는 COMMIT, ROLLBACK 등의 트랜잭션 제어어 사용 시 컴파일 에러 발생&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 15.5814%;&quot;&gt;오류에 주의&lt;/td&gt;
&lt;td style=&quot;width: 84.4186%;&quot;&gt;- 트리거 실행 중 오류가 발생하게 되면 트리거 실행의 원인을 제공한 데이터 작업에도 영향&lt;br /&gt;- 특정 테이블에 데이터를 추가한 후 발생하는 트리거에서 오류가 발생할 경우에는 트리거 이후의 작업이 진행되지 않거나 데이터가 추가되지않음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;04 데이터 조작 프로시저 최적화&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[1] 데이터 조작 프로시저 성능개선&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) 쿼리 성능 개선(튜닝)의 개념&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 쿼리 성능 개선은 데이터베이스에서 프로시저에 있는 SQL 시랳ㅇ 계획을 분석, 수정을 통해 최소의 시간으로 원한느 결과를 얻도록 프로시저를 수정하는 작업이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- SQL 성능 개선을 통해 데이터 조작 프로시저의 성능 개선이 가능하다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) 쿼리 성능 개선 절차&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQL 성능 개선 절차&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 6.24031%;&quot;&gt;순서&lt;/td&gt;
&lt;td style=&quot;width: 21.7054%;&quot;&gt;절차&lt;/td&gt;
&lt;td style=&quot;width: 72.0542%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 6.24031%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 21.7054%;&quot;&gt;문제있는 SQL 식별&lt;/td&gt;
&lt;td style=&quot;width: 72.0542%;&quot;&gt;문제 있는 SQL을 식별하기 위해 애플리케이션의 성능을 관리 및 모니터링 도구인 APM등을 활용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 6.24031%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 21.7054%;&quot;&gt;옵티마이저 통계 확인&lt;/td&gt;
&lt;td style=&quot;width: 72.0542%;&quot;&gt;옵티마이저는 개발자가 작성한SQL을 가장&amp;nbsp; 빠르고 효율적으로 수행할 최적의 처리 경로를 생성해주는 데이터베이스 핵심모듈&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 6.24031%;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 21.7054%;&quot;&gt;SQL 문 재구성&lt;/td&gt;
&lt;td style=&quot;width: 72.0542%;&quot;&gt;- 범위가 아닌 특정 값 지정으로 범위를 줄여 처리 속도를 빠르게 함&lt;br /&gt;- 옵티마이저가 비정상적인 실행계획을 수립할 경우, 힌트로서 옵티마이저의 접근 경로 및 조인 순서를 제어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 6.24031%;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;width: 21.7054%;&quot;&gt;인덱스 재구성&lt;/td&gt;
&lt;td style=&quot;width: 72.0542%;&quot;&gt;- 성능에 중요한 액세스 경로를 고려하여 인덱스 생성&lt;br /&gt;- 실행계획을 검토하여 기존 인덱스의 열 순서를 변경/추가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 6.24031%;&quot;&gt;5&lt;/td&gt;
&lt;td style=&quot;width: 21.7054%;&quot;&gt;실행계획 유지관리&lt;/td&gt;
&lt;td style=&quot;width: 72.0542%;&quot;&gt;- 데이터베이스 버전 업그레이드, 데이터 전환 등 시스템 환경의 변경 사항 발생 시에도 실행 계획이 유지되고 있는 지 관리&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(3) 옵티마이저 통계 확인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 옵티마이저(Optimizer)의 개념&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- SQL을 가장빠르고 효율적으로 수행할 최적의 처리경로를 생성해주는 DBMS 내부의 핵심엔진이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 옵티마이저가 생성한 SQL 처리경로를 실행계획이라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 옵티마이저의 유형&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 옵티마이저의 유형으로는 RBO, CBO가 있다.&lt;/p&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;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.2791%;&quot;&gt;비교&lt;/td&gt;
&lt;td style=&quot;width: 47.4418%;&quot;&gt;규칙기반 옵티마이저(RBO)&lt;/td&gt;
&lt;td style=&quot;width: 41.2791%;&quot;&gt;비용기반 옵티마이저(CBO)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.2791%;&quot;&gt;개념&lt;/td&gt;
&lt;td style=&quot;width: 47.4418%;&quot;&gt;통계 정보가 없는 상태에서 사전 등록된 규칙에 따라 질의 실행 계획을 선택하는 옵티마이저&lt;/td&gt;
&lt;td style=&quot;width: 41.2791%;&quot;&gt;통계 정보로부터 모든 접근 결로를 고려한 질의실행계획을 선택하는 옵티마이저&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.2791%;&quot;&gt;핵심&lt;/td&gt;
&lt;td style=&quot;width: 47.4418%;&quot;&gt;규칙(우선 순위)기반&lt;/td&gt;
&lt;td style=&quot;width: 41.2791%;&quot;&gt;비용(수행 시간)기반&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.2791%;&quot;&gt;평가 기준&lt;/td&gt;
&lt;td style=&quot;width: 47.4418%;&quot;&gt;인덱스 구조, 연산자, 조건절 형태 등&lt;/td&gt;
&lt;td style=&quot;width: 41.2791%;&quot;&gt;레코드 개수, 블록 개수, 평균 행 길이 컬럼 값의 수, 컬럼 값 분포, 인덱스 높이, 클러스터링 팩터 등&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.2791%;&quot;&gt;장점&lt;/td&gt;
&lt;td style=&quot;width: 47.4418%;&quot;&gt;사용자가 원하는 처리경로로 유도하기가 쉬움&lt;/td&gt;
&lt;td style=&quot;width: 41.2791%;&quot;&gt;옵티마이저의 이해도가 낮아도 성능보장 가능&lt;br /&gt;(기본설정)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) SQL수행과정 내 옵티마이저역할&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;SQL수행 시 옵티마이저 역할&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.6511%;&quot;&gt;서브엔진&lt;/td&gt;
&lt;td style=&quot;width: 80.3489%;&quot;&gt;역할&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.6511%;&quot;&gt;Query Transformer&lt;/td&gt;
&lt;td style=&quot;width: 80.3489%;&quot;&gt;- SQL을 좀 더 일반적이고 표준화된 형태로 변환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.6511%;&quot;&gt;Estimator&lt;/td&gt;
&lt;td style=&quot;width: 80.3489%;&quot;&gt;- 쿼리 명령어 각 단계의 선택도, 카디널리티, 비용을 계산&lt;br /&gt;- 궁극적으로 실행계획 전체에 대한 총비용 계산&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.6511%;&quot;&gt;Plan Generator&lt;/td&gt;
&lt;td style=&quot;width: 80.3489%;&quot;&gt;- 하나의 쿼리를 수행 시 후보군이 될 만한 실행계획들을 생성해내는 역할&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) 힌트 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- SQL 성능 개선의 핵심 부분으로 옵티마이저의 실행 계획을 원하는 대로 변경할 수 있게 한다.&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;pre id=&quot;code_1645285600901&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT /*+RULE*/ ENAME, SAL FROM EMP WHERE EMPNO &amp;gt; 9000;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 비용 기반 옵티마이저에서 규칙기반 옵티마이저모드로 변경 수행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주요 옵티마이저 힌트&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 99.6512%; height: 315px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.8785%;&quot;&gt;힌트&lt;/td&gt;
&lt;td style=&quot;width: 66.1215%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.8785%;&quot;&gt;/* +RULE */&lt;/td&gt;
&lt;td style=&quot;width: 66.1215%;&quot;&gt;규칙 기반 접근 방식을 사용하도록 지정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.8785%;&quot;&gt;/* +CHOOSE */&lt;/td&gt;
&lt;td style=&quot;width: 66.1215%;&quot;&gt;오라클 옵티마이저 디폴트 값에 따름&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.8785%;&quot;&gt;/* +INDEX(테이블명 인덱스명) */&lt;/td&gt;
&lt;td style=&quot;width: 66.1215%;&quot;&gt;지정된 인덱스를 강제적으로 사용하도록 지정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.8785%;&quot;&gt;/* +USER_HASH(테이블명) */&lt;/td&gt;
&lt;td style=&quot;width: 66.1215%;&quot;&gt;지정된 테이블의 조인이 Hash Join 형식으로 일어나도록 유도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.8785%;&quot;&gt;/* +USER_MERGE(테이블명) */&lt;/td&gt;
&lt;td style=&quot;width: 66.1215%;&quot;&gt;지정된 테이블들의 조인이 Sort Merge형식으로일어나동록 유도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.8785%;&quot;&gt;/* +USER_NL(테이블명) */&lt;/td&gt;
&lt;td style=&quot;width: 66.1215%;&quot;&gt;지정된 테이블들의 조인이 Nested Loop 형식으로 일어나도록 유도&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(4) SQL 문 재구성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- SQL 문의 성능개선을 위해 재구성가이드를 참고하여 쿼리를 재구성한다&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.9768%;&quot;&gt;구성 가이드&lt;/td&gt;
&lt;td style=&quot;width: 78.0232%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.9768%;&quot;&gt;특정 값 지정&lt;/td&gt;
&lt;td style=&quot;width: 78.0232%;&quot;&gt;- 조건절의 &amp;gt; 또는 &amp;lt; 가 아닌 = 을 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.9768%;&quot;&gt;별도의 SQL 사용&lt;/td&gt;
&lt;td style=&quot;width: 78.0232%;&quot;&gt;- 다양한 작업에 대해 하나의 SQL문을 사용할 경우 각 작업에 최적화 되지않은 결과 발생&lt;br /&gt;- 하나의 SQL문 사용 시 UNION ALL 연산자를 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.9768%;&quot;&gt;힌트 사용&lt;/td&gt;
&lt;td style=&quot;width: 78.0232%;&quot;&gt;- 옵티마이저가 비정상적인 실행 계획을 수립 시 힌트로서 액세스 경로 및 조인 순서를 제어할 수 있도록 함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.9768%;&quot;&gt;HAVING 미사용&lt;/td&gt;
&lt;td style=&quot;width: 78.0232%;&quot;&gt;- 인덱스가 걸려잇는 컬럼은 HAVING사용 시 인덱스 미사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.9768%;&quot;&gt;인덱스만 질의 사용&lt;/td&gt;
&lt;td style=&quot;width: 78.0232%;&quot;&gt;가능한 인덱스만 이용해 질의를 수행하여 옵티마이저가 최적의 경로를 찾도록 유도&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(5) 인덱스 재구성&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;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.093%;&quot;&gt;구성 가이드&lt;/td&gt;
&lt;td style=&quot;width: 77.907%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.093%;&quot;&gt;자주 쓰는 컬럼 선정&lt;/td&gt;
&lt;td style=&quot;width: 77.907%;&quot;&gt;조건절에 항상 사용되거나, 자주 사용되는 컬럼 설정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.093%;&quot;&gt;SORT명령어 생략&lt;/td&gt;
&lt;td style=&quot;width: 77.907%;&quot;&gt;SORT명령어를 생략하기 위한 컬럼을 추가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.093%;&quot;&gt;분포도를 고려&lt;/td&gt;
&lt;td style=&quot;width: 77.907%;&quot;&gt;분포도가 좋은 컬럼은 단독으로 인덱스를 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.093%;&quot;&gt;변경 적은 컬럼 선정&lt;/td&gt;
&lt;td style=&quot;width: 77.907%;&quot;&gt;데이터의 변경이 적은 컬럼에 인덱스를 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.093%;&quot;&gt;결합 인덱스 사용&lt;/td&gt;
&lt;td style=&quot;width: 77.907%;&quot;&gt;인덱스들이 자주 조합될 때는 결합 인덱스를 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[출저] 수제비 2021...! 정보처리기사 실기&lt;/p&gt;</description>
      <category>정보처리기사</category>
      <category>SQL</category>
      <category>SQL응용</category>
      <category>데이터베이스</category>
      <category>사용자정의함수</category>
      <category>정보처리기사</category>
      <category>정보처리기사 실기</category>
      <category>트랜잭션</category>
      <category>트리거</category>
      <category>프로시저</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/59</guid>
      <comments>https://thfdl0317.tistory.com/entry/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%EC%8B%A4%EA%B8%B0-07-SQL-%EC%9D%91%EC%9A%A9-01-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4%EC%9D%98-%EA%B8%B0%EB%B3%B8#entry59comment</comments>
      <pubDate>Thu, 17 Feb 2022 18:20:46 +0900</pubDate>
    </item>
    <item>
      <title>Spring Boot Security - NAVER(네이버) 로그인 완료하기</title>
      <link>https://thfdl0317.tistory.com/entry/Spring-Boot-Security-NAVER%EB%84%A4%EC%9D%B4%EB%B2%84-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EC%99%84%EB%A3%8C%ED%95%98%EA%B8%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developers.naver.com/main/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developers.naver.com/main/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1644410788076&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;NAVER Developers&quot; data-og-description=&quot;네이버 오픈 API들을 활용해 개발자들이 다양한 애플리케이션을 개발할 수 있도록 API 가이드와 SDK를 제공합니다. 제공중인 오픈 API에는 네이버 로그인, 검색, 단축URL, 캡차를 비롯 기계번역, 음&quot; data-og-host=&quot;developers.naver.com&quot; data-og-source-url=&quot;https://developers.naver.com/main/&quot; data-og-url=&quot;https://developers.naver.com/main&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/70Sty/hyNmA6wOjk/gl7ds8noIYmaurVJbnliu0/img.jpg?width=940&amp;amp;height=492&amp;amp;face=0_0_940_492,https://scrap.kakaocdn.net/dn/b1gl41/hyNmxaTfNf/Co95YaDzqZWklaZQwEBWk0/img.jpg?width=940&amp;amp;height=492&amp;amp;face=0_0_940_492&quot;&gt;&lt;a href=&quot;https://developers.naver.com/main/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developers.naver.com/main/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/70Sty/hyNmA6wOjk/gl7ds8noIYmaurVJbnliu0/img.jpg?width=940&amp;amp;height=492&amp;amp;face=0_0_940_492,https://scrap.kakaocdn.net/dn/b1gl41/hyNmxaTfNf/Co95YaDzqZWklaZQwEBWk0/img.jpg?width=940&amp;amp;height=492&amp;amp;face=0_0_940_492');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;NAVER Developers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;네이버 오픈 API들을 활용해 개발자들이 다양한 애플리케이션을 개발할 수 있도록 API 가이드와 SDK를 제공합니다. 제공중인 오픈 API에는 네이버 로그인, 검색, 단축URL, 캡차를 비롯 기계번역, 음&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developers.naver.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1225&quot; data-origin-height=&quot;305&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CK829/btrsWVcMHMr/mGnjAjxi0S5EdHSTFfD2pk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CK829/btrsWVcMHMr/mGnjAjxi0S5EdHSTFfD2pk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CK829/btrsWVcMHMr/mGnjAjxi0S5EdHSTFfD2pk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCK829%2FbtrsWVcMHMr%2FmGnjAjxi0S5EdHSTFfD2pk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;752&quot; height=&quot;188&quot; data-origin-width=&quot;1225&quot; data-origin-height=&quot;305&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;908&quot; data-origin-height=&quot;884&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bg2Ubf/btrsYGMHx6z/Pcx3NYrmX0Y0Om9W3gqB91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bg2Ubf/btrsYGMHx6z/Pcx3NYrmX0Y0Om9W3gqB91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bg2Ubf/btrsYGMHx6z/Pcx3NYrmX0Y0Om9W3gqB91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbg2Ubf%2FbtrsYGMHx6z%2FPcx3NYrmX0Y0Om9W3gqB91%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;742&quot; height=&quot;722&quot; data-origin-width=&quot;908&quot; data-origin-height=&quot;884&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;634&quot; data-origin-height=&quot;238&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mAuK2/btrsYcSxFZJ/f22v2VDYfTMjQ6gcTMHWX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mAuK2/btrsYcSxFZJ/f22v2VDYfTMjQ6gcTMHWX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mAuK2/btrsYcSxFZJ/f22v2VDYfTMjQ6gcTMHWX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmAuK2%2FbtrsYcSxFZJ%2Ff22v2VDYfTMjQ6gcTMHWX1%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;565&quot; height=&quot;212&quot; data-origin-width=&quot;634&quot; data-origin-height=&quot;238&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;867&quot; data-origin-height=&quot;795&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/euCEWE/btrsTcT3Too/pADEhr3YkgdlyLU1PvyKI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/euCEWE/btrsTcT3Too/pADEhr3YkgdlyLU1PvyKI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/euCEWE/btrsTcT3Too/pADEhr3YkgdlyLU1PvyKI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeuCEWE%2FbtrsTcT3Too%2FpADEhr3YkgdlyLU1PvyKI0%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;699&quot; height=&quot;640&quot; data-origin-width=&quot;867&quot; data-origin-height=&quot;795&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;application.yml&lt;/p&gt;
&lt;pre id=&quot;code_1644411394970&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    naver:
     client-id:아직모름
     client-secret:아직모름
     scope:
     -name
     -email
     client-name:Naver
     authorization-grant-type:authorization_code
     redirect-uri:http://localhost:8080/login/oauth2/code/naver ------&amp;gt;  고대로 넣어주기&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;958&quot; data-origin-height=&quot;402&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lRcge/btrsVKW3Qag/YKQTMTZYeteugWC644R0k1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lRcge/btrsVKW3Qag/YKQTMTZYeteugWC644R0k1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lRcge/btrsVKW3Qag/YKQTMTZYeteugWC644R0k1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlRcge%2FbtrsVKW3Qag%2FYKQTMTZYeteugWC644R0k1%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;645&quot; height=&quot;271&quot; data-origin-width=&quot;958&quot; data-origin-height=&quot;402&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;application.yml&lt;/p&gt;
&lt;pre id=&quot;code_1644411561184&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    naver:
     client-id:htghxb0Uip50vz6twKLC ------&amp;gt; 넣어주기
     client-secret:MJRTzZ2D5D ------------&amp;gt; 넣어주기
     scope:
     -name
     -email
     client-name:Naver
     authorization-grant-type:authorization_code
     redirect-uri:http://localhost:8080/login/oauth2/code/naver&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 오류가 발생되게 되는데,&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;897&quot; data-origin-height=&quot;57&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQPDu2/btrsYd40wfa/pkpWsuD2pH817Qh0phZvRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQPDu2/btrsYd40wfa/pkpWsuD2pH817Qh0phZvRk/img.png&quot; data-alt=&quot;네이버라는 registration이 없다고 나온다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQPDu2/btrsYd40wfa/pkpWsuD2pH817Qh0phZvRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQPDu2%2FbtrsYd40wfa%2FpkpWsuD2pH817Qh0phZvRk%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;704&quot; height=&quot;45&quot; data-origin-width=&quot;897&quot; data-origin-height=&quot;57&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;네이버라는 registration이 없다고 나온다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;application.yml&lt;/p&gt;
&lt;pre id=&quot;code_1644412245049&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  naver:
     client-id:htghxb0Uip50vz6twKLC
     client-secret:MJRTzZ2D5D
     scope:
     -name
     -email
     client-name:Naver
     authorization-grant-type:authorization_code
     redirect-uri:http://localhost:8080/login/oauth2/code/naver
   
     provider:
      naver:
       authorization-uri:https://nid.naver.com/ouath2.0/authorze
       token-uri:https://nid.naver.com/oauth2.0/token
       user-info-uri:https://openapi.naver.com/v1/nid/me
       user-name-attribute:resposne #회원정보를 JSON으로 받은데 RESPONSE라는 키값으로 네이버를 리턴해줌&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;810&quot; data-origin-height=&quot;265&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjCG53/btrsXs9aRAv/1EKP2dtoQDA331T0dNxXSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjCG53/btrsXs9aRAv/1EKP2dtoQDA331T0dNxXSk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjCG53/btrsXs9aRAv/1EKP2dtoQDA331T0dNxXSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjCG53%2FbtrsXs9aRAv%2F1EKP2dtoQDA331T0dNxXSk%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;688&quot; height=&quot;225&quot; data-origin-width=&quot;810&quot; data-origin-height=&quot;265&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요기 주소로 로그인하면 네이버창이 뜬다는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;loginForm.html&lt;/p&gt;
&lt;pre id=&quot;code_1644412454623&quot; class=&quot;xml&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;h1&amp;gt;로그인 페이지&amp;lt;/h1&amp;gt;

&amp;lt;form action=&quot;/login&quot; method=&quot;POST&quot;&amp;gt;

	&amp;lt;input type=&quot;text&quot; name=&quot;username&quot; placeholder=&quot;username&quot;&amp;gt;&amp;lt;br/&amp;gt;
	&amp;lt;input type=&quot;password&quot; name=&quot;password&quot; placeholder=&quot;password&quot;&amp;gt;&amp;lt;br/&amp;gt;

&amp;lt;button&amp;gt;로그인&amp;lt;/button&amp;gt;
&amp;lt;/form&amp;gt;

&amp;lt;a href=&quot;/oauth2/authorization/google&quot;&amp;gt;구글 로그인&amp;lt;/a&amp;gt;
&amp;lt;a href=&quot;/oauth2/authorization/fackbook&quot;&amp;gt;페이스북 로그인&amp;lt;/a&amp;gt;
&amp;lt;a href=&quot;/oauth2/authorization/naver&quot;&amp;gt;네이버 로그인&amp;lt;/a&amp;gt;
&amp;lt;a href=&quot;/joinForm&quot;&amp;gt;회원가입을 아직 하지 않으셨나요?&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[참고] 인프런 - &lt;span style=&quot;background-color: #ffffff;&quot;&gt;스프링부트 시큐리티 &amp;amp; JWT 강의&lt;/span&gt;&lt;/p&gt;</description>
      <category>Back-end/Spring Boot Security</category>
      <category>spring</category>
      <category>spring boot</category>
      <category>spring boot security</category>
      <category>스프링</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/57</guid>
      <comments>https://thfdl0317.tistory.com/entry/Spring-Boot-Security-NAVER%EB%84%A4%EC%9D%B4%EB%B2%84-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EC%99%84%EB%A3%8C%ED%95%98%EA%B8%B0#entry57comment</comments>
      <pubDate>Wed, 9 Feb 2022 22:15:06 +0900</pubDate>
    </item>
    <item>
      <title>Spring Boot Security - 구글 로그인 및 자동 회원가입 진행 완료</title>
      <link>https://thfdl0317.tistory.com/entry/Spring-Boot-Security-%EA%B5%AC%EA%B8%80-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EB%B0%8F-%EC%9E%90%EB%8F%99-%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85-%EC%A7%84%ED%96%89-%EC%99%84%EB%A3%8C</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;저번시간에는&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Authentication 안에 들어갈 수 있는 두개의 타입인&amp;nbsp;&amp;nbsp;&lt;br /&gt;UserDetails와 OAuth2User을 하나로 묶어서(PrincipalDetails) 처리하는 번거로움을 개선하려했었으며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 PrincipalDetails 타입으로 묶고 구글 로그인과 자동 회원가입진행을 완료하는 것을 목표로 진행할 예정이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1693&quot; data-origin-height=&quot;960&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dcdLkN/btrsSuTKlGJ/tL0wY8USs3Htq1K9FcbGEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dcdLkN/btrsSuTKlGJ/tL0wY8USs3Htq1K9FcbGEk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dcdLkN/btrsSuTKlGJ/tL0wY8USs3Htq1K9FcbGEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdcdLkN%2FbtrsSuTKlGJ%2FtL0wY8USs3Htq1K9FcbGEk%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;731&quot; height=&quot;414&quot; data-origin-width=&quot;1693&quot; data-origin-height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회원가입을 하면 어떤 오브젝트가 필요하냐면 User오브젝트가 필요한데, 둘 다 user오브젝트를 찾을 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 PrincipalDetails을 만들고 UserDetails를 implements 해서 User오프젝트를 품는다.&lt;br /&gt;그러면 어차피 UserDetails Authentication에 넣을 수 있으니 UserDetails를 principalDetails로 바꿔서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;User오브젝트에 접근가능하다. 근데,&amp;nbsp;내가&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OAuth2User로&amp;nbsp;로그인하면&amp;nbsp;OAuth2User,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UserDetails로&amp;nbsp;로그인하면&amp;nbsp;principalDetails가&amp;nbsp;나오기&amp;nbsp;때문에&amp;nbsp;프로그램&amp;nbsp;처리가&amp;nbsp;복잡해진다.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;따라서&amp;nbsp;이&amp;nbsp;OAuth2User도&amp;nbsp;principalDetails에&amp;nbsp;넣어서&amp;nbsp;이&amp;nbsp;둘을&amp;nbsp;묶어버린다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[참고] 인프런 - &lt;span style=&quot;background-color: #ffffff;&quot;&gt;스프링부트 시큐리티 &amp;amp; JWT 강의&lt;/span&gt;&lt;/p&gt;</description>
      <category>Back-end/Spring Boot Security</category>
      <category>Authentication</category>
      <category>Oauth2User</category>
      <category>principalDetails</category>
      <category>security</category>
      <category>spring</category>
      <category>spring boot</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/55</guid>
      <comments>https://thfdl0317.tistory.com/entry/Spring-Boot-Security-%EA%B5%AC%EA%B8%80-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EB%B0%8F-%EC%9E%90%EB%8F%99-%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85-%EC%A7%84%ED%96%89-%EC%99%84%EB%A3%8C#entry55comment</comments>
      <pubDate>Wed, 9 Feb 2022 10:42:00 +0900</pubDate>
    </item>
    <item>
      <title>Spring Boot Security - Authentication 객체가 가질 수 있는 2가지 타입</title>
      <link>https://thfdl0317.tistory.com/entry/Spring-Boot-Security-Authentication-%EA%B0%9D%EC%B2%B4%EA%B0%80-%EA%B0%80%EC%A7%88-%EC%88%98-%EC%9E%88%EB%8A%94-2%EA%B0%80%EC%A7%80-%ED%83%80%EC%9E%85</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;getClientRegistration 에는 서버에 기본 정보들이 들어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 OAuth로 로그인 했는지 확인한다.&lt;/p&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;로그인완료 하면 code를 리턴(OAuth-Client라이브러리) =&amp;gt; Access 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;이 userRequest정보로 뭘해야하냐면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회원프로필 정보를 받아야함(loadUser 함수호출) -&amp;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;PrincipalOauth2UserService&lt;/p&gt;
&lt;pre id=&quot;code_1644259170359&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
public class PrincipalOauth2UserService extends DefaultOAuth2UserService {
	//구글로 부터 받은 userRequest데이터에 대한 후처리 되는 함수
	@Override
	public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
		System.out.println(&quot;getClientRegistration:&quot;+userRequest.getClientRegistration());
		System.out.println(&quot;getAccessToken:&quot;+userRequest.getAccessToken().getTokenValue());
		System.out.println(&quot;getAttributes:&quot;+super.loadUser(userRequest).getAttributes());
		//받은 getAttributes 정보로 강제 회원가입을 시킬 것이다.
		
		OAuth2User oauth2User = super.loadUser(userRequest); 
		
		return super.loadUser(userRequest);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IndexController.java&lt;/p&gt;
&lt;pre id=&quot;code_1644260832881&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	@GetMapping(&quot;/test/login&quot;)
	public @ResponseBody String testLogin(Authentication authentication,
			@AuthenticationPrincipal PrincipalDetails userDetails) { //DI 의존성 주입
		System.out.println(&quot;/test/login=========&quot;);
		PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
		System.out.println(&quot;authentication:&quot;+principalDetails.getUser());
		
		System.out.println(&quot;userDetails:&quot;+userDetails.getUser());
		return &quot;세션 정보 확인하기&quot;;
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1644261797720&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	@GetMapping(&quot;/test/login&quot;)
	public @ResponseBody String testLogin(Authentication authentication,
			@AuthenticationPrincipal PrincipalDetails userDetails) { //DI 의존성 주입
		System.out.println(&quot;/test/login=========&quot;);
		PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
		System.out.println(&quot;authentication:&quot;+principalDetails.getUser());
		
		System.out.println(&quot;userDetails:&quot;+userDetails.getUser());
		return &quot;세션 정보 확인하기&quot;;
	}
	
	@GetMapping(&quot;/test/oauth/login&quot;)
	public @ResponseBody String testOAuthLogin(
			Authentication authentication){ //DI 의존성 주입
		System.out.println(&quot;/test/login=========&quot;);
		OAuth2User oauth2User = (OAuth2User) authentication.getPrincipal();
		System.out.println(&quot;authentication:&quot;+oauth2User.getAttributes());
		
		return &quot;OAuth 세션 정보 확인하기&quot;;
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1520&quot; data-origin-height=&quot;943&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfohWn/btrsVKO326i/Zco6cJq1tqkkjMuDZ5VIxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfohWn/btrsVKO326i/Zco6cJq1tqkkjMuDZ5VIxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfohWn/btrsVKO326i/Zco6cJq1tqkkjMuDZ5VIxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfohWn%2FbtrsVKO326i%2FZco6cJq1tqkkjMuDZ5VIxK%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;691&quot; height=&quot;428&quot; data-origin-width=&quot;1520&quot; data-origin-height=&quot;943&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세션안에 시큐리티가 관리하는 세션이 있고 Authentication&amp;nbsp;있어야한다. &lt;br /&gt;&lt;br /&gt;이&amp;nbsp;Authentication&amp;nbsp;안에&amp;nbsp;들어갈&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;두개의&amp;nbsp;타입이&amp;nbsp;있는데,&amp;nbsp; &lt;br /&gt;UserDetails와&amp;nbsp;OAuth2User타입이&amp;nbsp;들어갈&amp;nbsp;수&amp;nbsp;있다.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;시큐리티가 들고 있는 세션에는 무조건 이 Authentication 객체만 들어갈 수 있으며&lt;br /&gt;들어가는&amp;nbsp;순간&amp;nbsp;로그인이&amp;nbsp;되는&amp;nbsp;것이고&amp;nbsp; &lt;br /&gt;&lt;br /&gt;일반 로그인은 UserDetails&lt;br /&gt;구글, 페이스북 등의 OAuth 로그인은 OAuth2User&lt;br /&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;br /&gt;PrincipalDetails으로&amp;nbsp;묶는다면&amp;nbsp;이PrincipalDetails으로&amp;nbsp;&amp;nbsp;타입만&amp;nbsp;찾으면&amp;nbsp;둘&amp;nbsp;다&amp;nbsp;번거롭지&amp;nbsp;않게&amp;nbsp;찾을&amp;nbsp;수&amp;nbsp;있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1700&quot; data-origin-height=&quot;956&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsYndU/btrsRPxhPQO/bZxPFIXG5ZNr1kyvN5Jd11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsYndU/btrsRPxhPQO/bZxPFIXG5ZNr1kyvN5Jd11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsYndU/btrsRPxhPQO/bZxPFIXG5ZNr1kyvN5Jd11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsYndU%2FbtrsRPxhPQO%2FbZxPFIXG5ZNr1kyvN5Jd11%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;675&quot; height=&quot;380&quot; data-origin-width=&quot;1700&quot; data-origin-height=&quot;956&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;IndexController.java&lt;/p&gt;
&lt;pre id=&quot;code_1644368570774&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	@GetMapping(&quot;/user&quot;)
	public @ResponseBody String user(@AuthenticationPrincipal PrincipalDetails principalDetails) {
		return &quot;user&quot;;
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PrincipalDetails.java - 둘을 묶어놓기&lt;/p&gt;
&lt;pre id=&quot;code_1644368647359&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class PrincipalDetails implements UserDetails, OAuth2User{

....}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[참조] : 인프런 -&amp;nbsp; &lt;span style=&quot;background-color: #ffffff;&quot;&gt;스프링부트 시큐리티 &amp;amp; JWT 강의&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Back-end/Spring Boot Security</category>
      <category>Authentication</category>
      <category>It</category>
      <category>oauth</category>
      <category>Oauth2User</category>
      <category>spring</category>
      <category>spring boot</category>
      <category>spring boot security</category>
      <category>백엔드개발자</category>
      <category>스프링부트</category>
      <category>시큐리티</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/54</guid>
      <comments>https://thfdl0317.tistory.com/entry/Spring-Boot-Security-Authentication-%EA%B0%9D%EC%B2%B4%EA%B0%80-%EA%B0%80%EC%A7%88-%EC%88%98-%EC%9E%88%EB%8A%94-2%EA%B0%80%EC%A7%80-%ED%83%80%EC%9E%85#entry54comment</comments>
      <pubDate>Wed, 9 Feb 2022 10:01:20 +0900</pubDate>
    </item>
    <item>
      <title>Spring Boot Security - 구글 로그인,구글 회원 프로필 정보 받기</title>
      <link>https://thfdl0317.tistory.com/entry/Spring-Boot-Security-%EA%B5%AC%EA%B8%80-%EB%A1%9C%EA%B7%B8%EC%9D%B8%EA%B5%AC%EA%B8%80-%ED%9A%8C%EC%9B%90-%ED%94%84%EB%A1%9C%ED%95%84-%EC%A0%95%EB%B3%B4-%EB%B0%9B%EA%B8%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;우선 google api console로 들어가서 프로젝트 만들기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://console.developers.google.com/apis&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://console.developers.google.com/apis&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1644254156472&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Google Cloud Platform&quot; data-og-description=&quot;하나의 계정으로 모든 Google 서비스를 Google Cloud Platform을 사용하려면 로그인하세요.&quot; data-og-host=&quot;accounts.google.com&quot; data-og-source-url=&quot;https://console.developers.google.com/apis&quot; data-og-url=&quot;https://accounts.google.com/ServiceLogin?service=cloudconsole&amp;amp;passive=1209600&amp;amp;osid=1&amp;amp;continue=https://console.developers.google.com/apis&amp;amp;followup=https://console.developers.google.com/apis&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://console.developers.google.com/apis&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://console.developers.google.com/apis&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Google Cloud Platform&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;하나의 계정으로 모든 Google 서비스를 Google Cloud Platform을 사용하려면 로그인하세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;accounts.google.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;URL은&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1644254207364&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;http://localhost:8080/login/oauth2/code/google&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구글 로그인이 완료가 되면 서버쪽에서 코드를 돌려준다. 우리는 코드를받아 요청을할 때 필요한 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;535&quot; data-origin-height=&quot;382&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwXkfC/btrsA6NOz7w/ddCr77okBWjbv5PxCRRij1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwXkfC/btrsA6NOz7w/ddCr77okBWjbv5PxCRRij1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwXkfC/btrsA6NOz7w/ddCr77okBWjbv5PxCRRij1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwXkfC%2FbtrsA6NOz7w%2FddCr77okBWjbv5PxCRRij1%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;535&quot; height=&quot;382&quot; data-origin-width=&quot;535&quot; data-origin-height=&quot;382&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 메모장에 옮겨 적어놓기!&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;그리고 잠깐 oauth2-client 라이브러리가 등록되어져있는지 확인해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;537&quot; data-origin-height=&quot;68&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cXQZRC/btrsLwYHYrV/bUW7mXwFkSvTEfsLm1T8lk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cXQZRC/btrsLwYHYrV/bUW7mXwFkSvTEfsLm1T8lk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cXQZRC/btrsLwYHYrV/bUW7mXwFkSvTEfsLm1T8lk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcXQZRC%2FbtrsLwYHYrV%2FbUW7mXwFkSvTEfsLm1T8lk%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;537&quot; height=&quot;68&quot; data-origin-width=&quot;537&quot; data-origin-height=&quot;68&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pom.xml안에 등록되어있는지 확인.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;application.yml&lt;/p&gt;
&lt;pre id=&quot;code_1644254919077&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    security:
        oauth2:
        client:
        registration:
        google:
        client-id:아까 프로젝트만들 때 나왔던 ID
        client-secret:아까 프로젝트만들 때 나왔던 비밀번호
        scope:
        -email
        -profile&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;loginForm.html 안에 주소는 마음대로 적지말고&lt;/p&gt;
&lt;pre id=&quot;code_1644255076444&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;h1&amp;gt;로그인 페이지&amp;lt;/h1&amp;gt;

&amp;lt;form action=&quot;/login&quot; method=&quot;POST&quot;&amp;gt;
&amp;lt;input type=&quot;text&quot; name=&quot;username&quot; placeholder=&quot;username&quot;&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;input type=&quot;password&quot; name=&quot;password&quot; placeholder=&quot;password&quot;&amp;gt;&amp;lt;br/&amp;gt;

&amp;lt;button&amp;gt;로그인&amp;lt;/button&amp;gt;
&amp;lt;/form&amp;gt;

&amp;lt;a href=&quot;/oauth2/authorization/google&quot;&amp;gt;구글로그인&amp;lt;/a&amp;gt;
&amp;lt;a href=&quot;/joinForm&quot;&amp;gt;회원가입을 아직 하지 않으셨나요?&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SecurityConfig안에 추가&lt;/p&gt;
&lt;pre id=&quot;code_1644255274796&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled=true, prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter{
	
	@Bean
	public BCryptPasswordEncoder encodePwd() {
		return new BCryptPasswordEncoder();
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.csrf().disable();
		http.authorizeRequests()
		.antMatchers(&quot;/user/**&quot;).authenticated()
		.antMatchers(&quot;/manager/**&quot;).access(&quot;hasRole('ROLE_ADMIN') or hasRole('ROLE_MANAGER')&quot;)//이 권한이 있는 사람만 들어올 수 있게한다.
		.antMatchers(&quot;/admin/**&quot;).access(&quot;hasRole('ROLE_ADMIN')&quot;)
		.anyRequest().permitAll()
		.and()
		.formLogin()
		.loginPage(&quot;/loginForm&quot;) 
		.loginProcessingUrl(&quot;/login&quot;)
		.defaultSuccessUrl(&quot;/&quot;)
		.and() ---------------------------------&amp;gt; 이 부분 추가
		.oauth2Login()           ---------------&amp;gt; 이 부분 추가
		.loginPage(&quot;/loginForm&quot;);---------------&amp;gt; 이 부분 추가
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;후 실행한다면&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;966&quot; data-origin-height=&quot;773&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yjtSE/btrsJLhwk5g/WFKBZhondvh8G6O2o6JJF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yjtSE/btrsJLhwk5g/WFKBZhondvh8G6O2o6JJF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yjtSE/btrsJLhwk5g/WFKBZhondvh8G6O2o6JJF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyjtSE%2FbtrsJLhwk5g%2FWFKBZhondvh8G6O2o6JJF0%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;573&quot; height=&quot;459&quot; data-origin-width=&quot;966&quot; data-origin-height=&quot;773&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 왔다면 정상작동, 이제 계정을 선택 한 후 다음페이지에 후처리 진행을 해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그인이 완료한 뒤에 무엇을 돌려주냐면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 코드 받기(인증이 됐다는 것이다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 엑세스토큰(권한을 받고)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 사용자 프로필 정보를 가져와&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 그 정보를 토대로 회원가입을 자동으로 진행시키기도한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 이메일, 전화번호, 이름, 아이디 외의 추가적인 정보가 필요없다면 우리는 기본적인 정보만 가져와서 회원가입을 시킨다.&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;rarr; userService(null);&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SecurityConfig 안에 코드 추가&lt;/p&gt;
&lt;pre id=&quot;code_1644256371492&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;위에 
    @Autowired
	private PrincipalOauth2UserService prinOauth2UserService;
	
    
아래에
    .userInfoEndpoint()
	.userService(prinOauth2UserService);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;config 패키지 안에 oauth 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에 후처리를 진행하는데, 후처리는 loadUser로 진행한다.&lt;/p&gt;
&lt;pre id=&quot;code_1644257125837&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
public class PrincipalOauth2UserService extends DefaultOAuth2UserService {
	//구글로 부터 받은 userRequest데이터에 대한 후처리 되는 함수
	@Override
	public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
		System.out.println(&quot;userRequest:&quot;+userRequest);
		return super.loadUser(userRequest);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하고 실행할 시 console창에&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;675&quot; data-origin-height=&quot;42&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bc5HcR/btrsxjl7fzV/lkTGeJZIPxR0PSTEnapnTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bc5HcR/btrsxjl7fzV/lkTGeJZIPxR0PSTEnapnTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bc5HcR/btrsxjl7fzV/lkTGeJZIPxR0PSTEnapnTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbc5HcR%2Fbtrsxjl7fzV%2FlkTGeJZIPxR0PSTEnapnTk%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;675&quot; height=&quot;42&quot; data-origin-width=&quot;675&quot; data-origin-height=&quot;42&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드 수정&lt;/p&gt;
&lt;pre id=&quot;code_1644257530445&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
public class PrincipalOauth2UserService extends DefaultOAuth2UserService {
	//구글로 부터 받은 userRequest데이터에 대한 후처리 되는 함수
	@Override
	public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
		System.out.println(&quot;getClientRegistration:&quot;+userRequest.getClientRegistration());
		System.out.println(&quot;getAccessToken:&quot;+userRequest.getAccessToken());
		System.out.println(&quot;getAttributes:&quot;+super.loadUser(userRequest).getAttributes());
		return super.loadUser(userRequest);
	}
}&lt;/code&gt;&lt;/pre&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;396&quot; data-origin-height=&quot;86&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D3Pia/btrsLwLa7fe/EYsdBOY2yn9yP6YR2ZjVw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D3Pia/btrsLwLa7fe/EYsdBOY2yn9yP6YR2ZjVw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D3Pia/btrsLwLa7fe/EYsdBOY2yn9yP6YR2ZjVw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD3Pia%2FbtrsLwLa7fe%2FEYsdBOY2yn9yP6YR2ZjVw0%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;396&quot; height=&quot;86&quot; data-origin-width=&quot;396&quot; data-origin-height=&quot;86&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정보들이 보여짐&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;803&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/od9t6/btrsMbfJCUP/aVz5jKxK0kVPKf9tDq55qk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/od9t6/btrsMbfJCUP/aVz5jKxK0kVPKf9tDq55qk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/od9t6/btrsMbfJCUP/aVz5jKxK0kVPKf9tDq55qk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fod9t6%2FbtrsMbfJCUP%2FaVz5jKxK0kVPKf9tDq55qk%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;803&quot; height=&quot;375&quot; data-origin-width=&quot;803&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;User.java 안에 추가&lt;/p&gt;
&lt;pre id=&quot;code_1644258135101&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	private String provider;
	private String providerId;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PrincipalOauth2UserService&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;715&quot; data-origin-height=&quot;126&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHB9Kl/btrsNyapPv1/gpndwpRyhLe7i4YbqYvJO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHB9Kl/btrsNyapPv1/gpndwpRyhLe7i4YbqYvJO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHB9Kl/btrsNyapPv1/gpndwpRyhLe7i4YbqYvJO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHB9Kl%2FbtrsNyapPv1%2FgpndwpRyhLe7i4YbqYvJO0%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;715&quot; height=&quot;126&quot; data-origin-width=&quot;715&quot; data-origin-height=&quot;126&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;받은 getAttributes정보로 강제 회원가입을 시켜야한다.&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;amp; JWT 강의&lt;/p&gt;</description>
      <category>Back-end/Spring Boot Security</category>
      <category>Oauth2User</category>
      <category>security</category>
      <category>spring</category>
      <category>spring boot</category>
      <category>SpringBootSecurity</category>
      <category>구글 로그인</category>
      <category>스프링부트</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/53</guid>
      <comments>https://thfdl0317.tistory.com/entry/Spring-Boot-Security-%EA%B5%AC%EA%B8%80-%EB%A1%9C%EA%B7%B8%EC%9D%B8%EA%B5%AC%EA%B8%80-%ED%9A%8C%EC%9B%90-%ED%94%84%EB%A1%9C%ED%95%84-%EC%A0%95%EB%B3%B4-%EB%B0%9B%EA%B8%B0#entry53comment</comments>
      <pubDate>Tue, 8 Feb 2022 03:20:54 +0900</pubDate>
    </item>
    <item>
      <title>Spring Boot Security - 시큐리티 권한 처리</title>
      <link>https://thfdl0317.tistory.com/entry/Spring-Boot-Security-%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0-%EA%B6%8C%ED%95%9C-%EC%B2%98%EB%A6%AC</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;권한 처리를 하기 전&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;admin, manager 회원가입을 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;863&quot; data-origin-height=&quot;115&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqwxar/btrsMaVgUXv/bMNalM5d5pNdz5eeoytFNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqwxar/btrsMaVgUXv/bMNalM5d5pNdz5eeoytFNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqwxar/btrsMaVgUXv/bMNalM5d5pNdz5eeoytFNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbqwxar%2FbtrsMaVgUXv%2FbMNalM5d5pNdz5eeoytFNK%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;863&quot; height=&quot;115&quot; data-origin-width=&quot;863&quot; data-origin-height=&quot;115&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB에 확인하고 싶다면&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1644240094445&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT * FROM USER;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;권한 세팅&lt;/p&gt;
&lt;pre id=&quot;code_1644240219686&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;update user set role = 'ROLE_MANAGER' where id=2;
update user set role = 'ROLE_ADMIN' where id=3;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;user테이블에서 확인&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;885&quot; data-origin-height=&quot;116&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uffgf/btrsLwEkplt/NNizsI3YXqJ3oUnlM0Ndx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uffgf/btrsLwEkplt/NNizsI3YXqJ3oUnlM0Ndx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uffgf/btrsLwEkplt/NNizsI3YXqJ3oUnlM0Ndx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fuffgf%2FbtrsLwEkplt%2FNNizsI3YXqJ3oUnlM0Ndx1%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;885&quot; height=&quot;116&quot; data-origin-width=&quot;885&quot; data-origin-height=&quot;116&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;SecurityConfig안에 추가로 입력할 코드&lt;/p&gt;
&lt;pre id=&quot;code_1644240818323&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@EnableGlobalMethodSecurity(securedEnabled=true)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;secured 어노테이션 활성화인데, 이 코드를 추가 후&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;IndexController.java 파일에&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1644240978875&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	@Secured(&quot;ROLE_ADMIN&quot;)
	@GetMapping(&quot;info&quot;)
	public @ResponseBody String info() {
		return &quot;개인정보&quot;;
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Secured라는 어노테이션을 미리 붙이면 경로에 info를 입력해도 안들어가지게 설정 이제 admin만 이 info페이지에 들어갈 수 있는 것&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;291&quot; data-origin-height=&quot;86&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mM6qB/btrsO23iM2r/Jtm0YCKpfF5rcEFK47vQS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mM6qB/btrsO23iM2r/Jtm0YCKpfF5rcEFK47vQS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mM6qB/btrsO23iM2r/Jtm0YCKpfF5rcEFK47vQS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmM6qB%2FbtrsO23iM2r%2FJtm0YCKpfF5rcEFK47vQS1%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;291&quot; height=&quot;86&quot; data-origin-width=&quot;291&quot; data-origin-height=&quot;86&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;만약 다른 계정으로 info에 접근한다면&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;370&quot; data-origin-height=&quot;169&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dG1Cze/btrsxjTYdf5/vXA97UqsimW3fgPulIFtTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dG1Cze/btrsxjTYdf5/vXA97UqsimW3fgPulIFtTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dG1Cze/btrsxjTYdf5/vXA97UqsimW3fgPulIFtTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdG1Cze%2FbtrsxjTYdf5%2FvXA97UqsimW3fgPulIFtTK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;370&quot; height=&quot;169&quot; data-origin-width=&quot;370&quot; data-origin-height=&quot;169&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;또한 @PrePostEnabled가 있는데, 작성법은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SecurityConfig.java&lt;/p&gt;
&lt;pre id=&quot;code_1644242003408&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@EnableGlobalMethodSecurity(securedEnabled=true, prePostEnabled = true)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@PreAuthorize(&quot;hasRole('ROLE_MANAGER) or hasRole('ROLE_ADMIN')&quot;) &amp;rarr; 데이터가 실행되기 직전에 실행된다.&lt;/p&gt;
&lt;pre id=&quot;code_1644241919105&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	@PreAuthorize(&quot;hasRole('ROLE_MANAGER') or hasRole('ROLE_ADMIN')&quot;)
	@GetMapping(&quot;/data&quot;)
	public @ResponseBody String data() {
		return &quot;데이터정보&quot;;
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러개를 하려할 경우 hasRole넣어서 작성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 MANAGER 권한과 ADMIN 권한만 있는 사람들이 data 경로로 들어갈 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;admin 계정으로 들어갈 경우&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;311&quot; data-origin-height=&quot;95&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kM2Du/btrsMauhAta/bKXrdjJgwmIl229tzyjDI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kM2Du/btrsMauhAta/bKXrdjJgwmIl229tzyjDI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kM2Du/btrsMauhAta/bKXrdjJgwmIl229tzyjDI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkM2Du%2FbtrsMauhAta%2FbKXrdjJgwmIl229tzyjDI1%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;311&quot; height=&quot;95&quot; data-origin-width=&quot;311&quot; data-origin-height=&quot;95&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;권한 없는 sol2로 들어갈 경우&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;371&quot; data-origin-height=&quot;139&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cExRXz/btrsJL2OqCV/Zsww50i8BYyImRSr1OchN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cExRXz/btrsJL2OqCV/Zsww50i8BYyImRSr1OchN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cExRXz/btrsJL2OqCV/Zsww50i8BYyImRSr1OchN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcExRXz%2FbtrsJL2OqCV%2FZsww50i8BYyImRSr1OchN0%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;371&quot; height=&quot;139&quot; data-origin-width=&quot;371&quot; data-origin-height=&quot;139&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[참고] 인프런 - &lt;span style=&quot;background-color: #ffffff;&quot;&gt;스프링부트 시큐리티 &amp;amp; JWT 강의&lt;/span&gt;&lt;/p&gt;</description>
      <category>Back-end/Spring Boot Security</category>
      <category>JWT</category>
      <category>spring</category>
      <category>spring boot</category>
      <category>spring boot security</category>
      <category>백엔드개발자</category>
      <category>스프링부트</category>
      <category>시큐리티</category>
      <category>웹개발자</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/51</guid>
      <comments>https://thfdl0317.tistory.com/entry/Spring-Boot-Security-%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0-%EA%B6%8C%ED%95%9C-%EC%B2%98%EB%A6%AC#entry51comment</comments>
      <pubDate>Mon, 7 Feb 2022 22:32:52 +0900</pubDate>
    </item>
    <item>
      <title>Spring Boot Security - 시큐리티 회원가입, 로그인</title>
      <link>https://thfdl0317.tistory.com/entry/Spring-Boot-Security-%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0-%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85-%EB%A1%9C%EA%B7%B8%EC%9D%B8</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;| 시큐리티 회원가입&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;templates안에 loginForm.html 생성&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;779&quot; data-origin-height=&quot;311&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l9HYI/btrsFtg2mwU/VcoSxAH2WuCZKjjcmVYrA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l9HYI/btrsFtg2mwU/VcoSxAH2WuCZKjjcmVYrA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l9HYI/btrsFtg2mwU/VcoSxAH2WuCZKjjcmVYrA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl9HYI%2FbtrsFtg2mwU%2FVcoSxAH2WuCZKjjcmVYrA0%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;779&quot; height=&quot;311&quot; data-origin-width=&quot;779&quot; data-origin-height=&quot;311&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나머지는 모두 권한이 허용되어있기 때문에 /login 입력 시 작성한 loginForm.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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;model 패키지 생성 후 User 클래스 생성하여 객체 정의한다.&lt;/p&gt;
&lt;pre id=&quot;code_1644222722106&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
@Data
public class User {
	@Id//primary key
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	
	private int id;
	private String username;
	private String password;
	private String email;
	private String role; //ROLE_USER, ROLE_ADMIN
	
	private String provider;
	private String providerId;
	//private Timestamp loginDate;
	@CreationTimestamp
	private Timestamp createDate;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB에 User라는 테이블이 만들어졌는지 확인&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;368&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzLD2S/btrsMa1P1qW/YomA8DRHDCl0fjUd74ow0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzLD2S/btrsMa1P1qW/YomA8DRHDCl0fjUd74ow0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzLD2S/btrsMa1P1qW/YomA8DRHDCl0fjUd74ow0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzLD2S%2FbtrsMa1P1qW%2FYomA8DRHDCl0fjUd74ow0k%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;674&quot; height=&quot;368&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;368&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;joinForm.html 회원가입 만들기&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;331&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pR6fi/btrsNwXFg2O/tVJwgDtvJkFc9MyykRXAB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pR6fi/btrsNwXFg2O/tVJwgDtvJkFc9MyykRXAB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pR6fi/btrsNwXFg2O/tVJwgDtvJkFc9MyykRXAB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpR6fi%2FbtrsNwXFg2O%2FtVJwgDtvJkFc9MyykRXAB1%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;838&quot; height=&quot;331&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;331&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@ResponseBody을 써두었기 때문에 회원가입 시 화면에는 join이 나와야 정상작동,&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;Repository 패키지 생성 안에 UserRepository 인터페이스를 만들자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1644224663391&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface UserRepository extends JpaRepository&amp;lt;User, Integer&amp;gt;{

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JpaRepository가 CRUD함수를 들고 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Repository라는 어노테이션이 없어도 IoC가 되는데, 그 이유는 위의JpaRepository를 상속했기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;controller단의 join에 이렇게 셋팅을 하면 회원가입은 잘 되어지지만, 패스워드가 암호화가 되어야한다.&lt;/p&gt;
&lt;pre id=&quot;code_1644225167093&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;user.setRole(&quot;ROLE_USER&quot;);
userRepository.save(user);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SecurityConfig.java안에&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1644225482668&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
	
	@Bean
	public BCryptPasswordEncoder encodePwd() {
		return new BCryptPasswordEncoder();
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Bean 어노테이션을 적어서 해당 메서드의 리턴되는 오브젝트를 IoC로 등록시켜준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IndexController안에는 Autowired와 함께 join부분 추가&lt;/p&gt;
&lt;pre id=&quot;code_1644225898948&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@PostMapping(&quot;/join&quot;)
	public @ResponseBody String join(User user) {
		System.out.println(&quot;user&quot;+user);
		user.setRole(&quot;ROLE_USER&quot;);
		String rawPassword = user.getPassword();
		String endcPassword = bCrpBCryptPasswordEncoder.encode(rawPassword);
		user.setPassword(endcPassword);
		userRepository.save(user); 
		return &quot;redireact:/loginForm&quot;;
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하고 실행 후 DB를 확인하면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;127&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDFwKV/btrsC9J0SRg/Wb9FKiBhrk5l2XYkaC1ctk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDFwKV/btrsC9J0SRg/Wb9FKiBhrk5l2XYkaC1ctk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDFwKV/btrsC9J0SRg/Wb9FKiBhrk5l2XYkaC1ctk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDFwKV%2FbtrsC9J0SRg%2FWb9FKiBhrk5l2XYkaC1ctk%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;560&quot; height=&quot;127&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;127&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;| 시큐리티 로그인&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;추가 코드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;.loginProcessingUrl(&quot;/login&quot;) &amp;rarr; /login 주소가 호출이 되면 시큐리티가 낚아채서 대신 로그인을 진행해준다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그인 폼에서&amp;nbsp;form action=&quot;/login&quot;로 해주면 시큐리티가 낚아챈다는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &lt;br /&gt;.defaultSuccessUrl(&quot;/&quot;);&amp;nbsp; &lt;b&gt;&amp;rarr; &lt;/b&gt;로그인이 완료되면 보이는 경로&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644229142926&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.csrf().disable();
		http.authorizeRequests()
		.antMatchers(&quot;/user/**&quot;).authenticated()
		.antMatchers(&quot;/manager/**&quot;).access(&quot;hasRole('ROLE_ADMIN') or hasRole('ROLE_MANAGER')&quot;)//이 권한이 있는 사람만 들어올 수 있게한다.
		.antMatchers(&quot;/admin/**&quot;).access(&quot;hasRole('ROLE_ADMIN')&quot;)
		.anyRequest().permitAll()
		.and()
		.formLogin()
		.loginPage(&quot;/loginForm&quot;)
		.loginProcessingUrl(&quot;/login&quot;)
		.defaultSuccessUrl(&quot;/&quot;); 
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;auth 패키지 생성하고 안에 PrincipaDetails 클래스 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시큐리티가 /login 주소 요청이 오면 낚아채서 로그인을 진행시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그인을 진행이 완려되면 시큐리티session을 만들어준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 시큐리티가 가지고 있는 session 이있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시큐리티 자신만의 session공간을 가진다. Security ContextHolder안에 다가 session정보를 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시큐리티가 가지고있는 세션에 들어갈 수 있는 오브젝트가 정해져있다. 이 객체가 Authentication타입 객체이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 Authentication안에는 User정보가 있어야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;User오브젝트 타입은 UserDetails 타입 객체&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;시큐리티 세션 영역이있는데 여기에 들어갈 수 있는 객체가 Authentication,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 여기에 user정보를 저장할 때 UserDetails 객체를 꺼내사용하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러기 위해서 상속 UserDetails&amp;nbsp; 하고 오버라이딩 재정의와 생성자&lt;/p&gt;
&lt;pre id=&quot;code_1644231481914&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class PrincipalDetails implements UserDetails{
	
	private User user;
	
	public PrincipalDetails(User user) {
		this.user=user;
	}

	@Override
	public Collection&amp;lt;? extends GrantedAuthority&amp;gt; getAuthorities() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String getPassword() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String getUsername() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean isAccountNonExpired() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean isAccountNonLocked() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean isCredentialsNonExpired() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean isEnabled() {
		// TODO Auto-generated method stub
		return false;
	}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;auth패키지안에 PrincipalDetailsSevice 생성 후&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1428&quot; data-origin-height=&quot;290&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dsKJiY/btrsJLuSptI/sPucA8A1c0bAERTh6kV7P1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dsKJiY/btrsJLuSptI/sPucA8A1c0bAERTh6kV7P1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dsKJiY/btrsJLuSptI/sPucA8A1c0bAERTh6kV7P1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdsKJiY%2FbtrsJLuSptI%2FsPucA8A1c0bAERTh6kV7P1%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;1428&quot; height=&quot;290&quot; data-origin-width=&quot;1428&quot; data-origin-height=&quot;290&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;pre id=&quot;code_1644235687860&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//시큐리티 설정에서 loginProcessingUrl(&quot;/login&quot;), login 요청이 오면 자동으로 UserDetailsService 타입으로 IoC되어있는 loadUserByUsername함수가 실행
@Service
public class PrincipalDetailsService implements UserDetailsService{
	
	@Autowired
	private UserRepository userRepository;
	
	//시큐리티 session(내부 Authentication(내부 UserDetails) 

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		User userEntity = userRepository.findByUsername(username);
		if(userEntity!=null) {
			return new PrincipalDetails(userEntity);
		}
		return null;
	}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[참고] - 인프런 시프링 부트 시큐리티&amp;amp; JWT 강의&lt;/p&gt;</description>
      <category>Back-end/Spring Boot Security</category>
      <category>It</category>
      <category>JWT</category>
      <category>spring</category>
      <category>SpringBoot</category>
      <category>SpringBoot Security</category>
      <category>시큐리티 회원가입</category>
      <category>암호화</category>
      <category>웹개발자</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/50</guid>
      <comments>https://thfdl0317.tistory.com/entry/Spring-Boot-Security-%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0-%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85-%EB%A1%9C%EA%B7%B8%EC%9D%B8#entry50comment</comments>
      <pubDate>Mon, 7 Feb 2022 17:32:29 +0900</pubDate>
    </item>
    <item>
      <title>Spring Boot Security - 환경설정 &amp;amp; 시큐리티 설정</title>
      <link>https://thfdl0317.tistory.com/entry/Spring-Boot-Security-%ED%99%98%EA%B2%BD%EC%84%A4%EC%A0%95-%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0-%EC%84%A4%EC%A0%95</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;사용 DB : MySQL&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용 tool : Spring Boot (sts-4.11.0.RELEASE)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;696&quot; data-origin-height=&quot;102&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ViNeQ/btrsyFVDYOF/IJsjHe69FYtEOpKrrQMGC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ViNeQ/btrsyFVDYOF/IJsjHe69FYtEOpKrrQMGC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ViNeQ/btrsyFVDYOF/IJsjHe69FYtEOpKrrQMGC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FViNeQ%2FbtrsyFVDYOF%2FIJsjHe69FYtEOpKrrQMGC1%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;696&quot; height=&quot;102&quot; data-origin-width=&quot;696&quot; data-origin-height=&quot;102&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;551&quot; data-origin-height=&quot;728&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Zlf7u/btrsFsPaePa/GbYpjWUwYLgvPK4aMjkBu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Zlf7u/btrsFsPaePa/GbYpjWUwYLgvPK4aMjkBu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Zlf7u/btrsFsPaePa/GbYpjWUwYLgvPK4aMjkBu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZlf7u%2FbtrsFsPaePa%2FGbYpjWUwYLgvPK4aMjkBu1%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;418&quot; height=&quot;553&quot; data-origin-width=&quot;551&quot; data-origin-height=&quot;728&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;548&quot; data-origin-height=&quot;725&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcAEr3/btrsHGfjX33/RPoYE7Trd1OvN1yuvjqd40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcAEr3/btrsHGfjX33/RPoYE7Trd1OvN1yuvjqd40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcAEr3/btrsHGfjX33/RPoYE7Trd1OvN1yuvjqd40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcAEr3%2FbtrsHGfjX33%2FRPoYE7Trd1OvN1yuvjqd40%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;418&quot; height=&quot;554&quot; data-origin-width=&quot;548&quot; data-origin-height=&quot;725&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;MySQL에 들어가서&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;403&quot; data-origin-height=&quot;141&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/llGTn/btrsxEpOvuZ/D9kh20NZoWe681QfKSEcq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/llGTn/btrsxEpOvuZ/D9kh20NZoWe681QfKSEcq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/llGTn/btrsxEpOvuZ/D9kh20NZoWe681QfKSEcq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FllGTn%2FbtrsxEpOvuZ%2FD9kh20NZoWe681QfKSEcq1%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;403&quot; height=&quot;141&quot; data-origin-width=&quot;403&quot; data-origin-height=&quot;141&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 셋팅이 다 이뤄지면 src/main/resources안에 application.proerties를 yml파일로 변경&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;234&quot; data-origin-height=&quot;108&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/daFgOi/btrsHF8wFnA/GAcGxk677jZjIgIbu0X5SK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/daFgOi/btrsHF8wFnA/GAcGxk677jZjIgIbu0X5SK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/daFgOi/btrsHF8wFnA/GAcGxk677jZjIgIbu0X5SK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdaFgOi%2FbtrsHF8wFnA%2FGAcGxk677jZjIgIbu0X5SK%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;234&quot; height=&quot;108&quot; data-origin-width=&quot;234&quot; data-origin-height=&quot;108&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;418&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3eb5F/btrsxj6y6E9/avkMP54kP1jVsIZvKbYKh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3eb5F/btrsxj6y6E9/avkMP54kP1jVsIZvKbYKh1/img.png&quot; data-alt=&quot;application.yml안에 넣은 코드들&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3eb5F/btrsxj6y6E9/avkMP54kP1jVsIZvKbYKh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3eb5F%2Fbtrsxj6y6E9%2FavkMP54kP1jVsIZvKbYKh1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;690&quot; height=&quot;418&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;418&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;application.yml안에 넣은 코드들&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;com.sol.security2안에 Config 패키지 생성,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;com.sol.security2안에 Controller 패키지 생성하고 IndexController생성&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;215&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Xe7xx/btrsA7ktnGj/iSet5w5WkXEaj6OITniFSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Xe7xx/btrsA7ktnGj/iSet5w5WkXEaj6OITniFSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Xe7xx/btrsA7ktnGj/iSet5w5WkXEaj6OITniFSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXe7xx%2FbtrsA7ktnGj%2FiSet5w5WkXEaj6OITniFSK%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;848&quot; height=&quot;215&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;215&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 코드를 짤 때&amp;nbsp; 템플릿엔진을 mustach를 설정파일을 안에 넣어 사용&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;975&quot; data-origin-height=&quot;114&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/x7TIa/btrsxgbDeGG/qBdKTyogYrlP1fglKwpea0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/x7TIa/btrsxgbDeGG/qBdKTyogYrlP1fglKwpea0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/x7TIa/btrsxgbDeGG/qBdKTyogYrlP1fglKwpea0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fx7TIa%2FbtrsxgbDeGG%2FqBdKTyogYrlP1fglKwpea0%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;975&quot; height=&quot;114&quot; data-origin-width=&quot;975&quot; data-origin-height=&quot;114&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;머스테치 기본폴더 src/main/resources/ &lt;br /&gt;뷰리졸버 설정 시 : templates를 prefix로 잡고 , .mustache를 suffix로 잡아 세팅한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 application.yml부분에&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;125&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dmaCse/btrsxi0SGeY/WLS3o0r5kz4ZKGtkkm3NYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dmaCse/btrsxi0SGeY/WLS3o0r5kz4ZKGtkkm3NYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dmaCse/btrsxi0SGeY/WLS3o0r5kz4ZKGtkkm3NYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdmaCse%2Fbtrsxi0SGeY%2FWLS3o0r5kz4ZKGtkkm3NYK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;479&quot; height=&quot;125&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;125&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력하여 놨었으나 이건 없어도 괜찮다. 왜 없어도 가능할까?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그건 아까 보여줬듯이&amp;nbsp;우리가 머스터치를 사용하겠다고 의존성 등록을 해줬기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹브라우저로 보여줄 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;temlates안에 index.html 생성&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;215&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqIQtB/btrsAddui2v/Zg7XmiCgXb2i8cSl4aHo1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqIQtB/btrsAddui2v/Zg7XmiCgXb2i8cSl4aHo1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqIQtB/btrsAddui2v/Zg7XmiCgXb2i8cSl4aHo1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqIQtB%2FbtrsAddui2v%2FZg7XmiCgXb2i8cSl4aHo1K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;733&quot; height=&quot;215&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;215&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;config패키지 안에 WebMvcConfig.java 생성&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;506&quot; data-origin-height=&quot;283&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Qq5f2/btrszmvqCvc/epEv2vCBjwAYAbSLbKnrs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Qq5f2/btrszmvqCvc/epEv2vCBjwAYAbSLbKnrs1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Qq5f2/btrszmvqCvc/epEv2vCBjwAYAbSLbKnrs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQq5f2%2FbtrszmvqCvc%2FepEv2vCBjwAYAbSLbKnrs1%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;506&quot; height=&quot;283&quot; data-origin-width=&quot;506&quot; data-origin-height=&quot;283&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오버라이딩 후 내부 구성짜기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 뷰리졸버, Mustache를 재설정하기 위한오버라이딩&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;569&quot; data-origin-height=&quot;322&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBtGEs/btrsxISCLHn/JkQRebpJMHLlVIqxoTYAfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBtGEs/btrsxISCLHn/JkQRebpJMHLlVIqxoTYAfk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBtGEs/btrsxISCLHn/JkQRebpJMHLlVIqxoTYAfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBtGEs%2FbtrsxISCLHn%2FJkQRebpJMHLlVIqxoTYAfk%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;569&quot; height=&quot;322&quot; data-origin-width=&quot;569&quot; data-origin-height=&quot;322&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;resolver.setCharset(&quot;UTF-8&quot;); &amp;rarr; 내가 만든 view에 인코딩은 기본적으로 UTF-8로 설정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;resolver.setContentType(&quot;text/html; charset=UTF-8&quot;); &amp;rarr; 너한테 던지는 데이터는 html 파일이고 이 파일이 UTF-8이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;resolver.setSuffix(&quot;.html&quot;); &amp;rarr; html으로 바꾸면 머스터치가 인식을 한다.&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;console에&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Using generate security password가 나온다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;395&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c3WpLB/btrsDanLUcE/BR1aJX8XAcljDPjICJLyHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c3WpLB/btrsDanLUcE/BR1aJX8XAcljDPjICJLyHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c3WpLB/btrsDanLUcE/BR1aJX8XAcljDPjICJLyHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc3WpLB%2FbtrsDanLUcE%2FBR1aJX8XAcljDPjICJLyHk%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;342&quot; height=&quot;225&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;395&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;localhost:8080을 검색하면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 화면의 로그인 페이지로 이동하게된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;351&quot; data-origin-height=&quot;242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/S0BzS/btrsJMzEFaX/Gau2PBHkMDN4oN7wH4yboK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/S0BzS/btrsJMzEFaX/Gau2PBHkMDN4oN7wH4yboK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/S0BzS/btrsJMzEFaX/Gau2PBHkMDN4oN7wH4yboK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FS0BzS%2FbtrsJMzEFaX%2FGau2PBHkMDN4oN7wH4yboK%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;351&quot; height=&quot;242&quot; data-origin-width=&quot;351&quot; data-origin-height=&quot;242&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어? 아까 html파일에 &amp;lt;h2&amp;gt;첫 페이지&amp;lt;/h2&amp;gt; 라고 해서 작성한 것이 떠야하는거 아닌가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시큐리티로 의존성을 설정하게되면 홈페이지로 들어가는 모든 주소가 바뀌어 인증하는 홈페이지가 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1128&quot; data-origin-height=&quot;456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UpVxQ/btrsFtADoB1/dHdcaEI79539vb5dvSUMw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UpVxQ/btrsFtADoB1/dHdcaEI79539vb5dvSUMw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UpVxQ/btrsFtADoB1/dHdcaEI79539vb5dvSUMw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUpVxQ%2FbtrsFtADoB1%2FdHdcaEI79539vb5dvSUMw1%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;1128&quot; height=&quot;456&quot; data-origin-width=&quot;1128&quot; data-origin-height=&quot;456&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;303&quot; data-origin-height=&quot;113&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qyIDf/btrsytuXMPX/Oyt6OawnN5ebWfEAiszwL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qyIDf/btrsytuXMPX/Oyt6OawnN5ebWfEAiszwL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qyIDf/btrsytuXMPX/Oyt6OawnN5ebWfEAiszwL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqyIDf%2FbtrsytuXMPX%2FOyt6OawnN5ebWfEAiszwL0%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;303&quot; height=&quot;113&quot; data-origin-width=&quot;303&quot; data-origin-height=&quot;113&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아이디와 비밀번호를 입력할 때 아까 console에 나온 (Using generate security password)을 비밀번호에 넣는다면 아까 만든 index.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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;indexController에 들어가서&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1644220945499&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	
	@GetMapping(&quot;/user&quot;)
	public @ResponseBody String user() {
		return &quot;user&quot;;
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 식으로 admin, manager, login, 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;config패키지에 SecurityConfig라는 이름의 클래스를 생성한다.&lt;/p&gt;
&lt;pre id=&quot;code_1644221045507&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.csrf().disable();
		http.authorizeRequests()
		.antMatchers(&quot;/user/**&quot;).authenticated()
		.antMatchers(&quot;/manager/**&quot;).access(&quot;hasRole('ROLE_ADMIN') or hasRole('ROLE_MANAGER')&quot;)//이 권한이 있는 사람만 들어올 수 있게한다.
		.antMatchers(&quot;/admin/**&quot;).access(&quot;hasRole('ROLE_ADMIN')&quot;)
		.anyRequest().permitAll()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 @EnableWebSecurtiy &amp;rarr; 스프링 시큐리티 필터가 스프링 필터 체인에 등록이된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;manager와 admin쪽으로 들어오게되면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hasRole('ROLE_ADMIN') or hasRole('ROLE_MANAGER') 이 권한이 있는 사람만 들어올 수 있도록 설정한다.&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;h4 data-ke-size=&quot;size20&quot;&gt;403 권한이 없는 페이지에가 나올 시 login 페이지로 이동되도록하기 위한 코드&amp;nbsp;&lt;/h4&gt;
&lt;pre id=&quot;code_1644220885917&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package com.sol.security2.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.csrf().disable();
		http.authorizeRequests()
		.antMatchers(&quot;/user/**&quot;).authenticated()
		.antMatchers(&quot;/manager/**&quot;).access(&quot;hasRole('ROLE_ADMIN') or hasRole('ROLE_MANAGER')&quot;)//이 권한이 있는 사람만 들어올 수 있게한다.
		.antMatchers(&quot;/admin/**&quot;).access(&quot;hasRole('ROLE_ADMIN')&quot;)
		.anyRequest().permitAll()
		.and()
		.formLogin()
		.loginPage(&quot;/login&quot;);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제&amp;nbsp;어디로&amp;nbsp;가든(admin의&amp;nbsp;경로를&amp;nbsp;찍든,&amp;nbsp;manager로&amp;nbsp;경로를&amp;nbsp;찍든)&amp;nbsp;login&amp;nbsp;경로로&amp;nbsp;이동되어&amp;nbsp;웨브라우저에&amp;nbsp;보여지게된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;[참고] - 인프런 시프링 부트 시큐리티&amp;amp; JWT 강의&lt;/span&gt;&lt;/p&gt;</description>
      <category>Back-end/Spring Boot Security</category>
      <category>It</category>
      <category>JWT</category>
      <category>security</category>
      <category>spring</category>
      <category>SpringBoot</category>
      <category>SpringBootSecurity</category>
      <category>백엔드개발자</category>
      <category>웹개발자</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/49</guid>
      <comments>https://thfdl0317.tistory.com/entry/Spring-Boot-Security-%ED%99%98%EA%B2%BD%EC%84%A4%EC%A0%95-%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0-%EC%84%A4%EC%A0%95#entry49comment</comments>
      <pubDate>Mon, 7 Feb 2022 10:09:58 +0900</pubDate>
    </item>
    <item>
      <title>Spring Boot Security  -  인증과 인가 그리고 JWT에 대해서</title>
      <link>https://thfdl0317.tistory.com/entry/Spring-Boot-Security-JWT</link>
      <description>&lt;pre id=&quot;code_1644250465312&quot; class=&quot;asciidoc&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt; 목표 &amp;gt;

- 인증, 인가란? 에 대한 개념알기

- JWT이란? 개념과 사용하는 이유 알기&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;로그인과 관련된 JWT,&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;JWT를 알기 전에 '인증'과 '인가'에 대한 개념정리를 명확히 하고 들어가야한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;로그인을 하면 그 로그인한 상태가 유지되게 끔해야하는데 그럴 때 관련된 것이 이 '인증'과 '인가'이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;| 인증이란?&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;영어로는 '&lt;span style=&quot;color: #6164c6;&quot;&gt;Authentication&lt;/span&gt;'으로 간단하게 말해 '로그인',&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;'내가 여기 가입회원이다' , '내가 여기 특정서비스에 권한을 가질 수 있는 자다.'를 아이디와 패스워드을 통하여 보여주는&amp;nbsp; 것을 말한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;| 인가란?&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;영어로 '&lt;span style=&quot;color: #6164c6;&quot;&gt;Authorization&lt;/span&gt;' , 위에&amp;nbsp;인증을&amp;nbsp;받은&amp;nbsp;사용자가&amp;nbsp;이&amp;nbsp;인증&amp;nbsp;후&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;서비스의 여러 기능을 이용 시 내가 카톡에 친구추가, 친구에게 답장, 친구의 회신, 좋아요 등을 할 때&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다~ 나의 아이디, 비밀번호로 '인증한 계정으로만' 할 수 있는 활동들을 내가 그&amp;nbsp;서비스를&amp;nbsp;이용할&amp;nbsp;때&amp;nbsp;로그인이&amp;nbsp;되어있는&amp;nbsp;것을&amp;nbsp;보고&amp;nbsp;'그래,&amp;nbsp;좋아요&amp;nbsp;달기&amp;nbsp;허가,&amp;nbsp;목록보기&amp;nbsp;허가'&amp;nbsp;이렇게&amp;nbsp;해주는&amp;nbsp;것.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;즉&amp;nbsp;로그인이&amp;nbsp;되어있는&amp;nbsp;상태에서&amp;nbsp;일어나는&amp;nbsp;일들이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;| JWT란?&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;JSON 객체를 사용하여토근 자체에 정보들을 저장하고 있는 Json web Token &lt;br /&gt;&lt;br /&gt;&lt;b&gt;- JWT의 구성&lt;/b&gt; &lt;br /&gt;Header, Payload, Signature 3개의 부분으로 구성되어져있다.&amp;nbsp;&lt;br /&gt;Signature을 해싱하기 위한 알고리즘 정보들이 담겨져있다.&lt;br /&gt;Payload는 서버와 클라이언트가 주고받는, 시스템에서 실제로 사용될 정보에 대한 내용을 담고있다.&amp;nbsp;&lt;br /&gt;Signatuer은&amp;nbsp;토큰의&amp;nbsp;유효성&amp;nbsp;검증을&amp;nbsp;위한&amp;nbsp;문자열 &lt;br /&gt;&lt;br /&gt;&lt;b&gt;- JWT의 장점?&lt;/b&gt; &lt;br /&gt;-&amp;nbsp;중앙의&amp;nbsp;인증서버,&amp;nbsp;데이터&amp;nbsp;스토어에&amp;nbsp;대한&amp;nbsp;의존성&amp;nbsp;없기&amp;nbsp;때문에&amp;nbsp;시스템&amp;nbsp;수평&amp;nbsp;확장유리 &lt;br /&gt;-&amp;nbsp;Base64&amp;nbsp;URL&amp;nbsp;Safe&amp;nbsp;Encoding을&amp;nbsp;이용하기&amp;nbsp;때문에&amp;nbsp;URL,&amp;nbsp;Cookie,&amp;nbsp;Header모두&amp;nbsp;사용가능하다.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&lt;b&gt;- JWT 단점&lt;/b&gt; &lt;br /&gt;-&amp;nbsp;PayLoad의&amp;nbsp;정보가&amp;nbsp;많아지면&amp;nbsp;네트워크,&amp;nbsp;사용량&amp;nbsp;증가,&amp;nbsp;데이터&amp;nbsp;설계&amp;nbsp;고려&amp;nbsp;필요 &lt;br /&gt;-&amp;nbsp;토큰이&amp;nbsp;클라이언트에&amp;nbsp;저장,&amp;nbsp;서버에서&amp;nbsp;클라이언트의&amp;nbsp;토큰을&amp;nbsp;조작할&amp;nbsp;수&amp;nbsp;없음 &lt;br /&gt;&lt;br /&gt;출처:&amp;nbsp;&lt;a href=&quot;https://mattlee.tistory.com/62&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://mattlee.tistory.com/62&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 : 인프런 - Spring Boot JWT Tutorial&lt;/p&gt;</description>
      <category>Back-end/Spring Boot Security</category>
      <category>Authentication</category>
      <category>Authorization</category>
      <category>JWT</category>
      <category>security</category>
      <category>spring</category>
      <category>spring boot</category>
      <category>spring boot security</category>
      <category>스프링부트 시큐리티</category>
      <category>인가</category>
      <category>인증</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/48</guid>
      <comments>https://thfdl0317.tistory.com/entry/Spring-Boot-Security-JWT#entry48comment</comments>
      <pubDate>Mon, 7 Feb 2022 08:21:01 +0900</pubDate>
    </item>
    <item>
      <title>spring boot  프로잭트 생성 시 lombok 설치 방법</title>
      <link>https://thfdl0317.tistory.com/entry/spring-boot-%ED%94%84%EB%A1%9C%EC%9E%AD%ED%8A%B8-%EC%83%9D%EC%84%B1-%EC%8B%9C-lombok-%EC%84%A4%EC%B9%98-%EB%B0%A9%EB%B2%95</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;| lombok 설치 시 이런 경우&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;설치된 lombok을 두번 클릭하여 열었더니&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;844&quot; data-origin-height=&quot;653&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJPNJT/btrr11yiP2x/u5VS6O88VacmLrUv5KBSXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJPNJT/btrr11yiP2x/u5VS6O88VacmLrUv5KBSXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJPNJT/btrr11yiP2x/u5VS6O88VacmLrUv5KBSXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJPNJT%2Fbtrr11yiP2x%2Fu5VS6O88VacmLrUv5KBSXK%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;509&quot; height=&quot;394&quot; data-origin-width=&quot;844&quot; data-origin-height=&quot;653&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;| 먼저 lombok 다운로드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://projectlombok.org/download&quot;&gt;https://projectlombok.org/download&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;| 해결방법&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;cmd 명령 프롬프트 열고&lt;/span&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;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;  cmd 여는 방법&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;윈도우 검색창에 &amp;rarr; cmd 검색&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;- 윈도우 + R&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;  1번 cd를 치고 뒤에 lombok이 설치되어있는 주소를 입력&lt;b&gt;&lt;span style=&quot;background-color: #000000; color: #ffffff;&quot;&gt; cd &lt;span style=&quot;color: #f89009;&quot;&gt;+&lt;/span&gt; lombok 주소&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  2번&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #000000; color: #ffffff;&quot;&gt; java -jar + 설치된 lombok 버전.jar 입력 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(설치한 lombok 오른쪽 마우스 클릭 &amp;rarr; 속성 클릭 하면 알 수 있음)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;971&quot; data-origin-height=&quot;427&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmXGuq/btrr3nAHawZ/kakaIL38it3KICHJRgxXR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmXGuq/btrr3nAHawZ/kakaIL38it3KICHJRgxXR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmXGuq/btrr3nAHawZ/kakaIL38it3KICHJRgxXR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmXGuq%2Fbtrr3nAHawZ%2FkakaIL38it3KICHJRgxXR1%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;710&quot; height=&quot;312&quot; data-origin-width=&quot;971&quot; data-origin-height=&quot;427&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 lombok에 Specify location 클릭하여 사용하려는 IDE의 주소를 찾아 넣어준다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;831&quot; data-origin-height=&quot;486&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3YF8l/btrr3nm9nTH/ybzG6Pi1cM9PQlA6QTRGo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3YF8l/btrr3nm9nTH/ybzG6Pi1cM9PQlA6QTRGo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3YF8l/btrr3nm9nTH/ybzG6Pi1cM9PQlA6QTRGo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3YF8l%2Fbtrr3nm9nTH%2FybzG6Pi1cM9PQlA6QTRGo1%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;674&quot; height=&quot;394&quot; data-origin-width=&quot;831&quot; data-origin-height=&quot;486&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;422&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qer7L/btrr052xcSJ/4jtNr4BXAISCnGJ7hLq2p0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qer7L/btrr052xcSJ/4jtNr4BXAISCnGJ7hLq2p0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qer7L/btrr052xcSJ/4jtNr4BXAISCnGJ7hLq2p0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fqer7L%2Fbtrr052xcSJ%2F4jtNr4BXAISCnGJ7hLq2p0%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;704&quot; height=&quot;422&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;422&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Jem1y/btrr06tDyLy/sJ7m56BMhKKGAf0KnKBkMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Jem1y/btrr06tDyLy/sJ7m56BMhKKGAf0KnKBkMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Jem1y/btrr06tDyLy/sJ7m56BMhKKGAf0KnKBkMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJem1y%2Fbtrr06tDyLy%2FsJ7m56BMhKKGAf0KnKBkMK%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;754&quot; height=&quot;442&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;내가 설치한 IDE 폴더 안을 들여다봐서 lombok이 있다면 설치 완료이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;246&quot; data-origin-height=&quot;404&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMdmaR/btrr0BnmllT/yWMwOGnurZ1Uk1TXnJeKp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMdmaR/btrr0BnmllT/yWMwOGnurZ1Uk1TXnJeKp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMdmaR/btrr0BnmllT/yWMwOGnurZ1Uk1TXnJeKp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMdmaR%2Fbtrr0BnmllT%2FyWMwOGnurZ1Uk1TXnJeKp1%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;219&quot; height=&quot;360&quot; data-origin-width=&quot;246&quot; data-origin-height=&quot;404&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;참고사이트 - &lt;a href=&quot;https://journeytosth.tistory.com/155&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://journeytosth.tistory.com/155&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Back-end/Spring Boot</category>
      <category>i can't find any IDEs on your computer</category>
      <category>It</category>
      <category>Lombok</category>
      <category>lombok 설치</category>
      <category>spring boot</category>
      <category>롬복</category>
      <category>롬복설치</category>
      <category>스프링부트</category>
      <category>웹개발</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/45</guid>
      <comments>https://thfdl0317.tistory.com/entry/spring-boot-%ED%94%84%EB%A1%9C%EC%9E%AD%ED%8A%B8-%EC%83%9D%EC%84%B1-%EC%8B%9C-lombok-%EC%84%A4%EC%B9%98-%EB%B0%A9%EB%B2%95#entry45comment</comments>
      <pubDate>Sat, 29 Jan 2022 08:19:15 +0900</pubDate>
    </item>
    <item>
      <title>이클립스 실행하려할 때 갑자기 The selection cannot be lauched, and there are no recnet launches.</title>
      <link>https://thfdl0317.tistory.com/entry/%EC%9D%B4%ED%81%B4%EB%A6%BD%EC%8A%A4-%EC%8B%A4%ED%96%89%ED%95%98%EB%A0%A4%ED%95%A0-%EB%95%8C-%EA%B0%91%EC%9E%90%EA%B8%B0-The-selection-cannot-be-lauched-and-there-are-no-recnet-launches</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #666666; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;| 이클립스 실행하려할 때 오류&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이클립스에서 자바 작성 후 실행하려 했더니 이런 창이 튀어나온다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;The selection cannot be launched, and there are no recent launches&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #666666; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;| 오류발생의 이유&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;실행모드가 저장이 안되어서 발생하는 오류,&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;515&quot; data-origin-height=&quot;145&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bg4yav/btrrPpGyBWb/tq26o7hmNhPyKM0DU4yh9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bg4yav/btrrPpGyBWb/tq26o7hmNhPyKM0DU4yh9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bg4yav/btrrPpGyBWb/tq26o7hmNhPyKM0DU4yh9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbg4yav%2FbtrrPpGyBWb%2Ftq26o7hmNhPyKM0DU4yh9K%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;515&quot; height=&quot;145&quot; data-origin-width=&quot;515&quot; data-origin-height=&quot;145&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #666666;&quot;&gt;&lt;b&gt;| 해결 방법&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #666666;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;183&quot; data-origin-height=&quot;249&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/J9NW1/btrrReRBqM1/LkR8SSMJjrItJPJxbbLyS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/J9NW1/btrrReRBqM1/LkR8SSMJjrItJPJxbbLyS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/J9NW1/btrrReRBqM1/LkR8SSMJjrItJPJxbbLyS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJ9NW1%2FbtrrReRBqM1%2FLkR8SSMJjrItJPJxbbLyS0%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;183&quot; height=&quot;249&quot; data-origin-width=&quot;183&quot; data-origin-height=&quot;249&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;599&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBafsE/btrrLNVuSXy/cxepkeZjrMWSfk3J2tsHck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBafsE/btrrLNVuSXy/cxepkeZjrMWSfk3J2tsHck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBafsE/btrrLNVuSXy/cxepkeZjrMWSfk3J2tsHck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBafsE%2FbtrrLNVuSXy%2FcxepkeZjrMWSfk3J2tsHck%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;791&quot; height=&quot;599&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;599&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Apply또는 Apply and Close하면 잘 실행될 것이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Back-end/이클립스 실행 시</category>
      <category>and there are no recent launches</category>
      <category>Java</category>
      <category>The selection cannot be launched</category>
      <category>이클립스</category>
      <category>자바</category>
      <category>자바실행</category>
      <category>자바오류</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/43</guid>
      <comments>https://thfdl0317.tistory.com/entry/%EC%9D%B4%ED%81%B4%EB%A6%BD%EC%8A%A4-%EC%8B%A4%ED%96%89%ED%95%98%EB%A0%A4%ED%95%A0-%EB%95%8C-%EA%B0%91%EC%9E%90%EA%B8%B0-The-selection-cannot-be-lauched-and-there-are-no-recnet-launches#entry43comment</comments>
      <pubDate>Thu, 27 Jan 2022 05:48:41 +0900</pubDate>
    </item>
    <item>
      <title>스프렝 웹 개발 - API @ResponseBody</title>
      <link>https://thfdl0317.tistory.com/entry/%EC%8A%A4%ED%94%84%EB%A0%9D-%EC%9B%B9-%EA%B0%9C%EB%B0%9C-API-ResponseBody</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;HelloController 안에&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1643050648232&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@GetMapping(&quot;hello-string&quot;)
	@ResponseBody
	public String helloString(@RequestParam(&quot;name&quot;) String name) {
		return &quot;hello&quot; +name; 
	}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;| &lt;b&gt;@ResponseBody 의미&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- @ResponseBody &amp;rarr; 이것의 의미는 html에 나오는 body태그가 아니라,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;http에서 header부와 body가 있는데 body부의 내용을 직접내가 넣어주겠다라는 것이다.&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;위의 코드 중 return 코드 해석&lt;/p&gt;
&lt;pre id=&quot;code_1643050762270&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public String helloString(@RequestParam(&quot;name&quot;) String name) {
	return &quot;hello&quot; +name;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 내가 만약 spring이라고 name 값을 넣으면 hello spring&quot; 이라고 바뀐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;|&lt;span&gt; 템플릿 엔진 &lt;span style=&quot;color: #ee2323;&quot;&gt;vs &lt;/span&gt;&lt;/span&gt;@ResponseBody 차이&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전 시간에는 템플릿 엔진을 사용해서 웹브라우저에 넘겼는데, 이 @ResponseBody랑은 무슨 차이가 있는걸까?&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;템플릿엔진&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;@ResponseBody&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;뷰가 있는 상황에서 조작하는 방식&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;return에 있는 것을 그대로 내려준다.&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;| @ResponseBody라고 선언한 코드 안에 객체가 있는 경우&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1643051055627&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	@GetMapping(&quot;hello-api&quot;)
	 @ResponseBody
	 public Hello helloApi(@RequestParam(&quot;name&quot;) String name) {
		Hello hello = new Hello();
		hello.setName(name);
		return hello;
	 }
	
	 static class Hello {
	 private String name;
	 	public String getName() {
	 		return name;
	 }
	 	public void setName(String name) {
	 		this.name = name;
	 }
	 	
	 	//getter, setter를 위에서해주면 이런 매서드에 의해서 접근을 할 수 있다. 프로퍼티 접근방식임 
	 }}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;@ResponseBody 사용원리&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;똑같이 내장 톰켓 서버가 스프링에 던진다.&lt;/li&gt;
&lt;li&gt;스프링은 확인을 하다 어, @ResponseBody 란 것을 확인하고 그냥 이 데이터를 넘겨야겠다. http에, 근데 우리 쓴 거 보면 문자가 아닌 객체다.&lt;/li&gt;
&lt;li&gt;문자인 경우엔 기존에 http응답에 바로 넣어서 주고 끝 근데 객체를 준다?&lt;/li&gt;
&lt;li&gt;스프링입장에서는 객체? 객체가 오면 기본 default가 그냥 joson방식으로 만들어서http에 반환하겠다라고 정했다.&lt;/li&gt;
&lt;li&gt;객체를 보고(기존엔 뷰리졸버가 동작을 했지만)&lt;/li&gt;
&lt;li&gt;조건 2 - 단순 문자면 StringConverter라는게 동작, 객체면 JsonConverter가 작동한다.&lt;/li&gt;
&lt;li&gt;조건 1 - HttpMessageConverter이란 얘가 동작을 한다.&lt;/li&gt;
&lt;li&gt;이 Json스타일로 바꾼 것을 나를 요청한 웹브라우저한테 응답해준다.&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP 의 BODY에 직접 문자내용을 반환한다.&lt;/li&gt;
&lt;li&gt;ViewResolver 대신 HttpMessageContverter가 동작한다.&lt;/li&gt;
&lt;li&gt;기본 문자처리 : StringHttpMessageConverter 가 동작&lt;/li&gt;
&lt;li&gt;기본 객체처리 : MappingJackson2HttpMessageContverter 가 동작Spring은 기본적으로 이것을 사용 jackson이란 라이브러리로 제이슨을 바꿈.&lt;/li&gt;
&lt;li&gt;어? jackson? 유명한 라이브러리 중 하나Jackson이란 라이브러리가 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[참조자료] 인프런&amp;nbsp;&lt;span style=&quot;color: #ffffff;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 v2021&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Back-end/Spring Boot</category>
      <category>@ResponseBody</category>
      <category>http</category>
      <category>HttpMessageContverter</category>
      <category>Jackson</category>
      <category>joson</category>
      <category>spring boot</category>
      <category>StringHttpMessageConverter</category>
      <category>ViewResolver</category>
      <category>스프링부트</category>
      <category>템플릿엔진</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/42</guid>
      <comments>https://thfdl0317.tistory.com/entry/%EC%8A%A4%ED%94%84%EB%A0%9D-%EC%9B%B9-%EA%B0%9C%EB%B0%9C-API-ResponseBody#entry42comment</comments>
      <pubDate>Tue, 25 Jan 2022 04:07:05 +0900</pubDate>
    </item>
    <item>
      <title>스프링 웹 개발 - 템플릿 엔진 thymeleaf</title>
      <link>https://thfdl0317.tistory.com/entry/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9B%B9-%EA%B0%9C%EB%B0%9C-%ED%85%9C%ED%94%8C%EB%A6%BF-%EC%97%94%EC%A7%84-thymeleaf</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;템플릿 엔진을 사용하여 웹브라우저에 입력한 값이 나오게끔 해보자.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;먼저,&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;1. HelloController안에 Get매핑내용입력&lt;/p&gt;
&lt;pre id=&quot;code_1643049205513&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@GetMapping(&quot;hello-mvc&quot;)
	 public String helloMvc(@RequestParam(name = &quot;name&quot;, required = false) String name, Model model) {
	 model.addAttribute(&quot;name&quot;, name);
	 return &quot;hello-template&quot;;
	 }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1267&quot; data-origin-height=&quot;328&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Aw37G/btrrET01974/GEgvwfzS1TKxRLIkXAAxk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Aw37G/btrrET01974/GEgvwfzS1TKxRLIkXAAxk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Aw37G/btrrET01974/GEgvwfzS1TKxRLIkXAAxk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAw37G%2FbtrrET01974%2FGEgvwfzS1TKxRLIkXAAxk0%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;1267&quot; height=&quot;328&quot; data-origin-width=&quot;1267&quot; data-origin-height=&quot;328&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;그리고,&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;2. templates 안에 hello-template.html 만들기&lt;/p&gt;
&lt;pre id=&quot;code_1643049329408&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;html xmlns:th=&quot;http://www.thymeleaf.org&quot;&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;p th:text=&quot;'hello ' + ${name}&quot;&amp;gt;아하!&amp;lt;/p&amp;gt;
&amp;lt;/body&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;298&quot; data-origin-height=&quot;39&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7oZZn/btrruABTSJK/wqwhMoOAUvU7Om3pyk8f30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7oZZn/btrruABTSJK/wqwhMoOAUvU7Om3pyk8f30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7oZZn/btrruABTSJK/wqwhMoOAUvU7Om3pyk8f30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7oZZn%2FbtrruABTSJK%2FwqwhMoOAUvU7Om3pyk8f30%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;298&quot; height=&quot;39&quot; data-origin-width=&quot;298&quot; data-origin-height=&quot;39&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;thymeleaf를 사용하면 1번의 값으로 2번을 치환하기 때문에 서버없이 보기 가능하다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;즉, 1번의 값으로 내용물이 바뀌게 된다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;실행하면 에러나옴&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;497&quot; data-origin-height=&quot;143&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWy2NO/btrrDcG0ksy/kJHJVcaE2ZRzEFMKCTGKJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWy2NO/btrrDcG0ksy/kJHJVcaE2ZRzEFMKCTGKJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWy2NO/btrrDcG0ksy/kJHJVcaE2ZRzEFMKCTGKJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWy2NO%2FbtrrDcG0ksy%2FkJHJVcaE2ZRzEFMKCTGKJ0%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;497&quot; height=&quot;143&quot; data-origin-width=&quot;497&quot; data-origin-height=&quot;143&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #d44c47;&quot;&gt;오류: parameter 'name' for method parameter type String is not present&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;542&quot; data-origin-height=&quot;99&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zDGy8/btrruBt28UI/utFjFHBF35LD3oyITL4soK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zDGy8/btrruBt28UI/utFjFHBF35LD3oyITL4soK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zDGy8/btrruBt28UI/utFjFHBF35LD3oyITL4soK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzDGy8%2FbtrruBt28UI%2FutFjFHBF35LD3oyITL4soK%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;542&quot; height=&quot;99&quot; data-origin-width=&quot;542&quot; data-origin-height=&quot;99&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;name이 있어야한다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;public String helloMvc(@RequestParam(name = &quot;name&quot;, required = false) String name, Model model)&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;required라는 옵션이 있는데 여기에 기본의 값을 넘겨야한다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 false로 작성 후 다시 실행&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;387&quot; data-origin-height=&quot;66&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1TJZe/btrrEFBFRiX/pUMkM8SkugKdlFBjIGgKZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1TJZe/btrrEFBFRiX/pUMkM8SkugKdlFBjIGgKZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1TJZe/btrrEFBFRiX/pUMkM8SkugKdlFBjIGgKZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1TJZe%2FbtrrEFBFRiX%2FpUMkM8SkugKdlFBjIGgKZ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;387&quot; height=&quot;66&quot; data-origin-width=&quot;387&quot; data-origin-height=&quot;66&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;441&quot; data-origin-height=&quot;79&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/be8wJ5/btrrDwkWGk7/qqBxytLG3jHpvlOJuEzKAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/be8wJ5/btrrDwkWGk7/qqBxytLG3jHpvlOJuEzKAK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/be8wJ5/btrrDwkWGk7/qqBxytLG3jHpvlOJuEzKAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbe8wJ5%2FbtrrDwkWGk7%2FqqBxytLG3jHpvlOJuEzKAK%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;441&quot; height=&quot;79&quot; data-origin-width=&quot;441&quot; data-origin-height=&quot;79&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 되어진 원리는&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;90&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xrj4C/btrrAd7xAlF/ZxSB5hWl1qk9qP23cP6ENk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xrj4C/btrrAd7xAlF/ZxSB5hWl1qk9qP23cP6ENk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xrj4C/btrrAd7xAlF/ZxSB5hWl1qk9qP23cP6ENk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fxrj4C%2FbtrrAd7xAlF%2FZxSB5hWl1qk9qP23cP6ENk%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;686&quot; height=&quot;90&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;90&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;1번 name은 &amp;lsquo;맘대로써보자&amp;rsquo; 로바뀌고&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;2번도 name은 &amp;lsquo;맘대로써보자&amp;rsquo; 바뀌고&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;hello-template.html에서도 name은 모델에서 값을 꺼내는 것.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 &amp;lsquo;맘대로써보자&amp;rsquo;라고 했던 값이 나오는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;645&quot; data-origin-height=&quot;97&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmpYpJ/btrrxYQljG9/TcY9DOhIeWKOG2b9Fe6rP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmpYpJ/btrrxYQljG9/TcY9DOhIeWKOG2b9Fe6rP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmpYpJ/btrrxYQljG9/TcY9DOhIeWKOG2b9Fe6rP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmpYpJ%2FbtrrxYQljG9%2FTcY9DOhIeWKOG2b9Fe6rP0%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;645&quot; height=&quot;97&quot; data-origin-width=&quot;645&quot; data-origin-height=&quot;97&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;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;웹 브라우저에서 &lt;a href=&quot;http://localhost:8080&quot;&gt;localhost:8080&lt;/a&gt;/hello-mvc를 넘기면&lt;/li&gt;
&lt;li&gt;내장 톰켓 서버를 먼저 거치며 &amp;ldquo;어! hello-mvc가 왔네!&amp;rdquo; 하고 스프링에 던지고helloController에 넘김&lt;/li&gt;
&lt;li&gt;helloController에 맴핑된 메소드를 호출&lt;/li&gt;
&lt;li&gt;return은 hello-template, model은 name : 맘대로써보자. 라는 것을 또 넘긴다.&lt;/li&gt;
&lt;li&gt;넘긴 곳은 viewResolver. 여기서처리해달라하고 thymeleaf 랜더링해서 변환한 html을 웹브라우저에 넘긴다.&lt;/li&gt;
&lt;li&gt;스프링의 view를 찾아주고 템플릿에 연결해주는 viewResolver가 templates/hello-template.html라는 return과 똑같은 얘를 찾아서 thymeleaf템플릿 엔진에게&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[참조자료] 인프런 &lt;span style=&quot;color: #ffffff;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 v2021&lt;/span&gt;1&lt;/span&gt;&lt;/p&gt;</description>
      <category>Back-end/Spring Boot</category>
      <category>It</category>
      <category>required</category>
      <category>spring boot</category>
      <category>template</category>
      <category>thymeleaf</category>
      <category>ViewResolver</category>
      <category>백엔드</category>
      <category>스프링 부트</category>
      <category>웹개발</category>
      <category>템플릿 엔진</category>
      <author>카드값줘체리</author>
      <guid isPermaLink="true">https://thfdl0317.tistory.com/41</guid>
      <comments>https://thfdl0317.tistory.com/entry/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9B%B9-%EA%B0%9C%EB%B0%9C-%ED%85%9C%ED%94%8C%EB%A6%BF-%EC%97%94%EC%A7%84-thymeleaf#entry41comment</comments>
      <pubDate>Tue, 25 Jan 2022 03:49:44 +0900</pubDate>
    </item>
  </channel>
</rss>