<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>bang-wol.log</title>
        <link>https://velog.io/</link>
        <description>방울방울</description>
        <lastBuildDate>Fri, 21 Jun 2024 08:41:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>bang-wol.log</title>
            <url>https://velog.velcdn.com/images/bang-wol/profile/900f5d9b-d679-4be8-9648-92a640788f96/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. bang-wol.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/bang-wol" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[프로그래머스 데브코스] TIL - 11주차 Day3]]></title>
            <link>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-11%EC%A3%BC%EC%B0%A8-Day3</link>
            <guid>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-11%EC%A3%BC%EC%B0%A8-Day3</guid>
            <pubDate>Fri, 21 Jun 2024 08:41:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[[MySQL] 데이터 삭제하는 방법]]></title>
            <link>https://velog.io/@bang-wol/MySQL-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%82%AD%EC%A0%9C%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@bang-wol/MySQL-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%82%AD%EC%A0%9C%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Sun, 02 Jun 2024 14:45:54 GMT</pubDate>
            <description><![CDATA[<h2 id="mysql-데이터-삭제하는-방법">MySQL 데이터 삭제하는 방법</h2>
<h3 id="1-delete"><strong>1) DELETE</strong></h3>
<p>DELETE FROM 테이블명 (WHERE 조건);</p>
<p>: 조건이 있으면 조건에 맞는 행만 삭제됨</p>
<p>: 조건이 없으면 모든 행이 삭제됨</p>
<p>(테이블은 남아있음)</p>
<h3 id="2-drop"><strong>2) DROP</strong></h3>
<p>DROP TABLE 테이블명;</p>
<p>: 테이블을 통째로 삭제하는 것</p>
<p>주의해서 사용해야 함</p>
<h3 id="3-truncate"><strong>3) TRUNCATE</strong></h3>
<p>TRUNCATE 테이블명;</p>
<p>: 모든 행이 삭제됨</p>
<p>(테이블은 남아있음)</p>
<p>DELETE는 AI 남아있음 → TRUNCATE 사용하면 깔끔하게 AI 초기화 됨</p>
<p>PRIMARY키, FOREIGN 키 설정은 그대로!</p>
<h3 id="오류-발생">오류 발생</h3>
<p>참조되는 orderedBook 데이터 삭제하기 위해 truncate해줬지만 오류가 발생함</p>
<p><strong>🚨 Error Code: 1701. Cannot truncate a table referenced in a foreign key constraint</strong> (<code>Bookshop</code>.<code>orderedBook</code>, CONSTRAINT <code>fk_orderedBook_orders_id</code> FOREIGN KEY (<code>order_id</code>) REFERENCES <code>Bookshop</code>.<code>orders</code> (<code>id</code>))</p>
<pre><code class="language-sql">SET FOREIGN_KEY_CHECKS=0; // false
SET FOREIGN_KEY_CHECKS=1; // true</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Node.js 비동기]]></title>
            <link>https://velog.io/@bang-wol/Node.js-%EB%B9%84%EB%8F%99%EA%B8%B0</link>
            <guid>https://velog.io/@bang-wol/Node.js-%EB%B9%84%EB%8F%99%EA%B8%B0</guid>
            <pubDate>Sun, 02 Jun 2024 14:27:20 GMT</pubDate>
            <description><![CDATA[<h2 id="nodejs-비동기">Node.js 비동기</h2>
<p>Node.js 비동기 처리 방식</p>
<ul>
<li><strong>비동기 발생</strong></li>
</ul>
<p>실행되는 코드가 기다려야 하는 시간이 생긴다는 의미</p>
<p>ex. setTimeOut(), Ajax, setInterval(), <strong>query()</strong></p>
<p>→ sql 실행하면 db 프로그램 실행하러 가기 때문에 node.js는 기다려주지 않고 다음 코드를 실행한다.</p>
<ul>
<li><strong>비동기 처리</strong></li>
</ul>
<p>비동기가 필요 없을 때가 있다. . 지금!</p>
<p>이전 코드들의 시간을 다 기다려준다. 순서를 맞춰서 코드를 실행해준다.</p>
<ol>
<li>콜백 함수: 할 일 다 하고, 이거 실행해줘(= 순서 맞춰서 이걸 뒤에 실행해달라고)</li>
<li>promise (resolve, reject)</li>
<li>then &amp; catch</li>
<li><strong>async &amp; await</strong></li>
</ol>
<p><strong>Promise</strong> “객체” : 약속을 지키는 친구</p>
<pre><code class="language-jsx">let promise = new Promise(function(resolve, reject) {
    setTimeout(()=&gt; resolve(&#39;완료&#39;), 3000);
});</code></pre>
<pre><code class="language-jsx">promise.then(
    function(result){
    console.log(result)
    }, 
    function(error){
    }
);</code></pre>
<pre><code class="language-jsx">let promise = new Promise(function(resolve, reject) {
    setTimeout(()=&gt; resolve(&#39;완료&#39;), 3000);
}).then(
    function(result){
        console.log(result);
        return result+&quot;!!!!!&quot;;
    },
    function(error){}
).then(
    function(result){
        console.log(result);
        return result+&quot;!!!!!&quot;;
    },
    function(error){}
).then(
    function(result){
        console.log(result);
        return result+&quot;!!!!!&quot;;
    },
    function(error){}
)
;</code></pre>
<p>promise는 매개변수로 함수를 받음</p>
<p>excutor? 지킬 약속(할 일)</p>
<p>성공적으로 하면 resolve(결과), 실패하면 reject(에러)</p>
<p>일을 다 하면 무조건 콜백함수 resolve 또는 reject 둘 중 하나는 호출</p>
<p>then()은 기본 메소드, promise가 일 다 하고 호출해야하는 함수</p>
<p>chaining</p>
<p><strong>async &amp; await</strong></p>
<p>promise 객체를 좀 더 쉽고 편하게 사용 문법</p>
<p>즉 비동기 처리가 쉽다</p>
<p>async 함수</p>
<pre><code class="language-jsx">function f(){} // 일반 함수
async function f() {} // async 함수</code></pre>
<pre><code class="language-jsx">async function f() {
    return 7; // promise 객체를 반환 중
}

async function f() {
    return Promise.resolve(7);
}

f().then(
    function(result){
     console.log(&quot;promise resolve: &quot;,result);
    },
    function(error){
     console.log(&quot;promise resolve: &quot;,error);
    }
);</code></pre>
<p>async 함수는 무조건 promise 객체를 반환</p>
<p>만약 반환값이 promise가 아니면, promise.resolve()로 감싼다.</p>
<p>await는 async 함수 안에서만 동작!</p>
<p>await이 promise 객체 .then() 이 메소드를 좀 더 쉽게 사용할 수 있는 방법</p>
<p>async의 두 번째 기능</p>
<p>Promise 객체가 일이 끝날 때까지 기다릴 수 있는 공간을 제공한다.</p>
<pre><code class="language-jsx">async function(){
    let promise = new Promise(function(resolve, reject) {
    setTimeout(()=&gt; resolve(&quot;완료&quot;), 3000);
});

    let result=await promise;
    console.log(result);
}

f();</code></pre>
<p>async 함수 안에서 promise 객체 기다림 </p>
<pre><code class="language-jsx">async function(){
    let promise1 = new Promise(function(resolve, reject) {
    setTimeout(()=&gt; resolve(&quot;첫번째 쿼리&quot;), 3000);
});

    let result1 = await promise1;
    console.log(result1);

        let promise2 = new Promise(function(resolve, reject) {
    setTimeout(()=&gt; resolve(&quot;두번째 쿼리 with&quot;+result1), 3000);
});

    let result2 = await promise2;
    console.log(result2);

    let promise2 = new Promise(function(resolve, reject) {
    setTimeout(()=&gt; resolve(&quot;세번째 쿼리 with&quot;+result2), 3000);
});
    let result3 = await promise3;
    console.log(result3);
}

f();</code></pre>
<pre><code class="language-jsx">
const orderItems=(req,res)=&gt;{
    const { items, delivery, totalQuantity, totalPrice, userId, firstBookTitle} = req.body;

    let delivery_id;
    let order_id;

    let sql=`INSERT INTO delivery(address, receiver, contact) VALUES(?,?,?)`
    let values=[delivery.address, delivery.receiver, delivery.contact];

    conn.query(sql, values,
        (err,results)=&gt;{
            if(err){
                console.log(err)
                return res.status(StatusCodes.BAD_REQUEST).end();
            }
            delivery_id=results.insertId;
            console.log(&quot;results.insertId&quot;,results.insertId)
            console.log(&quot;conn.query - delivery_id&quot;,delivery_id)
        }
    )

    console.log(&quot;out - delivery_id&quot;,delivery_id);

    sql = `INSERT INTO orders (book_title, total_quantity, total_price, user_id, delivery_id)
            VALUES(?, ?, ?, ?, ?)`;
    values = [firstBookTitle, totalQuantity, totalPrice, userId, delivery_id]
        conn.query(sql, values,
        (err,results)=&gt;{
            if(err){
                console.log(err)
                return res.status(StatusCodes.BAD_REQUEST).end();
            }
            order_id=results.insertId;
        }
    )
    sql=`INSERT INTO orderedBook (order_id, book_id, quantity) VALUES ?`
    values=[];
    items.forEach((item)=&gt;{
        values.push([order_id, item.book_id, item.quantity])
        }
    )
    conn.query(sql, [values],
        (err,results)=&gt;{
            if(err){
                console.log(err)
                return res.status(StatusCodes.BAD_REQUEST).end();
            }
            return res.status(StatusCodes.OK).json(results);
        }
    )
}</code></pre>
<pre><code class="language-jsx">const mariadb = require(&#39;mysql2/promise&#39;)

const connection = async () =&gt; {
    const conn = await mariadb.createConnection({
        host: &#39;localhost&#39;,
        user: &#39;root&#39;,
        password: &#39;root&#39;,
        database: &#39;Bookshop&#39;,
        dateStrings: true
    });

    return conn;
}

module.exports=connection;
</code></pre>
<p><a href="https://sidorares.github.io/node-mysql2/docs/documentation/promise-wrapper">Promise Wrappers | Quickstart</a></p>
<p>쿼리 순서대로 실행시키기</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MySQL] LAST_INSERT_ID(), MAX()]]></title>
            <link>https://velog.io/@bang-wol/MySQL-LASTINSERTID-MAX</link>
            <guid>https://velog.io/@bang-wol/MySQL-LASTINSERTID-MAX</guid>
            <pubDate>Fri, 31 May 2024 08:18:23 GMT</pubDate>
            <description><![CDATA[<p>주문 DB를 생성하는 과정에서 주문 시스템에서 새로운 데이터를 생성한 직후 그 데이터를 참조해야 할 때가 있었다. 방금 삽입된 데이터를 가져오는 작업이 필요할 때 MySQL에서 주로 사용되는 두 가지 방법이 있다. 각각의 방법에 대해 알아보자.</p>
<h2 id="1-last_insert_id-함수">1. LAST_INSERT_ID() 함수</h2>
<p>LAST_INSERT_ID() 함수는 가장 최근에 AUTO_INCREMENT 컬럼에 삽입된 값을 반환한다. 이 함수의 가장 큰 장점은 멀티 유저 환경에서도 안정적으로 마지막으로 삽입된 행의 ID를 가져올 수 있다는 것이다. 즉, 여러 사용자가 동시에 데이터를 삽입하더라도 각 사용자는 자신이 삽입한 데이터의 ID를 정확히 가져올 수 있다.</p>
<pre><code class="language-sql">INSERT INTO orders (title, quantity) VALUES (&#39;어린왕자&#39;, 1);
SELECT LAST_INSERT_ID();
</code></pre>
<h3 id="장점">장점</h3>
<ul>
<li>멀티 유저 환경에서도 안전하게 사용할 수 있다.</li>
<li>세션별로 마지막 삽입 ID를 유지하기 때문에 다른 세션의 작업에 영향을 받지 않는다.</li>
</ul>
<h3 id="단점">단점</h3>
<ul>
<li><strong>시간차 공격</strong>으로 인해 오류가 간혹 발생할 수 있다. 매우 드문 경우지만, 네트워크 지연 등의 이유로 예상치 못한 값이 반환될 수 있음</li>
</ul>
<h2 id="2-max-함수">2. MAX() 함수</h2>
<p>MAX() 함수를 사용하여 특정 컬럼의 최대값을 찾는 방법도 있다. 이 방식은 특히 AUTO_INCREMENT 속성이 없는 컬럼에서 마지막으로 삽입된 값을 찾고자 할 때 유용하다.</p>
<pre><code class="language-sql">SELECT MAX(order_id) FROM orders;</code></pre>
<h3 id="장점-1">장점</h3>
<ul>
<li>AUTO_INCREMENT 속성이 없는 컬럼에서도 사용할 수 있다.</li>
</ul>
<h3 id="단점-1">단점</h3>
<ul>
<li>멀티 유저 환경에서는 안정적이지 않을 수 있다. 동시에 여러 사용자가 데이터를 삽입하면, 어떤 사용자의 데이터가 마지막인지 구분하기 어려울 수 있다.</li>
<li>성능 문제가 발생할 수 있다. 대용량 데이터가 있는 테이블에서는 MAX() 함수의 처리 시간이 길어질 수 있다.</li>
</ul>
<p>작업의 특성과 환경에 따라 적절한 방법을 선택하는 것이 중요하다. 일반적으로 LAST_INSERT_ID() 함수의 사용이 더 안정적이고 추천되는 방법이라고 한다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MySQL] "Duplicate key" 오류 해결]]></title>
            <link>https://velog.io/@bang-wol/MySQL-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0</link>
            <guid>https://velog.io/@bang-wol/MySQL-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0</guid>
            <pubDate>Thu, 30 May 2024 14:32:32 GMT</pubDate>
            <description><![CDATA[<p>MySQL에서 테이블을 생성하고 외래키(Foreign Key)제약 조건을 설정하다 오류를 만나게 되었다. 발생 원인과 해결 방법에 대해 알아보자.</p>
<h3 id="🚨-error-121-duplicate-key-on-write-or-update">🚨 ERROR: 121 Duplicate key on write or update</h3>
<p>외래키 제약 조건을 생성할 때, 데이터베이스 내에 동일한 이름의 제약 조건이 존재하여 오류가 발생했다. cartItems 테이블의 user_id 컬럼이 users 테이블의 id 컬럼을 참조하는 외래키 제약 조건을 생성하려고 할 때, 이미 같은 이름을 가진 제약 조건이 있다면 이 오류가 발생한다.</p>
<p><img src="https://velog.velcdn.com/images/bang-wol/post/96536e95-34db-450d-ba10-1ec7d593d0c3/image.png" alt=""></p>
<p>외래키 제약 조건 이름을 지을 때 중복을 피하기 위해 규칙을 설정할 수 있다.</p>
<pre><code>fk_기준이 되는 테이블 명_참조키가 있는 테이블 명_참조키</code></pre><p>예를 들어 cartItems 테이블의 user_id가 users 테이블의 id를 참조한다면, 이 외래키 제약 조건의 이름은 fk_cartItems_users_id로 지을 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/bang-wol/post/7c4488c6-1805-42a5-8c5e-2d657226b39d/image.png" alt=""></p>
<p>이름을 바꿔주니 오류가 사라졌다. 규칙대로 이름을 지어준다면 이름이 중복되진 않을 것 같다!</p>
<h3 id="🚨-error-1061-duplicate-key-name-book_id_idx">🚨 ERROR 1061: Duplicate key name &#39;book_id_idx’</h3>
<p>제약 조건 이름을 바꿔주고나니 이번엔 인덱스에서 중복이 발생했다. 제약 조건은 이름을 바꿔주었지만 인덱스 값은 아래와 같이 변경이 되지 않고 그대로 적용이 되어 오류가 났다.
<img src="https://velog.velcdn.com/images/bang-wol/post/a883a730-b615-435a-a93b-82b347bd98b8/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/bang-wol/post/aeaf2d85-53b5-4ede-90a9-2ec29aa66b66/image.png" alt=""></p>
<p>인덱스도 마찬가지로 규칙에 맞춰 fk_cartItems_users_id_idx 이런 식으로 변경해주니 오류가 해결됐다.</p>
<p>Duplicate key 오류는 처음부터 이름을 신중하게 지어주는 것만으로도 충분히 예방할 수 있을 것이다. 외래키 제약 조건이나 인덱스를 생성할 때, 이미 존재하는 이름을 피하기 위한 명명 규칙을 세워두는 것이 좋을 것이다. 나중에 오류 해결하느라 시간을 다 잡하먹는 것보단 미연에 방지하는 것이 좋겠지!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스 데브코스] TIL - 7주차 Day1]]></title>
            <link>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-7%EC%A3%BC%EC%B0%A8-Day1-qkhpi9ow</link>
            <guid>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-7%EC%A3%BC%EC%B0%A8-Day1-qkhpi9ow</guid>
            <pubDate>Mon, 20 May 2024 09:02:40 GMT</pubDate>
            <description><![CDATA[<h2 id="api-설계">API 설계</h2>
<p>API 설계에서 중요한 점은 각 엔드포인트가 명확하게 정의되고, 각 기능에 필요한 데이터가 적절하게 반영되는 것이다. </p>
<h3 id="요구사항-분석-및-리소스-식별">요구사항 분석 및 리소스 식별</h3>
<ul>
<li><strong>좋아요</strong>: 사용자가 도서에 좋아요를 추가하거나 취소할 수 있어야 한다.<code>bookId</code></li>
<li><strong>장바구니</strong>: 사용자가 도서를 장바구니에 담고, 장바구니를 조회하거나 도서를 삭제할 수 있어야 한다. <code>cartItemId</code>, <code>bookId</code>, <code>count</code></li>
<li><strong>주문</strong>: 사용자가 장바구니에 담은 도서를 주문할 수 있어야 한다. <code>orderId</code>, <code>items</code>, <code>delivery</code></li>
<li><strong>결제</strong>: 사용자가 주문을 확정하고 결제할 수 있어야 한다. <code>totalPrice</code>, <code>deliveryDetails</code></li>
</ul>
<h3 id="엔드포인트-설계">엔드포인트 설계</h3>
<p><strong>좋아요 API</strong></p>
<ol>
<li><p>좋아요 추가</p>
<ul>
<li>Method: PUT</li>
<li>URI: /likes/(bookId)</li>
<li>설명: 특정 도서에 대해 좋아요를 추가</li>
</ul>
</li>
<li><p>좋아요 취소</p>
<ul>
<li>Method: DELETE</li>
<li>URI: /likes/(bookId)</li>
<li>설명: 특정 도서에 대해 좋아요를 취소</li>
</ul>
</li>
</ol>
<p><strong>장바구니 API</strong></p>
<ol>
<li><p>장바구니 담기
Method: POST
URI: /cart
설명: 도서를 장바구니에 추가
Request Body: { bookId: &quot;도서 id&quot;, count: &quot;수량&quot; }</p>
</li>
<li><p>장바구니 조회
Method: GET
URI: /cart
설명: 장바구니에 담긴 도서 목록을 조회</p>
</li>
<li><p>장바구니 삭제
Method: DELETE
URI: /cart/(bookId)
설명: 장바구니에서 특정 도서를 삭제</p>
</li>
</ol>
<p><strong>주문 API</strong></p>
<ol>
<li><p>주문 예상 상품 목록 조회
Method: GET
URI: /cart
설명: 선택된 장바구니 항목의 주문 예상 목록을 조회
Request Body: [cartItemId, cartItemId, …]</p>
</li>
<li><p>주문 목록(내역) 조회
Method: GET
URI: /orders
설명: 사용자의 주문 내역을 조회</p>
</li>
<li><p>주문 상세 상품 조회
Method: GET
URI: /orders/{orderId}
설명: 특정 주문의 상세 내역을 조회</p>
</li>
</ol>
<h3 id="데이터-모델링">데이터 모델링</h3>
<ul>
<li>중복을 최소화하고, 관계형 데이터베이스의 장점을 살리기 위해 테이블 간의 관계를 정의한다. 이는 데이터 무결성을 유지하고, 효율적인 데이터 관리를 가능하게 한다.</li>
</ul>
<p><strong>Books (도서 정보 저장)</strong></p>
<pre><code class="language-sql">CREATE TABLE books (
    book_id SERIAL PRIMARY KEY,
    title VARCHAR(255),
    summary TEXT,
    author VARCHAR(255),
    price DECIMAL(10, 2)
);</code></pre>
<p><strong>Likes (사용자가 좋아요 표시한 도서 정보 저장)</strong></p>
<pre><code class="language-sql">CREATE TABLE likes (
    like_id SERIAL PRIMARY KEY,
    user_id INTEGER,
    book_id INTEGER REFERENCES books(book_id),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);</code></pre>
<p><strong>Carts (사용자 장바구니 정보 저장)</strong></p>
<pre><code class="language-sql">CREATE TABLE carts (
    cart_id SERIAL PRIMARY KEY,
    user_id INTEGER,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);</code></pre>
<p><strong>CartItems (장바구니에 담긴 각 도서 정보 저장)</strong></p>
<pre><code class="language-sql">CREATE TABLE cart_items (
    cart_item_id SERIAL PRIMARY KEY,
    cart_id INTEGER REFERENCES carts(cart_id),
    book_id INTEGER REFERENCES books(book_id),
    count INTEGER
);</code></pre>
<p><strong>Orders (주문 정보 저장)</strong></p>
<pre><code class="language-sql">CREATE TABLE orders (
    order_id SERIAL PRIMARY KEY,
    user_id INTEGER,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    address VARCHAR(255),
    receiver VARCHAR(50),
    contact VARCHAR(20),
    total_price DECIMAL(10, 2)
);</code></pre>
<p><strong>OrderItems (주문에 포함된 각 도서 정보 저장)</strong></p>
<pre><code class="language-sql">CREATE TABLE order_items (
    order_item_id SERIAL PRIMARY KEY,
    order_id INTEGER REFERENCES orders(order_id),
    book_id INTEGER REFERENCES books(book_id),
    count INTEGER,
    price DECIMAL(10, 2)
);</code></pre>
<h3 id="결제-api-추가">결제 API 추가</h3>
<p>장바구니 기능 설계하는 과정에서 결제가 필요하다는 요구사항 발생! 이를 추가해준다.</p>
<p><strong>결제하기 (주문 등록)</strong></p>
<ul>
<li>Method: POST</li>
<li>URI: /orders</li>
<li>설명: 장바구니에 담긴 도서를 주문하고 결제한다. 주문이 완료되면 해당 장바구니 항목은 삭제된다.</li>
<li>Request Body:<pre><code class="language-json">{
    &quot;items&quot;: [
        {
            &quot;cartItemId&quot;: &quot;장바구니 도서 id&quot;,
            &quot;bookId&quot;: &quot;도서 id&quot;,
            &quot;count&quot;: &quot;수량&quot;
        },
        {
            &quot;cartItemId&quot;: &quot;장바구니 도서 id&quot;,
            &quot;bookId&quot;: &quot;도서 id&quot;,
            &quot;count&quot;: &quot;수량&quot;
        }
    ],
    &quot;delivery&quot;: {
        &quot;address&quot;: &quot;주소&quot;,
        &quot;receiver&quot;: &quot;이름&quot;,
        &quot;contact&quot;: &quot;010-0000-0000&quot;
    },
    &quot;totalPrice&quot;: &quot;총 금액&quot;
}</code></pre>
</li>
</ul>
<hr>
<p>현업에서는 API 설계가 매우 중요할 것이고, 데이터베이스 스키마 역시 효율적이고 확장 가능한 설계가 중요할 것이다. 설계가 튼튼하다면 시스템의 안정성과 유지 보수성을 높일 수 있다. 이러한 설계 과정은 개발 초기 단계에 충분히 검토하고 논의해야 할 것이다. 혼자 해결할 수 있는 문제라기 보다 팀원들의 피드백도 반영하여 최대한 개선해 나가는 방향이 옳을 것이다. 현업에서는 한 달 가까이 걸쳐 정하는 부분이라는 강사님의 말씀에 충분히 그럴 수 있단 생각을 했다...</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JWT 구조 및 인증 절차]]></title>
            <link>https://velog.io/@bang-wol/JWT-%EA%B5%AC%EC%A1%B0-%EB%B0%8F-%EC%9D%B8%EC%A6%9D-%EC%A0%88%EC%B0%A8</link>
            <guid>https://velog.io/@bang-wol/JWT-%EA%B5%AC%EC%A1%B0-%EB%B0%8F-%EC%9D%B8%EC%A6%9D-%EC%A0%88%EC%B0%A8</guid>
            <pubDate>Tue, 14 May 2024 13:12:50 GMT</pubDate>
            <description><![CDATA[<p>웹 어플리케이션을 개발하다 보면, 사용자의 로그인 상태를 관리하는 것은 필수적인 요소 중 하나이다. 이를 위해 쿠키, 세션, JWT(JSON Web Token)같은 다양한 방법을 활용할 수 있다. 각각의 방법은 장단점을 가지고 있으며, 오늘은 JWT를 중심으로 개념과 활용 방법을 알아보려고 한다.</p>
<br>


<p><strong>로그인 세션에서 인증/인가의 차이</strong>
사용자가 로그인을 하면 서버는 해당 사용자의 로그인 세션을 생성하게 된다. 이 세션은 사용자가 로그인 상태를 유지할 수 있게 해주며, 세션이 만료되면 사용자는 다시 로그인을 해야한다.</p>
<h2 id="인증authentication-vs-인가authoriztion">인증(Authentication) vs 인가(Authoriztion)</h2>
<ul>
<li><strong>인증</strong>: 사용자가 누구인지 확인하는 과정이다. 예를 들어, 쇼핑몰에서 장바구니에 상품을 담거나 구매할 때 로그인이 필요하다.</li>
<li><strong>인가</strong>: 인증된 사용자가 특정 자원에 접근할 수 있는 권한을 가지고 있는지 확인하는 과정이다. 예를 들어, 관리자 페이지는 일반 사용자가 아닌 관리자만 접근할 수 있다.</li>
</ul>
<br>

<h2 id="쿠키-vs-세션">쿠키 vs 세션</h2>
<p><a href="https://songacoding.tistory.com/4">Cookie &amp; Session 개념</a></p>
<h3 id="쿠키">쿠키</h3>
<p>로그인 시 서버는 사용자에게 쿠키를 발급하고, 이후 사용자와 서버 간의 통신 시 이 쿠키를 이용해 사용자를 식별한다.(쿠키를 클라이언트와 서버가 주고받으며 사용자 인증 유지)</p>
<ul>
<li>장점: 서버의 저장 공간을 절약하고, HTTP의 Stateless 특성을 유지할 수 있다.</li>
<li>단점: 보안에 취약하다.</li>
</ul>
<h3 id="세션">세션</h3>
<p>로그인 시 서버가 정보를 저장하고, 그에 대한 식별 번호를 클라이언트에게 전달한다.</p>
<ul>
<li>장점: 보안성이 비교적 좋다.</li>
<li>단점: 서버의 저장 공간을 사용하며, HTTP의 Stateless 특성을 유지하지 못한다.</li>
</ul>
<h2 id="jwtjson-web-token">JWT(JSON Web Token)</h2>
<p><img src="https://velog.velcdn.com/images/bang-wol/post/5bbf054b-48b7-4229-81fa-621fe68c12ee/image.png" alt=""></p>
<p><a href="https://jwt.io/">jwt.io</a></p>
<p>웹 표준으로, 두 개체 사이에서 JSON 객체를 사용하여 가볍고 자가수용적인(self-contained) 방식으로 정보를 안전하게 전송하기 위해 설계되었다. 주로 사용자 인증 및 정보 교환에 사용된다. </p>
<p>cf. 자가수용적(self-contained) - 그 자체로 필요한 모든 정보를 포함하고 있다는 의미로, 토큰을 검증하고 사용자를 인증하는 데 필요한 정보가 토큰 안에 이미 포함되어 있어 별도의 정보 조회 과정 없이도 토큰만으로 사용자 인증 및 권한 부여 동의 처리가 가능하다는 것을 의미.</p>
<h3 id="jwt-구조">JWT 구조</h3>
<p>구조는 세 부분으로 나누어진다. 헤더(Header), 페이로드(Payload), 시그니처(Signature).</p>
<ol>
<li>헤더(Header)
헤더는 토큰의 타입(주로 JWT)과 사용된 해싱 알고리즘(예: HMAC SHA256 또는 RSA)을 포함하는 두 부분으로 구성된다. 이는 JSON 형식으로 인코딩되며, 이후 Base64Url로 인코딩되어 JWT의 첫 번째 부분을 형성한다.<pre><code class="language-jsx">{
&quot;alg&quot;: &quot;HS256&quot;,
&quot;typ&quot;: &quot;JWT&quot;
}</code></pre>
</li>
<li>페이로드(Payload)
페이로드는 토큰에 포함될 클레임(claim)을 담고 있다. 클레임은 엔티티(주로 사용자 정보)와 추가 데이터에 대한 내용이다. 페이로드도 JSON 형식으로 인코딩되며 Base64Url로 인코딩되어 JWT의 두 번째 부분을 형성한다.<pre><code class="language-jsx">{
&quot;sub&quot;: &quot;1234567890&quot;,
&quot;name&quot;: &quot;John Doe&quot;,
&quot;admin&quot;: true
}
</code></pre>
</li>
</ol>
<pre><code>
3. 시그니처(Signature)
시그니처는 토큰의 무결성과 정보의 검증을 보장하기 위해 생성된다. 헤더의 인코딩된 문자열, 페이로드의 인코딩된 문자열, 그리고 비밀키를 사용하여 헤더에서 지정한 알고리즘으로 해싱된 후 생성된다. 이 시그니처는 Base64Url로 인코딩되어 JWT의 세 번째 부분을 형성한다.


JWT는 이 세 부분을 점(.)을 사용하여 연결하여 하나의 문자열로 만든다. JWT를 사용하면 사용자 인증 정보를 안전하게 전송할 수 있고, 서버는 해당 토큰이 변조되지 않았음을 검증할 수 있다. 



&lt;br&gt;


### JWT 인증/인가 절차
1. **클라이언트**는 로그인 요청을 한다.
2. **서버**는 로그인이 성공하면 JWT를 발급한다.
3. **클라이언트**는 이후 요청 시 JWT를 Header에 포함시켜 서버에 전송한다. 
4. **서버**는 JWT의 서명을 확인하고, 요청에 대한 응답을 한다. (서명이 일치하지 않는 경우, 403 권한 없음 오류를 반환한다.)


### JWT 구현
Node.js 환경에서 [jsonwebtoken](https://www.npmjs.com/package/jsonwebtoken)과 [dotenv](https://www.npmjs.com/package/dotenv) 패키지를 활용하여 JWT 기반 인증 시스템을 구축할 수 있다. 
1. `npm install jsonwebtoken dotenv`로 필요한 패키지 설치
2. `.env` 파일에 환경변수(예: PRIVATE_KEY)를 설정하여 외부에 노출되면 안 되는 값 관리
3. jsonwebtoken 패키지를 사용하여 JWT를 발행하고 검증하는 로직 구현

```jsx
var jwt=require(&#39;jsonwebtoken&#39;);
var dotenv=require(&#39;dotenv&#39;);

dotenv.config();

// JWT 발행
var token = jwt.sign({foo:&#39;bar&#39;}, process.env.PRIVATE_KEY);
console.log(token);

// JWT 검증
var decoded = jwt.verify(token, process.env.PRIVATE_KEY);
console.log(decoded.foo); // &#39;bar&#39;
</code></pre><p><strong>환경 변수 파일(.env)</strong>
환경 변수 파일은 중요한 설정 값들을 외부에 유출되지 않도록 관리하기 위한 파일이다. 예를 들어, 데이터베이스 계정 정보, 비밀키 등이 이에 해당한다. </p>
<hr>
<p>🔑</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스 데브코스] TIL - 6주차 DAY1]]></title>
            <link>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-6%EC%A3%BC%EC%B0%A8-DAY1</link>
            <guid>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-6%EC%A3%BC%EC%B0%A8-DAY1</guid>
            <pubDate>Mon, 13 May 2024 08:05:09 GMT</pubDate>
            <description><![CDATA[<h2 id="express에서의-유효성-검사---express-validator-활용하기">Express에서의 유효성 검사 - express-validator 활용하기</h2>
<p>웹 애플리케이션 개발 시 사용자로부터 입력받은 데이터의 유효성을 검사하는 것은 매우 중요하다. Node.js의 Express 프레임워크에서는 <code>express-validator</code> 모듈을 통해 간편하게 입력 데이터의 유효성 검사를 수행할 수 있다. 이 글에서는 <code>express-validator</code>의 기본 사용법과 실제 프로젝트에서 유효성 검사 로직을 모듈화하는 방법에 대해 알아보자.</p>
<h3 id="express-validator-설치-및-기본-사용법">express-validator 설치 및 기본 사용법</h3>
<p>먼저 <code>express-validator</code>를 프로젝트에 설치한다.</p>
<pre><code class="language-bash">npm install express-validator</code></pre>
<p>설치가 완료되면, 다음과 같이 <code>express-validator</code>의 검사 함수들을 이용하여 유효성 검사를 수행할 수 있다.</p>
<pre><code class="language-jsx">const express = require(&#39;express&#39;);
const { body, validationResult } = require(&#39;express-validator&#39;);
const app = express();

app.use(express.json());

app.post(&#39;/user&#39;, [
  body(&#39;userId&#39;).notEmpty().isInt().withMessage(&#39;userId는 숫자여야 합니다.&#39;),
  body(&#39;name&#39;).isString().isLength({ min: 2 }).withMessage(&#39;이름은 2글자 이상의 문자열이어야 합니다.&#39;)
], (req, res) =&gt; {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    return res.status(400).json({ errors: errors.array() });
  }
  // 데이터 처리 로직
});

app.listen(3000);</code></pre>
<p>위 예제에서는 POST 요청으로 전달된 <code>userId</code>와 <code>name</code> 필드에 대한 유효성 검사를 수행한다. <code>userId</code>는 비어 있지 않고 숫자여야 하며, <code>name</code>은 문자열이고 최소 2글자 이상이어야 한다. 유효성 검사에 실패한 경우, 400 상태 코드와 함께 에러 메시지를 응답한다.</p>
<h3 id="유효성-검사-미들웨어-분리">유효성 검사 미들웨어 분리</h3>
<p>유효성 검사 코드는 여러 라우트에서 중복될 수 있으므로, 반복을 피하기 위해 별도의 미들웨어로 분리하는 것이 좋다. 이를 위해 먼저 유효성 검사 결과를 확인하고 처리하는 로직을 함수로 만든다.</p>
<pre><code class="language-jsx">const { validationResult } = require(&#39;express-validator&#39;);

const validate = (req, res, next) =&gt; {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    return res.status(400).json({ errors: errors.array() });
  }
  next();
};</code></pre>
<p>이제 <code>validate</code> 함수를 미들웨어로서 사용하여 유효성 검사 로직을 재사용할 수 있다.</p>
<pre><code class="language-jsx">const express = require(&#39;express&#39;);
const { body } = require(&#39;express-validator&#39;);
const app = express();
app.use(express.json());

app.post(&#39;/user&#39;, [
  body(&#39;userId&#39;).notEmpty().isInt(),
  body(&#39;name&#39;).isString().isLength({ min: 2 }),
  validate
], (req, res) =&gt; {
  // 데이터 처리 로직
});

app.listen(3000);</code></pre>
<p>위와 같이 유효성 검사 로직을 분리함으로써, 코드의 중복을 줄이고 유지보수를 용이하게 할 수 있다.</p>
<h3 id="정리">정리</h3>
<p><code>express-validator</code>를 사용하여 Express 애플리케이션에서 입력 데이터의 유효성을 쉽게 검사할 수 있다. 유효성 검사 로직을 미들웨어로 분리함으로써 코드의 재사용성을 높이고, 프로젝트의 구조를 개선할 수 있다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스 데브코스] TIL - 5주차 DAY4]]></title>
            <link>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-5%EC%A3%BC%EC%B0%A8-DAY4</link>
            <guid>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-5%EC%A3%BC%EC%B0%A8-DAY4</guid>
            <pubDate>Sat, 11 May 2024 14:57:37 GMT</pubDate>
            <description><![CDATA[<h2 id="workbench-시작">Workbench 시작</h2>
<ul>
<li><p>MySQL Workbench를 실행한 후, 상단 메뉴에서 <strong>Database</strong> &gt; <strong>Connect to Database</strong>를 선택한다. 
<img src="https://velog.velcdn.com/images/bang-wol/post/de512cf9-6a2d-4e60-8a4e-8bc672f63c07/image.png" alt=""></p>
</li>
<li><p>연결 설정</p>
<ul>
<li><code>Connection Method</code>: Standard (TCP/IP)</li>
<li><code>Hostname</code>: 127.0.0.1 또는 localhost</li>
<li><code>Port</code>: MySQL 서버가 사용 중인 포트 (기본값은 3306)</li>
<li><code>Username</code>: 데이터베이스 사용자 이름, 예: root</li>
<li><code>Password</code>: 연결을 위한 비밀번호 (설정된 경우)</li>
</ul>
</li>
</ul>
<br>

<h3 id="테이블-생성">테이블 생성</h3>
<p>Create Table 옵션을 사용하여 새 테이블을 정의한다다. 테이블의 이름과 필요한 컬럼을 추가한다.</p>
<p><img src="https://velog.velcdn.com/images/bang-wol/post/cb1fa5f2-bddd-472c-8b8a-d66110f2a097/image.png" alt=""></p>
<h2 id="nodejs와-db-연동">Node.js와 DB 연동</h2>
<p>Node.js 애플리케이션에서 MySQL 데이터베이스를 사용하려면 적절한 npm 패키지를 설치해야 한다. 여러 패키지들 중 <a href="https://www.npmjs.com/package/mysql2">npm: mysql2</a> 패키지가 성능이 개선되어 사용이 권장된다. </p>
<ul>
<li><p>패키지 설치
<code>npm install --save mysql2</code></p>
</li>
<li><p>데이터베이스 연결 및 쿼리 실행 예제</p>
<pre><code class="language-sql">// Get the client
const mysql = require(&#39;mysql2&#39;);

// Create the connection to database
const connection = mysql.createConnection({
  host: &#39;localhost&#39;,
  user: &#39;root&#39;,
  database: &#39;test&#39;,
  password: &#39;password&#39;
});

// A simple SELECT query
connection.query(
  &#39;SELECT * FROM `table` WHERE `name` = &quot;Page&quot; AND `age` &gt; 45&#39;,
  function (err, results, fields) {
    console.log(results); // results contains rows returned by server
    console.log(fields); // fields contains extra meta data about results, if available
  }
);</code></pre>
</li>
</ul>
<p>host, user, database, password 부분은 자신의 환경에 맞게 설정해주어야 한다.</p>
<p><img src="https://velog.velcdn.com/images/bang-wol/post/983d6c6d-4acd-4937-bdf5-18861bc183b6/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/bang-wol/post/d32fb158-fcf6-48d8-ae61-c817af534b0d/image.png" alt="">
코드 작성해서 실행해도 undefined 상태라 이유를 찾다가..
내 databse 이름이 대문자로 시작하는데, 소문자로 시작해서 그런 거였다. 이름은 대소문자 구분을 해야하나보다. 수정을 하고나니 제대로 results를 불러온다.</p>
<h3 id="timestamp-설정">timestamp 설정</h3>
<p>데이터베이스의 시간 설정을 Asia/Seoul로 변경하려면 다음 SQL 명령을 사용하면 된다. </p>
<ul>
<li><p>세션별 시간대 설정
<code>SET time_zone=&#39;Asia/Seoul&#39;;</code></p>
</li>
<li><p>글로벌 시간대 설정 (권장하지 않음)
<code>SET GLOBAL time_zone=&#39;Asia/Seoul&#39;;</code>
  글로벌 설정은 시스템 시간대 설정에 영향을 줄 수 있으므로 주의해서 사용해야 한다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/bang-wol/post/1251b91a-faba-4b0e-a29b-e0257609aa68/image.png" alt=""></p>
<p>GLOBAL 설정을 빼줬더니 시간대가 제대로 적용이 된 것을 확인할 수 있다.</p>
<p>Node.js에서 MySQL 서버의 시간대와 일치하는 시간 정보를 얻으려면, 데이터베이스 연결 설정 시 dateStrings 옵션을 true로 설정해야 한다.</p>
<pre><code class="language-jsx">const connection = mysql.createConnection({
    host: &#39;localhost&#39;,
    user: &#39;root&#39;,
    database: &#39;test&#39;,
    password: &#39;password&#39;,
    dateStrings: true
  });</code></pre>
<p>  이 설정을 통해 서버로부터 반환된 날짜 및 시간 값이 문자열 형태로 처리되어, 로컬 시간대에 영향을 받지 않는다.</p>
<hr>
<p>워크벤치를 정말 오랜만에 사용하는데 옛날 기억이 새록새록 떠올랐다. 그 때는 시간에 쫓겨 DB 연동할 때 완벽히 이해하지 못하고 구현하기 급급했는데, 이제 연동 방법도 제대로 파악하여 잘 사용할 수 있을 듯하다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스 데브코스] TIL - 5주차 DAY2]]></title>
            <link>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-5%EC%A3%BC%EC%B0%A8-DAY2</link>
            <guid>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-5%EC%A3%BC%EC%B0%A8-DAY2</guid>
            <pubDate>Tue, 07 May 2024 09:24:16 GMT</pubDate>
            <description><![CDATA[<h2 id="데이터베이스와-dbms">데이터베이스와 DBMS</h2>
<p>데이터베이스와 데이터베이스 관리 시스템(DBMS)은 <strong>데이터를 효율적으로 저장하고 관리, 검색</strong>하는데 필수적인 기술!
데이터베이스는 데이터의 집합체로, 데이터 중복을 최소화하고 데이터 관리를 최적화하기 위해 설계된다. DBMS는 이러한 <strong>데이터베이스를 쉽게 관리하고 조작하는 소프트웨어</strong>이다. 데이터의 생성, 조회, 수정, 삭제 등의 기능을 제공하며 이를 통해 데이터의 일관성과 무결성을 유지할 수 있다.</p>
<h2 id="데이터베이스-장단점">데이터베이스 장단점</h2>
<h4 id="장점">장점</h4>
<ol>
<li>중앙 집중화된 데이터 저장 - 하나의 위치에서 데이터를 관리함으로써 일관성을 유지할 수 있음</li>
<li>데이터 접근성과 재사용성 - 데이터를 효율적으로 공유하고 재사용할 수 있어 정보의 가치를 증가시킴</li>
<li>데이터 무결성 - 데이터베이스의 구조와 제약 조건이 데이터의 정확성을 보장함</li>
</ol>
<h4 id="단점">단점</h4>
<ol>
<li>복잡성 - 큰 규모의 데이터베이스는 설계와 관리가 복잡할 수 있음</li>
<li>비용 - 유지 관리와 운영에 높은 비용이 들 수 있음</li>
<li>보안 취약성 - 중앙 집중식 데이터는 해킹과 같은 보안 위협에 더 취약할 수 있음</li>
</ol>
<h2 id="dbms-장단점">DBMS 장단점</h2>
<h4 id="장점-1">장점</h4>
<ol>
<li>효율적인 데이터 관리 - 다양한 도구와 기능을 제공하여 데이터를 효과적으로 관리할 수 있음</li>
<li>동시성 지원 - 여러 사용자가 동시에 데이터베이스 작업을 수행할 수 있도록 지원함</li>
<li>데이터 보안과 무결성 유지 - 데이터 접근 권한 관리 및 무결성 규칙을 통해 데이터를 안전하게 보호함</li>
<li>백업 및 복구 - 데이터의 손실을 방지하기 위해 정기적인 백업과 복구 기능을 제공함</li>
</ol>
<h4 id="단점-1">단점</h4>
<ol>
<li>높은 비용 - 고성능 DBMS는 높은 초기 투자 및 지속적인 유지 관리 비용이 필요함</li>
<li>성능 문제 - 대용량 데이터나 복잡한 쿼리 처리 시 시스템의 성능 저하가 발생할 수 있음</li>
<li>기술적 복잡성 - 효과적인 DBMS 운영은 전문 지식을 요구하며, 복잡한 설정과 최적화가 필요함</li>
</ol>
<h2 id="주요-dbms-종류">주요 DBMS 종류</h2>
<ul>
<li>Oracle: 대규모 엔터프라이즈 환경에 적합한 기능을 제공</li>
<li>MySQL: 오픈 소스이며 가장 널리 사용되는 관계형 데이터베이스 관리 시스템 중 하나</li>
<li>MariaDB: MySQL과 호환되는 또 다른 오픈 소스 관계형 데이터베이스 시스템으로, 최적화된 기능과 보안 제공</li>
</ul>
<p>운영회사는 다르지만, 데이터베이스 연산을 위해 사용되는 주요 명령어는 같다. 따라서 요구사항과 리소스 고려해서 적절한 시스템을 선택 해야할 것이다!</p>
<h2 id="sqlstructured-query-language">SQL(Structured Query Language)</h2>
<p>관계형 데이터베이스에서 데이터를 관리하기 위한 표준 프로그래밍 언어. 주요 명령어는 다음과 같다.</p>
<p><code>INSERT</code> 데이터베이스에 새로운 데이터 삽입
<code>SELECT</code> 데이터 조회
<code>UPDATE</code> 기존 데이터 수정
<code>DELETE</code> 데이터 삭제</p>
<h2 id="rdbms란">RDBMS란?</h2>
<p><strong>관계형 데이터베이스 관리 시스템(Relational Databse Management System)</strong>의 약자로, 데이터를 테이블로 구성되는 형태로 저장한다. 이러한 테이블들은 서로 연결되어 있을 수 있고, 키를 사용하여 정의한다. 테이블은 열(column)과 행(row)으로 구성되며, 각 열은 특정 유형의 데이터를 나타내고, 각 행은 관련 데이터의 집합을 나타낸다. </p>
<h2 id="데이터베이스-정규화normalization">데이터베이스 정규화(Normalization)</h2>
<p>정규화는 데이터베이스 설계 과정에서 _데이터 중복을 최소화_하고, 무결성을 최대화하기 위해 데이터를 구조화하는 과정이다. 테이블을 더 작고, 관리하기 쉽게 여러 테이블로 분리하여 데이터베이스 효율성을 높인다.</p>
<p>정규화 과정에서의 테이블 분리는 데이터 정확성 유지되고 관리가 용이하다. 하지만 시스템 성능은 떨어질 수 있다. </p>
<h2 id="데이터베이스-키key">데이터베이스 키(Key)</h2>
<p>데이터베이스에서는 키(key)를 사용하여 데이터를 식별하고 조작한다. 각 키는 특정 목적을 가지고 설계된다. 아래는 여러 키 종류 중 가장 중요한 키 두 가지 개념이다.</p>
<ul>
<li><p><strong>Primary Key(PK)</strong>
  각 행을 고유하게 식별하는 키. 중복된 값이 없으며 NULL 값이 허용되지 않음</p>
</li>
<li><p><strong>Foreign Key(FK)</strong>
  다른 테이블의 기본 키를 참조하는 키. 외래키를 통해 두 테이블 간의 관계가 형성됨</p>
</li>
</ul>
<h2 id="데이터베이스-관계-유형">데이터베이스 관계 유형</h2>
<ul>
<li><strong>1:1</strong>
한 테이블의 행이 다른 테이블의 단 하나의 행과만 연결되는 경우</li>
<li><strong>1:N</strong>
한 테이블의 단일 행이 다른 테이블의 여러 행과 연결될 수 있음</li>
<li><strong>M:N</strong>
두 테이블 간 다수의 행이 서로 관련된 수 있는 경우</li>
</ul>
<hr>
<p>이제 데이터베이스와 DBMS의 차이점을 말하라고 하면 정확하게 설명할 수 있을 것 같다. 주요 개념들도 잊고 있었는데 강의를 들으며 함께 떠올릴 수 있었다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스 데브코스] TIL - 4주차 DAY5]]></title>
            <link>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-4%EC%A3%BC%EC%B0%A8-DAY5</link>
            <guid>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-4%EC%A3%BC%EC%B0%A8-DAY5</guid>
            <pubDate>Sun, 05 May 2024 08:31:35 GMT</pubDate>
            <description><![CDATA[<p>🏷️ 백엔드 기초 마무리! </p>
<h3 id="server와-router의-역할">Server와 Router의 역할</h3>
<ul>
<li>Server: 클라이언트로부터 HTTP 요청을 받는다. 서버는 이 요청을 처리하기 위해 필요한 리소스를 관리하고, 요청에 따른 적절한 응답을 반환한다.</li>
<li>Router: 요청을 받은 URL 및 HTTP 메소드에 따라 적절한 핸들러 함수로 요청을 전달한다. 라우터는 특정 경로(route)에 따라 처리할 로직을 정해준다. </li>
</ul>
<h3 id="nodejs에서의-라우팅이란">Node.js에서의 라우팅이란?</h3>
<p>Node.js에서 라우팅은 요청이 왔을 때 URL과 메소드에 기반하여 처리 함수(콜백 함수)를 호출하는 과정이다. 원하는 경로에 따라 적절한 방향으로 경로를 안내해주는 것이다. </p>
<pre><code class="language-jsx">const express = require(&#39;express&#39;);
const router = express.Router();

router.get(&#39;/api/path&#39;, (req, res) =&gt; {
    res.send(&#39;Response for GET request&#39;);
});

router.post(&#39;/api/path&#39;, (req, res) =&gt; {
    res.send(&#39;Response for POST request&#39;);
});</code></pre>
<h3 id="모듈화">모듈화</h3>
<p>Node.js에서는 자체적으로 개발한 서버 코드를 모듈로 만들어 다른 JavaScript 파일에서 재사용할 수 있다. <code>module.exports</code>와 <code>require()</code>를 통해 이루어진다.</p>
<pre><code class="language-jsx">// server.js
const express = require(&#39;express&#39;);
const app = express();
module.exports = app;

// index.js
const server = require(&#39;./server&#39;);
server.listen(3000);
</code></pre>
<h3 id="erdentity-relationship-diagram-설계">ERD(Entity Relationship Diagram) 설계</h3>
<p>간단하게 ERD 작성해보기</p>
<p><strong>회원</strong></p>
<table>
<thead>
<tr>
<th>user_id</th>
<th>password</th>
<th>name</th>
</tr>
</thead>
<tbody><tr>
<td>test1</td>
<td>1234</td>
<td>tester1</td>
</tr>
<tr>
<td>test2</td>
<td>5678</td>
<td>tester2</td>
</tr>
</tbody></table>
<p><strong>채널</strong></p>
<table>
<thead>
<tr>
<th>id</th>
<th>channel_title</th>
<th>user_id</th>
<th>sub_num</th>
<th>video_num</th>
<th>…</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>채널은방울방울</td>
<td>test1</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>2</td>
<td>회원은방울방울</td>
<td>test1</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>3</td>
<td>테스트는방울방울</td>
<td>test2</td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody></table>
<p>(* 데이터베이스에서 이름 지을 땐 <code>snake</code> 방식 사용)</p>
<h2 id="채널-api-설계-수정-및-예외-처리">채널 API 설계 수정 및 예외 처리</h2>
<p>ERD 그리다보니 userId가 필요하다고 생각되어 API 수정(언제든지 맞지 않다고 생각되거나, 고도화 할 생각이 있다면 설계를 뜯어고치면 된다. 겁먹지 말자!)</p>
<ul>
<li><p>채널 생성 API
요청: POST /channel
본문: { &quot;channelTitle&quot;: &quot;New Channel&quot;, &quot;userId&quot;: &quot;user1&quot; }
응답: 201 Created</p>
</li>
<li><p>회원별 채널 조회 API
요청: GET /channels/user1
응답: 200 OK, 채널 리스트 반환</p>
</li>
</ul>
<h2 id="예외-처리-고도화">예외 처리 고도화</h2>
<p>복잡한 if문을 간소화하고 함수를 통해 재사용 가능한 코드 조각을 만들어 예외 처리를 효과적으로 수행할 수 있다.</p>
<pre><code class="language-jsx">function notFoundChannel(res) {
    res.status(404).json({ message: &#39;채널을 찾을 수 없습니다.&#39; });
}

if (!channel) {
    notFoundChannel(res);
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스 데브코스] TIL - 4주차 DAY4]]></title>
            <link>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-4%EC%A3%BC%EC%B0%A8-DAY4-do0l4ffl</link>
            <guid>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-4%EC%A3%BC%EC%B0%A8-DAY4-do0l4ffl</guid>
            <pubDate>Sat, 04 May 2024 14:56:26 GMT</pubDate>
            <description><![CDATA[<h2 id="로그인-로직">로그인 로직</h2>
<h3 id="로그인-처리-과정">로그인 처리 과정</h3>
<ol>
<li>클라이언트에서 전송된 userId와 password를 받는다.</li>
<li>데이터베이스(db)를 반복적으로 검색하여 해당 userId를 가진 사용자를 찾는다.</li>
<li>사용자가 존재하면 입력된 비밀번호와 데이터베이스에 저장된 비밀번호를 비교한다.</li>
<li>응답 처리
 1) 성공 시: 비밀번호가 일치하면 200 상태 코드와 함께 환영 메시지를 반환한다.
 2) 비밀번호 불일치: 비밀번호가 일치하지 않을 경우, 400 상태 코드와 오류 메시지를 반환한다.
 3) 사용자 미존재: userId에 해당하는 사용자가 없을 경우, 404 상태 코드와 오류 메시지를 반환한다.</li>
</ol>
<pre><code class="language-jsx">router.post(&#39;/login&#39;, (req, res) =&gt; {
    const { userId, password } = req.body; // 요청에서 ID와 비밀번호 추출
    let loginUser = db.find(user =&gt; user.userId === userId); // DB에서 사용자 검색

    if (loginUser) {
        if (loginUser.password === password) {
            res.status(200).json({ message: `${loginUser.name}님 환영합니다!` });
        } else {
            res.status(400).json({ message: &#39;입력 값을 다시 확인해주세요.&#39; });
        }
    } else {
        res.status(404).json({ message: &#39;회원 정보가 없습니다.&#39; });
    }
});
</code></pre>
<p>코드를 전체적으로 올릴 수 없어 대략적으로 작성한 코드는 이렇다. </p>
<h2 id="자바스크립트-objectkeys">자바스크립트 Object.keys()</h2>
<p>Object.keys() 메소드는 객체의 모든 키를 배열로 반환한다. 이를 사용하여 객체가 비어 있는지 확인할 수 있다.</p>
<pre><code class="language-jsx">const obj1 = {};
const obj2 = { message: &#39;들어있음&#39; };

console.log(Object.keys(obj1)); // 출력: []
console.log(Object.keys(obj2)); // 출력: [&#39;message&#39;]
console.log(Object.keys(obj2).length === 0); // 출력: false
</code></pre>
<p>이 메소드는 로그인 과정에서 객체가 비어 있는지 아닌지를 확인하는 데 유용하게 사용된다.</p>
<pre><code class="language-jsx">function isExisted(obj) {
    return Object.keys(obj).length &gt; 0;
}</code></pre>
<p>이 함수는 객체에 키가 하나라도 존재하면 true를 반환하고, 그렇지 않으면 false를 반환한다. 로그인 로직에서는 이 함수를 사용하여 loginUser 객체가 비어 있는지 확인한다.</p>
<h3 id="채널-api-설계">채널 API 설계</h3>
<h4 id="1-채널-생성">1. 채널 생성</h4>
<ul>
<li><strong>Method</strong>: POST</li>
<li><strong>URL</strong>: /channels</li>
<li><strong>req</strong>: { &quot;channelTitle&quot;: &quot;채널명&quot; }</li>
<li><strong>res</strong>: { &quot;message&quot;: ${channelTitle}님 채널을 응원합니다.}</li>
</ul>
<h4 id="2-채널-전체-조회">2. 채널 전체 조회</h4>
<ul>
<li><strong>Method</strong>: GET</li>
<li><strong>URL</strong>: /channels</li>
<li><strong>req</strong>: -</li>
<li><strong>res</strong>: [ { &quot;id&quot;: 1, &quot;channelTitle&quot;: &quot;채널1&quot; }, ... ]</li>
</ul>
<h4 id="3-채널-개별-조회">3. 채널 개별 조회</h4>
<ul>
<li><strong>Method</strong>: GET</li>
<li><strong>URL</strong>: /channels/:id</li>
<li><strong>req</strong>: -</li>
<li><strong>res</strong>: { &quot;id&quot;: 1, &quot;channelTitle&quot;: &quot;채널1&quot; }</li>
</ul>
<h4 id="4-채널-수정">4. 채널 수정</h4>
<ul>
<li><strong>Method</strong>: PUT</li>
<li><strong>URL</strong>: /channels/:id</li>
<li><strong>req</strong>: { &quot;channelTitle&quot;: &quot;수정된 채널명&quot; }</li>
<li><strong>res</strong>: { &quot;message&quot;: &quot;채널명이 성공적으로 수정되었습니다.&quot; }</li>
</ul>
<h4 id="5-채널-삭제">5. 채널 삭제</h4>
<ul>
<li><strong>Method</strong>: DELETE</li>
<li><strong>URL</strong>: /channels/:id</li>
<li><strong>req</strong>: -</li>
<li><strong>res</strong>: { &quot;message&quot;: &quot;채널이 성공적으로 삭제되었습니다.&quot; }</li>
</ul>
<h3 id="채널-api-코드-틀">채널 API 코드 틀</h3>
<p>Express의 route() 메소드를 사용하면 하나의 경로에 대해 여러 HTTP 메소드를 쉽게 정의할 수 있다. 이를 통해 코드의 가독성을 높이고, 유지보수를 용이하게 만들 수 있다.</p>
<pre><code class="language-jsx">const express = require(&#39;express&#39;);
const app = express();

app.route(&#39;/path&#39;)
  .get((req, res) =&gt; {
    // GET 요청 처리 로직
  })
  .post((req, res) =&gt; {
    // POST 요청 처리 로직
  })
  .put((req, res) =&gt; {
    // PUT 요청 처리 로직
  })
  .delete((req, res) =&gt; {
    // DELETE 요청 처리 로직
  });

app.listen(3000, () =&gt; console.log(&#39;Server running on port 7777&#39;));
</code></pre>
<h2 id="자주-사용하는-http-상태-코드-정리">자주 사용하는 HTTP 상태 코드 정리</h2>
<ul>
<li><code>200</code> (OK): 요청이 성공적으로 처리되었다. 가장 일반적인 성공 상태 코드</li>
<li><code>201</code> (Created): 요청이 성공적으로 처리되었고 새로운 리소스가 생성되었다.</li>
<li><code>400</code> (Bad Request): 서버가 요청을 이해하지 못했다. 일반적으로 클라이언트의 요청 데이터가 형식에 맞지 않을 때 반환된다.</li>
<li><code>401</code> (Unauthorized): 이 상태 코드는 인증 실패를 나타낸다. 주로 로그인 실패 시 사용된다..</li>
<li><code>403</code> (Forbidden): 서버가 요청을 이해했지만 승인을 거부한다. 접근 권한이 없는 자원에 대한 요청에 사용된다.</li>
<li><code>404</code> (Not Found): 서버가 요청한 리소스를 찾을 수 없다. 일반적으로 잘못된 URL에 대한 요청에서 반환된다.</li>
<li><code>500</code> (Internal Server Error): 서버 내부에 오류가 발생했다. 서버가 요청을 처리할 수 없을 때 사용된다.</li>
</ul>
<p>동일한 경로를 묶어 정의할 수 있어 중복을 최소화할 수 있었다. 중복 되는 코드는 거의 없도록 노력하려하는데 이런 편리한 메소드가 있어 정말 편리한 듯하다. 🥹 상태 코드도 이제는 설명을 찾아보지 않고도 알 수 있을 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스 데브코스] TIL - 3주차 DAY5]]></title>
            <link>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-3%EC%A3%BC%EC%B0%A8-DAY5</link>
            <guid>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-3%EC%A3%BC%EC%B0%A8-DAY5</guid>
            <pubDate>Sun, 28 Apr 2024 04:59:25 GMT</pubDate>
            <description><![CDATA[<h2 id="expressmap-실습">Express+Map 실습</h2>
<pre><code class="language-jsx">const express = require(&#39;express&#39;);
const app = express();
app.listen(1234);

let db = new Map();
db.set(1, &quot;NoteBook&quot;); // 상품 정보를 저장하는 Map
db.set(2, &quot;Cup&quot;);
db.set(3, &quot;Chair&quot;);

app.get(&#39;/:id&#39;, function(req, res){
    let { id } = req.params;
    id = parseInt(id); // URL에서 받은 id를 숫자로 변환

    if(db.get(id) === undefined) {
        res.json({ message: &quot;상품을 찾을 수 없습니다.&quot; });
    } else {
        let product = { productName: db.get(id), id: id };
        res.json(product);
    }
});</code></pre>
<h2 id="express-구조">Express 구조</h2>
<p><a href="https://expressjs.com/ko/">Express - Node.js 웹 애플리케이션 프레임워크</a>
Express는 Node.js 기반의 웹 프레임워크로, 웹 애플리케이션과 API를 빠르게 구축할 수 있게 도와준다. 미들웨어 아키텍처를 사용하여 요청과 응답 사이에 다양한 기능을 쉽게 추가할 수 있다. (미들웨어는 다음 시간에 배울 것!)</p>
<h3 id="appjs-파일">app.js 파일</h3>
<p>app.js 파일은 Express 애플리케이션의 중심 파일로, 애플리케이션의 주요 설정을 포함한다. 예를 들어, 미들웨어 설정, 라우팅 규칙, 서비스 로직 등을 이 파일에 정의할 수 있다.</p>
<pre><code class="language-jsx">var createError = require(&#39;http-errors&#39;);
var express = require(&#39;express&#39;);
var path = require(&#39;path&#39;);
var cookieParser = require(&#39;cookie-parser&#39;);
var logger = require(&#39;morgan&#39;);

var indexRouter = require(&#39;./routes/index&#39;);
var usersRouter = require(&#39;./routes/users&#39;);

var app = express();

app.use(logger(&#39;dev&#39;)); // 개발 중 로그를 출력하는 미들웨어
app.use(express.json()); // JSON 요청을 파싱하는 미들웨어
app.use(express.urlencoded({ extended: false })); // URL 인코딩된 데이터를 파싱하는 미들웨어
app.use(cookieParser()); // 쿠키를 파싱하는 미들웨어
app.use(express.static(path.join(__dirname, &#39;public&#39;))); // 정적 파일을 제공하는 미들웨어

module.exports = app;
</code></pre>
<p>이 파일에서는 필요한 모듈들을 가져오고, 미들웨어를 설정한 후, 라우트를 설정한다. 모든 설정은 app 객체에 연결되어 있다.</p>
<h3 id="www-파일">www 파일</h3>
<p>www 파일은 서버를 구동하는 스크립트 파일로, 실제 서버의 시작점 역할을 한다. 이 파일에서는 HTTP 서버를 생성하고, 포트를 설정하며, 서버를 시작한다.</p>
<pre><code class="language-jsx">var app = require(&#39;../app&#39;);
var debug = require(&#39;debug&#39;)(&#39;express-base:server&#39;);
var http = require(&#39;http&#39;);

var port = normalizePort(process.env.PORT || &#39;3000&#39;);
app.set(&#39;port&#39;, port);

var server = http.createServer(app);

server.listen(port);
server.on(&#39;error&#39;, onError);
server.on(&#39;listening&#39;, onListening);</code></pre>
<p>이 파일에서는 app.js에서 설정된 Express 애플리케이션을 가져와 HTTP 서버 객체를 생성한다. 그리고 포트를 설정하고, 서버를 시작하여 외부의 요청을 받을 수 있도록 한다. 또한, 서버의 에러 핸들링과 리스닝 이벤트를 처리하는 부분도 포함되어 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스 데브코스] TIL - 3주차 DAY4]]></title>
            <link>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-3%EC%A3%BC%EC%B0%A8-DAY4</link>
            <guid>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-3%EC%A3%BC%EC%B0%A8-DAY4</guid>
            <pubDate>Thu, 25 Apr 2024 14:35:47 GMT</pubDate>
            <description><![CDATA[<h3 id="const-params는-무조건-문자열">const, params는 무조건 문자열</h3>
<pre><code class="language-jsx">let numer=parseInt(req.params.n)-10

    res.json({
        num:number
    })</code></pre>
<h3 id="reqparams-연습">req.params 연습</h3>
<p>//채널 주소: <a href="https://www.youtube.com/@ChimChakMan_Data">https://www.youtube.com/@ChimChakMan_Data</a></p>
<p>// 영상 클릭 주소: <a href="https://www.youtube.com/watch?v=0ilN6ERNCPQ">https://www.youtube.com/watch?v=0ilN6ERNCPQ</a></p>
<pre><code class="language-jsx">app.get(&#39;/:nickname&#39;,function(req,res){

    res.json({
        channel: req.params.nickname
        })
})</code></pre>
<pre><code class="language-jsx">app.get(&#39;/:nickname&#39;,function(req,res){
    const param=req.params

    res.json({
        channel: params.nickname
        })
})</code></pre>
<p>// 영상 클릭 주소: <a href="https://www.youtube.com/watch?v=iOZHOaYl5BY">https://www.youtube.com/watch?v=iOZHOaYl5BY</a></p>
<p>// 타임라인 주소: <a href="https://www.youtube.com/watch?v=iOZHOaYl5BY&amp;t=375s">https://www.youtube.com/watch?v=iOZHOaYl5BY&amp;t=375s</a></p>
<p>t=375s→시간 뜻하는 변수</p>
<pre><code class="language-jsx">app.get(&#39;/watch&#39;,function(req,res){
    const query=req.query


    res.json({
        video: query.v,
        timeline=q.t
            })
})</code></pre>
<p>?(질의) → 쿼리 스트링으로 파라미터 받기</p>
<p>url에 변수를 담아 뿌려본 것~</p>
<p>객체를 다르게 전달해보기</p>
<p>query={v:<strong>,t:</strong>}</p>
<pre><code class="language-jsx">app.get(&#39;/watch&#39;,function(req,res){

    const {v,t}=req.query

    res.json({
        video:v,
        timeline:t
    })
})</code></pre>
<pre><code class="language-jsx">app.get(&#39;/watch&#39;,function(req,res){

    const {q1,q2}=req.query

    res.json({
        video:q1,
        timeline:q2
    })
})
//이렇게하면 json 값이 제대로 안 담김
</code></pre>
<p>객체에서는 변수이름 그대로 사용!</p>
<h3 id="js객체json의-비구조화">JS객체(JSON)의 비구조화</h3>
<p>자바스크립트 배열 비구조화</p>
<pre><code class="language-jsx">const array=[1,2,3,4,5]

const num1=array[0]

const num4=array[3]</code></pre>
<p>비구조화 </p>
<pre><code class="language-jsx">const express=require(&#39;express&#39;)
app.listen(1234)

app.get(&#39;/:nickname&#39;,function(req,res){

    const {nickname}=req.param

    res.json({
        channel:nickname
    })
})</code></pre>
<pre><code class="language-jsx">const express=require(&#39;express&#39;)
app.listen(1234)

app.get(&#39;/:nickname&#39;,function(req,res){

    const {nickname}=req.param

    res.json({
        channel:nickname
    })
})</code></pre>
<pre><code class="language-jsx">let youtuber1={
    channelTitle=&quot;침착맨&quot;,
    sub: &quot;243만명&quot;,
    videoNum:&quot;6.9천개&quot;
}

let youtuber2={
    channelTitle=&quot;침착맨 원본 박물관&quot;,
    sub: &quot;38만명&quot;,
    videoNum:&quot;1.3천개&quot;
}

let youtuber3={
    channelTitle=&quot;침착맨 플러스&quot;,
    sub: &quot;71.3만명&quot;,
    videoNum:&quot;1.6천개&quot;
}

app.get(&#39;/:nickname&#39;,function(){
    const {nickname}=req.params

    if(nickname==&quot;@ChimChakMan_Official&quot;){
        res.json(youtuber1)
    }else if (nickname==&quot;@ChimChakMan_Data&quot;){
        res.json(youtuber2)
    }else if(nickname==&quot;@ChimChackMan_Plus&quot;){
        res.json(youtuber3)
    }else{
        res.json({
        message:&quot;모르는 유튜버입니다.&quot;
    })
})</code></pre>
<p>예외처리 생각해줘야한다.</p>
<h3 id="자바스크립트-네이밍-룰">자바스크립트 네이밍 룰</h3>
<p>kebab-case cf.snake_case</p>
<p>폴더/파일</p>
<p>알파벳 소문자</p>
<p>두 개이상의 단어를 합쳐서 쓸 땐 첫번째 단어와 두번째 단어 사이에 하이픈</p>
<p>camelCase</p>
<p>변수,함수</p>
<p>두 개이상의 단어를 합쳐서 쓸땐, 두 번째 단어의 첫글자를 대문자로</p>
<h3 id="자바스크립트-mapstring">자바스크립트 Map(String)</h3>
<p>key-value 형태</p>
<pre><code class="language-jsx">let db=new Map()
db.set(1,&quot;NoteBook&quot;) // 키로 밸류 찾을 수 있는 한 쌍 저장
db.set(2,&quot;Cup&quot;)
db.set(3,&quot;Chair&quot;)
</code></pre>
<p>반드시 알아야 할 자료구조</p>
<p>map</p>
<p>list</p>
<p>express+map(string)</p>
<pre><code class="language-jsx">const express=require(&#39;express&#39;)
const app=express()
app.listen(1234)

app.get(&#39;/:id&#39;,function(req,res){

    let {id}=req.params
    id=parseInt(id)

    if(db.get(id)==undefined){
        res.json({
            message:&quot;상품을 찾을 수 없습니다.&quot;
        })
    }else{
    res.json({
        id:id,
        productName:db.get(id)
    })
   }

})

let db=new Map()
db.set(1,&quot;NoteBook&quot;) // 키로 밸류 찾을 수 있는 한 쌍 저장
db.set(2,&quot;Cup&quot;)
db.set(3,&quot;Chair&quot;)
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스 데브코스] TIL - 3주차 DAY3]]></title>
            <link>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-3%EC%A3%BC%EC%B0%A8-DAY3</link>
            <guid>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-3%EC%A3%BC%EC%B0%A8-DAY3</guid>
            <pubDate>Wed, 24 Apr 2024 08:36:27 GMT</pubDate>
            <description><![CDATA[<h2 id="express">express</h2>
<p>express는 Node.js를 위한 가장 인기 있는 웹 프레임워크 중 하나로, 다양한 기능을 제공하여 개발을 편리하게 해준다. http 모듈보다 더 적은 코드로 더 많은 기능을 구현할 수 있다.</p>
<p><a href="https://www.npmjs.com/package/express">npm express</a></p>
<h4 id="express-설치">express 설치</h4>
<pre><code class="language-bash">npm i express</code></pre>
<h4 id="express-이용한-서버-구축-예제">express 이용한 서버 구축 예제</h4>
<pre><code class="language-jsx">const express = require(&#39;express&#39;)
const app = express()

app.get(&#39;/&#39;, function (req, res) {
  res.send(&#39;Hello World&#39;)
})

app.listen(3000)</code></pre>
<h2 id="jsonjavascript-object-notation이란">JSON(<strong>J</strong>ava<strong>S</strong>cript <strong>O</strong>bject <strong>N</strong>otation)이란?</h2>
<p>데이터를 전송하고 저장하는 표준 포맷 중 하나로, 키-값 쌍으로 이루어진 데이터 객체를 전달하는 데 사용된다. JavaScript에서 객체를 쉽게 생성하고 관리할 수 있다.</p>
<h3 id="객체란">객체란?</h3>
<p>객체는 JavaScript의 핵심 개념 중 하나로, 데이터와 그 데이터와 관련된 동작을 묶어 표현하는 데 사용된다. </p>
<pre><code class="language-jsx">app.get(`/products/:n`, function(req,res){

    res.json({
        num:n
    })
})</code></pre>
<pre><code class="language-jsx">
app.get(`/products/:n`, function(req,res){

// : =&gt; 어? 나한테 URL로 매개변수를 전달해줄 건가보다
// products/_ 빈칸에 오는 값을 n이라는 변수에 담아줘

    res.json({
        num: req.params
    })
})</code></pre>
<p>조금 더 응용하면 이렇게 작성할 수 있을 것이다!</p>
<pre><code class="language-jsx">
app.get(&#39;/products/:id&#39;, function(req, res) {
    let productId = req.params.id;  // URL에서 id 값을 추출
    // 데이터베이스에서 productId에 해당하는 정보를 조회
    res.json({
        id: productId,
        name: &quot;상품명&quot;,
        price: 20000
    });
});
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스 데브코스] TIL - 3주차 DAY2]]></title>
            <link>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-3%EC%A3%BC%EC%B0%A8-DAY2</link>
            <guid>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-3%EC%A3%BC%EC%B0%A8-DAY2</guid>
            <pubDate>Tue, 23 Apr 2024 14:32:28 GMT</pubDate>
            <description><![CDATA[<h2 id="http-method">HTTP method</h2>
<p>HTTP 메소드는 웹 서버와 통신할 때 사용자의 의도를 명시적으로 표현하는 방법이다. 각 메소드는 특정 작업을 수행하도록 설계되었다.</p>
<ul>
<li><code>GET</code> 데이터 조회</li>
<li><code>POST</code> 새로운 데이터 생성(=등록) </li>
<li><code>PUT</code> 기존 데이터 전체적으로 수정(덮어쓰기, 값이 있든없든 바꼈는 말든 무조건 수정)</li>
<li><code>PATCH</code> 기존 데이터 중 일부를 수정(값이 바꼈다면, 바뀐 값만 수정)</li>
<li><code>DELETE</code> 데이터 삭제 </li>
<li><code>HEAD</code>, <code>OPTIONS</code>, <code>CONNECT</code>, <code>TRACE</code> 다른 보조적인 기능</li>
</ul>
<p>cf. PATCH - 부분 수정
개인정보 수정 같이 특정 요소만 바꿈 → 부분 수정!
코드 작성할 때 PATCH는 까다로운 면이 있다.</p>
<h2 id="nodejs-개요">Node.js 개요</h2>
<p>Node.js는 이벤트 기반, 비동기 I/O를 지원하는 JavaScript 런타임 환경이다. 프론트엔드 개발 뿐만 아니라 백엔드 개발에도 사용된다. 대표적인 사례로는 넷플릭스, 에어비앤비, 링크드인, 우버 등등...nasa까지!</p>
<h3 id="nodejs-특징">Node.js 특징</h3>
<ul>
<li>싱글 스레드: 모든 요청을 단일 스레드에서 처리한다.</li>
<li>이벤트 기반: 이벤트가 발생할 때마다 콜백 함수를 호출한다.</li>
<li>논블로킹 I/O: I/O 작업이 CPU 작업과 동시에 일어날 수 있도록 한다. </li>
</ul>
<p>여기서도 강사님의 기가막힌 비유! </p>
<ul>
<li>싱글 스레드 ⇒ 식당에서 단 한 명의 요리사가 여러 주문을 동시에 처리하는 것과 비슷하다. 주문이 계속 밀려들어와도 한명이 어떻게든 처리해야 한다.
라면 1개, 볶음밥 1개 주문이 들어왔다. 라면 조리 10분 중 물 끓는 시간이 5분이고, 볶음밥 완성하는데 5분이 걸린다면 라면 물 올려놓고 볶음밥 요리하고 라면을 요리하면 효율이 극대화가 될 것이다!</li>
<li>이벤트 기반 ⇒ 주문이 들어와야만 일을 한다.(=주문이 없으면 일을 하지 않음)</li>
<li>논 블로킹 I/O(막히는게 없는 입출력) ⇒ 한 명이 일을 하는데, 요리를 순차적으로 하지 않고 중간중간 비는 시간이 있으면 다른 요리를 한다.</li>
</ul>
<h4 id="논-블로킹-실습-settimeout">논 블로킹 실습 setTimeout</h4>
<pre><code class="language-jsx">function first(){
    console.log(&quot;첫 번쨰&quot;);
}

function second(){
    console.log(&quot;두 번쨰&quot;);
}

function third(){
    console.log(&quot;세 번쨰&quot;);
}

first();
setTimeout(second, 2000);
third();</code></pre>
<h2 id="모듈">모듈</h2>
<h3 id="모듈이란">모듈이란?</h3>
<p>재사용 가능한 코드 덩어리를 의미한다. 이는 프로그램의 특정 기능을 담당하는 코드 부분으로, 다른 프로그램에서 쉽게 불러와 사용할 수 있습니다. 모듈화는 코드의 재사용성을 높이고, 관리를 용이하게 하며, 네임스페이스를 분리하여 코드 충돌을 방지합니다.</p>
<h3 id="모듈-종류">모듈 종류</h3>
<ol>
<li>내장 모듈
 프로그래밍 언어나 환경에 기본적으로 내장되어 있는 모듈. (예: Node.js의 http, fs 모듈)</li>
<li>외장 모듈
 다른 개발자들이 만들어 공유한 모듈로, npm(Node Package Manager)을 통해 설치하여 사용할 수 있다. (예: express, react)</li>
</ol>
<h2 id="라이브러리-vs-프레임워크">라이브러리 vs 프레임워크</h2>
<p>라이브러리와 프레임워크는 코드 재사용을 돕는 도구지만, 사용 방식에 차이가 있다.</p>
<ul>
<li><strong>라이브러리(Library)</strong>
  라이브러리는 개발자가 필요에 따라 선택적으로 사용할 수 있는 도구 모음.
개발자가 프로그램의 흐름을 제어하며, 필요할 때 특정 기능을 라이브러리에서 호출하여 사용.
(예: jQuery, Lodash)</li>
<li><strong>프레임워크(Framework)</strong>
프레임워크는 전체적인 애플리케이션의 구조(틀)를 제공.
프레임워크가 프로그램의 흐름을 제어하고, 개발자는 프레임워크가 정한 규칙에 따라 코드를 작성.
프레임워크는 필요한 모든 라이브러리를 포함하고 있을 수 있다.
(예: Angular, Spring)</li>
</ul>
<p>라이브러리는 상세 주제의 한권의 책을 골라내는 것. 내가 원하는 기준에 맞춰서!
장점은 내가 원하는 걸 빌릴 수 있고, 단점은 고르기가 힘들 수도 있다. 찾는 시간 오래걸리고 도서관 가는 시간 등 고려해야할 게 많다. 
라이브러리도 똑같은 미리 만들어놓은 모듈, 코드를 직접 찾아 선택해서 사용할 수 있음(빌려서 프로젝트에 적용해볼 수 있는 것)</p>
<p>라이브러리=모듈</p>
<p>프레임워크는 틀 안에서 일을 하는 것
내가 원하는(만들고싶은) 서비스 만들기(구현하기) 위한 모든 일을 틀 안에서 하는 것
프레임워크는 필요해보이는 라이브러리(모듈)를 미리 다 틀 안에 넣어뒀다! 
프레임워크가 지원하는 라이브러리 사용</p>
<h2 id="npm-figlet-사용해보기">npm, figlet 사용해보기</h2>
<h3 id="npmnode-package-manager">npm(Node Package Manager)</h3>
<p>npm은 Node.js의 패키지 관리자로, Node.js와 함께 자동으로 설치된다. npm을 사용하면 다양한 자바스크립트 라이브러리와 모듈을 쉽게 설치, 관리, 삭제할 수 있다.</p>
<h4 id="주요-기능">주요 기능</h4>
<p><code>npm install [패키지명] 또는 npm i [패키지명]</code>: 패키지 설치
<code>npm install -g [패키지명] (전역 설치)</code>: 글로벌 설치
<code>npm uninstall [패키지명]</code>: 패키지 제거
<code>package.json</code>: 프로젝트의 의존성을 관리하는 파일
<code>package-lock.json</code>: 설치된 모든 패키지의 정확한 버전을 기록하여 의존성을 일관되게 유지하는 파일
<code>node_modules</code>: 설치된 모든 npm 패키지가 저장되는 폴더</p>
<p><a href="https://www.npmjs.com/">npm | Home</a></p>
<h3 id="figlet-모듈-사용하기">figlet 모듈 사용하기</h3>
<p>figlet은 ASCII 아트를 생성하는 데 사용되는 npm 모듈이다. 텍스트를 스타일리시한 아트 형식으로 변환해주는 도구.
<a href="https://www.npmjs.com/package/figlet">npm: figlet</a></p>
<pre><code class="language-jsx">npm i figlet</code></pre>
<pre><code class="language-jsx">var figlet = require(&quot;figlet&quot;);

figlet(&quot;Bang Subeen!&quot;, function (err, data) {
  if (err) {
    console.log(&quot;Something went wrong...&quot;);
    console.dir(err);
    return;
  }
  console.log(data);
});
</code></pre>
<p>함수의 매개변수로 변수 또는 값을 전달하는 것이 아니라, 함수를 전달하는 것! _<strong>콜백 함수</strong>_라고 부르는 바로 그것.</p>
<p>함수 이름 없이 익명 함수 매개변수로 넘겨준다.(익명 함수 쓰는 이유는 이 함수를 쓸 일이 다른 데는 없어 한 번만 사용하기 때문)</p>
<p>첫 번째 매개변수 문자열을 받아서 아스키 아트를 만든 다음에 두 번째 매개변수 function 함수를 실행 = 콜백!</p>
<h3 id="nodejs-서버-예제">Node.js 서버 예제</h3>
<pre><code class="language-jsx">let http=require(&#39;http&#39;);

function onRequest(request, response){
    response.writeHead(200,{&#39;Content-Type&#39;:&#39;text/html&#39;});
    response.write(&#39;Hello Node.js&#39;);
    response.end();
}

http.createServer(onRequest).listen(8888);</code></pre>
<p>이 스크립트는 8888 포트에서 서버를 실행하고, 웹 브라우저에서 접근할 경우 &quot;Hello Node.js&quot; 메시지를 표시한다. http.createServer() 메소드는 요청을 처리할 콜백 함수를 매개변수로 받는다.</p>
<h2 id="let-const-및-템플릿-문자열">let, const 및 템플릿 문자열</h2>
<ul>
<li><strong>let</strong>: 블록 범위의 지역 변수를 선언하며, 선언된 블록 내에서만 유효하다.</li>
<li><strong>const</strong>: 블록 범위의 상수를 선언하며, 선언 후에는 값을 변경할 수 없다.</li>
<li><strong>템플릿 문자열</strong>: 백틱을 사용하여 문자열을 표현하며, <code>${expression}</code> 형태로 표현식을 문자열 안에 삽입할 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스 데브코스] TIL - 3주차 Day1]]></title>
            <link>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-3%EC%A3%BC%EC%B0%A8-Day1</link>
            <guid>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-3%EC%A3%BC%EC%B0%A8-Day1</guid>
            <pubDate>Mon, 22 Apr 2024 14:20:15 GMT</pubDate>
            <description><![CDATA[<h3 id="백엔드-개발자의-역할">백엔드 개발자의 역할</h3>
<p>백엔드 개발자는 _<strong>API(Application Programming Interface)</strong>_를 개발하여 서로 다른 소프트웨어 혹은 시스템 간의 연결을 가능하게 한다. 
예를 들어, 지하철 도착 정보 어플을 만들고자 할 때, 개인이 직접적으로 서울 교통 공사의 데이터베이스에 접근하는 것은 보안상 허용되지 않는다.😂 대신, 백엔드 개발자는 안전하게 접근할 수 있는 API를 개발한다.</p>
<ul>
<li><strong>API의 역할</strong>
  API는 애플리케이션과 서울 교통 공사의 데이터베이스 사이의 중재가 역할을 한다. 개발자는 API를 통해 지하철 도착 시간, 역 정보 등의 데이터 요청을 할 수 있다.
(단순히 데이터를 &quot;줘&quot;라는 요청 뿐만 아니라, 필요에 따라 데이터 연산이나 처리를 요구하는 복잡한 작업을 수행할 수 있다.)</li>
<li><strong>데이터 요청</strong>
애플리케이션 사용자가 지하철 도착 정보를 요청할 때, API는 이 요청을 서울 교통 공사의 데이터베이스로 전달하고, 필요한 데이터를 검색하여 애플리케이션으로 다시 전송한다. </li>
</ul>
<h3 id="interface란">Interface란?</h3>
<p>두 개체 혹은 시스템 간의 중재자/매개체 역할을 한다. 사용자 인터페이스(UI)는 아래와 같은 두 가지 주요 형태가 있다.</p>
<ul>
<li>GUI(Graphic User Interface): 그래픽을 통해 사용자가 시스템과 상호작용하는 방식</li>
<li>CLI(Command Line Interface): 텍스트 명령어를 통해 시스템과 상호작용하는 방식</li>
</ul>
<h3 id="rest-api-정의">REST API 정의</h3>
<p>REST API(Representational State Transfer API)는 웹 표준을 기반으로 개발된 API이다. HTTP 프로토콜의 원칙을 준수하면서 웹에서의 데이터 교환을 원활하게 한다. 각 리소스는 URL로 고유하게 식별되며, 표준 HTTP 메소드를 사용하여 리소스 상태를 조회하거나 업데이트한다. </p>
<p>강사님이 이해하기 쉽게 비유를 해주셔서 가려운 곳을 긁은 기분이었다.. </p>
<p>데이터 &quot;아무렇게나&quot; 주고 받으면 되는 건가? 아니!
웹(=인터넷 망 속 가상 공간) 개발자는 인터넷을 돌아다니기 위한 규약을 지켜야만 한다. = HTTP를 지켜야 한다.</p>
<p>과거에는 HTTP 형식을 무시하고 비효율적으로 데이터를 교환했었지만, 2000년대 초반 HTTP 창시자들이 이 형식 따를 때 효율이 극대화된다고 강조한 이후, 이 규칙을 엄격히 지키기 시작했다. </p>
<ul>
<li>REST API : HTTP 규약을 따르면서 데이터 교환을 효율적으로 수행할 수 있도록 설계된 API</li>
<li>RESTful API: HTTP 규약을 매우 철저히 준수하여 설계된 API, 통신의 표준화를 한층 더 높여준다.</li>
</ul>
<p>따라서 인터넷 상에서 원활한 데이터 공유와 전달을 위해 모든 데이터는 HTTP 프로토콜의 규약에 따라 안전하게 전송되어야 한다. </p>
<h4 id="-rest-api-특징">+ REST API 특징</h4>
<ol>
<li><strong>Stateless</strong>: 각 요청이 독립적으로 처리된다. 서버는 클라이언트의 상태를 저장하지 않는다.</li>
<li><strong>Uniform Interface</strong>: 통일된 인터페이스를 통해 시스템 내부 구현을 숨기고, 각 요소가 서로 독립적으로 진화할 수 있게 한다.</li>
<li><strong>Cacheable</strong>: 응답은 캐시 가능성이 명시되어야 하며, 적절한 관리를 통해 성능을 향상시킬 수 있다.</li>
</ol>
<h3 id="좋은-rest-api-설계-규칙">좋은 REST API 설계 규칙</h3>
<ul>
<li><strong>소문자 사용</strong>: 대소문자 구별하기 때문에 일관성 유지하기 위해 소문자만 사용</li>
<li><strong>하이픈(-) 사용</strong>: 가독성을 높이기 위해 언더바(_) 대신 하이픈(-) 사용 </li>
<li><strong>끝에 슬래시(/) 포함하지 않기</strong>: URI 끝에 슬래시(/) 포함하지 않음</li>
<li><strong>행위를 포함하지 않음</strong>: 리소스에 대한 행위를 포함하지 않음. 행위는 HTTP 메소드(GET, POST, PUT, DELETE)로 표현함</li>
<li><strong>파일 확장자 포함하지 않기</strong>: 리소스 표현은 HTTP 헤더를 통해 관리함</li>
<li><strong>복수형 명사 사용</strong>: 리소스는 복수형 명사를 사용하여 표현함</li>
</ul>
<h3 id="urlmethod-연습을-한-번-해보자">URL+method 연습을 한 번 해보자!</h3>
<ul>
<li>상품 등록: POST /products</li>
<li>전체 상품 조회: GET /products</li>
<li>상품 개별 조회: GET /products/{id}</li>
<li>상품 수정: PUT /products/{id}</li>
<li>전체 상품 삭제: DELETE /products</li>
</ul>
<p>ex. /product/1 ⇒ id=1인 데이터를 수정함</p>
<p>cf. 복수형으로 표현하면 좋은 이유</p>
<ul>
<li>상품들 중에서 id값을 가지는 개별 데이터라는 의미를 이해할 수 있음</li>
<li>통일감 줄 수 있음</li>
</ul>
<p>위와 같이 연습해본 것을 “<strong>API 설계</strong>”라고 부른다! 이제 나도 API 설계 해봤다!라고 말할 수 있다.
이러한 설계 원칙과 구조를 따름으로써 더욱 명확하고 효율적으로 데이터를 처리하고 사용자에게 서비스를 제공할 수 있다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스 데브코스] TIL - 2주차 Day4]]></title>
            <link>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-2%EC%A3%BC%EC%B0%A8-Day4</link>
            <guid>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-2%EC%A3%BC%EC%B0%A8-Day4</guid>
            <pubDate>Fri, 19 Apr 2024 08:56:28 GMT</pubDate>
            <description><![CDATA[<h2 id="쇼핑몰-프로젝트">쇼핑몰 프로젝트</h2>
<h3 id="메인-페이지">메인 페이지</h3>
<p><img src="https://velog.velcdn.com/images/bang-wol/post/05da6f8e-2d71-4a67-9918-d3ce18cf522c/image.png" alt=""></p>
<p>앞서배운 <code>&lt;div&gt;</code>, <code>&lt;a&gt;</code>, <code>&lt;img&gt;</code> 등의 태그를 사용하여 테니스 마켓 메인 페이지를 구현해보았다. order list를 클릭하면 주문 내역 페이지로 이동하고, order 버튼을 클릭하면 해당 색상 라켓을 주문할 수 있도록 추후 데이터베이스와 연결할 예정이다.</p>
<h2 id="백엔드">백엔드</h2>
<h3 id="백엔드의-구조">백엔드의 구조</h3>
<p>백엔드는 클라이언트에서 발생한 요청이 웹 서버를 거쳐 웹 어플리케이션 서버로 이동하고, 이곳에서 처리 후 데이터베이스와 상호 작용을 통해 필요한 데이터를 조작한 뒤 응답을 반환하는 구조로 이루어져 있다. </p>
<ul>
<li>요청 이동 경로 <code>클라이언트 -&gt; 웹 서버 -&gt; 웹 어플리케이션 서버 -&gt; 데이터베이스</code> </li>
<li>응답 이동 경로 <code>데이터베이스 -&gt; 웹 어플리케이션 서버 -&gt; 웹 서버 -&gt; 클라이언트</code> </li>
</ul>
<h3 id="웹-서버의-역할">웹 서버의 역할</h3>
<p>웹 서버는 주로 <strong>정적 페이지</strong>를 처리한다. 동적 페이지에 대한 처리는 직접하지 않고, 웹 어플리케이션 서버에 위임한다.</p>
<ul>
<li>정적 페이지: 화면의 내용/데이터 등 고정된 데이터를 보여주는 페이지</li>
<li>동적 페이지: 사용자의 요청에 따라 데이터 처리/연산을 통해 화면의 내용, 데이터가 변경되는 페이지</li>
</ul>
<h3 id="웹-어플리케이션-서버와-데이터베이스">웹 어플리케이션 서버와 데이터베이스</h3>
<p>웹 어플리케이션 서버는 <strong>동적 페이지</strong>를 처리한다. 필요한 데이터 연산을 위해 데이터베이스와 연결되어 있으며 데이터 조회, 수정, 삭제에 대한 처리를 요청한다.</p>
<ul>
<li>데이터베이스: 데이터를 통합하여 효율적으로 관리하기 위한 데이터 집합체를 말한다. 다음 시간에 더 자세히 다룰 예정!</li>
</ul>
<h3 id="nodejs의-이해">Node.js의 이해</h3>
<h4 id="nodejs란">Node.js란?</h4>
<p>JavaScript를 사용하여 서버 측 어플리케이션을 구축할 수 있게 하는 플랫폼이다. 이를 통해 JavaScript를 백엔드 프로그래밍에도 활용할 수 있다.</p>
<h3 id="nodejs를-이용한-웹-서버-구축">Node.js를 이용한 웹 서버 구축</h3>
<h4 id="http-모듈-사용">HTTP 모듈 사용</h4>
<p>Node.js의 <code>http</code> 모듈을 사용하여 HTTP 서버를 구축할 수 있다. <code>require()</code> 함수로 모듈을 불러와서 사용 가능하다. </p>
<h4 id="http-통신-구조">HTTP 통신 구조</h4>
<ul>
<li>헤더(Head): 요청과 응답의 상태를 나타내는 정보를 포함
  예: <code>200</code>(성공) <code>404</code>(찾을 수 없음) <code>500</code>(서버 오류)</li>
<li>바디(Body): 클라이언트에게 전달될 실제 데이터</li>
</ul>
<h4 id="서버-모듈화">서버 모듈화</h4>
<p>내가 구현한 서버 로직을 모듈화하여 다른 JavaScript 파일에서 재사용할 수 있다. <code>module.exports</code>를 사용하여 다른 파일에서 <code>require()</code>로 불러올 수 있게 한다.
<img src="https://velog.velcdn.com/images/bang-wol/post/7277cfe9-26d2-4dac-9a55-fde74c28ef5f/image.png" alt=""></p>
<h4 id="url-처리">URL 처리</h4>
<ul>
<li>URL(Uniform Resource Locator): 인터넷 상에서 자원의 위치를 나타내는 주소(하나의 정보를 공유할 수 있는 공간), 쉽게 말해 웹 페이지 주소
  예: <code>htto://localhost:8888</code> 로컬 호스트에서 포트 번호로 8888번을 사용하는 주소</li>
<li>포트 번호(port number): 클라이언트와 서버가 대화(연결)를 하고 싶다면, 같은 주파수를 맞춰야 한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스 데브코스] TIL - 2주차 Day3]]></title>
            <link>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-2%EC%A3%BC%EC%B0%A8-Day3</link>
            <guid>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-2%EC%A3%BC%EC%B0%A8-Day3</guid>
            <pubDate>Thu, 18 Apr 2024 05:29:09 GMT</pubDate>
            <description><![CDATA[<h2 id="🎨-css의-이해">🎨 CSS의 이해</h2>
<h3 id="css란">CSS란?</h3>
<p>CSS(Cascading Style Sheets)는 HTML로 작성된 웹 페이지를 꾸며주는 스타일 시트 언어. HTML 요소 각각에 스타일을 적용해서 세밀하게 디자인 할 수 있다. CSS를 활용하면 웹 페이지의 색상, 정렬, 폰트 등 다양한 시각적 요소를 손쉽게 조정할 수 있다. CSS를 HTML에 적용하는 방법은 크게 세 가지가 있다.</p>
<h3 id="1-인라인-스타일inline-style">1. 인라인 스타일(Inline Style)</h3>
<p>HTML 태그 내에 style 속성을 사용하여 직접 스타일을 적용하는 방법. 각 태그에 개별적으로 스타일을 적용할 수 있으나, 스타일 정보가 HTML과 혼합되어 관리가 복잡해질 수 있다.</p>
<pre><code>&lt;h1 style=&quot;color: cornflowerblue; text-align: center;&quot;&gt;로그인&lt;/h1&gt;
</code></pre><h3 id="2-내부-스타일-시트internal-style-sheet">2. 내부 스타일 시트(Internal Style Sheet)</h3>
<p>HTML 문서의 <code>&lt;head&gt;</code> 섹션 내에 <code>&lt;style&gt;</code> 태그를 사용하여 스타일을 정의하는 방법. 하나의 HTML 문서에만 적용되며, 문서 내에서 요소를 일괄적으로 스타일링 할 수 있다.</p>
<pre><code>&lt;style&gt;
    h1 {
        color: cornflowerblue;
        text-align: center;
    }
    .login_input {
        font-size: 20px;
    }
    #btn_login {
        font-size: 20px;
        width: 100px;
        height: 30px;
    }
&lt;/style&gt;
</code></pre><p>인라인보다 코드가 훨씬 깔끔하고 알아보기 편리함</p>
<h3 id="3-외부-스타일-시트external-style-sheet">3. 외부 스타일 시트(External Style Sheet)</h3>
<p>CSS 코드를 별도의 파일로 작성하고 HTML 문서에서 링크를 통해 참조하는 방법. 여러 HTML 문서에서 동일한 스타일 시트를 재사용할 수 있어 유지보수가 용이하다.</p>
<pre><code>&lt;link rel=&quot;stylesheet&quot; href=&quot;login.css&quot;&gt;
</code></pre><p>각 방법은 사용 상황에 따라 장단점이 있으며, 큰 프로젝트에서는 주로 외부 스타일 시트를 사용하여 스타일을 관리하는 것이 일반적이다. 외부 스타일 시트를 사용하면 HTML과 CSS를 분리하여 관리할 수 있기 때문에, 코드의 가독성과 재사용성이 향상된다.</p>
<h2 id="javascript의-이해">Javascript의 이해</h2>
<h3 id="javascript란">Javascript란?</h3>
<p>Javascript는 웹 페이지에서 사용되는 스크립트 언어로, 특정 HTML 요소를 선택하여 동적으로 제어할 수 있고 사용자와의 상호작용을 가능하게 한다.(예: 글자 변경, 버튼 비활성화, 색상 변경 등)</p>
<h4 id="스크립트-언어란">스크립트 언어란?</h4>
<p>독립적인 프로그램을 개발할 수 있는 프로그래밍 언어가 아닌 (프로그램 내부의 구성 요소 중 하나로)프로그램을 제어하는 스크립트 역할을 하는 언어이다. 최근 빠르게 발전하는 런타임 환경 덕분에 스크립트 언어만으로도 충분히 프로그래밍이 가능해져 역할이 확장되고 있다.</p>
<h3 id="html에-javascript를-적용하는-방법">HTML에 Javascript를 적용하는 방법</h3>
<ul>
<li><strong>인라인(Inline)</strong>: HTML 태그의 이벤트 속성에 직접 스크립트 코드를 작성한다. 예를 들어, 버튼에 클릭 이벤트를 추가할 때 사용한다.</li>
<li><strong>내부 스크립트(Internal script)</strong>: HTML 문서 내에 <code>&lt;script&gt;</code> 태그를 사용해 스크립트를 직접 삽입한다.</li>
<li><strong>외부 스크립트(External script)</strong>: 외부 .js 파일을 작성하고 HTML 문서에 연결한다. 이 방법은 유지보수가 쉽고, 여러 HTML 문서에서 재사용할 수 있다.</li>
</ul>
<h3 id="인라인-스크립트-예제">인라인 스크립트 예제</h3>
<pre><code>&lt;input id=&quot;btn_login&quot; type=&quot;button&quot; value=&quot;Login&quot; onclick=&quot;alert(&#39;clicked!&#39;)&quot;&gt;</code></pre><p><code>onclick</code> 속성을 사용하여 사용자가 버튼을 클릭하면 경고창이 나타나게 한다.</p>
<h3 id="함수function">함수(Function)</h3>
<p>특정 기능을 수행하는 코드 블록. 필요할 때마다 호출하여 사용할 수 있다.</p>
<pre><code>function 함수 이름(){
    // 함수가 수행할 작업
}</code></pre><h3 id="내부-스크립트-예제">내부 스크립트 예제</h3>
<p>태그를 찾고 이벤트를 처리하는 자바스크립트 함수를 내부 스크립트로 작성할 수 있다.</p>
<pre><code>&lt;script&gt;
    /* ID란에 입력된 값을 팝업창에 띄우기 */
    function popId(){
        alert(document.getElementById(&#39;txt_id&#39;).value);     
    }

    /* 나만의 함수 만들고, 버튼 클릭하면 호출하기 */
    function myFunction(){
        alert(&#39;로&#39;);  
        alert(&#39;그&#39;);
        alert(&#39;인&#39;);
    }
&lt;/script&gt;</code></pre><p><img src="https://velog.velcdn.com/images/bang-wol/post/e80ab94f-832c-495f-84ce-4a4c7f58ee3f/image.png" alt=""></p>
<p>HTML 요소(element) 찾는 방법</p>
<ul>
<li>ID로 찾기: <code>document.getElementById(&#39;아이디&#39;)</code></li>
<li>클래스 이름으로 찾기: <code>document.getElementByClassName(클래스 이름&#39;)</code></li>
<li>태그 이름으로 찾기: <code>document.getElementByTagName(&#39;태그 이름&#39;)</code></li>
</ul>
<p><del>document는 해당 문서를 뜻하고 .은 해당 문서 중에서 ~의(Of)란 뜻</del></p>
<h3 id="조건문if문">조건문(if문)</h3>
<p>조건문은 특정 조건에 따라 다른 행동을 하도록 프로그램을 지시하는 구문이다. JavaScript에서 <code>if</code>문은 주어진 조건이 참(true)일 때 코드 블록을 실행하고, 그렇지 않을 경우 다른 코드 블록을 실행할 수 있도록 한다.</p>
<pre><code>if (조건) {
    // 조건이 참일 때 실행될 코드
} else {
    // 조건이 거짓일 때 실행될 코드
}</code></pre><p>예를 들어, 사용자가 입력한 아이디가 비어 있는지 확인하고, 비어 있다면 경고 메시지를 표시하려고 한다면 아래와 같이 코드를 작성할 수 있다.</p>
<pre><code>if (userId === &#39;&#39;) {
    alert(&#39;아이디를 입력해주세요.&#39;);
} else {
    alert(&#39;입력된 아이디: &#39; + userId);
}
</code></pre><h3 id="변수">변수</h3>
<p>변수는 데이터를 저장할 수 있는 저장공간이다.<del>(데이터(값)을 담아놓는 상자)</del> JavaScript에서 변수를 선언하는 키워드에는 let, var, const가 있다. 각각의 키워드는 변수의 사용범위와 수정 가능성에 따라 선택해서 사용한다.</p>
<ul>
<li><code>let</code>: 블록 범위(scope) 지역 변수를 선언하며, 선언된 블록, 문 또는 표현식에서만 유효하다. 변수의 값이 변할 수 있다.</li>
<li><code>var</code>: 함수 범위(function scope) 지역 변수를 선언하며, 오래된 프로젝트나 구식 코드에서 주로 볼 수 있다.</li>
<li><code>const</code>: 값이 변경되지 않는 상수를 선언할 때 사용한다. let과 마찬가지로 블록 범위를 가지며, 한번 할당된 값은 변경할 수 없다.</li>
</ul>
<p>변수를 사용하면 중복을 최소화하여 코드를 더욱 깔끔하고 관리하기 쉽게 만들 수 있으며, 데이터를 효율적으로 처리할 수 있다.</p>
<p>📦 변수는 쉽게 말해 상자라고 할 수 있다. 데이터(값)를 담아놓는 상자! 상자 안에 데이터를 담아두고, 뭐가 들어있는지 이름표를 달아주면 된다.</p>
<h3 id="외부-스크립트">외부 스크립트</h3>
<p>JavaScript 코드를 별도의 파일에 작성하고 HTML 문서에 연결하여 사용하는 방법. 이를 통해 HTML 문서와 JavaScript 코드를 분리함으로써 유지보수가 쉽고, 코드의 재사용성이 높아진다.</p>
<pre><code>&lt;script type=&quot;text/javascript&quot; src=&quot;login.js&quot;&gt;&lt;/script&gt;</code></pre><p><code>src</code> 속성에는 외부 JavaScript 파일의 경로를 지정한다. 이렇게 하면 해당 JavaScript 파일의 코드가 HTML 문서에서 실행된다. 이 방식은 웹 페이지의 로딩 속도를 최적화하고, 스크립트 관리를 간편하게 할 수 있는 장점이 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스 데브코스] TIL - 2주차 Day2]]></title>
            <link>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-2%EC%A3%BC%EC%B0%A8-Day2</link>
            <guid>https://velog.io/@bang-wol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-TIL-2%EC%A3%BC%EC%B0%A8-Day2</guid>
            <pubDate>Wed, 17 Apr 2024 15:00:07 GMT</pubDate>
            <description><![CDATA[<h2 id="🌐-웹의-이해">🌐 웹의 이해</h2>
<h3 id="인터넷internet">인터넷(Internet)</h3>
<p>인터넷은 전 세계의 모든 컴퓨터를 하나의 통신망 안에서 연결한다는 의미를 가지며, International Networkd의 약어이다. 이는 &quot;우리는 모두 연결되어 있다&quot;는 개념을 상징한다. 여기서 인터넷과 웹은 같지 않다는 점을 느낄 수 있어야 한다.</p>
<h3 id="웹web이란">웹(Web)이란?</h3>
<p>월드 와이드 웹(World Wide Web), 줄여서 WWW, W3 또는 웹(Web)은 인터넷에 연결된 컴퓨터를 통해 사람들이 정보를 공유할 수 있는 공간이다. 웹은 정보의 공유 수단으로서 기능한다.</p>
<h3 id="웹web의-시작">웹(Web)의 시작</h3>
<p>1980년대 스위스의 유럽 입자 물리 연구소(CERN)에서 근무하던 컴퓨터 과학자 팀 버너스-리에 의해 탄생되었다. 이는 연구원들 간 신속한 정보 교환을 목적으로 고안되었다. 
<del>페이스북의 탄생 배경과 비슷한 맥락을 가지고 있다.</del></p>
<h3 id="웹web의-특징">웹(Web)의 특징</h3>
<p>웹은 정보를 하이퍼텍스트 형식으로 표현하고, 사용자가 하이퍼텍스트(링크)를 통해 다양한 정보나 문서들을 서로 연결하며 접근할 수 있게 한다.</p>
<p>*하이퍼텍스트(Hypertext)란, 단순히 글자가 아닌 그 이상의 기능을 가진 텍스트로 주로 링크, 참조의 역할을 하는 기술을 말함</p>
<h4 id="웹-페이지-vs-웹-사이트">웹 페이지 vs 웹 사이트</h4>
<p>웹 페이지와 웹 사이트는 다른 개념이다! 웹 페이지는 책의 한 페이지와 같고, 웹 페이지의 링크를 따라 다른 웹 페이지로 이동하는 것을 웹 서핑 혹은 웹 브라우징이라고 한다. 웹 사이트는 여러 웹 페이지가 모여서 만들어진 책과 같다.</p>
<h3 id="웹-브라우저web-brower란">웹 브라우저(Web brower)란?</h3>
<p>웹 브라우저는 웹 페이지나 웹 상의 데이터를 찾거나 읽을 때 사용하는 도구이다. 사용자가 웹을 통해 정보를 검색하고 접근할 수 있게 해주는 소프트웨어로, 우리가 인터넷을 탐색할 때 필수적인 도구이다. </p>
<br>

<h2 id="🏗️-웹의-구조">🏗️ 웹의 구조</h2>
<h3 id="클라이언트와-서버">클라이언트와 서버</h3>
<p>현실 세계에서의 클라이언트와 서버 관계는 고객과 서빙하는 사람의 관계와 비슷하다. 고객(클라이언트)이 요청을 하고, 서빙하는 사람(서버)이 그 요청을 처리하여 서비스를 제공한다. 웹에서도 이와 유사한 구조를 이루고 있다.</p>
<ul>
<li>클라이언트(Client): 서비스를 이용하며 요청을 하는 컴퓨터</li>
<li>서버(Server): 요청받은 서비스를 제공하는 컴퓨터</li>
</ul>
<p>웹에서 클라이언트는 웹 브라우저를 통해 서버에 접속하여 웹 페이지나 기타 서비스를 요청하고, 서버는 이러한 요청을 처리하여 필요한 데이터를 클라이언트에게 전송한다.</p>
<h3 id="프로토콜">프로토콜</h3>
<p>클라이언트와 서버가 서로 정보를 주고 받을 때에는 특정한 규칙이나 약속, 즉 <strong>프로토콜</strong>을 지켜야 한다. 이 프로토콜은 데이터 교환의 기준을 정하며, 웹에서는 주로 HTTP(Hyper Text Transfer Protocol)가 사용된다. </p>
<h4 id="웹-사용-방법">웹 사용 방법</h4>
<ul>
<li>요청
  사용자가 웹 브라우저에 웹 페이지의 주소(URL)를 입력한다. 웹 브라우저는 이 주소를 인터넷을 통해 해당 웹 서버에 전달하며, 웹 페이지를 요청한다.</li>
<li>응답
  웹 서버는 요청받은 주소에 해당하는 웹 페이지나 데이터를 찾아서, 다시 인터넷을 통해 웹 브라우저로 보낸다. 웹 브라우저는 이 데이터를 받아 사용자에게 웹 페이지를 표시한다. </li>
</ul>
<br>

<h2 id="👩🏻💻-웹-개발-직무-이해">👩🏻‍💻 웹 개발 직무 이해</h2>
<h3 id="프론트엔드">프론트엔드</h3>
<p>웹 서비스에서 사용자의 측면(Client-side)에서 작동하는 그래픽 사용자 인터페이스를 말한다. 프론트엔드는 웹 페이지에서 발생하는 상호작용(예: 글자 입력, 버튼 클릭, 화면 출력)을 담당한다. 사용자가 보고 직접 다루는 모든 요소가 프론트엔드의 범위에 속한다.</p>
<h3 id="백엔드">백엔드</h3>
<p>웹 서비스의 서버 측면(Server-side)에서 작동하며, 사용자 눈에는 보이지 않는다. 백엔드는 프론트엔드에서 보낸 데이터와 요청을 받아 내부 데이터베이스와의 연산을 통해 처리하고, 그 결과를 다시 프론트엔드로 전달한다. 이 과정을 통해 웹 페이지의 기능이 실행된다.</p>
<h3 id="프론트엔드와-백엔드-상호작용">프론트엔드와 백엔드 상호작용</h3>
<p>예를 들어 로그인 과정에서 사용자가 프론트엔드에서 로그인 요청을 하면 백엔드는 데이터베이스에서 해당 아이디를 찾는다. 아이디가 존재하면 비밀번호를 비교하여 맞다면 &quot;환영합니다&quot; 페이지를, 틀리다면 &quot;로그인 실패&quot; 메시지를 프론트엔드로 보낸다. 이와 같은 과정을 통해 사용자 인증이 이루어진다. </p>
<h3 id="프론트엔드-3대-요소">프론트엔드 3대 요소</h3>
<p>웹은 주로 HTML+CSS+Javascript 세 가지 기술로 구성된다.</p>
<ul>
<li><strong>HTML(HyperText Markup Language)</strong>: 웹 페이지의 기본 구조를 정의함. 각 웹 페이지 요소의 위치와 역할을 설정함</li>
<li><strong>CSS(Cascading Style Sheets)</strong>: 웹 페이지의 디자인과 스타일을 담당함. 색상, 레이아웃, 폰트 등 시각적 요소를 꾸며 사용자에게 보여지는 외관을 조정함.</li>
<li><strong>Javascript</strong>: 웹 페이지에 동적인 기능을 추가함. 사용자의 입력에 반응하거나, 서버로부터 데이터를 받아 웹 페이지에 실시간으로 반영하는 등의 기능을 수행함. 구성 요소들에 생명력을 불어넣음!</li>
</ul>
<br>

<h2 id="🔑-첫-html-파일-만들기">🔑 첫 HTML 파일 만들기</h2>
<h3 id="html이란">HTML이란?</h3>
<p>HTML(HyperText Markup Language)은 웹 페이지의 구조를 명시하는 언어로, 하이퍼텍스트 즉, 웹 페이지들을 서로 연결하는 기능을 가진 텍스트. HTML은 &lt;와 &gt; 괄호를 사용하는 태그를 통해 웹 페이지의 각 요소를 정의한다. 태그는 보통 여는 태그(&lt;태그&gt;)와 닫는 태그(&lt;/태그&gt;)의 쌍으로 구성되며, 일부 태그는 닫는 태그 없이 단독으로 사용된다(예: <code>&lt;br&gt;</code>).</p>
<p><img src="https://velog.velcdn.com/images/bang-wol/post/2ee6a1f6-53d0-4402-bc24-9491d0337a2e/image.png" alt=""></p>
<h3 id="자주-쓰는-html-태그">자주 쓰는 HTML 태그</h3>
<blockquote>
</blockquote>
<ul>
<li><code>&lt;html&gt;</code> HTML 문서의 루트 요소를 정의함. 모든 다른 요소는 이 요소 내부에 위치해야 함.</li>
<li><code>&lt;head&gt;</code> 문서의 메타데이터(문서 제목, 문자 인코딩, 스타일 시트 링크 등)를 포함하는 부분.</li>
<li><code>&lt;body&gt;</code> 웹 페이지의 모든 내용을 포함하는 부분으로, 텍스트, 하이퍼링크, 이미지, 동영상 등이 이 안에 위치함.</li>
<li><code>&lt;title&gt;</code> 브라우저 탭에 표시되는 문서의 제목을 정의함.</li>
<li><code>&lt;meta&gt;</code> 문서의 메타데이터(예: 문자 집합, 페이지 설명, 키워드 등)를 설정하는 태그.</li>
<li><code>&lt;div&gt;</code> 플로우 컨텐츠를 위한 컨테이너로, 주로 문서를 섹션으로 나누는 데 사용됨.</li>
<li><code>&lt;a&gt;</code> 하이퍼링크를 정의하며, 다른 페이지, 파일, 이메일 주소, 위치 등으로 연결할 수 있음.</li>
<li><code>&lt;script&gt;</code> 클라이언트 사이드 스크립트, 주로 JavaScript를 문서에 포함시킬 때 사용됨.</li>
<li><code>&lt;link&gt;</code> 외부 리소스를 문서와 연결할 때 사용되며, 주로 스타일 시트를 연결하는데 사용됨.</li>
<li><code>&lt;span&gt;</code> 인라인 요소로, 텍스트의 일부분에 스타일을 적용하거나, 문서 내에서 특정 그룹을 지정하는 데 사용됨.</li>
<li><code>&lt;br&gt;</code> 줄바꿈을 생성하는 데 사용되며, 닫는 태그 없이 사용하는 태그.</li>
</ul>
<h3 id="로그인-페이지-만들기">로그인 페이지 만들기</h3>
<p>HTML을 사용하여 로그인 폼을 만드는 기본적인 구조!</p>
<p><img src="https://velog.velcdn.com/images/bang-wol/post/064a1a82-4fff-4345-aebb-4ca842389cd3/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/bang-wol/post/f7b48fe6-cf73-420f-9648-95a93e916ffa/image.png" alt=""></p>
<ul>
<li><code>&lt;form&gt;</code> 사용자 입력을 웹 서버로 제출하기 위한 폼을 정의함</li>
<li><code>&lt;input&gt;</code> 사용자로부터 데이터를 입력받기 위한 입력 필드를 생성함. &#39;type&#39; 속성을 통해 다양한 형태의 입력 필드(텍스트, 비밀번호, 버튼 등)를 정의할 수 있음.</li>
</ul>
<br>

<p>아주 기본적인 구조를 만들었다보니 디자인도 적용시키고 싶고, 기능들도 추가시키고 싶었는데 강사님이 욕심으로부터 개발이 시작되는 것!이란 말씀을 해주셔서 너무 와닿았다. 욕심이 생기면 더 잘하고 싶고, 그 과정 속에서 발전해나가는 모습을 발견해나갈 수 있겠지! 이제 욕심을 많이 부려보자. </p>
]]></description>
        </item>
    </channel>
</rss>