<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개발자 도전기</title>
    <link>https://c-uncle-full-stack.tistory.com/</link>
    <description>개발공부</description>
    <language>ko</language>
    <pubDate>Sat, 20 Jun 2026 11:57:31 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>모건이삼촌</managingEditor>
    <image>
      <title>개발자 도전기</title>
      <url>https://tistory1.daumcdn.net/tistory/5905520/attach/5405a540fe26492fae0a7e8cf45bbc9e</url>
      <link>https://c-uncle-full-stack.tistory.com</link>
    </image>
    <item>
      <title>php spreadsheet 셀 스타일 메서드 정리</title>
      <link>https://c-uncle-full-stack.tistory.com/175</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;php excel의 메서드가 필요할 경우 아래 링크로 이동하길 바람&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://c-uncle-full-stack.tistory.com/168&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://c-uncle-full-stack.tistory.com/168&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1746665767385&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;php excel 셀 스타일 메서드 정리&quot; data-og-description=&quot;excel-&amp;gt;getActiveSheet()-&amp;gt;getStyle(&amp;quot;A1:K5&amp;quot;)-&amp;gt;getAlignment()-&amp;gt;setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);// 텍스트 세로 정렬$this-&amp;gt;excel-&amp;gt;getActiveSheet()-&amp;gt;getStyle('A2:K2')-&amp;gt;getAlignment()-&amp;gt;setVertical(PHPExcel_Style_Alignment::VERTIC&quot; data-og-host=&quot;blog.chanyongyang.com&quot; data-og-source-url=&quot;https://c-uncle-full-stack.tistory.com/168&quot; data-og-url=&quot;https://blog.chanyongyang.com/168&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cCh4T6/hyYRpeGTvC/H1M8M9h3BZZ37aHAWUoadk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/ctrgv3/hyYMU1J0FT/SN87jUCDLdH5HKhESNMlDK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/RycE5/hyYPlKUPpY/7KiKysKYYEQCuya7MESNck/img.jpg?width=259&amp;amp;height=276&amp;amp;face=0_0_259_276&quot;&gt;&lt;a href=&quot;https://c-uncle-full-stack.tistory.com/168&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://c-uncle-full-stack.tistory.com/168&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cCh4T6/hyYRpeGTvC/H1M8M9h3BZZ37aHAWUoadk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/ctrgv3/hyYMU1J0FT/SN87jUCDLdH5HKhESNMlDK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/RycE5/hyYPlKUPpY/7KiKysKYYEQCuya7MESNck/img.jpg?width=259&amp;amp;height=276&amp;amp;face=0_0_259_276');&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;php excel 셀 스타일 메서드 정리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;excel-&amp;gt;getActiveSheet()-&amp;gt;getStyle(&quot;A1:K5&quot;)-&amp;gt;getAlignment()-&amp;gt;setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);// 텍스트 세로 정렬$this-&amp;gt;excel-&amp;gt;getActiveSheet()-&amp;gt;getStyle('A2:K2')-&amp;gt;getAlignment()-&amp;gt;setVertical(PHPExcel_Style_Alignment::VERTIC&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.chanyongyang.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1746667586359&quot; class=&quot;php&quot; data-ke-language=&quot;php&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?
# 너비조절
$spreadsheet-&amp;gt;getActiveSheet()-&amp;gt;getColumnDimension('A')-&amp;gt;setWidth(10);
$spreadsheet-&amp;gt;getActiveSheet()-&amp;gt;getColumnDimension('B')-&amp;gt;setWidth(10);
$spreadsheet-&amp;gt;getActiveSheet()-&amp;gt;getColumnDimension('C')-&amp;gt;setWidth(20);

# 셀 배경색상 변경
$spreadsheet-&amp;gt;getActiveSheet()-&amp;gt;getStyle('A1:L1')-&amp;gt;getFill()-&amp;gt;setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)-&amp;gt;getStartColor()-&amp;gt;setARGB('e9e9e9');
# 셀 배경색상 변경 - A1부터 L12까지 배경색상 변경
$spreadsheet-&amp;gt;getActiveSheet()-&amp;gt;getStyle('A1:L12')-&amp;gt;getFill()-&amp;gt;setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)-&amp;gt;getStartColor()-&amp;gt;setARGB('e9e9e9');

# 셀 정렬 -&amp;gt; 가로정렬
# 가로정렬 -&amp;gt; 가운데 정렬
$spreadsheet-&amp;gt;getActiveSheet()-&amp;gt;getStyle(&quot;A1:H1&quot;)-&amp;gt;getAlignment()-&amp;gt;setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER);
# 가로정렬 -&amp;gt; 좌측 정렬
$spreadsheet-&amp;gt;getActiveSheet()-&amp;gt;getStyle(&quot;B2:B2&quot;)-&amp;gt;getAlignment()-&amp;gt;setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_LEFT);
# 가로정렬 -&amp;gt; 우측 정렬
$spreadsheet-&amp;gt;getActiveSheet()-&amp;gt;getStyle(&quot;F2:H2&quot;)-&amp;gt;getAlignment()-&amp;gt;setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_RIGHT);
# 가로정렬 -&amp;gt; 양쪽 정렬
$spreadsheet-&amp;gt;getActiveSheet()-&amp;gt;getStyle(&quot;F2:H2&quot;)-&amp;gt;getAlignment()-&amp;gt;setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_JUSTIFY);
# 가로정렬 -&amp;gt; 병합된 셀 가운데 정렬
$spreadsheet-&amp;gt;getActiveSheet()-&amp;gt;getStyle(&quot;F2:H2&quot;)-&amp;gt;getAlignment()-&amp;gt;setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER_CONTINUOUS);
# 가로정렬 -&amp;gt; 균등 정렬
$spreadsheet-&amp;gt;getActiveSheet()-&amp;gt;getStyle(&quot;F2:H2&quot;)-&amp;gt;getAlignment()-&amp;gt;setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_DISTRIBUTED);


# 세로 정렬 -&amp;gt; 상단 정렬
$spreadsheet-&amp;gt;getActiveSheet()-&amp;gt;getStyle(&quot;A1:H1&quot;)-&amp;gt;getAlignment()-&amp;gt;setVertical(\PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_TOP);
# 세로 정렬 -&amp;gt; 하단 정렬
$spreadsheet-&amp;gt;getActiveSheet()-&amp;gt;getStyle(&quot;A1:H1&quot;)-&amp;gt;getAlignment()-&amp;gt;setVertical(\PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_BOTTOM);
# 세로 정렬 -&amp;gt; 가운데 정렬
$spreadsheet-&amp;gt;getActiveSheet()-&amp;gt;getStyle(&quot;A1:H1&quot;)-&amp;gt;getAlignment()-&amp;gt;setVertical(\PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER);
# 세로 정렬 -&amp;gt; 양쪽 정렬
$spreadsheet-&amp;gt;getActiveSheet()-&amp;gt;getStyle(&quot;A1:H1&quot;)-&amp;gt;getAlignment()-&amp;gt;setVertical(\PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_JUSTIFY);
# 세로 정렬 -&amp;gt; 균등 정렬
$spreadsheet-&amp;gt;getActiveSheet()-&amp;gt;getStyle(&quot;A1:H1&quot;)-&amp;gt;getAlignment()-&amp;gt;setVertical(\PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_DISTRIBUTED);

