<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>eunoia</title>
    <link>https://eunoia07.tistory.com/</link>
    <description>output of develop</description>
    <language>ko</language>
    <pubDate>Thu, 9 Apr 2026 05:44:04 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>eunoia07</managingEditor>
    <image>
      <title>eunoia</title>
      <url>https://tistory1.daumcdn.net/tistory/4350109/attach/e8f31580c5bf458db4b2fa6644177e92</url>
      <link>https://eunoia07.tistory.com</link>
    </image>
    <item>
      <title>[ALGORITHM] 동적 계획법 (Dynamic Programming)</title>
      <link>https://eunoia07.tistory.com/entry/ALGORITHM-%EB%8F%99%EC%A0%81-%EA%B3%84%ED%9A%8D%EB%B2%95-Dynamic-Programming</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1269&quot; data-origin-height=&quot;832&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nq5BB/btr3J2VZD3t/7ha5rfU3kqOHBDtnH8VYak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nq5BB/btr3J2VZD3t/7ha5rfU3kqOHBDtnH8VYak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nq5BB/btr3J2VZD3t/7ha5rfU3kqOHBDtnH8VYak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnq5BB%2Fbtr3J2VZD3t%2F7ha5rfU3kqOHBDtnH8VYak%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;409&quot; height=&quot;268&quot; data-origin-width=&quot;1269&quot; data-origin-height=&quot;832&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;개념&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동적 프로그래밍(DP)은 복잡한 문제를 단순한 하위 문제로 나누어 푸는 방법으로 같은 입력값에 대한 반복되는 호출을 하는 솔루션을 만났을 때 사용합니다.&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;  다이나믹 프로그래밍은 하나의 문제를 단 한 번만 풀도록 하는 알고리즘으로 구체적인 알고리즘이라긴 보단, 문제 해결 패러다임에 가깝습니다.&lt;/blockquote&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;b&gt;[   탐욕 알고리즘과 다른점 ]&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘 다 최적의 값을 찾는다는 점에서 비슷하지만, 다른 방법으로 찾습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 40px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 15.4651%; height: 20px;&quot;&gt;탐욕 알고리즘&lt;/td&gt;
