<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>hong-brother.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Tue, 13 Jun 2023 16:03:54 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>hong-brother.log</title>
            <url>https://images.velog.io/images/hong-brother/profile/700f13ae-b343-4217-a5c9-1c54669e5d23/social.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. hong-brother.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hong-brother" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[JPA 연관 관계 맵핑]]></title>
            <link>https://velog.io/@hong-brother/JPA-%EC%97%B0%EA%B4%80-%EA%B4%80%EA%B3%84-%EB%A7%B5%ED%95%91</link>
            <guid>https://velog.io/@hong-brother/JPA-%EC%97%B0%EA%B4%80-%EA%B4%80%EA%B3%84-%EB%A7%B5%ED%95%91</guid>
            <pubDate>Tue, 13 Jun 2023 16:03:54 GMT</pubDate>
            <description><![CDATA[<h2 id="다대일-n1">다대일 [N:1]</h2>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/e9a5715f-1130-4d5d-b8ee-8c0987277d6a/image.png" alt=""></p>
<pre><code class="language-java">@Getter
@Setter
@Entity
public class Member {
        @Id @GeneratedValue
        @Column(name = &quot;MEMBER_ID&quot;)
        private Long id;

        @Column(name = &quot;USERNAME&quot;)
        private String username;

        @ManyToOne
        @JoinColumn(name = &quot;TEAM_ID&quot;)
        private Team team;
}</code></pre>
<pre><code class="language-java">@Getter
@Setter
@Entity
public class Team {
        @Id @GeneratedValue
        @Column(name = &quot;TEAM_ID&quot;)
        private Long id;

        @Column(name = &quot;name&quot;)
        private String name;
}</code></pre>
<hr>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/2e015e14-5b8a-4ad6-93ec-d2961ddfc6f3/image.png" alt=""></p>
<pre><code class="language-java">@Getter
@Setter
@Entity
public class Member {
        @Id @GeneratedValue
        @Column(name = &quot;MEMBER_ID&quot;)
        private Long id;

        @Column(name = &quot;USERNAME&quot;)
        private String username;

        @ManyToOne
        @JoinColumn(name = &quot;TEAM_ID&quot;)
        private Team team;
}</code></pre>
<pre><code class="language-java">@Getter
@Setter
@Entity
public class Team {
        @Id @GeneratedValue
        @Column(name = &quot;TEAM_ID&quot;)
        private Long id;

        @Column(name = &quot;name&quot;)
        private String name;

        @OneToMany(mappedBy = &quot;team&quot;)
        private List&lt;Member&gt; members = new ArrayList&lt;&gt;();
}</code></pre>
<hr>
<h2 id="일대다-1n">일대다 [1:N]</h2>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/0fefdbe1-bb82-4db7-b28c-c77cbbee78aa/image.png" alt=""></p>
<ul>
<li>실무에서 거의 권장하지 않음<ul>
<li>연관 관계 관리를 위해 추가적인 UPDATE SQL이 실행 된다.</li>
</ul>
</li>
<li>객체와 테이블의 차이 때문에 반대편 테이블의 외래 키를 관리해야하는 구조</li>
<li>Team 테이블에 JoinColumn을 반드시 사용해야한다. 사용하지 않으면 조인 테이블 방식(중간 Link 테이블)을 사용한다.</li>
<li>일대다 단방향 매핑보다는 <strong>다대일 양방향</strong> 매핑을 사용권장</li>
</ul>
<pre><code class="language-java">@Getter
@Setter
@Entity
public class Member {
        @Id @GeneratedValue
        @Column(name = &quot;MEMBER_ID&quot;)
        private Long id;

        @Column(name = &quot;USERNAME&quot;)
        private String username;
}</code></pre>
<pre><code class="language-java">@Getter
@Setter
@Entity
public class Team {
        @Id @GeneratedValue
        @Column(name = &quot;TEAM_ID&quot;)
        private Long id;

        @Column(name = &quot;name&quot;)
        private String name;

        @OneToMany(mappedBy = &quot;team&quot;)
        @JoinColumn(name = &quot;TEAM_ID&quot;)
        private List&lt;Member&gt; members = new ArrayList&lt;&gt;();
}</code></pre>
<hr>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/21cbca86-a108-4764-a4ea-a4ece6372c44/image.png" alt=""></p>
<ul>
<li>공식적으로 지원하지 않는 연관관계</li>
<li><strong>다대일 양방향을 사용</strong></li>
</ul>
<pre><code class="language-java">@Getter
@Setter
@Entity
public class Member {
        @Id @GeneratedValue
        @Column(name = &quot;MEMBER_ID&quot;)
        private Long id;

        @Column(name = &quot;USERNAME&quot;)
        private String username;

        @ManyToOne
        @JoinColumn(name = &quot;TEAM_ID&quot;, insertable = false, updatable = false) 
        // Insert, Update 무효화 즉 읽기 전용
        private Team team;
}</code></pre>
<pre><code class="language-java">@Getter
@Setter
@Entity
public class Team {
        @Id @GeneratedValue
        @Column(name = &quot;TEAM_ID&quot;)
        private Long id;

        @Column(name = &quot;name&quot;)
        private String name;

        @OneToMany(mappedBy = &quot;team&quot;)
        @JoinColumn(name = &quot;TEAM_ID&quot;)
        private List&lt;Member&gt; members = new ArrayList&lt;&gt;();
}</code></pre>
<hr>
<h2 id="일대일-11">일대일 [1:1]</h2>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/cb03ad56-b93f-4218-835e-165921f95bd4/image.png" alt=""></p>
<ul>
<li>일대일 관계는 그 반대도 일대일 관계</li>
<li>주 테이블이나 대상 테이블 중에 외래 키 선택 가능</li>
<li>외래 키에 데이터베이스 유니크(UNI) 제약 조건 추가</li>
<li>다대일(@ManyToOne) 단방향 매핑과 유사</li>
</ul>
<pre><code class="language-java">@Getter
@Setter
@Entity
public class Locker {
        @Id @GeneratedValue
        private Long id;

        @Column(name = &quot;NAME&quot;)
        private String name;

}</code></pre>
<pre><code class="language-java">@Getter
@Setter
@Entity
public class Member {
        @Id @GeneratedValue
        @Column(name = &quot;MEMBER_ID&quot;)
        private Long id;

        @Column(name = &quot;USERNAME&quot;)
        private String username;

        @OneToOne
        @JoinColumn(name = &quot;LOCKER_ID&quot;)
        private Locker;
}</code></pre>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/4ff858e6-8ce5-40af-b072-9c110e9fd1fd/image.png" alt=""></p>
<pre><code class="language-java">@Getter
@Setter
@Entity
public class Locker {
        @Id @GeneratedValue
        private Long id;

        @Column(name = &quot;NAME&quot;)
        private String name;

        @OneToOne(mappedBy = &quot;locker&quot;)
        private Member member;

}</code></pre>
<pre><code class="language-java">@Getter
@Setter
@Entity
public class Member {
        @Id @GeneratedValue
        @Column(name = &quot;MEMBER_ID&quot;)
        private Long id;

        @Column(name = &quot;USERNAME&quot;)
        private String username;

        @OneToOne
        @JoinColumn(name = &quot;LOCKER_ID&quot;)
        private Locker;
}</code></pre>
<h2 id="일대일-관계에서-외래-키">일대일 관계에서 외래 키</h2>
<h3 id="주-테이블에-외래-키">주 테이블에 외래 키</h3>
<ul>
<li>주 객체가 대상 객체의 참조를 가지는 것 처럼 주 테이블에 외래 키를 두고 대상 테이블을 찾음</li>
<li>객체지향 개발자 선호</li>
<li>JPA 매핑 편리</li>
<li>장점 : 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인 가능</li>
<li>단점 : 값이 없으면 외래 키에 null 허용</li>
</ul>
<h3 id="대상-테이블에-외래-키">대상 테이블에 외래 키</h3>
<ul>
<li>대상 테이블에 외래 키가 존재</li>
<li>전통적인 데이터베이스 개발자 선호</li>
<li>장점 : 주 테이블과 대상 테이블을 일대일에서 일대다 관계로 변경할 때 테이블 구조 유지</li>
<li>단점 : 프록시 기능의 한계로 지연 로딩으로 설정해도 항상 즉시 로딩됨</li>
</ul>
<hr>
<h2 id="다대다-nm">다대다 [N:M]</h2>
<h3 id="관계형-데이터-베이스에서-다대다란">관계형 데이터 베이스에서 다대다란?</h3>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/b6eb4c44-6573-44af-8185-37cd76d18619/image.png" alt=""></p>
<ul>
<li>관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없음</li>
<li>다대다 관계를 표현하기 위해서는 일대다, 다대일 관계로 표현 할 수 있음</li>
</ul>
<h3 id="객체에서-다대다란">객체에서 다대다란?</h3>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/be133ec7-3190-4ac2-847e-86fc7ab4bba7/image.png" alt=""></p>
<ul>
<li>Member는 Collection으로 Product List를 가질 수 있고 Product도 Collection으로 Member List를 가질 수 있음</li>
</ul>
<pre><code class="language-java">@Getter
@Setter
@Entity
public class Product {
        @Id @GeneratedValue
        private Long id;

        @Column(name = &quot;NAME&quot;)
        private String name;

        @ManyToMany(mappedBy = &quot;products&quot;)
        private List&lt;Member&gt; members = new ArrayList&lt;&gt;();
}</code></pre>
<pre><code class="language-java">@Getter
@Setter
@Entity
public class Member {
        @Id @GeneratedValue
        @Column(name = &quot;MEMBER_ID&quot;)
        private Long id;

        @Column(name = &quot;USERNAME&quot;)
        private String username;

        @ManyToMany
        @JoinTable(name = &quot;MEMBER_PRODUCT&quot;)
        private List&lt;Product&gt; products = new ArrayList&lt;&gt;();
}</code></pre>
<h3 id="다대다-한계-극복">다대다 한계 극복</h3>
<ul>
<li>연결 테이블을 엔티티로 승격하여 @ManyToMany보다는 @OneToMany, @ManyToOne으로 해결한다.
<img src="https://velog.velcdn.com/images/hong-brother/post/262782e8-fb0a-4b43-8d37-9bdd82085c2e/image.png" alt=""></li>
</ul>
<pre><code class="language-java">@Getter
@Setter
@Entity
public class Product {
        @Id @GeneratedValue
        private Long id;

        @Column(name = &quot;NAME&quot;)
        private String name;

        @OneToMany(mappedBy = &quot;products&quot;)
        private List&lt;MemberProduct&gt; memberProducts = new ArrayList&lt;&gt;();
}</code></pre>
<pre><code class="language-java">@Getter
@Setter
@Entity
public class Member {
        @Id @GeneratedValue
        @Column(name = &quot;MEMBER_ID&quot;)
        private Long id;

        @Column(name = &quot;USERNAME&quot;)
        private String username;

        @OneToMany(mappedBy = &quot;member&quot;)
        private List&lt;MemberProduct&gt; memberProducts = new ArrayList&lt;&gt;();
}</code></pre>
<pre><code class="language-java">@Entity
public class MemberProduct {
        @Id @GeneratedValue
        private Long id;

        @ManyToOne
        @JoinCoumn(name = &quot;MEMBER_ID&quot;)
        private Member member;

        @ManyToOne
        @JoinCoumn(name = &quot;PRODUCT_ID&quot;)
        private Product product; 
}  </code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Oracle Cloud로 평생 무료 서버 구축]]></title>
            <link>https://velog.io/@hong-brother/Oracle-Cloud%EB%A1%9C-%ED%8F%89%EC%83%9D-%EB%AC%B4%EB%A1%9C-%EC%84%9C%EB%B2%84-%EA%B5%AC%EC%B6%95</link>
            <guid>https://velog.io/@hong-brother/Oracle-Cloud%EB%A1%9C-%ED%8F%89%EC%83%9D-%EB%AC%B4%EB%A1%9C-%EC%84%9C%EB%B2%84-%EA%B5%AC%EC%B6%95</guid>
            <pubDate>Sat, 10 Jun 2023 16:42:37 GMT</pubDate>
            <description><![CDATA[<h1 id="oracle-cloud로-평생-무료-서버-구축">Oracle Cloud로 평생 무료 서버 구축</h1>
<h2 id="oracle-cloud">Oracle Cloud</h2>
<ul>
<li>2019년 오라클 오픈월드 2019에서 오라클 클라우드 프리티어가 공개
상시 무료 서비스를 제공하며, 추가적으로 $300의 크레딧을 제공
<img src="https://velog.velcdn.com/images/hong-brother/post/df1d481b-54b2-4c4a-b141-238859a417a8/image.png" alt="">
<img src="https://velog.velcdn.com/images/hong-brother/post/30aac99b-4d49-4f7d-9a96-76940e702044/image.png" alt=""></li>
</ul>
<h1 id="oracle-cloud-가입">Oracle Cloud 가입</h1>
<ul>
<li><a href="https://www.youtube.com/watch?v=yUA4FziG1Ak">오라클 클라우드 무료 체험 3분가이드</a></li>
</ul>
<h2 id="vm-인스턴스-생성">VM 인스턴스 생성</h2>
<h3 id="create-a-vm-instance">Create a VM Instance</h3>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/43c86c7e-9705-4beb-b631-f3282a2790ba/image.png" alt=""></p>
<h3 id="create-compute-instance">Create compute instance</h3>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/843f1a1e-1a4c-46fe-9d75-dfcd7f476b7b/image.png" alt=""></p>
<ul>
<li>이름<ul>
<li>인스턴스 이름 설정</li>
</ul>
</li>
<li>이미지 및 구성<ul>
<li>이미지는 Oracle Linux8 말고도 ubuntu, oracle 등 다양한 프리티원 지원하는 이미지를 선택 할 수 있다.</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/dbbe6029-2dbc-467c-b42d-5d8b59d4ab6f/image.png" alt=""></p>
<ul>
<li>네트워킹<ul>
<li>새 가상 클라우드 네트워크를 생성 선택</li>
<li>새 공용 서브넷 생성 선택</li>
</ul>
</li>
</ul>
<h2 id="vm-instance-접속">vm instance 접속</h2>
<ul>
<li>ssh 접속 (ssh key는 인스턴스 생성시 다운로드 받은 파일)</li>
</ul>
<pre><code class="language-bash">ssh -i &#39;ssh key&#39; 사용자이름@공인Ipv4주소</code></pre>
<ul>
<li>만약 Permission denied (publickey,gssapi-keyex,gssapi-with-mic) 발생시</li>
</ul>
<pre><code class="language-bash">chmod 400 key~
ssh -i &#39;ssh key&#39; user@ip</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[WEB] JWT Flow with Redis]]></title>
            <link>https://velog.io/@hong-brother/WEB-JWT-%EC%9D%B8%EC%A6%9D-%EC%A0%84%EB%9E%B5-with-Redis</link>
            <guid>https://velog.io/@hong-brother/WEB-JWT-%EC%9D%B8%EC%A6%9D-%EC%A0%84%EB%9E%B5-with-Redis</guid>
            <pubDate>Wed, 28 Dec 2022 16:53:23 GMT</pubDate>
            <description><![CDATA[<blockquote>
</blockquote>
<p>JWT(JSON Web Token) 이용하여 로그인시 Token을 발행하고 관리하는 Flow 대한 정리.</p>
<h2 id="access-token--refresh-token">Access Token &amp; Refresh Token</h2>
<ul>
<li>Access Token과 Refresh Toekn은 똑같이 JWT이다 둘 차이는 Refresh Token이 Access Token보다 유효기간이 상대적으로 길다.</li>
<li>사용자 로그인시 Access Toeken과 Refresh Token을 함께 발행하여 사용자에게 전달해주며 Access Token 만료시 Refresh Token을 전송하여 새로운 Access Token을 갱신 할 수 있다.</li>
<li>또한 서버측에서는 Refresh Token을 안전한 장소에 저장하고 사용자의 Access Token이 탈취당할 경우를 대비하여 탈취당했다고 판단 시, 서버측 Refresh Token을 삭제하여 해당 사용자를 강제 로그아웃을 시킬 수 있다.</li>
<li>이로써 JWT의 단점인 발급한 후 삭제가 불가능한 문제를 Access Token, Refresh Token으로 관리하므로써 어느정도 해소 시킬 수 있다.</li>
</ul>
<h2 id="jwt-token-flow">JWT Token Flow</h2>
<ul>
<li>Access Token, Refresh Token을 이용하여 JWT Token Flow을 생각해볼 것이다. 크게 Client, Server, DB, Redis를 사용하도록 구성 하였다.</li>
<li>Redis를 사용하는 이유는 Refresh Token을 저장하기 위함이 가장 크다.
Redis는 key-value 쌍으로 데이터를 관리하는 스토리지 이며 key에 TTL을 적용하여 Expire을 설정 할 수 있다.</li>
<li>Refresh Token의 저장하기 위한 Redis를 선택한 이유도 Redis의 장점을 이용한 빠른 엑세스 속도로 로그인시 병목 현상을 방지하기 위함이다. 또한 Refresh Token을 DB에 저장 할 경우 세부적으로 서버단에서 스케줄러에 의해서 또는 트리거에 의해서 Refresh Token을 직접 컨트롤 해야 한다. 하지만 Redis의 TTL을 사용하여 적용한다면 서버단에서 핸들링 할 부담은 더 줄어들 것이다.</li>
</ul>
<h3 id="로그인-flow">로그인 Flow</h3>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/682dc8ee-eb75-41a3-bbd8-fee4ebcec880/image.png" alt=""></p>
<ul>
<li><code>Client</code>가 로그인 시 <code>Server</code>는 <code>DB</code>의 사용자 정보를 조회 하여 회원 가입여부에 따라 <strong>AccessToken, Refresh Token</strong> 을 발급한다. </li>
<li>발급한 Refresh Token은 Redis에 저장 한다.</li>
<li><code>Server</code>는 요청한 <code>Client</code>에게 Access Token, Refresh Token을 응답한다.</li>
<li><code>Client</code>는 매 요청 API 마다 Header에 Access Token을 담아 전송 하고 서버는 전송받은 Access Token을 검증하여 <code>Client</code>요청에 응답한다.</li>
</ul>
<h3 id="access-token-만료시-flow">Access Token 만료시 Flow</h3>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/1b419352-cc75-4984-b4f4-82741b0d6e2f/image.png" alt=""></p>
<ul>
<li><code>client</code>에서 Access Token 만료 시 재발급을 위한 /reissue API를 요청한다. 해당 API의 Heder내에 Authorization header내에는 Refresh Token을 전송 한다.</li>
<li><code>Server</code>에서는 Refresh Token의 payload내에 Access Token 인지, Refresh Token 인지 확인한다.</li>
<li><code>Server</code>에서는 확인된 Token이 Refresh Token이면 Payload 내에 사용자 정보를 얻을 수 있는(ex. email, id ...)key로 <code>Redis</code>에 조회 하여 Refresh Token이 존재하는지 확인한다.</li>
<li>Refresh Token이 존재한다면 <code>Server</code>에서는 다시 Access Token, Refresh Token을 발급하여 <code>Client</code>에게 전달한다.</li>
<li>새로 발급된 Refresh Token은 다시 Redis에 저장한다.</li>
</ul>
<h3 id="로그아웃된-사용자-flow">로그아웃된 사용자 Flow</h3>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/afa2c856-0adb-4040-ac65-1e2701f49387/image.png" alt=""></p>
<ul>
<li><code>Client</code>에서는 Access Token 만료 시 재발급을 위한 /reissue API를 요청 한다.
만약 해당 사용자가 로그아웃이 되어 있다면 Refresh Token은 Redis에서 삭제 되었을 것이다.</li>
<li>Refresh Token을 받은 <code>Server</code> 에서는 Redis에서 Refresh Token이 존재 여부를 확인하고 존재 하지 않을 경우 <code>Client</code> 응답으로 HTTP UnAuthorized(401) 상태를 응답하게 된다.</li>
</ul>
<h3 id="refresh-token을-이용한-보안-강화">Refresh Token을 이용한 보안 강화</h3>
<ul>
<li>만약 정상적인 사용자 Access Token이 탈취 당하거나, 원치 않은 해외 IP가 사용된 사용자인 경우 Refresh Token을 서버내에(Redis)삭제 하므로써 해당 사용자를 강제 로그아웃하여 보안을 강화 할 수 있을 것 이다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[WEB] JWT(JSON Web Token)]]></title>
            <link>https://velog.io/@hong-brother/WEB-JWTJSON-Web-Token</link>
            <guid>https://velog.io/@hong-brother/WEB-JWTJSON-Web-Token</guid>
            <pubDate>Fri, 16 Dec 2022 15:51:20 GMT</pubDate>
            <description><![CDATA[<blockquote>
</blockquote>
<p>NEST.JS에 JWT Token을 적용하기 위한 이론 알고 가기</p>
<h1 id="🔐jwtjson-web-token">🔐JWT(JSON Web Token)</h1>
<ul>
<li><code>JWT란</code> 인증에 필요한 정보들을 암호화시킨 JSON 토큰을 말한다.</li>
<li>JWT 토큰(Access Token)을 HTTP 헤더내에 Authorization 담아 클라이언트와 서버가 통신한다.</li>
<li>JWT는 크게 <code>Header</code>, <code>Payload</code>, <code>Signature</code> 으로 점(.)으로 구분하는 구조이다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/35e27902-705d-4804-83ea-4ff472b852ee/image.png" alt="JWT"></p>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/dab00598-2f8f-40f8-9467-bc4ab88326e3/image.png" alt=""></p>
<h2 id="header">Header</h2>
<p>header는 <code>typ</code>,<code>alg</code> 정보를 가지고 있다.
<code>typ</code>은 토큰의 타입을 지정하며, <code>alg</code>은 해싱 알고리즘을 지정한다. 
해싱 알고리즘은 HMAC, SHA256, RSA등이 있으며 지정한 알고리즘은 토큰 검증 시 signature 부분에 사용 된다.</p>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/f1e94014-3574-43b3-b673-a37ea21b8600/image.png" alt=""></p>
<h2 id="payload">Payload</h2>
<p>payload는 토큰에 담을 정보가 담겨 있다. <code>key-value</code> 형식으로 이루어진 정보를 <code>클레임 셋 (Claim Set)</code> 이라 부른다.
Claim에는 크게 세가지 <code>registered Claim</code>, <code>public Claim</code>, <code>private Claim</code>을 토큰에 담을 수 있다.</p>
<h3 id="registered-claim">registered Claim</h3>
<p>토큰에 대한 정보들을 담기 위한 클레임 셋이다. 아래 클레임 셋은 모두 Optional이다.</p>
<ul>
<li><code>iss</code>: 토큰 발급자(issuer)</li>
<li><code>sub</code>: 토큰 제목(subject)</li>
<li><code>aud</code>: 토큰 대상자(audience)</li>
<li><code>exp</code>: 토큰 만료시간(expiration)</li>
<li><code>nbf</code>: 토큰의 활성 날짜(Not Before)</li>
<li><code>iat</code>: 토큰이 발급된 시간(issued at)</li>
<li><code>jti</code>: 고유 식별자로서 중복적인 처리를 방지하기 위해 사용, 일회용 토큰에 사용하면 유용</li>
</ul>
<h3 id="public-claim">public Claim</h3>
<p>사용자 정의 클레임으로 공개용 정보를 위해 사용된다. 또한 충돌 방지를 위해 URI 형식으로 이용한다.</p>
<pre><code class="language-json">{
    &quot;https://velog.io/@hong-brother/name&quot;: &quot;hong-brother&quot;
}</code></pre>
<h3 id="private-claim">private Claim</h3>
<p>클라이언트와 서버간에 합의하에 등록하여 사용 할 수 있는 클레임 이다.</p>
<h3 id="payload-예제">payload 예제</h3>
<pre><code class="language-json">{
  &quot;u&quot;: &quot;ggbqmf113013e4c5&quot;,
  &quot;r&quot;: &quot;fce10bab&quot;,
  &quot;t&quot;: &quot;a&quot;,
  &quot;https://velog.io/@hong-brother/name&quot;: &quot;hong-brother&quot;
  &quot;iat&quot;: 1671118700,
  &quot;exp&quot;: 1671723500
}</code></pre>
<h2 id="signature">Signature</h2>
<pre><code class="language-json">RSASHA256( &lt;-- header의 alg에 따라서 변경
  base64UrlEncode(header) + &quot;.&quot; +
  base64UrlEncode(payload),
  secret
  )</code></pre>
<p>signature는 인코딩된 header, payload에 &quot;.&quot;을 더한 뒤 비밀키로 해싱하여 생성한다.
Header 및 Payload는 단순 인코딩된 값이기 때문에 해커가 복호화하고 조작할 수 있지만, Signature는 서버 측에서 관리하는 비밀키가 유출되지 않는 이상 복호화할 수 없다.</p>
<p>따라서 Signature는 토큰의 위변조 여부를 확인하는 데 사용된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[typescript] Utility Types - Partial, Pick,  Omit]]></title>
            <link>https://velog.io/@hong-brother/typescript-Utility-Types-Partial-Pick-Omit</link>
            <guid>https://velog.io/@hong-brother/typescript-Utility-Types-Partial-Pick-Omit</guid>
            <pubDate>Mon, 12 Dec 2022 14:49:36 GMT</pubDate>
            <description><![CDATA[<h1 id="what-is-typescript-partial">What is Typescript Partial</h1>
<ul>
<li>특정 타입의 부분 집합을 만족하는 타입을 정의 할 수 있다. 즉 모든 요소를 Optional 지정한 타입을 새로 생성할 수 있다.<pre><code class="language-typescript">type userInfoType = {
  id: string;
  email: string;
  password: string;
}
</code></pre>
</li>
</ul>
<p>const hsnam: Partial<userInfoType> = {
    id: &#39;hsnam&#39;,
    email: &#39;robbins.hs@gmail.com&#39;
}</p>
<pre><code>- Partial 타입을 활용하면 모든 요소를 Optional로 지정하여 새로운 타입을 생성 할 수 있다.

# What is Typescript Pick
- 특정 타입 요소만 포함된 타입을 새로 생성한다.

```typescript
type userInfoType = {
    id: string;
    email: string;
    password: string;
}

const newUserInfoType: Pick&lt;userInfoType, &quot;id&quot;|&quot;password&quot;&gt; = {
    id: &#39;hsnam&#39;,
    password: &#39;password&#39;,
}</code></pre><ul>
<li>Pick은 첫 번째 인자로 받은 타입에서 주어진 속성을 포함하여 새로운 타입을 리턴한다.</li>
</ul>
<h1 id="what-is-typescript-omit">What is Typescript Omit</h1>
<ul>
<li>주어진 타입에서 특정 속성만 제거한 타입을 정의힌다.<pre><code class="language-typescript">type userInfoType = {
  id: string;
  email: string;
  password: string;
}

</code></pre>
</li>
</ul>
<p>const omitType: Omit&lt;userInfoType, &#39;id&#39;&gt;  = {
    email: &quot;<a href="mailto:robbins.hs@gmail.com">robbins.hs@gmail.com</a>&quot;,
    password: &quot;123456789a&quot;
}</p>
<pre><code>- omit은 첫 번째 인자로 받은 타입에서 주어진 속성을 제외한 새로운 타입을 리턴한다.
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[javascript] Tree-Shaking]]></title>
            <link>https://velog.io/@hong-brother/javascript-Tree-Shaking</link>
            <guid>https://velog.io/@hong-brother/javascript-Tree-Shaking</guid>
            <pubDate>Sun, 11 Dec 2022 14:51:31 GMT</pubDate>
            <description><![CDATA[<h1 id="tree-shaking">Tree-Shaking</h1>
<blockquote>
</blockquote>
<p>나무를 흔들어서 죽은 나뭇잎을 떨어뜨리듯, 코드를 빌드할 때도 실재로 쓰지 않는 코드들을 제외 한다는 뜻.</p>
<h2 id="tree-shaking-이란">Tree-Shaking 이란</h2>
<ul>
<li>Webpack, Rollup 등 JS 모듈을 번들링할때 사용하지 않는 코드를 제거하여 최적하는 과정을 뜻한다.</li>
</ul>
<h2 id="필요성">필요성</h2>
<ul>
<li>JS 파일이 늘어나면 늘어날 수록 요청 시에 네트워크 리소스 소모가 커지는 효과를 줄이기 위해서 필요하다.</li>
<li>JS 파일의 실행시간이 증가되어 랜더링 또는 CPU에 영향을 줌으로 페이지 로드 시간이 늘어날 수 있음을 방지 하기 위해 필요하다</li>
</ul>
<h2 id="import--export">import / export</h2>
<pre><code class="language-javascript">import _ from &#39;lodash&#39;;</code></pre>
<ul>
<li>lodash를 예를 들어 모든 요소들을 impor하기 때문에 모든 리소스가 불러와진다.</li>
</ul>
<pre><code class="language-javascript">import { map, filter } from &#39;lodash-es&#39;;</code></pre>
<ul>
<li>필요한 함수만 기능만 로드하여 불필요한 요스를 제외 시킨다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[OAuth2? 이해 해보자!]]></title>
            <link>https://velog.io/@hong-brother/OAuth2-%EC%9D%B4%ED%95%B4-%ED%95%B4%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@hong-brother/OAuth2-%EC%9D%B4%ED%95%B4-%ED%95%B4%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Wed, 23 Nov 2022 16:05:16 GMT</pubDate>
            <description><![CDATA[<h1 id="oauth2란">OAuth2란?</h1>
<p>OAuth2(Open Authorization 2.0)은 인증을 위한 개방형 표준 프로토콜이다.
OAuth 프로토콜은 써드파티 어플리케이션에게 인증을 위한 접근 권한을 위임하는 방식을 제공한다.</p>
<p>대표적으로 구글, 카카오, 네이버, 메타 등에서 제공하는 <code>간편 로그인</code> 기능도 OAuth2 프로토콜 기반의 사용자 인증 기능을 제공하고 있습니다.</p>
<h1 id="oauth2를-사용하는-이유">OAuth2를 사용하는 이유?</h1>
<p>만약 구글을 이용하여 구글드라이브 API를 통한 서드파티 어플리케이션을 개발한다고 가정하다. 써드파티 어플리케이션을 사용하는 사용자의 구글 아이디와 패스워드를 알고 있어야만 써드파티에서도 쉽게 서비스르를 이용할 수 가 있다. 하지만 이 방법은 처음보는 써드파티 어플리케이션을 신뢰 할 수 없기 때문에 상당히 위험하고 무서운 방법이다. 
그래서 OAuth2 프로토콜을 이용하여 사용자의 아이디 패스워드가 아닌 <code>accessToken</code>을 이용하여 접근 할 수 있으며 <code>accessToken</code>을 통하여 제공하는 서비스의 접근을 제한 할 수 있다.</p>
<h1 id="oauth2-주요-용어">OAuth2 주요 용어</h1>
<table>
<thead>
<tr>
<th>용어</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td>Authentication</td>
<td>인증, 접근 자격이 있는지 검증하는 단계</td>
</tr>
<tr>
<td>Authorization</td>
<td>인가, 자원에 접근할 권한을 부여한다. 인가가 완료되면 리소스 접근 권한이 담긴 Access Token이 클라이언트에게 전달된다.</td>
</tr>
<tr>
<td>Access Token</td>
<td>리소스 서버에게서 리소스 소유자의 보호된 자원을 획득할 때 사용되는 토큰</td>
</tr>
<tr>
<td>Refresh Token</td>
<td>Access Token 만료시 이를 갱신하기 위한 용도로 사용하는 Token, 일반적으로 Access Token보다 Refresh Token이 만료 시간이 더 길다.</td>
</tr>
</tbody></table>
<h1 id="authorization">Authorization</h1>
<h2 id="authorization-code-grant권한-부여-승인-코드-방식">Authorization Code Grant(권한 부여 승인 코드 방식)</h2>
<ul>
<li>OAuth2 에서 가장 많이 사용되는 방식이다.</li>
<li>간편 로그인 기능에서 사용되는 방식으로 클라이언트가 사용자를 대신하여 특정 자원에 접근을 요청할 때 사용되는 방식이다. </li>
</ul>
<p><a href="https://yonghyunlee.gitlab.io/temp_post/oauth-authorization-code/">https://yonghyunlee.gitlab.io/temp_post/oauth-authorization-code/</a></p>
<h1 id="reference">Reference</h1>
<p><a href="https://opentutorials.org/course/3405">생활코딩-OAuth2</a>
<img src="https://velog.velcdn.com/images/hong-brother/post/4e9d637b-2a1d-416e-9108-78a17df98a42/image.png" alt="velog"></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[NestJS] 프로젝트 구조에 대한 고찰]]></title>
            <link>https://velog.io/@hong-brother/NestJS-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B5%AC%EC%A1%B0%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B3%A0%EC%B0%B0</link>
            <guid>https://velog.io/@hong-brother/NestJS-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B5%AC%EC%A1%B0%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B3%A0%EC%B0%B0</guid>
            <pubDate>Sun, 28 Aug 2022 16:03:29 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/hong-brother/post/9adaf3c4-d7b8-4fa4-bfaf-12992312f9be/image.png" alt=""></p>
<p>해당 포스트에서는 NestJS에 대한 프로젝트 구조에 대해서 생각해보는 개인 고찰 포스트 입니다. <strong>단순히 이렇게도 생각해 볼 수 있겠군아</strong> 라고 넘겨 주셔도 좋을 것 같습니다.🙏</p>
<h1 id="프로젝트-구조는-항상-어렵다">프로젝트 구조는 항상 어렵다.</h1>
<ul>
<li>처음 개발자로 처음 시작한 언어는 Spring 프레임워크 였습니다. Spring만 5년(<del>하지만 아직도 어렵다는 ㅠㅠ😭</del>)이라는 시간동안 계속 해왔기 때문에 Spring에 초첨이 맞쳐져 있는건 아마 당연한 것 일거 같습니다.</li>
<li>타 언어를 습득할때(FastAPI, NodeJS, NestJS 등등) 항상 Spring 프레임워크 기준으로 타언어를 바라보기 때문에 러닝 커브가 있었다고 생각할 수도 있을것 같습니다. 
예를 들어 NodeJS(express)를 처음 접했을때 프로젝트 구조를 설정하는 것이 개인적인 선호에 따라 틀리고 프로젝트 아키텍쳐 및 모듈 주입에 따라 다르다는 사실에 혼란 스러웠습니다. Spring 기준으로 생각하는 저로써는 항상 같은 프로젝트 구조(Controller - Service - VO or DTO - Repository) 일괄되게 생각하기에 처음 타언어 프로젝트 구조를 가져갈때 구조적인 문제로 항상 많이 고민했던거 같습니다.</li>
</ul>
<h1 id="nestjs-운명">NestJS? 운명?</h1>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/330b6f97-ca1e-4780-b8e5-2287e63b5175/image.png" alt=""></p>
<ul>
<li>사실 작년만 해도 NodeJS를 하면서 <strong>Spring 프레임워크에 대한 진한 향수</strong>를 잊지 못하고 있었습니다.</li>
<li>TypeScript를 실무에 도입하므로써 타입에 대한 에러를 어느정도 문제를 해결 할 수 있었고 NestJS를 실무에 도입하므로써 가장 그리웠던 어노테이션, 데코레이터를 사용하므로써 Spring을 하는 착각(?)을 주는것 같았습니다.</li>
<li>NestJS에서 Spring을 따라가면서 DI, IOC등 개념을 적용 할 수 있어서 아직까지도 만족 하면서 사용하고 있습니다.</li>
</ul>
<h1 id="nestjs-프로젝트-구조">NestJS 프로젝트 구조</h1>
<ul>
<li><p>NestJS는 <code>Module</code> 기반으로 <code>@Module()</code> 데코레이터를 사용하여 각 기능별 모듈을 생성하고 Root Module에서 집합시켜 사용합니다.
<img src="https://velog.velcdn.com/images/hong-brother/post/b57e4513-8dc4-4c63-ac6b-acd596c3680b/image.png" alt=""></p>
</li>
<li><p>Spring에서는 모듈이라는 개념은 없기 때문에 여기서 쪼금 신선했습니다~ 하지만 뭐 각 기능에 따른 모듈만 만들어주고 그 모듈을 root module에 연결만 시켜주면 문제는 없었습니다.</p>
</li>
</ul>
<h1 id="module에-중복코드">Module에 중복코드</h1>
<ul>
<li>NestJS에 각 서비스 기능별로 module를 만들면서 문제가 발생 되었습니다. 각 module에 필요한 기능이 같으면 각 module에 명시를 해줘야 됩니다.
<img src="https://velog.velcdn.com/images/hong-brother/post/a467bede-3b51-4e80-aba2-45e4f0f35264/image.png" alt=""></li>
<li>a.module.ts(왼쪽), b.module.ts(오른쪽) 보시면 JwtModule이 이미 각 모듈에 중복해서 사용하고 있습니다. 사실 뭐 중복해도 사용해도 상관없지만(<del>아니야</del> 상관있어<del>!!!</del>) JwtModule설졍이 변경되면 사용된 각 모듈을 찾아서 설정해줘야 합니다ㅠㅠ </li>
<li>그래서 각 모듈에 이런 문제를 NestJS에서도 해결 하기 위해서 여러 모듈을 만들어 놓았습니다. 
(각 모듈에 대해서는 다음 포스트에서 자세희 다루겠습니다.)</li>
</ul>
<h2 id="nestjs-modules">NestJS Modules</h2>
<h3 id="shared-modules">Shared Modules</h3>
<ul>
<li>NestJS에서는 모듈이 싱글톤으로 관리 되기 때문에 여러 모듈 간에 쉽게 Providers의 동일한 인스턴스를 공유 할 수 있습니다.</li>
</ul>
<h3 id="module-re-exporting">Module re-exporting</h3>
<ul>
<li>import한 모듈을 다시 export하여 다른 모듈에서 사용 할 수 있게 합니다.</li>
</ul>
<h3 id="dependeny-injection">Dependeny Injection</h3>
<ul>
<li>Module class에 생성자를 사용하여 의존성을 주입한다.</li>
</ul>
<h3 id="gloval-modules">Gloval Modules</h3>
<ul>
<li>똑같은 모듈을 매번 import하는 수고를 덜기 위해 모듈을 전역 스코프에 설정 할 수 있습니다.</li>
<li>모듈 최상단에 <code>@Global()</code> 데코레이터를 붙이기만 하면 import 없이 해당 모듈이 Provider에 사용 할 수 있게 됩니다.</li>
</ul>
<h3 id="dynamic-modules">Dynamic Modules</h3>
<ul>
<li>사용자가 지정 가능한 모듈을 쉽게 만들어 줍니다.</li>
</ul>
<h2 id="좀더-예시를-들어보자">좀더 예시를 들어보자</h2>
<ul>
<li>만약 아래와 같이 Common, User라는 모듈이 있다고 하자 각 모듈에는 특정 사이트에 헬스 체크를 하는 API아 있다고 가정 해보자<blockquote>
</blockquote>
각 서비스에 요청하는 헬스 체크는 공식문서를 보고 참고 하였습니다. <a href="https://docs.nestjs.com/recipes/terminus#healthchecks-terminus">문서</a></li>
</ul>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/4cbe6f9a-bfa3-4bec-9dd3-7142e8d149d1/image.png" alt=""></p>
<ul>
<li><p>Common 모듈안에 Controller는  <code>GET - /common/check</code> 요청이 들어오면 Service안에 check함수를 요청하게 되고 <code>https://docs.nestjs.com</code>이라느 사이트에 대해서 상태 체크를 합니다.</p>
</li>
<li><p>User 모듈안에 Controller는  <code>GET - /common/check</code> 요청이 들어오면 Service안에 check함수를 요청하게 되고 <code>https://docs.nestjs.com</code>이라느 사이트에 대해서 상태 체크를 합니다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/a1b4be0c-50aa-4f85-aaba-cded0749c51e/image.png" alt=""></p>
<ul>
<li>각 모듈에서 특정 <code>URL</code>에 상태를 체크하기 위해 사용해야 하는 모듈은 <code>TerminusModule</code>, <code>HttpModule</code> 입니다. 상태를 체크하는 기능을 사용하기 위해서는 해당 모듈을 또 각 모듈에 import해야 하므로 위에서 JwtModule 중복되는 것 처럼 각 모듈에는 Module을 중복해서 import해야 하므로 중복 코드가 발생 될 것입니다.</li>
<li>NestJS에서 공유 모듈, 글로벌 모듈 등 각 여러개를 제시하고 있는것 같지만 제가 아직 모듈에 대한 지식이 부족하여 적용하지 못하는것 같습니다.</li>
</ul>
<h1 id="module를-스프링-구조로-해결해보자">Module를 스프링 구조로 해결해보자</h1>
<ul>
<li>위에서 설명한 각 모듈에 중복되는 코드들을 해결하고자 생각을 한게 그냥 스프링처럼 해보면 어떨까 입니다.</li>
<li>NestJS의 모듈방식이 아닌 Spring에서 사용하는 프로젝트 구조 처럼 구조를 변경하면 자연스럽게 해결될 것으로 생각이 듭니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/f68a1b18-cb3e-4c08-9cb8-e25c8dcb6c3a/image.png" alt=""></p>
<ul>
<li>스프링과 같이 <code>Controller</code>, <code>Service</code>, <code>Repository</code>, <code>Dto</code> 등등 이렇게 가져가면 굳이 모듈을 공유 하지 않아도 될까 라는 생각을 해보았습니다.</li>
<li><code>Controller</code> 에는 common, user에 대한 Controller만 모아 놓았으며 라우터만 존재합니다.</li>
<li><code>Service</code> 에서는 common, user에 대한 비지니스 코드들만 모아 작성하였습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/35bc2631-266c-4471-91d3-6494b5b452d0/image.png" alt=""></p>
<ul>
<li>모듈을 스프링과 같이 <code>controller</code>, <code>service</code>로 분리하여 모듈을 구성하니 <code>TerminusModule</code>, <code>HttpModule</code>대한 모듈은 <code>service</code>모둘에만 작성하면 되니 중복코드는 줄어 들었습니다.
이와 같이 <code>JwtModule</code>와 같은 예시도 이런 구조로 설정하면 중복코드는 사라질 것 같습니다.</li>
</ul>
<h1 id="정리">정리</h1>
<ul>
<li>NestJS를 사용하면서 각 기능에 따른 Module에 공통으로 사용되는 모듈에 대해서 중복 코드가 발생되어 Spring에서 흔희 사용하는 프로젝트 구조로 문제를 해결 할 수 있지 않을까? 생각해보았습니다.</li>
<li>어쩌면 아직은 제가 NestJS에 대한 Module에 대한 구조를 자세히 이해하지 못한 것 같습니다.</li>
<li>NestJS에서 제시해주는 Modules개념을 다시 익히면서 구조적으로 해결 할 수 있는 방법을 좀더 고안해봐야 할 것 같습니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[typescript] tsconfig.json ]]></title>
            <link>https://velog.io/@hong-brother/typescript-tsconfig.json</link>
            <guid>https://velog.io/@hong-brother/typescript-tsconfig.json</guid>
            <pubDate>Mon, 22 Aug 2022 16:46:04 GMT</pubDate>
            <description><![CDATA[<h1 id="tsconfigjson란">tsconfig.json란?</h1>
<p>타입스크립트 ts파일들을 js파일로 컴파일 할때 어떻게 변환할 것인지 세부 항목을 설정하는 json파일이다.
타입스크립트의 세부 설정 항목을 한번 살펴보겠다.
먼저 타이스크립트를 설정파일 을 만들기 위해 아래 typescript를 적용시켜보자</p>
<h2 id="typescript-적용">typescript 적용</h2>
<ul>
<li><p>package.json 파일 생성</p>
<pre><code class="language-bash">npm init -y</code></pre>
</li>
<li><p>install typescript</p>
<pre><code class="language-bash">npm install -D typescript</code></pre>
</li>
<li><p>tsconfig.json 생성
기본으로 타입 스크립트 설정 파일이 설정 될 것이다.</p>
<pre><code class="language-bash">npx tsc --init</code></pre>
</li>
</ul>
<h1 id="tsconfigjson">tsconfig.json</h1>
<ul>
<li><p>아래 tsconfig파일은 nestjs에서 기본으로 프로젝트 생성 시 기본으로 설정되어 있는 항목이다.
기본으로 설정되어 있는 항목을 살펴보면 아래와 같다.</p>
<pre><code>{
&quot;compilerOptions&quot;: {
  &quot;module&quot;: &quot;commonjs&quot;,
  &quot;declaration&quot;: true,
  &quot;removeComments&quot;: true,
  &quot;emitDecoratorMetadata&quot;: true,
  &quot;experimentalDecorators&quot;: true,
  &quot;allowSyntheticDefaultImports&quot;: true,
  &quot;target&quot;: &quot;es2017&quot;,
  &quot;sourceMap&quot;: true,
  &quot;outDir&quot;: &quot;./dist&quot;,
  &quot;baseUrl&quot;: &quot;./&quot;,
  &quot;incremental&quot;: true,
  &quot;skipLibCheck&quot;: true,
  &quot;strictNullChecks&quot;: false,
  &quot;noImplicitAny&quot;: false,
  &quot;strictBindCallApply&quot;: false,
  &quot;forceConsistentCasingInFileNames&quot;: false,
  &quot;noFallthroughCasesInSwitch&quot;: false
}
}</code></pre></li>
<li><p><code>module</code>은 TS 에서 컴파일된 JS가 모듈이 어떤 모듈을 사용할지 설정하는 항목이다.
기본으로 CommonJS로 설정 되어 있으며 각각 설정 항목을 확인하자면 아래와 같다.</p>
</li>
<li><p>Commonjs</p>
</li>
<li><p>AMD</p>
</li>
<li><p>UMD</p>
</li>
<li><p>Syem</p>
</li>
<li><p>ES6, ES2015, ES2020, ESNext</p>
</li>
<li><p><code>target</code>은 타입스크립트 파일을 어떤 버전의 자바스크립트로 버전으로 컴파일 할 지 <code>target</code>을 설정하는 부분이다. 자바스크립트 버전(ECMA Script)은 es5(es2009), es6(es2015), es7(es2016), es8(es2017), es9(es2018) 등으로 원하는 버전을 지정하면 해당 타입스크립트가 선택한 자바스크립트 버전으로 컴파일 된다.
대표적으로 <code>commonjs</code>와 <code>amd</code>, <code>esnext</code> 가 있다.</p>
</li>
<li><p><code>noImplicitAny</code>은 any라는 타입이 의도치 않게 발생할 경우 에러를 발생하는 설정이다.</p>
</li>
</ul>
<pre><code class="language-json">{
 &quot;compilerOptions&quot;: {
  &quot;target&quot;: &quot;es5&quot;, // &#39;es3&#39;, &#39;es5&#39;, &#39;es2015&#39;, &#39;es2016&#39;, &#39;es2017&#39;,&#39;es2018&#39;, &#39;esnext&#39; 가능
  &quot;module&quot;: &quot;commonjs&quot;, //무슨 import 문법 쓸건지 &#39;commonjs&#39;, &#39;amd&#39;, &#39;es2015&#39;, &#39;esnext&#39;
  &quot;allowJs&quot;: true, // js 파일들 ts에서 import해서 쓸 수 있는지 
  &quot;checkJs&quot;: true, // 일반 js 파일에서도 에러체크 여부 
  &quot;jsx&quot;: &quot;preserve&quot;, // tsx 파일을 jsx로 어떻게 컴파일할 것인지 &#39;preserve&#39;, &#39;react-native&#39;, &#39;react&#39;
  &quot;declaration&quot;: true, //컴파일시 .d.ts 파일도 자동으로 함께생성 (현재쓰는 모든 타입이 정의된 파일)
  &quot;outFile&quot;: &quot;./&quot;, //모든 ts파일을 js파일 하나로 컴파일해줌 (module이 none, amd, system일 때만 가능)
  &quot;outDir&quot;: &quot;./&quot;, //js파일 아웃풋 경로바꾸기
  &quot;rootDir&quot;: &quot;./&quot;, //루트경로 바꾸기 (js 파일 아웃풋 경로에 영향줌)
  &quot;removeComments&quot;: true, //컴파일시 주석제거 

  &quot;strict&quot;: true, //strict 관련, noimplicit 어쩌구 관련 모드 전부 켜기
  &quot;noImplicitAny&quot;: true, //any타입 금지 여부
  &quot;strictNullChecks&quot;: true, //null, undefined 타입에 이상한 짓 할시 에러내기 
  &quot;strictFunctionTypes&quot;: true, //함수파라미터 타입체크 강하게 
  &quot;strictPropertyInitialization&quot;: true, //class constructor 작성시 타입체크 강하게
  &quot;noImplicitThis&quot;: true, //this 키워드가 any 타입일 경우 에러내기
  &quot;alwaysStrict&quot;: true, //자바스크립트 &quot;use strict&quot; 모드 켜기

  &quot;noUnusedLocals&quot;: true, //쓰지않는 지역변수 있으면 에러내기
  &quot;noUnusedParameters&quot;: true, //쓰지않는 파라미터 있으면 에러내기
  &quot;noImplicitReturns&quot;: true, //함수에서 return 빼먹으면 에러내기 
  &quot;noFallthroughCasesInSwitch&quot;: true, //switch문 이상하면 에러내기 
 }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Typescript] 제네릭(Generics)]]></title>
            <link>https://velog.io/@hong-brother/Typescript-%EC%A0%9C%EB%84%A4%EB%A6%ADGenerics</link>
            <guid>https://velog.io/@hong-brother/Typescript-%EC%A0%9C%EB%84%A4%EB%A6%ADGenerics</guid>
            <pubDate>Sun, 21 Aug 2022 15:49:47 GMT</pubDate>
            <description><![CDATA[<h1 id="generics이란">Generics이란?</h1>
<p>제네릭은 <code>&lt;&gt;</code>을 가지는 클래스와 인터페이스를 말하며, 데이터와 타입을 일반화 한다는 것을 뜻한다.
제네릭은 자료형을 정하지 않고 생성 시점에 타입을 명시하여 하나의 타입만을 사용하는것이 아니라 다양한 타입을 사용 할 수 있도록하는 것을 뜻한다.
<strong>즉, 특정 타입에 대해서 함수의 파라미터 처럼 사용 할 수 있도록 하는 것이다.</strong>
한번의 선언으로 다양한 타입을 <code>재사용</code>이 가능하다는 이유로 실무에서 많이 쓰인다.</p>
<h1 id="generics-사용법">Generics 사용법</h1>
<h2 id="함수에서의-제네릭">함수에서의 제네릭</h2>
<pre><code class="language-typescript">function getLogs&lt;T&gt;(message: T): T {
    console.log(T);
}

getLogs&lt;string&gt;(&#39;LOGGER Test&#39;);
getLogs&lt;number&gt;(123123);
getLogs&lt;boolean&gt;(true);</code></pre>
<p>함수에서의 제네릭을 사용하는 기본 문법형태이다. <code>getLogs&lt;T&gt;</code>와 같이 <code>T</code>에 제네릭을 선언하고 함수 사용시 타입을 넘겨 줄 수 있다.
입력 값의 타입이 <code>string</code>이면서 반환값도 <code>string</code>이어야 한다.</p>
<blockquote>
</blockquote>
<p>제네릭 함수를 호출할때 <code>&lt;&gt;</code>안에 타입을 명시하는 것은 필수가 아니다. <code>getLogs(&#39;test&#39;)</code>처럼 <code>&lt;&gt;</code>를 생략할 수 있는데 <code>&lt;&gt;</code>을 생략할 경우 컴파일러가 인수의 타입을 보고 타입을 경정한다.</p>
<h2 id="클래스에서의-제네릭">클래스에서의 제네릭</h2>
<pre><code class="language-typescript">class Mart&lt;T&gt; {
  private items: T[] = [];
  private price: number;

  push(goods: T): void {
    items.push(goods);
  }

  getList(): T {
    return this.items;
  }
}

const meal = new Mart&lt;string&gt;();
meal.push(&#39;a&#39;);

const numberMeal = new Mart&lt;number&gt;();
meal.push(1);</code></pre>
<p>클래스 선언부에 <code>&lt;T&gt;</code>라는 제네릭을 사용하겠다고 선언한다. 그리고 클래스 멤버 변수에 사용할 제네릭을 <code>T</code>와 같이 명시해 특정한 타입이 된다.</p>
<blockquote>
<p>제네릭에 <code>&lt;T&gt;</code>는 타입 매개변수(type argument)의 의미 이며 관용적으로 <code>T</code>를 사용할뿐 <code>T</code>대신에서 다른 문자를 사용해도 상관없다.</p>
</blockquote>
<h1 id="제네릭을-사용하는-이유">제네릭을 사용하는 이유</h1>
<ul>
<li>재사용성을 위한 제네릭 사용
  제네릭을 사용하면 함수에서 타입에 매개변수를 여러타입으로 처리 할 수 있으므로 중복되는 코드를 줄일 수 있으므로 코드의 가독성도 함께 향상된다.</li>
<li>컴파일 단계에서 에러 케치<ul>
<li>만약 제네릭을 <code>any</code>로 구현한다면 컴파일 단계에서 타입에대한 오류를 찾을 수 없다. 사실 <code>any</code>로 제네릭 대신 사용해도 상관없지만 우리가 왜 javascript를 두고 typescript를 쓰는지에 대한 의미를 한번 더 생각해보자!
<img src="https://velog.velcdn.com/images/hong-brother/post/53b41392-122f-468c-a68c-254d70973234/image.png" alt=""></li>
</ul>
</li>
</ul>
<h1 id="다양한-제네릭-사용">다양한 제네릭 사용</h1>
<h2 id="클래스에서의-멀티-제네릭">클래스에서의 멀티 제네릭</h2>
<pre><code class="language-typescript">class CustomClss &lt;T, V&gt; {
    genericData1: T;
      genericData2: V;

  constructor(t: T, v: V) {
    this.t = t;
    this.v = v;
  }

}</code></pre>
<p>해당 클래스는 제네릭을 2개의 값을 받을 수 있다. 기존 클래스에 제네릭을 사용하는 것과 동일 하다.</p>
<h2 id="인터페이스에서의-제네릭">인터페이스에서의 제네릭</h2>
<pre><code class="language-typescript">interface ICustomInterface&lt;T&gt; {
  value: T;
}</code></pre>
<ul>
<li>클래스와 같이 인터페이스에도 제네릭을 선언하여 사용 할 수 있다.</li>
</ul>
<h2 id="정의된-타입으로-제네릭-타입-제한">정의된 타입으로 제네릭 타입 제한</h2>
<pre><code class="language-typescript">interface LengthType {
  length: number;
}

function logMessageLength&lt;T extents LengthType&gt; (message: T): T {
  console.log(message.length);
  return message;
}

logMessageLength(&#39;error message&#39;);</code></pre>
<ul>
<li>제네릭을 사용시에는 원하지 않는 속성에 접근하는 것을 막기 위해 제약 조건을 사용 할 수 있다.
<code>extends</code> 키워드로 제약 조건을 걸어준다.</li>
<li>특정 타입들로만 동작하는 제네릭 함수를 만들때 유용하다.(제약 조건에 벗어나는 타입을 선언하면 에러가 발생한다.)</li>
</ul>
<h2 id="keyof로-제네릭의-타입-제한하기">keyof로 제네릭의 타입 제한하기</h2>
<pre><code class="language-typescript">interface ShoppingItem {
  name: string;
  price: number;
  stock: number;
}

type Test = keyof ShoppingItem; // (&quot;name&quot;, &quot;price&quot;, &quot;stock&quot;)
function getShoppingItemOption&lt;T extends keyof ShoppingItem&gt;(itemOption: T): T {
  return itemOption;
}

getShoppingItemOption(&#39;name&#39;)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[typescript] class]]></title>
            <link>https://velog.io/@hong-brother/typescript-class</link>
            <guid>https://velog.io/@hong-brother/typescript-class</guid>
            <pubDate>Sat, 20 Aug 2022 11:12:21 GMT</pubDate>
            <description><![CDATA[<h1 id="class란">Class란</h1>
<ul>
<li>클래스란 객체를 정의하는 틀 또는 설계도와 같은 의미로 사용된다.</li>
<li>클래스는 객체의 상태를 나타내는 <code>field</code>와 객체의 행동을 나타내는 <code>method</code>로 구성된다.</li>
<li><code>field</code>는 클래스에 포함된 변수를 의미하며 <code>method</code>는 어떠한 특정 작업을 수행하기 위한 명령문의 집합이라고 말 할 수 있다. <blockquote>
<p>ES6에서 새롭게 도입된 클래스는 기존 프로토타입 기반 객체지향 언어보다 클래스 기반 언어에 익숙한 개발자가 보다 빠르게 학습할 수 있는 새로운 문법을 제시하고 있다. </p>
</blockquote>
</li>
</ul>
<h2 id="typescript-clss">TypeScript Clss</h2>
<ul>
<li><p>ES6부터 추가된 Clss </p>
<pre><code class="language-javascript">class Coffe {
constructor(name, price) {
  this.name = name;
  this.price = price;
}

take() {
  return this.price;
}
}</code></pre>
<p>ES6에 추가된 Class에는 클래스 몸체에 <code>method</code>만 포함 할 수 있다. </p>
</li>
<li><p>typescript class</p>
<pre><code class="language-typescript">class Coffe {
    name: string;
    prise: number
constructor(name: string, price: number) {
  this.name = name;
  this.price = price;
}

take() {
  return this.price;
}
}</code></pre>
</li>
</ul>
<h2 id="접근-제한자">접근 제한자</h2>
<h3 id="멤버-변수에-대한-접근-제한자">멤버 변수에 대한 접근 제한자</h3>
<ul>
<li>TypeScript 클래스는 타언어가 지원하는 접근 제한자(Access modifier)-<code>public</code>, <code>private</code>, <code>protected</code>를 지원하며 의미 또한 타언어와 동일하다.</li>
</ul>
<table>
<thead>
<tr>
<th>접근 가능성</th>
<th>public</th>
<th>protected</th>
<th>private</th>
</tr>
</thead>
<tbody><tr>
<td>클래스 내부</td>
<td>O</td>
<td>O</td>
<td>O</td>
</tr>
<tr>
<td>자식 클래스 내부</td>
<td>O</td>
<td>O</td>
<td>X</td>
</tr>
<tr>
<td>클래스 인스턴스</td>
<td>O</td>
<td>X</td>
<td>X</td>
</tr>
</tbody></table>
<ul>
<li>클래스 내부 멤버 변수에 접근 제한자를 명시 하지 않는 경우 다른 클래스 기반언어는 암묵적으로 protected로 지정되어 상속을 받아야만 공개가 되지만 TypeScript의 경우는 암묵적으로 <code>public</code>으로 선언된다.</li>
</ul>
<pre><code class="language-typescript">class Paper {
  public x: string;
  protected y: string;
  private z: string;

  // public, protected, private 접근 제한자 모두 클래스 내부에서 참조 가능하다.
  constructor(x: string, y: string, z: string) {  
    this.x = x;
    this.y = y;
    this.z = z;
  }
}

const paper = new Paper(&#39;x&#39;, &#39;y&#39;, &#39;z&#39;);

console.log(paper.x); // public 접근 제한자는 생성된 인스턴스를 통해 접근 할 수 있다.

console.log(paper.y); // Property &#39;y&#39; is protected and only accessible within class &#39;Paper&#39; and its subclasses.

console.log(paper.z); // Property &#39;z&#39; is private and only accessible within class &#39;Paper&#39;.

class draw extends Paper {
  constructor(x: string, y: string, z: string) {
    super(x, y, z);

    console.log(this.y); // protected 접근 제한자는 자식 클래스 내부만 접근이 가능하다
  }
}</code></pre>
<h3 id="생성자-파라미터의-접근-제한자">생성자 파라미터의 접근 제한자</h3>
<ul>
<li>접근 제한자를 클래스 멤버 변수에만 선언 할 수있는거 뿐만 아니라 생성자 파라미터에도 선언 할 수 있다.</li>
<li>constructor에 선언된 생성자 파라미터 X는 멤버 변수로 자동으로 선언 되며 클래스 내부에서만 참조 가능하다.<pre><code class="language-typescript">class Paper {
constructor(private x: string) { }
}
</code></pre>
</li>
</ul>
<p>const Paper = new Paper(&#39;MAN~&#39;);</p>
<p>console.log(bar); // Bar { x: &#39;MAN~&#39; }</p>
<p>console.log(bar.x);  // private이 선언된 Paper.x는 클래스 내부에서만 참조 가능하다</p>
<pre><code>
## readonly 
- typescript에서는 타언어에서 지원하는 readonly를 사용 할 수 있다.
- readonly는 클래스 멤버 변수 선언 시 또는 생성자 내부에서만 값을 할당할 수 있다. 그 외의 경우에는 값을 절대 할당 하거나 변경 할 수는 없고 오직 읽기 가능한 상태가 된다.

```typescript
class Paper {
  private readonly VALUE: number = 12;
  private readonly X: string;

  constructor() { 
      this.X = &#39;just readonly&#39;;  
  }
}
</code></pre><h2 id="static">static</h2>
<ul>
<li><p>ES6에서 추가된 기능 이며 클래스에서 static 메소드를 정의 한다.
정적 메서드는 클래스 인스턴스가 아닌 클래스 이름으로 호출하기 때문에 인스턴스를 생성하지 않아도 된다.</p>
<pre><code class="language-typescript">class Paper {
static staticPaper() {
  return &#39;static&#39;
}

constructor() { 
    this.X = &#39;just readonly&#39;;  
}
}
</code></pre>
</li>
</ul>
<p>console.log(Paper.staticPaper()); //return &#39;static&#39;
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript]  Enum]]></title>
            <link>https://velog.io/@hong-brother/TypeScript-Enum</link>
            <guid>https://velog.io/@hong-brother/TypeScript-Enum</guid>
            <pubDate>Sat, 20 Aug 2022 09:36:03 GMT</pubDate>
            <description><![CDATA[<h1 id="enum">Enum</h1>
<p>enum이란 enumerated type의 줄임말로 열거형이라고 부르며 멤버라 불리는 명명된 값의 집합을 이루는 자료형이다. 열거자 이름들은 일반적으로 해당 언어의 상수 역할을 하는 식별자이다.
<strong>서로 연관된 상수들을 하나의 namespace로 묶어 응집도를 높이기 위함이다.</strong></p>
<h1 id="enum-종류">Enum 종류</h1>
<h2 id="숫자형-enum">숫자형 Enum</h2>
<pre><code class="language-typescript">enum Team {
  PL,   // 0
  PM,   // 1
  Developer, // 2
  Designer,  // 3
}

let hsnam:number = Team.Designer;
// Team.Designer = 3</code></pre>
<h2 id="문자형-enum">문자형 Enum</h2>
<pre><code class="language-typescript">export enum LangagueTypeEnum {
    JAVA = &#39;java&#39;,
    TS = &#39;typescript&#39;,
    JS = &#39;javascript&#39;,
    PYTHON = &#39;python&#39;,
}
let developer1:string = LangagueTypeEnum.JAVA;
// develop1 = java

let developer2:string = LangagueTypeEnum.PYTHON;
// develop2 = python</code></pre>
<h2 id="const-enum">const Enum</h2>
<p>const enum은 내부 상수값들이 전부 compile 단계에서 내부 필드를 전부 상수로 변경하기 때문에 런타임에 의존 모듈의 영향을 받지 않게 되며, 코드 크기가 더 적기 때문에 더 선호된다고 한다. 
아래 코드는 일반적은 Enum과 Const Enum에 대한 코드 이다.</p>
<pre><code class="language-typescript">enum JustEnumNumber {
  zero,
  one,
}

console.log(JustEnumNumber.one) // 1
console.log(JustEnumNumber)



const enum EnumNumber {
  zero,
  one,
}

console.log(EnumNumber.one) // 1
console.log(EnumNumber) // 1</code></pre>
<p>위의 코드를 javascript로 컴파일 하게 되면 아래와 같은 코드로 컴파일 된다.</p>
<pre><code class="language-typescript">&quot;use strict&quot;;
var JustEnumNumber;
(function (JustEnumNumber) {
    JustEnumNumber[JustEnumNumber[&quot;zero&quot;] = 0] = &quot;zero&quot;;
    JustEnumNumber[JustEnumNumber[&quot;one&quot;] = 1] = &quot;one&quot;;
})(JustEnumNumber || (JustEnumNumber = {}));
console.log(JustEnumNumber.one); // 1
console.log(JustEnumNumber);
console.log(1 /* EnumNumber.one */); // 1
console.log(EnumNumber); // 1</code></pre>
<p>const enum은 컴파일 단계에서 내부 필드를 전부 상수로 변경하기 때문에 런타임에 의존 모듈의 영향을 받지 않게 되며 코드의 크기가 더 작아진다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[redis] 캐싱 전략]]></title>
            <link>https://velog.io/@hong-brother/redis-%EC%BA%90%EC%8B%B1-%EC%A0%84%EB%9E%B5</link>
            <guid>https://velog.io/@hong-brother/redis-%EC%BA%90%EC%8B%B1-%EC%A0%84%EB%9E%B5</guid>
            <pubDate>Thu, 18 Aug 2022 16:21:22 GMT</pubDate>
            <description><![CDATA[<h1 id="redis">Redis</h1>
<h2 id="redis란">Redis란?</h2>
<ul>
<li>Redis는 Remote Dictionary Server의 약자로서 <code>키-값</code> 구조의 비정형 데이터를 저장하고 관리하기 위한 오픈소스 이다.</li>
<li>비관계형 데이터 베이스 이며 모든 데이터를 메모리로 불러와 처리하는 메모리 기반 데이터베이스(In-Memory) 이다.</li>
<li>영속성(Persistence) 보장을 위해 보관과 백업 기능이 있다.</li>
</ul>
<h2 id="key-value-모델">Key-Value 모델</h2>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/85938d3e-f7d8-41da-8271-28cd78fc28d4/image.png" alt=""></p>
<h3 id="주요-모델">주요 모델</h3>
<ul>
<li>String<ul>
<li>String 자료형은 단순히 <code>Key-Value</code> 형태로 값을 저장한다.</li>
</ul>
</li>
<li>Set<ul>
<li>Set은 집합형 Data Type으로 정렬되지 않고 중복되지 않는 데이터를 저장한다.</li>
</ul>
</li>
<li>Sorted Set<ul>
<li>Set 구조와 다르게 Value값을 score 기준으로 정렬하여 저장한다.</li>
</ul>
</li>
<li>List<ul>
<li>Linked List 형태로 lpush, rpush와 같이 List에 왼쪽 오른쪽에 데이터를 저장 할 수 있으며 Set과 다르게 중복된 데이터를 저장 할 수 있다.</li>
</ul>
</li>
<li>Hash<ul>
<li>Hash구조형태로 <code>field-value</code> 쌍의 hash 형태로 저장한다.</li>
</ul>
</li>
</ul>
<h2 id="expire">Expire</h2>
<ul>
<li>아무리 서버 메모리가 테라단위로 증설이 가능한다고 하지만 물리적인 하드웨어 비용은 한정적이기에 redis에서는 데이터에 대해서 expire를 설정 할 수 있다.</li>
<li>대부분 key에 Expire를 설정할 것을 권장 한다.</li>
</ul>
<h1 id="redis-캐시-전략">Redis 캐시 전략</h1>
<h2 id="lazy-loading">Lazy Loading</h2>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/c56e5902-73f3-4e86-b8d3-970851752386/image.png" alt=""></p>
<ul>
<li>클라이언트에게서 데이터가 필요로 해줄때 캐싱하는 로딩 전략</li>
<li>클라이언트 요청시 캐시 데이터가 없다면 캐시를 DB로 부터 로딩한다.</li>
</ul>
<h2 id="write-through">Write-Through</h2>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/bc7b78e5-24a0-47f8-88dc-dff2d9849fb7/image.png" alt=""></p>
<ul>
<li>데이터를 입력하거나 수정할때는 캐시 데이터 및 DB를 모두 함께 반영한다.
<img src="https://velog.velcdn.com/images/hong-brother/post/a75a5c39-3088-4fa8-aa6d-0ba11af7921f/image.png" alt=""></li>
<li>데이터를 조회 할때는 캐시 데이터만 조회 한다.</li>
</ul>
<h1 id="적용">적용</h1>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/1a5b48ab-34cd-4025-b93b-7a799d283a88/image.png" alt=""></p>
<h1 id="ref">Ref</h1>
<blockquote>
</blockquote>
<p><a href="https://ko.wikipedia.org/wiki/%EB%A0%88%EB%94%94%EC%8A%A4">위키백과</a>
<a href="https://sabarada.tistory.com/142">redis</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] Union Type, Intersection Type]]></title>
            <link>https://velog.io/@hong-brother/TypeScript-Union-Type-Intersection-Type</link>
            <guid>https://velog.io/@hong-brother/TypeScript-Union-Type-Intersection-Type</guid>
            <pubDate>Tue, 16 Aug 2022 16:12:53 GMT</pubDate>
            <description><![CDATA[<h1 id="union-type">Union Type</h1>
<h2 id="union-type-이란">Union Type 이란</h2>
<p>유니온타입이란 자바스크립트의 OR 연산자와 같이 타입을 &#39;A&#39; 또는 &#39;B&#39;로 타입을 지정 할 수 있다.</p>
<pre><code class="language-typescript">function infoText(data: string | number) {
  console.log(data);
}</code></pre>
<p>해당 <code>infoText</code>의 파라미터의 타입을 <code>string</code> 또는 <code>number</code> 타입이 모두 입력 될 수 있다.
이처럼 <code>|</code> 연산자를 이용하여 타입을 여러 개 연결하는 방식을 Union Type 방식이라고 한다.</p>
<p>함수나 변수에 타입을 지정하기에는 애매한 상황에서 유리 할 수 있다. <code>any</code>라는 타입을 사용하여 애매한 상황을 <code>Untion Type</code> 대신 해결 할 수 있지만 <code>any</code>타입을 마구 쓰다보면 우리가 타입스크립트를 사용하는 목적을 상실 할 수 있다./
<code>any</code>는 최대한 <strong>변수 타입체크 해제(?)</strong> 기능 말고는 사용을 자제 하길 바란다.</p>
<h2 id="union-type의-활용">Union Type의 활용</h2>
<pre><code class="language-typescript">type direction = &#39;left&#39; | &#39;right&#39; | &#39;up&#39; | &#39;down&#39;;
function move(action: direction) {
  console.log(action)
}</code></pre>
<p>위와 같이 사용 할 경우 action은 <code>left</code>, <code>right</code>, <code>up</code>, <code>down</code>에 대항하는 문자열만 사용 할 수 있다.</p>
<h1 id="intersection-type">Intersection Type</h1>
<h2 id="intersection-type-이란">Intersection Type 이란</h2>
<p>Untion Type과는 다르게 Intersection Type은 여러 가지 타입을 결합(교집합)해서 사용 할수 있다.
Intersction Type은 <code>|</code> 대신 <code>&amp;</code> 연산자를 사용하여 표현한다.</p>
<h2 id="intersection-type-활용">Intersection Type 활용</h2>
<pre><code class="language-typescript">interface Person {
  name: string;
  age: number;
}

interface Developer {
  name: string;
  skill: string
}

function askSomeone(someone: Developer &amp; Person) {
  someone.name;
  someone.age;
  someone.skill;
}</code></pre>
<p><code>Person</code>, <code>Developer</code>의 인터페이스 속성을 모두 포함하여 새로운 타입을 만들게 된다.</p>
<h1 id="ref">Ref</h1>
<p><a href="https://typescript-kr.github.io/pages/unions-and-intersections.html">타입스크립트 GitBook</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Typescript] interface, type]]></title>
            <link>https://velog.io/@hong-brother/Typescript-interface-type</link>
            <guid>https://velog.io/@hong-brother/Typescript-interface-type</guid>
            <pubDate>Mon, 15 Aug 2022 14:57:47 GMT</pubDate>
            <description><![CDATA[<h1 id="interface">interface</h1>
<ul>
<li>자바에서의 인터페이스는 클래스를 구현하기 전에 필요한 메서드를 정의하는 용도로 쓰이지만,타입스크립트에서는 인터페이스로 정의할 수 있는 타입의 종류와 인터페이스로 인터페이스 타입을 정의 하는 방벙으로 사용한다.</li>
</ul>
<h2 id="변수를-정의하는-인터페이스">변수를 정의하는 인터페이스</h2>
<ul>
<li>User라는 인터페이스를 정의 하고 <strong>hsnam</strong> 이라는 변수에 사전에 정의된 인터페이스를 정의 할 수 있다. 정의된 인터페이스에 맞는 속성을 명시를 해야 한다.<pre><code class="language-typescript">interface User {
age: number;
name: string;
}
</code></pre>
</li>
</ul>
<p>var hsnam: User = {
  name: &#39;hsname&#39;,
  age: 34
}</p>
<pre><code>
## 함수의 인자를 정의하는 인터페이스
- 해당 함수(getUser)의 인자는 정의된 인터페이스 형식을 준수하는 데이터만 받을 수 있다. 
```typescript
interface User {
  age: number;
  name: string;
}

function getUser(user: User) {
    console.log(user);
}

const hsnam = {
  name: &#39;hsnam&#39;,
  age: 100
}
getUser(hsnam);</code></pre><h2 id="함수-구조를-정의하는-인터페이스">함수 구조를 정의하는 인터페이스</h2>
<ul>
<li>자바와는 다르게 함수의 구조적인 설계도 타입스크립트는 정의하여 활용 할 수 있다.</li>
<li>해당 방법은 라이브러리를 직접 만들거나 협업할때 유용하게 사용 할 것 같다.<pre><code class="language-typescript">interface SumFunction {
(a: number, b: number): number; 
}
</code></pre>
</li>
</ul>
<p>var sum: SumFunction;
sum = function(a: number, b: number): number {
  return a + b;
}</p>
<pre><code>
## 인덱싱 방식을 정의하는 인터페이스
- 배열 안에 들어가는 index와 값을 인터페이스로 정의하여 활용 할 수 있다.
```typescript
interface StringArray {
  [index: number]: string;
}

var arr: StringArray = [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;];
arr[0]; // &#39;a&#39;</code></pre><h2 id="인터페이스-딕셔너리-패턴">인터페이스 딕셔너리 패턴</h2>
<ul>
<li>딕셔너리 패턴<pre><code class="language-typescript">interface StringRegexDictionary {
[key: string]: RegExp //정규표현식 생성자
}
</code></pre>
</li>
</ul>
<p>var obj: StringRegexDictionary = {
  // sth: /abc/,
  cssFile: /.css$/ ,
  jsFile: /.js$/ ,</p>
<p>}</p>
<pre><code>
## 인터페이스 상속
- 인터페이스는 extents 키워드를 사용하여 인터페이스 또는 클래스를 상속받아 확장 할 수 있다.
```typescript
interface Persion {
  name: string;
  age: number;  
}

interface Developer extends Person {
  language: string;
}

var hsnam: Developer = {
  language: &#39;ts&#39;,
  age: 100,
  name: &#39;홍식쓰~&#39;
}</code></pre><h1 id="type">type</h1>
<h2 id="타입-별칭type-aliases">타입 별칭(type aliases)</h2>
<ul>
<li>타입 별칭은 새로운 타입 값을 하나 생성하는 것이 아니라 정의한 타입에 대한 쉽게 참고할 수 있게 이름을 부여하는 것과 같다.<pre><code class="language-typescript"></code></pre>
</li>
</ul>
<p>type Person {
  name: string;
  age: number;
}</p>
<p>var hsnam: Person = {
  name: &#39;홍식쓰&#39;
  age: 12
}</p>
<p>```</p>
<h1 id="interface-vs-type">interface VS type</h1>
<ul>
<li>인터페이스와 타입별칭과 가장 큰 차이점은 타입의 확장 가능 여부 입니다. 인터페이스는 확장이 가능한데 반해 타입 별칭은 확장이 불가능 합니다. </li>
<li>따라서 간단한 타입 정의에서는 타입 별칭을 추천하지만 확장성을 고려해야하는 상황이라면 interface를 사용하는것을 추천합니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Typescript] class-validator-작성중]]></title>
            <link>https://velog.io/@hong-brother/typescript-class-validator</link>
            <guid>https://velog.io/@hong-brother/typescript-class-validator</guid>
            <pubDate>Tue, 09 Aug 2022 16:36:22 GMT</pubDate>
            <description><![CDATA[<h1 id="class-validator">Class-Validator</h1>
<blockquote>
</blockquote>
<p>Typescript환경이나 javascript에서 class-validator를 통하여 dto, vo, request data를 지정된 형식으로 validation하는 과정을 말한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Typescript] 기초 배우기]]></title>
            <link>https://velog.io/@hong-brother/typescript-%EA%B8%B0%EC%B4%88-%EB%B0%B0%EC%9A%B0%EA%B8%B0</link>
            <guid>https://velog.io/@hong-brother/typescript-%EA%B8%B0%EC%B4%88-%EB%B0%B0%EC%9A%B0%EA%B8%B0</guid>
            <pubDate>Wed, 03 Aug 2022 16:12:38 GMT</pubDate>
            <description><![CDATA[<h1 id="typescript의-변수">TypeScript의 변수</h1>
<h2 id="변수-선언">변수 선언</h2>
<ul>
<li>TS 문자열 선언<pre><code class="language-javascript">let str: string = &#39;hello&#39;;</code></pre>
</li>
<li>TS 숫자 선언<pre><code class="language-javascript">let num: number = 10;</code></pre>
</li>
<li>TS 배열 선언<pre><code class="language-javascript">let arr: Array&lt;number&gt; = [1,2,3];
let heroes: Array&lt;string&gt; = [&#39;Cept&#39;, &#39;Thor&#39;, &#39;Hulk&#39;];
let items: number[] = [1,2,3];
</code></pre>
</li>
</ul>
<pre><code>
## 튜플
- 배열에 인덱스에 타입을 세부적으로 지정할 수 있다.
```javascript
let address: [string, number] = [&#39;gangnam&#39;, 1000];</code></pre><h2 id="객체">객체</h2>
<pre><code class="language-javascript">let person: { name: string, age: number} = {
  name: &#39;thor&#39;,
  age: 1000
}</code></pre>
<h2 id="진위값">진위값</h2>
<pre><code class="language-javascript">let show: boolean = true;</code></pre>
<h1 id="함수">함수</h1>
<ul>
<li><p>함수의 파라미터에 타입을 정의하는 방식</p>
<pre><code class="language-javascript">function sum(a: number, b:number) {
  return a + b;  
}
sum(10, 20);</code></pre>
</li>
<li><p>함수의 반환 값에 타입을  정의하는 방식</p>
<pre><code class="language-javascript">function add(): number {
return 10;
}
add();</code></pre>
</li>
<li><p>함수에 타입을 정의하는 방식</p>
<pre><code class="language-javascript">function sum(a: number, b: number): number {
return a + b;
}
sum(10, 20);</code></pre>
</li>
<li><p>함수의 파라미터를 제한 하는 특성(유현한 javascript를 제약함)</p>
<pre><code class="language-javascript">function sum(a, b) {
return a + b;
}
</code></pre>
</li>
</ul>
<p>sum(10, 20, 30, 40, 50);</p>
<pre><code>
- 함수의 옵셔널 파라미터
```javascript
function log(a: string, b?: string) {
  console.log(a + b);
}

log(&#39;hello world&#39;);
log(&#39;hello ts&#39;, &#39;abc&#39;);</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] 타입스크립트 기초 ]]></title>
            <link>https://velog.io/@hong-brother/TypeScript-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EA%B8%B0%EC%B4%88</link>
            <guid>https://velog.io/@hong-brother/TypeScript-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EA%B8%B0%EC%B4%88</guid>
            <pubDate>Sun, 31 Jul 2022 15:31:07 GMT</pubDate>
            <description><![CDATA[<h1 id="타입스크립트란">타입스크립트란?</h1>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/370fe79d-17d0-4b5b-bae9-35fcf8828728/image.png" alt=""></p>
<ul>
<li>타입스크립트는 기존에 변수의 타입이 없는 자바스크립트에 정접타입을 부여한 언어이다. 자바스크립트의 확장된 언어라고 볼 수 있다. 타입스크립트는 자바스크립트와 달리 브라우저에서 실행하려면 컴파일 과정을 해야한다.</li>
<li>코드 작성 단계에서 타입을 체크해 사전에 오류를 확인 할 수 있고 미리 타입을 결정하기 때문에 실행 속도가 매우 빠르다는 장점이 있다.</li>
</ul>
<p>[참고]동적 타입 언어와 정적 타입 언어</p>
<table>
<thead>
<tr>
<th>동적 타입 언어</th>
<th>정적 타입 언어</th>
</tr>
</thead>
<tbody><tr>
<td>타입에 대한 고민을 하지 않아도 되므로 배우기 쉬움</td>
<td>변수를 선언 할 때 마다 타입을 고민해야 하므로 진입 장벽이 높다.</td>
</tr>
<tr>
<td>코드의 양이 적을 때 생샌성이 높다.</td>
<td>코드의 양이 많을 때 동적 타입 언어에 비해 생산성이 높다</td>
</tr>
<tr>
<td>타입 오류가 런타임 시 발견된다.</td>
<td>타입 오류가 컴파일 시 발견된다.</td>
</tr>
</tbody></table>
<h1 id="typescript의-특징">TypeScript의 특징</h1>
<h2 id="컴파일-언어-정적인-타입static-type">컴파일 언어, 정적인 타입(Static Type)</h2>
<ul>
<li>기존 타입이 없는 자바스크립트에 비해 타입스크립트는 컴파일 단계에서 타입을 체크하여 타입에 대한 오류를 사전에 줄여 줄 수 있다.</li>
<li>기존 자바스크립트의 타입에 대한 단점을 보안을 해주므로써 코드의 가독성을 높여준다.<h3 id="비교">비교</h3>
</li>
<li>javascript의 동적인 타입<pre><code class="language-javascript">function sum(a, b) {
  return a + b;
}</code></pre>
</li>
<li>typescript의 정적인 타입<pre><code class="language-javascript">function sum(a:number, b: number) {
  return a + b;
}</code></pre>
</li>
</ul>
<h2 id="자바스크립트의-슈퍼셋superset">자바스크립트의 슈퍼셋(Superset)</h2>
<ul>
<li>슈퍼셋은 확장을 뜻하며 기존 자바스크립트의 모든 기능을 사용 가능하며 이외에 타입스크립트만이 지원하는 클래스, 인터페이스등 사용할 수 있는 확장판이다.</li>
</ul>
<h2 id="객체지향-프로그래밍-지원">객체지향 프로그래밍 지원</h2>
<ul>
<li><p>타입스크립트는 es6에서 새롭게 사용된 문법을 포함하고 있으며 클래서, 인터페이스, 상속, 모듈 등 객체지향 프로그래밍을 지원한다.</p>
</li>
<li><p>타입스크립트의 클래스</p>
<pre><code class="language-javascript">export class TestClass {
private people: string;
private car: string;
}                        </code></pre>
</li>
<li><p>타입스크립트의 상속</p>
<pre><code class="language-javascript">export class HomeClass extents SummerClass {
private people: string;
private car: string;
}                 </code></pre>
</li>
</ul>
<h1 id="타입스크립트를-써야하는-이유">타입스크립트를 써야하는 이유</h1>
<h2 id="에러의-사전방지">에러의 사전방지</h2>
<pre><code class="language-typescript">function sum(a: number, b: number) {
  return a + b;
}</code></pre>
<ul>
<li>타입을 지정하므로써 의도하지 않은 코드의 동작을 예방 할 수 있다.</li>
<li>기존 자바스크립트인 경우 타입을 지정하지 않고 sum(10, &#39;20&#39;)입력을 하게 되면 &#39;1020&#39; 이라는 결과를 얻게 된다. <blockquote>
</blockquote>
자바를 하던 나로써는 nodejs로 넘어 오면서 명확하게 타입을 지정 할 수 있다는 typescript를 마음에 들어 하게 되었다. 하지만 아직은 자바가 더 좋은걸ㅠㅠㅠ</li>
</ul>
<h2 id="코드-가이드-및-자동완성">코드 가이드 및 자동완성</h2>
<ul>
<li>인텔리J에 익숙한 개발자는 쉽게 VSCode로 넘어가기 힘든것 같다. 인텔리J와 비슷한 웹스톰을 사용해서 typescript를 개발하는데 웹스톰에서도 코드 가이드 및 자동완성을 불폄함 없을 정도로 지원을 해준다.</li>
</ul>
<blockquote>
</blockquote>
<p>참고 
<a href="https://joshua1988.github.io/ts/why-ts.html#%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%9E%80">타입스크립트 핸드북</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[jenkins] nestjs 배포 개선]]></title>
            <link>https://velog.io/@hong-brother/jenkins-nestjs-%EB%B0%B0%ED%8F%AC-%EA%B0%9C%EC%84%A0</link>
            <guid>https://velog.io/@hong-brother/jenkins-nestjs-%EB%B0%B0%ED%8F%AC-%EA%B0%9C%EC%84%A0</guid>
            <pubDate>Sat, 30 Jul 2022 15:56:55 GMT</pubDate>
            <description><![CDATA[<h1 id="goal">Goal</h1>
<ul>
<li>Jenkins를 이용하여 NestJS를 배포한다.</li>
<li>NestJS를 배포하면서 배포 속도를 개선한다.</li>
</ul>
<h1 id="전제조건">전제조건</h1>
<blockquote>
</blockquote>
<ul>
<li>Jenkins에 필요한 설정은 사전에 셋팅이 되어 있다.</li>
<li>NestJS는 dockerize되어 있지 않고 PM2로 관리 되어 있다.</li>
</ul>
<h1 id="배포">배포</h1>
<p>Application을 만들기 위해서는 여러명의 개발자들과 협업을 하면서 한개의 프로젝트에 여려명이 투입되어 개발을 하게 된다. 
그럼 당연히 Git이나 SVN등등 사용 할 것이며 이 모든 변경 사항을 서버에 배포가 이루어져야 하는데 코드가 변경될 때마다 매번 메인 개발자 또는 배포를 담당하는 개발자가 수동으로 배포하는것은 요즘 시대에 너무나도 멍청한 짓이다.(배포만 하는것이 아니라 다른일도 해야하는데... )
그러기에 CI/CD는 요즘 세상에는 필수이다. 그렇다면 회사에서는 CI/CD를 통하여 한 프로젝트당 3개의 서버에 배포가 된다. develop에 배포되는 서버가 따로 있고 release에 배포되는 서버가 따로 있으며 운영에 배포되는 서버는 따로 있으며 운영에 배포되는 서버는 특수한 상황(?)에 따라 수동으로 배포된다.
코드가 변경되서 develop, release 브렌치가 되면 merge가 되면 WebHook을 통하여 Jenkins에서 배포 하는 과정을 정리해보겠다.</p>
<h2 id="plan-1">Plan 1</h2>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/bfbbf33a-3213-43a8-80b1-632255a64438/image.png" alt=""></p>
<h3 id="jenkins-flow">Jenkins flow</h3>
<ul>
<li>누군가에 의해서 develop 브렌치에서 merge가 되면 Github에서 WebHook을 통하여 변경 감지를 알려준다.</li>
<li>Jenkins 서버는 즉시 소스코드를 Workspace에 clone을 받는다. (git clone)</li>
<li>Jenkins 서버는 필요한 라이브러리를 받는다 (npm install)</li>
<li>Jenkins 서버는 해당 코드를 javascript로 빌드한다(npm run build)</li>
<li>Jenkins 서버는 빌드된 결과물을 scp를 통하여 해당서버에 파일을 보낸다.</li>
<li>배포서버는 pm2 reload하여 인스턴스를 재시작한다.</li>
</ul>
<h3 id="장점">장점</h3>
<ul>
<li>해당 방법은 npm install, npm run build등 과정에서 문제가 생겨도 배포서버에 문제가 되지 않는다. </li>
<li>딱히 다른 장점(?) 잘 모르겠다.</li>
</ul>
<h3 id="단점">단점</h3>
<ul>
<li>Jenkis 서버 운영체제와 배포 운영체제가 틀릴 경우 npm install과정에서 운영체제에 따라 받아오는 라이브러리 틀려서 배포시 문제가 발생 할 수 있다.</li>
<li>배포서버에 불필요한 파일이 존재하며 node_modules을 scp로 옮기는 시간이 많이 걸린다.
(배포 서버에는 node_modules, ecosystem.config.js, dist파일만 필요)</li>
<li>Jenkis에서는 node버전을 상황에 따라 여러개로 셋팅을 해줘야 한다.</li>
</ul>
<h2 id="plan-2">Plan 2</h2>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/6817d2bf-4957-4ec3-9eae-a5c6a55be0fe/image.png" alt=""></p>
<h3 id="jenkins-flow-1">Jenkins flow</h3>
<ul>
<li>누군가에 의해서 develop 브렌치에서 merge가 되면 Github에서 WebHook을 통하여 변경 감지를 알려준다.</li>
<li>Jenkins 서버는 즉시 소스코드를 Workspace에 clone을 받는다. (git clone)</li>
<li>Jenkins 서버에서는 clone받은 파일을 scp를 통하여 배포서버에 파일을 보낸다.</li>
<li>배포 서버에서는 필요한 라이브러리를 받는다 (npm install)</li>
<li>배포 서버에서는 해당 코드를 javascript로 빌드한다(npm run build)</li>
<li>배포 서버에서는 pm2 reload하여 인스턴스를 재시작한다.</li>
</ul>
<h3 id="장점-1">장점</h3>
<ul>
<li>Jenkins에서는 node버전을 신경 쓰지 않아도 된다.</li>
<li>Jenkins서버에서 배포 서버로 파일을 보낼때 코드만 보내므로 전송 속도가 빠르다.</li>
<li>Jenkins서버와 배포서버 운영체제가 달라도 문제가 되지 않는다.</li>
</ul>
<h3 id="단점-1">단점</h3>
<ul>
<li>npm install, npm build등 서버에서 문제가 발생하면 바로 배포서버는 문제가 발생한다.</li>
</ul>
<h2 id="결과">결과</h2>
<p><img src="https://velog.velcdn.com/images/hong-brother/post/8b9e8002-c15d-469e-a6a6-0f8757443f58/image.png" alt=""></p>
<ul>
<li>#45번은 Plan1 Job 시간이 2분 4초 이며 #54번은 Plan2 Job 시간이 1분 18초이다.</li>
<li>확실히 배포 속도가 약 50%감소 하였으며 좀더 빠르게 배포를 진행 할 수 있었다.</li>
<li>Plan1과 Plan2를 비교 하였을때 안정성은 Plan1이라고 말 할 수도 있을 것 같다. 하지만 merge이전에 코드리뷰 및 테스트 케이스자동화로 인하여 문제될만한 것들은 사전에 차단하기 때문에 빠르게 배포하는것이 중요 하다고 생각한다</li>
<li>빠르게 배포하는이유는 팀원들과 같이 개발하는 중에 FE쪽에서 배포때문에 개발흐름이 끊어 질 수도 있고 개발 서버만큼은 빠르게 배포하여 피드백을 받는것이 중요하다고 생각하기 때문이다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[jenkins] pipeline에서 ssh 사용]]></title>
            <link>https://velog.io/@hong-brother/jenkins-pipeline%EC%97%90%EC%84%9C-ssh-%EC%82%AC%EC%9A%A9</link>
            <guid>https://velog.io/@hong-brother/jenkins-pipeline%EC%97%90%EC%84%9C-ssh-%EC%82%AC%EC%9A%A9</guid>
            <pubDate>Wed, 27 Jul 2022 16:19:56 GMT</pubDate>
            <description><![CDATA[<h1 id="goal">GOAL</h1>
<ul>
<li>Jenkins에서 PipeLine을 이용하여 배포 script 작성시 ssh 사용하기<blockquote>
</blockquote>
전제조건
ssh에 필요한 ssh agent가 설치 되어 있다는 전제조건으로 시작합니다.
Jenkins는 docker에서 기반으로 실행되고 있습니다.</li>
</ul>
<h1 id="ssh-인증서-생성하기">SSH 인증서 생성하기</h1>
<ul>
<li><p>*<em>SSH 인증키는 jenkins가 설치된 서버에서 생성합니다. *</em>
Native로 설치된 Jenkins라면 home 디렉토리 에서 .ssh로 이동합니다. 또는 docker container로 실행된 jenkins라면 jenkins_home/.ssh 디렉토리로 이동합니다.</p>
</li>
<li><p>인증서를 생성합니다.
```bash
ssh-keygen -t rsa -b 4086
enerating public/private rsa key pair.
Enter file in which to save the key (/home/hsnam/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/hsnam/.ssh/id_rsa.
Your public key has been saved in /home/hsnam/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:es3MyESZ54fFjTKE5m3VP6NONzVmaxVMG26G2BxcWRk <a href="mailto:hsnam@hsnam-ssh.localdomain">hsnam@hsnam-ssh.localdomain</a>
The key&#39;s randomart image is:</p>
</li>
<li><p>---[RSA 4086]----+
|         .. .o+E<em>|
|        o+ .=+==o|
|       o+.+o++.</em>.|
|       ..oo=  o*+|
|        S.o . + B|
|       + * . o = |
|      . + = o o .|
|       .     .   |
|                 |</p>
</li>
<li><p>----[SHA256]-----+</p>
<pre><code>인증키 생성시 공개키(id_rsa.pub), 비밀키(id_rsa)가 생성된다.</code></pre></li>
<li><p>공개키를 원격 호스트에 복사한다.(배포대상 서버)</p>
<pre><code class="language-bash">ssh-copy-id -i /home/hsnam/.ssh/id_rsa.pub hsnam@192.168.0.2</code></pre>
</li>
<li><p>Host key checking 
터미널에서 ssh 접속시 yes/no로 접속할지 물어본다. jenkins에서 ssh접속시 접속여부에 물어보지 안도록 한번은 아래와 옵션으로 접속하여 사용하도록 한다.</p>
<pre><code class="language-bash">ssh -o StrictHostKeyChecking=no hsnam@192.168.0.2</code></pre>
<p>만약 docker container로 운영중인 jenkins라면 container로 접속하여 설정하도록 하자.!</p>
</li>
</ul>
<h1 id="jenkins에-ssh-비밀키-등록">Jenkins에 SSH 비밀키 등록</h1>
<blockquote>
</blockquote>
<p>Dashboard &gt; Credentials &gt; System &gt; Global credentials &gt; Add Credentials</p>
<ol>
<li>인증서 등록
<img src="https://velog.velcdn.com/images/hong-brother/post/a357c789-b0fd-42b2-b806-649292952b3e/image.png" alt=""></li>
</ol>
<ul>
<li>ID<ul>
<li>PipeLine에서 설정한 ID로 설정값을 가져오기 때문에 중복되지 않은 ID를 입력한다.</li>
</ul>
</li>
<li>Private Key <ul>
<li>Enter directly를 설정하여 위에서 생성한 private key를 입력한다.</li>
</ul>
</li>
</ul>
<h1 id="pipeline-에서-ssh-사용하기">PIPELINE 에서 SSH 사용하기</h1>
<pre><code class="language-js">env.TARGET_HOST = &quot;hsnam@192.168.0.2&quot;
node {
    try {
        stage(&#39;ssh-test&#39;) {
            sshagent (credentials: [&#39;192.168.0.2-ssh&#39;]) {
                sh &#39;ssh -o StrictHostKeyChecking=no &quot;uptime&quot;&#39;
            }
        }
    } catch (env) {
        echo &#39;error = &#39; + env
        throw env
    }
}</code></pre>
<ul>
<li>위와 같이 pipline script를 작성하고 job을 실행 하면 해당 서버의 uptime 결과를 확인 할 수 있다.</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>