//윤곽선
$spreadsheet-&amp;gt;getActiveSheet()-&amp;gt;getStyle('A1:L'.$i)-&amp;gt;getBorders()-&amp;gt;getAllBorders()-&amp;gt;setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN);&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;</description>
      <category>php</category>
      <category>phpspreadsheet</category>
      <author>모건이삼촌</author>
      <guid isPermaLink="true">https://c-uncle-full-stack.tistory.com/175</guid>
      <comments>https://c-uncle-full-stack.tistory.com/175#entry175comment</comments>
      <pubDate>Thu, 8 May 2025 10:26:58 +0900</pubDate>
    </item>
    <item>
      <title>며칠전 부터 일하다가 문득</title>
      <link>https://c-uncle-full-stack.tistory.com/169</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;간단한 백단을 구성해서 스웨거로 테스트 및 배포까지 진행해볼예정&lt;/p&gt;</description>
      <category>Kotlin</category>
      <author>모건이삼촌</author>
      <guid isPermaLink="true">https://c-uncle-full-stack.tistory.com/169</guid>
      <comments>https://c-uncle-full-stack.tistory.com/169#entry169comment</comments>
      <pubDate>Thu, 12 Dec 2024 20:49:52 +0900</pubDate>
    </item>
    <item>
      <title>php excel 셀 스타일 메서드 정리</title>
      <link>https://c-uncle-full-stack.tistory.com/168</link>
      <description>&lt;pre id=&quot;code_1732682352346&quot; class=&quot;php&quot; data-ke-language=&quot;php&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?

// 텍스트 가운데 정렬
$this-&amp;gt;excel-&amp;gt;getActiveSheet()-&amp;gt;getStyle(&quot;A1:K5&quot;)-&amp;gt;getAlignment()-&amp;gt;setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);

// 텍스트 세로 정렬
$this-&amp;gt;excel-&amp;gt;getActiveSheet()-&amp;gt;getStyle('A2:K2')-&amp;gt;getAlignment()-&amp;gt;setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);

// 테두리
$this-&amp;gt;excel-&amp;gt;getActiveSheet()-&amp;gt;getStyle(&quot;A1:K5&quot;)-&amp;gt;getBorders()-&amp;gt;getAllBorders()-&amp;gt;setBorderStyle(PHPExcel_Style_Border::BORDER_THIN);

// 배경색
$this-&amp;gt;excel-&amp;gt;getActiveSheet()-&amp;gt;getStyle(&quot;A1:K1&quot;)-&amp;gt;getFill()-&amp;gt;setFillType(PHPExcel_Style_Fill::FILL_SOLID)-&amp;gt;getStartColor()-&amp;gt;setARGB(&quot;FFD3D3D3&quot;);

// 배경색2
$this-&amp;gt;excel-&amp;gt;getActiveSheet()-&amp;gt;getStyle(&quot;A2&quot;)-&amp;gt;getFill()-&amp;gt;setFillType(PHPExcel_Style_Fill::FILL_SOLID)-&amp;gt;getStartColor()-&amp;gt;setARGB(&quot;FFFFFF00&quot;);
$this-&amp;gt;excel-&amp;gt;getActiveSheet()-&amp;gt;getStyle(&quot;C2:H2&quot;)-&amp;gt;getFill()-&amp;gt;setFillType(PHPExcel_Style_Fill::FILL_SOLID)-&amp;gt;getStartColor()-&amp;gt;setARGB(&quot;FFFFFF00&quot;);

// 볼드체 변경
$this-&amp;gt;excel-&amp;gt;getActiveSheet()-&amp;gt;getStyle('A2')-&amp;gt;getFont()-&amp;gt;setBold(true);
$this-&amp;gt;excel-&amp;gt;getActiveSheet()-&amp;gt;getStyle('C2:H2')-&amp;gt;getFont()-&amp;gt;setBold(true);

// 개행처리
$this-&amp;gt;excel-&amp;gt;getActiveSheet()-&amp;gt;getStyle('F2')-&amp;gt;getAlignment()-&amp;gt;setWrapText(true);

// 셀 병합
$this-&amp;gt;excel-&amp;gt;getActiveSheet()-&amp;gt;mergeCells('A1:E1');

// 폰트 크기
$this-&amp;gt;excel-&amp;gt;getActiveSheet()-&amp;gt;getStyle('A1')-&amp;gt;getFont()-&amp;gt;setSize(18);


?&amp;gt;&lt;/code&gt;&lt;/pre&gt;</description>
      <author>모건이삼촌</author>
      <guid isPermaLink="true">https://c-uncle-full-stack.tistory.com/168</guid>
      <comments>https://c-uncle-full-stack.tistory.com/168#entry168comment</comments>
      <pubDate>Wed, 27 Nov 2024 13:39:33 +0900</pubDate>
    </item>
    <item>
      <title>window.onload(js)와 $(document).ready(jquery)의 차이</title>
      <link>https://c-uncle-full-stack.tistory.com/167</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;js의 window.onload (이하 onload)와 jquery의 $(document).ready (이하 ready)의 차이에 대해서 알아보겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 나는 두 함수를 그냥 페이지가 로드될 때 실행되는 함수라고만 생각했으나, 호출 시점의 차이가 있다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 아래 예제를 보겠다.&lt;/p&gt;
&lt;pre id=&quot;code_1705494863710&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 호출 시점에 대한 차이

window.onload = function() {
	alert(&quot;a&quot;);
}

$(document).ready(function() {
	alert(&quot;b&quot;);
});