&lt;td style=&quot;width: 84.5349%; height: 20px;&quot;&gt;전체의 값을 찾기 위해 지역적으로 탐욕적인 선택을 찾음&lt;br /&gt;&amp;rarr; 비용이 많이 들며, 전역적으로는 최적의 알고리즘을 보장하지 않을 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 15.4651%; height: 20px;&quot;&gt;동적 프로그래밍&lt;/td&gt;
&lt;td style=&quot;width: 84.5349%; height: 20px;&quot;&gt;전체의 값을 찾기 위해 하위 문제에 대한 최적의 값을 찾은 다음 결과를 결합함&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;알고리즘 과정&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[ 동적 프로그래밍의 선행 조건 2가지]&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 겹치는 부분 문제 (Overlapping Subproblem) 찾기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, 복잡한 문제를 하위 문제로 나누어 풀기 위해선, &lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;같은 부분 문제가 여러번 재사용되거나 재귀 알고리즘을 통해 해결되는 문제를 찾아야 합니다.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529;&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-filename=&quot;Untitled.png&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;534&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wItyD/btrGup5sa5u/egTmJNiDtKDpRPfJ1mCMQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wItyD/btrGup5sa5u/egTmJNiDtKDpRPfJ1mCMQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wItyD/btrGup5sa5u/egTmJNiDtKDpRPfJ1mCMQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwItyD%2FbtrGup5sa5u%2FegTmJNiDtKDpRPfJ1mCMQK%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;487&quot; height=&quot;311&quot; data-filename=&quot;Untitled.png&quot; data-origin-width=&quot;836&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;피보나치 수를 예를 들면 fib(4)를 다음 하위 문제로 나누었을 때, fib(2)와 fib(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;2. 최적의 하위 구조 (Optimal Substructure) 찾기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;겹치는 부분 문제를 찾았다면, 이제 최적의 하위 구조 속성을 찾아 수식을 정리합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  최적의 하위 구조란 문제의 최적의 해결책이 해당 문제의 하위 문제의 해결책으로부터 설계될 수 있는 경우로, 문제의 정답을 작은 문제의 정답에서부터 구할 수 있음을 나타냅니다.&lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;Fib(n) = Fib(n-1) + Fib(n-2)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 'n' 크기의 문제가 'n-1' 및 'n-2' 크기의 하위 문제로 축소되었음을 분명히 보여줍니다.&amp;nbsp;따라서 피보나치 수는 최적의 하위 구조 속성을 갖습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[ 알고리즘 동작 과정 ]&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  동적 프로그래밍은 문제를 해결하는 두 가지 방법이 있습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 메모리제이션을 이용한 하향식 (Top-down)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큰 문제를 작은 문제로 쪼개면서 푸는 기법으로 &lt;u&gt;재귀&lt;/u&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;pre id=&quot;code_1656922990066&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public int Recursive(int[] memoize, int n) {
	if(n &amp;lt; 2)
		return n;

	if(memoize[n] != 0)
		return memoize[n];
	
	memoize[n] = Recursive(memoize, n-1) + Recursive(memoize, n-2);
	return memoize[n];
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드를 보면, memoize[n]에 작은 문제의 결과를 메모리제이션 한 후, 문제의 결과를 구합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  메모리제이션이란 이미 해결된 문제의 결과를 캐싱(저장)해 같은 문제가 여러번 해결되지 않도록 결과를 저장하는 기술입니다. 최상위 문제를 먼저 해결한다는 의미에서 하향식으로 수행합니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 표를 이용한 상향식(Bottom-up)&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;- 반복해 배열의 &lt;span style=&quot;background-color: #ffffff; color: #3d3d4e;&quot;&gt;결과를 기반으로 원래 문제의 결과를 구합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656922314679&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int dp[] = new int[n+1];

dp[0] = 0;
dp[1] = 1;

for(int i=2; i&amp;lt;=n; i++){
  dp[i] = dp[i-1] + dp[i-2];
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;위의 코드를 보면, dp[9]를 구하기 위해 &lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;dp&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;[0], &lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;dp&lt;/span&gt;[1], &lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;dp&lt;/span&gt;[2] ... &lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;dp&lt;/span&gt;[9]의 순서대로 값을 구한 후, 해당 값을 가지고 다음 값을 구합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;구현 with JAVA&lt;/span&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 메모리제이션을 이용한 하향식 (Top-down)&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;class Fibonacci {

  public int Calc(int n) {
    int memoize[] = new int[n+1];
    //문제를 작은 문제로 나눕니다.
    return Recursive(memoize, n);
  }

  public int Recursive(int[] memoize, int n) {
    if(n &amp;lt; 2)
      return n;

    if(memoize[n] != 0)
      return memoize[n];
	
    //작은 문제를 풀고 결과를 메모리제이션합니다.
    memoize[n] = Recursive(memoize, n-1) + Recursive(memoize, n-2);
    return memoize[n];
  }

  public static void main(String[] args) {
    Fibonacci fib = new Fibonacci();
    fib.Calc(5);
    fib.Calc(6);
    fib.Calc(7);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 표를 이용한 상향식(Bottom-up)&lt;/p&gt;
&lt;pre id=&quot;code_1656919477406&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Fibonacci {

  public int Calc(int n) {
    if (n==0) return 0;
    int dp[] = new int[n+1];

    dp[0] = 0;
    dp[1] = 1;

	//문제의 크기를 크게 만들면서 순서대로 값을 구합니다.
    for(int i=2; i&amp;lt;=n; i++)
      dp[i] = dp[i-1] + dp[i-2];

	//반복해 배열의 결과를 기반으로 원래 문제의 결과를 구합니다.
    return dp[n];
  }

  public static void main(String[] args) {
    Fibonacci fib = new Fibonacci();
    fib.Calc(5);
    fib.Calc(6);
    fib.Calc(7);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;참고자료&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;nbsp;&lt;a href=&quot;https://www.programiz.com/dsa/dynamic-programming&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.programiz.com/dsa/dynamic-programming&lt;/a&gt; &lt;br /&gt;-&amp;nbsp;&lt;a href=&quot;https://en.wikipedia.org/wiki/Dynamic_programming&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://en.wikipedia.org/wiki/Dynamic_programming&lt;/a&gt; &lt;br /&gt;-&amp;nbsp;&lt;a href=&quot;https://www.educative.io/courses/grokking-dynamic-programming-patterns-for-coding-interviews/m2G1pAq0OO0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.educative.io/courses/grokking-dynamic-programming-patterns-for-coding-interviews/m2G1pAq0OO0&lt;/a&gt; &lt;br /&gt;-&amp;nbsp;&lt;a href=&quot;https://blog.naver.com/ndb796/221233570962&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://blog.naver.com/ndb796/221233570962&lt;/a&gt; &lt;br /&gt;-&amp;nbsp;&lt;a href=&quot;https://velog.io/@polynomeer/동적-계획법Dynamic-Programming&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://velog.io/@polynomeer/동적-계획법Dynamic-Programming&lt;/a&gt; &lt;br /&gt;-&amp;nbsp;&lt;a href=&quot;https://velog.io/@nninnnin7/Dynamic-programming-1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://velog.io/@nninnnin7/Dynamic-programming-1&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algrithm</category>
      <author>eunoia07</author>
      <guid isPermaLink="true">https://eunoia07.tistory.com/30</guid>
      <comments>https://eunoia07.tistory.com/entry/ALGORITHM-%EB%8F%99%EC%A0%81-%EA%B3%84%ED%9A%8D%EB%B2%95-Dynamic-Programming#entry30comment</comments>
      <pubDate>Mon, 4 Jul 2022 17:26:14 +0900</pubDate>
    </item>
    <item>
      <title>[SPRING BOOT] @Controller,  @RestController 차이</title>
      <link>https://eunoia07.tistory.com/entry/SPRING-Controller-RestController-%EC%B0%A8%EC%9D%B4</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1269&quot; data-origin-height=&quot;831&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SNe5U/btr3WbDrXjS/yVLIz311XuN6b2sFJ1Uwqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SNe5U/btr3WbDrXjS/yVLIz311XuN6b2sFJ1Uwqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SNe5U/btr3WbDrXjS/yVLIz311XuN6b2sFJ1Uwqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSNe5U%2Fbtr3WbDrXjS%2FyVLIz311XuN6b2sFJ1Uwqk%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;417&quot; height=&quot;273&quot; data-origin-width=&quot;1269&quot; data-origin-height=&quot;831&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 소스코드는 &lt;a title=&quot;여기서&quot; href=&quot;https://github.com/HongEunbeen/spring-code/tree/main/spring-controller&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;여기서&lt;/a&gt; 확인하실 수 있습니다  &lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;사전정보 - 어노테이션과 RESTful API&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[ Spring Annotation ]&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring 어노테이션은 프로그램에 대한 추가 정보를 제공하는데 사용합니다. 프로그램에 직접적인 영향은 미치지 않고 프로그램에 대한 데이터를 제공하는 메타데이터의 한 형태입니다.&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;Spring Framework는 아래와 같이 다양한 어노테이션을 제공하고 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Required&lt;/li&gt;
&lt;li&gt;@Autowired&lt;/li&gt;
&lt;li&gt;@Bean&lt;/li&gt;
&lt;li&gt;@Component&lt;/li&gt;
&lt;li&gt;&lt;b&gt;@Controller&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;@Service&lt;/li&gt;
&lt;li&gt;@Repository&lt;/li&gt;
&lt;li&gt;etc ...&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[ Spring REST API 워크플로 ]&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring에서 REST API를 처리하는 방법은 아래와 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;520&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdqyZB/btrF6aJht6r/ahH9vn1v7gu6S3PopVrbfk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdqyZB/btrF6aJht6r/ahH9vn1v7gu6S3PopVrbfk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdqyZB/btrF6aJht6r/ahH9vn1v7gu6S3PopVrbfk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdqyZB%2FbtrF6aJht6r%2FahH9vn1v7gu6S3PopVrbfk%2Fimg.jpg&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;475&quot; height=&quot;353&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;520&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. DispatcherServlets는 요청을 받음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. URI 요청을 처리하기 위해 핸들러에 매핑된 &lt;span&gt;Controller 메서드 &lt;/span&gt;실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Controller 메서드가 실행 된 후 반환된 리소스는 응답으로 처리&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;@Controller 어노테이션&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Controller 어노테이션은 @Component 어노테이션에서 발전한 것으로 특정 클래스가 컨트롤러 역할을 수행함을 표현할 때 사용합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1656578766524&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Controller
@ResponseBody
@RequestMapping(&quot;/api/hello&quot;)
public class TreeController {

    @Autowired
    private TreeRepository repository;
 
    @GetMapping(&quot;/{id}&quot;)
    public Tree getTreeById(@PathVariable int id) {
        return repository.findById(id);
    }
  
    @GetMapping
    public Tree getTreeById(@RequestParam String name, 
                            @RequestParam int age) {
        return repository.findFirstByCommonNameIgnoreCaseAndAge(name, age);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 DispatcherServlet는 요청이 들어오면 매핑된 메서드에 대해 Controller가 붙어있는 클래스를 검색할 수 있습니다. 클래스를 검색 한 후 RequestMapping 어노테이션을 통해&amp;nbsp;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;요청에 대해 어떤 Controller, 어떤 메소드가 처리할지를 맵핑합니다.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;@RestController 어노테이션&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@RestController는 RESTful 웹 서비스 생성을 단순화하기 위한 @Controller의 특수 버전으로@Controller&lt;span&gt;&amp;nbsp;&lt;/span&gt;+&lt;span&gt;&amp;nbsp;&lt;/span&gt;@ResponseBody으로 구성되어 결과적으로 컨트롤러 구현을 단순화합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  @ResponseBody 어노테이션은 해당 메서드의 반환된 값이 자동으로 JSON으로 직렬화되고 HttpRespnse 객체로 전달되었음을 Controller에게 알려주는 역할을 합니다.&amp;nbsp;&lt;/blockquote&gt;
&lt;pre id=&quot;code_1656579027986&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
  //..
}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
  //..
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드를 비교해 보면 RestController에 @ResponseBody 어노테이션이 미리 선언되어 있는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1656579374687&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@RestController
@RequestMapping(&quot;/api/hello&quot;)
public class TreeRestController {

    @Autowired
    private TreeRepository repository;
 
    @GetMapping(&quot;/{id}&quot;)
    public Tree getTreeById(@PathVariable int id) {
        return repository.findById(id);
    }
  
    @GetMapping
    public Tree getTreeById(@RequestParam String name, 
                            @RequestParam int age) {
        return repository.findFirstByCommonNameIgnoreCaseAndAge(name, age);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;맺으며 &amp;bull;&amp;bull;&amp;bull;  &lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 @Controller 어노테이션과 @RestController 어노테이션에 대해 알아봤습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;틀린문장이나 수정해야 할 부분은 댓글로 남겨주시면 감사하겠습니다 &lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[ 참고 ]&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;nbsp;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Controller.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Controller.html&lt;/a&gt;&amp;nbsp; &lt;br /&gt;-&amp;nbsp;&lt;a href=&quot;https://www.baeldung.com/spring-request-response-body&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.baeldung.com/spring-request-response-body&lt;/a&gt; &lt;br /&gt;-&amp;nbsp;&lt;a href=&quot;https://www.baeldung.com/spring-controller-vs-restcontroller&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.baeldung.com/spring-controller-vs-restcontroller&lt;/a&gt; &lt;br /&gt;-&amp;nbsp;&lt;a href=&quot;https://stackabuse.com/controller-and-restcontroller-annotations-in-spring-boot/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackabuse.com/controller-and-restcontroller-annotations-in-spring-boot/&lt;/a&gt;&lt;/p&gt;</description>
      <category>SERVER/SpringBoot</category>
      <author>eunoia07</author>
      <guid isPermaLink="true">https://eunoia07.tistory.com/29</guid>
      <comments>https://eunoia07.tistory.com/entry/SPRING-Controller-RestController-%EC%B0%A8%EC%9D%B4#entry29comment</comments>
      <pubDate>Thu, 30 Jun 2022 18:45:53 +0900</pubDate>
    </item>
    <item>
      <title>[ALGORITHM] 플로이드-워셜 (Floyd-Warshall)</title>
      <link>https://eunoia07.tistory.com/entry/ALGORITHM-%ED%94%8C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%9B%8C%EC%85%9C-Floyd-Warshall</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1269&quot; data-origin-height=&quot;831&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sWlXP/btr3SYx6uuP/QZC7VXrEE51oaYccMlKz80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sWlXP/btr3SYx6uuP/QZC7VXrEE51oaYccMlKz80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sWlXP/btr3SYx6uuP/QZC7VXrEE51oaYccMlKz80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsWlXP%2Fbtr3SYx6uuP%2FQZC7VXrEE51oaYccMlKz80%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;412&quot; height=&quot;270&quot; data-origin-width=&quot;1269&quot; data-origin-height=&quot;831&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;개념&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;플로이드-워셜 알고리즘은 가중치 그래프에서 모든 최단 경로를 구하는 알고리즘입니다. 한 번 실행하여 모든 노드 간 최단 경로를 구하는데 이때, 최단 경로를 찾기 위해 DP(동적 프로그래밍) 방식을 사용합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;[  &lt;/span&gt; 다익스트라와의 차이점? ]&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다익스트라 : 하나의 정점에서 다른 모든 정점까지의 최단 거리&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시작점으로 부터 나머지 정점까지 최단거리 구할 때 사용&lt;/li&gt;
&lt;li&gt;음의 가중치 간선이 있으면 사용하지 못 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로이드-워셜 : 한 번 실행해 모든 노드 간 최단 경로&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 정점간 최단 경로 구할 때 사용&lt;/li&gt;
&lt;li&gt;음의 가중치 간선에서 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✔ 시작점으로부터 각 정점까지 최단 거리만 구할 때 &amp;rarr; &lt;u&gt;다익스트라&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✔ 간결한 소스코드, 간선 수가 많을 떄 &amp;rarr; &lt;u&gt;플로이드-워셜&lt;/u&gt;&lt;u&gt;&lt;/u&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;[ 알고리즘 응용 ]&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최단 경로 찾는 방향 그래프&lt;/li&gt;
&lt;li&gt;실수 행렬의 반전 찾기&lt;/li&gt;
&lt;li&gt;무방향 그래프 이분법인지의 여부 테스트&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;알고리즘 과정&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;목표 : 모든 정점 사이의 최단 경로 구하기&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[ 1. 입력받은 그래프와 동일한 2차원 인접 행렬로 선언해 초기화 ]&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;534&quot; data-origin-height=&quot;341&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhGOct/btrF9gIgnFG/hAryZ5lDj6BsLpkNhuPOZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhGOct/btrF9gIgnFG/hAryZ5lDj6BsLpkNhuPOZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhGOct/btrF9gIgnFG/hAryZ5lDj6BsLpkNhuPOZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhGOct%2FbtrF9gIgnFG%2FhAryZ5lDj6BsLpkNhuPOZk%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;410&quot; height=&quot;341&quot; data-origin-width=&quot;534&quot; data-origin-height=&quot;341&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 그래프를 &lt;span&gt;5X5&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;2차원 인접 행렬로 변경해 i 정점에서 j 정점까지의 간선의 가중치를 입력합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;571&quot; data-origin-height=&quot;399&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baNkpn/btrF76zp2Bp/u08W88Risxso8zSfaGusl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baNkpn/btrF76zp2Bp/u08W88Risxso8zSfaGusl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baNkpn/btrF76zp2Bp/u08W88Risxso8zSfaGusl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaNkpn%2FbtrF76zp2Bp%2Fu08W88Risxso8zSfaGusl1%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;383&quot; height=&quot;268&quot; data-origin-width=&quot;571&quot; data-origin-height=&quot;399&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  INF = 해당 정점에서 특정 정점까지 길이 없음을 나타냅니다.&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[ 2. INF의 값을 채울 수 있도록 중간 정점 선택 ]&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제, INF의 값을 채울 수 있도록 정점들을 연결해 줘야 합니다. 간선으로 연결되어 있지 않은 정점들은 중간정점을 통해 정점 간의 가중치를 구할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;385&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvj509/btrGaqQXeAL/MB9Xn40oTzexdWbrmaiU6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvj509/btrGaqQXeAL/MB9Xn40oTzexdWbrmaiU6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvj509/btrGaqQXeAL/MB9Xn40oTzexdWbrmaiU6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbvj509%2FbtrGaqQXeAL%2FMB9Xn40oTzexdWbrmaiU6k%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;337&quot; height=&quot;210&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;385&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 그래프는 1정점과 3정점이 연결되어 있지 않기 때문에 중간 정점(2정점, 4정점)을 선택해 1 &amp;rarr; 중간정점 &amp;rarr; 3 이렇게 연결합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;471&quot; data-origin-height=&quot;377&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mK76l/btrF5aXbkPS/2KaEiWBDkoobauNksfVSo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mK76l/btrF5aXbkPS/2KaEiWBDkoobauNksfVSo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mK76l/btrF5aXbkPS/2KaEiWBDkoobauNksfVSo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmK76l%2FbtrF5aXbkPS%2F2KaEiWBDkoobauNksfVSo0%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;334&quot; height=&quot;267&quot; data-origin-width=&quot;471&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;모든 정점들은 중간 정점으로 사용할 수 있기 때문에 총 5번(정점의 개수)의 계산이 수행되어야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;-&amp;nbsp;&amp;nbsp;1 &amp;rarr; 중간정점(2) &amp;rarr; 3&amp;nbsp; = 4&lt;br /&gt;-&amp;nbsp;&amp;nbsp;1 &amp;rarr; 중간정점(4) &amp;rarr; 3&amp;nbsp; = 6&lt;br /&gt;2정점을 중간정점으로 거치는 가중치의 값이 이 더 작으므로 가중치 4가 행렬에 들어감&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, 위와 같이 중간정점이 여러개 일 경우에는 최단 거리를 구하는 알고리즘이기 때문에 행렬에 있는 값보다 계산된 값이 더 작으면 계산된 값으로 변경해줍니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[ 3. 모든 INF 값을 채우고 난 후 최단 거리&lt;/b&gt; ]&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;433&quot; data-origin-height=&quot;332&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dBXDaz/btrGaqQYpID/ZYkK77h4T3UofyppTnll91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dBXDaz/btrGaqQYpID/ZYkK77h4T3UofyppTnll91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dBXDaz/btrGaqQYpID/ZYkK77h4T3UofyppTnll91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdBXDaz%2FbtrGaqQYpID%2FZYkK77h4T3UofyppTnll91%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;295&quot; height=&quot;226&quot; data-origin-width=&quot;433&quot; data-origin-height=&quot;332&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: #ffffff; color: #212529;&quot;&gt;5정점까지 중간정점으로 선정 후 계산을 마치면 행렬에는 모든 정점 간 최단 거리가 들어가게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;시간 복잡도 및 빅오 표기&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;O(n&amp;sup3;)&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;구현 with JAVA&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;pre id=&quot;code_1656567643489&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.*;
import java.lang.*;
import java.io.*;
 
class AllPairShortestPath
{
    final static int INF = 99999, V = 4;
 
    void floydWarshall(int graph[][])
    {
        int dist[][] = new int[V][V];
        int i, j, k;

        for (i = 0; i &amp;lt; V; i++)
            for (j = 0; j &amp;lt; V; j++)
                dist[i][j] = graph[i][j];

        for (k = 0; k &amp;lt; V; k++)
        {
            for (i = 0; i &amp;lt; V; i++)
            {
                for (j = 0; j &amp;lt; V; j++)
                {
                    if (dist[i][k] + dist[k][j] &amp;lt; dist[i][j])
                        dist[i][j] = dist[i][k] + dist[k][j];
                }
            }
        }
    }
 
    public static void main (String[] args)
    {
        int graph[][] = { {0,   5,  INF, 10},
                          {INF, 0,   3, INF},
                          {INF, INF, 0,   1},
                          {INF, INF, INF, 0}
                        };

        AllPairShortestPath a = new AllPairShortestPath();
 
        a.floydWarshall(graph);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;출처&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.programiz.com/dsa/floyd-warshall-algorithm&quot;&gt;https://www.programiz.com/dsa/floyd-warshall-algorithm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.geeksforgeeks.org/floyd-warshall-algorithm-dp-16/&quot;&gt;https://www.geeksforgeeks.org/floyd-warshall-algorithm-dp-16/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://codedoc.tistory.com/95&quot;&gt;https://codedoc.tistory.com/95&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Algrithm</category>
      <author>eunoia07</author>
      <guid isPermaLink="true">https://eunoia07.tistory.com/28</guid>
      <comments>https://eunoia07.tistory.com/entry/ALGORITHM-%ED%94%8C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%9B%8C%EC%85%9C-Floyd-Warshall#entry28comment</comments>
      <pubDate>Thu, 30 Jun 2022 15:53:53 +0900</pubDate>
    </item>
    <item>
      <title>[REACT] react-hook-form 사용하기 - 구현(2)</title>
      <link>https://eunoia07.tistory.com/entry/REACT-react-hook-form-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-%EA%B5%AC%ED%98%84</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1269&quot; data-origin-height=&quot;832&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s0EVG/btr3S0QjuSp/6goJic10dc2IKOEJlKTRs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s0EVG/btr3S0QjuSp/6goJic10dc2IKOEJlKTRs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s0EVG/btr3S0QjuSp/6goJic10dc2IKOEJlKTRs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs0EVG%2Fbtr3S0QjuSp%2F6goJic10dc2IKOEJlKTRs0%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;418&quot; height=&quot;274&quot; data-origin-width=&quot;1269&quot; data-origin-height=&quot;832&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1편(개념편)에서 이어지는 내용입니다. &lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;339&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1R35d/btrFySukMi0/eYYVnfJYQZTxz5s76VPKHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1R35d/btrFySukMi0/eYYVnfJYQZTxz5s76VPKHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1R35d/btrFySukMi0/eYYVnfJYQZTxz5s76VPKHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1R35d%2FbtrFySukMi0%2FeYYVnfJYQZTxz5s76VPKHk%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;403&quot; height=&quot;237&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;339&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;react-hook-form을 사용해 입력과 동시에 유효성 검증을 구현해보겠습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;1. react-hook-form의 기본 설정값&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1편에서 설명했듯이 react-hook-form은 submit 함수가 호출 될 때, 즉 사용자가 어떤 행위를 해야 유효성 검증을 진행합니다. 이 부분을 해결하기 위해 입력 필드에 validate 옵션을 통해 함수로 유효성 검사하는 부분을 분리하겠습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;2. 구현&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[a.기능 설명]&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 입력 필드의 상태를 세 가지의 타입으로 나눴습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;139&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Yrr2Q/btrFzxwUUwI/xHQrVPmWrfyWFR4FR32Qt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Yrr2Q/btrFzxwUUwI/xHQrVPmWrfyWFR4FR32Qt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Yrr2Q/btrFzxwUUwI/xHQrVPmWrfyWFR4FR32Qt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYrr2Q%2FbtrFzxwUUwI%2FxHQrVPmWrfyWFR4FR32Qt1%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;910&quot; height=&quot;139&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;139&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- default : 기본 상태&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- error : 유효성 검사 실패 상태&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- complete : 유효성 검사 성공 후 입력 완료 상태&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[b.유효성 검사 구현]&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const Form = () =&amp;gt; { 
    const { register, handleSubmit, formState: { errors } } = useForm();

    const validateNickname = (value) =&amp;gt; {
      if (value.length &amp;lt;= 2) {
        return '2글자 이상 입력해주세요.';
      }
      return true;
    };

    return (
        &amp;lt;form onSubmit={handleSubmit(handleRegistration)}&amp;gt;
            &amp;lt;input
              type=&quot;text&quot;
              name=&quot;nickname&quot;
              ref={register('nickname', {
                validate: validateNickname
              })}
            /&amp;gt;
            {errors?.nickname &amp;amp;&amp;amp; errors.nickname.message}
         &amp;lt;button&amp;gt;Submit&amp;lt;/button&amp;gt;
        &amp;lt;/form&amp;gt;
    )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;react-hook-form에서 제공하는 validate 옵션을 이용해 입력 필드의 값을 받아 유효성을 검증하는 함수를 등록합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;errors?.nickname를 통해서 react-hook-form에 등록된 nickname이 errors에 있으면 message를 출력합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[c. 구현]&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 validate에 등록한 함수에서 반환한 값을 가지고 입력 필드의 스타일을 변경해줍니다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;import styled from &quot;@emotion/styled&quot;;
import { useForm } from &quot;react-hook-form&quot;;

const Form = () =&amp;gt; { 
    const { register, handleSubmit, formState: { errors } } = useForm();

    const validateNickname = (value) =&amp;gt; {
      if (value.length &amp;lt;= 2) {
        return '2글자 이상 입력해주세요.';
      }
      return true;
    };

    return (
        &amp;lt;form onSubmit={handleSubmit(handleRegistration)}&amp;gt;
            &amp;lt;Wrapper error={errors?.nickname &amp;amp;&amp;amp; true} &amp;gt;
                &amp;lt;Input
                  type=&quot;text&quot;
                  name=&quot;nickname&quot;
                  ref={register('nickname', {
                    validate: validateNickname
                  })}
                /&amp;gt;
            {errors?.nickname &amp;amp;&amp;amp; errors.nickname.message}
            &amp;lt;/Wrapper&amp;gt;

         &amp;lt;button&amp;gt;Submit&amp;lt;/button&amp;gt;
        &amp;lt;/form&amp;gt;
    )
}

const Wrapper = styled.div&amp;lt;{error?:boolean}&amp;gt;`
  display: flex;
  border-bottom: ${props =&amp;gt; props.error ? `1px solid red` : `1px solid black` };
  color : ${props =&amp;gt; props.error ? `red` : `black` };
`;

const Input = styled.input`
  height: 40px;
  border: none;
  outline: none;
`;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게, 사용자가 입력과 동시에 유효성을 확인하는 기능을 react-hook-form을 통해 구현했습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;3. 리팩토링&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  한 개의 입력 필드에 한 개의 함수가 생성되는 코드가 반복되고 있어, 입력 필드를 컴포넌트로 분리시켜 재사용 할 수 있도록 리팩토링을 진행했습니다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;- Input.tsx
- Form.tsx&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Form과 Input으로 컴포넌트를 분리하고 Form에 Input을 등록시키는 방식으로 개발합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[a. 구조 변경 - Form.tsx]&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Form과 Input으로 컴포넌트를 분리하고 Form에 Input을 등록시키는 방식으로 개발합니다.&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;/*Form.tsx*/
import { useForm, useWatch, FormProvider, FieldValues } from &quot;react-hook-form&quot;;

interface IFormInputs extends FieldValues {
  nickname:string;
}

const Form = () =&amp;gt; {
 const methods = useForm&amp;lt;IFormInputs&amp;gt;({
    defaultValues:{
      nickname : &quot;&quot;
    },
    mode:&quot;onChange&quot;
  });

  const {
    handleSubmit
  } = methods;

  return(
   &amp;lt;FormProvider {...methods} &amp;gt;
        &amp;lt;form onSubmit={handleSubmit(onSubmit)}&amp;gt;
       &amp;lt;Label&amp;gt;E-mail&amp;lt;/Label&amp;gt;
            &amp;lt;Input
              name=&quot;nickname&quot;
              rules={{
                required:true,
                minLength:{
                  value:2,
                  message:'2글자 이상 입력해주세요.'
                },
              }}
              type=&quot;text&quot;
              placeholder=&quot;닉네임을 입력해주세요.&quot;
              /&amp;gt;
          &amp;lt;/form&amp;gt;
      &amp;lt;/FormProvider&amp;gt;
    )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;code&gt;useForm({mode : &quot;onChange&quot;})&lt;/code&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;mode 옵션은 onSubmit 이벤트가 발생하기 전 유효성 검사를 언제 할건지를 결정할 수 있습니다. onChange로 설정해 입력 필드가 변경될 때 유효성 검사가 실행되도록 설정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FormProvider&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;react-hook-form에서 제공하는 FormProvider를 사용하면 각 input에 수동으로 props를 전달할 필요 없이 Input이 Form에 등록됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[b. 구조 변경 - Input.tsx]&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;/* Input.tsx */
import { useFormContext, useController, FieldPath, FieldValues, UseControllerProps } from &quot;react-hook-form&quot;;

interface InputProps&amp;lt;
    TFieldValues extends FieldValues = FieldValues,
    TName extends FieldPath&amp;lt;TFieldValues&amp;gt; = FieldPath&amp;lt;TFieldValues&amp;gt;
&amp;gt; 
extends UseControllerProps&amp;lt;TFieldValues, TName&amp;gt;{
   type?:string;
   placeholder?:string;
}


function Input&amp;lt;
  TFieldValues extends FieldValues = FieldValues,
  TName extends FieldPath&amp;lt;TFieldValues&amp;gt; = FieldPath&amp;lt;TFieldValues&amp;gt;
&amp;gt;
(props:InputProps&amp;lt;TFieldValues, TName&amp;gt;) {
  const name = props.name;
  const {field, fieldState} = useController({
    name,
    rules: props.rules
  });

  return (
    &amp;lt;Wrapper error={fieldState.error &amp;amp;&amp;amp; true}&amp;gt;
       &amp;lt;Input
         {...field}
          type={props.type}
          placeholder={props.placeholder}
        /&amp;gt;
        {fieldState.error &amp;amp;&amp;amp; fieldState.error.message}
    &amp;lt;/Wrapper&amp;gt;
  );
};

export default Input;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- const {field, fieldState} = useController();&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;useController hook을 사용해 react-hook-form에 등록되어 있는 입력필드의 상태(fieldState)와 제어되고 있는 입력필드의 현재 값(field)를 가져옵니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- field&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;onChange, name, ref를 포함하고 있는 개체로 입력 필드에 등록해 줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;code&gt;fieldState.error&lt;/code&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 상태를 가져오는 fieldState를 이용해 error 값을 받아오고 error의 값이 있으면 error가 가지고 있는 message 값을 가져올 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>FRONT/React</category>
      <author>eunoia07</author>
      <guid isPermaLink="true">https://eunoia07.tistory.com/27</guid>
      <comments>https://eunoia07.tistory.com/entry/REACT-react-hook-form-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-%EA%B5%AC%ED%98%84#entry27comment</comments>
      <pubDate>Tue, 28 Jun 2022 17:54:48 +0900</pubDate>
    </item>
    <item>
      <title>[REACT] react-hook-form 사용하기 - 개념(1)</title>
      <link>https://eunoia07.tistory.com/entry/REACT-React-Hook-Form-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1269&quot; data-origin-height=&quot;832&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YJqiH/btr3Qx8WX5F/rNhgTSKlBexr5bNzpaquA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YJqiH/btr3Qx8WX5F/rNhgTSKlBexr5bNzpaquA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YJqiH/btr3Qx8WX5F/rNhgTSKlBexr5bNzpaquA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYJqiH%2Fbtr3Qx8WX5F%2FrNhgTSKlBexr5bNzpaquA1%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;358&quot; height=&quot;235&quot; data-origin-width=&quot;1269&quot; data-origin-height=&quot;832&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;1. React Hook Form 소개&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;187&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/duJlro/btrFoDqSN1W/uiaksAqKgwBktaYS6OyNN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/duJlro/btrFoDqSN1W/uiaksAqKgwBktaYS6OyNN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/duJlro/btrFoDqSN1W/uiaksAqKgwBktaYS6OyNN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FduJlro%2FbtrFoDqSN1W%2FuiaksAqKgwBktaYS6OyNN0%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;270&quot; height=&quot;187&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;187&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;공식문서 링크 : &lt;a href=&quot;https://react-hook-form.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://react-hook-form.com/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;React Hook Form은 React 내에서 From을 쉽게 제어하고 손쉽게 유효성 검사를 처리하도록 도와주는 라이브러리입니다.다른 종속성이 없는 최소한의 라이브러리로 구성되어 있어 성능이 뛰어나고 사용이 간편합니다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[React 기본 입력 필드 처리]&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1655795998575&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React, { useState } from &quot;react&quot;;

export default function App() {
  const [state, setState] = useState({
    email: &quot;&quot;,
    password: &quot;&quot;
  });

  const handleInputChange = (event) =&amp;gt; {
    setState((prevProps) =&amp;gt; ({
      ...prevProps,
      [event.target.name]: event.target.value
    }));
  };

  const handleSubmit = (event) =&amp;gt; {
    event.preventDefault();
    console.log(state);
  };

  return (
    &amp;lt;div className=&quot;App&quot;&amp;gt;
      &amp;lt;form onSubmit={handleSubmit}&amp;gt;
         &amp;lt;input
            type=&quot;text&quot;
            name=&quot;email&quot;
            value={state.email}
            onChange={handleInputChange}
          /&amp;gt;
        &amp;lt;input
            type=&quot;password&quot;
            name=&quot;password&quot;
            value={state.password}
            onChange={handleInputChange}
          /&amp;gt;
        &amp;lt;button type=&quot;submit&quot;&amp;gt;Login&amp;lt;/button&amp;gt;
      &amp;lt;/form&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;React로 입력 필드들을 처리할 때의 순서입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 1. 입력 필드에 대한 데이터 state 선언&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 2. 입력 필드에 onChange 이벤트 등록해 state 변경&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 3. state를 입력 필드의 value로 등록&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;기존에 입력 필드들을 처리할 때면 state를 선언하고 각 입력 필드에 event를 연결해 value를 받아오는 과정을 거쳐야 합니다. 이런 입력 필드가 많은 회원가입, 설문조사 등 입력 필드가 많아 질 수록 제어하기 힘들어지고 유효성 검사를 처리하기 어려워집니다.&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[React Hook Form 적용]&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;React Hook Form을 사용하게 되면&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - value와 onChange로 각 입력 필드에 대한 처리를 추가할 필요없음&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - state를 직접 관리할 필요가 없음&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래와 같이 코드를 줄일 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1655796141781&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from &quot;react&quot;;
import { useForm } from &quot;react-hook-form&quot;;

export default function App() {
  const { register, handleSubmit, errors } = useForm();

  const onSubmit = (data) =&amp;gt; {
    console.log(data);
  };

  return (
    &amp;lt;div className=&quot;App&quot;&amp;gt;
      &amp;lt;form onSubmit={handleSubmit(onSubmit)}&amp;gt;
        &amp;lt;input type=&quot;text&quot; name=&quot;email&quot; ref={register} /&amp;gt;
        &amp;lt;input type=&quot;password&quot; name=&quot;password&quot; ref={register} /&amp;gt;
        &amp;lt;button type=&quot;submit&quot;&amp;gt;Login&amp;lt;/button&amp;gt;
      &amp;lt;/form&amp;gt;
    &amp;lt;/div&amp;gt;
  );&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;2. React Hook Form 사용&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;pre id=&quot;code_1655796241662&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const { register, handleSubmit, errors } = useForm();&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;React Hook Form은 form 작업에 사용할 수 있는 &lt;span&gt;useForm&lt;/span&gt; hook을 제공합니다. hook은 초기값 설정, 입력 필드 지우기 기능 등을 제공하지만, 제일 중요한 세 가지만 살펴보겠습니다.&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[register]&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;ref로 사용되는 함수로 입력 필드를 React Hook Form에 등록하고 변경 사항에 대해 값을 추적합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1655796645121&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;input type=&quot;text&quot; name=&quot;email&quot; ref={register} /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;주의할 점은 입력 필드에는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;name 속성&lt;/span&gt;이 있어야 하며 해당 값은 고유해야 합니다.&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[&lt;span&gt;handleSubmit&lt;/span&gt;]&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;form을 서버로 제출할 때 사용하는 함수입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1655796690577&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;form onSubmit={handleSubmit(onSubmit)}&amp;gt;

const onSubmit = (data) =&amp;gt; {  
 console.log(data);
};&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[&lt;span&gt;errors]&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;유효성 검사를 포함하는 객체입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1655796775887&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;input type=&quot;text&quot; name=&quot;email&quot; ref={register({ required: true})} /&amp;gt;
&amp;lt;input
  type=&quot;password&quot;
  name=&quot;password&quot;
  ref={register({ required: true, minLength: 6 })}
/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;3. validation 기본 구현&lt;/span&gt;&lt;/h2&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: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0a0a23;&quot;&gt;validation를 추가하기 위해서는 각 입력 필드 ref로 전달되는 레지스터 함수에 유효성 검사를 매개변수를 전달합니다. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1655798342185&quot; class=&quot;pgsql&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;input type=&quot;text&quot; name=&quot;email&quot; ref={register({ required: true})} /&amp;gt;
&amp;lt;input
  type=&quot;password&quot;
  name=&quot;password&quot;
  ref={register({ required: true, minLength: 6 })}
/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;자주 사용되는 유효성 검사 속성들 입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - required : 입력 필드에 대한 필수 여부 검사&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - minlength maxlength : 문자열 입력 값의 최소, 최대 길이 설정&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - min max : 숫자 입력 값의 최소값, 최대값 설정&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - type : 입력 필드에 대한 유형 (이메일, 숫자, 텍스트 등)&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - pattern : 정규식을 이용한 입력 필드에 대한 패턴 정의&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 정의된 속성들에 따라 form이 제출될 때 errors 로 유효성 검사 성공여부를 확인 할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1655798342189&quot; class=&quot;pgsql&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;input
  type=&quot;text&quot;
  name=&quot;email&quot;
  ref={register({
    required: 'Email is required.',
    pattern: {
      value: /^[^@ ]+@[^@ ]+\.[^@ .]{2,}$/,
      message: 'Email is not valid.'
    }
  })}
/&amp;gt;

{errors.email &amp;amp;&amp;amp; errors.email.type === &quot;required&quot; &amp;amp;&amp;amp; (
  &amp;lt;p className=&quot;errorMsg&quot;&amp;gt;Email is required.&amp;lt;/p&amp;gt;
)}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[validation 검사]&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 유효성 검사는 handleSubmit 함수가 실행 될 때 진행됩니다. &lt;span&gt;유효성 검사가 실패하면&amp;nbsp;&lt;/span&gt;React Hook Form은 다음과 같이 처리합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 해당 입력 필드에 자동으로 focus 처리&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - errors가 하나라도 존재할 경우 submit 함수 미처리(form 제출을 안함)&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;submit 버튼을 눌렀을 때 말고, 입력과 동시에 입력 필드의 유효성 검사를 진행하려면 사용자 정의 validation를 만들어 사용하면 됩니다.&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;4. 사용자 정의 validation&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;const validatePassword = (value) =&amp;gt; {
  if (value.length &amp;lt; 6) {
    return '6자리보다 적게 입력해주세요.';
  }
  return true;
};

&amp;lt;input
  type=&quot;password&quot;
  name=&quot;password&quot;
  ref={register({
    required: '비밀번호는 필수값입니다.',
    validate: validatePassword
  })}
/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;validate 함수를 추가하여 입력 필드에 대한 사용자 지정 유효성 검사를 제공할 수도 있습니다.&lt;/p&gt;</description>
      <category>FRONT/React</category>
      <author>eunoia07</author>
      <guid isPermaLink="true">https://eunoia07.tistory.com/26</guid>
      <comments>https://eunoia07.tistory.com/entry/REACT-React-Hook-Form-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0#entry26comment</comments>
      <pubDate>Tue, 21 Jun 2022 18:19:00 +0900</pubDate>
    </item>
    <item>
      <title>[REDIS] redis 데이터 사용량 엑셀로 추출하기</title>
      <link>https://eunoia07.tistory.com/entry/REDIS-redis-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%82%AC%EC%9A%A9%EB%9F%89-%EC%97%91%EC%85%80%EB%A1%9C-%EC%B6%94%EC%B6%9C%ED%95%98%EA%B8%B0</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1269&quot; data-origin-height=&quot;832&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxhDuH/btr32uP3s5b/eKNauHIz4XlAdRr9FbtSV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxhDuH/btr32uP3s5b/eKNauHIz4XlAdRr9FbtSV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxhDuH/btr32uP3s5b/eKNauHIz4XlAdRr9FbtSV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxhDuH%2Fbtr32uP3s5b%2FeKNauHIz4XlAdRr9FbtSV0%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;361&quot; height=&quot;237&quot; data-origin-width=&quot;1269&quot; data-origin-height=&quot;832&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;1.ecstats 오픈소스&lt;/span&gt;&lt;/h2&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: justify;&quot; data-ke-size=&quot;size16&quot;&gt;redis를 사용하다 모니터링이나 관리 툴을 사용하지 않고 간단하게 데이터량을 추출해보고 싶어서 ecstats 오픈소스를 사용해보게 되었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;ecstats 오픈소스는 ElastiCache, Azure Cache for Redis, Redis cluster를 python 스크립트를 사용해 데이터 사용량과 구성 정보를 엑셀로 추출해주는 오픈소스입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- 링크 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://github.com/Redislabs-Solution-Architects/ecstats&quot;&gt;https://github.com/Redislabs-Solution-Architects/ecstats&lt;/a&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[오픈소스 구조]&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;ecstats는 총 세 가지 유형의 캐시 저장소의 데이터량의 추출하는 스크립트를 제공합니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 57.093%; height: 84px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 38.881%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;&lt;span&gt;ElastiCache&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 61.119%; height: 20px;&quot;&gt;pullElasticCacheStats.py&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 38.881%; height: 19px; text-align: center;&quot;&gt;&lt;b&gt;Azure Cache for Redis&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 61.119%; height: 19px;&quot;&gt;pullAzureCacheForRedisStats.py&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 38.881%; height: 19px; text-align: center;&quot;&gt;&lt;b&gt;Redis cluster&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 61.119%; height: 19px;&quot;&gt;pullRedisOpenSourceStats.py&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;사용하고 있는 캐시 저장소에 따라 해당 스크립트를 사용하면 됩니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;2. Redis 사용 방법&lt;/span&gt;&lt;/h2&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: justify;&quot; data-ke-size=&quot;size16&quot;&gt;사용 방법에는 도커 이미지를 사용해 실행하거나, 로컬 PC에서 python을 사용해 실행하는 두 가지 방법이 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;저는 python 스크립트를 이용해 로컬에서 사용 중인 Redis의 데이터량을 추출했습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[실행을 위한 환경 정보]&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;redis 환경&lt;/u&gt; : 로컬(127.0.0.1)에서 포트번호 (6379, 6380, 6381)로 redis 세 개를 구성함&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;사용한 스크립트&lt;/u&gt; : pullRedisOpenSourceStats.py를 사용해 스크립트를 실행함&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;- 스크립트 input 엑셀 파일 (redis 환경 정보를 스크립트에 알려주기 위한 파일)&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;- 스크립트 output 엑셀 파일 (redis 데이터량 스크립트 실행에 대한 결과 파일)&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[A. Github에서 소스 받기]&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1647586042406&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# git clone
git clone https://github.com/Redislabs-Solution-Architects/ecstats&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;해당 스크립트를 사용하고 싶은 경로에 clone 해 소스를 받으면 3개의 스크립트를 모두 사용할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;307&quot; data-origin-height=&quot;273&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/by6qnq/btrwjnqHYWs/xiwGq9TYqVr8cWwZfTsczK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/by6qnq/btrwjnqHYWs/xiwGq9TYqVr8cWwZfTsczK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/by6qnq/btrwjnqHYWs/xiwGq9TYqVr8cWwZfTsczK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fby6qnq%2FbtrwjnqHYWs%2FxiwGq9TYqVr8cWwZfTsczK%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;307&quot; height=&quot;273&quot; data-origin-width=&quot;307&quot; data-origin-height=&quot;273&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;저는 pullRedisOpenSourceStats.py를 사용했습니다.&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[B. Redis DB 구성 엑셀에 작성]&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이제, 데이터량을 추출할 Redis에 관한 정보를 스크립트에 알려줘야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1647586863082&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pullRedisOpenSourceStats.py 

parser = argparse.ArgumentParser()
parser.add_argument(&quot;inputFile&quot;, 
		help='''The Excel file containing Redis endpoints to pull stats from ''')
# Startup parameters
input_file = args.inputFile&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 pullRedisOpenSourceStats.py 소스코드를 확인해보면 엑셀 파일을 command line argumenets로 전달해 Redis에 관한 정보를 입력받고 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; 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;329&quot; data-origin-height=&quot;134&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VbcKm/btrwhUbo19Y/ydpxk3hmIYtA6k7yolLCD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VbcKm/btrwhUbo19Y/ydpxk3hmIYtA6k7yolLCD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VbcKm/btrwhUbo19Y/ydpxk3hmIYtA6k7yolLCD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVbcKm%2FbtrwhUbo19Y%2Fydpxk3hmIYtA6k7yolLCD0%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;329&quot; height=&quot;134&quot; data-origin-width=&quot;329&quot; data-origin-height=&quot;134&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;엑셀 파일은 다운로드한 소스파일 경로에서 samples폴더 안에 있는 sampleOSSPullInput.xlsx를 참고해서 Redis에 관한 정보를 입력해줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;94&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ErtYB/btrwmaYcvop/cXR8zlZBWeVllYb0ohSSYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ErtYB/btrwmaYcvop/cXR8zlZBWeVllYb0ohSSYK/img.png&quot; data-alt=&quot;sampleOssPullInput을 이용해 작성한 input 엑셀 파일&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ErtYB/btrwmaYcvop/cXR8zlZBWeVllYb0ohSSYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FErtYB%2FbtrwmaYcvop%2FcXR8zlZBWeVllYb0ohSSYK%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;601&quot; height=&quot;94&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;94&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;sampleOssPullInput을 이용해 작성한 input 엑셀 파일&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;저는 총 3개의 Redis를 로컬에서 포트를 나누어 구성을 해놨기 때문에 3개를 작성해주었고 TLS, Password, User는 사용하지 않고 구성하여 빈 값으로 엑셀을 작성했습니다.&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[C. python 스크립트 실행]&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;먼저 스크립트를 실행하기 위한 python 라이브러리들을 설치해야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1647587548399&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pip install XlsxWriter #1.2.2
pip install boto3 #1.17
pip install openpyxl #3.0.4
pip install pandas #1.3.0
pip install pathlib #1.0.1
pip install redis #3.5.3&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;모두 다 설치가 완료되었다면 스크립트를 실행시킵니다.&lt;/p&gt;
&lt;pre id=&quot;code_1647587363142&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;python pullRedisOpenSourceStats.py samples/sampleOSSPullInput.xlsx&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;스크립트는 항상 input 엑셀 파일을 command line argumenets로 전달해 같이 실행해야 합니다. (samples 하위 경로에 input 엑셀 파일이 있으니 상대 경로로 작성했습니다)&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[D. 데이터 사용량 엑셀 확인]&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;447&quot; data-origin-height=&quot;79&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btRQyl/btrwlQlujNS/ctikQTxwAq4yKms9vox4Bk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btRQyl/btrwlQlujNS/ctikQTxwAq4yKms9vox4Bk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btRQyl/btrwlQlujNS/ctikQTxwAq4yKms9vox4Bk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtRQyl%2FbtrwlQlujNS%2FctikQTxwAq4yKms9vox4Bk%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;447&quot; height=&quot;79&quot; data-origin-width=&quot;447&quot; data-origin-height=&quot;79&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 실행이 완료되면 OSSStats.xlxs 파일이 생성된 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1082&quot; data-origin-height=&quot;97&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6YKLf/btrwmaxflER/KYyRfdNURIwLiFSGslaKq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6YKLf/btrwmaxflER/KYyRfdNURIwLiFSGslaKq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6YKLf/btrwmaxflER/KYyRfdNURIwLiFSGslaKq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6YKLf%2FbtrwmaxflER%2FKYyRfdNURIwLiFSGslaKq0%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;1082&quot; height=&quot;97&quot; data-origin-width=&quot;1082&quot; data-origin-height=&quot;97&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;해당 엑셀 파일을 통해 redis DB에 데이터량과 slaves 등의 설정 정보를 확인할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;3. 사용하기 편리하게 소스 변경하기&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[input 엑셀 파일 경로 및 이름 수정하기]&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1647589359891&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# python pullRedisOpenSourceStats.py samples/sampleOSSPullInput.xlsx
python pullRedisOpenSourceStats.py input.xlsx&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;358&quot; data-origin-height=&quot;63&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBV9ha/btrwjnEnUgj/GW0kh53QkKL56Grnu1eUI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBV9ha/btrwjnEnUgj/GW0kh53QkKL56Grnu1eUI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBV9ha/btrwjnEnUgj/GW0kh53QkKL56Grnu1eUI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBV9ha%2FbtrwjnEnUgj%2FGW0kh53QkKL56Grnu1eUI1%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;358&quot; height=&quot;63&quot; data-origin-width=&quot;358&quot; data-origin-height=&quot;63&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;input 엑셀 파일을 스크립트와 동일한 경로로 옮긴 후 이름을 수정하면 스크립트 실행을 하기 훨씬 수월합니다.&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;b&gt;[output 엑셀 파일 이름 수정하기]&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;179&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZ1XB9/btrwmYiNnKJ/hKGvSgAGkUJxHS0jb6ckwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZ1XB9/btrwmYiNnKJ/hKGvSgAGkUJxHS0jb6ckwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZ1XB9/btrwmYiNnKJ/hKGvSgAGkUJxHS0jb6ckwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZ1XB9%2FbtrwmYiNnKJ%2FhKGvSgAGkUJxHS0jb6ckwk%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;508&quot; height=&quot;179&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;179&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크립트에서 output file을 OssStats.xlsx로 추출하는 부분에서 이름을 수정해주면 원하는 이름의 형태로 엑셀 추출이 가능합니다.&lt;/p&gt;</description>
      <category>DevOps</category>
      <author>eunoia07</author>
      <guid isPermaLink="true">https://eunoia07.tistory.com/25</guid>
      <comments>https://eunoia07.tistory.com/entry/REDIS-redis-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%82%AC%EC%9A%A9%EB%9F%89-%EC%97%91%EC%85%80%EB%A1%9C-%EC%B6%94%EC%B6%9C%ED%95%98%EA%B8%B0#entry25comment</comments>
      <pubDate>Fri, 18 Mar 2022 16:43:49 +0900</pubDate>
    </item>
    <item>
      <title>[SPRING] EJB vs 스프링 프레임워크</title>
      <link>https://eunoia07.tistory.com/entry/SPRING-EJB-vs-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1269&quot; data-origin-height=&quot;831&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmaYCp/btr3U0PJcQV/cu1KJU4rmkgqwGbkyWtPsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmaYCp/btr3U0PJcQV/cu1KJU4rmkgqwGbkyWtPsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmaYCp/btr3U0PJcQV/cu1KJU4rmkgqwGbkyWtPsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmaYCp%2Fbtr3U0PJcQV%2Fcu1KJU4rmkgqwGbkyWtPsk%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;420&quot; height=&quot;275&quot; data-origin-width=&quot;1269&quot; data-origin-height=&quot;831&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;1. 스프링 프레임워크 이전&lt;/span&gt;&lt;/h2&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: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;스프링 프레임워크는 2005년 로드 존슨이 2004년에 만든 오픈소스 프레임워크입니다. 이러한 스프링 프레임워크가 등장하기 이전, 자바 기반의 애플리케이션은 대부분 EJB로 개발되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;[EJB]&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;EJB는 Enterprise JavaBeans의 약자로 기업환경의 시스템을 구현하기 위한 서버 측 컴포넌트입니다. 즉, 거대 규모 시스템 구축을 위한 컴포넌트 모델입니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;[EJB의 구조]&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;445&quot; data-origin-height=&quot;268&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJeesG/btrvy2nIKzU/H0n4cu5OXqh6B7wvbqRzjk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJeesG/btrvy2nIKzU/H0n4cu5OXqh6B7wvbqRzjk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJeesG/btrvy2nIKzU/H0n4cu5OXqh6B7wvbqRzjk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJeesG%2Fbtrvy2nIKzU%2FH0n4cu5OXqh6B7wvbqRzjk%2Fimg.jpg&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;445&quot; height=&quot;268&quot; data-origin-width=&quot;445&quot; data-origin-height=&quot;268&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;u&gt;&lt;b&gt;Enterprise Bean &lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; - CRUD를 관리하고 클라이언트와 DB 사이에 접근하는 역할&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;u&gt;&lt;b&gt;Container&amp;nbsp;&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; - 서버 내에서 Enterprise Bean에 대한 런타임 환경 제공&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; -&amp;nbsp;EJB Server와 Enterprise Bean 사이에 통신 역할&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; - Sevelt이 Apache Tomcat Continer에 올려 사용하듯, EJB는 Weblogic, JBoss와 같은 EJB Continer에 올려서 서비스&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;u&gt;&lt;b&gt;EJB Server&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; - 컨테이너는 관리해서 EJB로서 피룡한 시스템 서비스를 구현&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;u&gt;&lt;b&gt;ClientApplication&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; - EJB구조를 사용해 연결할 수 있는 클라이언트단의 어플리케이션&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; -Applet, Servlet, JSP&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;[EJB의 한계점]&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;하지만 EJB는 스펙 자체가 복잡하기 때문에 학습에 많은 시간이 필요하며, EJB를 배치하고 실행하기 위해서 필요한 WAS들은 고가의 장비가 필요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;결론적으로는 EJB를 기반으로 비즈니스 컴포넌트를 구현하는 것은 매우 복잡하고 비싸며, 많은 시간과 노력이 필요하기 때문에 EJB를 대체한 스프링 프레임워크가 등장했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;2. 스프링 프레임워크의 등장&lt;/span&gt;&lt;/h2&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: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;스프링 프레임워크는 POJO를 사용하면서도 EJB에서만 가능했던 일을 지원하고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;[POJO]&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Plain Old Java Object의 약자로 해석하자면 평범한 옛날 자바 객체를 의미합니다. 아무런 규칙이 없는 클래스이기 때문에 문법적 제약이 거의 없어 유연하고, 배우기가 쉽습니다. 메소드, 매개변수, 리턴 등 엄격한 규칙이 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Not POJO 클래스인 Servlet이나 EJB와 비교하면 이해가 더 쉽습니다. Servlet은 클래스를 만드는데 있어 엄격한 규칙이 적용되기 떄문에 규칙에 맞게 작성해야 합니다. 규칙이 엄격하면 배우기가 어려울 뿐 아니라 관리하는데 사용하는 메모리가도 많이 사용됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;3. 스프링 프레임워크의 특징&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;[경량]&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;스프링이 EJB에 비해 가벼운 이유는 두 가지입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 크기 측면에서 여러 개의 모듈(JAR파일)로 구성되어 있어 가벼움&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 스프링이 관리하는 객체가 POJO로 관리하는 메모리 사용량 적고 가벼움&lt;/span&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;[제어 역행:IoC]&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;제어역행(IoC)을 통해 애플리케이션의 느슨한 결합을 지원합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 제어 역행의 주체 : Srping Container&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 제어의 대상 : Container가 관리하는 POJO 형태의 자바 객체&lt;/span&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;[관점지향:AOP]&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&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: justify;&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: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 공통 기능의 코드를 분리 (예외 처리, 트랜잭션 처리 같은 공통 기능 모듈화 + 선언적으로 처리)&lt;/span&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;[Container]&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Container는 스프링 이전에도 사용되었던 개념입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- EJB Container: EJB 객체의 생성 및라이프사이클을 관리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- Servlet Container: Servlet 객체의 생성 및 라이프 사이클을 관리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Spring Container :&amp;nbsp; 객체의 생명주기와 객체들 간의 의존관계를 관리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;즉, 객체를 생성해서 관리하는 것을 Container의&amp;nbsp;개념이라고 생각하면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; 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;color: #0593d3;&quot;&gt;참고자료&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;a href=&quot;https://woongsin94.tistory.com/357&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://woongsin94.tistory.com/357&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;a href=&quot;https://zunoxi.github.io/programming/2020/12/30/dev-web-ejb/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://zunoxi.github.io/programming/2020/12/30/dev-web-ejb/&lt;/a&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>SERVER/SpringBoot</category>
      <author>eunoia07</author>
      <guid isPermaLink="true">https://eunoia07.tistory.com/24</guid>
      <comments>https://eunoia07.tistory.com/entry/SPRING-EJB-vs-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC#entry24comment</comments>
      <pubDate>Thu, 10 Mar 2022 15:39:51 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] Storage AWS S3</title>
      <link>https://eunoia07.tistory.com/entry/AWS-Storage-AWS-S3</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1269&quot; data-origin-height=&quot;832&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Wptpf/btr3SGR3cNK/fsqmQtT9SloszanyqKNhmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Wptpf/btr3SGR3cNK/fsqmQtT9SloszanyqKNhmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Wptpf/btr3SGR3cNK/fsqmQtT9SloszanyqKNhmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWptpf%2Fbtr3SGR3cNK%2FfsqmQtT9SloszanyqKNhmK%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;421&quot; height=&quot;276&quot; data-origin-width=&quot;1269&quot; data-origin-height=&quot;832&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;1. Amazon S3란?&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;289&quot; data-origin-height=&quot;264&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lSj8L/btrvvvoiy21/hnkwUn9gf52oRZKY1K1H31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lSj8L/btrvvvoiy21/hnkwUn9gf52oRZKY1K1H31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lSj8L/btrvvvoiy21/hnkwUn9gf52oRZKY1K1H31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlSj8L%2Fbtrvvvoiy21%2FhnkwUn9gf52oRZKY1K1H31%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;246&quot; height=&quot;198&quot; data-origin-width=&quot;289&quot; data-origin-height=&quot;264&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Amazon S3는 Amazon Simple Storage Service의 약자로 &lt;u&gt;언제 어디서나 데이터를 단순하게 처리&lt;/u&gt;할 수 있도록하는 웹 서비스 기반 인터페이스를 제공합니다. 웹에서 사용 가능한 오브젝트 저장소로 사용한 만큼만 비용을 지불하고 내구성과 확장성이 뛰어납니다.&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;2. S3 특징&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;API를 통한 직접 사용이 가능&lt;/li&gt;
&lt;li&gt;병렬 처리 지원&lt;/li&gt;
&lt;li&gt;수명 주기, 객체 잠금, 복제, 배치 작업등 스토리지 관리를 위한 기능 지원&lt;/li&gt;
&lt;li&gt;Labmda, SQS, SNS 등 데이터를 변환하고 워크플로를 트리거해 다양한 활동 자동화 처리 가능&lt;/li&gt;
&lt;li&gt;객체에 대한 강한 일관성 제공&lt;/li&gt;
&lt;li&gt;S3버킷과 객체는 기본적으로 비공개로 액세스하기 때문에 권한을 감사 및 관리하기 위한 기능 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;3. S3 저장 방식&lt;/span&gt;&lt;/h2&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: justify;&quot; data-ke-size=&quot;size16&quot;&gt;S3는 데이터를 버킷 내에 오브젝트 (Object)로 저장하는 객체 스토리지 서비스입니다. 모든 오브젝트를 버킷 내에 저장하고 S3에 데이터를 저장하기 전에 반드시 버킷이 생성되어 있어야 합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;버킷 (Bucket) : 오브젝트의 컨테이너 입니다.&lt;/li&gt;
&lt;li&gt;&amp;nbsp;오브젝트 (Object) : 텍스트 파일, 이미지 파일 및 비디오 파일 등 모든 종류의 파일이 가능합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[&lt;span&gt;버킷 (Bucket)&lt;/span&gt;]&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;버킷에는 오브젝트를 원하는 수만큼 저장할 수 있으며 모든 오브젝트는 버킷 내에 생성됩니다. 계정에 최대 100개의 버킷을 가질 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;버킷을 생성할 때는 이름과 리전이 중요합니다. 버킷의 이름은 고유한 값이기 때문에 조직 이름 또는 사용자 이름을 반영해 생성하는 것이 일반적입니다. 버킷 내에 저장된 오브젝트를 지정하기 위해서 버킷 이름은 URL에 포함되기 때문에 URL에 사용할 수 있도록 버킷 명명 규칙도 존재합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;소문자, 수수자, 점(.) 그리고 대쉬(-)를 포함 할 수 있습니다.&lt;/li&gt;
&lt;li&gt;반드시 숫자 또는 문자로 시작해야 합니다.&lt;/li&gt;
&lt;li&gt;최소 3 자에서 최대 255 문자의 길이로 지정이 가능합니다.&lt;/li&gt;
&lt;li&gt;IP 주소와 같은 형식으로 지정할 수 없습니다. (e.g., 265.255.5.4)&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이름과 리전은 한 번 설정 시 변경이 불가한 값이니 신중하게 생성해야 합니다.&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[오브젝트 (Object)]&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;오브젝트는 데이터와 메타데이터(키-값 쌍의 집합)로 구성됩니다. 버킷에 오브젝트를 추가할 때, 해당 오브젝트에 대한 권한 및 접근 설정등에 대한 정보를 메타데이터에 포함시킬 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;오브젝트는 키와 버전ID로 버킷 내에서 고유하게 식별됩니다. 키는 버킷 내 오브젝트의 고유 식별자로 버킷 내 모든 객체에는 하나의 키가 있으며 해당 키는 URL에 포함됩니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;기본적으로 S3 버킷에 있는 모든 오브젝트는 URL을 통해 해당 오브젝트를 읽을 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예시: &lt;span style=&quot;background-color: #dddddd;&quot;&gt;https://DOC-EXAMPLE-BUCKET.s3.us-west-2.amazonaws.com/photos/puppy.jpg&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2f3f3; color: #16191f;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;웹 서비스 엔드포인트&lt;/li&gt;
&lt;li&gt;버킷 이름 : DOC-EXAMPLE-BUCKET&lt;/li&gt;
&lt;li&gt;키 이름 : /photos/puppy.jpg&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;S3 URL은 기본값이 소유자 전용(private)으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;URL을 외부사용자(public)도 접근할 수 있도록 권한 설정을 하거나 해당 오브젝트에 대하여 인증저보가 포함된 시그니처기반의 Signed URL을 생성해 외부 사용자가 오브젝트에 접근할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;4. S3 종류&lt;/span&gt;&lt;/h2&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: justify;&quot; data-ke-size=&quot;size16&quot;&gt;S3는 데이터에 대한 Life Cycle 정책을 통해 &lt;span&gt;사용자들의 요구사항에&lt;span&gt; 따라&amp;nbsp;&lt;/span&gt;&lt;/span&gt;3가지의 스토리지로 계층화 되어 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;S3 Standard&lt;/li&gt;
&lt;li&gt;S3-IA&lt;/li&gt;
&lt;li&gt;S3 Glacier&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[S3 Standard]&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;주로 사용하는 데이터 또는 임시 처리용 데이터를 보관합니다. (Hot Data)&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;가장 가격이 비싸지만 검색시 발생하는 비용이 없습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 29.3023%; height: 40px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;가격&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;용량단위&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;결제단위&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;0.025$&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;GB&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;월간&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;사용 예시 : 데이터 생성 및 접근 발생시 사용합니다. (Big Data 분석용 데이터)&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[S3-IA]&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;간헐적으로 사용되는 데이터를 보관합니다. (Warm Data)&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 29.3023%; height: 40px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;가격&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;용량단위&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;결제단위&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;0.018$&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;GB&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;월간&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;IA에서 데이터를 찾고 싶다면 검색도 가능합니다. 하지만 S3 Standard와 다르게 가격이 발생합니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 19.0698%; height: 64px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;가격&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;용량단위&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;0.01$&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;GB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;사용 예시 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;S3 Standard에서 N일 이상 경과된 데이터를 IA로 Class를 변경합니다. ( 아카이브 또는 백업 / 재해 복구용 )&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[S3 Glacier]&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;보존 데이터 또는 규정에 의한 장기보관 데이터를 보관합니다. (Cold Data)&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;가격이 가장 저렴하며 높은 보안성(SSL &amp;amp; AES-256)과 높은 내구성을 지니고 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 29.3023%; height: 40px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;가격&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;용량단위&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;결제단위&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;0.005$&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;GB&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;월간&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Glacier에서 데이터를 가져오기 위해선 시간이 걸립니다. Clod Data이기 때문에 데이터를 사용하기 위해선 Warm을 하는 과정에서 발생하는 시간입니다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;3가지의 검색 옵션을 제공합니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 58.3722%; height: 141px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center; height: 20px;&quot;&gt;구분&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center; height: 20px;&quot;&gt;시간&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center; height: 20px;&quot;&gt;가격&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center; height: 20px;&quot;&gt;용량단위&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center; height: 20px;&quot;&gt;긴급(Expedited)&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center; height: 20px;&quot;&gt;1~5분&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center; height: 20px;&quot;&gt;0.033$&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center; height: 20px;&quot;&gt;GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center; height: 20px;&quot;&gt;표준(Standard)&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center; height: 20px;&quot;&gt;3~5시간&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center; height: 20px;&quot;&gt;0.011$&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center; height: 20px;&quot;&gt;GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center; height: 20px;&quot;&gt;대량(Bulk)&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center; height: 20px;&quot;&gt;5~12시간&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center; height: 20px;&quot;&gt;0.00275$&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; text-align: center; height: 20px;&quot;&gt;GB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;사용 예시 : S3 IA에서 N일 이상 경과도니 데이터를 Glacier로 Class를 변경합니다. ( 장기 보존용 아카이브 )&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;5. S3 관리 기능&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;S3 Obejct Tagging
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;(S3 객체에 대한 관리 및 접근 통제)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;S3 Analytics, Storage Class Analytics
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;(스토리지 및 Object에 대한 사용 패턴을 분석하여 적합한 스토리지 클래스로 전환)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;S3 Inventory
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;(규정 준수 및 규제요건 감시, 비지니스 워크플로우 및 빅데이터 업무를 단순화하고 가속화)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;S3 CloudWatch Metrics
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;(S3를 사용하는 어플리케이션의 특성을 이해하고, 성능을 개선하도록 도움)​&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>DevOps/AWS</category>
      <author>eunoia07</author>
      <guid isPermaLink="true">https://eunoia07.tistory.com/23</guid>
      <comments>https://eunoia07.tistory.com/entry/AWS-Storage-AWS-S3#entry23comment</comments>
      <pubDate>Tue, 8 Mar 2022 16:54:24 +0900</pubDate>
    </item>
    <item>
      <title>[REDIS] redis 기초 개념</title>
      <link>https://eunoia07.tistory.com/entry/Redis-redis-%EA%B8%B0%EC%B4%88-%EA%B0%9C%EB%85%90</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1269&quot; data-origin-height=&quot;832&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RkVCx/btr3SYLC38j/AsUekOZ4GBbItM7awQDyc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RkVCx/btr3SYLC38j/AsUekOZ4GBbItM7awQDyc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RkVCx/btr3SYLC38j/AsUekOZ4GBbItM7awQDyc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRkVCx%2Fbtr3SYLC38j%2FAsUekOZ4GBbItM7awQDyc1%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;403&quot; height=&quot;264&quot; data-origin-width=&quot;1269&quot; data-origin-height=&quot;832&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;1. Redis란?&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;326&quot; data-origin-height=&quot;217&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKJxAN/btruNiqk8Oh/dM5UvdQhMKuZ7cGDxJarL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKJxAN/btruNiqk8Oh/dM5UvdQhMKuZ7cGDxJarL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKJxAN/btruNiqk8Oh/dM5UvdQhMKuZ7cGDxJarL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKJxAN%2FbtruNiqk8Oh%2FdM5UvdQhMKuZ7cGDxJarL1%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;326&quot; height=&quot;217&quot; data-origin-width=&quot;326&quot; data-origin-height=&quot;217&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Remote Dictionary Server(redis)는 오픈소스 기반의 비관계형 데이터베이스 관리 시스템으로 모든 데이터를 &lt;u&gt;메모리&lt;/u&gt;에 저장하고 조회하는 키-값 기반의 NoSQL &lt;u&gt;인메모리 데이터 저장소&lt;/u&gt; 입니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[캐시]&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐시란 한 번 읽어온 데이터를 임의의 공간에 저장하여 다음에 읽을 때도 빠르게 결과값을 받을 수 있도록 도와주는 공간입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1275&quot; data-origin-height=&quot;674&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMOFRZ/btrutl3oIjg/As5mQEmdpATKVYVzVvL5tK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMOFRZ/btrutl3oIjg/As5mQEmdpATKVYVzVvL5tK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMOFRZ/btrutl3oIjg/As5mQEmdpATKVYVzVvL5tK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMOFRZ%2Fbtrutl3oIjg%2FAs5mQEmdpATKVYVzVvL5tK%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;1275&quot; height=&quot;674&quot; data-origin-width=&quot;1275&quot; data-origin-height=&quot;674&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB에서 한 번 불러온 데이터는 캐시에 저장 되어 다음에도 똑같은 데이터 요청이 있다면 캐시에서 반환하는 과정입니다.&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;1. 클라이언트는 서버에서 데이터 요청을 보냄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 서버는 캐시에 데이터가 있으면 캐시에서 가져옴&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 캐시에 데이터가 없다면 DB에서 데이터를 가져옴&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 가져온 데이터를 캐시에 저장하고 클라이언트에게 데이터 반환&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[인메모리 DB]&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;인메모리에서는 외부 저장 장치(disk-based DB)가 아닌 메모리(in-memory DB)에 데이터를 저장합니다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 40px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 14.186%; height: 20px;&quot;&gt;메모리&lt;/td&gt;
&lt;td style=&quot;width: 11.8605%;&quot;&gt;RAM&lt;/td&gt;
&lt;td style=&quot;width: 73.9535%; height: 20px;&quot;&gt;CPU에서 이루어진 연산을 기록하는 메모리 CPU와 하드디스크를 연결시켜주는 장치&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 14.186%; height: 20px;&quot;&gt;외부 저장 장치&lt;/td&gt;
&lt;td style=&quot;width: 11.8605%;&quot;&gt;HDD, SDD&lt;/td&gt;
&lt;td style=&quot;width: 73.9535%; height: 20px;&quot;&gt;컴퓨터의 정보, 문서, 자료 등을 저장하고 읽을 수 있는 장치&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1430&quot; data-origin-height=&quot;603&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tHHrF/btruE9nlL9F/IOcuub4RO5Za4ESDhkOZAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tHHrF/btruE9nlL9F/IOcuub4RO5Za4ESDhkOZAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tHHrF/btruE9nlL9F/IOcuub4RO5Za4ESDhkOZAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtHHrF%2FbtruE9nlL9F%2FIOcuub4RO5Za4ESDhkOZAk%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;1430&quot; height=&quot;603&quot; data-origin-width=&quot;1430&quot; data-origin-height=&quot;603&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 외부 저장 장치(하드 디스크)에 데이터를 저장하지 않고 메모리(RAM)에 바로 데이터를 저장합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부 저장 장치를 사용했다면 메모리와 외부 저장 장치와의 병목 현상이 발생했겠지만 메모리만 사용하기 때문에 데이터 저장 속도가 빠릅니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 40px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 13.721%; text-align: center; height: 20px;&quot;&gt;in-memory DB&lt;/td&gt;
&lt;td style=&quot;width: 14.593%; height: 20px; text-align: center;&quot;&gt;메모리(RAM)&lt;/td&gt;
&lt;td style=&quot;width: 71.6861%; height: 20px;&quot;&gt;속도는 빠르지만 영속성을 보장하지 않고(데이터 유실 가능), 저장 공간이 한정되어 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 13.721%; text-align: center; height: 20px;&quot;&gt;disk-based DB&lt;/td&gt;
&lt;td style=&quot;width: 14.593%; height: 20px; text-align: center;&quot;&gt;외부 저장 장치(디스크)&lt;/td&gt;
&lt;td style=&quot;width: 71.6861%; height: 20px;&quot;&gt;데이터를 읽어 메모리에 올리고, 메모리에 올라간 데이터를 읽기 때문에 속도가 느림&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;2. Redis 특징&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- single thread로 한 번에 딱 하나의 명령어만 실행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 메모리에 위치하기 때문에 디스크보다 수용력은 적지만 접근 속도는 빠릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Remote Data Storage로 여러 서버에서 같은 데이터를 공유하고 보고 싶을 때 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 메모리에 상주한 데이터들이 휘발되지 않도록 디스크에 스냅샷을 저장할 수 있습니다. (persistence 지원)&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[장점]&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 다양한 데이터 구조를 제공해 캐시 데이터 저장이나 &lt;span data-token-index=&quot;1&quot; data-reactroot=&quot;&quot;&gt;Persistence Data Storage 에 사용 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-token-index=&quot;1&quot; data-reactroot=&quot;&quot;&gt;&amp;nbsp; &amp;nbsp;(다른 in-memory 데이터베이스와의 가장 큰 차이점이 바로 다양한 자료 구조를 지원한다는 것입니다.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-token-index=&quot;1&quot; data-reactroot=&quot;&quot;&gt;- 키-값 기반으로 쿼리 필요없이 결과를 가져올 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-token-index=&quot;1&quot; data-reactroot=&quot;&quot;&gt;- 메모리에서 데이터를 처리하기 때문에 속도가 빠릅니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[단점]&lt;/b&gt;&lt;/h4&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;- 쓰기 연산이 copy on wirte 방식으로 동작하기 때문에 최대 메모리를 2배 이상까지 사용합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;3. Redis 사용 사례&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Remote Data Store를 이용한 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 인증 토큰 개발&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Ranking Board 시스템&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 유저 API Limit&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Job Queue&lt;/p&gt;</description>
      <category>DevOps</category>
      <author>eunoia07</author>
      <guid isPermaLink="true">https://eunoia07.tistory.com/22</guid>
      <comments>https://eunoia07.tistory.com/entry/Redis-redis-%EA%B8%B0%EC%B4%88-%EA%B0%9C%EB%85%90#entry22comment</comments>
      <pubDate>Wed, 2 Mar 2022 14:19:33 +0900</pubDate>
    </item>
    <item>
      <title>[C#] ?, ?? 연산자</title>
      <link>https://eunoia07.tistory.com/entry/%EC%97%B0%EC%82%B0%EC%9E%90</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1269&quot; data-origin-height=&quot;831&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yQblf/btr3SYZbz1n/LAK55ckuErUGWsFq1jKD8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yQblf/btr3SYZbz1n/LAK55ckuErUGWsFq1jKD8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yQblf/btr3SYZbz1n/LAK55ckuErUGWsFq1jKD8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyQblf%2Fbtr3SYZbz1n%2FLAK55ckuErUGWsFq1jKD8K%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;397&quot; height=&quot;260&quot; data-origin-width=&quot;1269&quot; data-origin-height=&quot;831&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;  ?, ?? 연산자란?&lt;/span&gt;&lt;/h2&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: justify;&quot; data-ke-size=&quot;size16&quot;&gt;C# 코드를 보면 물음표 문자가 변수 뒤, 메서드 뒤에 한 개 또는 여러 개씩 붙어 있는 경우가 있습니다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;int? max = list?.Max;
int min = list?.Min ?? 0;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;C#에서 &lt;code&gt;?&lt;/code&gt;를 사용하는 방식은 총 1개의 형식과 2개의 연산자가 존재합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- &lt;code&gt;nullable&lt;/code&gt; 형식&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- &lt;code&gt;?&lt;/code&gt; 연산자&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- &lt;code&gt;??&lt;/code&gt; 연산자&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;하나씩 알아보도록 하겠습니다.&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;  nullable 형식&lt;/span&gt;&lt;/h2&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: justify;&quot; data-ke-size=&quot;size16&quot;&gt;C# 2.0에 추가된 &lt;code&gt;nullable&lt;/code&gt; 형식은 &lt;code&gt;System.Nullable&amp;lt;T&amp;gt;&lt;/code&gt; 구조체입니다.&lt;br /&gt;즉, 값 형식에 대해 &lt;code&gt;null&lt;/code&gt; 표현이 가능하게 하는 역할을 합니다.&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[예제1 - &lt;code&gt;Nullable&lt;/code&gt; 사용]&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;Nullable&amp;lt;bool&amp;gt; _getMarried;
public NullAble&amp;lt;bool&amp;gt; GetMarrid
{
get {return _getMarried; } set { _getMarried = value; }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Nullable&amp;lt;T&amp;gt;&lt;/code&gt; 타입은 &lt;code&gt;HasValue&lt;/code&gt;, &lt;code&gt;Value&lt;/code&gt; 속성을 가집니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- &lt;code&gt;HasValue&lt;/code&gt; : 값이 할당되었는지 여부를 &lt;code&gt;bool&lt;/code&gt; 값으로 반환&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- &lt;code&gt;value&lt;/code&gt; : 값 존재 시 T 타입 값 반환&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt; 중요한 점은,&lt;br /&gt;&lt;code&gt;Nullable&amp;lt;T&amp;gt;&lt;/code&gt;는 표기의 축약형 값 형식에 &lt;code&gt;?&lt;/code&gt; 문자를 함께 붙이는 표현을 지원합니다.&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[예제2 - ? 문자로 리팩토링]&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;bool? _getMarried;
public bool? GetMarrid
{
get {return _getMarried; } set { _getMarried = value; }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;?&lt;/code&gt; 문자를 값 형식에 붙이면 C# 컴파일러는 빌드 시 자동으로 &lt;code&gt;Nullable&amp;lt;T&amp;gt;&lt;/code&gt;로 바꾸어 줍니다.&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;  ? 연산자&lt;/span&gt;&lt;/h2&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: justify;&quot; data-ke-size=&quot;size16&quot;&gt;C#6.0에 추가된 연산자로 &lt;code&gt;? 연산자&lt;/code&gt;는 &lt;code&gt;null 조건 연산자&lt;/code&gt;라고 불립니다.&lt;/p&gt;
&lt;pre class=&quot;gcode&quot;&gt;&lt;code&gt;참조형변수?.(멤버, 배열 ...)&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;참조 형식의 변수가 &lt;code&gt;null&lt;/code&gt;이라면 그대로 &lt;code&gt;null&lt;/code&gt;을 반환하고 &lt;code&gt;null&lt;/code&gt;이 아니라면 지정된 멤버를 호출합니다.&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[예제1- &lt;code&gt;?&lt;/code&gt;연산자 미사용]&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;List&amp;lt;int&amp;gt; list = GetList();

if(list != null)
{
Console.Write(list.Count);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;참조형에 대한 &lt;code&gt;null&lt;/code&gt;값을 체크할 때 이렇게 많이 코드를 작성하지만 &lt;code&gt;null 조건 연산자&lt;/code&gt;를 사용하면 훨씬 간결하게 처리할 수 있습니다.&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[예제2- &lt;code&gt;?&lt;/code&gt;연산자 사용]&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;List&amp;lt;int&amp;gt; list = GetList();

Console.Write(list?.Count);&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[주의사항]&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;null 조건 연산자&lt;/code&gt;는 단독으로는 사용이 불가하며, 반드시 해당 참조형 변수의 멤버를 접근하거나 매열 인덱스 같은 부가적인 접근이 필요합니다.&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;  ?? 연산자&lt;/span&gt;&lt;/h2&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: justify;&quot; data-ke-size=&quot;size16&quot;&gt;C#2.0에 추가된 연산자로 &lt;code&gt;?? 연산자&lt;/code&gt;는 &lt;code&gt;null&lt;/code&gt; 병합 연산자라고 불립니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;피연산자1 ?? 피연산자2&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;참조 형식의 피연산자1이 &lt;code&gt;null&lt;/code&gt;이 아니라면 그 값을 그대로 반환하고, &lt;code&gt;null&lt;/code&gt;이라면 피연산자2의 값을 반환합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;즉, &lt;code&gt;null&lt;/code&gt;값을 가진 참조형 변수를 손쉽게 처리할 수 있는 연산자입니다.&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[예제1- ??연산자 미사용]&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;axapta&quot;&gt;&lt;code&gt;string str = null;

if(str == null) 
{ 
Console.WriteLine(&quot;null값입니다.&quot;);
}
else 
{
Console.WriteLine(str);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;참조형에 대한 &lt;code&gt;null&lt;/code&gt;값을 체크할 때 이렇게 많이 코드를 작성하지만 &lt;code&gt;null&lt;/code&gt; 병합 연산자를 사용하면 훨씬 간결하게 처리할 수 있습니다.&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[예제2- ?? 연산자 사용]&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;string str = null;

Console.WriteLine(str ?? (&quot;null값입니다.&quot;));&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;정리&lt;/span&gt;&lt;/h2&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: justify;&quot; data-ke-size=&quot;size16&quot;&gt;처음에 본 코드를 다시 해석해 보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;int? max = list?.Max;
int min = list?.Min ?? 0;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[1. &lt;code&gt;nullable&lt;/code&gt; 형식]&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;값 형식에 대해 &lt;code&gt;null&lt;/code&gt; 표현이 가능하게 해 줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1644909149737&quot; class=&quot;cs&quot; data-ke-language=&quot;cs&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int? max //nullable 형식의 값 형식 max 변수&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[2. &lt;code&gt;?&lt;/code&gt; 연산자]&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;참조 형식 변수의 &lt;code&gt;null&lt;/code&gt; 여부에 따라 참조형식의 멤버를 호출합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1644909166510&quot; class=&quot;cs&quot; data-ke-language=&quot;cs&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;list?.Max //list가 null이 아니면 Max 멤버 호출&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[3. &lt;code&gt;??&lt;/code&gt; 연산자]&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;참조 형식의 &lt;code&gt;null&lt;/code&gt; 값 처리를 간결하게 해 줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1644909174977&quot; class=&quot;cs&quot; data-ke-language=&quot;cs&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;list?.Min ?? 0 //list가 null이 아니면 Min 멤버를 호출
			   //Min멤버가 null이 아니면 Min값 그대로를 돌려주고 null이면 0을 돌려줍니다.&lt;/code&gt;&lt;/pre&gt;</description>
      <category>SERVER/.NET</category>
      <author>eunoia07</author>
      <guid isPermaLink="true">https://eunoia07.tistory.com/21</guid>
      <comments>https://eunoia07.tistory.com/entry/%EC%97%B0%EC%82%B0%EC%9E%90#entry21comment</comments>
      <pubDate>Tue, 15 Feb 2022 16:15:34 +0900</pubDate>
    </item>
  </channel>
</rss>