<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Darren's Devlog</title>
    <link>https://darrenlog.tistory.com/</link>
    <description>Junior Backend Developer</description>
    <language>ko</language>
    <pubDate>Tue, 11 Aug 2026 07:34:31 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Darren Gwon</managingEditor>
    <item>
      <title>제네릭스: 타입시스템</title>
      <link>https://darrenlog.tistory.com/47</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번 게시글에서는 제네릭스부터 시작해, 클래스와 타입, 일반화, 변성에 대한 개념에 대해 설명한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모두 타입과 관련된 일반적인 개념이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그래밍 언어는 타입으로 부터 시작한다고 해도 과언이 아닐 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;그렇기 때문에 개발자는 타입 시스템을 잘 이해할 필요가 있다고 생각하며 정리를 시작했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;말은 거창하게 했지만, 본 게시글에서 다루는 내용은 사실 타입 시스템에서도 아주 기초적인 부분이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 게시글은 코틀린 인 액션의 제네릭스 챕터를 많이 인용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문법적 표현의 차이는 존재할 수 있지만 전반적인 개념을 이해하는데는 문제가 없을거라(?) 생각한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;제네릭스&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-sourcepos=&quot;3:1-4:46&quot; data-ke-size=&quot;size16&quot;&gt;제네릭은 타입 안전성을 유지하면서 유연성을 제공하는 중요한 기능이다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-sourcepos=&quot;3:1-4:46&quot; data-ke-size=&quot;size16&quot;&gt;내부에서 사용할 데이터 타입을 외부에서 지정할 수 있다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-sourcepos=&quot;3:1-4:46&quot; data-ke-size=&quot;size16&quot;&gt;타입 파라미터를 사용하여 다양한 타입의 인스턴스를 생성할 수 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;제네릭 클래스 선언&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;118&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CSW71/btsDGqAPzpV/7Fqcjbn0IGBQkpAy9YwIn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CSW71/btsDGqAPzpV/7Fqcjbn0IGBQkpAy9YwIn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CSW71/btsDGqAPzpV/7Fqcjbn0IGBQkpAy9YwIn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCSW71%2FbtsDGqAPzpV%2F7Fqcjbn0IGBQkpAy9YwIn1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;320&quot; height=&quot;118&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;118&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1705756467802&quot; class=&quot;angelscript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Box&amp;lt;T&amp;gt; { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #4a7ba6;&quot;&gt;클래스 이름&lt;/span&gt;&lt;/b&gt; 뒤, 다이아몬드 연산자에 &lt;b&gt;&lt;span style=&quot;color: #f17456;&quot;&gt;타입 파라미터&lt;/span&gt;&lt;/b&gt;를 지정하여 클래스를 &lt;span style=&quot;background-color: #e6f4fa;&quot;&gt;&lt;a style=&quot;background-color: #e6f4fa;&quot; title=&quot;not specific&quot; href=&quot;https://www.oxfordlearnersdictionaries.com/definition/english/generic_1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;제네릭하게&lt;/a&gt;&lt;/span&gt; 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 클래스 내부에서&lt;b&gt; &lt;span style=&quot;color: #f17456;&quot;&gt;타입 파라미터&lt;/span&gt;&lt;/b&gt;를 일반 타입처럼 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: GungSeo, serif;&quot;&gt;일반 클래스&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1705738108450&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Toy { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 클래스에는 타입 파라미터가 선언되어있지 않다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: 'Noto Serif KR';&quot;&gt;제네릭 타입&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;318&quot; data-origin-height=&quot;102&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ECOR9/btsDIBO830T/bXRznsSt8VIsLwZauq3Ll1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ECOR9/btsDIBO830T/bXRznsSt8VIsLwZauq3Ll1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ECOR9/btsDIBO830T/bXRznsSt8VIsLwZauq3Ll1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FECOR9%2FbtsDIBO830T%2FbXRznsSt8VIsLwZauq3Ll1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;318&quot; height=&quot;102&quot; data-origin-width=&quot;318&quot; data-origin-height=&quot;102&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;position: absolute;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 클래스를 타입으로 지정할 수 있듯이, 제네릭 클래스를 타입으로 지정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #f17456;&quot;&gt;타입 파라미터&lt;/span&gt;&lt;/b&gt;에 실제 타입을 &lt;b&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;타입 인자&lt;/span&gt;&lt;/b&gt;로 넘기면 &lt;b&gt;&lt;span style=&quot;color: #99d689;&quot;&gt;제네릭 타입&lt;/span&gt;&lt;/b&gt;이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;타입인자&lt;/span&gt;&lt;/b&gt;로 실제 타입 Toy를 넘겨 &lt;b&gt;&lt;span style=&quot;color: #99d689;&quot;&gt;Box&amp;lt;Toy&amp;gt;타입&lt;/span&gt;&lt;/b&gt;이 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: GungSeo, serif;&quot;&gt;일반 타입&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1705757384196&quot; class=&quot;kotlin&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;kotlin&quot;&gt;&lt;code&gt;val toy: Toy&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;일반 타입은 타입인자 없이, 일반 클래스명으로 타입을 지정한 형태를 보이고 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;제네릭 함수/메서드&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;513&quot; data-origin-height=&quot;62&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c81YoD/btsDLJZwr6t/BHFeMGcKwpS2mwoK6dH24K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c81YoD/btsDLJZwr6t/BHFeMGcKwpS2mwoK6dH24K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c81YoD/btsDLJZwr6t/BHFeMGcKwpS2mwoK6dH24K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc81YoD%2FbtsDLJZwr6t%2FBHFeMGcKwpS2mwoK6dH24K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;513&quot; height=&quot;62&quot; data-origin-width=&quot;513&quot; data-origin-height=&quot;62&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1705744314844&quot; class=&quot;kotlin&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;kotlin&quot;&gt;&lt;code&gt;fun &amp;lt;T&amp;gt; List&amp;lt;T&amp;gt;.elementAt(index: Int): T { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;제네릭 클래스 선언과 동일하게, 제네릭 함수/메서드도 T를 &lt;b&gt;&lt;span style=&quot;color: #f17456;&quot;&gt;타입 파라미터&lt;/span&gt;&lt;/b&gt;로 받는다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #f17456;&quot;&gt;타입 파라미터&lt;/span&gt;&lt;/b&gt;를 매개변수의 타입, 반환 타입, 그리고 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;수신 객체에 사용할 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: GungSeo, serif;&quot;&gt;일반 함수/메서드&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1705760400184&quot; class=&quot;kotlin&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun compareTo(other: String): Int&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;일반 함수에는 타입파라미터가 선언되어있지 않다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;letter-spacing: normal;&quot;&gt;타입 파라미터 제약(Generic Constraints)&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;78&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wMExf/btsDJFjiB2o/b21ImT1GbK6CoQgmOy6fI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wMExf/btsDJFjiB2o/b21ImT1GbK6CoQgmOy6fI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wMExf/btsDJFjiB2o/b21ImT1GbK6CoQgmOy6fI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwMExf%2FbtsDJFjiB2o%2Fb21ImT1GbK6CoQgmOy6fI0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;480&quot; height=&quot;78&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;78&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입 파라미터 제약은 클래스나 함수에 사용할 수 있는 &lt;b&gt;&lt;span style=&quot;color: #8a3db6; text-align: start;&quot;&gt;타입 인자&lt;/span&gt;&lt;/b&gt;를 제한하는 기능이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ffc6cf;&quot;&gt;특정 타입&lt;/span&gt;&lt;/b&gt;을 타입 파라미터에 대한 &lt;b&gt;&lt;span style=&quot;color: #ffc6cf;&quot;&gt;상한(upper bound)&lt;/span&gt;&lt;/b&gt;으로 지정하여 &lt;b&gt;&lt;span style=&quot;color: #8a3db6; text-align: start;&quot;&gt;타입 인자&lt;/span&gt;&lt;/b&gt;를 제한할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;어느 날, 프로그램에 합계를 구하는 기능이 필요해졌다고 가정해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1705823468837&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun sum(list: List&amp;lt;Int&amp;gt;): Int {
    var sum: Int = 0;
    for (i in list) {
        sum += i
    }
    return sum
}

