<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>code_my_dream</title>
        <link>https://velog.io/</link>
        <description>걸음마코더</description>
        <lastBuildDate>Wed, 18 May 2022 00:34:25 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>code_my_dream</title>
            <url>https://velog.velcdn.com/images/printver_2world/profile/1ab23e57-9cbf-491c-8718-7951dc02a733/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. code_my_dream. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/printver_2world" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[네트워크 | 토큰(Token)과 JWT]]></title>
            <link>https://velog.io/@printver_2world/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%ED%86%A0%ED%81%B0Token%EA%B3%BC-JWT</link>
            <guid>https://velog.io/@printver_2world/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%ED%86%A0%ED%81%B0Token%EA%B3%BC-JWT</guid>
            <pubDate>Wed, 18 May 2022 00:34:25 GMT</pubDate>
            <description><![CDATA[<h2 id="토큰">토큰</h2>
<p>서버에 토큰을 보내서 서버는 세션 DB에서 해당 토큰과 일치하는 정보를 찾는다.
세션은 모든 세션 ID를 DB에 저장하고, 요청이 들어올 때마다 서버는 쿠키에 담긴 세션 id와 일치하는 유저를 찾아야한다. 요청이 있을 때마다 DB에서 세션 ID를 찾아야 하므로 유저가 늘어나면 DB 리소스도 증가하게 된다.</p>
<h3 id="jwt">JWT</h3>
<p><img src="https://velog.velcdn.com/images/printver_2world/post/f5f7bef9-142d-4d07-a4b9-4aab242245a4/image.png" alt=""></p>
<p>토큰 형식이고, 세션 DB가 필요없다. 따라서 서버는 DB에서 유저를 찾는 일을 하지 않아도 된다.
브라우저에서 유저 정보를 받으면 서버는 sign을 한다. 그리고 사인된 정보를 string 형태로 브라우저로 보낸다.</p>
<h3 id="동작방식">동작방식</h3>
<p>브라우저에서 토큰 또는 사인된 정보를 보낸다.
서버는 토큰을 받으면 해당 사인이 유효한지 체크하고(조작된 토큰은 아닌가) 토큰이 유효하다면 성공.</p>
<h3 id="세션-vs-jwt">세션 vs JWT</h3>
<table>
<thead>
<tr>
<th align="center">항목</th>
<th align="center">세션</th>
<th align="center">JWT</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">브라우저에 전달하는 것</td>
<td align="center">세션 ID</td>
<td align="center">토큰</td>
<td>JWT는 필요한 정보(예. 유저를 인증하는데 필요한 정보)를 토큰에 저장</td>
</tr>
<tr>
<td align="center">DB</td>
<td align="center">필요</td>
<td align="center">불필요</td>
<td>세션(세션 ID를 받아 DB에 저장), JWT(서버는 토큰이 유효한지만 검증하기 때문에 DB가 필요없음. JWT는 암호화가 안되어있기 때문에 비밀번호를 저장하면 안됨)</td>
</tr>
<tr>
<td align="center">새로운 기능 추가</td>
<td align="center">가능</td>
<td align="center">불가능</td>
<td>ex. 로그아웃</td>
</tr>
<tr>
<td align="center">단점</td>
<td align="center">DB 유지보수 기능 증가</td>
<td align="center"></td>
<td></td>
</tr>
<tr>
<td align="center">용량 제한</td>
<td align="center">도메인 당 20개, 1쿠키당 4KB</td>
<td align="center">제한 없음</td>
<td>TMI. JWT는 용량제한 없음</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[네트워크 | 쿠키(cookie)와 세션(session)]]></title>
            <link>https://velog.io/@printver_2world/Network-cookieNsession</link>
            <guid>https://velog.io/@printver_2world/Network-cookieNsession</guid>
            <pubDate>Tue, 17 May 2022 05:09:46 GMT</pubDate>
            <description><![CDATA[<h2 id="1-쿠키와-세션을-왜-사용할까">1. 쿠키와 세션을 왜 사용할까?</h2>
<h3 id="http-프로토콜의-특징">HTTP 프로토콜의 특징</h3>
<ul>
<li>connectionless
  클라이언트가 서버에 요청을 한 후 응답을 받으면 연결을 끊어버리는 특징</li>
<li>stateless
  통신이 끝나면 상태를 유지하지 않는 특징</li>
</ul>
<p>HTTP 프로토콜의 특징이나 약점을 보완하기 위해서 쿠키와 세션을 사용한다.
<br></p>
<h2 id="2-🍪쿠키cookie">2. 🍪쿠키(Cookie)</h2>
<ul>
<li>쿠키는 클라이언트(브라우저) 로컬에 저장되어 있는 키와 값이 들어있는 작은 데이터 파일이다. </li>
<li>HTTP에서 클라이언트의 상태 정보를 클라이언트의 PC에 저장하였다가 필요시 정보를 참조하거나 재사용할 수 있다.</li>
<li>Response Header에 <code>Set-Cookie</code> 속성을 사용하면 클라이언트에 쿠키를 만들 수 있다.</li>
<li>유효시간을 정할 수 있어, 브라우저가 종료되어도 인증이 유지된다.</li>
<li>클라이언트에 300개까지 쿠키저장이 가능하다.</li>
<li>하나의 도메인당 20개의 쿠키를 가질 수 있다.</li>
<li>하나의 쿠키값은 4KB까지 저장 가능하다.<br>

</li>
</ul>
<h3 id="쿠키-구성요소">쿠키 구성요소</h3>
<ul>
<li>이름 : 각각의 쿠키를 구별하는 데 사용</li>
<li>값 : 쿠키의 이름과 관련된 값</li>
<li>유효시간 : 쿠키 유지 시간</li>
<li>도메인 : 쿠키를 전송할 도메인. 유튜브에서 준 쿠키는 유튜브에만 보낼 수 있다.</li>
<li>경로 : 쿠키를 전송할 요청 경로<br>

</li>
</ul>
<h3 id="쿠키-동작-순서">쿠키 동작 순서</h3>
<p><img src="https://velog.velcdn.com/images/printver_2world/post/95ed08ec-74fa-4c42-8fa9-1d5c0a66c037/image.png" alt=""></p>
<ol>
<li>클라이언트가 페이지를 요청한다.</li>
<li>서버에서 쿠키를 생성한다.</li>
<li>HTTP 헤더에 <code>Set-Cookie</code> 속성에, 쿠키를 포함 시켜 응답한다. </li>
<li>클라이언트는 쿠키를 로컬에 보관하였다가, 같은 요청을 할 때, 서버에 쿠키와 함께 요청을 한다. </li>
<li>서버에서 쿠키를 읽어, 이전 상태 정보를 변경할 필요가 있을 때 쿠키를 업데이트 하여 변경된 쿠키를 HTTP 헤더에 포함시켜 응답한다.<br>

</li>
</ol>
<h2 id="3-세션session">3. 세션(Session)</h2>
<ul>
<li>세션도 쿠키를 사용한다. 쿠키는 세션 ID를 전달하기 위한 매개체이다.</li>
<li>사용자 정보 파일을 브라우저에 저장하는 쿠키와 달리, 세션은 서버 측에서 관리한다. 브라우저에는 오직 세션 ID만 저장된다.</li>
<li>서버에서는 클라이언트를 구분하기 위해 세션 ID를 부여하여, 웹 브라우저가 서버에 접속해서 브라우저를 종료할 때까지 인증상태를 유지한다.<br>

</li>
</ul>
<h3 id="세션-동작-순서">세션 동작 순서</h3>
<p><img src="https://velog.velcdn.com/images/printver_2world/post/226ed8ba-6d19-4a90-adeb-936987639007/image.png" alt=""></p>
<ol>
<li>클라이언트가 서버에 접속 시, 서버는 세션 ID를 부여하여 DB에 저장한다.</li>
<li>서버는, 쿠키에 세션 ID를 포함시켜 응답한다.</li>
<li>클라이언트는 서버에 요청할 때, 세션 ID가 포함된 쿠키를 서버에 전달하여 요청한다.</li>
<li>서버는 세션 ID를 전달받는다. 이때 서버는 세션 ID가 있는 쿠키와 함께 요청이 들어온 것만 알지 정보를 알지는 못한다.</li>
<li>해당 세션에 저장되어 있는 클라이언트 정보를 가져와 응답한다.<br>

</li>
</ol>
<h2 id="🍪쿠키-vs-세션">🍪쿠키 vs 세션</h2>
<table>
<thead>
<tr>
<th align="center">항목</th>
<th align="center">쿠키</th>
<th align="center">세션</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">사용자 정보 저장 위치</td>
<td align="center">브라우저</td>
<td align="center">서버</td>
<td></td>
</tr>
<tr>
<td align="center">보안</td>
<td align="center">⬇</td>
<td align="center">⬆</td>
<td>세션은 서버에 저장되기 때문이다. 로컬은 변질되거나 request에서 스니핑의 우려가 있지만, 세션은 세션 ID만 로컬에 저장하고, 처리는 서버에서 하기 때문에 비교적 보안성이 좋다.</td>
</tr>
<tr>
<td align="center">속도</td>
<td align="center">⬆</td>
<td align="center">⬇</td>
<td>세션은 서버의 처리가 필요가 때문에 느리다.</td>
</tr>
<tr>
<td align="center">라이프 사이클</td>
<td align="center">만료시간이 길다면, 브라우저 종료해도 남아있다.</td>
<td align="center">만료시간이 길더라도, 브라우저가 종료되면 세션도 종료된다.</td>
<td></td>
</tr>
<tr>
<td align="center">용량 제한</td>
<td align="center">도메인 당 20개, 1쿠키당 4KB</td>
<td align="center">제한 없음</td>
<td>TMI. JWT는 용량제한 없음</td>
</tr>
<tr>
<td align="center"><br></td>
<td align="center"></td>
<td align="center"></td>
<td></td>
</tr>
</tbody></table>
<h2 id="세션보다는-쿠키">세션보다는 쿠키?</h2>
<p>세션은 서버의 자원을 사용하기 때문에 정보가 많아지면 서버 메모리를 많이 차지하고, 속도가 느려질 수 있다.</p>
<blockquote>
<p>네이티브 앱에서는 세션을 사용할 수 있지만, 쿠키는 브라우저에만 있으니 사용할 수 없다. -&gt; Token 등장!</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[네트워크 | HTTPS]]></title>
            <link>https://velog.io/@printver_2world/Network-HTTPS</link>
            <guid>https://velog.io/@printver_2world/Network-HTTPS</guid>
            <pubDate>Thu, 12 May 2022 15:55:26 GMT</pubDate>
            <description><![CDATA[<h2 id="http의-문제">HTTP의 문제</h2>
<p>HTTP(HyperText Transfer Protocol)는 말 그대로 <strong>하이퍼텍스트</strong>를 전송하기 위해 사용되는 통신 규약이다. 정보를 네트워크를 통해 텍스트로 주고 받게 되는데, 네트워크에서 전송 신호를 인터셉트하는 경우 원하지 않는 데이터 유출이 발생할 수 있다. 따라서 이러한 문제를 해결하기 위해 HTTP에 <strong>S(Secure Socket)</strong>이 추가된 HTTPS가 도입되었다.
<img src="https://velog.velcdn.com/images/printver_2world/post/7e90a244-d962-400d-b653-0575fc1703f3/image.png" alt="">
<br></p>
<h2 id="https">HTTPS</h2>
<ul>
<li>데이터를 주고 받는 과정에서 &#39;보안&#39; 요소가 추가</li>
<li>기본 TCP/IP 포트는 443이고, SSL 프로토콜 위에서 동작</li>
<li>일반 텍스트를 사용하는 대신, 정보를 암호화하는 TLS이나 SSL 프로토콜을 사용하여 데이터를 암호화
<img src="https://velog.velcdn.com/images/printver_2world/post/882aeb96-b5d7-4f27-b5f8-e367ee02c84f/image.png" alt=""></li>
</ul>
<h2 id="https-장단점">HTTPS 장단점</h2>
<p>당연하게도 HTTPS는 안전하다. 서버와 브라우저 사이의 통신에 인터셉트가 일어나지 않도록, 웹사이트의 무결성을 보호해준다.</p>
<p><strong>HTTPS에는 단점이 없는가?</strong></p>
<ul>
<li>SSL을 사용하기 때문에, 서버와 클라이언트 모두 암복호화 처리가 필요하다. 따라서 서버에 부하를 주어 하드웨어 리소스 소비가 불가피하고, 그 때문에 HTTP보다 통신 속도가 느리다. </li>
<li><blockquote>
<p>중요한 정보만을 암호화하여 리소스를 절약할 수 있다.</p>
</blockquote>
</li>
<li>HTTPS를 사용한다고 무조건 안전한 것은 아니다. 신뢰할 수 었는 CA기업을 통해 인증서를 발급할 수 있다.</li>
<li>추가 비용이 발생한다.</li>
</ul>
<h2 id="https-알고리즘">HTTPS 알고리즘</h2>
<p>공개키 방식과 공개키의 느리다는 단점을 보완한 대칭키 방식을 함께 사용한다. 공개키 방식으로 대칭키를 전달하고, 서로 공유된 대칭키를 가지고 통신하게 된다.</p>
<h3 id="공개키-방식">공개키 방식</h3>
<p>공개키와 비공개키를 이용하는데, 이걸 key pair라고도 한다. 둘이 쌍이라는 이야기임. 평문을 <strong>공개키</strong>로 암호문으로 만들고, 다시 복호화하기 위해서는 <strong>비공개키</strong>가 필요하다. 반대로 평문을 <strong>비공개키</strong>를 이용해서 암호문으로 만들면, <strong>공개키</strong>로 복호화가 가능하다.
<del>후자도 가능하지는 몰랐네.....</del></p>
<p>그렇다면 공개키 방식을 사용하는 이유는 뭘까.
<img src="https://velog.velcdn.com/images/printver_2world/post/d64fd5ea-f526-4618-8557-08412ad1f01f/image.png" alt="">
공개키 방식을 사용하는 이유는 <strong>배달사고</strong>때문이다. 평문과 암호문을 나만 보면 대칭키 방식을 사용하면 된다. 하지만 특정한 상대에게 메세지를 보내야하는 경우에, key를 보내야 하는데, 이때 key가 도난당할 수 있음.</p>
<h3 id="대칭키-방식">대칭키 방식</h3>
<h4 id="대칭키-도난은-어떻게-당하는거지">대칭키 도난은 어떻게 당하는거지</h4>
<p><img src="https://velog.velcdn.com/images/printver_2world/post/92322158-d877-46e5-896d-f58680b547ab/image.png" alt="">
<img src="https://velog.velcdn.com/images/printver_2world/post/fe817790-84a4-4a9f-a132-b274b0aae139/image.png" alt=""></p>
<blockquote>
<p>목표는 (A가 B에게 암호문과 키를 전달하여) B가 평문을 아는 것이다.
준비물은 <strong>A의 대칭키</strong>와 평문이다. 여기서 평문은 hello라고 하였다(세상 귀찮음).</p>
</blockquote>
<ol>
<li>먼저 A는 평문을 대칭키를 이용하여 암호화한다.</li>
<li>암호문과 <strong>대칭키</strong>를 B에게 전달한다.
3-1. B는 암호문을 대칭키를 이용하여 복호화하여 평문을 알 수 있다! 짜잔.
3-2. 하지만 네트워크로 암호문과 대칭키를 전달하는 과정에서 Cracker가 키를 훔쳐서 복화할 수 있음 주의.</li>
</ol>
<h4 id="공개키는-안전하지">공개키는 안전하지</h4>
<p><img src="https://velog.velcdn.com/images/printver_2world/post/888f13c2-3fde-4cc4-914d-354d50df6be3/image.png" alt=""></p>
<blockquote>
<p>목표는 위와 같이 B가 평문을 아는 것!
준비물은 <strong>B의 공개키와 비밀키</strong>와 평문이다.</p>
</blockquote>
<ol>
<li>먼저 A는 평문을 B의 공개키를 이용하여 암호화한다.</li>
<li>암호문을 B에게 전달한다.
3-1. B는 암호문을 자신의 비밀키를 이용하여 복호화하여 평문을 알 수 있다!
3-2. Cracker가 암호문을 훔쳐서 공개키로 복호화하려하지만, 실패!!ㅠ 공개키로 암호화하였기 때문에 비밀키로만 복호화가 가능하기 때문이지.</li>
</ol>
<blockquote>
<p>여기서 A가 공개키로 평문을 암호화하였지만, A도 비밀키가 없기 때문에 복호화가 불가능하다.</p>
</blockquote>
<h3 id="전자서명">전자서명</h3>
<p>공개키 방식은 보안에 취약하지 않기(?)때문에 전자서명에 사용된다.
<img src="https://velog.velcdn.com/images/printver_2world/post/a1b2e4b8-04ed-46d9-be62-13a838211a52/image.png" alt=""></p>
<blockquote>
<p>전자서명의 목표는 B가 작성한 내용이 정말로 B가 작성했는가? <strong>인증</strong>에 있음!</p>
</blockquote>
<ol>
<li>B가 평문을 B의 <strong>비밀키</strong>를 이용하여 암호화한다. 이 암호문이 전자서명이다.</li>
<li>평문과 암호문을 공개영역에 올린다.</li>
<li>A는 B의 <strong>공개키</strong>를 이용하여 복호화한다. 복호화한 결과가 B가 작성한 평문과 일치하면 인증 성공!</li>
<li>Cracker 본인이 만든 공개키와 비밀키가 있고, 조작된 평문이 있다. Cracker의 비밀키를 이용하여 조작된 평문을 암호화하고, 이 암호문과 조작된 평문을 공개영역에 올린다.</li>
<li>만약 A가 이 암호문을 가지고 와서 B의 공개키로 해독을 하면, 해독이 되지 않고, 평문도 다르다. -&gt; 해당 내용은 B가 작성한 것이 아님!</li>
</ol>
<h2 id="정리">정리</h2>
<blockquote>
<p>HTTP의 문제를 해결하기 위해서 HTTPS가 등장했고, 해당 알고리즘에는 공개키 방식과 대칭키 방식이 있다. 대칭키 방식에는 보안 문제가 있기 때문에 공개키 방식으로 보안 취약점을 개선!</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Algorithm | 3. 투포인터]]></title>
            <link>https://velog.io/@printver_2world/Algorithm-twoPointers</link>
            <guid>https://velog.io/@printver_2world/Algorithm-twoPointers</guid>
            <pubDate>Wed, 11 May 2022 00:06:34 GMT</pubDate>
            <description><![CDATA[<p>완전탐색으로 해결하면 시간초과가 나는 경우가 있는데, 이 때 투포인터 알고리즘으로 해결을 해야하는 경우가 다수이다.</p>
<blockquote>
<p>1차원 배열에서 2개의 포인터를 조작하는 방식</p>
</blockquote>
<h3 id="조건">조건</h3>
<ol>
<li>left, right 포인터 2개</li>
<li>처음 포인터는 left = 0, right = 0</li>
<li>left &lt;= right</li>
</ol>
<p>여기서 중요한 것은 <strong><code>[left, right)</code></strong> 라는 것이다. 따라서 left = right이면 크기가 0인 배열이다. </p>
<h3 id="알고리즘">알고리즘</h3>
<p>부분합이 M인 경우를 찾는다고 해보자.</p>
<ol>
<li>부분합이 M보다 클 경우, left 1 증가</li>
<li>부분합이 M보다 작을 경우, right 1 증가</li>
<li>부분합이 M일 경우, count -&gt; <u>left 1 증가</u></li>
</ol>
<blockquote>
<p>left가 이동하는 경우는</p>
</blockquote>
<ul>
<li>부분합이 M보다 클 경우</li>
<li>부분합이 M일 경우</li>
<li>right가 가장 마지막 index에 위치할 경우</li>
</ul>
<h3 id="초기상태">초기상태</h3>
<ol>
<li>left = 0, right = 0</li>
<li>sum = 0</li>
<li>M = 21</li>
<li>count = 0</li>
</ol>
<p><img src="https://velog.velcdn.com/images/printver_2world/post/5c286d7c-5335-4ccc-bd60-c3655e33b281/image.png" alt=""></p>
<ol>
<li>초기상태는 L = 0, R = 0 이다. <code>sum = 0</code> 이므로 R을 오른쪽으로 이동한다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/printver_2world/post/beece88f-acfc-4349-bc7a-57103007b0c3/image.png" alt="">
2. <code>sum = 3</code>으로 M보다 작다. R을 오른쪽으로 이동한다.</p>
<p><img src="https://velog.velcdn.com/images/printver_2world/post/3cc9baca-d761-4f04-bbe4-16d7a8cd4d9c/image.png" alt="">
3. <code>sum = 5</code>으로 M보다 작다. R을 오른쪽으로 이동한다.</p>
<p><img src="https://velog.velcdn.com/images/printver_2world/post/52d52912-ee0d-40df-b884-0945fddf0907/image.png" alt="">
4. <code>sum = 10</code>으로 M보다 작다. R을 오른쪽으로 이동한다.</p>
<p><img src="https://velog.velcdn.com/images/printver_2world/post/95109349-5916-43fc-a617-29157fcef1a8/image.png" alt="">
5. <code>sum = 15</code>으로 M보다 작다. R을 오른쪽으로 이동한다.</p>
<p><img src="https://velog.velcdn.com/images/printver_2world/post/f5e28c79-db83-410c-a2ca-54b0b11c7783/image.png" alt="">
6. <code>sum = 21</code>으로 M과 같다. <code>count = 1</code> 이다. L을 오른쪽으로 이동한다.</p>
<p><img src="https://velog.velcdn.com/images/printver_2world/post/67eb06cc-f73f-4fe8-a024-17ce8aa00635/image.png" alt="">
7. <code>sum = 19</code>으로 M보다 작다. R을 오른쪽으로 이동한다.</p>
<p><img src="https://velog.velcdn.com/images/printver_2world/post/cc86f0bf-79b8-4da9-8a47-c1e157a9a2a4/image.png" alt="">
8. <code>sum = 22</code>으로 M보다 크다. L을 오른쪽으로 이동한다.</p>
<p><img src="https://velog.velcdn.com/images/printver_2world/post/6327f4ef-2358-48f5-a75d-d81ec9700ce2/image.png" alt="">
9. <code>sum = 20</code>으로 M보다 작다. R을 오른쪽으로 이동한다.</p>
<p><img src="https://velog.velcdn.com/images/printver_2world/post/2af6fdaa-bec6-49d1-b33d-5dd20b35a157/image.png" alt="">
10. <code>sum = 24</code>으로 M보다 크다. L을 오른쪽으로 이동한다.</p>
<p><img src="https://velog.velcdn.com/images/printver_2world/post/4b2f7d4c-7dfd-49f8-93ae-c47d930c4b18/image.png" alt="">
11. <code>sum = 19</code>으로 M보다 작다. R을 오른쪽으로 이동한다.</p>
<p><img src="https://velog.velcdn.com/images/printver_2world/post/c60ff964-7a0f-4f54-9e3c-23d903c1a408/image.png" alt="">
12. <code>sum = 24</code>으로 M보다 크다. L을 오른쪽으로 이동한다.</p>
<p><img src="https://velog.velcdn.com/images/printver_2world/post/079f0693-9a96-4775-8e8f-b01e31dbd07f/image.png" alt="">
13. <code>sum = 19</code>으로 M보다 작다. R이 이미 제일 끝에 위치하므로 L을 오른쪽으로 이동한다.</p>
<p><img src="https://velog.velcdn.com/images/printver_2world/post/dcb809c5-28b1-493b-83d1-abee9c7d7180/image.png" alt="">
14. <code>sum = 11</code>으로 M보다 작다. R이 이미 제일 끝에 위치하므로 L을 오른쪽으로 이동한다.</p>
<p><img src="https://velog.velcdn.com/images/printver_2world/post/3ce5045f-23fc-481c-ac82-8e2eb0ff5a23/image.png" alt="">
15. <code>sum = 9</code>으로 M보다 작다. R이 이미 제일 끝에 위치하므로 L을 오른쪽으로 이동한다.</p>
<p><img src="https://velog.velcdn.com/images/printver_2world/post/be88e692-42dd-4068-9140-3ae1e512f474/image.png" alt="">
16. <code>sum = 5</code>으로 M보다 작다. R이 이미 제일 끝에 위치하므로 L을 오른쪽으로 이동한다.</p>
<p><img src="https://velog.velcdn.com/images/printver_2world/post/80f292d5-412a-47a1-b3b8-a0cdfb9e654d/image.png" alt="">
17. <code>sum = 0</code>으로 M보다 작다.</p>
<h3 id="코드">코드</h3>
<pre><code class="language-python">n = 9 # 데이터의 개수 N
m = 21 # 찾고자 하는 부분합 M
data = [3, 2, 5, 5, 6, 4, 4, 5, 7] # 전체 수열

count = 0
interval_sum = 0
right = 0

# left를 차례대로 증가시키며 반복
for left in range(n):
    while interval_sum &lt; m and end &lt; n:
        interval_sum += data[right]
        right += 1
    # left가 이동하는 구간
    # 부분합이 m보다 크거나 같을 경우
    if interval_sum == m:
        count += 1
    interval_sum -= data[left] # 합에서 제외하고 -&gt; for문에서 오른쪽으로 이동

print(count)</code></pre>
<h3 id="어려웠던-점">어려웠던 점</h3>
<p>right부분이 열린구간인 점을 간과한 점이 제일 큰 오류였다. 이 부분 때문에 다른 사람의 코드를 봐도 이해가 안된듯..!!ㅠ
<strong>이전 구간의 합을 확인한 후 -&gt; 이동해도 됨?</strong> 판단하는 로직이었다. 순서 뒤 바뀌면 안돼<del>~</del></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[우테코 프리코스 4기 후기]]></title>
            <link>https://velog.io/@printver_2world/%EC%9A%B0%EC%BD%94%ED%85%8C-4%EA%B8%B0-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@printver_2world/%EC%9A%B0%EC%BD%94%ED%85%8C-4%EA%B8%B0-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Tue, 14 Dec 2021 14:58:04 GMT</pubDate>
            <description><![CDATA[<p>우테코 프리코스가 끝났다.
마지막 과제는 기능을 완벽하게 구현하지 못했다. 시험기간과 겹쳐 많은 시간을 투자하지 못한 것이 너무 아쉬울 따름이다. 우테코는 <strong>바닐라 자바스크립트만을 사용</strong>해서 구현을 해야함으로써, 자바스크립트 실력을 키울 수 있고, <strong>주어진 요구사항을 지킴</strong>으로써 가독성있는 코드를 생산하는 역량을 키울 수 있었다. (물론 역량을 max로 키우지는 못했겠지... 하지만 최소한 요구사항을 지킬려고 노력함으로써 내가 그동안 얼마나 가독성없는 코드를 작성해왔는지 깨달을 수 있었다.)
우테코는 아래와 같이 3가지 양식을 지켜야 한다.</p>
<h3 id="1-요구사항-지키기">1. 요구사항 지키기</h3>
<p>단순히 구현하는 것보다 여러가지 요구사항을 지키는 것이 더 어려웠다. 우테코 자체가 구현은 베이스로 깔고, 클린 코드를 작성하는 것을 연습시키는 느낌이다. 한 주 과제가 끝나면, 전체 피드백을 주는데, UI로직과 비즈니스 로직을 구분하라는 것이 있었다. 그동안 얼마나 코드를 중구난방 작성했는지 <del>현타가 왔다.</del></p>
<h3 id="2-기능단위로-커밋">2. 기능단위로 커밋</h3>
<p>아무생각없이 코딩하다보면 커밋을 까먹을 때도 있지만, 이번 프리코스에서는 기능 단위로 커밋을 하려고 했다. 기능 요구사항을 적고, 하나하나 확인해가며, 구현하였다.</p>
<h3 id="3-예외사항">3. 예외사항</h3>
<p>요구사항에 있는 예외사항 이외의 내가 생각해야 하는 예외사항이 여럿 있었다. 능동적인 코딩을 하게 되었다.</p>
<p>이번주 토요일(2021.12.18)에 우테코 마지막 관문이 남아있다. 솔직히 다들 너무 잘하셔서 붙을지는 모르겠지만, 최선을 다해서 과제에 임할 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[네트워크 | HTTP]]></title>
            <link>https://velog.io/@printver_2world/Network-HTTP</link>
            <guid>https://velog.io/@printver_2world/Network-HTTP</guid>
            <pubDate>Sun, 28 Nov 2021 03:28:39 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/printver_2world/post/8ff3ede5-ab14-4eab-99de-1906b1f10957/image.jpg" alt=""></p>
<h2 id="1-http는-무엇일까">1. HTTP는 무엇일까</h2>
<ul>
<li>HTTP(Hypertext Transfer Protocol)</li>
<li>클라이언트(웹에서는 브라우저)와 서버 간에 데이터를 주고 받기 위한 방식</li>
<li>응용계층에 위치<br>

</li>
</ul>
<h2 id="2-http-특징">2. HTTP 특징</h2>
<ul>
<li>stateless : 이전 상태를 알 수 없다.</li>
<li>connectionless : 서버에 연결하고, 요청해서 응답을 받으면 연결을 끊어버린다. -&gt; 이러한 문제를 해결하기 위해 Cookie와 Session 등장<br>

</li>
</ul>
<h2 id="3-http-요청-메소드">3. HTTP 요청 메소드</h2>
<table>
<thead>
<tr>
<th align="center">메소드</th>
<th>설명</th>
<th align="center"></th>
</tr>
</thead>
<tbody><tr>
<td align="center">POST</td>
<td>요청된 자원 생성</td>
<td align="center">CREATE</td>
</tr>
<tr>
<td align="center">GET</td>
<td>자원 요청</td>
<td align="center">READ</td>
</tr>
<tr>
<td align="center">PUT</td>
<td>요청된 자원 수정</td>
<td align="center">UPDATE</td>
</tr>
<tr>
<td align="center">DELETE</td>
<td>요청된 자원 삭제</td>
<td align="center">DELETE</td>
</tr>
<tr>
<td align="center">HEAD</td>
<td>자원의 Header만 요청. Body는 요청하지 않는다.</td>
<td align="center"></td>
</tr>
<tr>
<td align="center">OPTIONS</td>
<td>서버 옵션들을 확인하기 위한 요청. CORS에서 사용</td>
<td align="center"></td>
</tr>
<tr>
<td align="center"><br></td>
<td></td>
<td align="center"></td>
</tr>
</tbody></table>
<h2 id="4-http-동작방식">4. HTTP 동작방식</h2>
<ul>
<li>서버/클라이언트 모델을 따른다.
  서비스 제공자(service provider)과 서비스 요청자(service requester)로 구분되는 네트워크 모델</li>
<li>TCP/IP 위에서 작동하고, 기본 포트는 80번이다.
  TCP : 데이터의 흐름 관리, 데이터의 정확성 확인
  IP : 패킷을 목적지까지 전송하는 역할</li>
</ul>
<p>클라이언트가 URI를 통해 요청(Request)를 보내면, 서버는 해당 요청(Reqeust)을 받아 처리하여 클라이언트에게 응답(Response)하는 형태</p>
<h3 id="request">Request</h3>
<p>웹 브라우저는 웹 서버에 데이터를 요청하는 클라이언트 프로그램이다.
HTTP 형식으로 <strong>메소드 + URI(요청하는 자원의 위치 명시) + HTTP 프로토콜 버전</strong>을 포함하여 서버에 요청한다. 그 외에 Host, Content-Type, Cookie 등이 Request Header에 포함된다.
<img src="https://velog.velcdn.com/images/printver_2world/post/0e43fdaa-cf3a-4c8c-9160-e6d24118092d/image.png" alt=""></p>
<h3 id="response">Response</h3>
<p>HTTP 형식으로 <strong>응답코드, 응답메시지</strong>를 포함하여 응답한다. 그 외에 Content-Type, Set-Cookie 등이 Response Header에 포함된다.</p>
<p><img src="https://velog.velcdn.com/images/printver_2world/post/2ac522df-4bc2-48f6-b58b-2b979a9f84f8/image.png" alt=""></p>
<blockquote>
<p>URI(Uniform Resource Identifiers)
HTTP와는 독립된 다른 체계이다. HTTP는 전송 프로토콜이고, URI는 자원의 위치를 알려주기 위한 프로토콜이다.
클라이언트(웹에서는 브라우저)는 URI에 자원의 위치를 담는다. <br>
<a href="http://www.test.co.kr/index.html">http://www.test.co.kr/index.html</a></p>
</blockquote>
<ol>
<li>http : 자원에 접근하기 위한 http 프로토콜을 사용</li>
<li><a href="http://www.test.co.kr">www.test.co.kr</a>(도메인 주소) : index.html이라는 자원의 인터넷상 위치</li>
</ol>
<br>

<h3 id="content-type">Content-Type</h3>
<p>HTTP 메시지(요청과 응답 모두)에 담겨 보내는 데이터의 형식을 알려주고, 헤더에 포함된다. HTTP 표준 스펙을 따르는 브라우저와 웹서버는 Content-Type 헤더를 기준으로 HTTP 메시지에 담긴 데이터를 분석하고 파싱한다.
만약 Content-Type 헤더가 없다면 데이터를 전송하는쪽(브라우저나 웹서버)에서는 특정한 형식의 데이터일지라도 데이터를 받는 입장에서는 단순히 텍스트 데이터로 받아들인다.
HTTP 요청이 GET방식인 경우에는 무조건 URL 끝에 쿼리스트링으로 value=text 형식으로 보내지기 때문에 Content-Type은 필요가 없다. 하지만 POST나 PUT처럼 메시지 BODY에 데이터를 보낼 때는 Content-Type를 추가해야한다.</p>
<br>

<h2 id="5-http-상태-코드">5. HTTP 상태 코드</h2>
<h3 id="2xx--성공">2XX : 성공</h3>
<table>
<thead>
<tr>
<th align="center">상태코드</th>
<th>response</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">200</td>
<td>OK(성공)</td>
<td>요청이 성공적으로 처리되었다. 서버가, 요청한 페이지를 제공하였다.</td>
</tr>
</tbody></table>
<h3 id="3xx--리다이렉션">3XX : 리다이렉션</h3>
<table>
<thead>
<tr>
<th align="center">상태코드</th>
<th>response</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">302</td>
<td>FOUND(임시 이동)</td>
<td>요청한 리소스의 URI가 일시적으로 변경되었다.</td>
</tr>
</tbody></table>
<h3 id="4xx--클라이언트-에러">4XX : 클라이언트 에러</h3>
<table>
<thead>
<tr>
<th align="center">상태코드</th>
<th>response</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">401</td>
<td>Unauthorized(권한 없음)</td>
<td>인증이 필요하다.</td>
</tr>
<tr>
<td align="center">403</td>
<td>Forbidden(금지됨)</td>
<td>서버가 요청을 거부하였다. 예를 들어 사용자가 리소스에 대한 필요 권한을 갖고 있지 않는 경우이다.</td>
</tr>
<tr>
<td align="center">404</td>
<td>Not Found(찾을 수 없음)</td>
<td>서버가 요청한 페이지(리소스)를 찾을 수 없다. 예를 들어 서버에, 존재하지 않는 페이지를 요청할 경우이다.</td>
</tr>
<tr>
<td align="center">405</td>
<td>Method Not Allowed(허용되지 않는 메소드)</td>
<td>예를 들어, POST 방식으로 요청을 받는 서버에 GET 요청을 보내는 경우, 읽기 전용 리소스에 PUT 요청을 보내는 경우, 필수 메소드인 GET과 HEAD를 제거할 경우에 발생한다.</td>
</tr>
</tbody></table>
<h3 id="5xx--서버-에러">5XX : 서버 에러</h3>
<table>
<thead>
<tr>
<th align="center">상태코드</th>
<th>response</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">500</td>
<td>Internal Server Error(내부 서버 오류)</td>
<td>서버에 오류가 발생하여 요청을 수행할 수 없다.</td>
</tr>
<tr>
<td align="center">501</td>
<td>Not Implemented(구현되지 않음)</td>
<td>서버에 요청을 수행할 수 있는 기능이 없다. 예를 들어 서버가 요청 메소드를 인식하지 못할 경우이다.</td>
</tr>
<tr>
<td align="center">502</td>
<td>Bad Gateway</td>
<td>서버가 게이트웨이나 프록시 역할을 하고 있거나 또는 업스트림 서버로부터 잘못된 응답을 받는 경우이다.</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[Algorithm | 2. DFS]]></title>
            <link>https://velog.io/@printver_2world/Algorithm-2.-DFS</link>
            <guid>https://velog.io/@printver_2world/Algorithm-2.-DFS</guid>
            <pubDate>Mon, 15 Nov 2021 04:33:34 GMT</pubDate>
            <description><![CDATA[<h3 id="1-준비">1. 준비</h3>
<ul>
<li><p>stack 리스트에는 현재 node와 앞으로 탐색해야 할 node가 담겨있다. stack은 가장 나중에 담긴 것을 가장 먼저 탐색하므로 순서를 잘 생각하며 append한다.</p>
</li>
<li><p>visited는 빈 리스트로 초기화한다. node에 방문했을 때 차례대로 append하면, 방문한 순서를 알 수 있다.</p>
</li>
<li><p>DFS는 그래프가 인접 노드를 확인할 수 있는 그래프가 필요하다. 아래 두 가지 방식이 있는데, </p>
<ul>
<li>인접 행렬 방식</li>
<li>인접 리스트 방식
이 두 가지의 장단점은 깃헙에 정리두었다. 
<a href="https://github.com/SJLEE316/Python-Algorithm-Study/blob/main/3.%20DFS%26BFS/%EC%9D%B4%EC%86%8C%EC%A0%95/DFS%26BFS.md#%EC%9D%B4-%EB%91%90-%EA%B0%80%EC%A7%80%EC%9D%80-%EC%96%B4%EB%96%A4-%EC%B0%A8%EC%9D%B4%EA%B0%80-%EC%9E%88%EC%9D%84%EA%B9%8C">장단점 알아가기</a></li>
</ul>
</li>
<li><p>목표 : <code>[[], [2, 3], [1, 5], [1, 4], [3, 5], [2, 4]]</code></p>
<ul>
<li>항상 번호와 index 사이에서 오류가 잘 나기 마련이어서 애초에 0행을 만들어주지만 사용하지 않는 것으로 방어 코딩(?)을 해보겠다.</li>
<li>input값을 받아 어떻게든 graph를 위의 형식을 출력을 한다.<pre><code>5 4
5 2
1 2
3 4
3 1</code></pre>위에 처럼 input값을 받아준다면<pre><code class="language-python">for _ in range(M):
v1, v2 = map(int, input().split()) # 한 줄에 들어오는 것을 각각 node로 받는다.
graph[v1].append(v2) # 해당 노드의 인접 노드로 append해준다.
graph[v2].append(v1) # 무방향이므로 다른 노드에도 append해준다.
</code></pre>
</li>
</ul>
<p>for adj in graph:
  adj.sort()</p>
<pre><code>처럼 graph를 만들어줄 수 있다.
&gt; **sort를 해주는 이유**
&gt; input이 정렬되어 들어오는 것이 아닐 수 있고, 코테 문제에 보면, 인접 노드가 여러 개일경우에는 번호가 작은 것 먼저 탐색 또는 큰 것 먼저 탐색하라는 조건이 있을 수 있기 때문이다. 따라서 일단 정렬을 해주는 것이 좋다. 
DFS 기능을 생각하면 순서와 상관없이 처리해주어도 되지만, 방문 순서가 다를 수 있다.
</code></pre></li>
</ul>
<br/>

<h3 id="2-반복">2. 반복</h3>
<p><code>while stack:</code>으로 stack이 빌 때까지 반복한다.
while문 안의 구조는 다음과 같다.</p>
<ul>
<li>stack에 담긴 node중에 현재 위치를 설정한다. <code>pop()</code>을 사용하면 가장 마지막 노드가 할당되고, 리스트에서는 삭제된다.</li>
<li>현재 노드가 방문한 노드인가?<ul>
<li>방문 처리를 한다.</li>
<li>stack에 현재 노드에 인접한 노드를 추가한다. <code>extend()</code>를 사용한다.</li>
</ul>
</li>
<li>stack이 비었을 때 visited를 리던한다.</li>
</ul>
<blockquote>
<p><strong>extend()를 사용하는 이유</strong>
extend() 메소드를 살펴보면, 리스트안에 리스트로 들어가는 것이 아니라, 값이 바로 들어간다. 따라서 2차원 리스트가 되는 것을 막을 수 있다.
주의해야 할 점은, stack에 넣는 것이므로, 인접한 노드가 여러 개일 경우, 어느 노드부터 탐색하라는 조건이 있을 때, 경우에 따라서 <code>reversed</code>를 사용해야 할 수도 있다.</p>
</blockquote>
<p>아래와 같은 코드로 작성하였다. 이 코드가 내가 dfs를 이해할 수 있는 코드이다. </p>
<pre><code class="language-python">N, M, V = map(int, input().split()) # V부터 탐색하시오!
# 인접행렬 방식
adjacency = [[] for _ in range(N+1)]
for _ in range(M):
  v1, v2 = map(int, input().split())
  adjacency[v1].append(v2)
  adjacency[v2].append(v1)

for adj in adjacency:
  adj.sort()

def dfs(adjacency, start_node):
  visited = []
  stack = [start_node] # 시작
  while stack: # stack이 빌 때까지
    now = stack.pop()
    if now not in visited: # 방문하지 않으면
      visited.append(now)
      stack.extend(reversed(adjacency[now])) # 작은 노드부터 탐색해야된다.

  return visited

print(dfs(adjacency, V))</code></pre>
<p>다음에는 재귀함수로 푸는 방법을 연구해봐야겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Python | 3. 리스트]]></title>
            <link>https://velog.io/@printver_2world/Python-%EB%A6%AC%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@printver_2world/Python-%EB%A6%AC%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Mon, 01 Nov 2021 06:58:44 GMT</pubDate>
            <description><![CDATA[<h1 id="리스트-자료형">리스트 자료형</h1>
<pre><code class="language-python">a = []   # 빈 값
b = [1, 2, 3]   # 숫자
c = [&#39;Life&#39;, &#39;is&#39;, &#39;too&#39;, &#39;short&#39;]   # 문자
d = [1, 2, &#39;Life&#39;, &#39;is&#39;]   # 숫자+문자
e = [1, 2, [&#39;Life&#39;, &#39;is&#39;]]   # 숫자+리스트

print(b[1]) # 2
print(b[-1]) # 3 -&gt; 뒤에서부터
print(c[1]) # is
print(d[2]) # Life
print(e[2]) # [&#39;Life&#39;, &#39;is&#39;]
print(e[2][0]) # Life
print(e[2][1]) # is</code></pre>
<br>

<h2 id="리스트의-슬라이싱">리스트의 슬라이싱</h2>
<p><code>a[이상:미만:간걱]</code></p>
<pre><code class="language-python">a = [1, 2, 3, 4, 5]

print(a[0:2]) # [1, 2]
print(a[:2]) # [1, 2]
print(a[2:]) # [3, 4, 5]</code></pre>
<br>

<h2 id="리스트의-더하기">리스트의 더하기</h2>
<pre><code class="language-python">a = [1, 2, 3]
b= [4, 5, 6]

print(a + b) # [1, 2, 3, 4, 5, 6]</code></pre>
<br>

<h2 id="리스트-반복하기">리스트 반복하기</h2>
<pre><code class="language-python">a = [1, 2, 3]

print(a * 3) # [1, 2, 3, 1, 2, 3, 1, 2, 3]</code></pre>
<br>

<h2 id="리스트에서-하나의-값-수정하기">리스트에서 하나의 값 수정하기</h2>
<pre><code class="language-python">a = [&#39;한&#39;, &#39;재&#39;, &#39;유&#39;]
a[0] = &#39;김&#39;

print(a) # [&#39;김&#39;, &#39;재&#39;, &#39;유&#39;]</code></pre>
<br>

<h2 id="리스트에서-연속된-범위의-값-수정하기">리스트에서 연속된 범위의 값 수정하기</h2>
<pre><code class="language-python">a = [&#39;한&#39;, &#39;재&#39;, &#39;유&#39;]
a[0:2] = [&#39;김&#39;, &#39;현&#39;]

print(a) # [&#39;김&#39;, &#39;현&#39;, &#39;유&#39;]</code></pre>
<br>

<h2 id="-사용하여-리스트-요소-삭제하기">[] 사용하여 리스트 요소 삭제하기</h2>
<pre><code class="language-python">a = [1, &#39;a&#39;, &#39;b&#39;, &#39;c&#39;, 4]
a[1:3] = []   # 빈 리스트로 교체

print(a) # [1, &#39;c&#39;, 4]</code></pre>
<br>

<h2 id="del-함수-사용해-리스트-요소-삭제하기">del 함수 사용해 리스트 요소 삭제하기</h2>
<pre><code class="language-python">a = [1, &#39;a&#39;, &#39;b&#39;, &#39;c&#39;, 4]
del a[0]

print(a) # [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;, 4]</code></pre>
<br>

<h2 id="리스트에-요소-추가append">리스트에 요소 추가(append)</h2>
<pre><code class="language-python">a = [1, 2, 3]

print(a.append(4)) # [1, 2, 3, 4]</code></pre>
<br>

<h2 id="리스트-정렬sort">리스트 정렬(sort)</h2>
<pre><code class="language-python">a = [1, 4, 3, 2]

# 가나다, 알파벳, 숫자는 크기 순
print(a.sort()) # [1, 2, 3, 4]</code></pre>
<br>

<h2 id="리스트-뒤집기reverse">리스트 뒤집기(reverse)</h2>
<pre><code class="language-python">a = [&#39;a&#39;, &#39;c&#39;, &#39;b&#39;]

print(a.reverse()) # [&#39;b&#39;, &#39;c&#39;, &#39;a&#39;]</code></pre>
<br>

<h2 id="위치-반환index">위치 반환(index)</h2>
<pre><code class="language-python">a = [1, 2, 3]

print(a.index(3)) # 3번 있냐</code></pre>
<pre><code>2 # 2번째에 있음</code></pre><br>

<h2 id="리스트에-요소-삽입insert">리스트에 요소 삽입(insert)</h2>
<pre><code class="language-python">a = [1, 2, 3]

print(a.insert(0, 4)) # 0번째 index에 4를 추가</code></pre>
<pre><code class="language-python">[4, 1, 2, 3]</code></pre>
<blockquote>
<p><strong>&lt; insert vs append &gt;</strong>
append는 맨 뒤에 추가
insert는 특정 index에 삽입할 수 있다
<br></p>
</blockquote>
<h2 id="리스트-요소-제거remove">리스트 요소 제거(remove)</h2>
<pre><code class="language-python">a = [1, 2, 3, 1, 2, 3]

print(a.remove(3)) # 3이라는 값 제거</code></pre>
<pre><code class="language-python">[1, 2, 1, 2, 3] # 가장 맨 앞에 있는 3만 제거</code></pre>
<p>모두 없애려면 for문 이용
<br></p>
<h2 id="리스트-요소-끄집어내기pop">리스트 요소 끄집어내기(pop)</h2>
<pre><code class="language-python">a = [1, 2, 3]

print(a.pop()) # 마지막 요소를 뽑는다
print(a) # 마지막 요소 제거</code></pre>
<pre><code class="language-python">3
[1, 2]</code></pre>
<br>

<h2 id="리스트에-포함된-요소-x의-개수-세기count">리스트에 포함된 요소 X의 개수 세기(count)</h2>
<pre><code class="language-python">a = [1, 5, 3, 1, 1]

print(a.count(1)) # 1의 개수를 센다</code></pre>
<pre><code class="language-python">3</code></pre>
<br>

<h2 id="리스트-확장extend">리스트 확장(extend)</h2>
<pre><code class="language-python">a = [1, 2, 3]
a.extend([4, 5])

print(a) # [1, 2, 3, 4, 5]</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Algorithm | 1. BFS]]></title>
            <link>https://velog.io/@printver_2world/Algorithm-1.-BFS</link>
            <guid>https://velog.io/@printver_2world/Algorithm-1.-BFS</guid>
            <pubDate>Thu, 28 Oct 2021 15:52:55 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>알고리즘 연습을 위해 deque 라이브러리는 사용하지 않는다. 다만 어떻게 사용하는지는 알아두자.</p>
</blockquote>
<h2 id="1차원">1차원</h2>
<h3 id="1-준비">1. 준비</h3>
<p>필요한 것은 q 리스트, visited 리스트, count이다.</p>
<ul>
<li>q에는 현재 위치가 담겨져 있다.</li>
<li>visited에는 0의 값을 가지는 리스트이고, 리스트의 크기를 설정해준다. (리스트의 크기를 잘못 설정할 시 런타임 에러가 발생할 수 있다.)</li>
<li>bfs는 보통 최단거리, 최단시간을 묻는 문제이므로 시간 및 거리를 담을 수 있는 count = 0(문제에 따라 1일 경우도 있음)을 준비한다. → count를 q에 데리고 다니는 것이 포인트이다.</li>
</ul>
<h3 id="2-반복">2. 반복</h3>
<p><code>while q</code> 로 q가 빈 queue가 될 때까지 반복한다.
반복문 내부의 구조는 다음과 같다.</p>
<ul>
<li><p>q에 담긴 node들 중에 현재 위치를 설정한다.</p>
</li>
<li><p>현재 count를 업데이트 한다.</p>
</li>
<li><p>방문한 노드를 삭제한다. (현재 위치)</p>
</li>
<li><p>현재 노드가 방문한 노드인가?</p>
<ul>
<li>방문했으면 if문을 빠져나와 앞으로 돌아간다. 현재 노드를 업데이트 해준다.</li>
<li>방문하지 않았으면<ul>
<li>방문 처리 한다.</li>
<li>찾는 노드인가? -&gt; return count! (함수가 종료된다.)</li>
<li>아니면 q에 append한다. (문제의 조건에 따라 if문으로 처리한다. 이때 주어진 범위에 벗어나면 안된다.)</li>
</ul>
</li>
</ul>
</li>
<li><p>q가 비었을 때 -1를 리턴한다. (찾지 못한 경우)</p>
</li>
</ul>
<h3 id="예외문제">예외문제</h3>
<ul>
<li>가끔씩 방문처리를 하지 않아도 되는 문제가 있다. 이때 방문처리를 위한 visited 리스트를 생성하게 되면 메모리 초과가 발생한다.
<a href="https://www.acmicpc.net/problem/16953">A → B</a> 문제는 방문처리를 하지 않아도 된다. 변수의 범위가 심각하게 클 경우는 이 부분을 의심해보자.</li>
</ul>
<h2 id="2차원">2차원</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[Python | 2.2 자료형_문자열]]></title>
            <link>https://velog.io/@printver_2world/Python-2.2-%EC%9E%90%EB%A3%8C%ED%98%95%EB%AC%B8%EC%9E%90%EC%97%B4</link>
            <guid>https://velog.io/@printver_2world/Python-2.2-%EC%9E%90%EB%A3%8C%ED%98%95%EB%AC%B8%EC%9E%90%EC%97%B4</guid>
            <pubDate>Mon, 25 Oct 2021 02:05:06 GMT</pubDate>
            <description><![CDATA[<h1 id="문자열">문자열</h1>
<pre><code class="language-python">a = &quot;Hello world&quot;

print(a) # Hello world</code></pre>
<pre><code class="language-python">a = &quot;Hello world&quot;

print(type(a)) # &lt;class &#39;str&#39;&gt; 문자열</code></pre>
<hr>
<p>큰따옴표, 작은따옴표 따로 사용 가능
중복해서 쓰면 오류발생</p>
<pre><code class="language-python">a =&quot;I&#39;m a good girl.&quot;
# 또는
a = &quot;i\&#39;m a good girl.&quot; # 백슬래시 이용

print(a) # I&#39;m a good girl.</code></pre>
<blockquote>
<p>&quot;&quot;
&#39;&#39;
&#39;&quot; &quot;&#39;
모두 가능</p>
</blockquote>
<hr>
<br>

<h2 id="줄-띄우기">줄 띄우기</h2>
<pre><code class="language-python">\n</code></pre>
<p>&quot;&quot;&quot; &quot;&quot;&quot;사이에 쓸 경우는 \n 쓰지 않아도 enter를 줄 띄우기로 인식한다.</p>
<br>

<h2 id="문자열-더하기">문자열 더하기</h2>
<pre><code class="language-python">a = &quot;Python&quot;
b = &quot; is fun!&quot;

print(a+b) # python is fun!</code></pre>
<br>

<h2 id="문자열-곱하기">문자열 곱하기</h2>
<pre><code class="language-python">a = &quot;Python&quot;

print(a*100) # PythonPythonPythonPythonPythonPythonPython.... Python이 100번 출력된다</code></pre>
<br>

<h2 id="인덱싱indexing">인덱싱(Indexing)</h2>
<pre><code class="language-python">a = &quot;Python is fun.&quot;

print(a[2]) # t (0부터 시작)
print(a[-2]) # n (뒤에서 두 번째)</code></pre>
<br>

<h2 id="슬라이싱slicing">슬라이싱(Slicing)</h2>
<p>a[ 이상 : 미만 : 간격 ]</p>
<pre><code class="language-python">a = &quot;Python is fun.&quot;

print(a[0:2]) # Py (0이상 2미만)
print(a[3:7]) # hon (뒤에서 두 번째)
print(a[:8]) # Python i (비워두면 무조건 처음부터)
print(a[8:]) # s fun! (8이상 맨 끝까지)
print(a[::1]) # Python is fun! (1칸 간격으로)
print(a[::2]) # Pto sfn (2칸 간격으로)
print(a[::-1]) # !nuf si nohtyP (1칸 간격으로 뒤에서 부터 읽음)
print(a[::-2]) # !u inhy (2칸 간격으로 뒤에서 부터 읽음)</code></pre>
<br>

<h2 id="문자열-포메팅">문자열 포메팅</h2>
<pre><code class="language-python">a = &quot;I eat %d apples.&quot; %3

print(a) # I eat 3 apples.</code></pre>
<pre><code class="language-python">number = 10
day = &quot;three&quot;

a=&quot;I ate %d apples, so I was sick for %s days.&quot; %(number, day)

print(a) # I ate 10 apples, so I was sick for three days.</code></pre>
<pre><code class="language-python">a = &quot;I was sick for {} days.&quot; .format(&quot;three&quot;)

print(a) # I was sick for three days.</code></pre>
<hr>
<p>변수 순서는 상관없다. 변수 이름 찾아서 포메팅 가능</p>
<pre><code class="language-python">a = &quot;Hello. My name is {name}. I&#39;m {age} years old.&quot; .format(name=&quot;Lucy&quot;, age=20)

print(a) # Hello. My name is Lucy. I&#39;m 20 years old.</code></pre>
<pre><code class="language-python">name = &quot;int&quot;
a = f &quot;나의 이름은 {name}입니다.&quot; # format 굳이 안써도 f만 써도 된다.

print(a) # 나의 이름은 int입니다.</code></pre>
<br>

<h2 id="정렬과-공백">정렬과 공백</h2>
<pre><code class="language-python">a = &quot;%s. Good today.&quot; %&quot;hi&quot;
b = &quot;%10s. Good today.&quot; %&quot;hi&quot; # 10칸 공백
c = &quot;%-10s. Good today.&quot; %&quot;hi&quot; # 뒤에서부터 10칸 공백

print(a)
print(b)
print(c)</code></pre>
<pre><code>hi. Good today.
          hi. Good today. # 10칸 공백
hi          .Good today.</code></pre><br>

<h2 id="소수점-표현">소수점 표현</h2>
<pre><code class="language-python">a = &quot;%f&quot; %3.423451343 # 소수점 전체 출력
b = &quot;%0.4f&quot; %3.423451343 # 간격.소수점 남기는 자리 수f

print(a) # 3.423451
print(b) # 3.4235</code></pre>
<br>

<h2 id="문자열-개수-세기count">문자열 개수 세기(count)</h2>
<pre><code class="language-python">a = &quot;hobby&quot;

print(a.count(&#39;b&#39;)) # b의 개수는 몇 개? 2</code></pre>
<br>

<h2 id="위치-알려주기">위치 알려주기</h2>
<h3 id="find">find</h3>
<pre><code class="language-python">a = &quot;hobby&quot;

print(a.find(&#39;b&#39;)) # 2 (가장 먼저 나오는 b의 index를 알려준다)
print(a.find(&#39;x&#39;)) # -1 (없으면 -1이 출력)</code></pre>
<h3 id="index">index</h3>
<pre><code class="language-python">a = &quot;Life is too short&quot;

print(a.index(&#39;t&#39;)) # 8 (있다)
print(a.index(&#39;a&#39;)) # ValueError : substring not found (없다)</code></pre>
<br>

<h2 id="문자열-삽입join">문자열 삽입(join)</h2>
<pre><code class="language-python">a = &quot;,&quot;.join(&quot;abcd&quot;)

print(a) # a,b,c,d</code></pre>
<pre><code class="language-python">a = &quot;,&quot;.join([&quot;a&quot;,&quot;b&quot;,&quot;c&quot;,&quot;d&quot;])

print(a) # a,b,c,d</code></pre>
<br>

<h2 id="소문자를-대문자로-바꾸기upper">소문자를 대문자로 바꾸기(upper)</h2>
<pre><code class="language-python">a = &quot;hi&quot;

print(a.upper()) # HI</code></pre>
<br>

<h2 id="대문자를-소문자로-바꾸기lower">대문자를 소문자로 바꾸기(lower)</h2>
<pre><code class="language-python">a = &quot;HI&quot;

print(a.lower()) # hi</code></pre>
<br>

<h2 id="양쪽-공백-지우기strip">양쪽 공백 지우기(strip)</h2>
<pre><code class="language-python">a = &quot;  hi  &quot;

print(a.strip()) # hi</code></pre>
<br>

<h2 id="문자열-바꾸기replace">문자열 바꾸기(replace)</h2>
<pre><code class="language-python">a = &quot;Life is too short.&quot;

print(a.replace(&quot;Life&quot;, &quot;Your leg&quot;)) # Your leg is too short.</code></pre>
<br>

<h2 id="문자열-나누기split">문자열 나누기(split)</h2>
<pre><code class="language-python">a = &quot;Life is too short.&quot;

print(a.split()) # [&#39;Life&#39;, &#39;is&#39;, &#39;too&#39;, &#39;short&#39;] (띄어쓰기를 기준으로 리스트로 만든다)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git | git add 취소하기(unstaged 상태 만들기)]]></title>
            <link>https://velog.io/@printver_2world/Git-git-add-%EC%B7%A8%EC%86%8C%ED%95%98%EA%B8%B0unstaged-%EC%83%81%ED%83%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@printver_2world/Git-git-add-%EC%B7%A8%EC%86%8C%ED%95%98%EA%B8%B0unstaged-%EC%83%81%ED%83%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Tue, 14 Sep 2021 15:44:52 GMT</pubDate>
            <description><![CDATA[<h1 id="git-add-취소하기">git add 취소하기</h1>
<h3 id="1-파일을-unstaged-상태로-만들기">1. 파일을 unstaged 상태로 만들기</h3>
<pre><code>git reset HEAD [file]</code></pre><br>

<h3 id="2-stage에-있는-모든-파일을-unstaged-상태로-만들기">2. stage에 있는 모든 파일을 unstaged 상태로 만들기</h3>
<pre><code>git reset HEAD</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Python | 2.1 자료형_숫자형]]></title>
            <link>https://velog.io/@printver_2world/Python-2.1-%EC%9E%90%EB%A3%8C%ED%98%95%EC%88%AB%EC%9E%90%ED%98%95</link>
            <guid>https://velog.io/@printver_2world/Python-2.1-%EC%9E%90%EB%A3%8C%ED%98%95%EC%88%AB%EC%9E%90%ED%98%95</guid>
            <pubDate>Mon, 13 Sep 2021 01:40:49 GMT</pubDate>
            <description><![CDATA[<h1 id="숫자형">숫자형</h1>
<pre><code class="language-python"># hello.py

a=1

print(a) # 1</code></pre>
<pre><code class="language-python">a=1

print(type(a)) # &lt;class &#39;int&#39;&gt; 정수형</code></pre>
<pre><code class="language-python">a=1.24

print(type(a)) # &lt;class &#39;float&#39;&gt; 실수형</code></pre>
<pre><code class="language-python">a=3
b=4

print(a+b) # 7</code></pre>
<blockquote>
<p>a * b(곱하기)
a / b(나머지)
a // b(몫)
a % b(나머지)
a ** b(제곱)</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Python | 1. What is Python?]]></title>
            <link>https://velog.io/@printver_2world/Python-1.-What-is-Python</link>
            <guid>https://velog.io/@printver_2world/Python-1.-What-is-Python</guid>
            <pubDate>Sun, 12 Sep 2021 12:42:51 GMT</pubDate>
            <description><![CDATA[<h1 id="파이썬의-특징">파이썬의 특징</h1>
<ul>
<li>파이썬은 인간다운 언어이다</li>
<li>파이썬은 무료이지만 강력하다 → 파이썬과 C언어는 찰떡궁합</li>
<li>파이썬은 간결하다</li>
<li>파이썬은 개발 속도가 빠르다<br>

</li>
</ul>
<h1 id="파이썬-실행">파이썬 실행</h1>
<pre><code class="language-python"># hello.py

print(&quot;hello&quot;)</code></pre>
<pre><code class="language-python">$ python hello.py</code></pre>
<p>터미널에서 python이라고 치면 python shell이 열린다</p>
<pre><code>&gt;&gt;&gt;</code></pre><p>또는 python 3.7(32-bit)에 들어갈 수도 있다.</p>
<p>(파이썬 대화형 인터프리터=파이썬 셸)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[django | 20. 로그인, 로그아웃 구현하기]]></title>
            <link>https://velog.io/@printver_2world/django-20.-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EB%A1%9C%EA%B7%B8%EC%95%84%EC%9B%83-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@printver_2world/django-20.-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EB%A1%9C%EA%B7%B8%EC%95%84%EC%9B%83-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 21 Aug 2021 02:46:14 GMT</pubDate>
            <description><![CDATA[<p>장고는 로그인, 로그아웃을 쉽게 구현할 수 있도록 <code>django.contrib.auth</code> 앱을 제공한다. 이 앱은 장고 프로젝트 생성 시 settings.py에 자동으로 추가된다.
<a href="https://docs.djangoproject.com/en/3.2/ref/contrib/auth/">django.contrib.auth 관련 공식문서</a></p>
<p><img src="https://images.velog.io/images/printver_2world/post/7406ffe1-f507-4b12-b3ae-a344168604d8/image.png" alt=""></p>
<h1 id="앱-생성-후-초기-설정하기">앱 생성 후 초기 설정하기</h1>
<p>로그인, 로그아웃은 home 앱에 구현해야 할까? 그렇지 않다. 하나의 웹 사이트에는 home과 같은 게시판 서비스외에도 블로그나 쇼핑몰과 같은 굵직한 단위의 앱들이 함께 있을 수 있기 때문에 공통으로 사용되는 기능인 로그인이나 로그아웃을 이 중의 하나의 앱에 종속시키는 것은 좋지 않기 때문이다. 이러한 이유로 &#39;users&#39; 앱을 만들어 구현할 것이다.</p>
<h2 id="1-users-앱-생성하기">1. users 앱 생성하기</h2>
<pre><code>$ django-admin startapp users</code></pre><h2 id="2-앱-등록하기">2. 앱 등록하기</h2>
<pre><code class="language-python"># settings.py

...
INSTALLED_APPS = [
    &#39;django.contrib.admin&#39;,
    &#39;django.contrib.auth&#39;,
    ...
    &#39;home&#39;,
    &#39;users&#39;,
]
...</code></pre>
<h2 id="3-urlspy에-url-연결하기">3. urls.py에 url 연결하기</h2>
<pre><code class="language-python">
...
urlpatterns = [
  ...
  path(&#39;users/&#39;, include(&#39;users.urls&#39;)), # users&gt;urls.py에서 관리할거야
]</code></pre>
<p><code>/users/</code>으로 시작하는 URL은 모두 users&gt;urls.py 파일을 참조할 것이다.</p>
<h2 id="4-user-앱의-urlspy-생성하기">4. user 앱의 urls.py 생성하기</h2>
<p>urls.py 파일을 생성하고 아래의 코드를 작성한다.</p>
<pre><code class="language-python"># urls.py

from django.urls import path
from .views import * # user&gt;views에서 모든 함수를 가져온다.

app_name = &quot;users&quot;
urlpatterns = [
]</code></pre>
<h1 id="로그인-구현하기">로그인 구현하기</h1>
<h2 id="1-loginhtml-생성하기">1. login.html 생성하기</h2>
<p>users 앱에 templates&gt;users 디렉토리를 생성한 후, 그 안에 login.html 파일을 만든다.</p>
<pre><code class="language-html">&lt;!-- users&gt;login.html --&gt;

&lt;h1&gt;로그인 페이지야&lt;/h1&gt;</code></pre>
<h2 id="2-로그인-url-연결하기">2. 로그인 URL 연결하기</h2>
<pre><code class="language-python"># users&gt;urls.py

from django.urls import path
from django.contrib.auth import views as auth_views

app_name = &quot;users&quot;
urlpatterns = [
  path(&#39;login/&#39;, auth_views.LoginView.as_view(), name=&#39;login&#39;), # 수정해야하는 코드
  # django.contrib.auth앱의 LoginView 클래스를 활용했으므로 별도의 views.py 파일 수정이 필요 없음
]</code></pre>
<p><code>django.contrib.auth</code> 앱을 사용할 것이므로 users&gt;views.py 파일은 수정할 필요가 없다. 여기서는 <code>django.contrib.auth</code> 앱의 LoginView 클래스를 사용한다.
<a href="https://docs.djangoproject.com/en/3.2/topics/auth/default/#module-django.contrib.auth.views">Authentication Views 관련 공식문서</a></p>
<h2 id="3-로그인-템플릿-만들기">3. 로그인 템플릿 만들기</h2>
<p>user관련된 것은 users 앱에서 관리하기로 하였으므로 <code>users/login</code>으로 들어가면 아래와 같은 에러가 발생한다.
<img src="https://images.velog.io/images/printver_2world/post/ee86ea90-c595-4eb5-9bfc-e3b901d910f5/image.png" alt="">
<code>registration/login.html</code>이 없다는 의미인데, 아래의 공식문서를 읽어보면 어떠한 문제인지 알 수 있다.
<a href="https://docs.djangoproject.com/en/3.2/topics/auth/default/#all-authentication-views">login템플릿 공식문서</a>
LoginView는 registration이라는 템플릿 디렉토리에서 login.html 파일을 찾는다. 그런데 이 파일을 찾지 못해서 오류가 발생한 것이다. 지금 users앱에 구현할 것이므로 아래 사진과 같이 <code>template_name=&#39;users/login.html&#39;</code>으로 설정하면 registration 디렉토리가 아닌 users 디렉토리에서 login.html파일을 참조하게 된다.
<img src="https://images.velog.io/images/printver_2world/post/78adb04f-c7ab-4587-b3e1-0b12d479399f/image.png" alt="">
아래와 같이 코드를 수정해준다.</p>
<pre><code class="language-python"># users&gt;urls.py

...
urlpatterns = [
  path(&#39;login/&#39;, auth_views.LoginView.as_view(template_name=&#39;users/login.html&#39;), name=&#39;login&#39;),
]</code></pre>
<p>아래와 같이 잘 연결된다.
<img src="https://images.velog.io/images/printver_2world/post/f5986fdc-959e-4179-ae42-134651f06ff8/image.png" alt=""></p>
<h2 id="4-loginhtml-내용-구성하기">4. login.html 내용 구성하기</h2>
<pre><code class="language-html">&lt;!-- users&gt;login.html --&gt;

{% extends &#39;base.html&#39; %}
{% block content %}

&lt;h1&gt;로그인&lt;/h1&gt;
&lt;form method=&quot;post&quot; action=&quot;{% url &#39;users:login&#39; %}&quot;&gt;
  {% csrf_token %}
  &lt;div&gt;
    &lt;label&gt;사용자 ID&lt;/label&gt;
    &lt;input type=&quot;text&quot; name=&quot;username&quot; id=&quot;username&quot;&gt;
  &lt;/div&gt;
  &lt;div&gt;
    &lt;label&gt;비밀번호&lt;/label&gt;
    &lt;input type=&quot;text&quot; name=&quot;password&quot; id=&quot;password&quot;&gt;
  &lt;/div&gt;
  &lt;button type=&quot;submit&quot;&gt;로그인&lt;/button&gt;
&lt;/form&gt;

{% endblock %}</code></pre>
<p>입력 항목 <code>username</code>과 <code>password</code>는 모두 <code>django.contrib.auth</code> 앱에서 요구하는 필수 항목이다.
<img src="https://images.velog.io/images/printver_2world/post/81b638d4-72f2-47c9-bad0-ae8cce2dd711/image.png" alt=""></p>
<h2 id="5-form_errorshtml-만들기">5. form_errors.html 만들기</h2>
<p>users&gt;form_errors.html 파일을 만든다.</p>
<pre><code class="language-html">&lt;!-- users&gt;form_errors.html --&gt;

{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
&lt;!-- 필드 오류를 출력한다. --&gt;
&lt;div&gt;
  &lt;strong&gt;{{ field.label }}&lt;/strong&gt;
  {{ error }}
&lt;/div&gt;
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
&lt;!-- 넌필드 오류를 출력한다. --&gt;
&lt;div&gt;
  &lt;strong&gt;{{ error }}&lt;/strong&gt;
&lt;/div&gt;
{% endfor %}
{% endif %}</code></pre>
<p>form_errors.html 파일은 로그인 실패 시 로그인이 실패한 원인을 알려 준다. 폼 오류에는 두 가지가 있는데</p>
<blockquote>
<ul>
<li>필드 오류(입력값이 누락되었거나 형식에 맞지 않음)</li>
</ul>
</blockquote>
<ul>
<li>넌필드 오류(입력값과 관계없이 발생한 오류)</li>
</ul>
<p>다 작성하면 login.html에 코드 한 줄을 추가한다.</p>
<pre><code class="language-html">&lt;!-- users&gt;login.html --&gt;

...
&lt;form method=&quot;post&quot; action=&quot;{% url &#39;users:login&#39; %}&quot;&gt;
  {% csrf_token %}
  {% include &#39;users/form_errors.html&#39; %} &lt;!-- 코드 추가 --&gt;
  &lt;div&gt;
    &lt;label&gt;사용자 ID&lt;/label&gt;
    ...
&lt;/form&gt;

{% endblock %}</code></pre>
<p><img src="https://images.velog.io/images/printver_2world/post/d5e5a94e-a90a-4968-b6ac-0d2adca08c9d/image.png" alt="">
<img src="https://images.velog.io/images/printver_2world/post/747f5ae6-7902-48fa-9cce-d3c58b17dda8/image.png" alt=""></p>
<h2 id="6-제대로-로그인해-보기">6. 제대로 로그인해 보기</h2>
<p>생성한 슈퍼 유저 계정으로 로그인을 해보면 아래와 같은 오류가 발생한다.
<img src="https://images.velog.io/images/printver_2world/post/acac2708-8b83-4268-abf8-e63551394da3/image.png" alt="">
장고는 로그인을 하면 <code>accounts/profile/</code> 라는 URL로 리다이렉트하는데, 지금 이 페이지가 존재하지 않아서 생긴 오류이다. 따라서 로그인 후 이동할 페이지를 등록해야 한다.</p>
<h2 id="7-로그인-성공-시-이동할-페이지-등록하기">7. 로그인 성공 시 이동할 페이지 등록하기</h2>
<p>장고는 <code>accounts/profile/</code> URL로 리다이렉트하지만, 다른 URL로 이동하고 싶다. <code>settings.py</code>에서 마지막 줄에 코드를 추가한다.</p>
<pre><code class="language-python"># settings.py

# 로그인 성공 시 자동으로 이동할 URL
LOGIN_REDIRECT_URL = &#39;/&#39;</code></pre>
<p>그러면 로그인 성공 시 / 페이지로 이동이 잘 된다.</p>
<h2 id="8-네브바에-연결하기">8. 네브바에 연결하기</h2>
<pre><code class="language-html">&lt;!-- _navbar.html --&gt;

&lt;a href=&quot;{% url &#39;users:login&#39; %}&quot;&gt;로그인&lt;/a&gt;</code></pre>
<p><img src="https://images.velog.io/images/printver_2world/post/a69cc651-d719-454a-ad09-879228e0af77/image.png" alt="">
<br></p>
<h1 id="로그아웃-구현하기">로그아웃 구현하기</h1>
<h2 id="1-로그아웃-url-연결하기">1. 로그아웃 URL 연결하기</h2>
<pre><code class="language-python"># users&gt;urls.py

from django.urls import path
from django.contrib.auth import views as auth_views

app_name = &quot;users&quot;
urlpatterns = [
  path(&#39;login/&#39;, auth_views.LoginView.as_view(template_name=&#39;users/login.html&#39;), name=&#39;login&#39;),
  path(&#39;logout/&#39;, auth_views.LogoutView.as_view(), name=&#39;logout&#39;), # 코드 추가하기
]</code></pre>
<h2 id="2-로그아웃-성공-시-이동할-페이지-등록하기">2. 로그아웃 성공 시 이동할 페이지 등록하기</h2>
<pre><code class="language-python"># settings.py

# 로그아웃 성공 시 자동으로 이동할 URL
LOGOUT_REDIRECT_URL = &#39;/&#39;</code></pre>
<p>로그아웃에 성공하면 &#39;/&#39; 페이지로 리다이렉트할 것이다.</p>
<h2 id="3-네브바에-연결하기">3. 네브바에 연결하기</h2>
<pre><code class="language-html">&lt;!-- _navbar.html --&gt;

{% if user.is_authenticated %} 
&lt;a href=&quot;{% url &#39;users:logout&#39; %}&quot;&gt;{{ user.username }}님 로그아웃&lt;/a&gt;
&lt;span&gt;||&lt;/span&gt;
{% else %}
&lt;a href=&quot;{% url &#39;users:login&#39; %}&quot;&gt;로그인&lt;/a&gt;
{% endif %}</code></pre>
<p><code>{% if user.is_authenticated %}</code>는 현재 로그인 상태를 판별한다.
<code>{{ user.username }}</code>는 로그인한 사용자명을 표시한다.</p>
<blockquote>
<p><strong>궁금궁금</strong>
<em><code>user</code>에는 사용자에 대한 정보가 자동으로 들어가는 것인지는 잘 모르겠다. 필드로 따로 설정한 것은 없다.</em></p>
</blockquote>
<p><img src="https://images.velog.io/images/printver_2world/post/a2c57306-2540-4ed1-a721-c75a6f7e0278/image.png" alt=""></p>
<p><a href="https://docs.djangoproject.com/en/3.2/topics/auth/default/#using-the-django-authentication-system">사용자 관련 공식문서</a>
<a href="https://docs.djangoproject.com/en/3.2/topics/auth/default/#how-to-log-a-user-in">새로운 로그인, 로그아웃 방법 : 공식문서</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[django | 19. 질문에 달린 답변 개수 표시하기]]></title>
            <link>https://velog.io/@printver_2world/django-19.-%EC%A7%88%EB%AC%B8%EC%97%90-%EB%8B%AC%EB%A6%B0-%EB%8B%B5%EB%B3%80-%EA%B0%9C%EC%88%98-%ED%91%9C%EC%8B%9C%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@printver_2world/django-19.-%EC%A7%88%EB%AC%B8%EC%97%90-%EB%8B%AC%EB%A6%B0-%EB%8B%B5%EB%B3%80-%EA%B0%9C%EC%88%98-%ED%91%9C%EC%8B%9C%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 21 Aug 2021 00:24:14 GMT</pubDate>
            <description><![CDATA[<h1 id="질문에-달린-답변-개수-표시하기">질문에 달린 답변 개수 표시하기</h1>
<pre><code class="language-html">&lt;!-- question_list.html --&gt;

...
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;
        {% if question.answer_set.count &gt; 0%}
        {{ question.answer_set.count }}
        {% endif %}
      &lt;/td&gt;
      ...</code></pre>
<p>답변이 있는 경우를 조사하고, 있으면 표시하고 없으면 표시하지 않는다.
<img src="https://images.velog.io/images/printver_2world/post/9be16671-1a21-4a0e-812b-8c89a20ae1b0/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[django | 18. 페이징 기능 추가하기]]></title>
            <link>https://velog.io/@printver_2world/django-18.-%ED%8E%98%EC%9D%B4%EC%A7%95-%EA%B8%B0%EB%8A%A5-%EC%B6%94%EA%B0%80%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@printver_2world/django-18.-%ED%8E%98%EC%9D%B4%EC%A7%95-%EA%B8%B0%EB%8A%A5-%EC%B6%94%EA%B0%80%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 20 Aug 2021 06:53:38 GMT</pubDate>
            <description><![CDATA[<h1 id="페이징-함수-작성하기">페이징 함수 작성하기</h1>
<pre><code class="language-python"># views.py
...
from django.core.paginator import Paginator
...

def question_list(request):
  questions = Question.objects.order_by(&#39;-create_date&#39;) # Question 모델 데이터를 작성일시의 역순(-)으로 정렬한다.
  # Paging 기능 구현하기
  page = request.GET.get(&#39;page&#39;, &#39;1&#39;) # GET 방식 요청 URL에서 page값을 가져올 때 사용(?page=1). page 파라미터가 없는 URL을 위해 기본값으로 1을 지정한 것
  paginator = Paginator(questions, 5) # Paginator 클래스는 questions를 페이징 객체 paginator로 변환. 페이지당 5개씩 보여주기
  page_obj = paginator.get_page(page) # page_obj 객체에는 여러 속성이 존재
  context = { &#39;questions_list&#39; : page_obj } # page_obj를 question_list에 저장한다.
  return render(request, &#39;home/question_list.html&#39;, context)</code></pre>
<p><img src="https://images.velog.io/images/printver_2world/post/f2373cab-e82d-4ef6-85dd-22e7282769ff/image.png" alt="">
5개씩 보이도록 설정하여서 5개만 보인다.
<code>page_obj</code> 객체에는 다음과 같은 속성들이 있다.</p>
<table>
<thead>
<tr>
<th>항목</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>paginator.count</td>
<td>전체 게시물 개수</td>
</tr>
<tr>
<td>paginator.per_page</td>
<td>페이지당 보여줄 게시물 개수</td>
</tr>
<tr>
<td>paginator.page_range</td>
<td>페이지 범위</td>
</tr>
<tr>
<td>number</td>
<td>현재 페이지 번호</td>
</tr>
<tr>
<td>previous_page_number</td>
<td>이전 페이지 번호</td>
</tr>
<tr>
<td>next_page_number</td>
<td>다음 페이지 번호</td>
</tr>
<tr>
<td>has_previous</td>
<td>이전 페이지 유무</td>
</tr>
<tr>
<td>has_next</td>
<td>다음 페이지 유무</td>
</tr>
<tr>
<td>start_index</td>
<td>현재 페이지 시작 인덱스(1부터 시작)</td>
</tr>
<tr>
<td>end_index</td>
<td>현재 페이지 끝 인덱스(1부터 시작)</td>
</tr>
<tr>
<td><br></td>
<td></td>
</tr>
</tbody></table>
<h1 id="페이징-적용하기">페이징 적용하기</h1>
<pre><code class="language-html">&lt;!-- question_list.html --&gt;

...
&lt;/table&gt;
&lt;ul&gt;
  &lt;!-- 이전 페이지가 있으면 --&gt;
  {% if questions_list.has_previous %}
  &lt;a href=&quot;?page={{ questions_list.previous_page_number }}&quot;&gt;이전&lt;/a&gt;
  {% endif %}
  &lt;!-- 페이지 리스트 --&gt;
  {% for page_number in questions_list.paginator.page_range %}
  &lt;!-- 현재 페이지 번호랑 같다면 style을 다르게 줄 수 있다. --&gt;
  {% if page_number == question_list.number %}
  &lt;li&gt;
    &lt;a href=&quot;?page={{ page_number }}&quot;&gt;{{ page_number }}&lt;/a&gt;
  &lt;/li&gt;
  {% else %}
  &lt;li&gt;
    &lt;a href=&quot;?page={{ page_number }}&quot;&gt;{{ page_number }}&lt;/a&gt;
  &lt;/li&gt;
  {% endif %}
  {% endfor%}
  &lt;!-- 다음 페이지가 있으면 --&gt;
  {% if questions_list.has_next %}
  &lt;a href=&quot;?page={{ questions_list.next_page_number }}&quot;&gt;다음&lt;/a&gt;
  {% endif %}
&lt;/ul&gt;
&lt;!-- &lt;a href=&quot;{% url &#39;home:question_create&#39; %}&quot;&gt;질문 등록하기&lt;/a&gt; --&gt;
&lt;!-- 모델 폼 이용하지 않을 경우 --&gt;
&lt;a href=&quot;{% url &#39;home:question_new&#39; %}&quot;&gt;질문 등록하기&lt;/a&gt;

{% endblock %}</code></pre>
<p>템플릿에 사용된 <code>{{ questions_list }}</code>가 바로 views.py 파일의 page_obj이다. 다시 말해 템플릿의 <code>{{ questions_list.previous_page_number }}</code>는 `{{ page_obj.previous_page_number }}와 동일하다.
<br></p>
<h1 id="페이지-표시-제한-기능-구현하기">페이지 표시 제한 기능 구현하기</h1>
<h2 id="현재-문제">현재 문제</h2>
<p>임의의 데이터 300개를 넣어보자.</p>
<pre><code>$ python manage.py shell
&gt;&gt;&gt; from home.models import Question
&gt;&gt;&gt; for i in range(300):
...     Question.objects.create(subject=&quot;test data [%03d]&quot; %i, content=&quot;test data&quot;)  
... </code></pre><p>하면 데이터 300개가 생긴다. 여기서 문제점은 아래 사진과 같다.
<img src="https://images.velog.io/images/printver_2world/post/22f00594-00d6-404d-9f32-957cd2dce4b4/image.png" alt="">
페이지 버튼이 너무 많아진다.</p>
<h2 id="해결방법">해결방법</h2>
<pre><code class="language-html">&lt;!-- question_list.html --&gt;

...
  &lt;!-- 페이지 리스트 --&gt;
  {% for page_number in questions_list.paginator.page_range %}
  &lt;!-- 코드 추가하기 : 페이지 표시 제한 기능 구현하기 --&gt;
  {% if questions_list.number|add:5 &gt;= page_number and page_number &gt;= questions_list.number|add:-5 %}

...</code></pre>
<p><code>{% if questions_list.number|add:5 &gt;= page_number and page_number &gt;= questions_list.number|add:-5 %}</code> : 현재 페이지 기준으로 좌우 5개씩 보이도록 한다. <code>questions_list.number</code>보다 5만큼 크거나 작은 값만 표시되도록 만든 것이다.
<code>|add:-5</code>는 5만큼 빼라는 의미이고, <code>|add:5</code>는 5만큼 더하라는 의미이다.
<img src="https://images.velog.io/images/printver_2world/post/f88f1d08-6035-42ad-9f7a-ade2b00a69a8/image.png" alt="">
현재 페이지가 8페이지라서 페이지 번호는 3부터 13까지 보여진다.
<br></p>
<h1 id="테플릿-필터-직접-만들어-보기">테플릿 필터 직접 만들어 보기</h1>
<p>템플릿 필터란 템플릿 태그에서 <code>|</code>문자 뒤에 사용하는 필터를 말한다. 예를 들어 None 대신 공백 문자열을 보여주기 위해 사용했던 <code>default_if_none</code>과 같은 것을 템플릿 필터라고 한다.</p>
<pre><code>{{ form.subject.value|default_if_none:&#39;&#39;||</code></pre><h2 id="현재-문제-1">현재 문제</h2>
<p><img src="https://images.velog.io/images/printver_2world/post/f4867df5-772f-416f-b649-4fac11b947a4/image.png" alt="">
페이지마다 게시물 번호가 항상 1부터 시작되는 문제가 있다. </p>
<h2 id="해결-방법">해결 방법</h2>
<h3 id="1-게시물-번호-공식-만들기">1. 게시물 번호 공식 만들기</h3>
<p>만약 질문 게시물이 12개라면(한 페이지에 10개씩 표시) 1페이지에는 12번째<del>3번째 게시물이, 2페이지에는 2번째</del>1번째 게시물이 역순으로 표시되어야 한다. 질문 게시물의 번호를 역순으로 정렬하려면 다음과 같은 공식을 적용해야 한다.</p>
<pre><code>일련번호 = 전체 게시물 개수 - 시작 인덱스 - 현재 인덱스 + 1</code></pre><p>시작 인덱스는 페이지당 시작되는 게시물의 시작 번호를 의미한다. 예를 들어 페이지당 게시물을 10건씩 보여준다면 1페이지의 시작 인덱스는 1, 2페이지의 시작 인덱스는 11이 된다. 현재 인덱스는 페이지에 보여지는 게시물 개수만큼 0부터 1씩 증가되는 번호이다.
따라서 전체 게시물의 개수가 12개이고 페이지당 10건씩 게시물을 보여 준다면 1페이지의 일련번호는 <code>12 - 1 - (0 ~ 9 반복) + 1</code>이 되어 12<del>3까지 표시되고 2페이지의 경우에는 `12 - 11 - (0</del>1 반복) + 1<code>이 되어 2~1이 표시될 것이다.
템플릿에서 이 공식을 적용하려면 빼기 기능이 필요하다. 앞에서 더하기 필터(</code>|add:5<code>)를 사용한 것처럼 빼기 필터가 있으면 좋을 것 같지만 장고에는 빼기 필터가 없다. 그래서 우리는 빼기 필터를 만들 것이다.</code>|add:-5`와 같이 숫자를 직접 입력하면 더하기 필터를 이용하여 원하는 값을 뺀 결과를 화면에 보여줄 수는 있다. 하지만 이 방법은 이곳에는 사용할 수 없다. 왜냐하면 더하기 필터에는 변수를 적용할 수 없기 때문이다.</p>
<h3 id="2-템플릿-필터-디렉토리-만들기">2. 템플릿 필터 디렉토리 만들기</h3>
<p>템플릿 필터 함수는 템플릿 필터 파일을 작성한 다음에 정의해야 한다. 템플릿 필터 파일은 템플릿 파일이나 스태틱 파일과 마찬가지로 home/templatetags 디렉토리를 새로 만들어 저장해야 한다. 또한 templatetags 디렉토리는 반드시 앱 디렉토리 아래에 생성해야 한다. 
<a href="https://docs.djangoproject.com/ko/3.2/howto/custom-template-tags/">공식문서</a>에 따르면 디렉토리 안에 <code>__init__.py</code>파일이 필요하다. 
<img src="https://images.velog.io/images/printver_2world/post/a2850a17-7f86-4a9c-b804-90c95b86c7f2/image.png" alt=""></p>
<h3 id="3-템플릿-필터-작성하기">3. 템플릿 필터 작성하기</h3>
<pre><code class="language-python"># home_filter.py

from django import template

register = template.Library()

@register.filter
def sub(value, arg):
  return value - arg</code></pre>
<p>템플릿 필터 함수를 만드는 방법은, sub함수에 <code>@register.filter</code>라는 애너테이션을 적용하면 템플릿에서 해당 함수를 필터로 사용할 수 있게 된다. 템플릿 필터 함수 sub는 기존 값 value에서 입력으로 받은 값 arg를 빼서 반환할 것이다.</p>
<h3 id="4-템플릿-필터-사용하기">4. 템플릿 필터 사용하기</h3>
<p>우리가 직접 만든 템플릿 필터를 사용하려면 템플릿 파일 맨 위에 <code>{% load home_filter %}</code>와 같이 템플릿 필터 파일을 로드해야 한다. 만약 템플릿 파일 맨 위에 extends 문이 있으면 load 문은 extends 문 다음에 위치해야 한다.</p>
<pre><code class="language-html">&lt;!-- question_list.html --&gt;

{% extends &#39;base.html&#39; %}
&lt;!-- 추가 --&gt;
{% load home_filter %} 
{% block content %}

...
  &lt;tbody&gt;
    {% if questions_list %}
    {% for question in questions_list %}
    &lt;tr&gt;
      &lt;!-- 추가 --&gt;
      &lt;td&gt;{{ questions_list.paginator.count|sub:questions_list.start_index|sub:forloop.counter0|add:1 }}&lt;/td&gt;
...</code></pre>
<table>
<thead>
<tr>
<th>공식 요소</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>questions_list.paginator.count</td>
<td>전체 게시물 개수</td>
</tr>
<tr>
<td>questions_list.start_index</td>
<td>시작 인덱스(1부터 시작)</td>
</tr>
<tr>
<td>forloop.counter0</td>
<td>루프 내의 현재 인덱스(forloop.counter0은 0부터, forloop.counter는 1부터 시작)</td>
</tr>
</tbody></table>
<p><img src="https://images.velog.io/images/printver_2world/post/f2b1b35e-81e2-4c18-b5c4-7957b2daa528/image.png" alt="">
문제가 해결되었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[django | 17. Include 이용해서 네브바 만들기]]></title>
            <link>https://velog.io/@printver_2world/django-17.-Include-%EC%9D%B4%EC%9A%A9%ED%95%B4%EC%84%9C-%EB%84%A4%EB%B8%8C%EB%B0%94-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@printver_2world/django-17.-Include-%EC%9D%B4%EC%9A%A9%ED%95%B4%EC%84%9C-%EB%84%A4%EB%B8%8C%EB%B0%94-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Wed, 18 Aug 2021 06:44:41 GMT</pubDate>
            <description><![CDATA[<p>장고에는 특정 위치에 템플릿 파일을 삽입하는 <code>include</code>라는 기능이 있다.</p>
<h1 id="navbar-코드-작성하기">navbar 코드 작성하기</h1>
<p>djangoMaster &gt; templates &gt; shared 디렉토리에 _navbar.html 파일을 생성하고 아래의 코드를 작성한다.</p>
<pre><code class="language-html">&lt;!-- djangoMaster &gt; templates &gt; shared &gt; _navbar.html --&gt;

&lt;span&gt;여기가 네브바야 ----&gt; &lt;/span&gt;
&lt;a href=&quot;{% url &#39;main&#39; %}&quot;&gt;메인으로 가기&lt;/a&gt;
&lt;span&gt;||&lt;/span&gt;
&lt;a href=&quot;{% url &#39;home:question_list&#39; %}&quot;&gt;질문 목록으로 가기&lt;/a&gt;</code></pre>
<br>

<h1 id="include-적용하기">include 적용하기</h1>
<pre><code class="language-html">&lt;!-- base.html --&gt;

...
&lt;body&gt;
  &lt;!-- 네브바 위치 --&gt;
  {% include &#39;shared/_navbar.html&#39; %}
  ...
&lt;/body&gt;  </code></pre>
<p>include 기능은 템플릿의 특정 영영을 중복, 반복해서 사용할 경우에 유용하다. 즉, 중복, 반복되는 템플리싕 특정 영역을 따로 템플릿 파일로 만들고, include 기능으로 그 템플릿을 포함한다. _navbar.html 파일은 base.html 파일에서 1번만 사용되지만 따로 파일로 관리해야 이후 유지, 보수하는 데 유리하므로 분리하였다.</p>
<p><img src="https://images.velog.io/images/printver_2world/post/4a940164-38cc-41f4-86c7-16cabbeec32d/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring | 1.4 빌드하고 실행하기]]></title>
            <link>https://velog.io/@printver_2world/Spring-1.4-%EB%B9%8C%EB%93%9C%ED%95%98%EA%B3%A0-%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@printver_2world/Spring-1.4-%EB%B9%8C%EB%93%9C%ED%95%98%EA%B3%A0-%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 20 Jul 2021 06:18:32 GMT</pubDate>
            <description><![CDATA[<p>인텔리제이 IDE 내에서 실행하지 않고, 빌드해보자. 먼저 인텔리제이 내부의 서버는 닫아줘야한다. 그렇지 않으면 에러가 발생한다.</p>
<h1 id="빌드하기">빌드하기</h1>
<h2 id="1-cmd창으로-프로젝트-파일에-들어오기">1. cmd창으로 프로젝트 파일에 들어오기</h2>
<p>나의 프로젝트 파일인 <code>hello.spring</code>까지 들어오고 내부를 살펴보면
<img src="https://images.velog.io/images/printver_2world/post/73034b4c-6838-4c62-8593-57da508063de/image.png" alt=""></p>
<p>이러한 파일들이 있는데,</p>
<h2 id="2-gradlew-파일-실행하기">2. <code>gradlew</code> 파일 실행하기</h2>
<p>윈도우 기준으로, <code>./gradlew build</code> 명령어를 치면 빌드가 실행된다.</p>
<p><img src="https://images.velog.io/images/printver_2world/post/0ae7b7f5-61ab-4a97-9a60-e06b354c2e24/image.png" alt=""></p>
<blockquote>
<p>처음에는 <code>gradlew build</code>만 쳐서
<img src="https://images.velog.io/images/printver_2world/post/cd581b9e-b095-4f8b-9e87-82ef2d32adbd/image.png" alt="">
이러한 오류가 계속 났었다.</p>
</blockquote>
<br>

<h1 id="실행하기">실행하기</h1>
<h2 id="1-build-폴더에-들어가기">1. build 폴더에 들어가기</h2>
<p>build가 잘 되면 build 폴더가 생긴다.
<img src="https://images.velog.io/images/printver_2world/post/4a8721e1-cb3c-4578-a0f8-81bf544b0e48/image.png" alt=""></p>
<p><code>cd build</code> 를 통해 build 폴더에 들어간다.</p>
<h2 id="2-libs-폴더에-들어가기">2. libs 폴더에 들어가기</h2>
<p>build 폴더 내부를 살펴보면, libs 폴더가 있다.
<img src="https://images.velog.io/images/printver_2world/post/cd9f4fbc-0994-4853-9b9e-207e07733cca/image.png" alt=""></p>
<p><code>cd libs</code>를 통해 libs 폴더에 들어간다.</p>
<h2 id="3-jar파일-실행하기">3. jar파일 실행하기</h2>
<p>libs 폴더 내부를 살펴보자.
build가 잘 되었다면
<img src="https://images.velog.io/images/printver_2world/post/f49d86d6-5496-4003-ab3a-022bf5ecc7a5/image.png" alt="">
18M짜리 파일인 hello.spring-0.0.1-SNAPSHOT.jar 파일이 있어야 된다.
jar 파일을 실행시켜보자.
<code>java -jar hello.spring-0.0.1-SNAPSHOT.jar</code> 
<img src="https://images.velog.io/images/printver_2world/post/7f23e0f8-2ac0-411b-a862-40a66da9e4f0/image.png" alt=""></p>
<p>서버 배포할 때는 jar파일만 복사해서 서버에 넣어주고 <code>java - jar~~~</code> 코드를 실행시키면 된다. 그렇다면 서버에서 spring이 실행된다.</p>
<blockquote>
<p>잘 되지 않으면
<code>./gradlw clean build</code>를 해보자.
<code>./gradlw clean</code>이 build폴더를 완전히 삭제된다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring | 1.1 프로젝트 생성]]></title>
            <link>https://velog.io/@printver_2world/Spring-0.-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%83%9D%EC%84%B1</link>
            <guid>https://velog.io/@printver_2world/Spring-0.-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%83%9D%EC%84%B1</guid>
            <pubDate>Tue, 13 Jul 2021 09:29:50 GMT</pubDate>
            <description><![CDATA[<h1 id="스프링-프로젝트-생성하기">스프링 프로젝트 생성하기</h1>
<p><a href="https://start.spring.io/">스프링 프로젝트 만들기</a></p>
<p><img src="https://images.velog.io/images/printver_2world/post/8f23e622-7fbf-42ab-8722-3bb60d6e453f/image.png" alt=""></p>
<p>자바는 11을 사용하였다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[django | 16. 부트스트랩 이용하여 화면 꾸미기]]></title>
            <link>https://velog.io/@printver_2world/django-16.-%EB%B6%80%ED%8A%B8%EC%8A%A4%ED%8A%B8%EB%9E%A9%EC%9C%BC%EB%A1%9C-%EC%98%88%EC%81%98%EA%B2%8C-%EA%BE%B8%EB%AF%B8%EA%B8%B0</link>
            <guid>https://velog.io/@printver_2world/django-16.-%EB%B6%80%ED%8A%B8%EC%8A%A4%ED%8A%B8%EB%9E%A9%EC%9C%BC%EB%A1%9C-%EC%98%88%EC%81%98%EA%B2%8C-%EA%BE%B8%EB%AF%B8%EA%B8%B0</guid>
            <pubDate>Tue, 13 Jul 2021 08:23:13 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-html">&lt;!-- question_list.html --&gt;

{% extends &#39;base.html&#39; %}
{% block content %}

&lt;div class=&quot;container my-3&quot;&gt;
  &lt;h1 class=&quot;border-bottom py-2&quot;&gt;질문 리스트 보기&lt;/h1&gt;
  &lt;table class=&quot;table&quot;&gt;
    &lt;thead&gt;
      &lt;tr class=&quot;thead-dark&quot;&gt;
        &lt;th&gt;번호&lt;/th&gt;
        &lt;th&gt;제목&lt;/th&gt;
        &lt;th&gt;작성일시&lt;/th&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      {% if questions_list %}
      {% for question in questions_list %}
      &lt;tr&gt;
        &lt;td&gt;{{ forloop.counter }}&lt;/td&gt;
        &lt;td&gt;
          &lt;a href=&quot;{% url &#39;home:question_detail&#39; question.id %}&quot;&gt;{{ question.subject }}&lt;/a&gt;
        &lt;/td&gt;
        &lt;td&gt;{{ question.create_date }}&lt;/td&gt;
      &lt;/tr&gt;
      {% endfor %}
      {% else %}
      &lt;tr&gt;
        &lt;td colspan=&quot;3&quot;&gt;질문이 없습니다.&lt;/td&gt;
      &lt;/tr&gt;
      {% endif %}
    &lt;/tbody&gt;
  &lt;/table&gt;
  &lt;a href=&quot;{% url &#39;home:question_create&#39; %}&quot;&gt;질문 등록하기&lt;/a&gt;
&lt;/div&gt;


{% endblock %}</code></pre>
<pre><code class="language-html">&lt;!-- question_detail.html --&gt;

{% extends &#39;base.html&#39; %}
{% block content %}

&lt;div class=&quot;container my-3&quot;&gt;
  &lt;h1 class=&quot;border-bottom py-2&quot;&gt;{{ a_question.subject }}&lt;/h1&gt;
  &lt;div class=&quot;card my-3&quot;&gt;
    &lt;div class=&quot;card-body&quot;&gt;
      &lt;div class=&quot;card-text&quot; style=&quot;white-space: pre-line&quot;&gt;
        {{ a_question.content }}
      &lt;/div&gt;
      &lt;div class=&quot;d-flex justify-content-end&quot;&gt;
        &lt;div class=&quot; badge-light py-2&quot;&gt;
          {{ a_question.create_date }}
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;div class=&quot;border-bottom my-3 py-2&quot;&gt;
    {{ a_question.answer_set.count }}개의 답변이 있습니다.
    {% for answer in a_question.answer_set.all %}
    &lt;div class=&quot;card my-3&quot;&gt;
      &lt;div class=&quot;card-body&quot;&gt;
        &lt;div class=&quot;card-text&quot; style=&quot;white-space: pre-line;&quot;&gt;{{ answer.content }}&lt;/div&gt;
        &lt;div class=&quot;d-flex justify-content-end&quot;&gt;
          &lt;div class=&quot;badge-light p-2&quot;&gt;
            {{ answer.create_date }}
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    {% endfor %}
    &lt;form action=&quot;{% url &#39;home:answer_create&#39; a_question.id %}&quot; method=&quot;post&quot; class=&quot;my-3&quot;&gt;
      {% csrf_token %}
      &lt;div class=&quot;form-group&quot;&gt;
        &lt;textarea name=&quot;content&quot; id=&quot;content&quot; class=&quot;form-control&quot; rows=&quot;10&quot;&gt;&lt;/textarea&gt;
      &lt;/div&gt;
      &lt;input type=&quot;submit&quot; value=&quot;답변등록&quot; class=&quot;btn btn-primary&quot;&gt;
      &lt;!-- {{ form.as_p }}대신 forms.py 사용 --&gt;
      &lt;!-- 오류표시 Start --&gt;
      {% if form.errors %}
      &lt;div class=&quot;alert alert-danger&quot; role=&quot;alert&quot;&gt;
        {% for field in form %}
        {% if field.errors %}
        &lt;strong&gt;{{ field.label }}&lt;/strong&gt;
        {{ field.errors }}
        {% endif %}
        {% endfor %}
      &lt;/div&gt;
      {% endif %}
      &lt;!-- 오류표시 End --&gt;
    &lt;/form&gt;
  &lt;/div&gt;
&lt;/div&gt;


{% endblock %}</code></pre>
<p><img src="https://images.velog.io/images/printver_2world/post/9ee5cf1e-28f5-4497-b537-ab0856e16ce1/image.png" alt=""></p>
<p><img src="https://images.velog.io/images/printver_2world/post/3cb6e595-de85-4606-820a-1b1b9f96d94b/image.png" alt=""></p>
<p><img src="https://images.velog.io/images/printver_2world/post/9cbc7e3d-60c2-46e9-922e-1f405846b97d/image.png" alt=""></p>
]]></description>
        </item>
    </channel>
</rss>