<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>minnczi.log</title>
        <link>https://velog.io/</link>
        <description>꿈꾸는 풀스택 개발자</description>
        <lastBuildDate>Fri, 03 Feb 2023 13:56:06 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. minnczi.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/minnczi" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Spring Boot] 한국수출입은행 Open API를 활용하여 환율 정보 가져오기]]></title>
            <link>https://velog.io/@minnczi/exchange-rate-open-api-java</link>
            <guid>https://velog.io/@minnczi/exchange-rate-open-api-java</guid>
            <pubDate>Fri, 03 Feb 2023 13:56:06 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<p>현재 구축하고 있는 대시보드 시스템에서 환율 정보가 필요해,
한국수출입은행에서 제공하는 환율 API를 활용해 실시간 환율 정보를 제공받아 사용해 보기로 했다.</p>
<h2 id="활용법">활용법</h2>
<h3 id="1-인증키-발급받기">1. 인증키 발급받기</h3>
<p>한국수출입은행 Open API 제공 페이지: <a href="https://www.koreaexim.go.kr/ir/HPHKIR020M01?apino=2&amp;viewtype=C&amp;searchselect=&amp;searchword=">https://www.koreaexim.go.kr/ir/HPHKIR020M01?apino=2&amp;viewtype=C&amp;searchselect=&amp;searchword=</a></p>
<p>위의 페이지로 접속하면 <code>Open API 인증키 발급</code> 탭에서 간단한 본인 인증을 하면 인증키를 발급 받을 수 있다.
발급받은 Key는 <code>나의 인증키 발급내역</code> 에서 확인 가능!</p>
<p><img src="https://velog.velcdn.com/images/minnczi/post/2d993173-2a66-410b-af00-045017a5498b/image.png" alt=""></p>
<h3 id="2-요청-변수-세팅하기">2. 요청 변수 세팅하기</h3>
<p>우선 공통 함수를 한데 모아두기 위해 스프링 폴더 구조상으로
<code>src &gt; main &gt; utils</code> 라는 패키지를 신규로 생성하고 <code>ExchangeRateUtils</code> 를 작성했다</p>
<p>이후 아래의 세개 요청 변수를 코드상으로 초기 세팅해주면 된다</p>
<p><img src="https://velog.velcdn.com/images/minnczi/post/150992e8-799a-4f7b-ba58-f28add4f6785/image.png" alt=""></p>
<pre><code class="language-java">import java.text.NumberFormat;  
import java.text.SimpleDateFormat;  
import java.util.Date;  
import java.util.Locale;

