<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>a_rubz.log</title>
        <link>https://velog.io/</link>
        <description>🔥 개발 공부 🔥</description>
        <lastBuildDate>Mon, 10 Apr 2023 11:29:31 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>a_rubz.log</title>
            <url>https://velog.velcdn.com/images/a_rubz/profile/7ab8e4d8-3f6c-4294-a882-70964c4f7732/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. a_rubz.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/a_rubz" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[백준] 3460번 이진수 - Java]]></title>
            <link>https://velog.io/@a_rubz/%EB%B0%B1%EC%A4%80-3460%EB%B2%88-%EC%9D%B4%EC%A7%84%EC%88%98-Java</link>
            <guid>https://velog.io/@a_rubz/%EB%B0%B1%EC%A4%80-3460%EB%B2%88-%EC%9D%B4%EC%A7%84%EC%88%98-Java</guid>
            <pubDate>Mon, 10 Apr 2023 11:29:31 GMT</pubDate>
            <description><![CDATA[<h3 id="🔗-link">🔗 Link</h3>
<p><a href="https://www.acmicpc.net/problem/3460">https://www.acmicpc.net/problem/3460</a></p>
<hr>
<h3 id="✨-insight">✨ Insight</h3>
<pre><code>1. 주어진 정수를 이진수로 변환

2. 뒤에서부터 반복문 돌리기
   (예) 문자열 123일 때, 인덱스를 0부터 시작하면 1 -&gt; 2 -&gt; 3 순서
        3 -&gt; 2 -&gt; 1 순서로 문자를 확인할 수 있게 인덱스를 &#39;문자열 길이 - 1&#39;부터 시작

3. 주어진 문제에 맞게 인덱스값 수정
   (예) 문자열 123일 때, 3의 인덱스는 2
           but, 문제에서 원하는 값은 0
        &#39;문자열 길이 - 실제 인덱스 값 - 1&#39;이 거꾸로 된 인덱스의 값</code></pre><br>

<h3 id="📃-code--124ms">📃 Code =&gt; 124ms</h3>
<pre><code class="language-java">package basic;

import java.io.*;

public class Main {
    public void solution() throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        int tc = Integer.parseInt(br.readLine());

        for (int i=0; i &lt; tc; i++) {
            int num = Integer.parseInt(br.readLine());
            String binaryNum = Integer.toBinaryString(num);

            for (int j=binaryNum.length()-1; j&gt;=0; j--) {
                if (binaryNum.charAt(j) == &#39;1&#39;) {
                    bw.write(binaryNum.length()-j-1 + &quot; &quot;);
                }
            }

            bw.newLine();
        }

        bw.flush();
        br.close();
        bw.close();
    }

    public static void main(String[] args) throws Exception {
        new Main().solution();
    }

}
</code></pre>
<hr>
<h3 id="💡-keyword">💡 Keyword</h3>
<p><em>-  Integer.toBinaryString(num) : 10진수를 이진수로 변환</em></p>
<p><em>- charAt(idx) : 문자열 내부에서 해당하는 인덱스의 문자값</em></p>
<p><em>-  char와 String 비교 시, &quot; &quot; 대신 &#39; &#39; 사용</em></p>
<p><em>-  bw.newLine() : BufferWriter 다음 줄 작성</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 2501번 약수 구하기 - Java]]></title>
            <link>https://velog.io/@a_rubz/%EB%B0%B1%EC%A4%80-2501%EB%B2%88-%EC%95%BD%EC%88%98-%EA%B5%AC%ED%95%98%EA%B8%B0-Java</link>
            <guid>https://velog.io/@a_rubz/%EB%B0%B1%EC%A4%80-2501%EB%B2%88-%EC%95%BD%EC%88%98-%EA%B5%AC%ED%95%98%EA%B8%B0-Java</guid>
            <pubDate>Mon, 10 Apr 2023 09:24:22 GMT</pubDate>
            <description><![CDATA[<h3 id="🔗-link">🔗 Link</h3>
<p><a href="https://www.acmicpc.net/problem/2501">https://www.acmicpc.net/problem/2501</a></p>
<hr>
<h3 id="✨-insight">✨ Insight</h3>
<pre><code>약수는 두 수의 곱으로 볼 수 있음

6의 약수 =&gt; 1, 2, 3, 6

1이 약수임을 알면 6도 약수란 걸 알 수 있음

따라서 sqrt로 주어진 수의 제곱근까지만 반복문 가능

But, 9의 약수 =&gt; 1, 3, 9

3이 중복으로 리스트에 추가되므로 처리해줘야함</code></pre><h3 id="📃-code--124ms">📃 Code =&gt; 124ms</h3>
<pre><code class="language-java">import java.io.*;
import java.util.*;

public class Main {
    public void solution() throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int num = Integer.parseInt(st.nextToken());
        int index = Integer.parseInt(st.nextToken());

        ArrayList&lt;Integer&gt; list = new ArrayList&lt;&gt;();

        for (int i=1; i&lt;=Math.sqrt(num); i++) {
            if (num%i == 0) {
                list.add(i);
                if (num/i != i) {
                    list.add(num/i);
                }
            }
        }

        if (list.size() &lt; index) {
            bw.write(&quot;0&quot;);
        } else {
            Collections.sort(list);
            bw.write(String.valueOf(list.get(index-1)));
        }

        bw.flush();
        br.close();
        bw.close();

    }

    public static void main(String[] args) throws Exception {
        new Main().solution();
    }
}</code></pre>
<br>

<hr>
<h3 id="💡-keyword">💡 Keyword</h3>
<p><em>-  BufferedReader, BufferedWriter, StringTokenizer</em>
<em>-  BufferedWriter로 출력시, valueOf로 값 바꿔주기</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코테] 기초 2 - 정수, 문자열, 배열 자료형]]></title>
            <link>https://velog.io/@a_rubz/%EC%BD%94%ED%85%8C-%EA%B8%B0%EC%B4%88-2-%EC%A0%95%EC%88%98-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%B0%B0%EC%97%B4-%EC%9E%90%EB%A3%8C%ED%98%95</link>
            <guid>https://velog.io/@a_rubz/%EC%BD%94%ED%85%8C-%EA%B8%B0%EC%B4%88-2-%EC%A0%95%EC%88%98-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%B0%B0%EC%97%B4-%EC%9E%90%EB%A3%8C%ED%98%95</guid>
            <pubDate>Mon, 03 Apr 2023 09:14:26 GMT</pubDate>
            <description><![CDATA[<h3 id="1-정수"><strong>1. 정수</strong></h3>
<h4 id="1-1-최대-최소">1-1. 최대, 최소</h4>
<pre><code class="language-python">   ans = ???
   for num in arr:
       if ans &gt; num:
        ans = num
   print(ans)</code></pre>
<p>   ans에 들어갈 적절한 값 찾기
   최종 ans는 arr에 있는 값 중 최솟값 찾기</p>
<p>   =&gt; arr에 있는 최댓값보다 큰 수가 저장되도록</p>
<pre><code class="language-python">   import sys
   ans = sys.maxsize</code></pre>
<br>


<h3 id="2-진법">2. 진법</h3>
<h4 id="2-1-10진수--2-8-16진수-변환">2-1. 10진수 =&gt; 2, 8, 16진수 변환</h4>
<pre><code class="language-python">   &gt;&gt;&gt; bin(42) 
&gt;&#39;0b101010&#39; 
&gt;&gt;&gt;&gt; oct(42) 
&gt;&#39;0o52&#39; 
&gt;&gt;&gt;&gt; hex(42) 
&gt;&#39;0x2a&#39;</code></pre>
   <br>

<h4 id="2-2-2-8-16진수--10진수-변환">2-2. 2, 8, 16진수 =&gt; 10진수 변환</h4>
<pre><code class="language-python">   &gt;&gt;&gt; int(&#39;0b111100&#39;, 2) 
&gt; 60
&gt;&gt;&gt; int(&#39;0o74&#39;, 8) 
&gt; 60
&gt;&gt;&gt; int(&#39;0x3c&#39;, 16)
&gt; 60</code></pre>
   <br>


<h3 id="3-문자열">3. 문자열</h3>
<h4 id="3-1-문자열을-거꾸로">3-1. 문자열을 거꾸로</h4>
<pre><code class="language-python">   alph = &quot;ABCD&quot;
alph[::-1]</code></pre>
   <br>

<h4 id="3-2-문자열--아스키코드">3-2. 문자열 &lt;=&gt; 아스키코드</h4>
<pre><code class="language-python"> ord() #문자 =&gt; 아스키코드 
chr() #아스키코드 =&gt; 문자</code></pre>
<br>

<h3 id="4-배열">4. 배열</h3>
<h4 id="4-1-배열-초기화">4-1. 배열 초기화</h4>
<pre><code class="language-python">   3 5 #배열 가로, 세로</code></pre>
<pre><code class="language-python">   N, M = map(int, input().split())
   arr = [[0] * N for _ in range(M)]</code></pre>
   <br>

<h4 id="4-2-배열의-원소를-거꾸로">4-2. 배열의 원소를 거꾸로</h4>
<pre><code class="language-python"> arr.reverse()</code></pre>
<p>=&gt; 반환값 없음</p>
<br>

<h4 id="4-3-배열-원소-갯수">4-3. 배열 원소 갯수</h4>
<pre><code class="language-python">   list.count(찾는 값)</code></pre>
<pre><code class="language-python">   str.count(찾는 값)</code></pre>
 <br>

<h4 id="4-4-원소-중복-제거">4-4. 원소 중복 제거</h4>
<pre><code class="language-python">   alpha = [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;, &#39;d&#39;, &#39;e&#39;, &#39;f&#39;, &#39;g&#39;, &#39;a&#39;, &#39;b&#39;, &#39;c&#39;, &#39;d&#39; ] 
alpha = list(set(alpha)) </code></pre>
<pre><code class="language-python">   #이차원 리스트 중복 제거
   print(list(set(map(tuple, lst))))</code></pre>
   <br>

<h4 id="4-5-배열-정렬">4-5. 배열 정렬</h4>
<pre><code class="language-python">   arr.sort()</code></pre>
<pre><code class="language-python">   #오름차순
   arr.sort(reverse=True)</code></pre>
<pre><code class="language-python">   #배열의 원소가 리스트
   arr.sort(key=lamda x:(x[0], x[1]))</code></pre>
 <br>

<p>출처 - <a href="https://covenant.tistory.com/142">https://covenant.tistory.com/142</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코테] 기초 1 - 입출력 방법]]></title>
            <link>https://velog.io/@a_rubz/%EC%BD%94%ED%85%8C-%EA%B8%B0%EC%B4%88-1-%EC%9E%85%EC%B6%9C%EB%A0%A5-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@a_rubz/%EC%BD%94%ED%85%8C-%EA%B8%B0%EC%B4%88-1-%EC%9E%85%EC%B6%9C%EB%A0%A5-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Mon, 03 Apr 2023 07:44:43 GMT</pubDate>
            <description><![CDATA[<h3 id="1-다양한-입력"><strong>1. 다양한 입력</strong></h3>
<h4 id="1-1-나누어-입력받기">1-1. 나누어 입력받기</h4>
<pre><code class="language-python">   1 2</code></pre>
<pre><code class="language-python">   a, b = map(int, input().split())</code></pre>
<br>

<h4 id="1-2--입력-출력-가속">1-2.  입력 출력 가속</h4>
<p>   =&gt; 입력값이 많은 경우, 빠르게 입력 받기</p>
<pre><code class="language-python">   import sys
   N = int(sys.stdin.readline())
   sys.stdout.write(str(N))</code></pre>
<pre><code class="language-python">   from sys import stdin, stdout
   input = stdin.readline
   print = stdout.write</code></pre>
<br>


<h3 id="2-배열-입력">2. 배열 입력</h3>
<h4 id="2-1-우아한-배열-입력">2-1. 우아한 배열 입력</h4>
<pre><code class="language-python">   3
   1 2 3
   4 5 6
   7 8 9</code></pre>
<pre><code class="language-python">   MAP = [list(map(int, input().split())) for _ in range(int(intput()))]</code></pre>
   <br>

<h4 id="2-2-정수와-배열이-같은-줄에-들어오는-경우">2-2. 정수와 배열이 같은 줄에 들어오는 경우</h4>
<pre><code class="language-python">   4 10 20 30 40
   3 7 5 12
   3 125 15 25</code></pre>
<pre><code class="language-python">   N, *arr = map(int, input().split())</code></pre>
<p>   arr 변수 앞에 *를 붙이면 뒤이어 나오는 값이 arr에 배열로 저장</p>
   <br>

<h4 id="2-3-문자열을-한-글자씩-배열에-저장">2-3. 문자열을 한 글자씩 배열에 저장</h4>
<pre><code class="language-python">   3
   AAAA
   ABCA
   AAAA</code></pre>
<pre><code class="language-python">   arr = [[&#39;A&#39;, &#39;A&#39;, &#39;A&#39;, &#39;A&#39;]
          [&#39;A&#39;, &#39;B&#39;, &#39;C&#39;, &#39;A&#39;]
          [&#39;A&#39;, &#39;A&#39;, &#39;A&#39;, &#39;A&#39;]]</code></pre>
<pre><code class="language-python">   arr = [list(input()) for _ in range(N)]</code></pre>
<br>

<h3 id="3-배열-출력">3. 배열 출력</h3>
<h4 id="3-1-배열을-연결해서-출력-1">3-1. 배열을 연결해서 출력 1</h4>
<pre><code class="language-python">   arr = [1, 2, 3, 4]</code></pre>
<pre><code class="language-python">   1234</code></pre>
<pre><code class="language-python">   print(&quot;&quot;.join(map(str, arr)))</code></pre>
<p>   =&gt; arr의 정수를 string 형식으로 변환 후, 공백 없이 값 연결</p>
   <br>

<h4 id="3-2-배열을-연결해서-출력-2">3-2. 배열을 연결해서 출력 2</h4>
<pre><code class="language-python">   1 2 3 4</code></pre>
<pre><code class="language-python">   print(*arr)</code></pre>
<br>

<p>출처 - <a href="https://covenant.tistory.com/141">https://covenant.tistory.com/141</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 최종 프로젝트 4일 차]]></title>
            <link>https://velog.io/@a_rubz/TIL-%EC%B5%9C%EC%A2%85-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-4%EC%9D%BC-%EC%B0%A8</link>
            <guid>https://velog.io/@a_rubz/TIL-%EC%B5%9C%EC%A2%85-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-4%EC%9D%BC-%EC%B0%A8</guid>
            <pubDate>Thu, 09 Feb 2023 12:53:07 GMT</pubDate>
            <description><![CDATA[<p><em>스파르타 내일배움캠프에서 진행하는 최종 프로젝트 구현 일지를 작성합니다.</em></p>
<h2 id="📋-오늘-한-업무">📋 오늘 한 업무</h2>
<h3 id="최종프로젝트-sa">최종프로젝트 S.A</h3>
<ul>
<li>채팅 구현</li>
</ul>
<br>

<h2 id="🔥-업무-중-이슈-고민--해결">🔥 업무 중 이슈, 고민 (+ 해결)</h2>
<h3 id="stomp">Stomp?</h3>
<blockquote>
<p><strong>Simple Text Oriented Messaging Protocol<br>
WebSocket 위에서 동작하는 프로토콜로써 클라이언트와 서버가 전송할 메세지의 유형, 형식, 내용들을 정의하는 매커니즘<br>
메세지의 헤더에 값을 줄 수 있어 헤더 값을 기반으로 통신 시 인증 처리를 구현할 수 있다.</strong></p>
</blockquote>
<p>Stomp는 pub/sub 구조로 되어있다.</p>
<blockquote>
<p>pub/sub?
메세지를 공급하는 주체와 소비하는 주체를 분리해 제공하는 메세징 방법
Publisher - Topic - Subscriber
Topic : (우체통, 채팅방) 메세지가 담기는 곳
Publisher : (집배원) 메세지를 발행 - 송신
Subscriber : (구독자) 메세지를 구독 - 수신</p>
</blockquote>
<br>

<p>WebSocket만으로 채팅을 구현하면 단순한 통신 구조로 인해 해당 메시지가 어떤 요청인지, 어떻게 처리해야 되는지에 따라 채팅룸과 세션을 하나하나 구현하고 메세지 발송 부분을 관리하는 추가 코드를 구현해야한다.</p>
<p>Stomp를 활용한다면 pub/sub 방식으로 인해서 위의 것들을 더 쉽게 관리할 수 있다!</p>
<br>
<br>

<h2 id="✨-내일-할-일">✨ 내일 할 일!</h2>
<ul>
<li>채팅 기능 백엔드 마무리</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 최종 프로젝트 3일 차]]></title>
            <link>https://velog.io/@a_rubz/TIL-%EC%B5%9C%EC%A2%85-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-3%EC%9D%BC-%EC%B0%A8</link>
            <guid>https://velog.io/@a_rubz/TIL-%EC%B5%9C%EC%A2%85-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-3%EC%9D%BC-%EC%B0%A8</guid>
            <pubDate>Wed, 08 Feb 2023 11:38:47 GMT</pubDate>
            <description><![CDATA[<p><em>스파르타 내일배움캠프에서 진행하는 최종 프로젝트 구현 일지를 작성합니다.</em></p>
<h2 id="📋-오늘-한-업무">📋 오늘 한 업무</h2>
<h3 id="최종프로젝트-sa">최종프로젝트 S.A</h3>
<ul>
<li>채팅 공부 (WebSocket, SockJS, Stomp, Redis ... )</li>
<li>채팅 구현</li>
</ul>
<br>

<h2 id="🔥-업무-중-이슈-고민--해결">🔥 업무 중 이슈, 고민 (+ 해결)</h2>
<p>채팅 서비스 구현에 WebSocket, Stomp, Redis를 사용하기로 했다.</p>
<p>3가지 모두 어디선가 들어는 보기만 해서 하루에 하나씩 정리해보려고 한다!</p>
<h3 id="websocket">WebSocket?</h3>
<blockquote>
<p><strong>기존의 단방향인 HTTP 프로토콜과 호환되어 양방향 통신을 제공하기 위해 개발된 프로토콜<br>
일반 Socket통신과 달리 HTTP 80 Port를 사용해 방화벽에 제약이 없다.<br>
접속까지는 HTTP 프로토콜을 이용하고, 그 이후 통신은 자체적인 WebSocket 프로토콜로 통신한다.</strong></p>
</blockquote>
<p>HTTP 통신은 <strong>반이중 통신(Half Duflex)</strong>로 클라이언트가 요청을 보내면 서버가 응답하고 연결을 끊어낸다.</p>
<p>연결하고 연결을 해제해 효율이 떨어지는 문제를 보완하기 위해 WebSocket이 생겼다!
(사실은 WebSocket 이전에 Polling, Long Polling, Streaming 등의 방식이 있었다.)</p>
<p>WebSocket은 클라이언트가 접속 요청을 하고 서버가 응답을 한 후에 <strong>연결을 계속 유지</strong>하고 클라이언트의 요청이 없어도 데이터를 전송할 수 있다.</p>
<p><strong>실시간성을 보장</strong>해야 하고, <strong>변경사항의 빈도</strong>가 잦다면 WebSocket 사용이 아주 효율적이다.</p>
<br>

<p>그래서 실시간으로 메세지를 주고받는 채팅 기능에는 WebSocket이 적합하다!</p>
<p>하지만 WebSocket만으로 채팅을 구현하기에는 몇 가지 <strong>문제</strong>가 있는데 그 중 3가지만 이야기해보자면 아래와 같다.</p>
<ol>
<li>웹소켓을 지원하지 않는 브라우저가 있음
 =&gt; SockJS로 해결</li>
<li>단 하나의 채팅방만 만들 수 있음</li>
<li>이전의 채팅 내용이 저장되지 않음</li>
</ol>
<br>
<br>

<h2 id="✨-내일-할-일">✨ 내일 할 일!</h2>
<ul>
<li>채팅 기능 구현</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 최종 프로젝트 2일 차]]></title>
            <link>https://velog.io/@a_rubz/TIL-%EC%B5%9C%EC%A2%85-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-2%EC%9D%BC-%EC%B0%A8</link>
            <guid>https://velog.io/@a_rubz/TIL-%EC%B5%9C%EC%A2%85-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-2%EC%9D%BC-%EC%B0%A8</guid>
            <pubDate>Tue, 07 Feb 2023 11:06:03 GMT</pubDate>
            <description><![CDATA[<p><em>스파르타 내일배움캠프에서 진행하는 최종 프로젝트 구현 일지를 작성합니다.</em></p>
<h2 id="📋-오늘-한-업무">📋 오늘 한 업무</h2>
<h3 id="최종프로젝트-sa">최종프로젝트 S.A</h3>
<ul>
<li>Jira로 프로세스 정리</li>
<li>Git Repository 생성 및 프로젝트 구조 생성</li>
<li>역할분배</li>
<li>개발</li>
</ul>
<br>

<h2 id="🔥-업무-중-이슈-고민--해결">🔥 업무 중 이슈, 고민 (+ 해결)</h2>
<h3 id="buildgradle-오류-이슈">build.gradle 오류 이슈</h3>
<h4 id="1-providedruntime">1. providedRuntime</h4>
<p><strong>❌ 에러</strong></p>
<pre><code class="language-bash"># 에러
Could not find method providedRuntime() for arguments [org.springframework.boot:spring-boot-starter-tomcat] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.</code></pre>
<br>

<p><strong>✅ 원인</strong></p>
<pre><code class="language-bash">dependencies {
    providedRuntime &#39;org.springframework.boot:spring-boot-starter-tomcat&#39;
}</code></pre>
<p><code>providedRuntime</code>은 <code>war</code> plugin에서 제공</p>
<br>

<p><strong>💡 해결</strong></p>
<pre><code>plugins{
    id &#39;war&#39;
}</code></pre><p>plugins에 <code>id &#39;war&#39;</code> 추가</p>
<br>

<h4 id="2-compile">2. compile()</h4>
<p><strong>❌ 에러</strong></p>
<pre><code class="language-bash"># 에러
Could not find method compile() for arguments [{group=org.thymeleaf.extras, name=thymeleaf-extras-java8time}] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.</code></pre>
<br>

<p><strong>✅ 원인</strong></p>
<pre><code class="language-bash">dependencies {
    compile group: &#39;org.thymeleaf.extras&#39;, name: &#39;thymeleaf-extras-java8time&#39;
}</code></pre>
<p><code>compile</code>, <code>runtime</code>, <code>testCompile</code>, <code>testRuntime</code>은 Gradle 4.10 (2018.8.27) 이래로 deprecate</p>
<br>

<p><strong>💡 해결</strong></p>
<pre><code class="language-bash">dependencies {
    implementation(&quot;org.thymeleaf.extras:thymeleaf-extras-java8time:3.0.4.RELEASE&quot;)
}</code></pre>
<p>compile을 implementation으로 수정</p>
<br>
<br>

<h2 id="✨-내일-할-일">✨ 내일 할 일!</h2>
<ul>
<li>채팅 기능 공부</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 최종 프로젝트 1일 차]]></title>
            <link>https://velog.io/@a_rubz/TIL-%EC%B5%9C%EC%A2%85-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-1%EC%9D%BC-%EC%B0%A8</link>
            <guid>https://velog.io/@a_rubz/TIL-%EC%B5%9C%EC%A2%85-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-1%EC%9D%BC-%EC%B0%A8</guid>
            <pubDate>Mon, 06 Feb 2023 15:16:35 GMT</pubDate>
            <description><![CDATA[<p><em>스파르타 내일배움캠프에서 진행하는 최종 프로젝트 구현 일지를 작성합니다.</em></p>
<h2 id="📋-오늘-한-업무">📋 오늘 한 업무</h2>
<h3 id="최종프로젝트-sa">최종프로젝트 S.A</h3>
<ul>
<li>팀 규칙 설정</li>
<li>기획 (주제, 기능...)</li>
<li>와이어프레임</li>
<li>ERD</li>
<li>API</li>
<li>MVP SCOPE</li>
</ul>
<br>

<p>[노션 링크]
<a href="https://www.notion.so/fedf7e81c9e9437eb4357f4734304fab">https://www.notion.so/fedf7e81c9e9437eb4357f4734304fab</a></p>
<br>

<h2 id="🔥-업무-중-이슈-고민--해결">🔥 업무 중 이슈, 고민 (+ 해결)</h2>
<h3 id="최종-프로젝트-주제-설정">최종 프로젝트 주제 설정</h3>
<p>최종 프로젝트를 기획하면서 여러 의견들이 나왔다.
다음은 회의에 나온 최종PJT에 쓰고 싶은 주제이다.</p>
<p><strong>[주제]</strong>
클론 (넷플, 인스타, 배민, 당근) / 알림앱 / 반려동물 (반려생활) / 영화 추천 / 노션(블로그) / 테이블링 / 캐치테이블 (식당 웨이팅) / 쇼핑몰 / 심부름 / 운동</p>
<p>여러 의견들이 나왔지만 우리가 공부하고 직접 써보고 싶은 기술에 적절한 주제를 선택하기로 했고 다음은 회의에 언급된 쓰고 싶은 기술들이다.</p>
<br>

<p><strong>[기술]</strong>
WebRTC (캠) / 딥러닝, 머신러닝 / 추천 알고리즘 / 웹소켓 (실시간 통신) / 대용량 트래픽 처리 / 멀티모듈 / OAuth2 / Grafana(성능 지표), nGrinder</p>
<p><strong>WebRTC</strong>를 통해 반려동물 웹캠 서비스도 좋은 아이디어 중 하나였다.
만약 반려동물의 <strong>모션인식</strong>도 가능하다면 반려동물의 행동(물 마시기, 밥 먹기)에 대한 알림을 사용자에게 보내는 기능이 언급되었다.
하지만, 딥러닝 api가 반려동물의 작은 움직임까지 인식할 수 있을만큼 세밀한 동작을 하는지 확신할 수 없어서 보류하게 되었다.</p>
<p><strong>추천 알고리즘</strong>의 경우는 알고리즘 로직을 구현해야했는데 그것보다는 더 백엔드에서 이것만큼은 써봐야한다!라는 기술들 (redis..)에 더 초점을 맞추는 것이 맞다고 생각해 제외되었다.</p>
<p>그리고 마지막으로 나온 것이 <strong>게임 매칭 sns</strong>였다.
인스타와 같은 sns 기능을 기반으로 매칭 서비스를 추가한 것이다.
매칭서비스는 게임의 종류, 인원 등의 조건을 설정한 사용자가 매칭 신청을 하면 동시간대에 매칭을 신청한 사용자 중에서 설정한 조건에 맞는 사용자를 매칭시켜주는 기능이다.
이건 예전에 싸피에서 했던 프로젝트인데 그때 프론트를 맡아 백엔드의 로직은 전혀 몰라서 직접 구현해보고싶었다.
혹시 된다면 그때의 프로젝트보다 더 효율을 높이고 추가 기능도 구현해보고자 한다.</p>
<br>
<br>

<h2 id="✨-내일-할-일">✨ 내일 할 일!</h2>
<ul>
<li>Git Repository 생성</li>
<li>Git Commit Convention Template 설정</li>
<li>Jira 설정</li>
<li>역할 분배</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[WIL] JPA 심화]]></title>
            <link>https://velog.io/@a_rubz/WIL-JPA-%EC%8B%AC%ED%99%94</link>
            <guid>https://velog.io/@a_rubz/WIL-JPA-%EC%8B%AC%ED%99%94</guid>
            <pubDate>Sun, 05 Feb 2023 15:50:18 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-이번-주-한-일">📌 이번 주 한 일</h2>
<ul>
<li>자바 스터디 마무리</li>
<li>JPA 심화 강의</li>
</ul>
<br>

<h2 id="📚-자바-스터디">📚 자바 스터디</h2>
<p>자바 스터디가 드디어 끝났다! 이것이 자바다 책을 처음 샀을 때는 이렇게 두꺼운 책을 언제 다 볼지 걱정이 먼저 앞섰는데 막상 시작하니 너무 유익하고 뿌듯했다. 모든 내용을 블로그에 정리하지 못해서 아쉬울 따름이다. 이 책 다음은 JPA ORM! 이 책도 열심히 공부해서 주니어 개발자로 한걸음 다가가야지!</p>
<br>

<h2 id="💡-나의-회고">💡 나의 회고</h2>
<p>이번 주는 최종프로젝트 주제, 기술 생각을 하느라고 집중이 잘 안 됐다. 심지어 모든 강의를 다 듣지 못해서 프로젝트를 하면서 계속 강의를 들어야한다. 정신차려!!!!!!! 월요일부터 최종프로젝트인데 마지막 프로젝트이니 아쉬움 없이 끝낼 수 있도록 하루하루 집중해야지. 9to9 프로젝트를 하고 그 시간 후에도 못봤던 강의들을 보면서 어떻게 프로젝트에 적용해보면 좋을지 고민해야겠다. 최종 플젝 파이팅!</p>
<br>

<h2 id="🔥-다음-주-할-일">🔥 다음 주 할 일</h2>
<ul>
<li>최종프로젝트 시작!</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[WIL] 심화 프로젝트 마무리 & JPA 심화 1주차]]></title>
            <link>https://velog.io/@a_rubz/WIL-%EC%8B%AC%ED%99%94-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%A7%88%EB%AC%B4%EB%A6%AC-JPA-%EC%8B%AC%ED%99%94-1%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@a_rubz/WIL-%EC%8B%AC%ED%99%94-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%A7%88%EB%AC%B4%EB%A6%AC-JPA-%EC%8B%AC%ED%99%94-1%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Sun, 29 Jan 2023 12:26:58 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-이번-주-한-일">📌 이번 주 한 일</h2>
<ul>
<li>심화 프로젝트 마무리 및 발표</li>
<li>테스트코드 강의</li>
<li>이것이 자바다 스터디</li>
</ul>
<br>

<h2 id="💻-심화-프로젝트-회고">💻 심화 프로젝트 회고</h2>
<p><em>아래는 팀 프로젝트를 마무리하고 포스팅한 링크이다.</em>
<a href="https://velog.io/@a_rubz/TIL-%EC%8B%AC%ED%99%94-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-6%EC%9D%BC-%EC%B0%A8">https://velog.io/@a_rubz/TIL-%EC%8B%AC%ED%99%94-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-6%EC%9D%BC-%EC%B0%A8</a></p>
<p>이번 프로젝트에는 AOP를 활용한 예외처리와 관리자 기능을 구현했다. 추가로 다른 팀원이 맡은 도움 요청 게시판의 기능들도 일부 구현했다.</p>
<p>처음에는 해보지 않은 Spring Security와 JWT를 맡고 싶었지만 이 기능을 해보고 싶은 팀원이 있어서 양보하게 되었고 대신 저번에 했던 예외처리와 함께 관리자 기능 두 가지를 하게 되었다.</p>
<p>예외처리는 저번과 내용은 같지만 도메인에 따라 Exception의 종류를 여러가지로 나눠서 더 다양하게 만들었다. 또한, 파일 분리를 더 체계적으로 했다.</p>
<p>관리자 기능은 Spring Security가 제공하는 @PreAuthorize를 통해서 관리자를 검증했고 이후의 로직은 다른 기능들의 CRUD와 비슷했다.</p>
<p>기존에 했던 것과 같은 기능을 담당해도 좀 더 개선된 로직을 만들기 위해 노력해서 만족스러웠다.</p>
<br>

<p><em>다음의 링크는 프로젝트에 대해 튜터님께서 남겨주신 코멘트의 링크이다.</em>
<a href="https://github.com/quipu1/ZIPSA-HelperPJT/issues/69">https://github.com/quipu1/ZIPSA-HelperPJT/issues/69</a></p>
<p>여기서 특히 인상 깊었던 점은 코드의 중복을 해결하는 부분이었다.</p>
<p>DTO에 모든 객체를 담아서 어쩔 수 없이 서비스단에서 거의 모든 부분에 DB에서 데이터 한 개를 가져오는(GET, findBy..) 로직이 중복된다.</p>
<p>그래서 아예 DTO에 담지 않고 객체 자체를 반환하는 로직을 만들고 이를 의존성 주입을 통해 가져다 쓰도록 하는 방법이었다.</p>
<p>최종 프로젝트에서는 기간이 길어진만큼 코드의 효율에 중점을 두고 더 좋은 코드에 대해 고민하는 시간을 충분히 가져야겠다.</p>
<br>

<h2 id="💡-나의-회고">💡 나의 회고</h2>
<p>이번 프로젝트는 아쉬운 부분이 꽤 됐다. 팀원의 질문을 많이 받았던 게 큰 부분을 차지했는데 이게 알려주기 위해서 해당 문제를 더 깊이 파고들게 되기 때문에 내가 아는 것이 많아져서 좋지만 그런 시간이 길어지면 내가 맡은 부분에 소홀해지게 되었다. 더 좋은 로직을 만들 수 있지 않았을까! 라는 아쉬움이 큰 프로젝트였다.</p>
<p>하여튼 최종은 이런 아쉬움이 적었으면 좋겠고 추가로 더 욕심을 내서 이제까지 한 프로젝트보다 규모를 키우고 싶다. 도메인을 더 다양하게 하거나 새로운 기능을 넣거나 아니면 대규모 트래픽을 다뤄보고싶다.</p>
<p>그래서 남은 기간동안 배웠던 걸 다시 복습하고 하고 싶은 기술에 대해 공부를 열심히 해야겠다! 마지막 프로젝트니 아쉬움이 남지 않도록! 파이팅 파이팅!</p>
<br>

<h2 id="🔥-다음-주-할-일">🔥 다음 주 할 일</h2>
<ul>
<li>알고리즘</li>
<li>JPA 심화 강의</li>
<li>Spring 선발대 수업</li>
<li>이것이 자바다 스터디</li>
<li>JPA 공부</li>
<li>최종프로젝트 주제, 기술 고민</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] JPA 심화 2일 차]]></title>
            <link>https://velog.io/@a_rubz/TIL-JPA-%EC%8B%AC%ED%99%94-2%EC%9D%BC</link>
            <guid>https://velog.io/@a_rubz/TIL-JPA-%EC%8B%AC%ED%99%94-2%EC%9D%BC</guid>
            <pubDate>Sun, 29 Jan 2023 10:31:38 GMT</pubDate>
            <description><![CDATA[<p><em>스파르타 내일배움캠프에서 진행하는 JPA 심화 강의 일지를 작성합니다.</em></p>
<h2 id="📋-오늘-한-업무">📋 오늘 한 업무</h2>
<ol>
<li>이것이 자바다 스터디</li>
<li>테스트코드 강의</li>
</ol>
<br>

<h2 id="🔥-업무-중-이슈-고민--해결">🔥 업무 중 이슈, 고민 (+ 해결)</h2>
<h3 id="객체지향과-관계형-데이터베이스의-패러다임-불일치">객체지향과 관계형 데이터베이스의 패러다임 불일치</h3>
<p>객체지향 프로그래밍을 하면서 자연스럽게 관계형 데이터베이스를 사용했고 두 가지의 미묘함을 느끼고 있었지만 JPA만을 사용했기 때문에 정확히 알지 못했다.</p>
<p>여기서 미묘함이란 것은 개발을 위해 DB모델링을 고려했을 때, 객체의 필드와 DB의 컬럼 사이의 애매함과 PK, FK, 연관관계, 상속에서의 애매함,, 여기서 애매함이라고 표현한 것은 두 가지가 같은 것이 아닌데 JPA로 마치 같은 것처럼 사용하기 때문에 확 와닿지 않기 때문이다.</p>
<p>이번에 JPA 공부를 새롭게 시작했고 평소 느꼈던 이 미묘함이 어디서 나온 것인지를 알 수 있었다.</p>
<br>

<h4 id="패러다임의-불일치">패러다임의 불일치</h4>
<p>먼저, 객체지향 언어로 개발하면 비즈니스 요구사항을 정의한 도메인 모델도 객체로 모델링을 할 수 있는데 객체로 모델링한 이 도메인 모델을 저장할 때 문제가 생긴다.</p>
<p>예를 들어, 유저의 회원 가입에서 회원이라는 도메인을 객체 인스턴스로 생성한 후에 이 객체를 어딘가에 영구적으로 보관해야한다.</p>
<p>이때에 관계형 데이터베이스가 필요하게 된다. </p>
<p>하지만, 관계형 데이터베이스는 데이터 중심으로 구조화되어 있고, 집합적인 사고를 요구한다. 그리고 객체지향에서 이야기하는 추상화, 상속, 다형성 같은 개념이 없다.</p>
<p><strong>객체지향과 관계형 데이터베이스는 지향하는 목적이 서로 달라 둘의 기능과 표현 방법이 다른데 이것을 패러다임 불일치 문제</strong>라고 한다.</p>
<br>

<h4 id="jpa를-통한-문제-해결">JPA를 통한 문제 해결</h4>
<p>패러다임 불일치 문제에는 상속, 연관관계, 객체 그래프 탐색, 비교하기가 있는데 JPA는 이런 패러다임 불일치 문제를 해결해준다. </p>
<p><strong>상속</strong>
객체는 상속 기능이 있지만 DB 테이블에는 없음</p>
<p><strong>연관관계</strong>
객체는 참조를 통해 다른 객체와 연관관계를 가지고 참조에 접근해 연관 객체를 조회함
테이블은 외래키를 사용해 연관관계를 가지고 조인을 사용해 연관된 테이블을 조회함</p>
<p><strong>객체 그래프 탐색</strong>
객체에서 참조를 사용해 연관된 객체를 찾는 것을 객체 그래프 탐색이라고 함
테이블에서는 조인을 통해 연관된 테이블을 조회해야하므로 자유로운 탐색이 어려움</p>
<p><strong>비교</strong>
객체는 동일성 비교(==), 동등성 비교(equals())로 객체의 주소값과 내부 값을 비교함
데이터베이스는 기본 키의 값으로 각 로우를 구분함
같은 객체를 두 번 조회할 경우, 데이터베이스는 같은 것을 두 번 조회해 같은 값이지만 객체는 동등성 비교는 같지만 다른 인스턴스로 설정되어 동일성 비교는 달라짐</p>
<p>위의 문제들은 JPA를 통해 DB와 데이터를 주고받는다면 모두 해결된다!</p>
<br>
<br>

<h2 id="✨-내일-할-일">✨ 내일 할 일!</h2>
<ul>
<li>주말 푹 쉬기</li>
<li>최종 프로젝트 주제, 기술 생각해보기</li>
<li>JPA 공부</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] JPA 심화 1일 차]]></title>
            <link>https://velog.io/@a_rubz/TIL-JPA-%EC%8B%AC%ED%99%94-1%EC%9D%BC</link>
            <guid>https://velog.io/@a_rubz/TIL-JPA-%EC%8B%AC%ED%99%94-1%EC%9D%BC</guid>
            <pubDate>Sun, 29 Jan 2023 10:01:17 GMT</pubDate>
            <description><![CDATA[<p><em>스파르타 내일배움캠프에서 진행하는 JPA 심화 강의 일지를 작성합니다.</em></p>
<h2 id="📋-오늘-한-업무">📋 오늘 한 업무</h2>
<ol>
<li>이것이 자바다 스터디</li>
<li>테스트코드 강의</li>
</ol>
<br>

<h2 id="🔥-업무-중-이슈-고민--해결">🔥 업무 중 이슈, 고민 (+ 해결)</h2>
<h3 id="api란">API란?</h3>
<p>프로그래밍을 공부하면서 API라는 단어를 자주 접했고 백엔드를 맡아 API 개발을 했다.</p>
<p>하지만 사실은 API의 정확한 정의를 잘 몰라 헷갈리는 부분이 있었다.</p>
<p>개발을 하면서 <em>URI를 설정하는 것이 API인가? 아니면 기상청API나 카카오API 등의 제공되는 API를 통해서 여러 기술을 사용할 수 있는데 여기서의 API는 다른 것인가? API의 정의가 여러가지인가?</em> 라는 생각을 했다.</p>
<p>그리고 API란 무엇인지 제대로 알아보고자 했다.</p>
<blockquote>
<p>💡** API란?**
<strong>어떠한 응용프로그램에서 데이터를 주고 받기 위한 방법</strong>
어떤 특정 사이트에서 특정 데이터를 공유할 경우 어떠한 방식으로 정보를 요청해야하는지, 어떤 데이터를 제공받을 수 있는지에 대한 규격들
구현 방식을 알지 못하는 제품 또는 서비스와 통신할 수 있음</p>
</blockquote>
<blockquote>
<p>💡 <strong>URI란?</strong>
<em>Uniform Resource Identifier</em>
<strong>특정 리소스를 식별하는 통합 자원 식별자</strong>
웹 기술에서 사용하는 논리적 또는 물리적 리소스를 식별하는 고유한 문자열 시퀀스</p>
</blockquote>
<p>그러니까 이 정의에 따르면 앞서 말한 URI를 통해 API를 개발할 때의 API와 외부에서 제공되는 API로 여러 기술을 사용할 수 있는 API는 둘 다 그냥 같은 API였던 것!</p>
<p>전자는 자원을 식별해 API를 사용하기 위해 URI를 이용한 것이고,
후자는 외부에서 제공해주는 응용프로그램을 사용할 수 있도록 API를 이용한 것이다.</p>
<p>지금 생각해보면 둘이 똑같은건데 왜 고민했나 싶을 정도의,, 멍청고민,,</p>
<p>그래도 이제부터 제대로 이해했으니까 내가 어떤 걸 만들고 사용하는지 확실히 알아감에 의미를 두자!</p>
<br>
<br>

<h2 id="✨-내일-할-일">✨ 내일 할 일!</h2>
<ul>
<li>이것이 자바다 스터디</li>
<li>테스트코드 강의</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[CH13. 제네릭]]></title>
            <link>https://velog.io/@a_rubz/CH13.-%EC%A0%9C%EB%84%A4%EB%A6%AD</link>
            <guid>https://velog.io/@a_rubz/CH13.-%EC%A0%9C%EB%84%A4%EB%A6%AD</guid>
            <pubDate>Fri, 27 Jan 2023 09:18:39 GMT</pubDate>
            <description><![CDATA[<h2 id="📝-정리">📝 정리</h2>
<h3 id="u131-제네릭이란u"><U>13.1 제네릭이란?</U></h3>
<p>📌 <span style='background-color:#fff5b1'><strong>제네릭(Generic)</strong></span></p>
<ul>
<li><p>결정되지 않은 타입을 파라미터로 처리하고 실제 사용할 때 파라미터를 구체적인 타입으로 대체시키는 기능</p>
</li>
<li><p><code>&lt;T&gt;</code> : T는 타입 파라미터로, 타입이 필요한 자리에 T 사용할 수 있음을 알려주는 역할</p>
</li>
<li><p>타입 파라미터로 명시한 타입은 객체가 생성될 시점에 다른 타입으로 대체됨</p>
</li>
<li><p><span style='background-color:#fff5b1'>타입 파라미터를 대체하는 타입은 클래스 및 인터페이스 (int(기본 타입) 불가 =&gt; Integer(포장 클래스) 가능)</span></p>
</li>
<li><p>변수를 선언할 때와 동일한 타입으로 호출하고 싶으면 생성자 호출 시 생성자에는 타입을 명시하지 않고 &lt;&gt;만 붙일 수 있음. =&gt; <code>Box&lt;String&gt; box = new Box&lt;&gt;();</code> 가능 (new Box&lt;&gt;()의 &lt;&gt; 안에 타입 명시 안 해도 됨) </p>
</li>
</ul>
<br>


<p>📌 <strong>제네릭 예시</strong></p>
<pre><code class="language-java">//상자 안에 어떤 게 들어갈지 처음부터 정할 수 없다! =&gt; 제네릭 이용
public class Box &lt;T&gt; {
    public T content;
}</code></pre>
<pre><code class="language-java">//(1) 박스 안에 문자열 넣기
Box&lt;String&gt; box = new Bow&lt;String&gt;();

//변수 선언 시와 같은 타입으로 호출하고 싶을 경우
//Box&lt;String&gt; box = new Box&lt;&gt;(); 가능

box.content = &quot;박스에 문자열 넣기&quot;;
String content = box.content; //casting 없이 바로 값을 얻을 수 있음</code></pre>
<pre><code class="language-java">//(2) 박스 안에 숫자 넣기
Box&lt;Integer&gt; box = new Box&lt;Integer&gt;(); //Box&lt;int&gt; 불가!

//변수 선언 시와 같은 타입으로 호출하고 싶을 경우
//Box&lt;Integer&gt; box = new Box&lt;&gt;(); 가능

box.content = 100;
int content = box.content; //마찬가지로 casting 없이 바로 값 얻을 수 있음</code></pre>
<br>

<hr>
<h3 id="u132-제네릭-타입u"><U>13.2 제네릭 타입</U></h3>
<p>📌 <span style='background-color:#fff5b1'><strong>제네릭 타입</strong></span></p>
<ul>
<li><p>결정되지 않은 타입을 파라미터로 가지는 클래스와 인터페이스</p>
</li>
<li><p>선언부에 <span style='background-color:#fff5b1'>&lt;&gt;</span>부호, 그 사이에 타입 파라미터</p>
</li>
<li><p>타입 파라미터는 일반적으로 대문자 알파벳 한 글자로 표현 (변수명과 동일한 규칙으로 작성은 가능)</p>
</li>
<li><p><span style='background-color:#fff5b1'>외부에서 제네릭 타입을 사용하려면 타입 파라미터에 구체적은 타입을 지정해야함</span></p>
</li>
<li><p>지정하지 않을 경우, 암묵적으로 Object 타입 사용</p>
</li>
<li><p>타입 파라미터는 기본적으로 Object 타입으로 간주되어 Object의 메소드 호출 가능 (equals()...)</p>
<pre><code class="language-java">public class 클래스명&lt;A, B, ...&gt; {...}
public interface 인터페이스명&lt;A, B, ...&gt; {...}</code></pre>
</li>
</ul>
<br>

<p>📌 <strong>클래스 제네릭 타입 선언 예시</strong></p>
<pre><code class="language-java">//제네릭 타입 클래스
@Getter
@Setter //setter는 지양합시다! 예시라서 편하게 쓰기 위해 추가
public class Product&lt;K, M&gt; {
    private K kind;
    private M model;
}</code></pre>
<pre><code class="language-java">public class GenericExample {
    public static void main(String[] args) {
          //Tv 클래스가 있을 경우
          Product&lt;Tv, String&gt; product1 = new Product&lt;&gt;;

          product1.setKind(new Tv());
          product1.setModel(&quot;스마트 TV&quot;);

          //Car 클래스가 있을 경우
          Product&lt;Car, String&gt; product1 = new Product&lt;&gt;;

          product1.setKind(new Car());
          product1.setModel(&quot;SUV 자동차&quot;);
      }
}</code></pre>
<br>

<p>📌 <strong>인터페이스 제네릭 타입 선언 예시</strong></p>
<pre><code class="language-java">//제너릭 타입 인터페이스
public interface Rentable&lt;P&gt; {
    P rent();
}</code></pre>
<pre><code class="language-java">//Home 클래스가 있을 경우
public class HomeAgency implements Rentable&lt;Home&gt; {
    @Override
    public Home rent() {
        return new Home();
    }
}</code></pre>
<pre><code class="language-java">//Car 클래스가 있을 경우
public class CarAgency implements Rentable&lt;Car&gt; {
    @Override
    public Car rent() {
        return new Car();
    }
}</code></pre>
<pre><code class="language-java">public class GenericExample {
    public static void main(String[] args) {
        HomeAgency homeAgency = new HomeAgency();
        Home home = homeAgency.rent();

        CarAgency carAgency = new CarAgency();
        Car car = carAgency.rent();
    }
}</code></pre>
<br>

<hr>
<h3 id="u133-제네릭-메소드u"><U>13.3 제네릭 메소드</U></h3>
<p>📌 <strong>제네릭 메소드</strong></p>
<ul>
<li>타입 파라미터를 가지고 있는 메소드</li>
<li>타입 파라미터가 메소드 선언부에 정의</li>
<li>리턴 타입 앞에 &lt;&gt;기호, 타입 파라미터 정의하고 <span style='background-color:#fff5b1'>리턴타입과 매개변수 타입에서 사용</span></li>
</ul>
<pre><code class="language-java">//&lt;A, B, ...&gt; =&gt; 타입 파라미터 정의
public &lt;A, B, ...&gt; 리턴타입 메소드명(매개변수, ...) {...}</code></pre>
<br>

<p>📌 <strong>제네릭 메소드 예시</strong></p>
<pre><code class="language-java">public class Box&lt;T&gt; {
    private T t;

    public T get() {
        return t;
    }

    public void set(T t) {
        this.t = t;
    }
}</code></pre>
<pre><code class="language-java">public class GenericExample {
    public static &lt;T&gt; Box&lt;T&gt; boxing(T t) {
        Box&lt;T&gt; box = new Box&lt;T&gt;();
        box.set(t);
        return box;
}

public static void main(String[] args) {
    //제네릭 메소드 호출 (1)
    Box&lt;Integer&gt; box1 = boxing(100);
    int intValue = box1.get();

    //제네릭 메소드 호출 (2)
    Box&lt;Sting&gt; box2 = boxing(&quot;백&quot;);
    String strValue = box2.get();
}</code></pre>
<br>

<hr>
<h3 id="u134-제한된-타입-파라미터u"><U>13.4 제한된 타입 파라미터</U></h3>
<p>📌 <span style='background-color:#fff5b1'><strong>제한된 타입 파라미터(bounded type parameter)</strong></span></p>
<ul>
<li>타입 파라미터를 대체하는 구체적인 타입을 제한할 필요가 있음</li>
<li>제한된 타입 파라미터는 모든 타입으로 대체할 수 없고, 특정 타입과 자식 도는 구현 관계에 있는 타입만 대체할 수 있는 타입 파라미터</li>
<li>상위 타입은 클래스뿐만 아니라 인터페이스도 가능 (인터페이스도 extends, implements X)</li>
</ul>
<pre><code class="language-java">public &lt;T extends 상위타입&gt; 리턴타입 메소드(매개변수, ...) {...}</code></pre>
<br>

<hr>
<h3 id="u135-와일드카드-타입-파라미터u"><U>13.5 와일드카드 타입 파라미터</U></h3>
<p>📌 <span style='background-color:#fff5b1'><strong>와일드카드 타입 파라미터</strong></span></p>
<ul>
<li>제네릭 타입을 매개값이나 리턴 타입으로 사용할 때, 타입 파라미터로 <code>?(와일드카드)</code>를 사용할 수 있음</li>
<li><code>?</code>는 범위에 있는 모든 타입으로 대체할 수 있다는 표시</li>
</ul>
<pre><code class="language-java">//명시된 클래스의 자식 클래스까지만 가능하도록
리턴타입 메소드명(제네릭타입&lt;? extends 클래스&gt; 변수){...}</code></pre>
<pre><code class="language-java">//명시된 클래스의 부모 클래스까지만 가능하도록
리턴타입 메소드명(제네릭타입&lt;? super 클래스&gt; 변수){...}</code></pre>
<pre><code class="language-java">//어떤 타입이든 가능하도록
리턴타입 메소드명(제네릭타입&lt;?&gt; 변수){...}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 심화 프로젝트 6일 차]]></title>
            <link>https://velog.io/@a_rubz/TIL-%EC%8B%AC%ED%99%94-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-6%EC%9D%BC-%EC%B0%A8</link>
            <guid>https://velog.io/@a_rubz/TIL-%EC%8B%AC%ED%99%94-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-6%EC%9D%BC-%EC%B0%A8</guid>
            <pubDate>Wed, 25 Jan 2023 11:28:47 GMT</pubDate>
            <description><![CDATA[<p><em>스파르타 내일배움캠프에서 진행하는 심화 프로젝트 일지를 작성합니다.</em></p>
<h2 id="📋-오늘-한-업무">📋 오늘 한 업무</h2>
<ol>
<li>심화 프로젝트 발표</li>
<li>회고</li>
</ol>
<BR>

<h2 id="💻-spring-심화-프로젝트---호랑이굴">💻 Spring 심화 프로젝트 - 호랑이굴</h2>
<h3 id="📌-프로젝트-소개">📌 프로젝트 소개</h3>
<p>23.01.16 - 23.01.25</p>
<p>  <strong>&quot;간단한 도움이 필요할 때, 심부름 서비스 루비네 집사&quot;</strong></p>
<p>간단한 도움이 필요한 구매자가 도움 글을 게시하면 도움을 줄 헬퍼가 이를 확인한 후 매칭 신청을 합니다.</p>
<p>구매자가 매칭 신청을 확인한 후 이를 수락,거절하여 매칭 결과를 표시합니다. </p>
<p>매칭이 수락된 경우, 도움 글의 상태는 심부름 중으로 변하고 심부름이 마친 후 심부름 끝으로 변합니다.</p>
<p>관리자는 구매자와 헬퍼의 프로필을 관리 할 수 있으며, 구매자가 심부름 요청을 하면 관리자는 승인 및 거절을 할 수 있고, 헬퍼와 구매자가 부적절한 행동을 할 경우 구매자 및 헬퍼 권한을 해제할 수 있습니다.</p>
<br>

<h3 id="📌-github">📌 Github</h3>
<p><a href="https://github.com/quipu1/ZIPSA-HelperPJT">https://github.com/quipu1/ZIPSA-HelperPJT</a></p>
<br>

<h3 id="📌-시연-영상">📌 시연 영상</h3>
<p><a href="https://www.youtube.com/watch?v=Gx3Uzo4izNk">https://www.youtube.com/watch?v=Gx3Uzo4izNk</a></p>
<br>

<h2 id="📝-spring-심화-프로젝트-회고kpt">📝 Spring 심화 프로젝트 회고(KPT)</h2>
<h4 id="-keep-">[ KEEP ]</h4>
<p><strong><em>이번 프로젝트에서 진행한 과정 중 다음 프로젝트에서도 유지했으면 하는 부분, 만족하는 부분</em></strong></p>
<ul>
<li><p>아침 저녁 두번 스크럼 해보기</p>
</li>
<li><p>분담을 적절히 해서 병합하면서 오류를 겪으며 성장했던 경험</p>
</li>
<li><p>Git 통한 협업과 커밋메시지 통일</p>
</li>
<li><p>프로젝트 시작 전 설계하기</p>
</li>
<li><p>오류 발생시, 콘솔의 오류 문구를 잘 확인해 문제 해결하기</p>
</li>
</ul>
<BR>

<h4 id="-problem-">[ PROBLEM ]</h4>
<p>*<em>문제점 : 이번 프로젝트에서 발생한 문제점을 객관적으로 판단
*</em></p>
<ul>
<li><p>추가 기능 구현하지 못한 점</p>
</li>
<li><p>코드 리뷰를 자세히 안했기 때문에 정확하게 자기 외에 코드를 이해 못했다.</p>
</li>
<li><p>테스트코드 미작성</p>
</li>
</ul>
<BR>

<h4 id="-tryfeel-">[ TRY+FEEL ]</h4>
<p><strong><em>다음 프로젝트를 위해 해야 할 노력 + 이번 프로젝트를 통해 느낀 점</em></strong></p>
<ul>
<li><p>필수적인 요구 사항 이외에 추가적인 기능도 고려해보기</p>
</li>
<li><p>포스트맨 팀 스페이스 활용하기</p>
</li>
<li><p>코드 리뷰를 자세히 해서 서로 실력 향상이 될 수 있도록 공유를 한다.</p>
</li>
<li><p>Git commit template, Git Pre-Commit Hooks, lint를 이용해 커밋 메세지 검증해보기</p>
</li>
<li><p>적절한 주석을 통해 서로의 코드 이해 돕기</p>
</li>
<li><p>사용하지 않는 코드(어노테이션, 생성자 등) 정리하기</p>
</li>
</ul>
<br>


<h2 id="✨-내일-할-일">✨ 내일 할 일!</h2>
<ul>
<li>이것이 자바다 스터디</li>
<li>JPA 심화 강의</li>
<li>알고리즘</li>
<li>객체지향의 사실과 오해 읽기</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[WIL] 심화 프로젝트 1주차]]></title>
            <link>https://velog.io/@a_rubz/WIL-%EC%8B%AC%ED%99%94-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-1%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@a_rubz/WIL-%EC%8B%AC%ED%99%94-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-1%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Tue, 24 Jan 2023 18:30:52 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-이번-주-한-일">📌 이번 주 한 일</h2>
<ul>
<li>Spring 심화 프로젝트 구현</li>
<li>발표 준비</li>
</ul>
<br>

<h2 id="💡-나의-회고">💡 나의 회고</h2>
<p>연휴까지 합쳐서 심화 프로젝트의 구현을 모두 마무리 했다. 평일에 다 구현했다고 했지만 영상을 담당하는 팀원이 자잘한 오류들을 계속 발견해서 연휴에도 프로젝트를 수정했다. 연휴에 하는 건 상관이 없지만 내가 맡은 부분을 제대로 체크하지 못해 생긴 일이라 반성했다. 다음엔 진짜 세세한 부분 하나도 놓치지 않고 확인하고 추가로 더 좋은 로직에 대한 고민을 충분히 해야겠다는 생각을 했다. 뭔가 팀원들의 질문을 받으면서 프로젝트를 진행하다보니 내 할 일에 소홀해졌다. 최종 프로젝트에서는 이런 부분들을 보완하고 싶다. 극단적으로는 애매한 질문들,, 혼자서 충분히 찾아보지 않고 질문한다거나 하는 것은 알아서 하세요! 라고 하고 싶은 생각도 들지만,, 그건 오히려 프로젝트 전체의 퀄리티가 낮아질 것 같다. 좋은 방법이 없을까? 요즘 최대의 고민이다! 최종 전까지 이 문제를 깊게 생각해보고 최대한 모두가 좋을 수 있는 방향으로 해나가고 싶다. 암튼 일단은 발표에 집중해야지! 열심히 만들어놓고 제대로 보여주지 못하면 아까우니까! </p>
<br>

<h2 id="🔥-다음-주-할-일">🔥 다음 주 할 일</h2>
<ul>
<li>심화 프로젝트 발표</li>
<li>JPA 심화 강의</li>
<li>최종 프로젝트를 위한 준비
1-이것이 자바다 끝내기
  2-JPA 공부
  3-최종 프로젝트 주제 및 사용할 기술 생각해보기</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 심화 프로젝트 5일 차]]></title>
            <link>https://velog.io/@a_rubz/TIL-%EC%8B%AC%ED%99%94-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-5%EC%9D%BC-%EC%B0%A8</link>
            <guid>https://velog.io/@a_rubz/TIL-%EC%8B%AC%ED%99%94-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-5%EC%9D%BC-%EC%B0%A8</guid>
            <pubDate>Tue, 24 Jan 2023 18:17:15 GMT</pubDate>
            <description><![CDATA[<p><em>스파르타 내일배움캠프에서 진행하는 심화 프로젝트 일지를 작성합니다.</em></p>
<h2 id="📋-오늘-한-업무">📋 오늘 한 업무</h2>
<ol>
<li>심화 프로젝트 마무리</li>
<li>발표 준비</li>
</ol>
<br>

<h2 id="🔥-업무-중-이슈-고민--해결">🔥 업무 중 이슈, 고민 (+ 해결)</h2>
<h3 id="jwt의-로그아웃">JWT의 로그아웃</h3>
<p>이번 프로젝트에서 로그인을 JWT 방식으로 구현했다. 그리고 로그아웃을 구현한 팀원의 코드를 확인해보니 다음과 같았다.</p>
<pre><code class="language-java">//로그아웃
    @GetMapping(&quot;/logout&quot;)
    public ResponseEntity logout(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session != null) {
            session.invalidate(); // 등록된 세션을 삭제한다.
        }
        return new ResponseEntity(&quot;로그아웃 되었습니다.&quot;, HttpStatus.OK);
    }</code></pre>
<br>

<p>JWT 방식이지만 세션의 값을 지워서 로그아웃을 구현했고 의문이 들었다.</p>
<p>JWT의 가장 큰 장점은 다른 DB를 사용할 필요 없이 사용자 인증에 대한 정보가 토큰 자체에 포함되어있어 별도의 인증 저장소가 없다는 점(stateless)이라고 생각한다. 이로 인해서 비용적인 면이나 트래픽에 대한 부담 면에서 장점이라고 보는데 JWT를 썼지만 로그아웃을 위해 Session 저장소를 연결하게 된 것이다.</p>
<br>

<p>JWT의 stateless라는 특성이 장점이지만 단점이 되게 되었다.
stateless 해서 JWT 토큰을 관리할 시스템이 없어 이를 해결하기 위한 또 다른 방법을 도입해야만 했고 우리 팀은 JWT를 사용했지만 session까지 추가로 사용한 것이다.</p>
<p>그리고 이건 좋은 방법이 아니다. 단도직입적으로 그럴거면 JWT 왜 써?,,라는 게 내 입장이다.</p>
<br>

<p>session 없이 이 문제를 해결하는 방법은 몇 가지 있다.</p>
<ol>
<li>토큰의 생명 주기를 굉장히 짧게 하는 방법으로 해당 시간이 지나면 새로운 토큰 생성</li>
<li>시스템에서 최근에 만료된 토큰을 저장</li>
</ol>
<p>하지만, 이 방법을 사용한다고 해도 결국 redis와 같은 인증을 관리하는 곳이 필요하게 되고 JWT의 장점이 발휘되지 못한다.</p>
<br>

<p>결론은 JWT는 장점과 단점이 확고하기 때문에 서비스에 따라 사용을 할지말지 신중하게 결정해야하고 규모가 아주 큰 서비스가 아니라면 session 방식이 더 유효할 수 있다는 점을 명심해야한다.</p>
<p><a href="https://yceffort.kr/2021/05/drawback-of-jwt">https://yceffort.kr/2021/05/drawback-of-jwt</a></p>
<br>
<br>

<h2 id="✨-내일-할-일">✨ 내일 할 일!</h2>
<ul>
<li>프로젝트 찐찐 마무리</li>
<li>연휴 푹 쉬기</li>
<li>최종 프로젝트 고민해보기</li>
<li>부족한 부분 공부!</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 심화 프로젝트 4일 차]]></title>
            <link>https://velog.io/@a_rubz/TIL-%EC%8B%AC%ED%99%94-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-4%EC%9D%BC-%EC%B0%A8</link>
            <guid>https://velog.io/@a_rubz/TIL-%EC%8B%AC%ED%99%94-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-4%EC%9D%BC-%EC%B0%A8</guid>
            <pubDate>Thu, 19 Jan 2023 15:03:48 GMT</pubDate>
            <description><![CDATA[<p><em>스파르타 내일배움캠프에서 진행하는 심화 프로젝트 일지를 작성합니다.</em></p>
<h2 id="📋-오늘-한-업무">📋 오늘 한 업무</h2>
<ol>
<li>심화 프로젝트 기능 구현</li>
</ol>
<ul>
<li>Board 기능 구현 (CRUD + Paging)</li>
<li>MatchBoard, Admin, exception 수정</li>
</ul>
<br>

<h2 id="🔥-업무-중-이슈-고민--해결">🔥 업무 중 이슈, 고민 (+ 해결)</h2>
<h3 id="error-no-property-userroleenum-found-for-type-user">[Error] No property &#39;userRoleEnum&#39; found for type &#39;User&#39;</h3>
<p>구현한 프로젝트를 테스트하기 위해 실행을 하자마자 실행도 안 되고 에러가 발생했다,,
엄청 긴 에러인데 그 중에서 중요한 문구만 가져와봤다.</p>
<p>1.
<code>UnsatisfiedDependencyException: Error creating bean with name &#39;securityConfig&#39; defined in file</code>
...
<code>UnsatisfiedDependencyException: Error creating bean with name &#39;jwtUtil&#39; defined in file</code>
...
<code>Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name &#39;userRepository&#39; defined</code><br>
=&gt; 먼저 userRepository를 시작으로 시큐리티까지 빈 생성에 문제가 생기는 것을 알게 되었다.</p>
<br>

<ol start="2">
<li><code>Failed to create query for method public abstract org.springframework.data.domain.Page com.sparta.zipsa.repository.UserRepository.findByUserRoleEnum(com.sparta.zipsa.entity.UserRoleEnum,org.springframework.data.domain.Pageable); No property &#39;userRoleEnum&#39; found for type &#39;User&#39;</code><br>
=&gt; 가장 중요한 부분이다! UserRepository에 있는 findByUserRoleEnum(...)에서 User에 있는 타입 중에 userRoleEnum을 찾을 수 없다고 한다!</li>
</ol>
<br>

<p>이 문구들을 종합해서 해석하자면 UserRepository에 있는 findByUserRoleEnum(...)이란 메서드는 User라는 객체의 컬럼에 UserRoleEnum이란 것이 없어서 메서드 자체에 문제가 있었고 이 때문에 UserRepository를 빈으로 등록할 수 없게 됐다.
이로 인해서 관련된 여러 부분에서도 Bean 등록에 실패하게 되어 길고 긴 에러가 발생한 것이다.</p>
<br>

<p>다음은 문제의 코드이다.</p>
<p>[UserRepository]</p>
<pre><code class="language-java">@Repository
public interface UserRepository extends JpaRepository&lt;User, Long&gt; {
    Page&lt;User&gt; findByUserRoleEnum(UserRoleEnum role, Pageable pageable);
    ...
}</code></pre>
<p>문제가 되는 findByUserRoleEnum(...)의 UserRoleEnum은 User에 없는 컬럼이라고 한다. 아닌데 분명 있는데! 라고 생각하며 다음의 코드를 확인했다.</p>
<p>[User]</p>
<pre><code class="language-java">@Entity(name = &quot;users&quot;)
public class User {

    ...

    @Column(nullable = false)
    @Enumerated(value = EnumType.STRING)
    private UserRoleEnum role;

    ...
}</code></pre>
<p>UserRoleEnum이 있긴 한데,,, 컬럼명이 아니라 컬럼에 들어오는 데이터들의 타입명이 UserRoleEnum,,,,
다시 말해서, 컬럼명 =&gt; <code>role</code>, 데이터 타입 =&gt; <code>UserRoleEnum</code>인 것이었다.</p>
<p>UserRepository를 다음의 코드로 수정하니 잘 돌아갔다.</p>
<p>[UserRepository]</p>
<pre><code class="language-java">@Repository
public interface UserRepository extends JpaRepository&lt;User, Long&gt; {
    Page&lt;User&gt; findByRole(UserRoleEnum role, Pageable pageable);
    ...
}</code></pre>
<p>이런 약간의 실수로 프로젝트 자체가 실행도 못하게 되다니,, 정말 코딩의 세계는 험난하다,, 앞으로는 익숙한 코드더라도 써지는대로 막 쓰는 게 아니라 이게 어떤 걸 의미하는지 정확하게 생각하면서 작성해야겠다!</p>
<br>
<br>

<h2 id="✨-내일-할-일">✨ 내일 할 일!</h2>
<ul>
<li>프로젝트 오류 수정 및 마무리!</li>
<li>발표 준비</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 심화 프로젝트 3일 차]]></title>
            <link>https://velog.io/@a_rubz/TIL-%EC%8B%AC%ED%99%94-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-3%EC%9D%BC-%EC%B0%A8</link>
            <guid>https://velog.io/@a_rubz/TIL-%EC%8B%AC%ED%99%94-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-3%EC%9D%BC-%EC%B0%A8</guid>
            <pubDate>Wed, 18 Jan 2023 14:28:48 GMT</pubDate>
            <description><![CDATA[<p><em>스파르타 내일배움캠프에서 진행하는 심화 프로젝트 일지를 작성합니다.</em></p>
<h2 id="📋-오늘-한-업무">📋 오늘 한 업무</h2>
<ol>
<li>심화 프로젝트 기능 구현</li>
</ol>
<ul>
<li>@RestControllerAdvice를 활용한 예외처리 구현</li>
<li>관리자 기능들 예외 처리 수정</li>
</ul>
<br>

<h2 id="🔥-업무-중-이슈-고민--해결">🔥 업무 중 이슈, 고민 (+ 해결)</h2>
<h3 id="구현한-기능의-논의가-필요한-점">구현한 기능의 논의가 필요한 점</h3>
<p>현재 내가 담당한 관리자의 기능과 예외처리를 모두 구현했다. 하지만, 세부적인 수정이 필요할 거 같아서 일단 적어뒀고 이를 팀원과 논의해서 결정하려고 한다.</p>
<ol>
<li><p>회원 조회 (페이징) 
⇒ password 때문에 dto로 반환할지 말지 고민 중 (현재 Page<User>로 User 그대로 반환)
⇒ customer 회원 조회, helper 회원 조회를 따로 구현하지 않고 parameter의 role 입력값에 따라 조회의 결과가 달라지도록 구현함</p>
</li>
<li><p>헬퍼 신청서 목록 조회 
⇒ dto로 반환할지는 필요없는 데이터가 있는지에 따라 결정할 예정 (아직 없음)</p>
</li>
<li><p>helper 권한 등록 
⇒ helper 권한 등록 시, helper 신청글을 삭제할까 고민 중
⇒ 신청글에 status 추가해서 신청이 수락되었는지 거절되었는지 확인할 수 있도록 할까도 고민</p>
</li>
<li><p>helper 권한 삭제 
⇒ 권한을 삭제하는게 HELPER→CUSTOMER이라 기능은 삭제지만 PutMapping으로 설정</p>
</li>
</ol>
<br>
<br>

<h2 id="✨-내일-할-일">✨ 내일 할 일!</h2>
<ul>
<li>프로젝트 기능 구현 마무리 (오류 잡기 제외)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 심화 프로젝트 2일 차]]></title>
            <link>https://velog.io/@a_rubz/TIL-%EC%8B%AC%ED%99%94-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-2%EC%9D%BC-%EC%B0%A8</link>
            <guid>https://velog.io/@a_rubz/TIL-%EC%8B%AC%ED%99%94-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-2%EC%9D%BC-%EC%B0%A8</guid>
            <pubDate>Tue, 17 Jan 2023 14:58:43 GMT</pubDate>
            <description><![CDATA[<p><em>스파르타 내일배움캠프에서 진행하는 심화 프로젝트 일지를 작성합니다.</em></p>
<h2 id="📋-오늘-한-업무">📋 오늘 한 업무</h2>
<ol>
<li>심화 프로젝트 기능 구현</li>
</ol>
<ul>
<li>관리자의 role별 유저 조회 기능</li>
<li>관리자의 helper 신청글 조회 기능</li>
<li>관리자의 helper 권한 수락, 삭제 기능</li>
</ul>
<br>

<h2 id="💻-심화-프로젝트-sa-피드백">💻 심화 프로젝트 S.A 피드백</h2>
<p>다음은 심화 프로젝트의 Starting Assignment의 피드백 내용이다.</p>
<blockquote>
<ul>
<li>문서가 벌써부터 틀이 잡혀있고 공유도 잘 되고있는 느낌이라 매우 좋습니당. </li>
</ul>
</blockquote>
<ul>
<li>기능분담도 체계적으로 잘 된것같아서 좋네요. 하지만 서로 체크해주고 같이 고민해주는것 잊지마세용. </li>
<li>매칭 주제정보가 좀더 명확해지면 좋을 것 같습니다.</li>
<li>모든 테이블에 생성일시, 수정일시 필드 추가하는거 검토해주세요.</li>
</ul>
<p>열심히 정리한 내용인데 칭찬 받아서 아주 뿌듯하다!
매칭 주제 정보를 프로젝트 소개 부분에 제대로 정리하지 않았는데 이 부분 수정해야할 거 같고 helper 신청글의 테이블에 생성일시, 수정일시 필드를 추가하기로 했다.</p>
<br>

<h2 id="🔥-업무-중-이슈-고민--해결">🔥 업무 중 이슈, 고민 (+ 해결)</h2>
<h3 id="spring-pageable">Spring Pageable</h3>
<p>오늘 구현한 관리자의 role별 유저 조회 기능에서 페이징을 사용했다.</p>
<blockquote>
<p><strong>페이징(Paging)</strong>
페이징은 <strong>정돈 되어있는</strong> 데이터를 대상으로 데이터베이스에 <strong>한정된 양</strong>의 레코드를 요청하는 것
이렇게 말하면 뭔가 이해가 안 되는데 예시를 들어보자!
게시판에 게시글을 작성일자 순으로 10개씩 나눠 조회
정돈 되어있는 =&gt; 작성일자 순으로 정렬된 / 한정된 양 =&gt; 10개</p>
</blockquote>
<br>

<p>이런 페이징을 스프링 JPA에서 제공하는 Pageable을 통해 간단하게 구현할 수 있다!</p>
<p>Spring JPA에서 JpaRepository의 부모 인터페이스인 PagingAndSortingRepository에서 페이징과 소팅 기능을 제공한다.</p>
<p>이 인터페이스에 명시된 findAll() 메서드의 반환 타입과 파라미터는 페이징 기능의 핵심적인 역할이다.</p>
<ul>
<li><code>org.springframework.data.domain.Pageable</code></li>
<li><code>org.springframework.data.domain.Page</code></li>
</ul>
<p>Pageable: 페이징을 제공하는 중요한 인터페이스
Page: 페이징 findAll()의 기본적인 반환 메서드로 여러 반환 타입 중 하나</p>
<p>JpaRepository&lt;&gt;를 사용할 때, findAll() 메서드를 Pageable 인터페이스로 파라미터를 넘기면 페이징을 사용할 수 있다.</p>
<br>

<p>오늘 작성한 코드의 일부이다.</p>
<p><strong>controller</strong></p>
<pre><code class="language-java">public Page&lt;User&gt; getUserAllByRoll(
        @RequestParam(&quot;page&quot;) int page,
        @RequestParam(&quot;size&quot;) int size,
        @RequestParam(&quot;isAsc&quot;) boolean isAsc,
        @RequestParam(&quot;role&quot;) String role
) {
    return adminService.getUserAllByRole(page, size, isAsc, role);
}</code></pre>
<p>controller단에서는 메소드의 리턴값을 Page 타입으로 받고 메소드의 파라미터로 page(첫 페이지 번호), size(한 페이지에 들어갈 데이터 개수), isAsc(정렬방법)을 통해 페이징의 세부사항을 설정하기 위한 데이터를 받는다.</p>
<br>

<p><strong>service</strong></p>
<pre><code class="language-java">public Page&lt;User&gt; getUserAllByRole(int page, int size, boolean isAsc, String role) {
    //페이징 처리
    //삼항연산자로 true ASC / false DESC 정렬 설정
    //sortBy로 정렬 기준이 되는 property 설정 - id
    Sort.Direction direction = isAsc ? Sort.Direction.ASC : Sort.Direction.DESC;
    Sort sort = Sort.by(direction, &quot;id&quot;);
    Pageable pageable = PageRequest.of(page, size, sort);

    Page&lt;User&gt; users = userRepository.findByUserRoleEnum(pageable, UserRoleEnum.ADMIN);

    return users;
}</code></pre>
<p>service단에서는 입력받은 페이징 세부사항 데이터로 세부사항을 설정한다.
Sort.Direction에서 삼항연산자를 통해 정렬방법을 정한다.
Sort.by(정렬방법, 정렬기준)으로 어떤 데이터를 기준으로 어떻게 정렬할지 결정한다.
Pagable 변수에 page, size, sort값을 넣은 설정값을 해당 repository의 find 메소드에 파라미터로 전달한다.</p>
<br>

<p><strong>repostiory</strong></p>
<pre><code class="language-java">public interface UserRepository extends JpaRepository&lt;User,Long&gt; {
    Page&lt;User&gt; findByUserRoleEnum(UserRoleEnum role, Pageable pagable);
}</code></pre>
<p>repository단에서는 파라미터로 Pageable을 입력받고 상황에 따라 다른 값도 함께 입력받아서 출력할 데이터를 설정한다.</p>
<br>
<br>

<h2 id="✨-내일-할-일">✨ 내일 할 일!</h2>
<ul>
<li>프로젝트 기능 구현 - 예외처리</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 심화 프로젝트 1일 차]]></title>
            <link>https://velog.io/@a_rubz/TIL-%EC%8B%AC%ED%99%94-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-1%EC%9D%BC-%EC%B0%A8</link>
            <guid>https://velog.io/@a_rubz/TIL-%EC%8B%AC%ED%99%94-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-1%EC%9D%BC-%EC%B0%A8</guid>
            <pubDate>Mon, 16 Jan 2023 14:50:06 GMT</pubDate>
            <description><![CDATA[<p><em>스파르타 내일배움캠프에서 진행하는 심화 프로젝트 일지를 작성합니다.</em></p>
<h2 id="📋-오늘-한-업무">📋 오늘 한 업무</h2>
<ol>
<li>심화 프로젝트 S.A</li>
</ol>
<ul>
<li>팀 규칙 설정</li>
<li>프로젝트 기획(프로젝트명, 주제, 기능)</li>
<li>데이터 모델링</li>
<li>API 명세서 작성</li>
<li>프로젝트 구현 일정 계획</li>
<li>역할분담 - (내 역할: 관리자 기능, 예외처리)</li>
<li>Git Repository 생성</li>
</ul>
<br>

<h2 id="💻-심화-프로젝트-sa">💻 심화 프로젝트 S.A</h2>
<p>다음은 심화 프로젝트의 Starting Assignment를 정리한 노션의 링크이다.
<a href="https://skitter-leotard-f46.notion.site/5bb98d3381be413bb4ccea516835ca27">https://skitter-leotard-f46.notion.site/5bb98d3381be413bb4ccea516835ca27</a></p>
<br>

<p>고객-판매자 매칭 서비스가 주어진 주제였고 구체적인 매칭 주제는 자율 결정으로 우리 팀은 심부름 서비스를 주제로 했다.</p>
<p>사용자는 고객, 헬퍼, 관리자로 나뉘고 고객이 도움을 원하는 글을 게시하면 헬퍼는 그 글에 도움 신청글을 남긴다. 고객은 헬퍼들이 남긴 신청글을 여러 기준(글 내용, 도움 횟수 등)을 통해 도움을 받을 헬퍼를 선택한다. 그리고, 헬퍼가 되기 위해서는 회원가입 후 관리자에게 헬퍼 신청글을 남기고 관리자의 승인을 받아야한다.</p>
<p>이번 심화 프로젝트는 기간이 짧아서 많은 기능을 구현할 수 없어 너무 아쉽다. 주제가 너무 마음에 들어서 채팅, 경고, 위치 기반 등의 기능도 추가해서 최종 프로젝트에서 마무리하고 싶다는 생각도 든다.</p>
<br>

<h2 id="🔥-업무-중-이슈-고민--해결">🔥 업무 중 이슈, 고민 (+ 해결)</h2>
<h3 id="개념적-모델링--논리적-모델링--물리적-모델링">개념적 모델링 / 논리적 모델링 / 물리적 모델링</h3>
<p>프로젝트 기획 단계에서 ERD와 프로젝트 기능 순서도(?)를 작성하면서 데이터 모델링에 대한 자료를 접하게 됐다. 어디선가 많이 들어봤지만 정확히 알고 있지 않은 개념이라 이번 기회에 정리해보려 한다.</p>
<blockquote>
<p><strong>개념적 모델링</strong>
개념적 모델링은 <strong>개체와 개체들 간의 관계에서 ER다이어그램을 만드는 과정</strong>이다.
쉽게 말해 Entity를 추출하고 Entity간의 관계를 정의해 표현하는 것이다.<br>
ER Diagram은 개체를 사각형, 객체의 속성을 원, 개체 사이의 관계를 마름모로 표현하고 연결선을 통해 관계를 표현하는 것이다.
예를 들어, 유저와 게시글을 ER Diagram으로 표현하면 아래와 같다.
<img src="https://velog.velcdn.com/images/a_rubz/post/5008ba80-8b26-4495-b855-bbbe99b2b2fa/image.png" alt=""></p>
</blockquote>
<p>이건 귀찮아서 손으로 그렸는데 draw.io 같은 사이트에서 깔끔하게 만들 수 있다.
<br></p>
<blockquote>
<p><strong>논리적 모델링</strong>
논리적 모델링은 <strong>ER 다이어그램을 사용해 관계 스키마 모델을 만드는 과정</strong>이다.
개념적 모델링에서 만든 ER 다이어그램을 사용하려는 DBMS에 맞게 Mapping해 실제 데이터베이스로 구현하기 위한 관계 스키마 모델을 만드는 것이다.<br>
스키마 모델 표현 방법은 테이블 형태와 리스트 형태가 있는데 아래는 리스트형으로 표현했다.
<img src="https://velog.velcdn.com/images/a_rubz/post/7d3bc81f-0962-4347-ae1d-3f6d160950eb/image.png" alt=""></p>
</blockquote>
<p>사실 게시에 대한 중계테이블은 필요 없지만 대충 이런 느낌이다라는 걸 위해 일부러 추가했다.
<br></p>
<blockquote>
<p><strong>물리적 모델링</strong>
물리적 모델링은 <strong>관계 스키마 모델의 물리적 구조를 정의하고 구현하는 과정</strong>이다.
작성된 논리적 모델을 실제로 DB에 저장하기 위한 물리적 구조로 정의하고 구현하는 것이다.<br>
아래는 이번 프로젝트에 사용할 물리적 모델링을 통해 작성한 물리적 모델링 ERD이다.
<img src="https://velog.velcdn.com/images/a_rubz/post/4bac84c8-8416-4523-bd83-7a3b24f56fa4/image.png" alt=""></p>
</blockquote>
<p>이 ERD에 각 컬럼의 최대 길이도 같이 표기해주어야 한다! (예시 varchar(40)) 나중에 추가해줘야지,,</p>
<br>
<br>

<h2 id="✨-내일-할-일">✨ 내일 할 일!</h2>
<ul>
<li>프로젝트 기능 구현</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>