$(document).ready(function() {
	alert(&quot;c&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;위 코드의 실행 순서는 b -&amp;gt; c -&amp;gt; a가 된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 ready가 먼저 실행될까??? 우선 onload부터 알아보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0. HTML 문서의 처리 및 렌더링 과정&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML 문서 파싱 : 브라우저가 HTML문서를 받아들이고, 파싱하여 DOM Tree 형성&lt;/li&gt;
&lt;li&gt;정적자원 로드 : DOM Tree 형성 후 html문서에 포함된 외부 정적자원(image, stylesheet, script)로드&lt;/li&gt;
&lt;li&gt;로딩이 완료된 후 js가 실행되어 추가적인 자원 로드 (동적페이지)&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;1. window.onload&lt;/p&gt;
&lt;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;- dom의 모든 구성요소가 로드되고, 정적자원(이미지 등)이 로드 되면 실행이 되는 함수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 동일한 문서에는 오직 하나의 onload만 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- onload를 중복선언했을 경우 가장 마지막 onload만 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- window 객체가 실행되었을 때 혹은 원하는 돔 객체가 로드되었을 때 실행할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1705495489922&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;document.getElementById('name').onload = function() {
	alert('실행');
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- jquery의 load는 onload와 같은 동작을 하는 함수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;1-1. DOMContentLoaded&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- ready와 실행시점이 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- ready처럼 중복해서 사용할 수 없다. (이벤트 리스너의 규칙, 중복 등록시 마지막에 등록한 리스너만 실행됨)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- 사용방법은 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1705496947415&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;document.addEventListener('DOMContentLoaded', function() {
	alert('DOM 로드된 후 실행');
});&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. $(document).ready&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- DOM Tree가 완성되면 바로 실행된다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;2-1. $(function() {})&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- $(document).ready와 같다 사용방법은 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1705498746996&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$(function() {
	alert(&quot;DOM 로드된 후 실행&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;3. DOM(Document Object Model)트리란 무엇인가? &lt;span style=&quot;color: #006dd7;&quot;&gt;*이해를 돕기위함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- DOM Tree란 HTML 또는 XML 문서의 구조를 계층적으로 나타낸것, 각 구성요소를 노드(node)라고 부르며 node는 객체(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;3-1. node의 종류&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Document Node : 문서 전체를 나타내는 최상위 노드 (html)&lt;/li&gt;
&lt;li&gt;Element Node : html요소 (p, div, ul 등)&lt;/li&gt;
&lt;li&gt;Attribute Node : html요소의 속성 (id 등)&lt;/li&gt;
&lt;li&gt;Text Node : 요소의 텍스트 내용 (&amp;lt;h1&amp;gt;hello&amp;lt;/h1&amp;gt; 의 hello 부분)&lt;/li&gt;
&lt;li&gt;Comment Node : 주석&lt;/li&gt;
&lt;li&gt;Document Type Declaration Node : html문서의 형식 선언문 (!DOCTYPE html)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;3-2 부모(parent)와 자식(child) 관계&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- 한 노드가 다른 노드를 포함하는 경우 그 노드는 부모이고, 포함되는 노드는 자식이 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1705496492991&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div&amp;gt;
	&amp;lt;p&amp;gt;child&amp;lt;/p&amp;gt;
   	&amp;lt;p&amp;gt;child&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; &amp;nbsp; - 위 예제에서 div태그가 부모, p태그가 자식 관계가 성립된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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;- onload와 ready에 대해서 알아보았다. 비슷한 성질을 가지고 있지만, 실행시점은 다르다. (ready가 더 빠름)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- ready와 비슷한 DOMContentLoaded 이벤트가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- onload는 모든 정적자원이 로드되었을 때 실행되므로 자원들이 로드되었을 때의 이벤트를 생각한다면 사용하는게 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- jquery를 사용하지 않는경우 DOMContentLoaded를 사용을 고려해볼만하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- ready는 $(function() {})으로 축약하여 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 대용량 동영상과 같은 큰 리소스는 리소스를 가져오는 함수를 ready에 사용하는게 적합하다.&lt;/p&gt;</description>
      <category>HTML5, CSS3/Java Script</category>
      <author>모건이삼촌</author>
      <guid isPermaLink="true">https://c-uncle-full-stack.tistory.com/167</guid>
      <comments>https://c-uncle-full-stack.tistory.com/167#entry167comment</comments>
      <pubDate>Wed, 17 Jan 2024 22:18:48 +0900</pubDate>
    </item>
    <item>
      <title>23-11-28 windows 개발환경에 php 설치</title>
      <link>https://c-uncle-full-stack.tistory.com/163</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;1. php 설치&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://windows.php.net/download/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://windows.php.net/download/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;링크에 들어가 버전에 맞는 php 설치&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;1139&quot; data-origin-height=&quot;721&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dWy8W1/btsAZ9Pdetp/KApRMk0KqFw0M4Pxu3tx71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dWy8W1/btsAZ9Pdetp/KApRMk0KqFw0M4Pxu3tx71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dWy8W1/btsAZ9Pdetp/KApRMk0KqFw0M4Pxu3tx71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdWy8W1%2FbtsAZ9Pdetp%2FKApRMk0KqFw0M4Pxu3tx71%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1139&quot; height=&quot;721&quot; data-origin-width=&quot;1139&quot; data-origin-height=&quot;721&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;2. 압축 해제 및 ini 파일 수정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;2-1. 필자는 C:\php8.3.0 에 압축을 해제함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;2-2. php.ini-development 파일을 복사 붙여넣기 해서 php.ini 파일로 이름 변경&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;2-3. php.ini 파일을 vscode 에서 열고 ctrl+f로 본인이 원하는 기능을 찾아 주석을 해제해야함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - extension_dir = 'C:\php8.3.0\ext'&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - extension의 경로를 설정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - short_open_tag = on&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp; &amp;nbsp; -&lt;span&gt; &amp;lt;?php 태그 사용 on&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;3. php 환경변수 등록&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1653&quot; data-origin-height=&quot;1219&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cq8ZbH/btsA7ZxiMC4/PjyVFUgNopLfS1AjChPPN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cq8ZbH/btsA7ZxiMC4/PjyVFUgNopLfS1AjChPPN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cq8ZbH/btsA7ZxiMC4/PjyVFUgNopLfS1AjChPPN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcq8ZbH%2FbtsA7ZxiMC4%2FPjyVFUgNopLfS1AjChPPN0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1653&quot; height=&quot;1219&quot; data-origin-width=&quot;1653&quot; data-origin-height=&quot;1219&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <author>모건이삼촌</author>
      <guid isPermaLink="true">https://c-uncle-full-stack.tistory.com/163</guid>
      <comments>https://c-uncle-full-stack.tistory.com/163#entry163comment</comments>
      <pubDate>Tue, 28 Nov 2023 20:12:04 +0900</pubDate>
    </item>
    <item>
      <title>jwt 관련 정리글 (만료시간, 토큰 생성 및 통신, 시나리오)</title>
      <link>https://c-uncle-full-stack.tistory.com/158</link>
      <description>&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;1. 필자는 MEVN(MongoDB, Express.js, Vue.js, Node.js) 프로젝트를 하고있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. refresh 토큰과 access 토큰을 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. refresh 토큰은 redis에 저장하여 사용&lt;/p&gt;
&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. jwt 인증시간을 설정하면 앞단에서 만료시간을 정할 필요가 없음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 토큰의 만료시간은 토큰을 검증하는 과정속에서 내가 정해둔 만료시간을 확인하고 만료시간 도달시 재발급 하는 수순으로 작업하게됨 (지우게 된다면 좀 끔찍해질수도..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 그러나 redis의 만료시간은 설정해주는게 좋을거 같음 &lt;b&gt;(개인적인 생각)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 불필요한 리소스를 삭제하는게 옳다고 생각하기 때문 (물론 refresh token의 만료시간은 길다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;※ 토큰 생성 및 통신&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. 토큰 생성&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;1-1. id, pw값을 json에 담아 백엔드 login api로 전송(axios) - front&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;1-2. 프론트에서 전송된 값을 토대로 access토큰, refresh토큰 생성 - back&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;1-3. refresh토큰을 redis에 저장, res.json으로 access, refresh 토큰을 front로 전송 - back&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;1-4-1. response.data로 백엔드에서 전송된 토큰값을 vue-cookies를 사용하여 쿠키로 저장 - front&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;1-4-2.&lt;span&gt;&amp;nbsp;&lt;/span&gt;response.data로 백엔드에서 전송된 토큰값을 localStorage 혹은 sessionStorage에 저장 -front&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;2. 토큰 시나리오(login 상태 확인, 권한 확인 등을 위한)를 위한 통신&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;2-1. localStorage 혹은 sessionStorage 혹은 vue-cookies에 담겨있는 토큰값을 headers에 담아 백엔드로 전송 - front&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;2-2. 토큰 검증 후 &lt;b&gt;토큰 시나리오&lt;/b&gt; 진행 - back&lt;/p&gt;
&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;0. &lt;b&gt;토큰이 있다&lt;/b&gt;(설정해둔 &lt;b&gt;만료시간이 유효&lt;/b&gt;하다), &lt;b&gt;토큰이 없다&lt;/b&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;1. refresh토큰과 access토큰이 있다 -&amp;gt; 해당 페이지 route&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. refresh토큰은 있으나 access토큰은 없다 -&amp;gt; 기존 access토큰의 payload값을 decoded한 후 newAccess토큰 발급&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. refresh토큰은 없고 access토큰은 있을경우 -&amp;gt; access토큰을 기반으로 newRefresh토큰 발급&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 둘 다 없는경우 -&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;&amp;nbsp; &amp;nbsp;&lt;/p&gt;</description>
      <category>기타 라이브러리 및 프레임워크</category>
      <category>Express</category>
      <category>jsonwebtoken</category>
      <category>JWT</category>
      <category>jwt 통신</category>
      <category>jwt관련</category>
      <category>MongoDB</category>
      <category>redis</category>
      <category>VUE</category>
      <author>모건이삼촌</author>
      <guid isPermaLink="true">https://c-uncle-full-stack.tistory.com/158</guid>
      <comments>https://c-uncle-full-stack.tistory.com/158#entry158comment</comments>
      <pubDate>Wed, 25 Oct 2023 00:31:04 +0900</pubDate>
    </item>
    <item>
      <title>23-09-10 passport를 활용하여 login기능 구현</title>
      <link>https://c-uncle-full-stack.tistory.com/156</link>
      <description>&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;※ 목차&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;패키지 구조&lt;/li&gt;&lt;li&gt;passport 동작 과정&lt;/li&gt;&lt;li&gt;auth.js&lt;/li&gt;&lt;li&gt;local strategy.js, index.js&lt;/li&gt;&lt;li&gt;middlewares.js&lt;/li&gt;&lt;li&gt;app.js 적용&lt;/li&gt;&lt;li&gt;postman test&lt;/li&gt;&lt;li&gt;후기&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;0. 패키지 구조&lt;/p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;328&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n5mDW/btstCHYbAks/vLswJCzkCrQ60Q8pjkGoFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n5mDW/btstCHYbAks/vLswJCzkCrQ60Q8pjkGoFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n5mDW/btstCHYbAks/vLswJCzkCrQ60Q8pjkGoFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn5mDW%2FbtstCHYbAks%2FvLswJCzkCrQ60Q8pjkGoFk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;328&quot; height=&quot;788&quot; data-origin-width=&quot;328&quot; data-origin-height=&quot;788&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;br&gt;1. passport 동작 과정&lt;br&gt;&amp;nbsp;&lt;br&gt;routes/auth.js &lt;br&gt;/login&amp;nbsp;으로&amp;nbsp;POST요청이&amp;nbsp;올경우&amp;nbsp;passport.authenticate실행. &lt;br&gt;첫번째&amp;nbsp;매개변수(전략)을&amp;nbsp;통해&amp;nbsp;내가&amp;nbsp;설정한&amp;nbsp;전략을&amp;nbsp;실행함. &lt;br&gt;*&amp;nbsp;local&amp;nbsp;전략이라는&amp;nbsp;가정하에&amp;nbsp;작성 &lt;br&gt;&lt;br&gt;passport/localStrategy.js &lt;br&gt;LocalStrategy&amp;nbsp;객체에&amp;nbsp;내가&amp;nbsp;options으로&amp;nbsp;설정한&amp;nbsp;필드값을&amp;nbsp;검증받아&amp;nbsp;객체&amp;nbsp;생성 &lt;br&gt;상수(이하&amp;nbsp;user)에&amp;nbsp;id를&amp;nbsp;req.params값으로&amp;nbsp;받아&amp;nbsp;db에서&amp;nbsp;id탐색 &lt;br&gt;탐색&amp;nbsp;후&amp;nbsp;찾는&amp;nbsp;id가&amp;nbsp;있다면&amp;nbsp;비밀번호&amp;nbsp;검증&amp;nbsp;실행 &lt;br&gt;검증&amp;nbsp;후&amp;nbsp;비밀번호가&amp;nbsp;일치하면&amp;nbsp;done(null,&amp;nbsp;user)&amp;nbsp;리턴 &lt;br&gt;id&amp;nbsp;혹은&amp;nbsp;비밀번호가&amp;nbsp;일치하지&amp;nbsp;않으면&amp;nbsp;message&amp;nbsp;전송 &lt;br&gt;&lt;br&gt;routes/auth.js &lt;br&gt;다시&amp;nbsp;돌아와&amp;nbsp;user값이&amp;nbsp;있으면&amp;nbsp;session에&amp;nbsp;값&amp;nbsp;저장&lt;br&gt;session id를 cookie에 저장&lt;br&gt;user가 없거나 서버에 에러가 났을경우 에러메세지 출력&lt;br&gt;&amp;nbsp;&lt;br&gt;passport/index.js&lt;br&gt;login 검증이 끝나면 passport.serializeUser실행&lt;br&gt;req.user 호출시 deserializeUser을 실행하여 response&lt;br&gt;&amp;nbsp;&lt;br&gt;위 설명을 그림으로 표현하자면 아래와 같다.&lt;/p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1129&quot; data-origin-height=&quot;558&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkbh4N/btstwHyDoIv/uY2InMoqqbaQOrSATnokl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkbh4N/btstwHyDoIv/uY2InMoqqbaQOrSATnokl0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkbh4N/btstwHyDoIv/uY2InMoqqbaQOrSATnokl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbkbh4N%2FbtstwHyDoIv%2FuY2InMoqqbaQOrSATnokl0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1129&quot; height=&quot;558&quot; data-origin-width=&quot;1129&quot; data-origin-height=&quot;558&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;2. auth.js&lt;br&gt;&amp;nbsp;2-1. 회원가입 로직 생성&lt;br&gt;root/models/member.js&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const mongoose = require('mongoose');
const bcrypt = require('bcrypt');

const Account = new mongoose.Schema({
	//unique를 사용하여 중복방지, required를 사용하여 not null
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;username : {type:String, unique:true, required: true},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pw : {type:String, required: true},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;nickName : {type:String, required: true},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// default:Date.now()를 사용하여 가입날짜 지정
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;regDate: {type:Date, default:Date.now()},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;updateDate:{type:Date, default: Date.now()}
});

Account.statics.create = async function(payload) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const member = new this(payload);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// bcrypt를 사용하여 pw 암호화
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;member.pw = await bcrypt.hash(payload.pw, 10);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return member.save();
};

module.exports = mongoose.model(&quot;Member&quot;, Account);&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;br&gt;root/routes/members.js&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const router = require('express').Router();
const Member = require('../models/member');

const register = router.post('/signup', (req, res) =&amp;gt; {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Member.create(req.body)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.then(member =&amp;gt; res.send(member))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.catch(err =&amp;gt; res.status(500).send(err));
});

module.exports = router;&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;br&gt;2-2. 로그인 로직생성&lt;br&gt;root/routes/auth.js&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const express = require('express');
const passport = require('passport');
const bcrypt = require('bcrypt');
const Member = require('../models/member');
const {isLoggedIn, isNotLoggedIn} = require('./middlewares');
const router = express.Router();

router.post('/login', isNotLoggedIn, (req, res, next) =&amp;gt; {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;console.log('login user -&amp;gt;', req.body);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// local은 local전략을 사용하겠다는 뜻
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// passport.authenticate가 실행되면 전략에 맞춰 구성해놓은 전략이 실행됨
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 예를들어 local로 지정해놨다하면 passport/localStrategy.js가 실행되어 회원검증을 함
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;passport.authenticate('local', (err, member, info) =&amp;gt; {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(err) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;console.error(err);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return next(err);
&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;if(!member) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return res.redirect(`/auth/?loginError=${info.message}`);
&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;return req.login(member, loginError =&amp;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;if(loginError) {
&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;console.error(loginError);
&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;return next(loginError);
&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;// return res.json({message:&quot;로그인&quot;});
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// return res.send(member);
&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;// 로그인 검증이 끝나면 http://localhost로 redirect
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return res.redirect('/');
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;});
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;})(req, res, next);
});
&amp;nbsp;&amp;nbsp; 
router.get('/logout', isLoggedIn, (req, res) =&amp;gt; {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;req.logout()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;req.session.destroy();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;res.redirect('/')
});

module.exports = router;&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #009A87;&quot;&gt;* 필자는 Missing Credentials에러가 나서 에러를 해결했는데, 원인을 확인해보니 localStratege.js 설정중 회원을 제대로찾지 못해 나온 에러였다. 본인이 js를 잘 하지 못하면 log를 찍어 코드가 어디까지 통과했는지 어디서 막혔는지 잘 찾아내는게 중요하다.&lt;/span&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;3. LocalStrategy.js, Index.js&lt;br&gt;&amp;nbsp;3-1. root/passport/localStrategy.js&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const bcrypt = require('bcrypt');

const Member = require('../models/member');

module.exports = () =&amp;gt; {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;passport.use(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;new LocalStrategy(
&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;// 본인이 구성한 Member Schema대로 필드값을 받아야한다
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 예를들어 id의 Documnet가 userId일경우 usernameField에 userId라고 적어야 한다.
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// pw도 위와 같다.
&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;usernameField : 'username', // 
&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;passwordField : 'pw',
&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;// exUser를 먼저 찾아와야하기 때문에 콜백함수(async, await) 사용
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;async (username, pw, done) =&amp;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;try {
&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;console.log(username);
					
&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;// usernameField에 적혀진대로 username을 받아 db에 값이 있는지 찾는다.
&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;const exUser = await Member.findOne({ username : username});
&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;console.log(&quot;exUser : &quot;, exUser)
&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;if(exUser) {
&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;	// 값이 있는지 확인 후 pw 검증
&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;const result = await bcrypt.compare(pw, exUser.pw)
&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;if(result) {
&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;	// pw 일치시 done 호출
&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;return done(null, exUser);
&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;}else {
&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;	// pw 일치하지 않을경우 message 출력
&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;done(null, false, {message : '비밀번호가 일치 하지 않습니다.'})
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// exUser를 찾지못했을경우 message 출력
&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;done(null, false, {message : '가입되지 않은 회원입니다.'})
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}catch (err) {
&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;console.error(&quot;err =&quot;,err)
&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;done(err)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;);
};&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;3-2. root/passport/index.js&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const passport = require('passport');
const local = require('./localStrategy');
const Member = require('../models/member');

module.exports = () =&amp;gt; {
	// passport를 사용하여 로그인이 성공했을때 실행
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;passport.serializeUser((user, done) =&amp;gt; {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;console.log('serializeUser -&amp;gt; ', user)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;done(null, user.username);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;})

	// 로그인한 유저정보를 호출했을시(req.user) 실행
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;passport.deserializeUser((username, done) =&amp;gt; {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Member.findOne({username: username})
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.then(user =&amp;gt; done(null, user))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.catch(err =&amp;gt; done(err));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;})

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;local();
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;br&gt;4. middlewares.js&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;exports.isLoggedIn = (req, res, next) =&amp;gt; {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(req.isAuthenticated()) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}else {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;res.status(403).send('로그인 필요');
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
};

exports.isNotLoggedIn = (req, res, next) =&amp;gt; {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(!req.isAuthenticated()) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} else {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const message = encodeURIComponent('로그인한 상태입니다.');
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;res.redirect(`/?error=${message}`);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
};&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;br&gt;5. app.js 적용&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;require('dotenv').config();

const mongoose = require('mongoose');
const createError = require('http-errors');
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const indexRouter = require('./routes/index');
const bodyParser = require(&quot;body-parser&quot;);
const app = express();
const cors = require('cors')


/* cors start */
const corsOptions = {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;origin: 'http://localhhost:3000', // 배포시 주석
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// origin: 'https://pf6.chanyongyang.com:3000', // 배포시 주석 해제
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;credentials: true
}

app.use(cors(corsOptions));
/* cors end */

/* passport start */
const passportConfig = require('./passport');
const session = require('express-session');
const passport = require('passport');
passportConfig();
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;session({
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;resave: false,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;saveUninitialized: false,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;secret: process.env.COOKIE_SECRET,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cookie: {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;httpOnly:true,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;secure: false // https일경우 true
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;},
}));
app.use(passport.initialize());
app.use(passport.session());
app.use('/auth', require('./routes/auth'));
/* passport end */

app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());

const Member = require('./models/member');

/* MongoDB connect start */
const uri = process.env.MONGODB_URI;
mongoose.connect(uri, { useNewUrlParser: true, useUnifiedTopology: true });
const db = mongoose.connection;
db.on('error', console.error);
db.once('open', function(){
&amp;nbsp;&amp;nbsp;console.log(&quot;Connection Success&quot;);
});
/* MongoDB connect end */


module.exports = app;&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;br&gt;6. postman test&lt;br&gt;&amp;nbsp;&lt;br&gt;6-1. 회원가입&lt;/p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1030&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A1DAr/btstXztlvjN/K8W6jWk9PJ9ktEuMlxDLG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A1DAr/btstXztlvjN/K8W6jWk9PJ9ktEuMlxDLG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A1DAr/btstXztlvjN/K8W6jWk9PJ9ktEuMlxDLG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FA1DAr%2FbtstXztlvjN%2FK8W6jWk9PJ9ktEuMlxDLG0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1920&quot; height=&quot;1030&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1030&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;br&gt;6-2 login&lt;br&gt;&amp;nbsp;6-2-1. root/routes/index.js&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
&amp;nbsp;&amp;nbsp;if(req.user) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;console.log(&quot;req.user = &quot;, req.user);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;console.log(req.user);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;console.log(req.user.username);
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;res.render('index', { title: 'Express' });
});

module.exports = router;&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;6-2-2. postman&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1030&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ybuwP/btstX92hasd/PxqmDWph8eTWxB4hqEpGY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ybuwP/btstX92hasd/PxqmDWph8eTWxB4hqEpGY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ybuwP/btstX92hasd/PxqmDWph8eTWxB4hqEpGY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FybuwP%2FbtstX92hasd%2FPxqmDWph8eTWxB4hqEpGY1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1920&quot; height=&quot;1030&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1030&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;br&gt;6-2-3. log 출력&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;{
&amp;nbsp;&amp;nbsp;_id: new ObjectId(&quot;6502b77354db2b91d0174d3b&quot;),
&amp;nbsp;&amp;nbsp;username: 'tistory',
&amp;nbsp;&amp;nbsp;pw: '$2b$10$/teaT1QROYwgjsOwQpR/F.55tVpoYQd1H3RjgOkJ/0bmYPNIppvim',
&amp;nbsp;&amp;nbsp;nickName: 'loginTest',
&amp;nbsp;&amp;nbsp;regDate: 2023-09-14T07:34:07.679Z,
&amp;nbsp;&amp;nbsp;updateDate: 2023-09-14T07:34:07.679Z,
&amp;nbsp;&amp;nbsp;__v: 0
}
tistory&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;7. 후기&lt;br&gt;js를 가지고 백엔드 구축하는데 있어 어려움을 많이 느꼈다.&lt;br&gt;다 하고나서 spring security의 인증부분과 상당히 비슷하다고 느꼈다(사실 처음부터 느꼈더라면 금방 구현했을텐데..)&lt;br&gt;이 글을 읽고있는 여러분도 에러없이 금방 구현하길 바란다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>기타 라이브러리 및 프레임워크</category>
      <category>Authenticate</category>
      <category>Express</category>
      <category>JavaScript</category>
      <category>localstrategy</category>
      <category>MongoDB</category>
      <category>passport</category>
      <category>passport login</category>
      <category>Passport.js</category>
      <category>Postman</category>
      <category>인증</category>
      <author>모건이삼촌</author>
      <guid isPermaLink="true">https://c-uncle-full-stack.tistory.com/156</guid>
      <comments>https://c-uncle-full-stack.tistory.com/156#entry156comment</comments>
      <pubDate>Sun, 10 Sep 2023 22:57:38 +0900</pubDate>
    </item>
    <item>
      <title>23-09-09 jetbrains datagrip에 mongodb cluster 연결하기</title>
      <link>https://c-uncle-full-stack.tistory.com/155</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;나는 Spring data JPA를 사용할 때 직접 쿼리를 생각하고 생각한 쿼리대로 코드를 작성했었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MEVN 프로젝트중 MongoDB는 첫 사용을 하는것이라 코드를 작성하면서 자꾸 헷갈릴때가 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;datagrip에 직접 쿼리를 날리고 백엔드 코드를 작성하면서 빠르게 MongoDB를 익혀야겠다는 생각에 이 글을 작성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;datagrip에 mongodb cluster를 연결하는방법에 대해 구글링 해봤지만 모두 local에서 연결하는 법만 나왔고 그냥 내가 알아서 해봐야겠다는 생각에 직접 해봤는데 정말 간단했다. (사실 이렇게 간단한걸 여러시도끝에 해낸 내가 바보같긴함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연결방법은 아래와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;* 아래 방법은 mongodb 클러스터 생성, datagrip설치를 생략하고 진행&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. mongodb 로그인&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1896&quot; data-origin-height=&quot;809&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJIn07/btstx40Lgqo/tKfJIN5TmmkUjExPPfSnm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJIn07/btstx40Lgqo/tKfJIN5TmmkUjExPPfSnm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJIn07/btstx40Lgqo/tKfJIN5TmmkUjExPPfSnm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJIn07%2Fbtstx40Lgqo%2FtKfJIN5TmmkUjExPPfSnm0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1896&quot; height=&quot;809&quot; data-origin-width=&quot;1896&quot; data-origin-height=&quot;809&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 로그인 후 Connect 클릭&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;794&quot; data-origin-height=&quot;829&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CDzKc/btstwkQPG9D/WZXBjuvnkBCOkb6B1MQy9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CDzKc/btstwkQPG9D/WZXBjuvnkBCOkb6B1MQy9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CDzKc/btstwkQPG9D/WZXBjuvnkBCOkb6B1MQy9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCDzKc%2FbtstwkQPG9D%2FWZXBjuvnkBCOkb6B1MQy9k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;794&quot; height=&quot;829&quot; data-origin-width=&quot;794&quot; data-origin-height=&quot;829&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- Drivers 클릭&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;792&quot; data-origin-height=&quot;865&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dfCEvQ/btstxNracAk/IgraIifyKAPPXRFtaEQnY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dfCEvQ/btstxNracAk/IgraIifyKAPPXRFtaEQnY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dfCEvQ/btstxNracAk/IgraIifyKAPPXRFtaEQnY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdfCEvQ%2FbtstxNracAk%2FIgraIifyKAPPXRFtaEQnY1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;792&quot; height=&quot;865&quot; data-origin-width=&quot;792&quot; data-origin-height=&quot;865&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 위 부분만 복사 후 uri 맨 끝부분에 본인이 연결하고자 하는 document name 작성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- ex)&lt;span style=&quot;background-color: #f9fbfa; color: #001e2b; text-align: left;&quot;&gt;mongodb+srv://&lt;b&gt;사용자명&lt;/b&gt;:&lt;b&gt;비밀번호&lt;/b&gt;@mevn.deasdzr.mongodb.net/&lt;b&gt;document명&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: #f9fbfa; color: #001e2b; text-align: left;&quot;&gt;2. datagrip 실행 및 mongodb 연결&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;458&quot; data-origin-height=&quot;477&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dmUiHw/btstzm0UDy4/TZttmxodbvFG17hbu0vd5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dmUiHw/btstzm0UDy4/TZttmxodbvFG17hbu0vd5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dmUiHw/btstzm0UDy4/TZttmxodbvFG17hbu0vd5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdmUiHw%2Fbtstzm0UDy4%2FTZttmxodbvFG17hbu0vd5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;477&quot; data-origin-width=&quot;458&quot; data-origin-height=&quot;477&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 alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;426&quot; data-origin-height=&quot;378&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c2NHuw/btstwHZxElT/f2PJmKHqFC6nOdxxrXKfdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c2NHuw/btstwHZxElT/f2PJmKHqFC6nOdxxrXKfdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c2NHuw/btstwHZxElT/f2PJmKHqFC6nOdxxrXKfdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2NHuw%2FbtstwHZxElT%2Ff2PJmKHqFC6nOdxxrXKfdK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;378&quot; data-origin-width=&quot;426&quot; data-origin-height=&quot;378&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 데이터소스, MongoDB 클릭&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;806&quot; data-origin-height=&quot;688&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nxaZZ/btstw4tpQgP/h8xkH0JmUHChTNfDc9n7XK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nxaZZ/btstw4tpQgP/h8xkH0JmUHChTNfDc9n7XK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nxaZZ/btstw4tpQgP/h8xkH0JmUHChTNfDc9n7XK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnxaZZ%2Fbtstw4tpQgP%2Fh8xkH0JmUHChTNfDc9n7XK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;806&quot; height=&quot;688&quot; data-origin-width=&quot;806&quot; data-origin-height=&quot;688&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- URL부분에 1번에서 복사한 URL입력 후 하단 연결테스트 클릭&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&amp;nbsp;* URL을 입력하면 사용자와 비밀번호는 알아서 채워진다.&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;3. 간단한 쿼리 테스트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;연결한 document에 data값을 출력하는지에 대한 테스트다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1040&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctfwww/btstCFsmZ0k/fxntB7dYFJDYVolHbGZqHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctfwww/btstCFsmZ0k/fxntB7dYFJDYVolHbGZqHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctfwww/btstCFsmZ0k/fxntB7dYFJDYVolHbGZqHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fctfwww%2FbtstCFsmZ0k%2FfxntB7dYFJDYVolHbGZqHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1920&quot; height=&quot;1040&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1040&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 정상적으로 출력하는걸 볼수있다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DATABASE</category>
      <category>DataGrip</category>
      <category>MongoDB</category>
      <category>mongodbcluster</category>
      <author>모건이삼촌</author>
      <guid isPermaLink="true">https://c-uncle-full-stack.tistory.com/155</guid>
      <comments>https://c-uncle-full-stack.tistory.com/155#entry155comment</comments>
      <pubDate>Sat, 9 Sep 2023 22:20:02 +0900</pubDate>
    </item>
    <item>
      <title>23-08-29 Jest #1 설치 및 설정</title>
      <link>https://c-uncle-full-stack.tistory.com/153</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;1. 설치&lt;/p&gt;
&lt;pre id=&quot;code_1693283522337&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install --save-dev&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 data-ke-size=&quot;size16&quot;&gt;pakage.json &quot;test&quot; 구문 변경&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;기존 &amp;gt;&amp;gt; &quot;test&quot; : &quot;??&quot;&lt;/li&gt;
&lt;li&gt;변경 &amp;gt;&amp;gt; &quot;test&quot; : &quot;jest&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1693283572132&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;name&quot;: &quot;board-back&quot;,
  &quot;version&quot;: &quot;0.0.0&quot;,
  &quot;private&quot;: true,
  &quot;scripts&quot;: {
    &quot;start&quot;: &quot;node ./bin/www&quot;,
    &quot;test&quot; : &quot;jest&quot;
  },&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;3-1. fn.js 파일 생성&lt;/p&gt;
&lt;pre id=&quot;code_1693284081440&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fn = {
  add: (num1, num2) =&amp;gt; num1 + num2,
};

module.exports = fn;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;&amp;nbsp;3-2. fn.test.js 파일 생성&lt;/p&gt;
&lt;pre id=&quot;code_1693284121426&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 3-1에서 작성한 fn을 가져옴
const fn = require('./fn');

// test('테스트 코드에 대한 설명 / 1 = 1이 된다.') 
test('1 = 1', ()=&amp;gt; {
	// expect(테스트 대상).toBe(예상값)
  expect(1).toBe(1);
});

// 테스트 성공
test('2 + 3 = 5', ()=&amp;gt; {
  expect(fn.add(2, 3)).toBe(5);
});

// 테스트 실패
// 3 + 3 = 6이기 때문에 FAIL 출력
test('3 + 3 = 5', ()=&amp;gt; {
  expect(fn.add(3, 3)).toBe(5);
});&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;3-3 테스트 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 터미널에 npm jest 입력&lt;/p&gt;
&lt;pre id=&quot;code_1693284334378&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm jest&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;818&quot; data-origin-height=&quot;836&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R8RJ8/btssigoBPoK/5hpzhWLLS6WVobd4fNsH0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R8RJ8/btssigoBPoK/5hpzhWLLS6WVobd4fNsH0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R8RJ8/btssigoBPoK/5hpzhWLLS6WVobd4fNsH0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR8RJ8%2FbtssigoBPoK%2F5hpzhWLLS6WVobd4fNsH0k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;818&quot; height=&quot;836&quot; data-origin-width=&quot;818&quot; data-origin-height=&quot;836&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3-2 에서 설명한것과 같이 어디에서 실패했는지 알려준다.&lt;/p&gt;</description>
      <category>기타 라이브러리 및 프레임워크/Jest</category>
      <category>jest</category>
      <category>TDD</category>
      <category>단위테스트</category>
      <category>유닛테스트</category>
      <category>자바스크립트</category>
      <category>자바스크립트 단위테스트</category>
      <category>통합테스트.</category>
      <author>모건이삼촌</author>
      <guid isPermaLink="true">https://c-uncle-full-stack.tistory.com/153</guid>
      <comments>https://c-uncle-full-stack.tistory.com/153#entry153comment</comments>
      <pubDate>Tue, 29 Aug 2023 13:49:05 +0900</pubDate>
    </item>
    <item>
      <title>23-07-12 JAVA / Spring Bean Life Cycle</title>
      <link>https://c-uncle-full-stack.tistory.com/147</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;0. 목차&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JAVA 객체의 Life Cycle&lt;/li&gt;
&lt;li&gt;Spring Bean의 Life Cycle&lt;/li&gt;
&lt;li&gt;References&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. JAVA 객체의 Life Cycle&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체의 Life Cycle에 대해 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 크게 5단계로 나눌 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;객체생성&lt;/li&gt;
&lt;li&gt;초기화&lt;/li&gt;
&lt;li&gt;사용중&lt;/li&gt;
&lt;li&gt;Finalized&lt;/li&gt;
&lt;li&gt;소멸&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1-1. 객체 생성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체를 위한 메모리 공간을 Heap 영역에 할당,&amp;nbsp;클래스(설계도)로 부터 객체(완제품)을 new 키워드를 사용하여 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1-2. 초기화&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;객체가 생성되면 해당 객체의 인스턴스 변수들이 기본값으로 초기화 되며 생성자를 통해 인스턴스 변수를 원하는값으로 설정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1-3. 사용중&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Garbage Collector의 대상이 되지 않는다&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;&quot;&gt;* Garbage Collector(이하 GC)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;GC란 JVM내에서 메모리 관리를 담당하는 주요 구성요소이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;동적으로 할당한 객체들 중에서 더이상 사용되지않는 객체를 찾아내고, 해당 객체들이 사용한 메모리를 자동으로 회수한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;개발자는 명시적으로 메모리를 해제할 필요가 없으며 GC가 자동으로 더 이상 참조되지 않는 객체를 탐지하여 회수한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1-4. Finalized&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;finalizer를 통해 finalize가 실행된 후의 상태,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체의 finalize()가 정의되어 있을 경우 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;finalize()가 정의되어 있지 않을경우 GC의 stack에 추가된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1-5. 소멸&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체가 더이상 사용되지 않을때 GC에 의해서 소멸(메모리의 반환) 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1-6. 결론&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JAVA의 객체는 new 키워드를 통해 Heap영역에 객체를 생성하며 객체내 변수들을 초기화 하고, 사용되며 사용이 끝날시 GC에 의해 소멸된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. Spring Bean의 Life Cycle&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bean 객체의 Life Cycle에 대해 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 크게 4단계로 나눌수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;인스턴스화&lt;/li&gt;
&lt;li&gt;의존성주입&lt;/li&gt;
&lt;li&gt;초기화&lt;/li&gt;
&lt;li&gt;사용중&lt;/li&gt;
&lt;li&gt;소멸&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-1. 인스턴스화&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bean 객체의 인스턴스를 생성, Bean 클래스의 기본생성자를 호출하여 객체를 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-2. 의존성 주입(DI / Dependency Injection)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;생성된 Bean 객채에 대해 의존성을 주입한다.&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;Spring IoC 컨테이너 생성&lt;/li&gt;
&lt;li&gt;어노테이션과 설정파일을 읽어 IoC컨테이너 안에 Bean으로 등록&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의존성 주입은 2가지 방법으로 나뉜다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;생성자 주입&lt;/li&gt;
&lt;li&gt;Setter 주입&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;2-2-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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;* 생성자 주입으로 인한 이점&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&amp;nbsp;1) null을 주입하지 않는 한 NullPointerException은 발생하지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&amp;nbsp;2) 의존관계를 주입하지 않은 경우 객체를 생성할 수 없다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&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;size18&quot;&gt;&amp;nbsp; 2-2-2. Setter 주입&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 객체의 생성 -&amp;gt; 의존관계 주입으로 라이프 사이클이 나누어져 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-3. 초기화&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Bean객체는 초기화되기 전에 초기화 콜백 메서드를 호출할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;InitializingBean 인터페이스를 구현하거나 @PostConstruct 어노테이션을 사용하여 초기화 콜백 메서드를 지정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 단계에서 Bean객체를 초기화하고 필요한 설정을 수행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-4. 사용중&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bean객체들과 협력하여 비즈니스 로직을 수행하거나 필요한 작업을 수행함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-5. 소멸&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Bean객체가 더 이상 필요하지 않게 되면 소멸한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DisposableBean 인터페이스를 구현하거나 @PreDestroy 어노테이션을 사용하여 소멸 콜백메서드를 지정할 수 있다.&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;2-6. 결론&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;Spring 프레임워크는 Bean객체의 Life Cycle을 자동으로 관리해주며 Bean객체를 초기화하고, 필요한 의존성을 주입한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션이 종료될때 Spring은 등록된 Bean객체들의 소멸 메서드를 호출하여 리소스를 정리하고 필요에 따라 초기화와 소멸단계에서 추가적인 로직을 구현할 수 있다.&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;3. References&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;3-1. Blog 1&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://lemontia.tistory.com/649&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://lemontia.tistory.com/649&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;3-2. Blog 2&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev-coco.tistory.com/170&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://dev-coco.tistory.com/170&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;</description>
      <category>JAVA</category>
      <author>모건이삼촌</author>
      <guid isPermaLink="true">https://c-uncle-full-stack.tistory.com/147</guid>
      <comments>https://c-uncle-full-stack.tistory.com/147#entry147comment</comments>
      <pubDate>Wed, 12 Jul 2023 21:46:03 +0900</pubDate>
    </item>
  </channel>
</rss>