public class ExchangeRateUtils {

private static HttpURLConnection connection;
private static BigDecimal defaultExchangeRate = BigDecimal.valueOf(1300);

public static BigDecimal getExchangeRate () {

    String authKey = &lt;발급받은 인증키&gt;;
    String searchDate = new SimpleDateFormat(&quot;yyyyMMdd&quot;).format(new Date());
    String dataType = &quot;AP01&quot;;
    BigDecimal exchangeRate = null;

    ...
}</code></pre>
<h3 id="3-api-request-보내기">3. API Request 보내기</h3>
<pre><code class="language-java">...
public static BigDecimal getExchangeRate () {
    ...
    BufferedReader reader;
    String line;
    StringBuffer responseContent = new StringBuffer();
    JSONParser parser = new JSONParser();

    try {
        // Request URL
        URL url = new URL(&quot;https://www.koreaexim.go.kr/site/program/financial/exchangeJSON?authkey=&quot; + authKey + &quot;&amp;searchdate=&quot; + searchDate + &quot;&amp;data=&quot; + dataType);
        connection = (HttpURLConnection) url.openConnection();

        // Request 초기 세팅
        connection.setRequestMethod(&quot;GET&quot;);
        connection.setConnectTimeout(5000);
        connection.setReadTimeout(5000);

        int status = connection.getResponseCode();

        // API 호출
        // 실패했을 경우 Connection Close
        if (status &gt; 299) {
            reader = new BufferedReader(new InputStreamReader(connection.getErrorStream()));
            while ((line = reader.readLine()) != null) {
                responseContent.append(line);
            }
            reader.close();
        } else { // 성공했을 경우 환율 정보 추출
            reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            while ((line = reader.readLine()) != null) {
                JSONArray exchangeRateInfoList = (JSONArray) parser.parse(line);

                }
            }
            reader.close();
        }
        System.out.println(responseContent.toString());

    } catch (MalformedURLException e) {
        throw new RuntimeException(e);
    } catch (IOException e) {
        throw new RuntimeException(e);
    } catch (ParseException e) {
        throw new RuntimeException(e);
    } catch (java.text.ParseException e) {
        throw new RuntimeException(e);
    } finally {
        connection.disconnect();
    }

    return exchangeRate;
}</code></pre>
<h3 id="4-가져온-데이터-파싱하여-사용하기">4. 가져온 데이터 파싱하여 사용하기</h3>
<pre><code class="language-java">public static BigDecimal getExchangeRate () {
    ...
        } else { // 성공했을 경우 환율 정보 추출
            reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            while ((line = reader.readLine()) != null) {
                JSONArray exchangeRateInfoList = (JSONArray) parser.parse(line);

                // KRW -&gt; USD에 대한 환율 정보 조회
                for (Object o : exchangeRateInfoList) {
                    JSONObject exchangeRateInfo = (JSONObject) o;
                    if (exchangeRateInfo.get(&quot;cur_unit&quot;).equals(&quot;USD&quot;)) {

                        // 쉼표가 포함되어 String 형태로 들어오는 데이터를 Double로 파싱하기 위한 부분
                        NumberFormat format = NumberFormat.getInstance(Locale.getDefault());
                        exchangeRate = new BigDecimal(format.parse(exchangeRateInfo.get(&quot;deal_bas_r&quot;).toString()).doubleValue());
                    }
                }
           ...
    if (exchangeRate == null) {
        exchangeRate = defaultExchangeRate; // 클래스 변수로 선언
    }

    return exchangeRate;
}</code></pre>
<h2 id="전체-코드">전체 코드</h2>
<pre><code class="language-java">public static BigDecimal getExchangeRate () {

    BufferedReader reader;
    String line;
    StringBuffer responseContent = new StringBuffer();
    JSONParser parser = new JSONParser();

    String authKey = &lt;발급받은 인증키&gt;;
    String searchDate = new SimpleDateFormat(&quot;yyyyMMdd&quot;).format(new Date());
    String dataType = &quot;AP01&quot;;
    BigDecimal exchangeRate = null;

    try {
        // Request URL
        URL url = new URL(&quot;https://www.koreaexim.go.kr/site/program/financial/exchangeJSON?authkey=&quot; + authKey + &quot;&amp;searchdate=&quot; + searchDate + &quot;&amp;data=&quot; + dataType);
        connection = (HttpURLConnection) url.openConnection();

        // Request 초기 세팅
        connection.setRequestMethod(&quot;GET&quot;);
        connection.setConnectTimeout(5000);
        connection.setReadTimeout(5000);

        int status = connection.getResponseCode();

        // API 호출
        // 실패했을 경우 Connection Close
        if (status &gt; 299) {
            reader = new BufferedReader(new InputStreamReader(connection.getErrorStream()));
            while ((line = reader.readLine()) != null) {
                responseContent.append(line);
            }
            reader.close();
        } else { // 성공했을 경우 환율 정보 추출
            reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            while ((line = reader.readLine()) != null) {
                JSONArray exchangeRateInfoList = (JSONArray) parser.parse(line);

                // KRW -&gt; USD에 대한 환율 정보 조회
                for (Object o : exchangeRateInfoList) {
                    JSONObject exchangeRateInfo = (JSONObject) o;
                    if (exchangeRateInfo.get(&quot;cur_unit&quot;).equals(&quot;USD&quot;)) {

                        // 쉼표가 포함되어 String 형태로 들어오는 데이터를 Double로 파싱하기 위한 부분
                        NumberFormat format = NumberFormat.getInstance(Locale.getDefault());
                        exchangeRate = new BigDecimal(format.parse(exchangeRateInfo.get(&quot;deal_bas_r&quot;).toString()).doubleValue());
                    }
                }
            }
            reader.close();
        }
        System.out.println(responseContent.toString());

    } catch (MalformedURLException e) {
        throw new RuntimeException(e);
    } catch (IOException e) {
        throw new RuntimeException(e);
    } catch (ParseException e) {
        throw new RuntimeException(e);
    } catch (java.text.ParseException e) {
        throw new RuntimeException(e);
    } finally {
        connection.disconnect();
    }

    if (exchangeRate == null) {
        exchangeRate = defaultExchangeRate;
    }

    return exchangeRate;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[1. Spring Boot 프로젝트에 Heroku PostgreSQL DB 연결하기]]></title>
            <link>https://velog.io/@minnczi/1.-Spring-Boot-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90-Heroku-PostgreSQL-DB-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@minnczi/1.-Spring-Boot-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90-Heroku-PostgreSQL-DB-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 24 Feb 2022 15:55:14 GMT</pubDate>
            <description><![CDATA[<h3 id="개요">개요</h3>
<p>Spring Boot 앱을 개발하면서, 여러 사람들과 함께 협업하면서 작업할 예정이기 때문에, 같이 공유하면서 작업할 수 있는 데이터베이스를 개설하고 사용하기로 하였다. 추후에 웹사이트를 배포할때에도, 로컬 환경이 아닌 DB로의 접속은 필수적으로 필요하기 때문에, 프로젝트를 시작하면서 DB와 연결하는 작업을 가장 먼저 해주었다.</p>
<p>우리는 무료로 클라우드 데이터베이스를 제공하는 곳들 중 Heroku라는 곳의 DB를 사용하기로 하였다.</p>
<ul>
<li>1GB / 최대 10,000건의 데이터 무료 사용 가능 (토이 프로젝트 규모로는 충분)</li>
<li>사용 기간의 제약 없음</li>
<li>PostgreSQL DB 제공 (가장 익숙히 알고 있는 mySQL과 거의 동일한 문법)</li>
</ul>
<h3 id="준비-사항">준비 사항</h3>
<ol>
<li>Heroku 회원가입</li>
<li><a href="https://devcenter.heroku.com/articles/heroku-cli#install-the-heroku-cli">Heroku CLI 설치</a> (미 설치시에도 진행은 가능하나 해당 블로그 포스트에서는 다룰 예정)</li>
<li><a href="https://www.postgresql.org/download/">PostgreSQL 설치</a></li>
<li><a href="https://www.pgadmin.org/download/">PgAdmin4 설치</a> (선택)</li>
</ol>
<h3 id="데이터베이스-생성">데이터베이스 생성</h3>
<ol>
<li>Heroku 웹사이트로 로그인 후, 새로운 앱을 생성한다. Region은 미국으로 지정해주었다.
<img src="https://images.velog.io/images/minnczi/post/1e7c5c0b-6e7c-4ff8-9fe3-ec9b5471cc71/Screen%20Shot%202022-02-25%20at%2012.24.11%20AM.png" alt=""></li>
</ol>
<p><img src="https://images.velog.io/images/minnczi/post/157321b4-c1fc-4852-945c-5368ca3a0723/Screen%20Shot%202022-02-25%20at%2012.25.28%20AM.png" alt=""></p>
<ol start="2">
<li><p>앱 생성 후, 앱의 메인 페이지로 들어와 Resources 탭을 클릭
<img src="https://images.velog.io/images/minnczi/post/a9b3aa7c-aa59-412b-a046-c97ba3e5ba2c/Screen%20Shot%202022-02-25%20at%2012.27.16%20AM.png" alt=""></p>
</li>
<li><p>Add-ons 섹션에서 <code>Heroku Postgres</code>를 검색해 추가한다.</p>
</li>
<li><p>Plan name에 <code>Hobby Dev - Free</code>를 선택하고 &quot;Submit Order Form&quot; 버튼을 클릭한다</p>
</li>
<li><p>Resources 탭에 Heroku Postgres가 성공적으로 추가된 것을 확인하면 완료!</p>
</li>
</ol>
<p><img src="https://images.velog.io/images/minnczi/post/5871ed42-dd01-4839-97b9-e2ac86f50f0e/Screen%20Shot%202022-02-25%20at%2012.31.32%20AM.png" alt=""></p>
<h3 id="데이터베이스-확인--테스트">데이터베이스 확인 &amp; 테스트</h3>
<p>생성된 데이터베이스를 클릭하면 상세페이지로 넘어갈 수 있는데, 여기서 데이터베이스에 대한 세부 정보들을 확인할 수 있다</p>
<p>그 중, Settings, 탭에 들어가면 Database 연결 관련된 정보를 확인할 수 있는데, 여기 있는 정보들을 활용해 Spring Boot에서 DB와 연결을 완료해야한다</p>
<p><img src="https://images.velog.io/images/minnczi/post/ebc165c2-7c84-4095-8eec-10a87ce65d79/Screen%20Shot%202022-02-25%20at%2012.33.13%20AM.png" alt=""></p>
<h3 id="spring-boot-설정">Spring Boot 설정</h3>
<ol>
<li><code>build.gradle</code> 파일에 dependency들을 추가해준다<ul>
<li>Postgresql과 log4의 경우, 주석에 있는 url 링크를 통해 최신 버전에 대한 build.gradle 설정 코드를 찾을 수 있다</li>
<li>*주의: <code>build.gradle</code> 파일을 업데이트 한 이후에는 꼭 새로고침을 해서 새로운 패키지들을 다운 받아 준다</li>
</ul>
</li>
</ol>
<pre><code class="language-java">dependencies {
    // 필수
    implementation &#39;org.springframework.boot:spring-boot-starter-jdbc&#39;    
    // https://mvnrepository.com/artifact/org.postgresql/postgresql
    implementation group: &#39;org.postgresql&#39;, name: &#39;postgresql&#39;, version: &#39;42.3.3&#39;

  // 선택: SQL를 편하게 보기 위한 log4 추가
    // https://mvnrepository.com/artifact/org.bgee.log4jdbc-log4j2/log4jdbc-log4j2-jdbc4.1
    implementation group: &#39;org.bgee.log4jdbc-log4j2&#39;, name: &#39;log4jdbc-log4j2-jdbc4.1&#39;, version: &#39;1.16&#39;

}</code></pre>
<ol start="2">
<li><code>application.properties</code> 파일에 DB 설정 관련 정보를 추가해준다</li>
</ol>
<p>여기서 필요한 정보들을 앞서 말한 Settings 페이지에서 전부 찾을 수 있다</p>
<pre><code class="language-java">spring.datasource.hikari.maximum-pool-size=4
spring.datasource.url=jdbc:postgresql://&lt;Host&gt;/&lt;Database&gt;
spring.datasource.username=&lt;User&gt;
spring.datasource.password=&lt;Password&gt;
spring.datasource.platform=postgres</code></pre>
<p>이렇게 하면 모든 설정이 완료되었다! - 실제 DB가 제대로 연결된건지 확인하기 위해 첫번째 API 코드를 작성하는 것을 진행해보자!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[0.1 Gradle Wrapper로 Spring Boot프로젝트 실행하기]]></title>
            <link>https://velog.io/@minnczi/00.1-Gradle-Wrapper%EB%A1%9C-Spring-Boot%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@minnczi/00.1-Gradle-Wrapper%EB%A1%9C-Spring-Boot%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 30 Jan 2022 05:57:44 GMT</pubDate>
            <description><![CDATA[<h3 id="개요-gradle-wrapper란-무엇일까">개요: Gradle Wrapper란 무엇일까?</h3>
<p>Spring (Boot) 로 개발한 application을 실행하기 위해서는 build라는 과정을 반드시 거쳐야 하는데, 쉽게 말해서 사람이 읽을 수 있는 형태로 작성한 코드 (Spring Boot)를 컴퓨터가 인식할 수 있는 형태로 변환하여 앱을 동작시키는 과정을 말한다.</p>
<p>이런 과정을 수행해주는 도구로, 흔히 쓰이는 <strong>gradle과 maven</strong> 이렇게 두가지 도구가 있다. Spring Boot 프로젝트를 처음 설정할때 gradle을 사용할지, maven을 사용할지 결정하여 프로젝트 생성할 수 있고, 어떤 것을 선택하는지에 따라 설정 방법에 약간씩의 차이가 생긴다</p>
<p>이렇게 만든 프로젝트를 실제로 동작 시키려면, 내 로컬 환경에 <strong>java 뿐만 아니라 gradle / maven 이 설치되어 있어야 작동이 가능</strong>하다. 하지만, 내 프로젝트를 실행하는 모든 사람이 나와 같은 환경에서 프로젝트를 동작시키는 것이 아니기 때문에, 실제 프로젝트 실행 시 다양한 변수가 생길 수 있다. (어떤 java 버젼을 사용하는지, 어떤 gradle 버전을 사용하는지 등등.. 에 따라서) 혹은, gradle 자체가 로컬 환경에 설치되어있지 않을 수도 있다.</p>
<blockquote>
<p>gradle을 가지고 있지 않은 사람도 쉽게 내 프로젝트를 다운 받아서 실행할수 있도록 도와주는 도구가 바로 gradle wrapper (wrapper / gradlew) 이다.</p>
</blockquote>
<h3 id="준비-사항">준비 사항</h3>
<p>프로젝트를 생성하고 설정하는 사람의 경우:</p>
<ul>
<li>프로젝트 환경에 맞는 java 설치 및 환경 변수 설정</li>
<li>gradle 다운로드</li>
</ul>
<p>프로젝트를 다운 받아 실행하는 사람의 경우:</p>
<ul>
<li>프로젝트 환경에 맞는 java 설치 및 환경 변수 설정</li>
</ul>
<h3 id="gradle-wrapper-설정">Gradle Wrapper 설정</h3>
<p>프로젝트를 초기 생성할때 gradlew로 생성하지 않았다면, 별도의 명령어를 사용하여, gradle wrapper 프로젝트로 변형해 주어야 한다</p>
<p><em>** 이 과정을 위해서는 gradle이 사전 다운로드 되어 있어야 함</em></p>
<ol>
<li>gradle wrapper 프로젝트로 재 build</li>
</ol>
<pre><code class="language-bash">$ gradle wrapper --gradle-version &lt;버전명&gt;</code></pre>
<ol start="2">
<li>gradle wrapper 관련 설정 파일이 생긴것을 확인</li>
</ol>
<p>아래의 폴더 및 파일들이 생성된 것을 확인하면 성공!</p>
<ul>
<li>gradle/wrapper 폴더</li>
<li>gradlew</li>
<li>gradlew.bat</li>
</ul>
<p><img src="https://images.velog.io/images/minnczi/post/20ea486e-9708-4f72-be65-e00f98e70866/Screen%20Shot%202022-01-30%20at%2011.47.59%20AM.png" alt=""></p>
<h3 id="gradle-wrapper로-프로젝트-빌드하기">Gradle Wrapper로 프로젝트 빌드하기</h3>
<p>프로젝트 소스 코드에 변경 사항이 생길 때, build를 새로 해주어야 한다. 이 경우 아래 코드를 입력하여 프로젝트를 재 빌드한다.</p>
<pre><code class="language-bash">$ ./gradlew build</code></pre>
<h3 id="gradle-wrapper로-빌드된-프로젝트-실행하기">Gradle Wrapper로 빌드된 프로젝트 실행하기</h3>
<p>이미 gradle wrapper를 통해 빌드 된 프로젝트를 팀원 또는 협업하는 사람이 받아서 실행하는 경우라고 가정해보자. 이 경우 git 또는 다른 VCS를 통해 프로젝트 소스 코드만 다운로드 받아 놓은 상황이고 처음 프로젝트를 실행하는 상황일 것이다.</p>
<p>gradlew가 있는 프로젝트 최상단 루트 폴더로 가서, 터미널을 켜고 아래 명령어를 실행시킨다</p>
<pre><code class="language-bash">$ ./gradlew bootRun</code></pre>
<p>명령어를 실행하면, <code>gradle/wrapper/gradle-wrapper.properties</code> 에 명시되어있는 gradle 버젼이 자동으로 다운 받아지고, spring boot application이 실행되게 된다</p>
<p>실행 끝!</p>
<h3 id="관련-참고-링크">관련 참고 링크</h3>
<p>Gradle 공식 문서: <a href="https://docs.gradle.org/current/samples/sample_building_spring_boot_web_applications.html">https://docs.gradle.org/current/samples/sample_building_spring_boot_web_applications.html</a></p>
<p>Spring 공식 문서: <a href="https://spring.io/guides/gs/gradle/">https://spring.io/guides/gs/gradle/</a></p>
<p>간단한 설명 영상: <a href="https://www.youtube.com/watch?v=zAR3Ahr8VnA">https://www.youtube.com/watch?v=zAR3Ahr8VnA</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ 내 생애 첫 Github Opensource Contribution 도전기]]></title>
            <link>https://velog.io/@minnczi/%EB%82%B4-%EC%83%9D%EC%95%A0-%EC%B2%AB-Github-Opensource-Contribution-%EB%8F%84%EC%A0%84%EA%B8%B0</link>
            <guid>https://velog.io/@minnczi/%EB%82%B4-%EC%83%9D%EC%95%A0-%EC%B2%AB-Github-Opensource-Contribution-%EB%8F%84%EC%A0%84%EA%B8%B0</guid>
            <pubDate>Sun, 28 Nov 2021 11:12:01 GMT</pubDate>
            <description><![CDATA[<h3 id="contribution을-하게-된-계기">Contribution을 하게 된 계기</h3>
<p>엄청 거창한 타이틀을 단 것 같지만, 사실 고작 딱 한 줄의 contribution을 하게 되었다...! 내가 엄청난 기능을 만든것도, 대단한 버그를 고친 것도 아니었지만, 내게는 새롭고, 어려울 줄만 알았던 contribution을 하게 된 계기와 과정을 담아보려고 한다.</p>
<p>1년동안 코딩 교육 과정을 들으면서, 배운 것들을 기록하고, TIL을 정리하는 것을 좋아했다. 그리고 특히나 깃허브의 다양한 활용 방법을 배우기 시작하면서, TIL을 깃허브에 올리고, 깃허브 메인 프로필 페이지를 꾸미고 정리하기 시작했다. 취업을 하면서, 예전보다는 꾸준히 새로운 것들을 배우고 기록하는 것에 소홀해 졌다는걸 느끼기 시작했다.</p>
<p>다시 마음을 잡기 위해, 블로그를 꾸준히 써보기로 마음먹었다. 그리고 우연히, 블로그 게시글 상위 5개를 깃허브 프로필 README에 노출해주는 <a href="https://github.com/gautamkrishnar/blog-post-workflow">blog post workflow</a> 라는 오픈소스 Github Action이 있다는 걸 발견했다. Documentation을 읽어보고, 사용해 보려던 찰나, Velog에 대한 설명은 Documentation에 추가되어 있지 않다는 걸 발견했다. Velog가 한국에서만 널리 사용되는 플랫폼이다 보니, Velog를 사용하는 예제는 추가되어 있지 않았던 것이다. 항상 주어진 것을 주어진 방법대로만 사용하다가, 내가 처음으로 남들이 시도해 보지 않은 것을 해보고, 공유해보는 계기가 될 수도 있다는 생각이 들었다.</p>
<h3 id="과정">과정</h3>
<p>사실 과정은 너무나도 쉬웠다. 현재 기준 4000명이 넘는 유저가 사용하고 있는 Opensource 이기 때문에 Documentation이 정말 잘 작성되어 있었다. 그 중에서, 새로운 기능이나 개선 사항을 추가하고 싶을때 누구나 참여할 수 있도록 Contribution을 하는 방법이 적혀 있어 그 방법대로 하나씩 따라해보기 시작했다.</p>
<h4 id="1-테스트">1. 테스트</h4>
<p>일단, 내가 사용하려는 기능이 잘 돌아가는지 확인해야 했다. 해당 Opensource를 활용하려면 RSS 피드를 제공하는 웹사이트여야 했는데, Velog가 RSS 피드를 제공하는지 먼저 체크해보았다. 그리고 실제 Velog 주소를 넣어서 Action을 수행했을 때 잘 동작하는지 내 깃허브 페이지를 통해 테스트 해보았다.</p>
<pre><code class="language-yml">...
jobs:
  update-readme-with-blog:
    name: Update this repo&#39;s README with latest blog posts
    runs-on: ubuntu-latest
    steps:
      ...
          feed_list: &quot;https://v2.velog.io/rss/minnczi&quot;</code></pre>
<p>이렇게 내 블로그 주소를 넣고 Action을 수행했을 때, 성공적으로 최신 5개 게시물의 제목을 가져온 것을 확인했다.</p>
<p><img src="https://images.velog.io/images/minnczi/post/f8e4ac54-78d2-4200-b487-ae3371e8fd00/Screen%20Shot%202021-11-28%20at%207.19.27%20PM.png" alt=""></p>
<h4 id="2-issue-작성하기">2. Issue 작성하기</h4>
<p>테스트가 성공적으로 작동한 것을 확인하고, 곧바로 Issue를 작성하러 갔다. 이전 이슈들을 참고하여, 새로운  Blog Source를 추가하고 싶다는 내용을 작성해 올렸고, 템플릿에 따라 내 블로그에 적용한 예제를 참고하여 올렸다.
<img src="https://images.velog.io/images/minnczi/post/eda24063-739a-4378-8fd0-c4ec4b2be155/Screen%20Shot%202021-11-28%20at%207.34.26%20PM.png" alt=""></p>
<h4 id="3-pull-request-작성하기">3. Pull Request 작성하기</h4>
<p>이후, 해당 Repository를 Fork 해온 다음, README에 Velog 활용에 대한 내용을 추가했다. 나는 직접적으로 이 Repository를 수정할 수 있는 권한이 없기 때문에, Fork를 통해 복사본을 만들어서 수정 사항을 올린 다음, 원작자에게 Pull Request를 요청하여 실제로 수정 사항이 반영될 수 있도록 한 것이다.</p>
<p>Pull Request를 할 시, 실제로 기능에 큰 변화가 있을 경우, 기존 소스와의 충돌이나 버그가 생길 수 있기 때문에 이와 같이 테스트를 완료 했는지에 대한 간단한 체크리스트와 메세지도 작성했다.
<img src="https://images.velog.io/images/minnczi/post/76e4cb8f-8f3f-4302-84f9-7cae5807ffce/Screen%20Shot%202021-11-28%20at%207.40.54%20PM.png" alt=""></p>
<p>몇시간 후, 바로 원작자분께서 확인을 해주시고, 실제 내가 수정한 README가 원본 소스에 반영될 수 있게 Merge를 해주었다!</p>
<p><img src="https://images.velog.io/images/minnczi/post/1c61d2a8-3972-433f-a922-8cab745c3ce5/Screen%20Shot%202021-11-28%20at%207.42.05%20PM.png" alt=""></p>
<h4 id="4-결과물">4. 결과물</h4>
<p>내가 수정한 Documentation 부분
Velog를 사용할 때는 이렇게 하세요! 라고 한줄 넣어주었다 :)
<img src="https://images.velog.io/images/minnczi/post/fd660080-7572-4f61-9d5b-6a4ea3530258/Screen%20Shot%202021-11-28%20at%207.43.18%20PM.png" alt=""></p>
<p>그리고 당당하게 이름을 올린 한줄짜리 컨트리뷰터ㅋㅋㅋㅋㅋㅋㅋ
<img src="https://images.velog.io/images/minnczi/post/08839dce-7226-4ea6-9018-9a3791083394/Screen%20Shot%202021-11-28%20at%207.47.02%20PM.png" alt=""></p>
<h3 id="느낀점">느낀점</h3>
<ol>
<li><p>생각보다 무섭지 않았다!
&quot;오픈소스&quot; 라는 단어를 들었을 때, 이걸 만드는 사람들은 대단한 사람들이고, 나는 유저의 입장에서 오픈소스를 활용하기만 한다고 생각했었다. 그래서 그런지, 처음에는 오픈소스에 contributing을 한다는 것 자체가 너무 무섭고 두려웠다. 그런데 실상은 나와 같이 불편을 느낀 많은 유저들이 함께 만들어가는 네이버 지식인 같은 느낌이었다.
내가 &quot;이거 고치고 싶어요!&quot; 라고 질문을 올리면 원작자 또는 다른 유저분들이 그것에 대한 응답을 해주시고 소통을 하는 느낌이었다.
그리고 실제로 내가 고친 소스가 바로 반영이 되는 것이 아니라, 여러번의 검토를 거쳐 반영되는 것이기 때문에, 혹시 뭐가 잘못되진 않을까..? 라는 걱정을 하지는 않아도 될 것 같다!</p>
</li>
<li><p>Documentation의 중요성
실제 많은 유저들이 사용하는 서비스를 만드려면 documentation이 정말 중요하다는 사실을 다시 한번 깨달았다. 이 오픈소스의 경우도, contribution을 하는 방법에 대한 설명이 정말 자세히 되어 있었기 때문에, 많은 사람들이 쉽게 contribution을 하고, 이 프로젝트 또한 빨리 발전할 수 있었다는 생각이 들었다.</p>
</li>
<li><p>더 많은 오픈소스에 기여해보고 싶다
이 경험을 계기로 더 많은 오픈소스 프로젝트에 기여해보고 싶다고 생각했다. 그리고 단순히 코멘트를 다는 수준이 아닌, 기능 추가나 버그 수정과 같은 큰 contribution에도 도전해보고 싶다는 생각이 들었다!</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[GitHub Token Authentication으로 바꾸기]]></title>
            <link>https://velog.io/@minnczi/GitHub-Token-Authentication%EC%9C%BC%EB%A1%9C-%EB%B0%94%EA%BE%B8%EA%B8%B0</link>
            <guid>https://velog.io/@minnczi/GitHub-Token-Authentication%EC%9C%BC%EB%A1%9C-%EB%B0%94%EA%BE%B8%EA%B8%B0</guid>
            <pubDate>Sun, 01 Aug 2021 07:57:41 GMT</pubDate>
            <description><![CDATA[<p>Github을 사용하면서 작년부터 많이 받기 시작했던 이메일이 있었다.</p>
<p><img src="https://images.velog.io/images/minnczi/post/44c52847-ec7f-4dc2-bd12-d44bd16474f7/Screen%20Shot%202021-08-01%20at%203.49.20%20PM.png" alt=""></p>
<p>대충 작년 2020년 12월 15일부로 이메일과 비밀번호로 인증하는 방식을 바꾸려고 하는중이고 곧 deprecate 될 예정이라는 이메일이었다. 매번 바꿔야겠다는 생각은 있었지만, 계속 까먹기도하고..ㅎㅎ Git의 기본적인 기능말고는 사용해본적이 많이 없었던터라 미루고 미루던 끝에 드디어 바꿔보기로했다!</p>
<p>끝내고 보니 너무 쉬운 작업이었어서 이걸 왜 이때까지 미루고 있었지 생각이 들었다..</p>
<h3 id="1-토큰-발급받기-generate-token">1. 토큰 발급받기 (Generate Token)</h3>
<p>Github 공식 홈페이지에서 제공하는 <a href="https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token">해당 링크</a>에 스크린샷과 함께 자세한 설명이 나와있어서 토큰을 발급받는 부분은 전혀 어렵지 않게 할 수 있었다!</p>
<blockquote>
<p> <code>홈페이지 우측 상단에 프로필 아이콘 &gt; Settings &gt; Developer settings &gt; Personal access tokens &gt; Generate new token</code> 순서로 클릭해 토큰을 받급받는 페이지로 이동할 수 있다.</p>
</blockquote>
<p>이 페이지에서는 해당 토큰을 사용하는 사람이 얼만큼의 권한을 가질 수 있는지에 대한 scope을 지정할 수 있는데 써보지 않아 내가 필요한 기능들을 수행하기 위해서는 어떤 권한들이 필요할지에 대한 궁금증이 생겼다.</p>
<h4 id="1-1-scope-설정하기">1-1. Scope 설정하기</h4>
<p>Github <a href="https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps">공식 문서</a>를 통해 다양한 권한들에 대한 설명을 볼 수 있었다. 그 중 내가 필요로 하는 주요로 하는 기능들은:</p>
<ul>
<li><code>repo</code>: repository에 대한 접근 / 통제 권한 - 이 카테고리에 있는 기능들만 포함해도 일상적인 git으로 활용하는 기능들은 거의 전부 수행할 수 있다<ul>
<li><code>repo:status</code>: public / private repo에 대한 커밋 기록을 볼 수 있는 권한 부여</li>
<li><code>public_repo</code>: public repo에 대한 모든 권한 부여 (push, pull, fetch 등등..)</li>
</ul>
</li>
<li><code>admin:org</code>: Organization에 대한 권한 부여<ul>
<li><code>write:org</code>: organization의 멤버 관리, 프로젝트 관리등의 권한 부여</li>
<li><code>read:org</code>: organization에 있는 멤버, 프로젝트를 볼 수 있는 권한 부여</li>
</ul>
</li>
<li><code>delete_repo</code>: 레포지토리 삭제 권한 부여</li>
</ul>
<p>여기서 신기했던건 token access를 통해서는 내가 할 수 있는 액션만 제한할 수 있을 뿐, <strong>어떤 repository에 대한 권한을 부여할지 선택적으로 제한할 수는 없다는 것이었다</strong>. 이런 기능을 활용하려면 <code>deploy key</code> 라는걸 활용해야된다는데 이건 다음번에 기회가 있으면 활용해 보는걸로..</p>
<p>나는 나 혼자만 활용할 내 repository들에 대한 권한이 필요했기 때문에 모든 권한을 부여했다!</p>
<h4 id="1-2-발급-받은-토큰-저장하기">1-2. 발급 받은 토큰 저장하기</h4>
<p><code>Generate token</code> 버튼을 누르면 방금 발급받은 토큰을 볼 수 있는데, <strong>이번 한번만 볼수 있으니 꼭 저장해놓아야된다!</strong></p>
<h3 id="2-기존-remote-연결-삭제하기">2. 기존 remote 연결 삭제하기</h3>
<p>터미널 창을 켜서 git repository와 연결되어 있는 가장 상단 폴더로 이동해준다</p>
<p>여기에서 <code>git remote -v</code>라는 명령어를 입력하면 현재 연결되어 있는 remote repository의 정보를 보여준다. 현재는 다음과 같은 형태로 url이 설정되있다.</p>
<pre><code class="language-bash">$ git remote -v

origin https://github.com/&lt;유저 또는 org 이름&gt;/&lt;repo 이름&gt; (fetch)
origin https://github.com/&lt;유저 또는 org 이름&gt;/&lt;repo 이름&gt; (push)</code></pre>
<p>아래 명령어를 사용해 현재 remote 연결을 삭제한다 (앞 단계에서 url 앞에 적혀있는 키워드가 remote의 이름이다 - 이름이 origin이 아니라면 remote의 현재 이름을 사용)</p>
<pre><code class="language-bash">$ git remote remove origin</code></pre>
<h3 id="3-token을-활용해-remote-repository를-다시-연결하기">3. Token을 활용해 remote repository를 다시 연결하기</h3>
<p>터미널 창에서 아래 명령어를 입력한다</p>
<pre><code class="language-bash">$ git remote add origin https://&lt;토큰&gt;/&lt;유저 또는 org 이름&gt;/&lt;repo 이름&gt;</code></pre>
<ul>
<li>여기서 토큰 뒷부분을 어떻게 적어야할지 확실히 잘 모르겠다면, 원하는 repository의 github 페이지로 들어가서 url의 <code>https://github.com/</code> 뒷부분을 복사해서 쓰면 된다.</li>
</ul>
<p>다시 <code>git remote -v</code> 명령어를 사용했을때 아까랑은 다르게 토큰이 포함된 url이 설정된 것을 볼 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Java 기본 문법: 클래스와 객체 (Class and Objects)]]></title>
            <link>https://velog.io/@minnczi/Java-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%99%80-%EA%B0%9D%EC%B2%B4-Class-and-Objects</link>
            <guid>https://velog.io/@minnczi/Java-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%99%80-%EA%B0%9D%EC%B2%B4-Class-and-Objects</guid>
            <pubDate>Mon, 07 Jun 2021 14:57:21 GMT</pubDate>
            <description><![CDATA[<p>클래스란 쉽게 말해 <u>공통 된 특징을 가진 데이터들을 묶어서 관리하는 것이다</u>. 자바에서는 <u>클래스도 하나의 타입이다</u> - int와 String 타입의 변수를 선언해서 그 안에 값을 넣을 수 있듯이, 자바에서는 클래스를 타입으로 가지는 변수를 만들어 그 안에 해당 클래스의 객체를 넣을 수 있다</p>
<p>이 클래스가 객체 지향 프로그래밍에서 가장 기초가 되는 개념 중 하나이다.</p>
<h3 id="클래스-vs-객체">클래스 vs. 객체</h3>
<p><strong>클래스:</strong> 공통된 특징을 갖고 있는 데이터들을 하나의 단위로 묶어서 관리하는 것</p>
<p><strong>객체</strong>: 각 클래스의 속성을 가지고 만들어 진 객체 하나하나</p>
<p>*<em>필드: *</em>해당 클래스가 가질수 있는 속성들, 해당 클래스의 특징들을 말한다</p>
<h3 id="클래스-및-객체-생성하기">클래스 및 객체 생성하기</h3>
<ol>
<li>클래스를 정의한다<ul>
<li>이때까지 봤던 파일들과들 다르게 메인함수(<code>public static void main(String[] args)</code>) 에 넣는것이 아닌 일반 클래스 함수에 넣어 정의한다</li>
</ul>
</li>
</ol>
<pre><code class="language-java">// Person1.java
package Section1;

public class Person1 {
    public String name; // field, data member
    public String number;
}</code></pre>
<ol start="2">
<li><p>정의한 클래스를 활용해서 새로운 객체를 생성한다</p>
<ul>
<li>앞에서 정의한 클래스를 데이터 타입처럼 활용하여 새로운 객체를 생성한다</li>
</ul>
<pre><code class="language-java">// Code1.java
package Section1;
</code></pre>
</li>
</ol>
<p>public class Code1 {</p>
<pre><code>public static void main(String[] args) {
// first라는 이름의 Person1 객체를 생성한다
// 1. 생성 후 초기화 하기
Person1 first; // 생성
first = new Person1(); // 초기화 - 실제로 새로운 객체가 생성됨

// 2. 생성과 초기화를 동시에 하기
    Person1 first = new Person1();

// 생성된 객체의 필드 수정하기
    first.name = &quot;John&quot;;
    first.number = &quot;010-1234-1234&quot;;
}</code></pre><p>}</p>
<pre><code>


3. 생성한 객체의 필드를 수정한다

```java
// Code1.java
package Section1;

public class Code1 {

    public static void main(String[] args) {
    ...
    // 이름과 전화번호 수정하기
        first.name = &quot;John&quot;;
        first.number = &quot;010-1234-1234&quot;;
    }
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Java 기본 문법: 배열(Array)]]></title>
            <link>https://velog.io/@minnczi/Java-%EA%B8%B0%EB%B3%B8%EB%AC%B8%EB%B2%95-%EB%B0%B0%EC%97%B4</link>
            <guid>https://velog.io/@minnczi/Java-%EA%B8%B0%EB%B3%B8%EB%AC%B8%EB%B2%95-%EB%B0%B0%EC%97%B4</guid>
            <pubDate>Mon, 07 Jun 2021 14:55:59 GMT</pubDate>
            <description><![CDATA[<h4 id="배열array-이란">배열(Array) 이란?</h4>
<p>가장 많이 쓰이고 다양하게 활용될 수 있는 자료구조 중 하나인 배열! Java에서는 <strong>동일한 타입의 데이터</strong>들을 묶어서 저장하기 위해 배열 (Array)을 활용한다.</p>
<p>자바에서는 배열을 <strong>선언, 생성, 초기화</strong> 하는 과정을 거쳐 비로소 배열이 만들어진다</p>
<h4 id="배열-선언">배열 선언</h4>
<p>생성된 배열을 다루게 될 참조 변수를 설정 - 이때 실제로 배열이 저장될 메모리나 주소가 할당되는것은 아니다!</p>
<pre><code class="language-java">// 배열 선언
int[] arr1;
int arr2[];</code></pre>
<h4 id="배열-생성">배열 생성</h4>
<p>배열의 크기를 직접 지정해 줌으로써 실제로 값을 저장할 공간 생성</p>
<ul>
<li>long, double, integer, Long, Double, String등의 타입을 사용할 수 있음</li>
<li>사용되는 타입에 따라 배열의 값이 특정 값으로 초기화 됨</li>
</ul>
<pre><code class="language-java">// 배열 생성
arr1 = new int[5];

// 배열 선언 + 생성
int[] arr3 = new int[5];</code></pre>
<h4 id="배열의-값을-초기화">배열의 값을 초기화</h4>
<pre><code class="language-java">// 이미 선언 + 생성된 배열의 값 초기화
for (int i=0, i&lt;5, i++)
  arr1[i] = i

// 배열 선언 + 생성 + 초기화
int[] arr4 = {1, 2, 3, 4, 5};
int[] arr5 = new int[] {1, 3, 5, 7, 9};</code></pre>
<p>출처:</p>
<p><a href="https://m.blog.naver.com/alcmskfl17/221731876315">https://m.blog.naver.com/alcmskfl17/221731876315</a></p>
<p><a href="https://ifuwanna.tistory.com/231">https://ifuwanna.tistory.com/231</a></p>
<p><a href="https://joy-baek.tistory.com/47">https://joy-baek.tistory.com/47</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Java 기본 문법: 데이터 타입, 변수 (Data Type, Variables)]]></title>
            <link>https://velog.io/@minnczi/Java-%EA%B8%B0%EB%B3%B8%EB%AC%B8%EB%B2%95-%EB%B3%80%EC%88%98-Variables</link>
            <guid>https://velog.io/@minnczi/Java-%EA%B8%B0%EB%B3%B8%EB%AC%B8%EB%B2%95-%EB%B3%80%EC%88%98-Variables</guid>
            <pubDate>Sat, 22 May 2021 12:10:03 GMT</pubDate>
            <description><![CDATA[<p>프로그래밍 언어에 있어서 가장 기초적인 개념이 되는것들 중 하나가 변수이다.</p>
<blockquote>
<p>변수란, 어떤 값을 저장하기 위한 껍데기와 같은 역할을 해주는 것이고, 이 껍데기 안에는 숫자, 문자, 배열 등등 다양한 종류의 데이터들이 저장될 수 있다.</p>
</blockquote>
<p>앞으로 올 여러 포스팅에서는 다양한 데이터 타입과 각각의 데이터 타입으로 할 수 있는 것들을 더욱 자세히 살펴 볼 예정이다.</p>
<h3 id="데이터-타입">데이터 타입</h3>
<p>데이터는 크게 원시 타입과 참조 타입으로 나누어지는데, 이 둘의 가장 큰 차이점은 <strong>원시 타입 객체는 데이터 그 자체가 저장되는 반면, 참조 타입 객체는 데이터가 저장되어있는 주소가 저장된다는 것이다</strong>.</p>
<table>
<thead>
<tr>
<th>원시 타입 (Primitive Type)</th>
<th>참조 타입 (Reference Type)</th>
</tr>
</thead>
<tbody><tr>
<td>- byte<br />- short / long<br />- int<br />- double<br />- float<br />- char<br />- boolean<br />- String6<br /></td>
<td>- array</td>
</tr>
</tbody></table>
<h3 id="변수-선언-문법">변수 선언 문법</h3>
<ul>
<li><strong>지역 변수 (main 함수 안)</strong>: <code>&lt;type&gt; &lt;변수_이름&gt; = &lt;값&gt;</code> 의 형태로 변수를 선언할 수 있다</li>
<li><strong>전역 변수 (main 함수 밖)</strong>: static 키워드를 붙여서 전역 변수를 선언 할 수 있다 </li>
</ul>
<pre><code class="language-java">// main 함수 밖에서 변수 선언
static int num1 = 3

public static void main(String[] args) {
  // main 함수 안에서 원시 타입 변수 선언
  int num2 = 5;
  // main 함수 안에서 참조 타입 변수 선언
  int[] numList = new int[5];
}</code></pre>
<h3 id="변수-계산-과정">변수 계산 과정</h3>
<p>다른 타입을 가진 변수들이 계산되는 과정에서 자바는 다양한 타입에 형변환을 진행해서 결과값을 계산한다</p>
<ul>
<li>left associativity: 왼쪽부터 오른쪽의 순서로 계산</li>
<li>str + int를 할때는 자동으로 int를 str으로 변환해서 계산한다</li>
</ul>
<pre><code class="language-java">public static void main(String[] args) {
  int num1 = 2;
  int num2 = 3;

  System.out.println(num1 + num2) // 5
     System.out.println(&quot;Num1 value: &quot; + num1) // Num1 value: 2
  System.out.println(&quot;Num1 value: &quot; + num1 + num2) // Num1 value: 25
  System.out.println(&quot;Num1 value: &quot; + (num1 + num2)) // Num1 value: 7
}</code></pre>
<h3 id="변수의-적용-스코프">변수의 적용 스코프</h3>
<p>특정 변수를 어디에서 사용할 수 있는지(적용 범위)를 <strong>스코프</strong>라고 하는데, 변수가 선언된 위치에 따라서 다른 스코프를 가진다.</p>
<ul>
<li>메서드 내부 (블록 안에서) 선언된 변수 --&gt; 해당 메서드 안에서만 사용 가능 (<strong>블록 스코프</strong>)</li>
<li>메서드 외부 (클래스 내부)에서 선언된 변수 --&gt; 클래스 내에서 사용 가능 (<strong>전역 스코프</strong>)</li>
</ul>
<h3 id="input을-입력받는-방법">input을 입력받는 방법</h3>
<p>변수를 입력해주는 방법도 있지만, 사용자로 부터 input을 받아야 되는 상황이 많이 있다. Java에서는 input을 입력 받기 위해 다양한 방법을 사용할 수 있는데 그 중 가장 간단한 방법 중 하나인 Scanner를 사용해서 input을 받을 수 있다.</p>
<p>어떤 타입의 데이터를 입력받을 지에 따라 다른 메서드를 활용하여 적절하게 데이터를 받아올 수 있다.</p>
<p><strong>정수 입력 받기</strong></p>
<ul>
<li><code>Scanner.nextInt()</code></li>
</ul>
<pre><code class="language-java">// 스캐너 import 해오기 
import java.util.Scanner

public class Code {

  public static void main(String[] args) {
    Scanner kb = new Scanner( System.in ); // 새로운 스캐너 생성
    int input = kb.nextInt(); // 입력받은 정수를 변수에 할당
    kb.close(); // 스캐너 사용이 완료되면 스캐너를 종료하기
  }

}</code></pre>
<p><strong>문자열 입력 받기</strong></p>
<ul>
<li><code>scanner.next()</code>: 공백을 기준으로 한 단어씩 끊어서 읽어오기</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Django로 CRUD 웹사이트 만들기 1: 프로젝트 시작하기 ]]></title>
            <link>https://velog.io/@minnczi/Django%EB%A1%9C-CRUD-%EC%9B%B9%EC%82%AC%EC%9D%B4%ED%8A%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0-1-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@minnczi/Django%EB%A1%9C-CRUD-%EC%9B%B9%EC%82%AC%EC%9D%B4%ED%8A%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0-1-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 02 May 2021 16:23:34 GMT</pubDate>
            <description><![CDATA[<h3 id="static-vs-dynamic-website">Static vs. Dynamic Website</h3>
<p><strong>Static</strong>: 정해진 것 만을 제공해 주는 웹사이트</p>
<p><strong>Dynamic</strong>: DB와의 통신을 거쳐서 사용자가 원하는 데이터를 동적으로 제공해 주는 웹사이트</p>
<p>장고의 경우 DB와의 통신까지 지원하는 server side framework이다</p>
<h3 id="django의-기본-동작-원리">Django의 기본 동작 원리</h3>
<p><strong>Model</strong>: 데이터를 관리 해주는 역할 (MVC에서 Model과 같은 역할)</p>
<p><strong>Template</strong>: 보여지는 페이지를 만드는 역할 (MVC에서 View와 같은 역할)</p>
<p><strong>View</strong>: 어떤 동작을 수행할지 알려주는 중간 관리자 (MVC에서 Controller와 같은 역할)</p>
<p><strong>(+) urls.py:</strong> 어떤 특정 경로로 들어온 요청이 어느 view로 연결될지 알려주는 기능</p>
<p><strong>요청 처리 순서</strong>: urls를 통한 요청 ---&gt; view 함수로 연결 --&gt; model에서 필요 정보 수집 --&gt; template render</p>
<p><img src="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Introduction/basic-django.png" alt="basic-django"></p>
<h3 id="가상환경-설정하기-선택">가상환경 설정하기 (선택)</h3>
<p>선택사항이지만 프로젝트의 독립적인 관리를 위해서는 가상환경을 사용하는것이 좋다!</p>
<p>각 프로젝트마다 필요한 패키지, 버젼등등이 다를 수 있기 때문에 새로운 가상환경을 하나 설치에서 그 가상환경안에 알맞는 버젼의 패키지를 깔아주면 된다</p>
<ol>
<li>가상환경 생성</li>
</ol>
<pre><code class="language-bash">$ python -m venv venv</code></pre>
<ol start="2">
<li>가상환경 activate</li>
</ol>
<pre><code class="language-bash">$ source venv/bin/activate</code></pre>
<ol start="3">
<li>장고 설치</li>
</ol>
<pre><code class="language-bash">$ pip install django</code></pre>
<ol start="4">
<li>(optional) 진행되고 있는 프로젝트를 받아와서 requirements 파일이 이미 있는 경우</li>
</ol>
<pre><code class="language-bash">$ pip install -r requirements.txt</code></pre>
<h3 id="장고-프로젝트-시작하기">장고 프로젝트 시작하기</h3>
<p>터미널에서 다음 코드를 입력하면 된다</p>
<pre><code class="language-bash">$ django-admin startproject &lt;project_name&gt;</code></pre>
<p>crud라는 이름의 프로젝트를 만드려면:</p>
<pre><code class="language-bash">$ django-admin startproject crud</code></pre>
<h4 id="새로운-앱-추가하기">새로운 앱 추가하기</h4>
<p><strong>App</strong>: 장고 안에서 특정 기능을 수행하는 모듈들의 단위</p>
<ol>
<li>앱을 생성한다: articles와 accounts라는 이름의 앱을 생성해준다</li>
</ol>
<pre><code class="language-bash">$ python manage.py startapp articles
$ python manage.py startapp accounts</code></pre>
<ol start="2">
<li>settings.py 파일안에 installed apps에 방금 만든 app을 추가한다</li>
</ol>
<pre><code class="language-python">INSTALLED_APPS = [
    # 1. local apps
      &#39;accounts&#39;,
    &#39;articles&#39;,
    # 2. 3rd-party apps
    # 3. django apps
    &#39;django.contrib.admin&#39;,
    &#39;django.contrib.auth&#39;,
    &#39;django.contrib.contenttypes&#39;,
    &#39;django.contrib.sessions&#39;,
    &#39;django.contrib.messages&#39;,
    &#39;django.contrib.staticfiles&#39;,
]</code></pre>
<p><strong>최종 파일 트리 모양</strong></p>
<p><img src="https://images.velog.io/images/minnczi/post/7f0f1180-54bf-430a-bb4b-f3dfdb550046/Screen%20Shot%202021-05-03%20at%201.19.34%20AM.png" alt=""></p>
<h3 id="settingspy-설정하기">Settings.py 설정하기</h3>
<p>기본적인 세팅과 더불어 다음과 같이 추가 설정을 해준다</p>
<ol>
<li>언어와 지역 설정을 지역에 알맞게 해준다. 한국의 경우:</li>
</ol>
<pre><code class="language-python">LANGUAGE_CODE = &#39;ko-kr&#39;

TIME_ZONE = &#39;Asia/Seoul&#39;</code></pre>
<ol start="2">
<li>기본 templated을 찾을 수 있는 template 경로를 설정해준다</li>
</ol>
<pre><code class="language-python">TEMPLATES = [
  {
    &#39;DIRS&#39;: [
      BASE_DIR / &#39;&lt;app_name&gt;&#39; / &#39;templates&#39;
    ]
  }
]</code></pre>
<ol start="3">
<li><p>Base User Model을 대체해준다 (나중에 회원가입, 로그인 기능에 필요한 User 모델을 초기 프로젝트를 만들때 대체 설정을 해줘야한다 -- 나중에는 매우 고치기 힘듬!)</p>
<ol>
<li>accounts/models.py에 다음 코드를 추가한다</li>
</ol>
<pre><code class="language-python">from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    pass</code></pre>
<ol start="2">
<li>settings.py 맨 밑에 다음 한줄을 추가한다</li>
</ol>
<pre><code class="language-python">AUTH_USER_MODEL = &#39;accounts.User&#39;</code></pre>
</li>
</ol>
<h4 id="장고-서버-실행하기">장고 서버 실행하기</h4>
<pre><code class="language-bash"># manage.py가 있는 프로젝트 root_folder 안에서 실행해야함
$ pwd
~/&lt;project_root_folder&gt;

$ python manage.py runserver</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Javascript 기초 문법 1: 변수, 데이터 타입]]></title>
            <link>https://velog.io/@minnczi/Javascript-%EA%B8%B0%EC%B4%88-%EB%AC%B8%EB%B2%95-1-%EB%B3%80%EC%88%98-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85</link>
            <guid>https://velog.io/@minnczi/Javascript-%EA%B8%B0%EC%B4%88-%EB%AC%B8%EB%B2%95-1-%EB%B3%80%EC%88%98-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85</guid>
            <pubDate>Sun, 02 May 2021 12:49:24 GMT</pubDate>
            <description><![CDATA[<h2 id="변수-선언하기">변수 선언하기</h2>
<h3 id="var-vs-const-vs-let">var vs. const vs. let</h3>
<p><code>var</code>: ES6 이전에 쓰였던 유일한 변수 선언법으로 ES6 이후로는 사용이 권장되지 않고 있다</p>
<p><code>const</code>: constant의 줄임말로, 변하지 않는 값을 저장할때 주로 사용되므로 재선언, 재할당이 둘다 허용되지 않는다</p>
<p><code>let</code>: 재선언은 불가능하지만 재할당은 가능하다</p>
<table>
<thead>
<tr>
<th></th>
<th>const</th>
<th>let</th>
<th>var</th>
</tr>
</thead>
<tbody><tr>
<td>재선언 / 재할당</td>
<td>재선언: 불가능<br />재할당: 불가능</td>
<td>재선언: 불가능<br />재할당: 가능</td>
<td>재선언: 가능<br />재할당: 가능</td>
</tr>
<tr>
<td>스코프**</td>
<td>블럭 스코프</td>
<td>블럭 스코프</td>
<td>함수 스코프</td>
</tr>
</tbody></table>
<p>위와 같은 차이점을 코드로 봤을때는 이런 형태이다</p>
<pre><code class="language-javascript">const a = 1
const a = 2 // 재선언: 에러
a = 3 // 재할당: 에러

let b = 1
let b = 2 // 재선언: 에러
b = 3 // 재할당: 가능

var c = 1
var c = 2 // 재선언: 가능
c = 3 // 재할당: 가능</code></pre>
<h3 id="변수를-선언하는-다양한-문법">변수를 선언하는 다양한 문법</h3>
<p>Javascript에서는 변수 선언하고 할당하는 행위가 나눠져 있다</p>
<ul>
<li><strong>Declaration</strong> (선언): 변수 (껍데기) 생성하는 것</li>
<li><strong>Assignment</strong> (할당): 선언된 변수에 실제 값을 저장하는 것</li>
<li><strong>Initialization</strong> (초기화): 변수에 처음에 값을 저장하는 시점 또는 행위</li>
</ul>
<pre><code class="language-javascript">// 선언과 할당을 개별적으로 하는 코드
// 1. 선언
let a
// 2. 할당
a = 1 // 초기화 시점

// 선언과 할당을 동시에 하는 코드
let b = 2 // 초기화 시점</code></pre>
<h2 id="데이터-타입">데이터 타입</h2>
<h3 id="primitive-vs-reference">primitive vs. reference</h3>
<p>크게 Primitive Type과 Reference Type 두가지로 나뉜다</p>
<table>
<thead>
<tr>
<th></th>
<th>Primitive Type</th>
<th>Reference Type</th>
</tr>
</thead>
<tbody><tr>
<td>특징</td>
<td>- Object가 아닌 기본 타입<br />- 실제 값 자체가 담긴다<br />- 복사시 실제 값이 담긴다</td>
<td>- Object 형태<br />- 값의 주소가 저장된다<br />- 복사시 참조 값이 복사된다</td>
</tr>
<tr>
<td>예시</td>
<td>숫자, 문자열, undefined, null, Boolean</td>
<td>객체(object), 함수(function), 배열(array)</td>
</tr>
</tbody></table>
<h3 id="할당-연산자">할당 연산자</h3>
<p>데이터에 연산을 하면서 새로운 값을 할당하는 연산자이다</p>
<pre><code class="language-javascript">let x = 0

// 파이썬과 동일하게 다음과 같은 연산을 할 수 있다
x += 1
x -= 1
x *= 10
x /= 10

// x의 값을 1씩 증가 또는 감소 시키는 다음과 같은 연산도 할 수 있다
// 주로 for, while loop에서 값을 1씩 증가시키면서 looping을 할때 쓰인다
x++
x--</code></pre>
<h3 id="비교-연산자">비교 연산자</h3>
<p>Javascript에서는 두가지 타입의 비교연산이 존재한다</p>
<ul>
<li><p><strong>동등 비교 연산자 (==)</strong>: Javascript에서 내부적으로 형변환이 진행되어, 형 변환 된 값이 같은지 다른지를 비교한다</p>
<ul>
<li><p>Boolean 값과 비교시 각 데이터 타입은 다음과 같이 변환된다 (<a href="https://tc39.es/ecma262/#sec-ecmascript-language-types-boolean-type">출처</a>)</p>
<table>
<thead>
<tr>
<th>Type</th>
<th>false</th>
<th>true</th>
</tr>
</thead>
<tbody><tr>
<td>Undefined</td>
<td>항상</td>
<td>X</td>
</tr>
<tr>
<td>Null</td>
<td>항상</td>
<td>X</td>
</tr>
<tr>
<td>Boolean</td>
<td>false</td>
<td>true</td>
</tr>
<tr>
<td>Number</td>
<td>+0, -0, NaN</td>
<td>그 외 모든 경우</td>
</tr>
<tr>
<td>String</td>
<td>빈 문자열(&quot;&quot;)</td>
<td>그 외 모든 경우</td>
</tr>
<tr>
<td>Symbol</td>
<td>X</td>
<td>항상</td>
</tr>
<tr>
<td>BigInt</td>
<td>0</td>
<td>그 외 모든 경우</td>
</tr>
<tr>
<td>Object</td>
<td>X</td>
<td>항상</td>
</tr>
</tbody></table>
</li>
</ul>
</li>
<li><p><strong>일치 비교 연산자 (===)</strong>: 형변환을 하지 않고, 엄격한 비교(데이터의 값과 타입을 모두 비교)가 이루어진다</p>
</li>
</ul>
<h3 id="논리-연산자">논리 연산자</h3>
<ul>
<li><code>&amp;&amp;</code>: and 연산자</li>
<li><code>||</code>: or 연산자</li>
<li><code>!</code>: not 연산자</li>
<li>단축 평가를 지원한다: 비교 대상중 하나만 비교했을때도 그 결과값을 알 수 있을때, 더 이상 비교를 진행하지 않고 바로 결과값을 반환</li>
</ul>
<h3 id="삼항-연산자">삼항 연산자</h3>
<ul>
<li>세 개의 피연산자를 사용해 true / false 여부에 따라 값을 반환하는 연산자</li>
<li><code>(a ? b : c)</code>: a의 조건식이 참이라면 b를 반환, 거짓이라면 c를 반환</li>
</ul>
<pre><code class="language-javascript">console.log(true ? 1 : 2) // true</code></pre>
<p>python 문법에서 다음과 동일하다</p>
<pre><code class="language-python">a = true
print(1 if a==True else 2)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Django REST Framework (DRF)로 REST API 구축하기]]></title>
            <link>https://velog.io/@minnczi/Django-REST-Framework-DRF%EB%A1%9C-REST-API-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@minnczi/Django-REST-Framework-DRF%EB%A1%9C-REST-API-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 29 Apr 2021 12:13:30 GMT</pubDate>
            <description><![CDATA[<h3 id="api--rest-api란">API / REST API란?</h3>
<p><strong>API (Application Programming Interface)</strong>란 운영 체제나 프로그래밍 언어가 제공하는 기능을 제어할 수 있게 만든 인터페이스를 말한다. 즉, 코드를 통해 다른 시스템에서 제공하는 기능이나 서비스를 쉽게 사용할 수 있도록 도와주는 시스템과 시스템간의 인터페이스이다.</p>
<p>예를들어, 카카오 지도 같은 Open API를 생각해보면, 우리가 직접 지도의 기능을 개발하지 않아도, 카카오에서 제공하는 기본적인 지도의 기능들을 내가 작성하는 웹사이트에서 활용할 수 있다.</p>
<p><strong>REST(Representational State Transfer) API</strong>란 웹 설계의 장점을 활용할 수 있는 아키텍쳐 방법론중에 하나로 URI와 HTTP Method를 활용해 자원을 표현한다.</p>
<ul>
<li><strong>URI:</strong> 지정된 자원들을 가져올 수 있는 주소</li>
<li><strong>HTTP Method:</strong> 특정 자원에 대한 행위 (조회, 수정, 삭제...)<ul>
<li><strong>GET</strong>: 데이터를 받기 위한 메서드</li>
<li><strong>POST</strong>: 서버로 데이터를 전송하여 변경하는 메서드</li>
<li><strong>PUT</strong>: 요청한 주소의 자원을 수정하기 위한 메서드</li>
<li><strong>DELETE</strong>: 자원을 삭제하기 위한 메서드</li>
</ul>
</li>
<li>최종적으로 JSON 형태로 필요한 API를 client에게 제공해 준다</li>
</ul>
<p><strong>Django REST Framework</strong>란 Python 기반의 Django로 REST API를 생성할 수 있도록 도와주는 프레임워크이다.</p>
<ul>
<li><strong>Serializer</strong>: DRF에서는 Serializer를 사용하여 내부적으로 사용하는 Queryset을 JSON으로 쉽게 변환 가능한 Python의 데이터 타입으로 바꿔주는 역할을 한다<ul>
<li>ModelSerializer 클래스를 제공하여 Django의 Model을 기반으로 데이터를 serializer 해준다</li>
</ul>
</li>
</ul>
<p><img src="https://www.seobility.net/en/wiki/images/f/f1/Rest-API.png" style="width: 80%;"></img></p>
<h3 id="rest-api-설계하기">REST API 설계하기</h3>
<p><strong>RESTful한 API 설계시 주의할 점</strong></p>
<ol>
<li>하이픈(-) 사용하기</li>
<li>소문자 사용하기</li>
<li>파일 확장자는 포함하지 않기</li>
<li>Method를 통해 정의되어있는 행위에 대한 표현을 URI에 중복적으로 표현하지 않기</li>
</ol>
<h3 id="drf로-rest-api-구축하기">DRF로 REST API 구축하기</h3>
<ol>
<li><p>DRF를 설치한다</p>
<pre><code class="language-bash">$ pip install djangorestframework</code></pre>
</li>
<li><p>settings.py 파일에 DRF를 추가한다</p>
<pre><code class="language-python"># settings.py
INSTALLED_APPS = [
  ...
     &#39;rest_framework&#39;,
]</code></pre>
</li>
<li><p><code>urls.py</code> 에 API 경로를 추가한다</p>
<pre><code class="language-python"># urls.py
urlpatterns = [
      ...
    path(&#39;json/&#39;, views.article_json),
]</code></pre>
</li>
<li><p>Serializer 기능을 사용하기 위해 추가적으로 model이 있는 app 폴더 안에 <code>serializers.py</code> 파일을 만들어 준다</p>
</li>
<li><p><code>serializers.py</code>에 serializer를 추가한다</p>
<pre><code class="language-python"># serializers.py
from rest_framework import serializers
from .models import Article

class ArticleSerializer(serializers.ModelSerializer):
  class Meta:
    model = Article
    fields = &#39;__all__&#39;</code></pre>
</li>
<li><p><code>views.py</code> 에서 serializer를 활용해 API를 제공한다</p>
<pre><code class="language-python">from rest_framework.response import Response
from rest_framework.decorators import api_view

from .models import Article
from .serializers import ArticleSerializer

# http method 정의
@api_view([&#39;GET&#39;])
def article_json(request):
  articles = Article.objects.all() # 모델 데이터
  serializer = ArticleSerializer(articles, many=True) # serializer
  return response(serializer.data)</code></pre>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Javascript Manipulation (DOM 조작)]]></title>
            <link>https://velog.io/@minnczi/Javascript-2</link>
            <guid>https://velog.io/@minnczi/Javascript-2</guid>
            <pubDate>Wed, 28 Apr 2021 12:37:27 GMT</pubDate>
            <description><![CDATA[<h3 id="dom-조작으로-할-수-있는-것들">DOM 조작으로 할 수 있는 것들</h3>
<ol>
<li>DOM 만들기</li>
<li>Child 추가하기</li>
<li>DOM 안에 있는 text 바꾸기</li>
<li>DOM의 attribute 바꾸기</li>
<li>DOM 삭제하기</li>
</ol>
<h3 id="manipulation-예제-코드">Manipulation 예제 코드</h3>
<h5 id="1-dom-만들기">1. DOM 만들기</h5>
<pre><code class="language-javascript">const ul = document.createElement(&#39;ul&#39;)
const li1 = document.createElement(&#39;li&#39;)
const li2 = document.createElement(&#39;li&#39;)</code></pre>
<h5 id="2-child-추가하기">2. Child 추가하기</h5>
<pre><code class="language-javascript">body.appendChild(ul)
ul.append(li1, li2)</code></pre>
<h5 id="3-dom-안에-있는-text-바꾸기">3. DOM 안에 있는 text 바꾸기</h5>
<pre><code class="language-javascript">li1.innerText = &#39;Hello&#39;
li2.innerHTML = &#39;&lt;strong&gt;Hello&lt;/strong&gt;&#39;</code></pre>
<h5 id="4-dom의-attribute-바꾸기">4. DOM의 attribute 바꾸기</h5>
<pre><code class="language-javascript">li1.style.color = &#39;blue&#39;
li2.setAttribute(&#39;id&#39;, &#39;myId&#39;)</code></pre>
<h5 id="5-dom-삭제하기">5. DOM 삭제하기</h5>
<pre><code class="language-javascript">li1.remove()</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Javascript DOM Selector (선택자)]]></title>
            <link>https://velog.io/@minnczi/Javascript-1</link>
            <guid>https://velog.io/@minnczi/Javascript-1</guid>
            <pubDate>Wed, 28 Apr 2021 12:23:20 GMT</pubDate>
            <description><![CDATA[<h3 id="dom이란">DOM이란?</h3>
<p><strong>HTML</strong> 요소들을 <strong>구조화해서 표현한 인터페이스</strong>, 프로그래밍 언어를 통해 DOM 구조에 쉽게 접근할 수 있는 방법을 제공하여 문서의 구조, 스타일, 내용등을 변경할 수 있도록 돕는다.</p>
<p>대표적으로 Javascript를 활용해 DOM의 각 object에 접근하여 선택, 수정할 수 있다.</p>
<h3 id="queryselector--queryselectorall">querySelector / querySelectorAll</h3>
<ul>
<li>Class, Id, TagName 등등 <strong>다양한 속성을 통해 DOM</strong>을 가져올 수 있다</li>
<li>querySelector는 <strong>단일 Object</strong> (여러개가 있다면 그 중 첫번째 조건에 부합하는 object)를 가져온다</li>
<li>querySelectorAll은 조건에 맞는 <strong>모든 Object</strong>를 <strong>NodeList</strong>의 형태로 가져온다</li>
</ul>
<pre><code class="language-javascript">// 첫 번째 일치하는 요소 가져오기
const selectOneByClass = document.querySelector(&#39;.myclass&#39;)
const selectOneById = document.querySelector(&#39;#myid&#39;)
const selectOneByTag = document.querySelector(&#39;body &gt; h1&#39;)

// 모든 요소 가져오기
const selectAllByClass = document.querySelectorAll(&#39;.myclass&#39;)
const selectAllById = document.querySelectorAll(&#39;#myid&#39;)
const selectAllByTag = document.querySelectorAll(&#39;body &gt; h1&#39;)</code></pre>
<h3 id="getelementby">getElementBy</h3>
<ul>
<li>Class, Id, TagName 별로 DOM을 가져올 수 있다</li>
<li><strong>getElementById</strong>: 해당 아이디를 가진 단일 객체를 가져온다</li>
<li><strong>getElementByClass</strong>: 해당 클래스를 가진 객체를 HTMLCollection의 형태로 모두 가져온다</li>
<li><strong>getElementByTagName</strong>: 해당 TagName을 가진 객체를 HTMLCollection의 형태로 모두 가져온다</li>
</ul>
<pre><code class="language-javascript">const byId = document.querySelector(&#39;myid&#39;)
const byClass = document.querySelector(&#39;myclass&#39;)
const byTagName = document.querySelector(&#39;h1&#39;)</code></pre>
<h3 id="queryselector-vs-getelementby">querySelector vs. getElementBy</h3>
<table>
<thead>
<tr>
<th>querySelector</th>
<th>getElementBy</th>
</tr>
</thead>
<tbody><tr>
<td>- Class, Id, TagName에 상관없이 동일한 querySelector 메서드를 쓸 수 있다<br />- querySelectorAll의 경우 NodeList로 결과 반환 (Static)</td>
<td>- Class, Id, TagName에 따라서 알맞는 메서드를 사용해야한다<br />- 여러 객체 반환시 HTML Collection으로 결과 반환 (Live)</td>
</tr>
</tbody></table>
]]></description>
        </item>
    </channel>
</rss>