fun main(args: Array&amp;lt;String&amp;gt;) {
    val numbers: List&amp;lt;Int&amp;gt; = (1..9).toList()
    print(sum(numbers))
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Int로 구성된 리스트를 매개변수로 받아 합계를 구하는 로직을 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후에 Long타입도 고려가 되어야 한다고 하여 코드를 추가했다.&lt;/p&gt;
&lt;pre id=&quot;code_1705823596821&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun sum(list: List&amp;lt;Long&amp;gt;): Long {
    var sum: Long = 0;
    for (i in list) {
        sum += i
    }
    return sum
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지는 특별한 문제가 없을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 또 다른 타입들도 고려되어야 한다면, 계속해서 비슷한 기능의 다른 코드가 늘어날 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705823717668&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun sum(list: List&amp;lt;Float&amp;gt;): Float { ... }
fun sum(list: List&amp;lt;Double&amp;gt;): Double { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다양한 타입 때문에 코드가 늘어나는 게 문제라면, 모든 타입을 받도록 수정하면 되지 않을까?&lt;/p&gt;
&lt;pre id=&quot;code_1705836076531&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun sum(list: List&amp;lt;Any&amp;gt;): Double { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드는 리스트의 요소가 불분명하기 때문에 적절한 sum함수라고 할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 요구사항을 타입 파라미터 제약을 활용하여 개선할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제약을 위한 상한 타입 잘 지정하기 위해서는 일반화하는 과정이 필요하다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;일반화(Generalization)&lt;/span&gt;&lt;span style=&quot;font-family: GungSeo, serif;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;font-family: GungSeo, serif;&quot;&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #444444; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #e6f4fa;&quot;&gt;&lt;a style=&quot;background-color: #e6f4fa; color: #0070d1;&quot; href=&quot;https://coart.tistory.com/11&quot;&gt;일반화&lt;/a&gt;&lt;/span&gt;란 여러 실체유형 간의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;공통적인 특성을 파악하는 과정&lt;/b&gt;을 말한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 예제에 일반화를 적용하며 개선해 보도록 하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1364&quot; data-origin-height=&quot;488&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PIsDM/btsDXxYNyIE/Lx7GlBePIHEU3lHFD2wkUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PIsDM/btsDXxYNyIE/Lx7GlBePIHEU3lHFD2wkUk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PIsDM/btsDXxYNyIE/Lx7GlBePIHEU3lHFD2wkUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPIsDM%2FbtsDXxYNyIE%2FLx7GlBePIHEU3lHFD2wkUk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;575&quot; height=&quot;206&quot; data-origin-width=&quot;1364&quot; data-origin-height=&quot;488&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 사용했던 8개의 자료형들을 정수와 부동소수점수(floating-point number) 그룹으로 분류했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정수와 부동소수점수 두 그룹 모두 컴퓨터에서 수(numeric value)를 표현한다는 &lt;b&gt;공통적인 특성&lt;/b&gt;을 가지고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 수(numeric value)를 &lt;b&gt;대표하는 자료형&lt;/b&gt;을 만들어 관계를 맺을 수 있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1640&quot; data-origin-height=&quot;456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PuF3C/btsDGr7HMP5/QVtM336gf8pifxPnAK607k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PuF3C/btsDGr7HMP5/QVtM336gf8pifxPnAK607k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PuF3C/btsDGr7HMP5/QVtM336gf8pifxPnAK607k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPuF3C%2FbtsDGr7HMP5%2FQVtM336gf8pifxPnAK607k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;623&quot; height=&quot;173&quot; data-origin-width=&quot;1640&quot; data-origin-height=&quot;456&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #e6f4fa;&quot;&gt;&lt;a style=&quot;background-color: #e6f4fa;&quot; title=&quot;Superclass for all platform classes representing numeric values.&quot; href=&quot;https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-number/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; Number 클래스&lt;/a&gt;&lt;/span&gt;를 만들어 정수와 부동소수점수 타입들이 Number클래스를 &lt;b&gt;확장&lt;/b&gt;하도록 수정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 Number는 &lt;b&gt;일반화된 타입&lt;/b&gt;이고 정수 자료형들과 부동소수점수 자료형들은 &lt;b&gt;구체화된 타입&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &amp;nbsp;&lt;b&gt;&lt;span style=&quot;color: #ffc6cf;&quot;&gt;상한 타입을&lt;/span&gt;&lt;/b&gt;&amp;nbsp;지정하여 코드를 개선해 보도록 하겠다.&lt;/p&gt;
&lt;pre id=&quot;code_1705834573015&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun &amp;lt;T: Number&amp;gt; sum(list: List&amp;lt;T&amp;gt;): Double {
    var sum: Double = 0.0;
    for (i in list) {
        sum += i.toDouble()
    }
    return sum
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반화된 타입 Number를 &lt;b&gt;&lt;span style=&quot;color: #ffc6cf;&quot;&gt;상한 타입으로&lt;/span&gt;&lt;/b&gt; 지정한 제네릭 함수를 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sum함수는 Number와 그 하위 타입만 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;타입 인자로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;허용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 sum함수는 우리가 기대하는 합산 기능을 안전하게 수행할 수 있다는 것이 보장되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;타입을 정하는 매 순간 &lt;span style=&quot;font-family: 'Noto Serif KR'; color: #333333; text-align: center;&quot;&gt;일반화는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;고려된다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;개발자는 필요에 따라 타입을 일반화하는 기술이 필요하다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000; font-size: 1.62em; letter-spacing: -1px;&quot;&gt;클래스와 타입&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; letter-spacing: 0px;&quot;&gt;타입 간의 상위타입(supertype), 하위타입(subtype) 개념이 존재한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;앞선 일반화 과정을 통해, 공통된 특성을 파악하고,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;일반화된&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;새로운 클래스&lt;/b&gt;를 생성하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;타입 간의 관계&lt;/b&gt;를 맺어주는 과정을 보았다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;클래스와 타입은 서로 밀접하게 연관되어 있기 때문에 이 둘의 개념이 혼용되는 경우가 있다.&lt;br /&gt;타입 간의 관계를 더 얘기하기 전에 먼저 클래스와 타입의 차이에 대해 알아보자.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: GungSeo, serif;&quot;&gt;일반 클래스&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;일반 클래스에서는 클래스 이름 그대로 타입을 표현할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1705923749347&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val firstName: String
val lastName: String&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: GungSeo, serif;&quot;&gt;Nullable 타입&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;일반 클래스가 두 개 이상의 타입을 구성할 수도 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1706012329289&quot; class=&quot;kotlin&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;kotlin&quot;&gt;&lt;code&gt;val fullname: String
val nickname: String?&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;String 클래스는 Nullable(널 허용), Non-nullable(널이 될 수 없는) 타입이 될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: GungSeo, serif;&quot;&gt;제네릭 클래스&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;제네릭 클래스의 타입은 조금 더 특별하다.&lt;/p&gt;
&lt;pre id=&quot;code_1705924696756&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val texts: ArrayList&amp;lt;String&amp;gt;
val numbers: ArrayList&amp;lt;Number&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;같은 ArrayList 클래스이지만, ArrayList&amp;lt;String&amp;gt;는 타입이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;ArrayList&amp;lt;String&amp;gt;, ArrayList&amp;lt;Number&amp;gt;, ArrayList&amp;lt;Any&amp;gt; 모두 엄연히 서로 다른 타입이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;제네릭 클래스는 무수히 많은 타입을 만들어낼 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;클래스와 타입은 서로 다르다는 것을 알았으니 타입 관계에 알아보도록 하겠다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #333333;&quot;&gt;타입 관계 - 하위 타입(Subtype)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입 사이의 하위 타입 개념은 다음과 같은 이유로 아주 중요하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;color: #333333;&quot;&gt;컴파일러는 변수에 값을 할당하거나 함수/메서드 인자 전달 시,&amp;nbsp;&lt;b&gt;하위 타입 검사를 매번 수행한다.&lt;/b&gt;&lt;/li&gt;
&lt;li style=&quot;color: #333333;&quot;&gt;어떤 값의 타입이, 변수 타입의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;하위 타입인 경우에만&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;변수에 값을 할당한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #333333;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&quot;어떤 타입 A의 값이 필요한 곳에 어떤 타입 B의 값을 넣어도 아무 문제가 없다면,&lt;br /&gt;타입 B는 타입 A의 하위 타입이다.&quot;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #9d9d9d; text-align: center;&quot;&gt;코틀린 인 액션 p.407&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1258&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ce8wz/btsDRKZRH0r/xidjNCkvoogGSfKcMX4lMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ce8wz/btsDRKZRH0r/xidjNCkvoogGSfKcMX4lMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ce8wz/btsDRKZRH0r/xidjNCkvoogGSfKcMX4lMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCe8wz%2FbtsDRKZRH0r%2FxidjNCkvoogGSfKcMX4lMK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;133&quot; data-origin-width=&quot;1258&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아주 당연한 말 일수도 있겠지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;Number 타입의 값이 필요한 곳에 Int타입의 값을 넣어도 아무 문제가 없으니, Int는 Number의 하위 타입이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;String 타입이 필요한 곳에 Int타입의 값을 넣을 수 없으니, Int는 String의 하위 타입이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1492&quot; data-origin-height=&quot;366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LxFCF/btsDW4brimr/hCblEYCXoSwNfbXuLFutW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LxFCF/btsDW4brimr/hCblEYCXoSwNfbXuLFutW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LxFCF/btsDW4brimr/hCblEYCXoSwNfbXuLFutW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLxFCF%2FbtsDW4brimr%2FhCblEYCXoSwNfbXuLFutW0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;650&quot; height=&quot;159&quot; data-origin-width=&quot;1492&quot; data-origin-height=&quot;366&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 언급한 Nullable과 Non-nullable 타입에도 상위/하위타입 관계를 적용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nullable타입의 경우, null과 아닌 값을 모두 수용하지만, Non-null 타입은 null 값은 허용하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 Nullable 타입이 상위 타입이고, Non-nullable타입은 하위타입이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 타입 관계 더 간단하게 표현하자면, 얼마나 더 확장하는지 또는 멤버가 더 많은지 비교하는 것이라 할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 언어는&amp;nbsp;&lt;span style=&quot;background-color: #e6f4fa;&quot;&gt;&lt;a style=&quot;color: #0070d1; text-align: left; background-color: #e6f4fa;&quot; href=&quot;https://en.wikipedia.org/wiki/Comparison_of_programming_languages_by_type_system&quot;&gt;고유한 타입 시스템&lt;/a&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;을 갖고 있어, 실제 관계를 평가하는 방식은 이론적으로 다를 수 있지만,&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;이런 정의들은 모든 언어에 공통적으로 적용할 수 있는 개념이라 생각한다.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;span style=&quot;text-align: right;&quot;&gt;하위타입 평가에 대해&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt;더 궁금하다면&lt;/span&gt;&lt;span style=&quot;text-align: right;&quot;&gt;&amp;nbsp;Nominal과 Structural Typing에 대해 알아보자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;변성(Variance)&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;변성은 성질의 변화를 의미하는데, 프로그래밍에서는 변성 개념이 앞서 알아본 타입 관계에 적용될 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이전에 하위타입 개념은 아주 중요하다고 언급하였다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;타입 간의 관계가 변할 수 있는데, &lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;타입 시스템에서 &lt;b&gt;하위 타입 간의 관계가 &lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;&lt;b&gt;어떻게 변하는지&lt;/b&gt;를 나타내는 개념이 변성이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;변성은 타입 시스템에서 아주 중요한 개념 중 하나로, 잘 이해할 필요가 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;변성의 대표적인 세 가지 유형에서 어떻게 하위타입 관계가 형성되는지 알아보겠다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: GungSeo, serif;&quot;&gt;공변성&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WDTug/btsDVpmU6so/kDElW2OaqP3SEPpfs22ma0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WDTug/btsDVpmU6so/kDElW2OaqP3SEPpfs22ma0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WDTug/btsDVpmU6so/kDElW2OaqP3SEPpfs22ma0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWDTug%2FbtsDVpmU6so%2FkDElW2OaqP3SEPpfs22ma0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;162&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;일반적인 하위타입 관계가 동일하게 유지된다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;B가 A의 하위타입이다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: GungSeo, serif;&quot;&gt;반공변성&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8VGbA/btsDQ8UcEWd/1RiEPWXu9dO70yNxTXmh3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8VGbA/btsDQ8UcEWd/1RiEPWXu9dO70yNxTXmh3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8VGbA/btsDQ8UcEWd/1RiEPWXu9dO70yNxTXmh3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8VGbA%2FbtsDQ8UcEWd%2F1RiEPWXu9dO70yNxTXmh3k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;162&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;공변성의 반대되는 개념으로, 일반적인 하위 타입 관계가 역전된다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;B가 A의 하위타입일 때, A가 B의 하위타입이 된다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: GungSeo, serif;&quot;&gt;무공변성&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;556&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6lUww/btsDRopd0UR/QKiHzj6BJFW3a7OxP7Za4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6lUww/btsDRopd0UR/QKiHzj6BJFW3a7OxP7Za4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6lUww/btsDRopd0UR/QKiHzj6BJFW3a7OxP7Za4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6lUww%2FbtsDRopd0UR%2FQKiHzj6BJFW3a7OxP7Za4K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;150&quot; data-origin-width=&quot;556&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;무공변성에서는 하위타입 관계가 성립되지 않는다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;A와 B는 아무 관계가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴파일러는 값이 할당될 때 항상 하위 타입 관계가 성립되는지 체크한다고 말하였다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;변성은 하위 타입 관계의 변화에 대한 규칙으로, 컴파일러는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;변성이 적용된 타입의 사용위치를 제한&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #e6f4fa;&quot;&gt;&lt;a style=&quot;background-color: #e6f4fa;&quot; href=&quot;https://ko.wikipedia.org/wiki/리스코프_치환_원칙#원칙&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;리스코프 치환 원칙&lt;/a&gt;&lt;/span&gt;에서는 시그니처에 변성을 적용하여 강제하는 요구사항이 있는데 간단히 정리하자면 다음과 같다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 54px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 16.666667%; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.666667%; height: 18px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;공변성&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.333333%; height: 18px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;반공변성&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.333333%; height: 18px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;무공변성&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 16.666667%;&quot;&gt;관계&lt;/td&gt;
&lt;td style=&quot;width: 16.666667%; height: 18px;&quot;&gt;하위 타입 관계 유지&lt;/td&gt;
&lt;td style=&quot;width: 33.333333%; height: 18px;&quot;&gt;하위 타입 관계 역전&lt;/td&gt;
&lt;td style=&quot;width: 33.333333%; height: 18px;&quot;&gt;하위타입 관계 X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 16.666667%;&quot;&gt;제한&lt;/td&gt;
&lt;td style=&quot;width: 16.666667%; height: 18px;&quot;&gt;반환 위치에만 사용 가능&lt;/td&gt;
&lt;td style=&quot;width: 33.333333%; height: 18px;&quot;&gt;함수/메서드 파라미터에만 사용 가능&lt;/td&gt;
&lt;td style=&quot;width: 33.333333%; height: 18px;&quot;&gt;제한 X&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #9d9d9d;&quot;&gt;이런 제한사항은 타입 안정성을 위한 것이며, 사실 조금만 생각해 보면 아주 당연한 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;제네릭 클래스의 변성&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입의 변성은 제네릭 클래스에 적용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제네릭 클래스의 변성은 &lt;b&gt;Base타입은 같지만,&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt; 다른 타입 인자를 갖는 제네릭 타입 간의 상하위 관계를 결정&lt;/b&gt;하는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: GungSeo, serif;&quot;&gt;공변성&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;554&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4KxLL/btsDXEcvmJB/6llasMJNSykhR5np1L0t51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4KxLL/btsDXEcvmJB/6llasMJNSykhR5np1L0t51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4KxLL/btsDXEcvmJB/6llasMJNSykhR5np1L0t51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4KxLL%2FbtsDXEcvmJB%2F6llasMJNSykhR5np1L0t51%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;151&quot; data-origin-width=&quot;554&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B가 A의 하위 타입일 때, Producer&amp;lt;B&amp;gt;가 Producer&amp;lt;A&amp;gt;의 하위 타입이면 Producer는 공변적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 하위 타입 관계가 유지된다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코틀린의 List는 대표적인 공변 인터페이스이다.&lt;/p&gt;
&lt;pre id=&quot;code_1706099690704&quot; class=&quot;angelscript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;kotlin&quot;&gt;&lt;code&gt;var numbers: List&amp;lt;Number&amp;gt;
numbers = listOf&amp;lt;Int&amp;gt;(1,2,3,4,5)
numbers = listOf&amp;lt;Long&amp;gt;(1L, 2L, 3L, 4L, 5L)
numbers = listOf&amp;lt;Double&amp;gt;(1.0, 2.0, 3.0, 4.0, 5.0)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Int, Long, Double은 Number의 하위 타입이기 때문에, 공변적인 List&amp;lt;T&amp;gt;의 하위타입 관계가 유지된다.&lt;/p&gt;
&lt;pre id=&quot;code_1706100271146&quot; class=&quot;kotlin&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface List&amp;lt;out E&amp;gt; : Collection&amp;lt;E&amp;gt; {
	/* ... */
    public operator fun get(index: Int): E
    public fun subList(fromIndex: Int, toIndex: Int): List&amp;lt;E&amp;gt;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;공변적인 타입 파라미터는 오직&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;반환 타입&lt;/b&gt;에만 사용할 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;코틀린에서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;out 키워드&lt;/b&gt;를 사용하여 타입 파라미터에 대해 공변적임을 표시하며, 타입 파라미터의 사용을 &lt;b&gt;반환 타입으로 제한&lt;/b&gt;한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;반환 = out, 아주 명시적이지 않은가?&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입 파라미터가 반환 타입에만 사용되는 경우,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공변적으로 선언해도 안전하며 제네릭 타입 간 하위타입 관계를 유지함으로써 더 유연하게 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: GungSeo, serif;&quot;&gt;반공변성&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;554&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnExnR/btsDXBUqaND/BOfTr4IzkYZN5tK8HhgWs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnExnR/btsDXBUqaND/BOfTr4IzkYZN5tK8HhgWs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnExnR/btsDXBUqaND/BOfTr4IzkYZN5tK8HhgWs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnExnR%2FbtsDXBUqaND%2FBOfTr4IzkYZN5tK8HhgWs0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;151&quot; data-origin-width=&quot;554&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B가 A의 하위 타입일 때, Consumer&amp;lt;A&amp;gt;가 Consumer&amp;lt;B&amp;gt;의 하위 타입이면 Consumer은 반공변적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 하위 타입 관계가 역전된다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Comparator은 대표적인 반공변 클래스이다.&lt;/p&gt;
&lt;pre id=&quot;code_1706101743847&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface Comparator&amp;lt;in T&amp;gt; {
    fun compare(el: T, e2: T): Int { /* ... */ }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;반공변적인 타입 파라미터는 오직&lt;b&gt;&lt;span&gt; 함수/메서드의 파라미터 타입&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;에만 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Comparator 클래스는 파라미터 타입 T를 반공변적으로 선언하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;코틀린에서는&lt;b&gt;&lt;span&gt; in&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&amp;nbsp;키워드&lt;/b&gt;를 사용하여 타입 파라미터에 대해 반공변적임을 표시하며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입 파라미터의 사용을 &lt;b&gt;함수/메서드의 파라미터 타입&lt;/b&gt;으로 제한한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;함수 내부 = in, 아주 인상적이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1706104587492&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val anyComparator = Comparator&amp;lt;Any&amp;gt; {
    o1, o2 -&amp;gt; o1.hashCode() - o2.hashCode()
}

val strings: List&amp;lt;String&amp;gt; = listOf(&quot;A&quot;, &quot;B&quot;, &quot;C&quot;)
strings.sortedWith(anyComparator)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;strings의 sortedWith() 함수는 Comparator&amp;lt;in String&amp;gt;의 구현체를 받아 정렬하는 함수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Comparator가 타입 파라미터 String에 대해 반공변적이기 때문에, 역전된 하위 타입 관계가 성립된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 Comparator&amp;lt;Any&amp;gt;는 Comparator&amp;lt;String&amp;gt;의 반공변적 하위타입이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 말은 sortedWith() 함수에 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Comparator&amp;lt;Any&amp;gt; 타입을 인자로 넘겨도 안전하다는 의미이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입 파라미터가 함수 매개변수에만 사용되는 경우 반공변적으로 선언할 수 있으며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 타입 관계가 역전된(&lt;b&gt;일반화된&lt;/b&gt;) 타입만 허용한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: GungSeo, serif;&quot;&gt;무공변성&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;570&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbQyQv/btsDUhbN0bX/1ERVsBQeF8ZjBgYZCC9uN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbQyQv/btsDUhbN0bX/1ERVsBQeF8ZjBgYZCC9uN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbQyQv/btsDUhbN0bX/1ERVsBQeF8ZjBgYZCC9uN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbQyQv%2FbtsDUhbN0bX%2F1ERVsBQeF8ZjBgYZCC9uN0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;146&quot; data-origin-width=&quot;570&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;B가 A의 하위 타입이어도, 아무런 하위 타입 관계가 형성되지 않는다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;MutableList는 대표적인 무공변 클래스이다.&lt;/p&gt;
&lt;pre id=&quot;code_1706099877732&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var numbers: MutableList&amp;lt;Number&amp;gt;
numbers = mutableListOf&amp;lt;Number&amp;gt;(1,2,3,4,5)

//numbers = mutableListOf&amp;lt;Int&amp;gt;(1,2,3,4,5)
//Type mismatch: inferred type is MutableList&amp;lt;Int&amp;gt; but MutableList&amp;lt;Number&amp;gt; was expected

//numbers = mutableListOf&amp;lt;Double&amp;gt;(1.0, 2.0, 3.0, 4.0, 5.0)
//Type mismatch: inferred type is MutableList&amp;lt;Double&amp;gt; but MutableList&amp;lt;Number&amp;gt; was expected&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Int, Long, Double은 Number의 하위 타입이지만, MutableList&amp;lt;T&amp;gt;에는 아무런 하위 타입 관계가 형성되지 않는다.&lt;/p&gt;
&lt;pre id=&quot;code_1706100055169&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface MutableList&amp;lt;E&amp;gt; : List&amp;lt;E&amp;gt;, MutableCollection&amp;lt;E&amp;gt; {
	/* ... */
    override fun add(element: E): Boolean
    public operator fun get(index: Int): E
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MutableList의 타입파라미터에는 변성에 대한 표시가 없다. 그렇기 때문에 무공변적이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무공변적인 타입 파라미터는 파라미터 타입(in)과 반환 타입(out)에 모두 사용될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입 파라미터를 함수/메서드 파라미터로 받고, 반환 타입으로도 사용한다면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무공변적으로 선언하여 타입 안전성을 제공해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 54px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;클래스&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;공변성&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;반공변성&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;무공변성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;선언&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;Producer&amp;lt;out T&amp;gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;Consumer&amp;lt;in T&amp;gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;MutableList&amp;lt;T&amp;gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;관계&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;타입 인자의 하위 타입 관계가 유지&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;타입 인자의 하위타입 관계가 역전&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;하위타입 관계 X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;제한&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;T를 아웃 위치(반환 타입)에서만 사용 가능&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;T를 인 위치(매개변수)에서만 사용 가능&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;T를 아무 위치에서 사용 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변성 규칙의 핵심은 클래스 외부의 사용자가 클래스를 잘못 사용하는 일을 방지하기 위함이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;함수/메서드 변성&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수는 일급 객체이다. 이 말은 함수를 변수, 매개변수, 반환타입으로 전달할 수 있다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 말은 함수 또한 함수 자료형이 존재하다는 의미이기도 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 자료형에 대한 포스팅은 추후에 추가하도록 하겠다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1706155058655&quot; class=&quot;angelscript&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;kotlin&quot;&gt;&lt;code&gt;class String { /* ... */ }
interface List&amp;lt;out T&amp;gt; { /* ... */ }

val str: String
val numbers: List&amp;lt;Int&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스와 인터페이스의 자료형은 위처럼 표현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1706155058656&quot; class=&quot;kotlin&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;kotlin&quot;&gt;&lt;code&gt; fun multiply(x: Int, y: Int): Int {
     return x * y
 }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 함수는 어떻게 표현할 수 있을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수/메서드에는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://developer.mozilla.org/ko/docs/Glossary/Signature/Function&quot;&gt;시그니처&lt;/a&gt;라는 개념이 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS</category>
      <category>generic</category>
      <category>Kotlin</category>
      <category>typescript</category>
      <category>반공변성</category>
      <category>변성</category>
      <category>일반화</category>
      <category>제네릭</category>
      <category>제네릭스</category>
      <category>함수형</category>
      <author>Darren Gwon</author>
      <guid isPermaLink="true">https://darrenlog.tistory.com/47</guid>
      <comments>https://darrenlog.tistory.com/47#entry47comment</comments>
      <pubDate>Thu, 25 Jan 2024 12:59:52 +0900</pubDate>
    </item>
    <item>
      <title>[리눅스] 시스템 타임존(TimeZone) 변경하기</title>
      <link>https://darrenlog.tistory.com/46</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;timedatectl 명령어를 통해서 리눅스 시스템 타임존을 변경할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 설정된 타임존 확인&lt;/p&gt;
&lt;pre id=&quot;code_1702537823269&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ timedatectl&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1702537972282&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Local time: Thu 2023-12-14 04:56:14 UTC
Universal time: Thu 2023-12-14 04:56:14 UTC
RTC time: Thu 2023-12-14 04:56:14
Time zone: n/a (UTC, +0000)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UTC로 설정되어있으니, 변경하려는 시간대를 먼저 찾아야한다.&lt;/p&gt;
&lt;pre id=&quot;code_1702538132207&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ timedatectl list-timezones&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1702538140175&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Africa/Abidjan
Africa/Accra
Africa/Addis_Ababa
Africa/Algiers
...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 명령어를 통해 수정해주면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1702538179049&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ timedatectl set-timezone Asia/Jakarta&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정상적으로 바뀌었는지 확인&lt;/p&gt;
&lt;pre id=&quot;code_1702538295275&quot; class=&quot;elixir&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;$ timedatectl&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1702538327397&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Local time: Thu 2023-12-14 14:18:24 WIB
Universal time: Thu 2023-12-14 07:18:24 UTC
RTC time: Thu 2023-12-14 07:18:23
Time zone: Asia/Jakarta (WIB, +0700)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Linux</category>
      <category>linux</category>
      <category>TimeZone</category>
      <category>UTC</category>
      <category>리눅스</category>
      <category>리눅스타임존</category>
      <category>시간변경</category>
      <author>Darren Gwon</author>
      <guid isPermaLink="true">https://darrenlog.tistory.com/46</guid>
      <comments>https://darrenlog.tistory.com/46#entry46comment</comments>
      <pubDate>Thu, 14 Dec 2023 16:19:05 +0900</pubDate>
    </item>
    <item>
      <title>[스프링배치] 스프링배치 소개</title>
      <link>https://darrenlog.tistory.com/45</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;오늘은&amp;nbsp;&lt;b&gt;스프링배치에 대한 소개&lt;/b&gt;라는 주제로 포스팅해 보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;최근에 저는 실무에서 스프링배치 관련&amp;nbsp;&lt;span style=&quot;text-align: start;&quot;&gt;유지보수&amp;nbsp;&lt;/span&gt;업무를 맡게 되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;업무하다보니 단순한 유지보수 작업을 넘어, 프레임워크에 대한 이해와 성장에 대한 도전의식이 생기게 되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;text-align: start; color: #000000;&quot;&gt;실제 업무를 통해 스프링 배치에 대한 지식과 경험을 쌓으며, 단순히 코드를 고치는 것 이상의 가치를 찾고 싶었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;뿐만 아니라, 직접 배치 프로그램을 설계하고 구현하는 것을 목표로 스프링배치를 주제로 스터디를 진행하게 되었습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이번 스터디를 통해 실무에서의 역량을 더욱 향상시키며, 더 나은 개발자로 성장하고자 하는 목표를 가지고 시리즈로 이어나갈 계획입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;스프링배치의 등장 배경&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 배치는 Java 진영에서&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;대용량의 데이터를 일괄 처리&lt;/b&gt;를 목적으로 사용되는 오픈 소스 프레임워크입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링배치가 등장하기 전까지는 Java 진영의 배치 아키텍처 프레임워크가 관심과 결과물이 부족한 상황이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 자연스럽게 &lt;b&gt;자신들만의 배치 솔루션을 개발&lt;/b&gt;해 사용하는 추세가 형성되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-19 오후 9.47.38.png&quot; data-origin-width=&quot;1844&quot; data-origin-height=&quot;192&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bn12ze/btsgB2P6WM0/pkXqDFCEKM4dWPq9TMVfu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bn12ze/btsgB2P6WM0/pkXqDFCEKM4dWPq9TMVfu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bn12ze/btsgB2P6WM0/pkXqDFCEKM4dWPq9TMVfu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbn12ze%2FbtsgB2P6WM0%2FpkXqDFCEKM4dWPq9TMVfu1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;554&quot; height=&quot;192&quot; data-filename=&quot;스크린샷 2023-05-19 오후 9.47.38.png&quot; data-origin-width=&quot;1844&quot; data-origin-height=&quot;192&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;position: absolute;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 문제를 해결하기 위해 Accenture와 SpringSource가 협력하여 지금의 스프링배치가 탄생하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Accenture는 자사가 보유한 배치 아키텍처 구축에 대한 경험과 기술 기반의 배치 아키텍처를 기증하였고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SpringSource와 협력하여 현재의 enterprise-level의 배치 프레임워크가 탄생할 수 있도록 기여하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;Spring Batch is not a scheduling framework.&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식문서에 &quot;스프링 배치는 스케쥴링 프레임워크가 아니다&quot;라고 언급하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;대용량 데이터 처리에 특화된&lt;/b&gt; 프레임워크라는 것을 강조하는 것으로 다음과 같은 특징을 가지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;확장성:&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;u&gt;분산 환경에서 작업을 병렬로 실행&lt;/u&gt;하거나 여러 서버에 배포하여 &lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;대용량 데이터의&amp;nbsp;&lt;/span&gt;처리 성능을 향상&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모니터링의 용이성&lt;/b&gt;:&lt;br /&gt;작업의 진행 상황을 &lt;u&gt;모니터링&lt;/u&gt;하고, 실패한 작업을 &lt;u&gt;재시작&lt;/u&gt;하거나 &lt;u&gt;건너뛸 수 있는 기능&lt;/u&gt;을 제공&lt;/li&gt;
&lt;li&gt;&lt;b&gt;트랜잭션 관리&lt;/b&gt;:&lt;br /&gt;데이터 처리 중 예외가 발생하면 &lt;u&gt;롤백&lt;/u&gt;하고, 작업 단위 내에서 &lt;u&gt;데이터 일관성을 유지&lt;/u&gt;하여 안정적인 데이터 처리를 보장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;재시작 및 건너뛰기&lt;/b&gt;:&lt;br /&gt;작업을 중지한 후에도 &lt;u&gt;작업을 재개&lt;/u&gt;하거나 이전 작업을 &lt;u&gt;건너뛸 수 있는 기능&lt;/u&gt; 제공하여&amp;nbsp;작업의 &lt;u&gt;유연성과 오류 처리를 개선&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장애 복구와 관리&lt;/b&gt;:&lt;br /&gt;모든 작업에 대한 &lt;u&gt;로그를 기록&lt;/u&gt;하므로 작업이 실패한 경우에도 적절한 조치를 취하고,&lt;br /&gt;예기치 않은 상황에서의 대응력을 향상&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;메타데이터 스키마 제공&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L6CBU/btsgFeHNBva/seQug3FxndmY6rZZvk6k21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L6CBU/btsgFeHNBva/seQug3FxndmY6rZZvk6k21/img.png&quot; data-origin-width=&quot;832&quot; data-origin-height=&quot;678&quot; data-is-animation=&quot;false&quot; width=&quot;460&quot; height=&quot;375&quot; style=&quot;width: 61.4147%; margin-right: 10px;&quot; data-widthpercent=&quot;62.14&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L6CBU/btsgFeHNBva/seQug3FxndmY6rZZvk6k21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL6CBU%2FbtsgFeHNBva%2FseQug3FxndmY6rZZvk6k21%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;832&quot; height=&quot;678&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVB5bX/btsgCkCMQWG/8ThyzPDdJbJP7ZJgK9o5V0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVB5bX/btsgCkCMQWG/8ThyzPDdJbJP7ZJgK9o5V0/img.png&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;666&quot; data-is-animation=&quot;false&quot; style=&quot;width: 37.4226%;&quot; data-widthpercent=&quot;37.86&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVB5bX/btsgCkCMQWG/8ThyzPDdJbJP7ZJgK9o5V0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVB5bX%2FbtsgCkCMQWG%2F8ThyzPDdJbJP7ZJgK9o5V0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;498&quot; height=&quot;666&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;스프링배치에서 처리한 모든 프로세스의 메타데이터를 저장하는 스키마를 미리 제공합니다&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;덕분에 앞서 언급한 것처럼 &lt;span style=&quot;color: #000000; text-align: left;&quot;&gt;메타데이터를 기반으로&lt;/span&gt; 모니터링 능력이 향상되고 자연스럽게 에러에 대한 대응력도 향상되게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;나아가, 실패한 작업에 대해 효율적인 repeat, retry, skip 처리가 가능해집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;메타데이터 스키마는 다음에 더 자세히 살펴볼 예정입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;스프링배치의 구성&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;626&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JBZgt/btsgDPhSZKR/wajoMp5KJtUkZmLHQ7pxIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JBZgt/btsgDPhSZKR/wajoMp5KJtUkZmLHQ7pxIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JBZgt/btsgDPhSZKR/wajoMp5KJtUkZmLHQ7pxIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJBZgt%2FbtsgDPhSZKR%2FwajoMp5KJtUkZmLHQ7pxIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;624&quot; height=&quot;310&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;626&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링배치를 구성하는 각 Job, Step, Tasklet 도메인에 대한 이해가 중요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Job:&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배치 프로그램의 &lt;b&gt;업무 목적 &lt;/b&gt;자체를 의미하는 도메인입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'매출 통계', '데이터 이관', '다량 이메일 일괄 전송'등의 예시가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Step:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배치작업(Job)을 &lt;b&gt;작은 단계로 분리&lt;/b&gt;하여 정의하고 실행을 관리하는 도메인입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;배치 처리의 &lt;b&gt;실행 흐름을 관리&lt;/b&gt;하고, 각 단계의 성공 여부에 따라 &lt;b&gt;다음 단계를 결정&lt;/b&gt;합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Taskle&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;t:&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;Step의 실행 단위로서, Step에서 수행되는 &lt;b&gt;실제 작업을 정의하는 도메인&lt;/b&gt;입니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;개발자가 작성한 일련의 &lt;b&gt;로직을 포함&lt;/b&gt;하고 있으며 T&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;asklet방식과 Chunk방식이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 도메인에 대한 자세한 내용도 별도로 다루도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;요약&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Java 진영의 대용량 데이터 일괄처리 목적의 프레임워크&lt;/li&gt;
&lt;li&gt;Accenture와 SpringSource의 기여로 탄생&lt;/li&gt;
&lt;li&gt;대용량 데이터 처리를 위한 강력한 배치 아키텍처&lt;/li&gt;
&lt;li&gt;병렬처리, 트랜잭션 관리, 효율적인 재시작 및 스킵 기능으로 배치 처리의 신뢰성 제공, 장애대응&lt;/li&gt;
&lt;li&gt;메타데이터 스키마 제공&lt;/li&gt;
&lt;li&gt;Job, Step, Tasklet으로 구성&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링배치는&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp;&lt;/span&gt;개발자가 오직 &lt;b&gt;비즈니스 로직에만 집중&lt;/b&gt;할 수 있도록 도와주는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대용량 데이터 처리에 특화된 프레임워크라고 결론 지을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음에는 각 도메인에 대한 자세한 설명과 실행 흐름에 대해 살펴보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;본 게시글은 정수원님의 스프링 배치 - Spring Boot 기반으로 개발하는 Spring Batch 강의를 참고하여 정리하였습니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Spring Boot</category>
      <category>BATCH</category>
      <category>batchprogram</category>
      <category>jobsteptasklet</category>
      <category>SpringBatch</category>
      <category>스케쥴러</category>
      <category>스프링</category>
      <category>스프링배치</category>
      <category>스프링스케쥴러</category>
      <author>Darren Gwon</author>
      <guid isPermaLink="true">https://darrenlog.tistory.com/45</guid>
      <comments>https://darrenlog.tistory.com/45#entry45comment</comments>
      <pubDate>Sat, 20 May 2023 00:12:50 +0900</pubDate>
    </item>
    <item>
      <title>[PostMan] API시뮬레이터 - Mock Server 만들기</title>
      <link>https://darrenlog.tistory.com/44</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 초기 개발 단계에 아주 유용한 PostMan의 Mock Server를 소개하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Mock Server는 &lt;u&gt;&lt;b&gt;가상 API서버&lt;/b&gt;&lt;/u&gt;를 제공해 주어 요청과 응답이 실제 처리되는 것처럼 &lt;b&gt;시뮬레이션&lt;/b&gt;해 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;백엔드 환경이 완전히 구축되지 않았어도&lt;/b&gt; 사전에 합의된 API를 제공해 주어 &lt;b&gt;지체 없이 바로 개발을 시작할 수 있게 도와줍니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IMCwG/btsf2l22d6e/BPqdLokUZs5OSKWcpVpbY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IMCwG/btsf2l22d6e/BPqdLokUZs5OSKWcpVpbY1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2784&quot; data-origin-height=&quot;1824&quot; data-filename=&quot;1.png&quot; style=&quot;width: 49.418605%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IMCwG/btsf2l22d6e/BPqdLokUZs5OSKWcpVpbY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIMCwG%2Fbtsf2l22d6e%2FBPqdLokUZs5OSKWcpVpbY1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2784&quot; height=&quot;1824&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXhygp/btsf3qCwt0D/V8OiZzll5GJw57obgBP2HK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXhygp/btsf3qCwt0D/V8OiZzll5GJw57obgBP2HK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2784&quot; data-origin-height=&quot;1824&quot; data-filename=&quot;2.png&quot; style=&quot;width: 49.418605%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXhygp/btsf3qCwt0D/V8OiZzll5GJw57obgBP2HK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXhygp%2Fbtsf3qCwt0D%2FV8OiZzll5GJw57obgBP2HK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2784&quot; height=&quot;1824&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 먼저 포스트맨을 실행시켜 주신 후 새로운 Collection을 생성해 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;2784&quot; data-origin-height=&quot;1824&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1J8wa/btsf2kC4uWw/CmleZa4SdRkMLVweohREZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1J8wa/btsf2kC4uWw/CmleZa4SdRkMLVweohREZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1J8wa/btsf2kC4uWw/CmleZa4SdRkMLVweohREZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1J8wa%2Fbtsf2kC4uWw%2FCmleZa4SdRkMLVweohREZ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2784&quot; height=&quot;1824&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;2784&quot; data-origin-height=&quot;1824&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 좌측에 Mock Servers 탭 선택 후 Create Mock Server 버튼 또는 + 버튼을 눌러줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;2784&quot; data-origin-height=&quot;1824&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bASDjP/btsf2oL6JtJ/dfmSgKUmxaH0TwrzhXjua0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bASDjP/btsf2oL6JtJ/dfmSgKUmxaH0TwrzhXjua0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bASDjP/btsf2oL6JtJ/dfmSgKUmxaH0TwrzhXjua0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbASDjP%2Fbtsf2oL6JtJ%2FdfmSgKUmxaH0TwrzhXjua0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2784&quot; height=&quot;1824&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;2784&quot; data-origin-height=&quot;1824&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Select An existing collection 탭을 눌러 아까 생성하신 Collection을 선택 후 Next를 눌러주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;2784&quot; data-origin-height=&quot;1824&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/maY6B/btsf3hezsOH/2jviGs8sYNp4RcDvOijL10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/maY6B/btsf3hezsOH/2jviGs8sYNp4RcDvOijL10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/maY6B/btsf3hezsOH/2jviGs8sYNp4RcDvOijL10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmaY6B%2Fbtsf3hezsOH%2F2jviGs8sYNp4RcDvOijL10%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2784&quot; height=&quot;1824&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;2784&quot; data-origin-height=&quot;1824&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. Mock Server Name을 지정해 주시고, Save the mock server URL as an new environment variables 체크 후&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Create Mock Server 버튼을 눌러 생성해 주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;2784&quot; data-origin-height=&quot;1824&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bR3sfs/btsf3qvLGAS/xKFOYSyWjY65o5wB8fh9kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bR3sfs/btsf3qvLGAS/xKFOYSyWjY65o5wB8fh9kk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bR3sfs/btsf3qvLGAS/xKFOYSyWjY65o5wB8fh9kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbR3sfs%2Fbtsf3qvLGAS%2FxKFOYSyWjY65o5wB8fh9kk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2784&quot; height=&quot;1824&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;2784&quot; data-origin-height=&quot;1824&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. Mock Server가 생성되었으면 &lt;a href=&quot;https://~~~.mock.pstmn.io&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://~~~.mock.pstmn.io&lt;/a&gt;로 끝나는 URL주소를 복사해 주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;2784&quot; data-origin-height=&quot;1824&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dXlbXY/btsf3sf0JJ2/PSU4YugwkLG7rSLyh9qu60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dXlbXY/btsf3sf0JJ2/PSU4YugwkLG7rSLyh9qu60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dXlbXY/btsf3sf0JJ2/PSU4YugwkLG7rSLyh9qu60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdXlbXY%2Fbtsf3sf0JJ2%2FPSU4YugwkLG7rSLyh9qu60%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2784&quot; height=&quot;1824&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;2784&quot; data-origin-height=&quot;1824&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 다시 Collections 탭으로 돌아가 Add request로 새로운 요청을 하나 생성해 주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;8.png&quot; data-origin-width=&quot;2784&quot; data-origin-height=&quot;1824&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b81gzp/btsf2pEdsgX/sQveLh6k2pkvO8DWOdKuhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b81gzp/btsf2pEdsgX/sQveLh6k2pkvO8DWOdKuhK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b81gzp/btsf2pEdsgX/sQveLh6k2pkvO8DWOdKuhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb81gzp%2Fbtsf2pEdsgX%2FsQveLh6k2pkvO8DWOdKuhK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2784&quot; height=&quot;1824&quot; data-filename=&quot;8.png&quot; data-origin-width=&quot;2784&quot; data-origin-height=&quot;1824&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. 저는 user를 조회하는 mock API를 만든다고 가정하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성하신 request -&amp;gt; 우측 마우스 -&amp;gt; Add example을 눌러주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 아래 API명세서를 기준으로 mock API 하나를 만들어보겠습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 123px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;background-color: #9b9b9b; color: #ffffff; text-align: center; height: 19px;&quot; colspan=&quot;2&quot;&gt;user 조회 API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;background-color: #efefef; height: 17px;&quot;&gt;Request Path(URL)&lt;/td&gt;
&lt;td style=&quot;background-color: #f9f9f9; height: 17px;&quot;&gt;/api/user/{userId}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;background-color: #efefef; height: 17px;&quot;&gt;&lt;span style=&quot;background-color: #efefef; color: #333333; text-align: start;&quot;&gt;HttpMethod&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;background-color: #f9f9f9; height: 17px;&quot;&gt;GET&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;background-color: #efefef; height: 17px;&quot;&gt;Request Parameter&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;none&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;background-color: #efefef; height: 17px;&quot;&gt;Headers&lt;/td&gt;
&lt;td style=&quot;background-color: #f9f9f9; height: 17px;&quot;&gt;none&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;background-color: #efefef; height: 19px;&quot;&gt;Response Body&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;{&lt;br /&gt;&amp;nbsp; &quot;userId&quot;:&quot;아이디&quot;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;&quot;name&quot;:&quot;이름&quot;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;&quot;address&quot;:&quot;주소&quot;&lt;br /&gt;}&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-15 오후 9.59.56.png&quot; data-origin-width=&quot;2784&quot; data-origin-height=&quot;1824&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cn86gS/btsf4cxgczW/wmVnFc7dNHorz2MsolYI6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cn86gS/btsf4cxgczW/wmVnFc7dNHorz2MsolYI6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cn86gS/btsf4cxgczW/wmVnFc7dNHorz2MsolYI6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcn86gS%2Fbtsf4cxgczW%2FwmVnFc7dNHorz2MsolYI6K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2784&quot; height=&quot;1824&quot; data-filename=&quot;스크린샷 2023-05-15 오후 9.59.56.png&quot; data-origin-width=&quot;2784&quot; data-origin-height=&quot;1824&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8. 여기서부터 mock API를 설정하는 단계입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HttpMethod, URL, 요청 Parameter, Headers, 요청 Body, 응답 Body 등 상세한 설정을 하실 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Base URL에 해당하는 {{url}}은 4번에서 Mock Server를 생성하면서 만들어진 URL이&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자동으로 Environment에 추가되어 바로 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;test01 유저를 조회하면 상세정보인 이름(darren)과 주소(서울특별시)를 반환하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저장 후 우측에 Try 버튼을 눌러주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3Ivug/btsf0ROImco/drsxRLGW1QlM6UZ60KL2kK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3Ivug/btsf0ROImco/drsxRLGW1QlM6UZ60KL2kK/img.png&quot; data-origin-width=&quot;2784&quot; data-origin-height=&quot;1824&quot; data-filename=&quot;스크린샷 2023-05-15 오후 10.12.55.png&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;51.01&quot; style=&quot;width: 50.417898%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3Ivug/btsf0ROImco/drsxRLGW1QlM6UZ60KL2kK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3Ivug%2Fbtsf0ROImco%2FdrsxRLGW1QlM6UZ60KL2kK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2784&quot; height=&quot;1824&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baazNe/btsfWUrqXFm/aMHvyUp52Naxrjyp8niHwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baazNe/btsfWUrqXFm/aMHvyUp52Naxrjyp8niHwk/img.png&quot; data-origin-width=&quot;1372&quot; data-origin-height=&quot;936&quot; data-filename=&quot;스크린샷 2023-05-15 오후 10.16.47.png&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;48.99&quot; style=&quot;width: 48.419311%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baazNe/btsfWUrqXFm/aMHvyUp52Naxrjyp8niHwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaazNe%2FbtsfWUrqXFm%2FaMHvyUp52Naxrjyp8niHwk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1372&quot; height=&quot;936&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;9. 아까 복사한 Base URL과 Path로 요청을 보내게 되면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 사진처럼 Mock Server에서 요청을 처리하여 응답 값이 오는 것을 확인하실 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;또한 일반 브라우저에서도 Mock API가 동작하는 것을 볼 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 개발 초기에 미리 설계된 API명세서를 기반으로 Mock Server를 설정해 놓게 되면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;API&lt;/span&gt;서버에서 요청과 응답을 처리하는 것처럼 시물레이션 하여&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프론트엔드와 백엔드 양 쪽 모두 지체 없이 바로 개발을 시작할 수 있다는 큰 장점이 있습니다.&lt;/p&gt;</description>
      <category>Tools</category>
      <category>API</category>
      <category>apiserver</category>
      <category>API서버</category>
      <category>API테스트</category>
      <category>mockserver</category>
      <category>Postman</category>
      <category>RestAPI</category>
      <category>개발도구</category>
      <category>포스트맨</category>
      <category>포스트맨mockserver</category>
      <author>Darren Gwon</author>
      <guid isPermaLink="true">https://darrenlog.tistory.com/44</guid>
      <comments>https://darrenlog.tistory.com/44#entry44comment</comments>
      <pubDate>Mon, 15 May 2023 22:23:54 +0900</pubDate>
    </item>
    <item>
      <title>스프링의 등장 배경과 스프링부트와의 차이는?</title>
      <link>https://darrenlog.tistory.com/43</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;/span&gt;자바를 공부를 하다 보면 자연스럽게 스프링에 관심을 가지게 되고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링을 공부를 하다 보면 한 번쯤은 다음과 같은 질문을 해보셨을 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&quot;스프링과 스프링부트는 무엇이 다르지?&quot;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저도 단순하게 스프링보다 설정이 간편하고 내장 톰켓을 지원한다 정도로만 넘겼었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에 개인적으로 공부를 하며 비슷하지만 서로 엄연히 다른 스프링과 스프링부트에 대해 알아보기로 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Java기반 웹 기술의 발전&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스프링!=스프링부트.png&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1QtpQ/btr0BXcpj5g/XA9Dh1dImv3NBP3xDg1KVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1QtpQ/btr0BXcpj5g/XA9Dh1dImv3NBP3xDg1KVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1QtpQ/btr0BXcpj5g/XA9Dh1dImv3NBP3xDg1KVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1QtpQ%2Fbtr0BXcpj5g%2FXA9Dh1dImv3NBP3xDg1KVK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;602&quot; height=&quot;339&quot; data-filename=&quot;스프링!=스프링부트.png&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;시작하기 앞서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;스프링의 등장 배경&lt;/b&gt;부터 스스로에게 질문해 보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;1989 - 1997&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터넷의 등장 이후, 1989년에 처음으로 Website가 등장하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹사이트의 첫 등장 이후 1997년에 100만 번째 도메인이 등록되고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터넷과 가정용 PC가 보급되면서 웹 사용자가 급격히 증가하게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;1997 - 2000&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;782&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Rb4MU/btr0DUT2a13/I8kIc0KuHTcAXagFF7INoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Rb4MU/btr0DUT2a13/I8kIc0KuHTcAXagFF7INoK/img.png&quot; data-alt=&quot;출처:&amp;amp;amp;nbsp;https://www.protechtraining.com/bookshelf/jboss_admin_tutorial/web_tier&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Rb4MU/btr0DUT2a13/I8kIc0KuHTcAXagFF7INoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRb4MU%2Fbtr0DUT2a13%2FI8kIc0KuHTcAXagFF7INoK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;572&quot; height=&quot;349&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;782&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처:&amp;amp;nbsp;https://www.protechtraining.com/bookshelf/jboss_admin_tutorial/web_tier&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;웹의 첫 등장부터 1990년도 중반까지 &lt;/span&gt;&lt;span&gt;CGI(Common Gateway Interface)라는&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;웹 서버&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;기술이 활발하게 사용되고 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 CGI는 멀티스레드를 지원하지 않고 각 요청별로 하나의 프로세서가 담당하다 보니&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부화가 많이 걸리는 비효율적인 동작 방식을 가지고 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1995년에 첫 출시된 Java는 멀티스레드를 지원하는 언어 중 하나였고, &lt;span&gt;덕분에 &lt;/span&gt;높은 트래픽을 감당이 가능하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발 및 유지보수가 편리했던 &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;Java의 Servlet 기술이 자연스럽게 CGI를 대체하게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;1999 - 2004&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상업용 웹 애플리케이션 개발을 돕기 위한 &lt;span&gt;EJB(Enterprise JavaBeans)라는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;하나의 스펙이 등장하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EJB를 통해 웹 애플리케이션 개발이 보다 편해졌지만, 아직도 무겁고 과하게 복잡하다는 평이 많았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;복잡하고 어려운 EJB의 대체안!&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;어려운 테스트 (&lt;span&gt;Using EJB makes applications harder to test&lt;/span&gt;)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span&gt;어려운 배포 (&lt;/span&gt;Using EJB makes applications harder to deploy)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span&gt;객체지향 디자인의 방해요소(&lt;/span&gt;Using EJB with remote interfaces may hamper practicing OO design)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span&gt;간단한 작업의 불필요한 난이도 상승 (&lt;/span&gt;Using EJB may make simple things hard)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span&gt;제한적 WAS 선택 (&lt;/span&gt;Reduced choice of application servers)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;위와 같은 EJB의 단점을 개선하여 나온 것이 바로 Spring Framework입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 프레임워크는 2004년에 첫 등장을 했고, 이로부터 10년 후 스프링부트가 첫 등장하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;스프링 프레임워크의 특징&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1024px-Spring_Framework_Logo_2018.svg.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;263&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1a47I/btr0DhPisaI/BjC45YHyWKCF79V6yo4eo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1a47I/btr0DhPisaI/BjC45YHyWKCF79V6yo4eo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1a47I/btr0DhPisaI/BjC45YHyWKCF79V6yo4eo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1a47I%2Fbtr0DhPisaI%2FBjC45YHyWKCF79V6yo4eo0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;432&quot; height=&quot;111&quot; data-filename=&quot;1024px-Spring_Framework_Logo_2018.svg.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;263&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링에서 주장하는 대표적인 강점으로는 POJO, AOP, IoC/DI 등이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 특징들이 조금 더 현실적으로 와닿으려면 스프링 1.0 첫 출시 당시의 EJB와 비교를 해보아야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;POJO (Plain Old Java Object)&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1123&quot; data-origin-height=&quot;655&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m7LkF/btr0Hu1CGqs/UX6ksmHoZbIs9kO96KobOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m7LkF/btr0Hu1CGqs/UX6ksmHoZbIs9kO96KobOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m7LkF/btr0Hu1CGqs/UX6ksmHoZbIs9kO96KobOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm7LkF%2Fbtr0Hu1CGqs%2FUX6ksmHoZbIs9kO96KobOk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1123&quot; height=&quot;655&quot; data-origin-width=&quot;1123&quot; data-origin-height=&quot;655&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링은 출시 당시부터 POJO 모델을 기반으로 채택하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;POJO는 이름 그대로의 순수 Java 객체로 &lt;span&gt;특정 프레임워크나 컨테이너에 대한 &lt;b&gt;종속성이 없다&lt;/b&gt;는 특징이 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;덕분에 스프링은 비교적&lt;span&gt; 입문하기 쉽고,&lt;/span&gt;&amp;nbsp;유연하고, 단위 테스트하기 편리한 코드를 작성하는데 유리하였습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;EJB는 상업용 애플리케이션을 위해 Java Beans 확장한 형태로서 POJO에 비해 &lt;b&gt;많은 규약&lt;/b&gt;들이 존재했습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EJB Container에서 관리가 가능하도록 규격 인터페이스를 구현하거나 별도 설정을 필요로 하는 등&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EJB의 환경과 스펙에 종속적으로 코드를 작성해야만 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;EJB 3.0부터 POJO를 지원한다고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;AOP (Aspect Oriented&amp;nbsp; Programming)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링은 AOP(관점 지향 프로그래밍)를 통해 개발자가 &lt;b&gt;비즈니스 로직에만 집중&lt;/b&gt;할 수 있도록 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 기능을 수행하는데 필요한 로직을 &lt;b&gt;핵심적인 로직&lt;/b&gt;과 &lt;b&gt;부가적인 로직&lt;/b&gt;으로 나누어,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부가적인 로직은 따로 분리하여 공통적으로 처리하도록 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그로 인해 중복코드가 줄어듦으로써 &lt;span&gt;불필요한&lt;span&gt; 코드의 수정과 &lt;/span&gt;&lt;/span&gt;유지보수의 비용을 줄여주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;E &lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;= mc&amp;sup2;&lt;br /&gt;Error = (More Code)&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&amp;sup2;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1918&quot; data-origin-height=&quot;792&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beIfUp/btr0H7ldKVp/OM4Gjoxb3qO19tKL1JzAG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beIfUp/btr0H7ldKVp/OM4Gjoxb3qO19tKL1JzAG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beIfUp/btr0H7ldKVp/OM4Gjoxb3qO19tKL1JzAG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeIfUp%2Fbtr0H7ldKVp%2FOM4Gjoxb3qO19tKL1JzAG1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1918&quot; height=&quot;792&quot; data-origin-width=&quot;1918&quot; data-origin-height=&quot;792&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링에서는 JDBC, Trasaction, Logging 등에 AOP를 활용하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드는 Spring JDBC를 활용하여 DB연동을 하는 예제 코드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1970&quot; data-origin-height=&quot;2206&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/diDzrT/btr0GaW1bs0/D4RRWCy0qP1ByQuuM1oX2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/diDzrT/btr0GaW1bs0/D4RRWCy0qP1ByQuuM1oX2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/diDzrT/btr0GaW1bs0/D4RRWCy0qP1ByQuuM1oX2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdiDzrT%2Fbtr0GaW1bs0%2FD4RRWCy0qP1ByQuuM1oX2k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;547&quot; height=&quot;2206&quot; data-origin-width=&quot;1970&quot; data-origin-height=&quot;2206&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 AOP가 없었다면, 위처럼 SQL문을 실행하는 핵심로직 외에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB연결과 종료와 같은 &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;불필요한 부가로직의 공통코드가 증가되었을 겁니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;IoC(Inversion of Control) / DI(Dependency Injection)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링은 이런 방법으로 엄청난 유연함과 간결함을 통해 EJB 개발자들의 불편한 점들을 개선시켜 주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 스프링과 스프링부트의 차이점은 무엇일까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스프링과 스프링부트의 차이&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;76e31b00-782c-11e9-8fdc-eec6e93d055b.png&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;315&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLqN7k/btr0Iu1jzTQ/ZWMcXUKXYj7Z8n2gjjStA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLqN7k/btr0Iu1jzTQ/ZWMcXUKXYj7Z8n2gjjStA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLqN7k/btr0Iu1jzTQ/ZWMcXUKXYj7Z8n2gjjStA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLqN7k%2Fbtr0Iu1jzTQ%2FZWMcXUKXYj7Z8n2gjjStA0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;324&quot; height=&quot;170&quot; data-filename=&quot;76e31b00-782c-11e9-8fdc-eec6e93d055b.png&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;315&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #333333; font-size: 1.12em; letter-spacing: 0px;&quot;&gt;기존 스프링을 더 간편하게!&lt;/span&gt;&lt;/p&gt;
&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;figure id=&quot;og_1677341246760&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;Improved support for 'containerless' web application architectures [SPR-9888] &amp;middot; Issue #14521 &amp;middot; spring-projects/spring-framewor&quot; data-og-description=&quot;Mike Youngstrom opened SPR-9888 and commented As the enterprise development landscape grows more diverse the simpler the application framework the more likely developers are to adopt the framework....&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/spring-projects/spring-framework/issues/14521&quot; data-og-url=&quot;https://github.com/spring-projects/spring-framework/issues/14521&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bhunYk/hyRJGWZsZZ/fqW0WXJ32tW270A4XCnBp0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/spring-projects/spring-framework/issues/14521&quot; data-source-url=&quot;https://github.com/spring-projects/spring-framework/issues/14521&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bhunYk/hyRJGWZsZZ/fqW0WXJ32tW270A4XCnBp0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Improved support for 'containerless' web application architectures [SPR-9888] &amp;middot; Issue #14521 &amp;middot; spring-projects/spring-framewor&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Mike Youngstrom opened SPR-9888 and commented As the enterprise development landscape grows more diverse the simpler the application framework the more likely developers are to adopt the framework....&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링부트는 스프링 첫 출시로부터 10년 후에 등장을 하게 되는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링도 Containerless 웹 애플리케이션 아키텍처를 지원해 달라는 한 개발자의 요청으로부터 시작됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 배경을 이해해 보자면, 스프링부트가 등장한 2010년 당시에는 JavaScript의 Node.js나 Python의 Django 같은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빠르게 웹 애플리케이션을 개발하고 배포할 수 있는 경량 프레임워크들이 많은 인기를 얻었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그에 비해 스프링은 프로젝트 생성 시점부터 실제 개발을 시작하여 코드를 작성하기까지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용할 라이브러리들을 채택하고 서로 간의 호환성 등을 따져가면서 차근차근 프로젝트를 설계했어야 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Spring Boot makes it &lt;span style=&quot;background-color: #a7d86d; color: #666666;&quot;&gt;&lt;span&gt;easy&lt;/span&gt;&lt;/span&gt;&amp;nbsp;to create stand-alone,&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;production-grade Spring based Applications that you can &quot;&lt;span style=&quot;background-color: #a7d86d;&quot;&gt;just run&lt;/span&gt;&quot;.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;947&quot; data-origin-height=&quot;297&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZhTUA/btr0KHlxZTW/nx4sJ9eIr5L8dQMq9Z9390/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZhTUA/btr0KHlxZTW/nx4sJ9eIr5L8dQMq9Z9390/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZhTUA/btr0KHlxZTW/nx4sJ9eIr5L8dQMq9Z9390/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZhTUA%2Fbtr0KHlxZTW%2Fnx4sJ9eIr5L8dQMq9Z9390%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;624&quot; height=&quot;196&quot; data-origin-width=&quot;947&quot; data-origin-height=&quot;297&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링부트는 무엇이다!라는 명확한 정의는 없지만, &quot;복잡한 고민 없이 빠르게 스프링 기반 애플리케이션 개발을 시작할 수 있게 도와주는 도구&quot;라고 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본격적으로 스프링부트가 스프링과 비교하였을 때 어떻게 다른지 이야기해 보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Containerless&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ipqga/btr0JOyECPE/qKYbsghK96hjpJUQua4X1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ipqga/btr0JOyECPE/qKYbsghK96hjpJUQua4X1K/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-filename=&quot;무제.png&quot; width=&quot;394&quot; height=&quot;222&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ipqga/btr0JOyECPE/qKYbsghK96hjpJUQua4X1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIpqga%2Fbtr0JOyECPE%2FqKYbsghK96hjpJUQua4X1K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/deHfWB/btr0IGgxTd9/UiyewU1uMKElJN3ObJYtsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/deHfWB/btr0IGgxTd9/UiyewU1uMKElJN3ObJYtsK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-filename=&quot;무제(1).png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/deHfWB/btr0IGgxTd9/UiyewU1uMKElJN3ObJYtsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdeHfWB%2Fbtr0IGgxTd9%2FUiyewU1uMKElJN3ObJYtsK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;좌) 일반적인 웹 서버구조, 우) Java기반 웹 서버 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 프로그램(Component)은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;항상 Server의 내부 Container안에 존재하여야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Client의 요청에 의해 Server에서 각각의 웹 프로그램이 동작하고, Dynamic Content를 만들어 응답해 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;ex) &amp;nbsp;회원가입, 로그인, 게시글 작성&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 말하는 Containerless란 흔히 알고 있는 Serverless라는 것과 유사합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Serverless란 개발자가 서버에 대한 설치나 관리를 신경 쓰지 않고 애플리케이션을 개발하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배포할 수 있는 환경을 의미하며 &quot;서버가 필요하지 않다&quot;라는 의미는 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 스프링 레거시 프로젝트의 경우, 프로젝트 생성 후 추가적으로 web.xml설정, WAR구조, 배포관리 등등&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WAS서버를 설치 및 설정을 해주어야만 하는 번거로움이 존재했습니다.&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 스프링부트의 경우 내장되어 있는 WAS와 초기 설정들 덕분에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자가 WAS를 학습하여 &lt;span&gt;설치하고, 실행 및 관리하는&lt;/span&gt;&amp;nbsp;개발자의 수고를 제거해 주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Opinionated&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1335&quot; data-origin-height=&quot;565&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uUmw4/btr0H6Nk2zw/ZFK7X1fmk2TXaiy4s8J1ZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uUmw4/btr0H6Nk2zw/ZFK7X1fmk2TXaiy4s8J1ZK/img.png&quot; data-alt=&quot;첫 프로젝트 생성 후 초기 라이브러리 목록. 좌) 스프링, 우) 스프링부트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uUmw4/btr0H6Nk2zw/ZFK7X1fmk2TXaiy4s8J1ZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuUmw4%2Fbtr0H6Nk2zw%2FZFK7X1fmk2TXaiy4s8J1ZK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;553&quot; height=&quot;234&quot; data-origin-width=&quot;1335&quot; data-origin-height=&quot;565&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;첫 프로젝트 생성 후 초기 라이브러리 목록. 좌) 스프링, 우) 스프링부트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;스프링 레거시의 경우, 개발자 스스로 특정 기술에 필요한 라이브러리를 선택하고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;버전 호환성을 확인하여 수동으로 추가해주어야 하는 번거로움이 존재했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://mvnrepository.com/search?q=JSON&quot;&gt;https://mvnrepository.com/search?q=JSON&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 JSON과 관련된 기능을 수행하는 라이브러리를 선택을 할 때 약 8000개의 라이브러리 중에서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원하는 라이브러리를 선택하고 버전 호환성을 확인해야 하는 과정이 불가피했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링부트는 Web, DB연동, &lt;span&gt;Security, Batch와&lt;/span&gt; 같은 기술에 필요한 여러 선택지들 중에서 꼭 필요하고 적합하다고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;판단되는 라이브러리들을 미리 정해놓고 상호 &lt;span&gt;호환되는 버전을 결정하여 &lt;/span&gt;개발자에게 제공해 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나아가 각 라이브러리의 Bean 설정까지 어느 정도 제공해 주어 번거로운 과정을 생략시켜 주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Configuration&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bx0iIK/btr0KRBUuDh/R9n7QFAIeRAwKTjvuPXymK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bx0iIK/btr0KRBUuDh/R9n7QFAIeRAwKTjvuPXymK/img.png&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1502&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.611%; margin-right: 10px;&quot; data-widthpercent=&quot;50.19&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bx0iIK/btr0KRBUuDh/R9n7QFAIeRAwKTjvuPXymK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbx0iIK%2Fbtr0KRBUuDh%2FR9n7QFAIeRAwKTjvuPXymK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2048&quot; height=&quot;1502&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCYW5E/btr0JA1uVgg/gRSVdXkdm86NRrG9U9Alrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCYW5E/btr0JA1uVgg/gRSVdXkdm86NRrG9U9Alrk/img.png&quot; data-origin-width=&quot;874&quot; data-origin-height=&quot;646&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;49.81&quot; style=&quot;width: 49.2262%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCYW5E/btr0JA1uVgg/gRSVdXkdm86NRrG9U9Alrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCYW5E%2Fbtr0JA1uVgg%2FgRSVdXkdm86NRrG9U9Alrk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;874&quot; height=&quot;646&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;좌) 스프링 root-context.xml, 우) 스프링부트 application.yml&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 사진은 스프링과 스프링부트에서 DB연동과 MyBatis 설정을 하는 방식입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링부트는 보시는 것처럼 불필요한 내용이 없어지고 아주 단순해졌습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;다양한 커스터마이징 vs 빠르고 효율적인 개발&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링과 스프링부트는 서로 다른 니즈(Needs)에서 시작되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링은 더 유연하고, 더 다양한 커스터마이징에 초첨을 두었다면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링부트는 시대의 변화에 맞춰 &lt;span&gt;애플리케이션 개발의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;더 빠르고 효율적인 방법을 제공하는 데 초점을 두었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring Boot</category>
      <category>ejb</category>
      <category>ejb스프링</category>
      <category>스프링</category>
      <category>스프링vs스프링부트</category>
      <category>스프링부트</category>
      <category>스프링부트장점</category>
      <category>스프링역사</category>
      <category>스프링의정석</category>
      <category>스프링특징</category>
      <category>토비의스프링부트</category>
      <author>Darren Gwon</author>
      <guid isPermaLink="true">https://darrenlog.tistory.com/43</guid>
      <comments>https://darrenlog.tistory.com/43#entry43comment</comments>
      <pubDate>Sun, 26 Feb 2023 16:22:13 +0900</pubDate>
    </item>
    <item>
      <title>[ObjectMapper] CustomDeserializer 만들기</title>
      <link>https://darrenlog.tistory.com/42</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #161513;&quot;&gt;ObjectMapper은 데이터 포맷 중 하나인 JSON을 간편하게 POJO로 다룰 수 있는 기능들을 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #161513;&quot;&gt;또한 매우 Customizable하기 때문에 고도한 Object 처리를 가능하게 해줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 JSON &amp;rarr; POJO로 변환하는 과정(Deserialize, 역직렬화)에서 발생한&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;InvalidFormatException을 해결할 수 있는 CustomDeserializer클래스를 만들어보겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 시나리오&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Book JSON&lt;/p&gt;
&lt;pre id=&quot;code_1675433092487&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[
  {
    &quot;name&quot;:&quot;자바의정석&quot;,
    &quot;reviewCount&quot;:&quot;735&quot;
  },
  {
    &quot;name&quot;:&quot;토비의스프링&quot;,
    &quot;reviewCount&quot;:&quot;2,413&quot;
  }
]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BookDto&lt;/p&gt;
&lt;pre id=&quot;code_1675432874841&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Getter
@Setter
public class BookDto {
    private String name;
    private int reviewCount;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Service&lt;/p&gt;
&lt;pre id=&quot;code_1675433537487&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
@RequiredArgsConstructor
public class BookService {
    private final ObjectMapper objectMapper;
    
    public List&amp;lt;BookDto&amp;gt; getBooks(JsonNode responseNode) throws JsonProcessingException {
        List&amp;lt;BookDto&amp;gt; bookList = objectMapper.readValue(responseNode.toString(), new TypeReference&amp;lt;List&amp;lt;BookDto&amp;gt;&amp;gt;() {});
        return bookList;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Book JSON이 담긴 responseNode를 List&amp;lt;BookDto&amp;gt;로 변환해주는 코드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;자바의정석&quot; 데이터의 경우 BookDto로 변환하는데 문제가 없지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;토비의스프링&quot; 도서 데이터처럼 콤마(comma)를 포함하는 경우엔 BookDto로 변환이 불가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;형변환 에러 로그&lt;/p&gt;
&lt;pre id=&quot;code_1675434196679&quot; class=&quot;routeros&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.lang.Integer` from String &quot;2,413&quot;: not a valid `java.lang.Integer` value&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;reviewCount는 엄연한 숫자 데이터이지만, 위처럼 변환이 불가능한 경우에는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CustomDeserializer 클래스를 정의하여 등록해주면 ObjectMapper를 보다 유용하게 사용 가능합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 구현 코드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CustomIntegerDeserializer&lt;/p&gt;
&lt;pre id=&quot;code_1675434227769&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class CustomIntegerDeserializer extends JsonDeserializer&amp;lt;Integer&amp;gt; {
    @Override
    public Integer deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
        String stringNumber = p.getValueAsString();
        if(Objects.isNull(stringNumber) || &quot;&quot;.equals(stringNumber)) return null;

        return Integer.parseInt(stringNumber.replace(&quot;,&quot;, &quot;&quot;));
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JsonDeserializer를 상속받아 deserialize메서드를 오버라이딩하는 커스텀 클래스를 만들어줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;콤마를 &lt;span&gt;stringNumber.replace(&quot;,&quot;, &quot;&quot;)로 변환 후,&lt;/span&gt; Integer.parseInt()를 통해 int형으로 반환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BookDto&lt;/p&gt;
&lt;pre id=&quot;code_1675436740062&quot; class=&quot;less&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Getter
@Setter
public class BookDto {
    private String name;
    private int reviewCount;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;reviewCount의 타입을 기본형 int에서 Wrapper클래스인 Integer로 변경해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본형 int타입의 경우 의도한대로 변환이 불가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ObjectMapper&lt;/p&gt;
&lt;pre id=&quot;code_1675434693426&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
public class SpringConfig {
    @Bean
    public ObjectMapper objectMapper() {
        return JsonMapper.builder()
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                .addModule(new SimpleModule().addDeserializer(Integer.class, new CustomIntegerDeserializer()))
                .build();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드처럼 CustomIntegerDeserializer 클래스를 module로 추가해주면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;선언된 타입이 &lt;span&gt;Integer일 때, &lt;span&gt;역직렬화 과정에서&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;CustomIntegerDeserializer 클래스에 의해 변환이 이루어집니다.&lt;/p&gt;</description>
      <category>Spring</category>
      <category>customdeserialize</category>
      <category>customserialize</category>
      <category>fasterxml</category>
      <category>json</category>
      <category>objectmapper</category>
      <category>POJO</category>
      <category>스프링</category>
      <category>역직렬화</category>
      <category>자바</category>
      <category>직렬화</category>
      <author>Darren Gwon</author>
      <guid isPermaLink="true">https://darrenlog.tistory.com/42</guid>
      <comments>https://darrenlog.tistory.com/42#entry42comment</comments>
      <pubDate>Sat, 4 Feb 2023 00:10:26 +0900</pubDate>
    </item>
    <item>
      <title>[JsonNode] JsonNode을 Stream으로 변환하기</title>
      <link>https://darrenlog.tistory.com/41</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Array형식의 응답 값을 간편하게 다루기 위한 고민을 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JsonNode는 Iterable 인터페이스를 구현하고 있어, Stream으로 변환하여 처리하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;StreamSupport 클래스의 stream() 메서드로 변환이 가능합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1675270262198&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;StreamSupport.stream(jsonNode.spliterator(), false);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 응답값을 간편하게 &lt;span&gt;특정 조건으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;필터링한 후 List로 반환해주는 예제입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1675270228233&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JsonNode responseNode = restTemplate.exchange(uri, HttpMethod.POST, entity, JsonNode.class).getBody();
List&amp;lt;JsonNode&amp;gt; visitorNodeList = StreamSupport.stream(responseNode.spliterator(), false)
                        .filter(x -&amp;gt; x.get(&quot;age&quot;).asInt() &amp;lt; maxAge)
                        .collect(Collectors.toList());&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <category>JsonNode</category>
      <category>JsonNodeStream</category>
      <category>JsonNodeToStream</category>
      <category>restTemplate</category>
      <category>Stream</category>
      <category>StreamFilter</category>
      <category>StreamSupport</category>
      <category>stream변환</category>
      <category>스트림</category>
      <category>스트림변환</category>
      <author>Darren Gwon</author>
      <guid isPermaLink="true">https://darrenlog.tistory.com/41</guid>
      <comments>https://darrenlog.tistory.com/41#entry41comment</comments>
      <pubDate>Thu, 2 Feb 2023 02:07:09 +0900</pubDate>
    </item>
    <item>
      <title>[OAuth 2.0] 스프링부트로 Google 로그인 구현해보기 -2</title>
      <link>https://darrenlog.tistory.com/40</link>
      <description>&lt;figure id=&quot;og_1673585479378&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[OAuth 2.0] OAuth 개념과 구글 OAuth 세팅 및 로그인 스프링부트로 구현 해보기 -1&quot; data-og-description=&quot;안녕하세요. 이번 게시글에서는 OAuth 2.0에 대한 간략한 개념과 스프링부트 환경에서 직접 구현해보는 단계까지 다뤄보도록 하겠습니다. OAuth, Open Authorization 정의 OAuth는 인터넷 사용자들이 비밀&quot; data-og-host=&quot;darrenlog.tistory.com&quot; data-og-source-url=&quot;https://darrenlog.tistory.com/38&quot; data-og-url=&quot;https://darrenlog.tistory.com/38&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/rohPY/hyRgrStVC7/XVmbDE1qkn2Tt5v8ZzccK0/img.png?width=622&amp;amp;height=398&amp;amp;face=0_0_622_398,https://scrap.kakaocdn.net/dn/fkhov/hyRgq67bzz/baATeYFKyGyM4q6UiJ1SR1/img.png?width=622&amp;amp;height=398&amp;amp;face=0_0_622_398,https://scrap.kakaocdn.net/dn/YN9z3/hyRgrkFB1K/PG7BsxAtkIVcurD4X68AJK/img.png?width=861&amp;amp;height=266&amp;amp;face=0_0_861_266&quot;&gt;&lt;a href=&quot;https://darrenlog.tistory.com/38&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://darrenlog.tistory.com/38&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/rohPY/hyRgrStVC7/XVmbDE1qkn2Tt5v8ZzccK0/img.png?width=622&amp;amp;height=398&amp;amp;face=0_0_622_398,https://scrap.kakaocdn.net/dn/fkhov/hyRgq67bzz/baATeYFKyGyM4q6UiJ1SR1/img.png?width=622&amp;amp;height=398&amp;amp;face=0_0_622_398,https://scrap.kakaocdn.net/dn/YN9z3/hyRgrkFB1K/PG7BsxAtkIVcurD4X68AJK/img.png?width=861&amp;amp;height=266&amp;amp;face=0_0_861_266');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[OAuth 2.0] OAuth 개념과 구글 OAuth 세팅 및 로그인 스프링부트로 구현 해보기 -1&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요. 이번 게시글에서는 OAuth 2.0에 대한 간략한 개념과 스프링부트 환경에서 직접 구현해보는 단계까지 다뤄보도록 하겠습니다. OAuth, Open Authorization 정의 OAuth는 인터넷 사용자들이 비밀&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;darrenlog.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 게시글은 1편에 이어 스프링 부트를 활용하여 유저의 이메일 정보를 받아오는 코드를 작성해 보도록 하겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Authorization Code 발급&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;364&quot; data-origin-height=&quot;377&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buZLVw/btrWbLyvMcm/cZ7DpX031Rw3LZT2R1P7ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buZLVw/btrWbLyvMcm/cZ7DpX031Rw3LZT2R1P7ck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buZLVw/btrWbLyvMcm/cZ7DpX031Rw3LZT2R1P7ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuZLVw%2FbtrWbLyvMcm%2FcZ7DpX031Rw3LZT2R1P7ck%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;364&quot; height=&quot;377&quot; data-origin-width=&quot;364&quot; data-origin-height=&quot;377&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저 해야하는 Authoriztion code 발급부터 테스트해보도록 하겠습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;a href=&quot;https://accounts.google.com/o/oauth2/auth?client_id=&quot;&gt;https://accounts.google.com/o/oauth2/auth?client_id=&lt;/a&gt;&lt;a href=&quot;https://accounts.google.com/o/oauth2/auth?client_id=CLIENT_ID&amp;amp;redirect_uri=REDIRECT_URI&amp;amp;response_type=code&amp;amp;scope=https://www.googleapis.com/auth/userinfo.email%20https://www.googleapis.com/auth/userinfo.profile&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;CLIENT_ID&lt;/span&gt;&amp;amp;redirect_uri=&lt;span style=&quot;color: #ee2323;&quot;&gt;REDIRECT_URI&lt;/span&gt;&amp;amp;response_type=code&amp;amp;scope=&lt;/a&gt;&lt;a href=&quot;https://www.googleapis.com/auth/userinfo.email&quot;&gt;https://www.googleapis.com/auth/userinfo.email&lt;/a&gt;&lt;a href=&quot;https://www.googleapis.com/auth/userinfo.profile&quot;&gt;https://www.googleapis.com/auth/userinfo.profile&lt;/a&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유저가 위 페이지에서 구글 로그인을 마치고나면 redirect_uri에 Authorization code를 응답해 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 Authorization code를 콘솔에 출력하는 것부터 진행해 보겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;318&quot; data-origin-height=&quot;281&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OTgRm/btrWbiSOpri/wvKqRtXNO3fAVhRQDltBHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OTgRm/btrWbiSOpri/wvKqRtXNO3fAVhRQDltBHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OTgRm/btrWbiSOpri/wvKqRtXNO3fAVhRQDltBHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOTgRm%2FbtrWbiSOpri%2FwvKqRtXNO3fAVhRQDltBHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;263&quot; height=&quot;232&quot; data-origin-width=&quot;318&quot; data-origin-height=&quot;281&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;패키지 구조는 간단하게 구성하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;application.yml&lt;/h3&gt;
&lt;pre id=&quot;code_1673619745184&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;oauth2:
  google:
    client-id: 클라이언트ID
    client-secret: 클라이언트SECRET
    redirect-uri: 리디렉션URI
    token-uri: https://oauth2.googleapis.com/token
    resource-uri: https://www.googleapis.com/oauth2/v2/userinfo
  kakao:
    client-id: 클라이언트ID
    client-secret: 클라이언트SECRET
    redirect-uri: 리디렉션URI
    token-uri: 엑세스토큰URI
    resource-uri: 리소스URI&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;컨트롤러&lt;/h3&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨트롤러 URL Mapping은 Google OAuth API 설정 시 등록했던 리디렉션 URI와 동일하게 해 주세요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;491&quot; data-origin-height=&quot;149&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cK7Osy/btrWdoKHKIc/uPvZ5NR0oNzUWOI8cdIigk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cK7Osy/btrWdoKHKIc/uPvZ5NR0oNzUWOI8cdIigk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cK7Osy/btrWdoKHKIc/uPvZ5NR0oNzUWOI8cdIigk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcK7Osy%2FbtrWdoKHKIc%2FuPvZ5NR0oNzUWOI8cdIigk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;491&quot; height=&quot;149&quot; data-origin-width=&quot;491&quot; data-origin-height=&quot;149&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;@RestController
@RequestMapping(value = &quot;/login/oauth2&quot;, produces = &quot;application/json&quot;)
public class LoginController {

    LoginService  loginService;

    public LoginController(LoginService loginService) {
        this.loginService = loginService;
    }

    @GetMapping(&quot;/code/{registrationId}&quot;)
    public void googleLogin(@RequestParam String code, @PathVariable String registrationId) {
        loginService.socialLogin(code, registrationId);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;서비스&lt;/h3&gt;
&lt;div&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Service
public class LoginService {
    public void socialLogin(String code, String registrationId) {
        System.out.println(&quot;code = &quot; + code);
        System.out.println(&quot;registrationId = &quot; + registrationId);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;534&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tCvQs/btscMHUquTU/PFKY4jGDaOWIs2LunuXVq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tCvQs/btscMHUquTU/PFKY4jGDaOWIs2LunuXVq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tCvQs/btscMHUquTU/PFKY4jGDaOWIs2LunuXVq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtCvQs%2FbtscMHUquTU%2FPFKY4jGDaOWIs2LunuXVq0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;534&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;534&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구글 로그인 후에 콘솔에 위에&amp;nbsp; 사진처럼 잘 출력되신다면 성공입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. Access Token 발급&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;364&quot; data-origin-height=&quot;377&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rWNY5/btrWcK7G78T/M2jprFMWYxLIPEgrHW8gCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rWNY5/btrWcK7G78T/M2jprFMWYxLIPEgrHW8gCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rWNY5/btrWcK7G78T/M2jprFMWYxLIPEgrHW8gCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrWNY5%2FbtrWcK7G78T%2FM2jprFMWYxLIPEgrHW8gCK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;364&quot; height=&quot;377&quot; data-origin-width=&quot;364&quot; data-origin-height=&quot;377&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발급받은 Authorization code를 통해 Access Token을 발급받아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;서비스&lt;/h3&gt;
&lt;div&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Service
public class LoginService {

    private final Environment env;
    private final RestTemplate restTemplate = new RestTemplate();
    
    public LoginService(Environment env) {
        this.env = env;
    }
    public void socialLogin(String code, String registrationId) {
        String accessToken = getAccessToken(code, registrationId);
        System.out.println(&quot;accessToken = &quot; + accessToken);
    }

    private String getAccessToken(String authorizationCode, String registrationId) {
        String clientId = env.getProperty(&quot;oauth2.&quot; + registrationId + &quot;.client-id&quot;);
        String clientSecret = env.getProperty(&quot;oauth2.&quot; + registrationId + &quot;.client-secret&quot;);
        String redirectUri = env.getProperty(&quot;oauth2.&quot; + registrationId + &quot;.redirect-uri&quot;);
        String tokenUri = env.getProperty(&quot;oauth2.&quot; + registrationId + &quot;.token-uri&quot;);

        MultiValueMap&amp;lt;String, String&amp;gt; params = new LinkedMultiValueMap&amp;lt;&amp;gt;();
        params.add(&quot;code&quot;, authorizationCode);
        params.add(&quot;client_id&quot;, clientId);
        params.add(&quot;client_secret&quot;, clientSecret);
        params.add(&quot;redirect_uri&quot;, redirectUri);
        params.add(&quot;grant_type&quot;, &quot;authorization_code&quot;);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        HttpEntity entity = new HttpEntity(params, headers);

        ResponseEntity&amp;lt;JsonNode&amp;gt; responseNode = restTemplate.exchange(tokenUri, HttpMethod.POST, entity, JsonNode.class);
        JsonNode accessTokenNode = responseNode.getBody();
        return accessTokenNode.get(&quot;access_token&quot;).asText();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;931&quot; data-origin-height=&quot;83&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pYPWr/btrWbMMB49A/pX6teUR5S6WuId91p1FNK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pYPWr/btrWbMMB49A/pX6teUR5S6WuId91p1FNK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pYPWr/btrWbMMB49A/pX6teUR5S6WuId91p1FNK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpYPWr%2FbtrWbMMB49A%2FpX6teUR5S6WuId91p1FNK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;737&quot; height=&quot;66&quot; data-origin-width=&quot;931&quot; data-origin-height=&quot;83&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;콘솔에 다음과 같이 출력되었으면 accessToken까지 발급하는 데에 성공하셨습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. Resource Server에서 유저정보 받기&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;364&quot; data-origin-height=&quot;377&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1ePJv/btrWbUDLLoh/9atLBp7N515fjOIGIT9iCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1ePJv/btrWbUDLLoh/9atLBp7N515fjOIGIT9iCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1ePJv/btrWbUDLLoh/9atLBp7N515fjOIGIT9iCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1ePJv%2FbtrWbUDLLoh%2F9atLBp7N515fjOIGIT9iCK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;364&quot; height=&quot;377&quot; data-origin-width=&quot;364&quot; data-origin-height=&quot;377&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 마지막 단계입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OAuth 개념에 Resource Server라는 것이 있는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유저 정보를 안전하게 저장하고 있는 서버라고 생각하시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;서비스&lt;/h3&gt;
&lt;div&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Service
public class LoginService {

    private final Environment env;
    private final RestTemplate restTemplate = new RestTemplate();

    public LoginService(Environment env) {
        this.env = env;
    }
    public void socialLogin(String code, String registrationId) {
        String accessToken = getAccessToken(code, registrationId);
        JsonNode userResourceNode = getUserResource(accessToken, registrationId);
        System.out.println(&quot;userResourceNode = &quot; + userResourceNode);

        String id = userResourceNode.get(&quot;id&quot;).asText();
        String email = userResourceNode.get(&quot;email&quot;).asText();
        String nickname = userResourceNode.get(&quot;name&quot;).asText();
        System.out.println(&quot;id = &quot; + id);
        System.out.println(&quot;email = &quot; + email);
        System.out.println(&quot;nickname = &quot; + nickname);
    }

    private String getAccessToken(String authorizationCode, String registrationId) {
        String clientId = env.getProperty(&quot;oauth2.&quot; + registrationId + &quot;.client-id&quot;);
        String clientSecret = env.getProperty(&quot;oauth2.&quot; + registrationId + &quot;.client-secret&quot;);
        String redirectUri = env.getProperty(&quot;oauth2.&quot; + registrationId + &quot;.redirect-uri&quot;);
        String tokenUri = env.getProperty(&quot;oauth2.&quot; + registrationId + &quot;.token-uri&quot;);

        MultiValueMap&amp;lt;String, String&amp;gt; params = new LinkedMultiValueMap&amp;lt;&amp;gt;();
        params.add(&quot;code&quot;, authorizationCode);
        params.add(&quot;client_id&quot;, clientId);
        params.add(&quot;client_secret&quot;, clientSecret);
        params.add(&quot;redirect_uri&quot;, redirectUri);
        params.add(&quot;grant_type&quot;, &quot;authorization_code&quot;);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        HttpEntity entity = new HttpEntity(params, headers);

        ResponseEntity&amp;lt;JsonNode&amp;gt; responseNode = restTemplate.exchange(tokenUri, HttpMethod.POST, entity, JsonNode.class);
        JsonNode accessTokenNode = responseNode.getBody();
        return accessTokenNode.get(&quot;access_token&quot;).asText();
    }

    private JsonNode getUserResource(String accessToken, String registrationId) {
        String resourceUri = env.getProperty(&quot;oauth2.&quot;+registrationId+&quot;.resource-uri&quot;);

        HttpHeaders headers = new HttpHeaders();
        headers.set(&quot;Authorization&quot;, &quot;Bearer &quot; + accessToken);
        HttpEntity entity = new HttpEntity(headers);
        return restTemplate.exchange(resourceUri, HttpMethod.GET, entity, JsonNode.class).getBody();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;986&quot; data-origin-height=&quot;196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q3YAj/btrWefzVSS1/aOhr4CnkvJWuOazC4tEjv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q3YAj/btrWefzVSS1/aOhr4CnkvJWuOazC4tEjv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q3YAj/btrWefzVSS1/aOhr4CnkvJWuOazC4tEjv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq3YAj%2FbtrWefzVSS1%2FaOhr4CnkvJWuOazC4tEjv0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;986&quot; height=&quot;196&quot; data-origin-width=&quot;986&quot; data-origin-height=&quot;196&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;콘솔에 위처럼 값이 출력되면 구글 OAuth2.0 로그인 부분 구현에 성공하셨습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 발급받은 email 정보를 통해 각자 서비스 정책에 맞는 회원가입 로직을 작성하시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종 코드는 깃헙에 공유해놓았습니다.&lt;/p&gt;
&lt;figure id=&quot;og_1673626497805&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - darren-gwon/springboot_oauth_example: springboot_oauth_example&quot; data-og-description=&quot;springboot_oauth_example. Contribute to darren-gwon/springboot_oauth_example development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/darren-gwon/springboot_oauth_example&quot; data-og-url=&quot;https://github.com/darren-gwon/springboot_oauth_example&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cBjIMr/hyRgrrZrZm/7cCkx2xihnV1FK7LnqX03K/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/darren-gwon/springboot_oauth_example&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/darren-gwon/springboot_oauth_example&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cBjIMr/hyRgrrZrZm/7cCkx2xihnV1FK7LnqX03K/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - darren-gwon/springboot_oauth_example: springboot_oauth_example&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;springboot_oauth_example. Contribute to darren-gwon/springboot_oauth_example development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring</category>
      <category>Google</category>
      <category>google로그인</category>
      <category>kakao로그인</category>
      <category>naver로그인</category>
      <category>oauth</category>
      <category>oauth2</category>
      <category>구글로그인</category>
      <category>소셜로그인</category>
      <author>Darren Gwon</author>
      <guid isPermaLink="true">https://darrenlog.tistory.com/40</guid>
      <comments>https://darrenlog.tistory.com/40#entry40comment</comments>
      <pubDate>Sat, 14 Jan 2023 00:26:01 +0900</pubDate>
    </item>
    <item>
      <title>2022년 회고록 - 전역 후 개발자로 취업까지</title>
      <link>https://darrenlog.tistory.com/39</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;1월 공군 만기 전역&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;1월 13일에 미복귀 휴가를 나오며 공군 만기 전역을 하였습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;2월 28일 드디어 민간인 신분이 되어&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;개발자가 되기 위한 목표를 달성하기 위해 국취제 프로그램을 알아보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;2월 비트캠프 합격&lt;/span&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;240&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbkhma/btrU56YgdI0/a1crxmW6y3ekI20quRxAT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbkhma/btrU56YgdI0/a1crxmW6y3ekI20quRxAT0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbkhma/btrU56YgdI0/a1crxmW6y3ekI20quRxAT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbbkhma%2FbtrU56YgdI0%2Fa1crxmW6y3ekI20quRxAT0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;311&quot; height=&quot;115&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;240&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;여러 학원들 중 강남 비트캠프를 선택하게 되었고&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;2월 11일 합격을 하게 되었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7vY9x/btrU0usuewQ/Rt8KM4JfKebqYyuT2hV5O0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7vY9x/btrU0usuewQ/Rt8KM4JfKebqYyuT2hV5O0/img.png&quot; data-origin-width=&quot;1058&quot; data-origin-height=&quot;1411&quot; data-is-animation=&quot;false&quot; style=&quot;width: 25.850502%; margin-right: 10px;&quot; data-widthpercent=&quot;26.47&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7vY9x/btrU0usuewQ/Rt8KM4JfKebqYyuT2hV5O0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7vY9x%2FbtrU0usuewQ%2FRt8KM4JfKebqYyuT2hV5O0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1058&quot; height=&quot;1411&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byHvrB/btrUWbf6cNS/54DDFFD8SdfqD4kl8m4IV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byHvrB/btrUWbf6cNS/54DDFFD8SdfqD4kl8m4IV0/img.png&quot; data-origin-width=&quot;1152&quot; data-origin-height=&quot;1536&quot; data-is-animation=&quot;false&quot; style=&quot;width: 25.85661%; margin-right: 10px;&quot; data-widthpercent=&quot;26.47&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byHvrB/btrUWbf6cNS/54DDFFD8SdfqD4kl8m4IV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyHvrB%2FbtrUWbf6cNS%2F54DDFFD8SdfqD4kl8m4IV0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1152&quot; height=&quot;1536&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dQ9JLA/btrUYPKsRjA/Q4DnBftxnBD0XrALE5RdeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dQ9JLA/btrUYPKsRjA/Q4DnBftxnBD0XrALE5RdeK/img.png&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;47.06&quot; data-filename=&quot;blob&quot; style=&quot;width: 45.967307%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dQ9JLA/btrUYPKsRjA/Q4DnBftxnBD0XrALE5RdeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdQ9JLA%2FbtrUYPKsRjA%2FQ4DnBftxnBD0XrALE5RdeK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;본가가 강원도라 ktx를 타고 왔다 갔다 하면서 수업을 들었었습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;지금 생각해보면 열정 하나만으로 버틸 수 있었던 것 같습니다.&lt;/p&gt;
&lt;figure id=&quot;og_1672496895693&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;비트캠프 수료, 그리고 남궁성 선생님의 DevCamp!&quot; data-og-description=&quot;드디어 비트캠프를 수료하게 됐습니다! 사실 수료한지 이미 며칠이 지났지만 기록을 남기려고 포스팅을 합니다 ㅎㅎ 처음시작했을 때는 수료날이 언제 올까 싶었는데... 시간이 참 빠르네요. 주&quot; data-og-host=&quot;darrenlog.tistory.com&quot; data-og-source-url=&quot;https://darrenlog.tistory.com/9&quot; data-og-url=&quot;https://darrenlog.tistory.com/9&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cpaPRK/hyQ6TOzxyj/3M0XAiA7Bn7b6vzQsrfKrK/img.png?width=800&amp;amp;height=537&amp;amp;face=0_0_800_537,https://scrap.kakaocdn.net/dn/ogkbl/hyQ6SB8SHt/EKYk5DPGYNC3NXLoX3lZLK/img.png?width=800&amp;amp;height=537&amp;amp;face=0_0_800_537,https://scrap.kakaocdn.net/dn/b52iQB/hyQ5xzBSQv/dIGX3gxhjlQ0aGhRfNKKjk/img.png?width=3362&amp;amp;height=2257&amp;amp;face=0_0_3362_2257&quot;&gt;&lt;a href=&quot;https://darrenlog.tistory.com/9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://darrenlog.tistory.com/9&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cpaPRK/hyQ6TOzxyj/3M0XAiA7Bn7b6vzQsrfKrK/img.png?width=800&amp;amp;height=537&amp;amp;face=0_0_800_537,https://scrap.kakaocdn.net/dn/ogkbl/hyQ6SB8SHt/EKYk5DPGYNC3NXLoX3lZLK/img.png?width=800&amp;amp;height=537&amp;amp;face=0_0_800_537,https://scrap.kakaocdn.net/dn/b52iQB/hyQ5xzBSQv/dIGX3gxhjlQ0aGhRfNKKjk/img.png?width=3362&amp;amp;height=2257&amp;amp;face=0_0_3362_2257');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;비트캠프 수료, 그리고 남궁성 선생님의 DevCamp!&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;드디어 비트캠프를 수료하게 됐습니다! 사실 수료한지 이미 며칠이 지났지만 기록을 남기려고 포스팅을 합니다 ㅎㅎ 처음시작했을 때는 수료날이 언제 올까 싶었는데... 시간이 참 빠르네요. 주&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;darrenlog.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;4월 패스트캠퍼스 인터뷰 촬영&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQYTO7/btrU2980gof/ynSEOEEl9RyNFdTIn1QWO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQYTO7/btrU2980gof/ynSEOEEl9RyNFdTIn1QWO0/img.png&quot; data-origin-width=&quot;982&quot; data-origin-height=&quot;476&quot; data-is-animation=&quot;false&quot; width=&quot;448&quot; height=&quot;217&quot; style=&quot;width: 61.124316%; margin-right: 10px;&quot; data-widthpercent=&quot;61.84&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQYTO7/btrU2980gof/ynSEOEEl9RyNFdTIn1QWO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQYTO7%2FbtrU2980gof%2FynSEOEEl9RyNFdTIn1QWO0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;982&quot; height=&quot;476&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l0qjp/btrUWRPvCRj/PlqyEkXYOhvmaVJPLSBLU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l0qjp/btrUWRPvCRj/PlqyEkXYOhvmaVJPLSBLU1/img.png&quot; data-origin-width=&quot;877&quot; data-origin-height=&quot;689&quot; data-is-animation=&quot;false&quot; style=&quot;width: 37.712893%;&quot; data-widthpercent=&quot;38.16&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l0qjp/btrUWRPvCRj/PlqyEkXYOhvmaVJPLSBLU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl0qjp%2FbtrUWRPvCRj%2FPlqyEkXYOhvmaVJPLSBLU1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;877&quot; height=&quot;689&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;열심히 공부하던 중 패스트캠퍼스로 부터 인터뷰 제안을 받게 되었습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;저는 단지 제가 해야만 하는 공부를 한 것뿐인데&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;제게 이런 특별한 기회를 주신 패스트캠퍼스 분들에게 감사하다는 말씀드리고 싶습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&quot;나의 노력을 알아주는 사람이 있구나!&quot;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;라는 위로와 용기를 얻을 수 있던 것 같습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1672504790431&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;[패캠인사이트] Darren 수강생님과 함께한 인사이트 인터뷰 | 패스트캠퍼스&quot; data-og-description=&quot;패스트캠퍼스와 함께 변화한 수강생의 이야기를 듣습니다 &quot; data-og-host=&quot;fastcampus.co.kr&quot; data-og-source-url=&quot;https://fastcampus.co.kr/insight_darren&quot; data-og-url=&quot;https://fastcampus.co.kr/insight_darren&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/RgLDa/hyQ5AXri3K/hEp0H94RYuy0dwS9aHkNyK/img.jpg?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080,https://scrap.kakaocdn.net/dn/eJv87/hyQ6RwviS5/w0PZKVpeSWQ7TpPrKu0TjK/img.png?width=1277&amp;amp;height=715&amp;amp;face=0_0_1277_715,https://scrap.kakaocdn.net/dn/bSFhVe/hyQ6NU99Xi/NduegIKXnzTN4a68dFRxjk/img.png?width=1277&amp;amp;height=715&amp;amp;face=0_0_1277_715&quot;&gt;&lt;a href=&quot;https://fastcampus.co.kr/insight_darren&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://fastcampus.co.kr/insight_darren&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/RgLDa/hyQ5AXri3K/hEp0H94RYuy0dwS9aHkNyK/img.jpg?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080,https://scrap.kakaocdn.net/dn/eJv87/hyQ6RwviS5/w0PZKVpeSWQ7TpPrKu0TjK/img.png?width=1277&amp;amp;height=715&amp;amp;face=0_0_1277_715,https://scrap.kakaocdn.net/dn/bSFhVe/hyQ6NU99Xi/NduegIKXnzTN4a68dFRxjk/img.png?width=1277&amp;amp;height=715&amp;amp;face=0_0_1277_715');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[패캠인사이트] Darren 수강생님과 함께한 인사이트 인터뷰 | 패스트캠퍼스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;패스트캠퍼스와 함께 변화한 수강생의 이야기를 듣습니다 &lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;fastcampus.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;7월 파이널 프로젝트 &amp;amp; 프로젝트 멘토링&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/52jX0/btsQcsSiXJ0/YtevNv4hAVNDCaDHDU3CZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/52jX0/btsQcsSiXJ0/YtevNv4hAVNDCaDHDU3CZk/img.png&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1152&quot; data-is-animation=&quot;false&quot; width=&quot;441&quot; height=&quot;331&quot; data-widthpercent=&quot;53.55&quot; data-filename=&quot;blob&quot; style=&quot;width: 52.930587%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/52jX0/btsQcsSiXJ0/YtevNv4hAVNDCaDHDU3CZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F52jX0%2FbtsQcsSiXJ0%2FYtevNv4hAVNDCaDHDU3CZk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1536&quot; height=&quot;1152&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cy2AkC/btrU02CDKZA/FmrRNFGaddavou2si4Vow0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cy2AkC/btrU02CDKZA/FmrRNFGaddavou2si4Vow0/img.png&quot; data-origin-width=&quot;244&quot; data-origin-height=&quot;211&quot; data-is-animation=&quot;false&quot; style=&quot;width: 45.906623%;&quot; data-widthpercent=&quot;46.45&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cy2AkC/btrU02CDKZA/FmrRNFGaddavou2si4Vow0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcy2AkC%2FbtrU02CDKZA%2FFmrRNFGaddavou2si4Vow0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;244&quot; height=&quot;211&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;제가 관리하고 있는 스터디모임에서 지원자를 받아&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;웹 프로젝트를 진행하게 되었습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;저는 멘토로 활동하면서 프로젝트 설계와 진행을 돕는 역할을 했었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;8월 데브캠프&lt;/span&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbSac0/btrUWSHB33m/EuFtCvz9KaQFkk0RSoXBT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbSac0/btrUWSHB33m/EuFtCvz9KaQFkk0RSoXBT1/img.png&quot; data-origin-width=&quot;1058&quot; data-origin-height=&quot;1411&quot; data-is-animation=&quot;false&quot; style=&quot;width: 26.447039%; margin-right: 10px;&quot; data-widthpercent=&quot;27.08&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbSac0/btrUWSHB33m/EuFtCvz9KaQFkk0RSoXBT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbSac0%2FbtrUWSHB33m%2FEuFtCvz9KaQFkk0RSoXBT1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1058&quot; height=&quot;1411&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwAr9H/btrU38IVMcV/2UzVY8OpwjsNFmOd3GNiHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwAr9H/btrU38IVMcV/2UzVY8OpwjsNFmOd3GNiHK/img.png&quot; data-origin-width=&quot;514&quot; data-origin-height=&quot;405&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;45.83&quot; data-filename=&quot;blob&quot; style=&quot;width: 44.763754%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwAr9H/btrU38IVMcV/2UzVY8OpwjsNFmOd3GNiHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwAr9H%2FbtrU38IVMcV%2F2UzVY8OpwjsNFmOd3GNiHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;514&quot; height=&quot;405&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dSooye/btsP889mIcG/7qC97BmOl3AtXoPdHnp8Fk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dSooye/btsP889mIcG/7qC97BmOl3AtXoPdHnp8Fk/img.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1706&quot; data-is-animation=&quot;false&quot; style=&quot;width: 26.463626%;&quot; data-widthpercent=&quot;27.09&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dSooye/btsP889mIcG/7qC97BmOl3AtXoPdHnp8Fk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdSooye%2FbtsP889mIcG%2F7qC97BmOl3AtXoPdHnp8Fk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;1706&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;비트캠프 수료 후 데브캠프를 들어가게 됐습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;첫 개발 공부를 할 때 자바의정석으로 시작을 하였고,&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;스프링의 정석을 통해 본격적으로 웹 개발 공부를 하였습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;자바의정석 저자시며 스프링의정석 강사이신 남궁성 선생님께 직접 배울 수 있는 기회를 통해서&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;정말 많이 성장할 수 있었고 지금의 제가 있을 수 있었습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;선생님 감사합니다.&lt;/p&gt;
&lt;figure id=&quot;og_1672504824102&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;남궁성 선생님의 부트캠프, 2022 DevCamp를 수료하며&quot; data-og-description=&quot;https://darrenlog.tistory.com/9 비트캠프 수료, 그리고 남궁성 선생님의 DevCamp! 드디어 비트캠프를 수료하게 됐습니다! 사실 수료한지 이미 며칠이 지났지만 기록을 남기려고 포스팅을 합니다 ㅎㅎ 처&quot; data-og-host=&quot;darrenlog.tistory.com&quot; data-og-source-url=&quot;https://darrenlog.tistory.com/18&quot; data-og-url=&quot;https://darrenlog.tistory.com/18&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ct0EkU/hyQ6QRSmES/KBolnSO5xATktOkP75KNdK/img.png?width=800&amp;amp;height=1066&amp;amp;face=49_314_765_444,https://scrap.kakaocdn.net/dn/bNHQik/hyQ5G4r5Aj/cZoDIK24rOyphdXyjgvtz1/img.png?width=800&amp;amp;height=1066&amp;amp;face=49_314_765_444,https://scrap.kakaocdn.net/dn/clR6VP/hyQ5DUaERZ/PyjpGGKsR0RPmDblXHL0iK/img.jpg?width=1824&amp;amp;height=2432&amp;amp;face=0_0_1824_2432&quot;&gt;&lt;a href=&quot;https://darrenlog.tistory.com/18&quot; data-source-url=&quot;https://darrenlog.tistory.com/18&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ct0EkU/hyQ6QRSmES/KBolnSO5xATktOkP75KNdK/img.png?width=800&amp;amp;height=1066&amp;amp;face=49_314_765_444,https://scrap.kakaocdn.net/dn/bNHQik/hyQ5G4r5Aj/cZoDIK24rOyphdXyjgvtz1/img.png?width=800&amp;amp;height=1066&amp;amp;face=49_314_765_444,https://scrap.kakaocdn.net/dn/clR6VP/hyQ5DUaERZ/PyjpGGKsR0RPmDblXHL0iK/img.jpg?width=1824&amp;amp;height=2432&amp;amp;face=0_0_1824_2432');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;남궁성 선생님의 부트캠프, 2022 DevCamp를 수료하며&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;https://darrenlog.tistory.com/9 비트캠프 수료, 그리고 남궁성 선생님의 DevCamp! 드디어 비트캠프를 수료하게 됐습니다! 사실 수료한지 이미 며칠이 지났지만 기록을 남기려고 포스팅을 합니다 ㅎㅎ 처&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;darrenlog.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;10월 취업&lt;/span&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n1K0Q/btrUYQoY9Hc/oL75Z58Jel8cAEnH3FG5U0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n1K0Q/btrUYQoY9Hc/oL75Z58Jel8cAEnH3FG5U0/img.png&quot; style=&quot;width: 25.847491%; margin-right: 10px;&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;26.46&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n1K0Q/btrUYQoY9Hc/oL75Z58Jel8cAEnH3FG5U0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn1K0Q%2FbtrUYQoY9Hc%2FoL75Z58Jel8cAEnH3FG5U0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLwq4f/btrU147Xe2J/zcwXi0xAs0Ho5qIxV46O7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLwq4f/btrU147Xe2J/zcwXi0xAs0Ho5qIxV46O7K/img.png&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;47.05&quot; data-filename=&quot;blob&quot; style=&quot;width: 45.951095%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLwq4f/btrU147Xe2J/zcwXi0xAs0Ho5qIxV46O7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLwq4f%2FbtrU147Xe2J%2FzcwXi0xAs0Ho5qIxV46O7K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OrVjQ/btrUVi0QX60/bVmaR7Pj5kNF4oXDxm9Ci1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OrVjQ/btrUVi0QX60/bVmaR7Pj5kNF4oXDxm9Ci1/img.png&quot; style=&quot;width: 25.875833%;&quot; data-origin-width=&quot;913&quot; data-origin-height=&quot;1216&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;26.49&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OrVjQ/btrUVi0QX60/bVmaR7Pj5kNF4oXDxm9Ci1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOrVjQ%2FbtrUVi0QX60%2FbVmaR7Pj5kNF4oXDxm9Ci1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;913&quot; height=&quot;1216&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;한 달 정도 취준 생활을 하며 여러 곳에 면접도 보고&amp;nbsp;바쁘게 지낸 것 같습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;결국 제가 소속될 곳을 결정하고 10월 11일 첫 출근을 하게 되었습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;저희 회사 종무식 사진입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;각자 부담없이 작은 선물을 준비하여 보드 게임을 하면서 보내는 문화가 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;일등부터 자신이 원하는 선물을 가져갈 수 있고 저는 운 좋게도 공동 2등을 하게 됐네요.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;정말 재밌고 특별한 추억을 만들 수 있었던 것 같습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;좋은 문화와 좋은 사람들이 모여있는 곳이라 &quot;더 열심히 잘하고 싶다&quot;라는 마음이 드는 회사입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;비록 몇 달 안 된 신입 개발자이지만 앞으로 성장할 제 모습이 기대가 됩니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;더 성장하여 좋은 역량으로 보답하는 제가 됐으면 좋겠네요.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;화이팅!&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;누군가 제게 2022년도가 어떤 한해였는지 묻는다면&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&quot;제 인생에 이보다 더 큰 열정으로 살아본 적이 없다&quot;라고 자신 있게 대답할 수 있을 것 같습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;여러분들에게 2022년도는 어떤 한 해였나요?&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;좋았던 일, 그렇지 못했던 일 이제는 다 과거의 추억으로 남겨놓으시고&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;다가올 새로운 날을 기대하셨으면 좋겠습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이 글을 읽으시는 분들 모두 2023년에는 항상 좋은 일들만 가득하시길 바랍니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;새해 복 많이 받으세요.&lt;/p&gt;</description>
      <category>일상</category>
      <category>2022회고록</category>
      <category>2023</category>
      <category>회고록</category>
      <author>Darren Gwon</author>
      <guid isPermaLink="true">https://darrenlog.tistory.com/39</guid>
      <comments>https://darrenlog.tistory.com/39#entry39comment</comments>
      <pubDate>Sat, 31 Dec 2022 23:57:56 +0900</pubDate>
    </item>
    <item>
      <title>[OAuth 2.0] 개념과 Google OAuth2.0 세팅부터 스프링부트로 구현-1</title>
      <link>https://darrenlog.tistory.com/38</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 게시글에서는 OAuth 2.0에 대한 간략한 개념과&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링부트 환경에서 직접 구현해보는 단계까지 다뤄보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;OAuth, Open Authorization 정의&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;OAuth는 인터넷 사용자들이&amp;nbsp;&lt;u&gt;비밀번호를 제공하지 않고&lt;/u&gt;&amp;nbsp;다른 웹사이트 상의 자신들의 정보에 대해 웹사이트나 애플리케이션의 &lt;u&gt;접근 권한을 부여&lt;/u&gt;할 수 있는 공통적인 수단으로서 사용되는, 접근 위임을 위한 개방형 표준이다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유저가 특정 웹사이트(타 서비스)를 이용하려고 할 때, 자신의 회원정보를 기존에 이미 가입했던 구글, 네이버, 카카오 등에서 제공해주어 보다 안전하고 간편하게 회원가입 또는 로그인 처리를 돕는 프로토콜입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비밀번호와 같은 나의 민감한 정보를 &lt;u&gt;타 서비스에서 관리하도록 하는 것이 아니라&lt;/u&gt; 구글, 네이버, 카카오 등에 &lt;u&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;개인정보 관리 책임을 &lt;/span&gt;위임&lt;/u&gt;하여 보안 및 관리적인 측면에서 유리하다고 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-type=&quot;image&quot; data-ke-style=&quot;style1&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;Google OAuth 흐름도&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;364&quot; data-origin-height=&quot;377&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJMINs/btrTXNlLQoW/rjkRw5fDx1nkGGFOSsjaK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJMINs/btrTXNlLQoW/rjkRw5fDx1nkGGFOSsjaK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJMINs/btrTXNlLQoW/rjkRw5fDx1nkGGFOSsjaK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJMINs%2FbtrTXNlLQoW%2FrjkRw5fDx1nkGGFOSsjaK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;364&quot; height=&quot;377&quot; data-origin-width=&quot;364&quot; data-origin-height=&quot;377&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;사용자가&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Third-party 어플리케이션에서 &lt;/span&gt;구글로그인 진행 할 때 다음과 같은 플로우로 진행됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 구글 로그인 진행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 로그인 성공 시, Google 승인서버(Authorization Server)에서 &lt;u&gt;Authorization Code를 제공&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. &lt;span&gt;Google 승인서버(Authorization Server)에 &lt;/span&gt;&lt;u&gt;Authorization Code로 Access Token과 교환&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. Access Token으로 Google 자원서버(Resource Server)에 &lt;u&gt;유저자원(유저정보) 요청&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 유저자원(유저정보) 반환&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구글 OAuth를 사용하기 앞서 Google Cloud에 가입해주셔야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cloud.google.com/apis?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://cloud.google.com/apis?hl=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1671416146871&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Cloud APIs &amp;nbsp;|&amp;nbsp; Google Cloud&quot; data-og-description=&quot;REST API를 활용하여 코드에서 BigQuery, Compute Engine과 같은 Google Cloud 제품을 사용하세요.&quot; data-og-host=&quot;cloud.google.com&quot; data-og-source-url=&quot;https://cloud.google.com/apis?hl=ko&quot; data-og-url=&quot;https://cloud.google.com/apis?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/rIjbF/hyQWyxzm5L/a1C5KagH7O04mFTPPLbDVK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://cloud.google.com/apis?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cloud.google.com/apis?hl=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/rIjbF/hyQWyxzm5L/a1C5KagH7O04mFTPPLbDVK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Cloud APIs &amp;nbsp;|&amp;nbsp; Google Cloud&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;REST API를 활용하여 코드에서 BigQuery, Compute Engine과 같은 Google Cloud 제품을 사용하세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cloud.google.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rPute/btrTXLuIzzy/8LB3ecwx3zX0Jd3cTuyoR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rPute/btrTXLuIzzy/8LB3ecwx3zX0Jd3cTuyoR1/img.png&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;266&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;61.95&quot; style=&quot;width: 61.2301%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rPute/btrTXLuIzzy/8LB3ecwx3zX0Jd3cTuyoR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrPute%2FbtrTXLuIzzy%2F8LB3ecwx3zX0Jd3cTuyoR1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;861&quot; height=&quot;266&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N6Fsw/btrTYDiZiIq/kz6xDOJVp8Oq6ILnOjMmjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N6Fsw/btrTYDiZiIq/kz6xDOJVp8Oq6ILnOjMmjk/img.png&quot; data-origin-width=&quot;499&quot; data-origin-height=&quot;251&quot; data-is-animation=&quot;false&quot; style=&quot;width: 37.6071%;&quot; data-widthpercent=&quot;38.05&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N6Fsw/btrTYDiZiIq/kz6xDOJVp8Oq6ILnOjMmjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN6Fsw%2FbtrTYDiZiIq%2Fkz6xDOJVp8Oq6ILnOjMmjk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;499&quot; height=&quot;251&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 아직 생성한 프로젝트가 없으시면 위 처럼 새 프로젝트를 먼저 생성해주시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dH5MI5/btrTVTzT6jp/VmuRuks19KK4k3ctZlkiqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dH5MI5/btrTVTzT6jp/VmuRuks19KK4k3ctZlkiqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dH5MI5/btrTVTzT6jp/VmuRuks19KK4k3ctZlkiqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdH5MI5%2FbtrTVTzT6jp%2FVmuRuks19KK4k3ctZlkiqk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;542&quot; height=&quot;130&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;150&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. OAuth 동의 화면을 검색해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;602&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XiSMI/btrTXMOeMxe/eVvmNBYgV1DqZkq9IYciv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XiSMI/btrTXMOeMxe/eVvmNBYgV1DqZkq9IYciv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XiSMI/btrTXMOeMxe/eVvmNBYgV1DqZkq9IYciv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXiSMI%2FbtrTXMOeMxe%2FeVvmNBYgV1DqZkq9IYciv1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;450&quot; height=&quot;433&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;602&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 외부 선택 후 만들기를 눌러주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Bkl01/btrTZzHUUsI/asTx1Zxc939IGZd0SKKyB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Bkl01/btrTZzHUUsI/asTx1Zxc939IGZd0SKKyB1/img.png&quot; data-origin-width=&quot;568&quot; data-origin-height=&quot;443&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;44.07&quot; style=&quot;width: 43.5533%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Bkl01/btrTZzHUUsI/asTx1Zxc939IGZd0SKKyB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBkl01%2FbtrTZzHUUsI%2FasTx1Zxc939IGZd0SKKyB1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;568&quot; height=&quot;443&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnMDz8/btrTTp7ylzh/hK3PRtsZMOWbq50kGujMN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnMDz8/btrTTp7ylzh/hK3PRtsZMOWbq50kGujMN1/img.png&quot; data-origin-width=&quot;568&quot; data-origin-height=&quot;349&quot; data-is-animation=&quot;false&quot; style=&quot;width: 55.2839%;&quot; data-widthpercent=&quot;55.93&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnMDz8/btrTTp7ylzh/hK3PRtsZMOWbq50kGujMN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnMDz8%2FbtrTTp7ylzh%2FhK3PRtsZMOWbq50kGujMN1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;568&quot; height=&quot;349&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 필요한 내용을 작성 후 저장 후 계속 클릭해주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;562&quot; data-origin-height=&quot;245&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOGydu/btrT4dEiT4t/C9d4oxKBMCM6FpnXk0UUc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOGydu/btrT4dEiT4t/C9d4oxKBMCM6FpnXk0UUc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOGydu/btrT4dEiT4t/C9d4oxKBMCM6FpnXk0UUc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOGydu%2FbtrT4dEiT4t%2FC9d4oxKBMCM6FpnXk0UUc1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;404&quot; height=&quot;176&quot; data-origin-width=&quot;562&quot; data-origin-height=&quot;245&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;885&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xjp1w/btrTVT77Zo9/fzWAAuZjLuxOKXsYOEReP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xjp1w/btrTVT77Zo9/fzWAAuZjLuxOKXsYOEReP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xjp1w/btrTVT77Zo9/fzWAAuZjLuxOKXsYOEReP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fxjp1w%2FbtrTVT77Zo9%2FfzWAAuZjLuxOKXsYOEReP1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;620&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;885&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. Google 자원서버로 부터 제공받을 유저정보의 범위를 설정하여 업데이트 해주시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 프로필 정보와 이메일 정보를 받아올 예정이라 사진처럼 설정하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;557&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dwpEaf/btrTYCETxQw/ZJdP5vmeVBrNqJCBYkWbK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dwpEaf/btrTYCETxQw/ZJdP5vmeVBrNqJCBYkWbK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dwpEaf/btrTYCETxQw/ZJdP5vmeVBrNqJCBYkWbK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdwpEaf%2FbtrTYCETxQw%2FZJdP5vmeVBrNqJCBYkWbK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;454&quot; height=&quot;439&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;557&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. OAuth 테스트 상태 동안 접근을 허용해줄 이메일 계정을 등록해주시고 저장하시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;566&quot; data-origin-height=&quot;949&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l89kC/btrTZzBm5ua/OW8AgURkpbmh1hD6kq9JJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l89kC/btrTZzBm5ua/OW8AgURkpbmh1hD6kq9JJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l89kC/btrTZzBm5ua/OW8AgURkpbmh1hD6kq9JJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl89kC%2FbtrTZzBm5ua%2FOW8AgURkpbmh1hD6kq9JJ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;321&quot; height=&quot;538&quot; data-origin-width=&quot;566&quot; data-origin-height=&quot;949&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. OAuth 동의 화면은 이걸로 마쳤습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;514&quot; data-origin-height=&quot;123&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vOFR9/btrTRFCHPXd/31vTk107ej5rVKcamwuIbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vOFR9/btrTRFCHPXd/31vTk107ej5rVKcamwuIbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vOFR9/btrTRFCHPXd/31vTk107ej5rVKcamwuIbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvOFR9%2FbtrTRFCHPXd%2F31vTk107ej5rVKcamwuIbK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;514&quot; height=&quot;123&quot; data-origin-width=&quot;514&quot; data-origin-height=&quot;123&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;398&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNMu12/btrT4Hd3nNC/ljVUfQwk647SB146SlNQLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNMu12/btrT4Hd3nNC/ljVUfQwk647SB146SlNQLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNMu12/btrT4Hd3nNC/ljVUfQwk647SB146SlNQLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNMu12%2FbtrT4Hd3nNC%2FljVUfQwk647SB146SlNQLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;424&quot; height=&quot;398&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;398&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;9. 사용자 인증 정보를 검색하여 사용자 인증 정보를 만들어 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;709&quot; data-origin-height=&quot;942&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6OgOl/btrWc3tfVh1/4UvXaloAlIGbiHrZ6oPeYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6OgOl/btrWc3tfVh1/4UvXaloAlIGbiHrZ6oPeYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6OgOl/btrWc3tfVh1/4UvXaloAlIGbiHrZ6oPeYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6OgOl%2FbtrWc3tfVh1%2F4UvXaloAlIGbiHrZ6oPeYK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;468&quot; height=&quot;622&quot; data-origin-width=&quot;709&quot; data-origin-height=&quot;942&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;10. 승인된 리디렉션 URI에는 authorization code를 받을&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨트롤러의 Mapping URI를 입력해주시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만들기 버튼을 눌러주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;510&quot; data-origin-height=&quot;448&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nkdb0/btrTSMaQTSJ/ZkHSSkhFh2S27tzBJkkJqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nkdb0/btrTSMaQTSJ/ZkHSSkhFh2S27tzBJkkJqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nkdb0/btrTSMaQTSJ/ZkHSSkhFh2S27tzBJkkJqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnkdb0%2FbtrTSMaQTSJ%2FZkHSSkhFh2S27tzBJkkJqk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;510&quot; height=&quot;448&quot; data-origin-width=&quot;510&quot; data-origin-height=&quot;448&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 처럼 Client ID와 Client Secret Key를 발급 받으셨으면 OAuth를 사용하기 위한 기본 준비는 끝났습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 간단한 테스트를 해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;a href=&quot;https://accounts.google.com/o/oauth2/auth?client_id=CLIENT_ID&amp;amp;redirect_uri=REDIRECT_URI&amp;amp;response_type=code&amp;amp;scope=https://www.googleapis.com/auth/userinfo.email%20https://www.googleapis.com/auth/userinfo.profile&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://accounts.google.com/o/oauth2/auth?client_id=&lt;span style=&quot;color: #ee2323;&quot;&gt;CLIENT_ID&lt;/span&gt;&amp;amp;redirect_uri=&lt;span style=&quot;color: #ee2323;&quot;&gt;REDIRECT_URI&lt;/span&gt;&amp;amp;response_type=code&amp;amp;scope=https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile&lt;/a&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 링크를 본인이 발급받은 클라이언트ID와 리디렉션URI로 변경하여 접속해보세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;467&quot; data-origin-height=&quot;517&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRA62K/btrV6dDOzY4/a7HikEeTAAw1KWTgkBAcc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRA62K/btrV6dDOzY4/a7HikEeTAAw1KWTgkBAcc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRA62K/btrV6dDOzY4/a7HikEeTAAw1KWTgkBAcc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRA62K%2FbtrV6dDOzY4%2Fa7HikEeTAAw1KWTgkBAcc1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;338&quot; height=&quot;517&quot; data-origin-width=&quot;467&quot; data-origin-height=&quot;517&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 사진과 같은 화면이 나온다면 이제 모든 준비는 완료되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 코드로 구현하는 부분은 다음 포스팅에서 다뤄보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring</category>
      <category>JWT</category>
      <category>oauth</category>
      <category>OAuth2.0</category>
      <category>구글</category>
      <category>구글oauth</category>
      <category>소셜로그인</category>
      <category>소셜로그인기능</category>
      <category>카카오oauth</category>
      <author>Darren Gwon</author>
      <guid isPermaLink="true">https://darrenlog.tistory.com/38</guid>
      <comments>https://darrenlog.tistory.com/38#entry38comment</comments>
      <pubDate>Tue, 27 Dec 2022 11:32:45 +0900</pubDate>
    </item>
  </channel>
</rss>