<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jee_ji.log</title>
        <link>https://velog.io/</link>
        <description>열쩡</description>
        <lastBuildDate>Fri, 08 Sep 2023 12:02:20 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>jee_ji.log</title>
            <url>https://velog.velcdn.com/images/jee_ji/profile/399924c6-4e04-4ff6-9d95-4a76ffe2663b/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. jee_ji.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jee_ji" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[클래스, 객체 인스턴스]]></title>
            <link>https://velog.io/@jee_ji/%ED%81%B4%EB%9E%98%EC%8A%A4-%EA%B0%9D%EC%B2%B4-%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4</link>
            <guid>https://velog.io/@jee_ji/%ED%81%B4%EB%9E%98%EC%8A%A4-%EA%B0%9D%EC%B2%B4-%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4</guid>
            <pubDate>Fri, 08 Sep 2023 12:02:20 GMT</pubDate>
            <description><![CDATA[<h2 id="클래스란">클래스란?</h2>
<ul>
<li><p>클래스는 객체를 만들기 위한 일종의 설계 도면이며, 객체의 특성과 동작을 정의한다. </p>
</li>
<li><p>클래스는 데이터와 함수를 묶어 놓은 구조로, 객체를 생성하기 위한 틀이라고 할 수 있습니다.</p>
</li>
</ul>
<h2 id="객체란">객체란?</h2>
<ul>
<li>프로그래밍에서 데이터와 해당 데이터를 조작하기 위한 동작(메서드 또는 함수)을 하나로 묶은 개념이다.</li>
<li>객체는 속성과 기능, 두 종류의 구성요소로 이루어져 있으며, 일반적으로 객체는 다수의 속성과 다수의 기능을 갖는다.</li>
<li>즉, 객체는 속성과 기능의 집합이라고 할 수 있다.</li>
</ul>
<h2 id="인스턴스란">인스턴스란?</h2>
<ul>
<li>인스턴스는 클래스를 기반으로 실제로 메모리에 생성된 객체를 나타낸다. </li>
<li>클래스의 설계에 따라 여러 개의 인스턴스를 생성할 수 있으며, 각각의 인스턴스는 독립적인 데이터와 동작을 가진다.</li>
<li>클래스로부터 객체를 만드는 과정을 클래스의 인스턴스화라고 하며, 어떤 클래스로부터 만들어진 객체를 그 클래스의 인스턴스라고 한다.</li>
</ul>
<h2 id="인스턴스와-객체">인스턴스와 객체</h2>
<ul>
<li>tv클래스로부터 만들어진 객체를 tv 클래스의 인스턴스라고 한다.
결국 인스턴스는 객체와 같은 의미이지만, 객체는 모든 인스턴스를 대표하는 포관적인 의미를 갖고 있으며, 인스턴스는 어떤 클래스로부터 만들어진 것인지를 보다 강조하는 의미를 갖고있다.</li>
<li>예를 들면, &#39;책상은 인스턴스다.&#39;라고 하기 보다는 &#39;책상은 객체다&#39;라는 쪽이, &#39;책상은 책상 클래스의 객체이다&#39; 라고 하기 보다는 &#39;책상은 책상 클래스의 인스턴스다&#39;라고 하는 것이 더 자연스럽다</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] N+1, 프로젝트, 커스텀 어노테이션]]></title>
            <link>https://velog.io/@jee_ji/TIL-N1-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%BB%A4%EC%8A%A4%ED%85%80-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98</link>
            <guid>https://velog.io/@jee_ji/TIL-N1-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%BB%A4%EC%8A%A4%ED%85%80-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98</guid>
            <pubDate>Wed, 09 Aug 2023 16:42:41 GMT</pubDate>
            <description><![CDATA[<p>🙃 프로젝트</p>
<ul>
<li>유저 초대, 권한 부여 기능구현</li>
<li>AOP, Exction 구현</li>
<li>postman으로 테스트</li>
</ul>
<p><a href="https://velog.io/@jee_ji/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Trello">[프로젝트] Trello</a></p>
<br>

<p>🙃 커스텀 어노테이션</p>
<ul>
<li>AOP에서 메서드들을 상황별로 묶어 좀더 효율적으로 할 수 있는 방법을 찾았고 적용해서 AOP 구현 했다.</li>
</ul>
<p><a href="https://velog.io/@jee_ji/Spring-%EC%BB%A4%EC%8A%A4%ED%85%80-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98">[Spring] 커스텀 어노테이션</a></p>
<br>

<p>🙃 N+1</p>
<ul>
<li>UserBoard 엔티티에서 ManyToOne 관계로 User 엔티티를 참조하고 있다.
UserBoard 엔티티에서 userId를 사용해 사용자 ID에 해당하는 보드를 조회하려고 했다.
이럴 경우, 각각의 보드마다 해당 보드의 작성자인 사용자 정보를 가져오기 위해 추가 쿼리를 실행하게 된다.
이로 인해 사용자마다 보드 개수만큼 추가적인 쿼리가 실행되어 N+1 문제가 발생한다.</li>
</ul>
<pre><code class="language-java">public interface UserBoardRepository extends JpaRepository&lt;UserBoard, Long&gt; {
    List&lt;UserBoard&gt; findAllByUserId(Long userId);
}</code></pre>
<ul>
<li>해결 : Fetch join
주어진 사용자 ID에 해당하는 모든 유저보드 엔티티를 가져오면서 작성자 정보를 함께 가져와서 추가적인 쿼리 없이 N+1 문제를 해결할 수 있었다.</li>
</ul>
<pre><code class="language-java">public interface UserBoardRepository extends JpaRepository&lt;UserBoard, Long&gt; {
    @Query(&quot;SELECT ub FROM UserBoard ub JOIN FETCH ub.board WHERE ub.user.id = :userId&quot;)
    List&lt;UserBoard&gt; findAllByUserIdWithUserFetch(Long userId);
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로젝트] Trello]]></title>
            <link>https://velog.io/@jee_ji/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Trello</link>
            <guid>https://velog.io/@jee_ji/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Trello</guid>
            <pubDate>Wed, 09 Aug 2023 16:35:14 GMT</pubDate>
            <description><![CDATA[<h1 id="구현">구현</h1>
<h3 id="보드-관리-기능">보드 관리 기능</h3>
<ul>
<li><input checked="" disabled="" type="checkbox"> 보드 초대<pre><code>  - 특정 사용자들을 해당 보드에 초대시켜 협업을 할 수 있어야 합니다.
  - 보드 생성자만 초대 가능
  - 초대된 유저는 member 적용
  - 초대된 유저는 다시 초대 불가능</code></pre></li>
</ul>
<p>🐾 이메일 인증을 통한 초대를 구현하고 싶었는데 팀 프로젝트이고 일정이 일주일 밖에 되지 않아 아쉽지만 간단하게 구현하기로 했다.
보드 생성자만이 초대를 할 수 있고 초대된 유저는 member로 userBoardRepository에 저장된다.</p>
<br>

<h3 id="추가-기능">추가 기능</h3>
<ul>
<li><input checked="" disabled="" type="checkbox"> 회원 권한 부여<ul>
<li>MEMBER → ADMIN, ADMIN → MEMBER</li>
<li>보드 생성자만 회원 권한 부여 가능</li>
</ul>
</li>
</ul>
<br>

<hr>
<h1 id="이슈">이슈</h1>
<h2 id="🔥-n1">🔥 N+1</h2>
<ul>
<li>UserBoard 엔티티에서 ManyToOne 관계로 User 엔티티를 참조하고 있다.
UserBoard 엔티티에서 userId를 사용해 사용자 ID에 해당하는 보드를 조회하려고 했다.
이럴 경우, 각각의 보드마다 해당 보드의 작성자인 사용자 정보를 가져오기 위해 추가 쿼리를 실행하게 된다. 
이로 인해 사용자마다 보드 개수만큼 추가적인 쿼리가 실행되어 <code>N+1</code> 문제가 발생한다.</li>
</ul>
<pre><code class="language-java">public interface UserBoardRepository extends JpaRepository&lt;UserBoard, Long&gt; {
    List&lt;UserBoard&gt; findAllByUserId(Long userId);
}</code></pre>
<br>

<h3 id="👏🏻-해결">👏🏻 해결</h3>
<ul>
<li>Fetch join<ul>
<li>주어진 사용자 ID에 해당하는 모든 유저보드 엔티티를 가져오면서 작성자 정보를 함께 가져와서 추가적인 쿼리 없이 N+1 문제를 해결할 수 있다.</li>
</ul>
</li>
</ul>
<pre><code class="language-java">public interface UserBoardRepository extends JpaRepository&lt;UserBoard, Long&gt; {
    @Query(&quot;SELECT ub FROM UserBoard ub JOIN FETCH ub.board WHERE ub.user.id = :userId&quot;)
    List&lt;UserBoard&gt; findAllByUserIdWithUserFetch(Long userId);
}</code></pre>
<br>


<h2 id="🔥-aop--커스텀-어노테이션">🔥 AOP &amp; 커스텀 어노테이션</h2>
<ul>
<li><p><a href="https://velog.io/@jee_ji/Spring-%EC%BB%A4%EC%8A%A4%ED%85%80-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98">[Spring] 커스텀 어노테이션</a></p>
</li>
<li><p>처음에는 pointcut을 메서드 별로 사용했는데 너무 비효율적이라는 생각이 들었다.
그리고 상황별로 나눠서 메서드를 묶어 처리하고 싶었다.</p>
</li>
<li><p>찾아보니 커스텀 어노테이션을 통해서 메서드에 어노테이션을 추가해 일괄 처리할 수 있었다.</p>
</li>
</ul>
<h3 id="👏🏻-해결-1">👏🏻 해결</h3>
<ul>
<li>AccessCheck 커스텀 어노테이션을 만들어 일괄 처리 하였다.</li>
</ul>
<pre><code class="language-java">/*ExcludeLogging 어노테이션을 메서드에만 적용할 수 있도록 지정*/
@Target(ElementType.METHOD) 
/*ExcludeLogging 어노테이션이 런타임까지 유지되도록 지정*/
@Retention(RetentionPolicy.RUNTIME) 
public @interface AccessCheck {
}</code></pre>
<pre><code class="language-java">@Pointcut(&quot;@annotation(com.example.tenrello.board.aop.AccessCheck)&quot;)
    private void accessCheckMethods() {
    }

    @Around(&quot;accessCheckMethods()&quot;)
    public Object boardAccessCheck(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();

            User user = (User) joinPoint.getArgs()[0];
            Long boardId = (Long) joinPoint.getArgs()[1];

            Board board = boardService.findByBoard(boardId);

            if (userBoardRepository.findByBoardIdAndUserId(boardId, user.getId()).isEmpty()) {
                log.warn(&quot;초대 받지 못한 유저입니다.&quot;);
                throw new BoardAccessException(&quot;초대 받지 못한 유저입니다.&quot;);
            }

        return joinPoint.proceed();
    }</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] 커스텀 어노테이션]]></title>
            <link>https://velog.io/@jee_ji/Spring-%EC%BB%A4%EC%8A%A4%ED%85%80-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98</link>
            <guid>https://velog.io/@jee_ji/Spring-%EC%BB%A4%EC%8A%A4%ED%85%80-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98</guid>
            <pubDate>Wed, 09 Aug 2023 16:34:17 GMT</pubDate>
            <description><![CDATA[<h1 id="🙃-커스텀-어노테이션">🙃 커스텀 어노테이션</h1>
<h3 id="메타-어노테이션">메타 어노테이션</h3>
<ul>
<li><p><strong>@Retention</strong> : 컴파일러가 어노테이션을 다루는 방법을 기술, 어느 시점까지 영향을 미치는지를 결정</p>
<ul>
<li>RetentionPolicy.SOURCE : 컴파일 전까지만 유효
RetentionPolicy.CLASS : 컴파일러가 클래스를 참조할 때까지 유효
RetentionPolicy.RUNTIME : 컴파일 이후 런타임 시기에도 JVM에 의해 참조가 가능(리플렉션)</li>
</ul>
</li>
<li><p><strong>@Target</strong> : 어노테이션 적용할 위치 선택</p>
<ul>
<li>ElementType.PACKAGE : 패키지 선언
ElementType.TYPE : 타입 선언
ElementType.ANNOTATION_TYPE : 어노테이션 타입 선언
ElementType.CONSTRUCTOR : 생성자 선언
ElementType.FIELD : 멤버 변수 선언
ElementType.LOCAL_VARIABLE : 지역 변수 선언
ElementType.METHOD : 메서드 선언
ElementType.PARAMETER : 전달인자 선언
ElementType.TYPE_PARAMETER : 전달인자 타입 선언
ElementType.TYPE_USE : 타입 선언</li>
</ul>
</li>
<li><p><strong>@Documented</strong> : 해당 어노테이션을 Javadoc에 포함시킴</p>
</li>
<li><p><strong>@Inherited</strong> : 어노테이션의 상속을 가능하게 함</p>
</li>
<li><p><strong>@Repeatable</strong> : Java8 부터 지원하며, 연속적으로 어노테이션을 선언할 수 있게 함</p>
</li>
</ul>
<br>

<h2 id="커스텀-어노테이션-만들기">커스텀 어노테이션 만들기</h2>
<ol>
<li><p>인터페이스 앞에 @를 붙여서 생성할 수 있다.</p>
</li>
<li><p>메타 어노테이션 추가</p>
</li>
<li><p>적용할 어노테이션 추가</p>
</li>
<li><p>변수 추가</p>
</li>
<li><p>적용 하기</p>
</li>
</ol>
<pre><code class="language-java">@RestControllerWithSwagger(value = &quot;RestMemberController&quot;, name = &quot;RestMemberController&quot;)
@RequiredArgsConstructor
@Test1
@RequestMapping(&quot;/member&quot;)
public class RestMemberController {

    private final MemberService memberService;

    @ApiOperation(&quot;멤버 목록 반환&quot;)
    @GetMapping(&quot;/list&quot;)
    public ResponseEntity&lt;String&gt; upload() {
        return ResponseEntity.ok(memberService.getList());
    }

}</code></pre>
<br>
<br>

<h4 id="참고">참고</h4>
<p><a href="https://mangkyu.tistory.com/130">[Java] Custom Annotation(커스텀 어노테이션) 만들기</a>
<a href="https://velog.io/@potato_song/Java-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98-%EC%BB%A4%EC%8A%A4%ED%85%80-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98-%EB%A7%8C%EB%93%A4%EA%B8%B0">[Java] 어노테이션 (+커스텀 어노테이션 만들기)</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 프로젝트, MVC 패턴, 알고리즘]]></title>
            <link>https://velog.io/@jee_ji/TIL-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-MVC-%ED%8C%A8%ED%84%B4-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@jee_ji/TIL-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-MVC-%ED%8C%A8%ED%84%B4-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Wed, 09 Aug 2023 15:25:53 GMT</pubDate>
            <description><![CDATA[<p>🐰 board CRUD 구현</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://velog.io/@jee_ji/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-TrelloBoard">[프로젝트] Trello</a></p>
<br>


<p>📋 CS</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://velog.io/@jee_ji/MBC-%ED%8C%A8%ED%84%B4">MVC 패턴</a></p>
<br>

<p>✏️ 알고리즘</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://github.com/jiinse0/Algorithm">Algorithm</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로젝트] Trello]]></title>
            <link>https://velog.io/@jee_ji/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-TrelloBoard</link>
            <guid>https://velog.io/@jee_ji/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-TrelloBoard</guid>
            <pubDate>Wed, 09 Aug 2023 15:25:32 GMT</pubDate>
            <description><![CDATA[<h3 id="🐾-board-crud-구현">🐾 board CRUD 구현</h3>
<ul>
<li><p>Create
<img src="https://velog.velcdn.com/images/jee_ji/post/791bf628-8641-4325-8a8f-fcc4d899b1f8/image.png" alt=""></p>
</li>
<li><p>Read (사용자가 속한 보드 리스트)
<img src="https://velog.velcdn.com/images/jee_ji/post/9af4edd7-b0af-4958-8f30-0ea22cec8b8d/image.png" alt=""></p>
</li>
</ul>
<ul>
<li>Update
<img src="https://velog.velcdn.com/images/jee_ji/post/29aaad37-724a-4c98-8b8c-4efec0ba4a20/image.png" alt=""></li>
</ul>
<ul>
<li>Delete
<img src="https://velog.velcdn.com/images/jee_ji/post/ee1a3f37-94e9-42ab-a66c-a95e047beda6/image.png" alt=""></li>
</ul>
<br>

<h3 id="api-수정">API 수정</h3>
<table>
<thead>
<tr>
<th align="left">기능</th>
<th align="left">URL</th>
<th align="left">Method</th>
<th align="left">Request</th>
<th align="left">Response</th>
</tr>
</thead>
<tbody><tr>
<td align="left">보드 생성</td>
<td align="left">/api/board</td>
<td align="left">POST</td>
<td align="left">{<br>&quot;title&quot;:&quot;보드 생성&quot;,<br>&quot;description&quot;:&quot;설명&quot;<br>}</td>
<td align="left">{<br>&quot;userId&quot;: 2,<br>&quot;boardId&quot;: 5,<br>&quot;title&quot;: &quot;보드 생성&quot;,<br>&quot;description&quot;: &quot;설명&quot;,<br>&quot;createAt&quot;: &quot;2023-08-09T23:57:42.4182004&quot;,<br>&quot;modifiedAt&quot;: &quot;2023-08-09T23:57:42.4182004&quot;<br>}</td>
</tr>
<tr>
<td align="left">보드 조회</td>
<td align="left">/api/board/include</td>
<td align="left">GET</td>
<td align="left">-</td>
<td align="left">[<br>{<br>&quot;userId&quot;: 2,<br>&quot;boardId&quot;: 1,<br>&quot;title&quot;: &quot;보드 생성&quot;,<br>&quot;description&quot;: &quot;설명&quot;,<br>&quot;createAt&quot;: &quot;2023-08-09T23:10:02.899023&quot;,<br>&quot;modifiedAt&quot;: &quot;2023-08-09T23:10:26.341357&quot;<br>},<br>{<br>&quot;userId&quot;: 2,<br>&quot;boardId&quot;: 5,<br>&quot;title&quot;: &quot;보드 생성&quot;,<br>&quot;description&quot;: &quot;설명&quot;,<br>&quot;createAt&quot;: &quot;2023-08-09T23:57:42.4182004&quot;,<br>&quot;modifiedAt&quot;: &quot;2023-08-09T23:57:42.4182004&quot;<br>}<br>]</td>
</tr>
<tr>
<td align="left">보드 수정</td>
<td align="left">/api/board/{boardId}</td>
<td align="left">PUT</td>
<td align="left">{<br>&quot;title&quot;:&quot;보드 수정&quot;,<br>&quot;description&quot;:&quot;수정수정&quot;<br>}</td>
<td align="left">{<br>&quot;userId&quot;: 2,<br>&quot;boardId&quot;: 5,<br>&quot;title&quot;: &quot;보드 수정&quot;,<br>&quot;description&quot;: &quot;수정수정&quot;,<br>&quot;createAt&quot;: &quot;2023-08-09T23:57:42.4182&quot;,<br>&quot;modifiedAt&quot;: &quot;2023-08-09T23:57:42.4182&quot;<br>}</td>
</tr>
<tr>
<td align="left">보드 삭제</td>
<td align="left">/api/board/{boardId}</td>
<td align="left">DELETE</td>
<td align="left">-</td>
<td align="left">{<br>&quot;msg&quot;: &quot;삭제 되었습니다.&quot;,<br>&quot;statusCode&quot;: 200<br>}</td>
</tr>
</tbody></table>
<br>

<ul>
<li><strong>보드 관리 기능</strong><ul>
<li><input checked="" disabled="" type="checkbox"> 보드 생성</li>
<li><input checked="" disabled="" type="checkbox"> 보드 수정<ul>
<li>보드 이름</li>
<li>배경 색상</li>
<li>설명</li>
</ul>
</li>
<li><input checked="" disabled="" type="checkbox"> 보드 삭제<ul>
<li>생성한 사용자만 삭제를 할 수 있습니다.</li>
</ul>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[MVC 패턴]]></title>
            <link>https://velog.io/@jee_ji/MBC-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@jee_ji/MBC-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Tue, 08 Aug 2023 11:39:38 GMT</pubDate>
            <description><![CDATA[<h1 id="✏️-mvc-패턴">✏️ MVC 패턴</h1>
<blockquote>
<p>Model-View-Controller 의 약어로 애플리케이션을 세 가지 역할로 구분한 개발 방법론</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jee_ji/post/1c13650d-7c3a-43eb-9f8c-b3e1edcf4f7e/image.png" alt=""></p>
<h2 id="model">Model</h2>
<blockquote>
<p>데이터와 비즈니스 로직을 관리한다.</p>
</blockquote>
<ul>
<li><p>데이터는 내부의 상태에 대한 정보를 가질 수도 있고, 모델을 표현하는 이름 속성으로 가질 수 있다.</p>
</li>
<li><p>모델의 상태에 변화가 있을 때 컨트롤러와 뷰에 이를 통보한다.</p>
</li>
<li><p>이와 같은 통보를 통해 뷰는 최신의 결과를 보여줄 수 있고, 컨트롤러는 모델의 변화에 따른 적용 가능한 명령을 추가, 제거, 수정할 수 있다.</p>
</li>
</ul>
<h4 id="규칙">규칙</h4>
<ol>
<li>사용자가 편집하길 원하는 모든 데이터를 가지고 있어야만 한다.</li>
<li>뷰나 컨트롤러에 대해서 어떠한 정보도 알지 말아야 한다.</li>
<li>변경이 일어나면, 변경 통지에 대한 처리 방법을 구현해야 한다.</li>
</ol>
<br>

<h2 id="view">View</h2>
<blockquote>
<p>레이아웃과 화면을 처리한다.</p>
</blockquote>
<ul>
<li>항목이 사용자에게 보여지는 방식을 정의하며, 표시할 데이터를 모델로부터 받는다.</li>
</ul>
<h4 id="규칙-1">규칙</h4>
<ol>
<li>모델이 가지고 있는 정보를 따로 저장해서는 안된다.</li>
<li>모델이나 컨트롤러와 같이 다른 구성 요소를 몰라야 함</li>
<li>변경이 일어나면, 변경 통지에 대한 처리방법을 구현해야 함</li>
</ol>
<br>


<h2 id="controller">Controller</h2>
<blockquote>
<p>앱의 사용자로부터의 입력에 대한 응답으로 모델 및/또는 뷰를 업데이트하는 로직을 포함</p>
</blockquote>
<ul>
<li>입력이 컨트롤러에게 전송되고, 모델을 적당하게 처리한다음, 업데이트된 데이터를 뷰로 전송해서 사용자에게 알려준다.</li>
</ul>
<h4 id="규칙-2">규칙</h4>
<ol>
<li>모델이냐 뷰에 대해서 알고 있어야 함</li>
<li>모델이나 뷰의 변경을 모니터링해야 함</li>
</ol>
<br>

<p><img src="https://velog.velcdn.com/images/jee_ji/post/6f3cc2e3-5bae-428b-ac87-da627919ef97/image.png" alt=""></p>
<ul>
<li>사용자가 Controller를 조작하면 Controller는 Model을 통해 데이터를 가져오고 그 데이터를 바탕으로 View를 통해 시각적 표현을 제어하여 사용자에게 전달하게 된다.</li>
</ul>
<ol>
<li>사용자가 웹사이트에 접속 (Users)</li>
<li>Controller는 사용자가 요청한 웹페이지를 서비스하기 위해서 모델을 후출 (Manipulates)</li>
<li>Model은 데이터베이스나 파일과 같은 데이터 소스를 제어한 후 그 결과를 Return</li>
<li>Controller는 Model이 리턴한 결과를 View에 반영 (Updates)</li>
<li>데이터가 반영된 View는 사용자에게 보여진다. (Sees)</li>
</ol>
<br>


<h2 id="mvc-패턴-방식">MVC 패턴 방식</h2>
<p><img src="https://velog.velcdn.com/images/jee_ji/post/b96e9626-d801-4ede-9e15-e9e5b0f5018f/image.png" alt=""></p>
<ul>
<li>웹브라우저 사용자의 요청을 서블릿이 받고 서블릿은 해당 요청으로 View로 보여줄 것인지 Model로 보낼 것인지를 판단하여 전송한다.
HTML 소스와 JAVA소스를 분리해놓았기 때문에 확장시키기도 쉽고 유지보수 또한 쉽다.</li>
</ul>
<h3 id="장점">장점</h3>
<ul>
<li>디자이너와 개발자의 분업이 가능하며 유지보수 및 확장이 쉬움</li>
</ul>
<h3 id="단점">단점</h3>
<ul>
<li>설계가 어려우며 개발 난이도가 높음</li>
</ul>
<br>

<h2 id="mvc-패턴을-사용해야-하는-이유">MVC 패턴을 사용해야 하는 이유</h2>
<ul>
<li>비즈니스 로직과 UI로직을 분리하여 유지보수를 독립적으로 수행가능</li>
<li>Model과 View가 다른 컴포넌트들에 종속되지 않아 애플리케이션의 확장성, 유연성에 유리함</li>
<li>중복 코딩의 문제점 제거</li>
</ul>
<br>

<h2 id="mvc-패턴의-한계">MVC 패턴의 한계</h2>
<ul>
<li>MVC패턴에서 View는 Controller에 연결되어 화면을 구성하는 단위 요소이므로 다수의 View를 가질 수 있습니다. 
그리고 Model은 Controller를 통해서 View와 연결되지만, Controller에 의해서 하나의 View에 연결될 수 있는 Model도 여러 개가 될 수 있어 View와 Model이 서로 의존성을 띄게 됩니다. 
즉, Controller에 다수의 Model과 View가 복잡하게 연결되어 있는 상황이 발생할 수 도 있습니다.</li>
</ul>
<br>

<h4 id="참고">참고</h4>
<p><a href="https://developer.mozilla.org/ko/docs/Glossary/MVC">MVC</a>
<a href="https://cocoon1787.tistory.com/733">[개발상식] MVC 패턴이란? (Model-View-Controller)</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] Trello 프로젝트, ddl-auto, 알고리즘, DI와 IoC]]></title>
            <link>https://velog.io/@jee_ji/TIL230807</link>
            <guid>https://velog.io/@jee_ji/TIL230807</guid>
            <pubDate>Mon, 07 Aug 2023 16:46:54 GMT</pubDate>
            <description><![CDATA[<p>👏🏻 Trello 프로젝트</p>
<ul>
<li><p>역할 : 보드 생성, 수정, 삭제 및 초대 구현
추가 : ADMIN, MEMBER 역할 부여, 보드 조회</p>
</li>
<li><p>고민해 봐야할 문제 : UserBoard entity에 저장할 권한을 어디서 받아올 것인지, 초대는 어떤 방식을 사용할 것인지? </p>
</li>
</ul>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://velog.io/@jee_ji/1%EC%B0%A8%EC%84%A4%EA%B3%84-Trello-S.A">[1차설계] Trello S.A</a></p>
<BR>

<p>🙃 프로젝트 진행하면서 당연한 이야기지만 테스트를 위해 포스트맨을 처음 사용할 때 mySql 연결 후 사용한다.
평소와 다르지 않은 날이였는데... 분명 그랬는데 처음 보는 에러를 만났다.
db도 drop해보고, 삭제하고 다시 생성도 해보고, MYSQL에서 select database(); 로 계속 확인도 해봤지만 테이블이 생성되지 않으면서 저 에러가 자꾸 생겼다.
그러던 중 ddl-auto를 update가 아닌 none으로 설정한게 생각이 나서 바꿔줬더니 됐었다! 
별거 아닌거에 시간을 너무 잡아먹었지만 이렇게 된거 제대로 알고가자는 마음에 정리해봤다. 
정리하면서 느낀점은 이거!!! 지금 이라도 알아서 참 다행이다! </p>
<pre><code class="language-java">SQL Error: 1146, SQLState: 42S02</code></pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://velog.io/@jee_ji/Spring-ddl-auto-%EC%98%B5%EC%85%98">[Spring] ddl-auto 옵션</a></p>
<br>


<p>✏️ 알고리즘</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://github.com/jiinse0/Algorithm">Algorithm</a></p>
<BR>

<p>📋 CS</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://velog.io/@jee_ji/DI%EC%99%80-IoC">DI와 IoC</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[1차설계] Trello S.A]]></title>
            <link>https://velog.io/@jee_ji/1%EC%B0%A8%EC%84%A4%EA%B3%84-Trello-S.A</link>
            <guid>https://velog.io/@jee_ji/1%EC%B0%A8%EC%84%A4%EA%B3%84-Trello-S.A</guid>
            <pubDate>Mon, 07 Aug 2023 16:41:51 GMT</pubDate>
            <description><![CDATA[<h1 id="🐾-trello-sa">🐾 Trello S.A</h1>
<br>

<h2 id="팀명">팀명</h2>
<ul>
<li>Tenrello</li>
</ul>
<br>

<h2 id="api">API</h2>
<p><img src="https://velog.velcdn.com/images/jee_ji/post/2671b28e-a296-476a-8a2b-04b42f3e8b12/image.png" alt=""><img src="https://velog.velcdn.com/images/jee_ji/post/a3244c62-c867-4242-8d95-c7bba585580c/image.png" alt="">
<img src="https://velog.velcdn.com/images/jee_ji/post/58a3807b-d93d-41e3-9426-a04661ad2fa0/image.png" alt="">
<img src="https://velog.velcdn.com/images/jee_ji/post/a047bf9c-64a8-4a31-8fc4-28ad8b5ae186/image.png" alt=""></p>
<br>

<h2 id="erd">ERD</h2>
<p><img src="https://velog.velcdn.com/images/jee_ji/post/8586b781-733b-4533-b4a8-298a440822bc/image.png" alt=""></p>
<br>

<h2 id="와이어-프레임">와이어 프레임</h2>
<ul>
<li>메인 페이지
<img src="https://velog.velcdn.com/images/jee_ji/post/ecaf5315-49d6-47b2-a917-0e6dc6d720f6/image.png" alt=""></li>
</ul>
<ul>
<li>로그인
<img src="https://velog.velcdn.com/images/jee_ji/post/5f9dc543-cf1f-4a8f-b3b6-f06afc15fe14/image.png" alt=""></li>
</ul>
<ul>
<li>마이 페이지
<img src="https://velog.velcdn.com/images/jee_ji/post/ea8c9c02-884f-4d4d-bc04-4378544a7574/image.png" alt=""></li>
</ul>
<ul>
<li>카드 페이지
<img src="https://velog.velcdn.com/images/jee_ji/post/e7f97e25-121a-4cc4-9982-a7afd622d5f8/image.png" alt=""></li>
</ul>
<br>


<h2 id="🐣-역할">🐣 역할</h2>
<ul>
<li><strong>보드 관리 기능</strong><ul>
<li><input disabled="" type="checkbox"> 보드 생성</li>
<li><input disabled="" type="checkbox"> 보드 수정<ul>
<li>보드 이름</li>
<li>배경 색상</li>
<li>설명</li>
</ul>
</li>
<li><input disabled="" type="checkbox"> 보드 삭제<ul>
<li>생성한 사용자만 삭제를 할 수 있습니다.</li>
</ul>
</li>
<li><input disabled="" type="checkbox"> 보드 초대<ul>
<li>특정 사용자들을 해당 보드에 초대시켜 협업을 할 수 있어야 합니다.</li>
</ul>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[WIL_12]]></title>
            <link>https://velog.io/@jee_ji/WIL12</link>
            <guid>https://velog.io/@jee_ji/WIL12</guid>
            <pubDate>Mon, 07 Aug 2023 16:21:03 GMT</pubDate>
            <description><![CDATA[<p>✏️ 스터디</p>
<ul>
<li>알고리즘 및  CS 스터디를 주 5일 하는중이다. 
알고리즘은 하루에 0Lv을 3-4문제씩 풀고, CS는 목터뷰 면접 질문에서 한문제씩 맡아서 설명해주는 방식으로 진행중이다.
그리고 알고리즘을 벨로그에 하나 하나 정리했는데 <code>백준 허브</code> 확장 프로그램을 이용해서 이제는 깃허브에 자동 커밋된다!!! <code>백준 허브</code> 최고!!</li>
</ul>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://github.com/jiinse0/Algorithm">Algorithm</a></p>
<br>

<p>📋 CS</p>
<ul>
<li>스터디에서 면접 질문 답을 위해 정리하는 과정에서 헷갈리거나 모르는 내용을 알아가는 과정이 굉장히 흥미롭다!</li>
</ul>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://velog.io/@jee_ji/%EB%B0%B0%EC%97%B4-%EC%97%B0%EA%B2%B0-%EB%A6%AC%EC%8A%A4%ED%8A%B8">배열과 연결 리스트 비교</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://velog.io/@jee_ji/CORS">CORS</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://velog.io/@jee_ji/%EC%8B%9C%EA%B0%84%EB%B3%B5%EC%9E%A1%EB%8F%84-%EB%B0%8F-%EA%B3%B5%EA%B0%84%EB%B3%B5%EC%9E%A1%EB%8F%84">시간복잡도 및 공간복잡도</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://velog.io/@jee_ji/DI%EC%99%80-IoC">DI와 IoC</a></p>
<br>

<p>🔥 그 외 AOP, JPA 심화 AWS 등을 들었는데 이것들은 정리가 좀 더 하고 깃허브에 push할 예정이다.</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://velog.io/@jee_ji/Spring-AOP">[Spring] AOP</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://velog.io/@jee_ji/JPA-ORM-%EC%9D%98-%ED%83%84%EC%83%9D-%EB%B0%B0%EA%B2%BD-JDBC-Query-Mapper">[JPA] ORM 의 탄생 배경 (JDBC, Query Mapper)</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] ddl-auto 옵션]]></title>
            <link>https://velog.io/@jee_ji/Spring-ddl-auto-%EC%98%B5%EC%85%98</link>
            <guid>https://velog.io/@jee_ji/Spring-ddl-auto-%EC%98%B5%EC%85%98</guid>
            <pubDate>Mon, 07 Aug 2023 12:00:11 GMT</pubDate>
            <description><![CDATA[<h1 id="🐰-ddl-auto">🐰 ddl-auto</h1>
<blockquote>
<p>데이터베이스 스키마를 자동으로 생성, 수정 또는 삭제하는 기능</p>
</blockquote>
<h2 id="ddl-auto-옵션-종류">ddl-auto 옵션 종류</h2>
<ul>
<li><p><code>create</code> : 기존테이블 삭제 후 다시 생성 (DROP + CREATE)</p>
</li>
<li><p><code>create-drop: create</code> : create와 같으나 종료 시점에 테이블 DROP</p>
</li>
<li><p><code>update</code> : 변경분만 반영 (운영DB 에서는 사용하면 안됨)</p>
</li>
<li><p><code>validate</code> : 엔티티와 테이블이 정상 매핑되었는지만 확인</p>
</li>
<li><p><code>none</code> : 사용하지 않음 (사실상 없는 값이지만 관례상 none이라고 한다.)</p>
</li>
</ul>
<br>

<h2 id="⭐-주의할-점">⭐ 주의할 점</h2>
<ul>
<li><p>운영 장비에서는 절대 create, create-drop, update 사용하면 안된다.</p>
</li>
<li><p>개발 초기 단계는 <code>create</code> 또는 <code>update</code></p>
</li>
<li><p>테스트 서버는 <code>update</code> 또는 <code>validate</code></p>
</li>
<li><p>스테이징과 운영 서버는 <code>validate</code> 또는 <code>none</code></p>
</li>
</ul>
<br>

<p><strong>평소 update를 사용한다. 엔티티의 필드를 삭제한후 실제 테이블을 확인하면 반영되지 않는다. 이유를 알아보자!!</strong> </p>
<h2 id="문제-원인">문제 원인</h2>
<h3 id="update의-특성">update의 특성</h3>
<ul>
<li><p>update 옵션이 엔티티 상태에 따라 테이블을 수정하는 옵션이기 하지만, 칼럼 삭제의 경우에는 해당되지 않는다.</p>
</li>
<li><p>즉 ddl-auth=update 를 통해 칼럼을 삭제할 수 없다.</p>
</li>
</ul>
<h3 id="왜">왜?</h3>
<ul>
<li><p>이러한 동작은 의도된 설계이다.</p>
</li>
<li><p>왜냐하면, 레거시 DB를 사용할 수 있도록 허용한 것이기 때문이다.</p>
</li>
<li><p>즉 과거에 사용하던 DB를 사용할 수 있도록 설계된 사항이다.</p>
</li>
</ul>
<h3 id="해결-방안">해결 방안</h3>
<ol>
<li><p>ddl-auto=create-drop 을 사용한다.</p>
</li>
<li><p>직접 SQL을 작성하여 칼럼 삭제한다.</p>
</li>
<li><p>파일을 DROP 시키고 다시 빌드한다.</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[DI와 IoC]]></title>
            <link>https://velog.io/@jee_ji/DI%EC%99%80-IoC</link>
            <guid>https://velog.io/@jee_ji/DI%EC%99%80-IoC</guid>
            <pubDate>Sat, 05 Aug 2023 17:44:14 GMT</pubDate>
            <description><![CDATA[<h1 id="🐰-ioc-inversion-of-control">🐰 IoC (Inversion of Control)</h1>
<blockquote>
<ul>
<li><code>제어의 역전</code> 이라는 의미로, 말 그대로 메서드나 객체의 호출작업을 개발자가 결정하는 것이 아니라, 외부(프레임워크나 컨테이너)에서 결정되는 것을 의미한다.</li>
</ul>
</blockquote>
<ul>
<li>간단히 말해 <code>제어의 흐름을 바꾼다</code> 라고 한다.</li>
</ul>
<br>

<h3 id="제어가-역전된-경우">제어가 역전된 경우</h3>
<ul>
<li>아래 코드는, <code>A</code> 객체는 <code>B</code> 객체에 의존하고 있다를 보여준다.
제어를 개발자가 관리하고 있다.</li>
</ul>
<pre><code class="language-java">public class A {

    private B b;

    public A() {
        b = new B();
    }
}</code></pre>
<ul>
<li><p>하지만 Spring에서는 @Autowired를 통해 객체를 주입받는다.</p>
<pre><code class="language-java">public class A {
  @Autowired
  private B b;
}</code></pre>
<ul>
<li>B라는 객체가 스프링 컨테이너에게 관리되고 있는 Bean 이라면 @Autowired를 통해 객체를 주입받을 수 있게 된다.
이것은 스프링 컨테이너에서 직접(제어) 객체를 생성하여 해당 객체에 주입 시켜준 것이다.</li>
</ul>
</li>
<li><p><strong>이것이 바로 제어가 역전된 경우다</strong>
개발자가 해야 할 제어를 스프링 컨테이너에서 대신 해주고 있기 때문이다.
이것이 IoC 라는 개념이다.</p>
</li>
</ul>
<br>



<h2 id="장점">장점</h2>
<ul>
<li><p>객체 간 결합도를 낮춘다.</p>
</li>
<li><p>유연한 코드 작성 가능</p>
</li>
<li><p>가독성 증진</p>
</li>
<li><p>코드 중복 방지</p>
</li>
<li><p>유지 보수 용이</p>
</li>
</ul>
<br>


<hr>
<h1 id="🐰-di-dependency-injection">🐰 DI (Dependency Injection)</h1>
<blockquote>
<ul>
<li><code>의존성 주입</code> 이라는 의미로, 클래스 간의 의존성을 줄이기 위해 사용되는 개념이다.</li>
</ul>
</blockquote>
<ul>
<li>스프링이 다른 프레임워크와 차별화되어 제공하는 의존관계 주입 기능</li>
</ul>
<p>🐾 의존성 : 한 클래스가 다른 클래스에 의존하여 해당 클래스의 기능을 사용하거나 데이터를 받아와야 하는 상태를 말한다.</p>
<ul>
<li><p>객체를 직접 생성하는 게 아니라 외부에서 생성한 후 주입 시켜주는 방식이다.</p>
</li>
<li><p>일반적으로 클래스를 설계할 때, 의존성이 높게 구성되어 있다면 코드의 재사용성이 떨어지고 테스트하기도 어려워 진다. 
이런 문제를 해결하기 위해 DI는 의존성을 외부에서 관리하도록 한다. 
즉, 클래스 내부에서 필요로 하는 객체를 직접 생성하는 대신, 외부에서 이를 주입받도록 한다.</p>
</li>
</ul>
<br>

<h2 id="구현-방법">구현 방법</h2>
<ol>
<li><p><strong>생성자 주입 (Constructor Injection)</strong></p>
<ul>
<li><p>생성자를 통해 의존 관계를 주입하는 방법이다.
의존성을 객체를 생성할 때 생성자를 통해 주입한다는 말이다.</p>
</li>
<li><p>객체 생성 시 1회 호출되는 것이 보장된다. 
그렇기 때문에 주입받은 객체가 불변 객체여야 되거나, 반드시 객체의 주입이 필요한 경우에 강제하기 위해 사용할 수 있다.
생성자가 1개만 있을 경우 @Autowired를 생략해도 주입이 가능하다.</p>
</li>
</ul>
</li>
</ol>
<pre><code class="language-java">@Service
public class UserService {

    private UserRepository userRepository;
    private MemberService memberService;

    @Autowired
    public UserService(UserRepository userRepository, MemberService memberService) {
        this.userRepository = userRepository;
        this.memberService = memberService;
    }

}</code></pre>
<br>

<ol start="2">
<li><p><strong>수정자 주입 (Setter Injection)</strong></p>
<ul>
<li><p>필드 값을 변경하는 setter()를 통해서 의존 관계를 주입하는 방법
주입받는 객체가 변경될 가능성이 있는 경우에 사용한다.
선택적인 의존성을 사용할 때 유용하다.
상황에 따라 의존성 주입이 가능하다.</p>
</li>
<li><p>@Autowired로 주입할 대상이 없는 경우에는 오류가 발생한다.
주입할 대상이 없어도 동작하도록 하려면 @Autowired(required = false)를 통해 설정할 수 있다.</p>
</li>
</ul>
</li>
</ol>
<pre><code class="language-java">@Service
public class UserService {

    private UserRepository userRepository;
    private MemberService memberService;

    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Autowired
    public void setMemberService(MemberService memberService) {
        this.memberService = memberService;
    }
}</code></pre>
<br>


<h3 id="생성자-주입을-사용해야-하는-이유">생성자 주입을 사용해야 하는 이유</h3>
<p>최근에 Spring을 포함한 DI 프레임워크의 대부분이 생성자 주입을 권장하고 있다.</p>
<ul>
<li><p><strong>수정자 주입의 단점</strong></p>
<ul>
<li><p>public으로 구현하기 때문에, 관계를 주입받는 객체의 변경 가능성을 열어둔다.
이런 이유 때문에, 수정자 주입 방식은 주입 받는 객체가 변경될 필요성이 있을 때만 사용해야 한다.</p>
</li>
<li><p>변경의 가능성을 열어두면, 다른 곳에서 임의로 객체를 변경할 수 있기 때문에 에러가 발생할 위험이 높다.</p>
</li>
</ul>
</li>
</ul>
<br>

<ul>
<li><p><strong>객체의 불변성을 확보</strong>
 🐾 객체의 불변성을 확보할 수 있다.</p>
<ul>
<li><p>객체의 생성자는, 객체 생성 시 1회만 호출된다는 게 보장되는 특징이 있다.
이 특징 덕분에 주입받은 객체가 불변 객체여야 되거나, 반드시 해당 객체의 주입이 필요한 경우에 사용한다.</p>
</li>
<li><p>생성자로 한번 의존 관계를 주입하면, 생성자는 다시 호출될 일이 없기 때문에 불변 객체를 보장한다.</p>
</li>
</ul>
</li>
</ul>
<br>


<ul>
<li><p><strong>테스트 코드의 작성</strong>
 🐾 테스트 코드의 작성이 용이해진다.</p>
<ul>
<li><p>@Autowired를 사용하여 스프링과 결합하면 테스트가 단위 테스트가 아니고, 테스트 비용이 증가할 수 있다.</p>
</li>
<li><p>컴파일 시점에 객체를 주입받아 테스트 코드를 작성할 수 있으며, 주입하는 객체가 누락된 경우 컴파일 시점에 오류를 발견할 수 있다.</p>
</li>
<li><p>특히 순수 자바로 작성된 테스트 코드에서는 외부 의존성을 모의(Mock) 객체로 대체하여 유닛 테스트를 더 쉽게 수행할 수 있다.</p>
</li>
</ul>
</li>
</ul>
<br>


<ul>
<li><p><strong>final 키워드 작성 및 Lombok 과의 결합</strong>
 🐾 final 키워드를 사용할 수 있고, Lombok과의 결합을 통해 코드를 간결하게 작성할 수 있다</p>
<ul>
<li><p>생성자 주입을 사용하면 필드 객체에 final 키워드를 사용할 수 있으며, 컴파일 시점에 누락된 의존성을 확일할 수 있다.</p>
</li>
<li><p>Lombok의 @RequiredArgsConstructor를 활용하면 간결한 코드 작성이 가능하다.</p>
</li>
</ul>
</li>
</ul>
<br>

<ul>
<li><p><strong>순환 참조 에러 방지</strong></p>
<ul>
<li><p>A객체가 B객체가 서로 참조하고 있을 때 발생한다.</p>
</li>
<li><p>생성자 주입을 사용하면 애플리케이션 구동 시점(객체의 생성 시점)에 순환 참조 에러를 예방한다.</p>
</li>
</ul>
</li>
</ul>
<br>


<h2 id="장점-1">장점</h2>
<ul>
<li><p>모듈 간의 결합도가 낮아지고 유연성이 높아진다.</p>
</li>
<li><p>가독성 및 코드 중복, 유지 보수를 편하게 할 수 있게 한다.</p>
</li>
</ul>
<br>

<hr>
<h2 id="ioc와-di">IoC와 DI</h2>
<ul>
<li>객체지향 프로그래밍의 원리를 따르며, 코드의 결합도를 낮추고 유지 보수성을 향상시키는 데 도움을 준다. 또한 테스트 용이성과 모듈화를 강화하고, 대규모 애플리케이션 개발에서 코드의 복잡성을 관리하는 데 유용하다.</li>
</ul>
<br>
<br>

<h4 id="참고">참고</h4>
<p><a href="https://velog.io/@gillog/Spring-DIDependency-Injection">[Spring] DI, IoC 정리</a>
<a href="https://isoomni.tistory.com/entry/TISPRING-IOC-DI-%EC%A0%95%EC%9D%98-%EC%9E%A5%EC%A0%90">IOC,DI 정의/장점</a>
<a href="https://mangkyu.tistory.com/125">다양한 의존성 주입 방법과 생성자 주입을 사용해야 하는 이유</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[시간복잡도 및 공간복잡도]]></title>
            <link>https://velog.io/@jee_ji/%EC%8B%9C%EA%B0%84%EB%B3%B5%EC%9E%A1%EB%8F%84-%EB%B0%8F-%EA%B3%B5%EA%B0%84%EB%B3%B5%EC%9E%A1%EB%8F%84</link>
            <guid>https://velog.io/@jee_ji/%EC%8B%9C%EA%B0%84%EB%B3%B5%EC%9E%A1%EB%8F%84-%EB%B0%8F-%EA%B3%B5%EA%B0%84%EB%B3%B5%EC%9E%A1%EB%8F%84</guid>
            <pubDate>Fri, 04 Aug 2023 10:51:14 GMT</pubDate>
            <description><![CDATA[<h3 id="복잡도-complexity">복잡도 (Complexity)</h3>
<blockquote>
<p>알고리즘의 성능을 나타내는 지표</p>
</blockquote>
<ul>
<li><p>가독성(Readability)와 다른 의미로 쓰인다.
즉, 코드가 얼마나 복잡하고 알아보기 어려운지를 의미하는 것이 아니라 불특정한 함수의 성능적인 측면에서의 복접도를 의미한다.</p>
</li>
<li><p>시간 복잡도 : 알고리즘의 <strong>수행 시간</strong> 분석</p>
</li>
<li><p>공간 복잡도 : 알고리즘의 <strong>메모리 사용량</strong> 분석</p>
</li>
<li><p>이때, 동일한 기능을 수행하는 알고리즘이 있다면, 일반적으로 복잡도가 낮은 알고리즘이 좋은 알고리즘이다.</p>
</li>
</ul>
<h1 id="🐰-시간-복잡도-time-complexity">🐰 시간 복잡도 (Time Complexity)</h1>
<blockquote>
<p>알고리즘이 작업을 완료하는 데 <strong>걸리는 시간</strong>을 나타낸다.</p>
</blockquote>
<ul>
<li><p>시간 복잡도가 낮다는 말은 알고리즘이 더 빠르고 효율적으로 실행된다는 것을 의미한다.</p>
</li>
<li><p>시간 복잡도는 여러가지 개념이 있지만 그중 <code>worst case</code>를 기준으로 표기하는 빅-오(Big-O) 표기법을 사용한다.
즉, 알고리즘이 작업을 완료하는 데 걸리는 최대 시간을 의미한다.</p>
</li>
<li><p>예를 들어, 시간 복접도가 O(n)인 알고리즘은 입력 크기(n)가 증가함에 따라 실행하는 데 더 오랜 시간이 걸리는 반면, 시간 복잡도가 O(1)인 알고리즘은 입력 크기에 상관없이 실행하는 데 동일한 시간이 걸린다. </p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/jee_ji/post/5cbfcd10-7c3e-4e68-9996-04b1236c4cd6/image.png" alt="">
faster O(1) &lt; O(log n) &lt; O(nlog n) &lt; O(n²) &lt; O(2ⁿ) slower</p>
<p>slower로 갈수록(즉, 오른쪽 방향으로 갈수록) 효율성이 떨어진다.</p>
<br>
<br>

<h1 id="🐰-공간-복잡도-space-complexity">🐰 공간 복잡도 (Space Complexity)</h1>
<blockquote>
<p>알고리즘이 작업을 완료하는 데 필요한 <strong>메모리 양</strong>을 나타낸다.</p>
</blockquote>
<ul>
<li><p>공간 복잡도가 낮다는 말은 알고리즘이 더 효율적이고 더 적은 리소스를 사용한다는 것을 의미한다.</p>
</li>
<li><p>알고리즘이 입력 크기의 함수로서 요구하는 메모리의 양으로 측정된다.</p>
</li>
<li><p>예를 들어, 공간 복잡도가 O(n)인 알고리즘은 입력 크기가 증가함에 따라 더 많은 메모리를 필요로 하는 반면, 공간 복잡도가 O(1)인 알고리즘은 입력 크기에 관계없이 동일한 양의 메모리를 필요로 한다.</p>
</li>
</ul>
<br>

<h2 id="정리">정리</h2>
<ul>
<li>알고리즘을 설계하고 분석할 때 시간 복잡도와 공간 복잡도 모두 중요한 고려 사항이라는 점에 유의해야 한다.
시간 복잡도가 낮은 알고리즘은 실행하는 데 더 많은 메모리가 필요할 수 있지만 공간 복잡도가 낮은 알고리즘은 실행하는 데 더 오래 걸릴 수 있다. 이 두 요소 사이의 균형은 알고리즘의 특정 요구 사항과 사용 가능한 리소스에 따라 달라진다. 최근에는 하드웨어 메모리 용량이 많이 좋아졌기 때문에 시간 복잡도가 우선시 된다.</li>
</ul>
<br>
<br>

<h4 id="참고">참고</h4>
<p><a href="https://dev-cool.tistory.com/19">혼잣말하는 개발자</a>
<a href="https://khys.tistory.com/95">시간 복잡도와 공간 복잡도</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL_230804]]></title>
            <link>https://velog.io/@jee_ji/TIL230804</link>
            <guid>https://velog.io/@jee_ji/TIL230804</guid>
            <pubDate>Thu, 03 Aug 2023 17:35:48 GMT</pubDate>
            <description><![CDATA[<p>🐰 <a href="https://github.com/jiinse0/Algorithm">Algorithm</a></p>
<p>🐰 <a href="https://velog.io/@jee_ji/CORS">CORS</a></p>
<ul>
<li>교차 출처 리소스 공유라는 뜻으로,  브라우저가 보안을 위해 기존 출처의 리소스와 다른 출저의 리소스 접근을 허용/거부하는 정책 입니다.
허용 방안으로는 simple request, preflight request, credential request가 있는데, 대부분 preflight 방법으로 허용합니다. preflight 방법은 클라이언트가 예비 요청을 통해 받아온 서버의 Access-Control-Allow-Origin 헤더의 정보와 본 요청의 origin 헤더를 비교해 같은 출처라면 허용하는 방법입니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 제곱수 판별하기 Java]]></title>
            <link>https://velog.io/@jee_ji/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%A0%9C%EA%B3%B1%EC%88%98-%ED%8C%90%EB%B3%84%ED%95%98%EA%B8%B0-Java</link>
            <guid>https://velog.io/@jee_ji/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%A0%9C%EA%B3%B1%EC%88%98-%ED%8C%90%EB%B3%84%ED%95%98%EA%B8%B0-Java</guid>
            <pubDate>Thu, 03 Aug 2023 12:15:41 GMT</pubDate>
            <description><![CDATA[<h2 id="🐰-문제">🐰 문제</h2>
<ul>
<li>어떤 자연수를 제곱했을 때 나오는 정수를 제곱수라고 합니다. 정수 n이 매개변수로 주어질 때, n이 제곱수라면 1을 아니라면 2를 return하도록 solution 함수를 완성해주세요.</li>
</ul>
<p><strong>제한사항</strong>
1 ≤ n ≤ 1,000,000</p>
<p><strong>입출력 예</strong>
n    result
144    1
976    2</p>
<p><strong>입출력 예 #1</strong></p>
<ul>
<li>144는 12의 제곱이므로 제곱수입니다. 따라서 1을 return합니다.</li>
</ul>
<p><strong>입출력 예 #2</strong></p>
<ul>
<li>976은 제곱수가 아닙니다. 따라서 2를 return합니다.</li>
</ul>
<br>


<h2 id="내-풀이">내 풀이</h2>
<pre><code class="language-java">class Solution {
    public int solution(int n) {

        if((double)Math.sqrt(n) % 1 == 0) {
            return 1;
        }
        return 2;
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[CORS]]></title>
            <link>https://velog.io/@jee_ji/CORS</link>
            <guid>https://velog.io/@jee_ji/CORS</guid>
            <pubDate>Wed, 02 Aug 2023 14:52:20 GMT</pubDate>
            <description><![CDATA[<h1 id="🐰-cors">🐰 CORS</h1>
<blockquote>
<p><strong>교차 출처 리소스 공유</strong> (Cross-Origin Resource Sharing)</p>
</blockquote>
<ul>
<li><p>추가 HTTP 헤더를 사용하여, 한 출처에서 실행중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제</p>
</li>
<li><p>웹 애플리케이션은 리소스가 자신의 출처와 다를 때 교차 출처 HTTP 요청을 실행한다.</p>
</li>
<li><p>쉽게말해 웹사이트가 다른 웹사이트의 자원을 사용할 수 있도록 허용하는 체제이다.</p>
<ul>
<li>예를 들어, A.com이라는 웹사이트에서 B.com이라는 웹사이트의 이미지를 사용하려면 B.com에서 CORS를 설정해야 한다. 이렇게 하면 브라우저가 A.com에서 B.com의 이미지를 안전하게 가져올 수 있다.</li>
</ul>
</li>
</ul>
<br>

<h2 id="출처origin">출처(Origin)</h2>
<p><img src="https://velog.velcdn.com/images/jee_ji/post/9b99fe4e-10ad-4019-85e7-3e8e38292fca/image.png" alt=""></p>
<ul>
<li>출처는 Protocol, Host 그리고 Port까지 모두 합친 것을 의미한다.
브라우저의 개발자 도구 콘솔에서 Location 객체가 가지고 있는 origin 프로퍼티에 접근하여 현재 출처를 알아낼 수도 있다.</li>
</ul>
<br>

<h2 id="작동-원리">작동 원리</h2>
<ul>
<li>다른 출처의 리소스를 요청할 때 HTTP 프로토콜을 사용하여 요청을 보내게 되는데, 이때 브라우저는 요청헤더에 Origin 이라는 필드에 요청을 보내는 출처를 함께 담아서 보낸다.</li>
</ul>
<pre><code>Origin: https://velog.io</code></pre><ul>
<li><p>이후 서버가 요청에 대한 응답을 할 때 응답 헤더의 Access-Countrol-Allow-ORigin 이라는 값에 접근이 허용된 출처를 알려주고 응답을 받은 브라우저는 클라이언트가 보낸 요청의 Origin 과 서버가 보내준 응답을 비교하여 이 응답이 유효한 응답인지 아닌지 결정한다.</p>
</li>
<li><p>CORS 요청에는 <code>단순 요청</code>과 <code>실행 전 요청</code> 두 가지 유형이 있다.</p>
</li>
</ul>
<h3 id="1-단순-요청-simple-request">1. 단순 요청 (Simple Request)</h3>
<ul>
<li>예비 요청(Prefilght)을 생략하고 바로 서버에 본 요청을 한후, 서버가 이에 대한 응답의 헤더에 Access-Control-Allow-Origin 헤더를 보내주면 브라우저가 CORS 정책 위반 여부를 검사하는 검사하는 방식이다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/jee_ji/post/beef0da9-e01b-4bbc-8bbc-836699e0093c/image.png" alt=""></p>
<ul>
<li><p>단순요청은 특정한 조건을 만족하는 경우에만 성립할 수 있다.</p>
<ol>
<li><p>요청 메서드(Method)는 GET, HEAD, POST 중 하나여야 한다.</p>
</li>
<li><p>Content-Type 헤더가 <code>application/x-www-form-urlencoded</code>, <code>multipart/form-data</code>, <code>text/plain</code>중 하나여야한다. 아닐 경우 예비 요청으로 동작된다.</p>
</li>
<li><p><code>Accept</code>, <code>Accept-Language</code>, <code>Content-Language</code>, <code>Content-Type</code>, <code>DPR, Downlink</code>, <code>Save-Data</code>, <code>Viewport-Width</code>, <code>Width</code> 헤더일 경우 에만 적용된다.</p>
</li>
</ol>
</li>
<li><p><strong>예를 들어</strong>, 브라우저에서 웹사이트 A에서 웹사이트 B로 데이터를 가져오려고 할 때, 위의 조건을 모두 만족하면 해당 요청은 &quot;단순 요청&quot;으로 간주되어 별도의 사전 요청(예비 요청)없이 바로 실행된다.</p>
</li>
</ul>
<h3 id="2-예비-요청-preflight-request">2. 예비 요청 (Preflight Request)</h3>
<ul>
<li>예비 요청과 본 요청으로 나누어서 서버로 전송한다.
이때 브라우저가 예비요청을 보내는 것을 Preflight라고 부르며 예비요청은 OPTIONS 메소드를 사용한다. <strong>예비 요청의 역할은 본 요청을 보내기전 브라우저가 요청을 보내는 것이 안전한지 확인하는 것이다.</strong></li>
</ul>
<p><img src="https://velog.velcdn.com/images/jee_ji/post/d5ca5421-dd3b-48da-96a9-13655074f98f/image.png" alt=""></p>
<ul>
<li><p>자바스크립트의 fetch API를 통해 브라우저에게 리소스를 받아오게 하면 브라우저는 서버로 예비요청을 먼저 보내고 서버는 이 예비요청에 대한 응답으로 어떤 것을 허용하고 어떤것을 금지하고 있는지에 대한 정보를 담아서 브라우저로 다시 보내준다.</p>
</li>
<li><p>이후 브라우저는 보낸 요청과 서버가 응답해준 정책을 비교하여 해당 요청이 안전한지 확인하고 본 요청을 보내게 된다. 이후 서버가 본 요청에 대한 응답을 하면 최종적으로 이 응답 데이터를 자바스립트로 넘겨준다.</p>
</li>
</ul>
<h3 id="3-인증된-요청-credentialed-request">3. 인증된 요청 (Credentialed Request)</h3>
<ul>
<li><p>다른 출처간 통신에서 좀 더 보안을 강화하고 싶을 때 사용한다.</p>
</li>
<li><p>기본적으로 제공하는 리소스 요청 API인 XMLHttpRequest 또는 fetch는 별도의 옵션 없이 브라우저의 쿠키 정보나 인증과 관련된 헤더를 함부로 요청에 담지 않는다. 이때 요청에 인증과 관련되 정보를 담을 수 있게 해주는 옵션이 credentials옵션이다.</p>
</li>
</ul>
<table>
<thead>
<tr>
<th align="left">옵션값</th>
<th align="left">설명</th>
</tr>
</thead>
<tbody><tr>
<td align="left">same-origin(기본값)</td>
<td align="left">같은 출처간 요청에만 인증 정보를 담을 수 있다</td>
</tr>
<tr>
<td align="left">include</td>
<td align="left">모든 요청에 인증 정보를 담을 수 있다</td>
</tr>
<tr>
<td align="left">omit</td>
<td align="left">모든 요청에 인증 정보를 담지 않는다</td>
</tr>
</tbody></table>
<ul>
<li><p>만약 same-origin 이나 include와 같은 옵션을 사용하여 리소스 요청에 인증 정보가 포함된다면, 브라우저는 다른 출처의 리소를 요청할 때 Access-Control-Allow-Origin만 확인하는 것이 아니라 다른 조건을 추가로 검사한다.</p>
</li>
<li><p>요청에 인증정보가 담겨있는 상태에서 다른 출처의 리소스를 요청하게 되면 브라우저는 CORS정책 위반 여부를 검사하는 룰에 다음 두가지를 추가하게 된다.</p>
</li>
<li><p>Access-Control-Allow-Origin 에는 모든 요청을 허용하는*을 사용할 수 없으며, 명시적인 URL이어야 한다
응답 헤더에는 반드시 Access-Control-Allow-Credentials:true가 존재해야 한다</p>
</li>
</ul>
<br>

<h2 id="🐾-허용하는-방법">🐾 허용하는 방법</h2>
<ul>
<li><p>서버 측에서 적절한 설정을 해주어야 한다.</p>
</li>
<li><p>서버에서 Access-Control-Allow-Origin 헤더에 허용할 출처를 기재해서 클라이언트에 응답하면 된다.</p>
</li>
</ul>
<pre><code>Access-Control-Allow-Origin: https://example.com</code></pre><ul>
<li>이렇게 하면 <a href="https://example.com%EC%9D%B4%EB%9D%BC%EB%8A%94">https://example.com이라는</a> 출처에서 오는 요청이 허용된다.</li>
</ul>
<br>

<h2 id="🐾-access-control-allow-origin-헤더-세팅">🐾 Access-Control-Allow-Origin 헤더 세팅</h2>
<ul>
<li>JSP / Servlet<pre><code class="language-java">import javax.servlet.*;
</code></pre>
</li>
</ul>
<p>public class CORSInterceptor implements Filter {</p>
<pre><code>private static final String[] allowedOrigins = {
        &quot;http://localhost:3000&quot;, &quot;http://localhost:5500&quot;, &quot;http://localhost:5501&quot;,
        &quot;http://127.0.0.1:3000&quot;, &quot;http://127.0.0.1:5500&quot;, &quot;http://127.0.0.1:5501&quot;
};

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) servletRequest;

    String requestOrigin = request.getHeader(&quot;Origin&quot;);
    if(isAllowedOrigin(requestOrigin)) {
        // Authorize the origin, all headers, and all methods
        ((HttpServletResponse) servletResponse).addHeader(&quot;Access-Control-Allow-Origin&quot;, requestOrigin);
        ((HttpServletResponse) servletResponse).addHeader(&quot;Access-Control-Allow-Headers&quot;, &quot;*&quot;);
        ((HttpServletResponse) servletResponse).addHeader(&quot;Access-Control-Allow-Methods&quot;,
                &quot;GET, OPTIONS, HEAD, PUT, POST, DELETE&quot;);

        HttpServletResponse resp = (HttpServletResponse) servletResponse;

        // CORS handshake (pre-flight request)
        if (request.getMethod().equals(&quot;OPTIONS&quot;)) {
            resp.setStatus(HttpServletResponse.SC_ACCEPTED);
            return;
        }
    }
    // pass the request along the filter chain
    filterChain.doFilter(request, servletResponse);
}

private boolean isAllowedOrigin(String origin){
    for (String allowedOrigin : allowedOrigins) {
        if(origin.equals(allowedOrigin)) return true;
    }
    return false;
}</code></pre><p>}</p>
<pre><code>
- Spring 
```java
// 스프링 서버 전역적으로 CORS 설정
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping(&quot;/**&quot;)
            .allowedOrigins(&quot;http://localhost:8080&quot;, &quot;http://localhost:8081&quot;) // 허용할 출처
            .allowedMethods(&quot;GET&quot;, &quot;POST&quot;) // 허용할 HTTP method
            .allowCredentials(true) // 쿠키 인증 요청 허용
            .maxAge(3000) // 원하는 시간만큼 pre-flight 리퀘스트를 캐싱
    }
}</code></pre><pre><code class="language-java">// 특정 컨트롤러에만 CORS 적용하고 싶을때.
@Controller
@CrossOrigin(origins = &quot;*&quot;, methods = RequestMethod.GET) 
public class customController {

    // 특정 메소드에만 CORS 적용 가능
    @GetMapping(&quot;/url&quot;)  
    @CrossOrigin(origins = &quot;*&quot;, methods = RequestMethod.GET) 
    @ResponseBody
    public List&lt;Object&gt; findAll(){
        return service.getAll();
    }
}</code></pre>
<br>

<h4 id="참고">참고</h4>
<p><a href="https://developer.mozilla.org/ko/docs/Web/HTTP/CORS">교차 출처 리소스 공유 (CORS)</a></p>
<p><a href="https://velog.io/@jimmy0417/WEB-CORS-%EA%B0%9C%EB%85%90%EA%B3%BC-%EC%A0%81%EC%9A%A9-%EB%B0%A9%EB%B2%95">[WEB] CORS 개념 정리</a></p>
<p><a href="https://inpa.tistory.com/entry/WEB-%F0%9F%93%9A-CORS-%F0%9F%92%AF-%EC%A0%95%EB%A6%AC-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95-%F0%9F%91%8F#%EB%8B%A8%EC%88%9C_%EC%9A%94%EC%B2%AD_simple_request">악명 높은 CORS 개념 &amp; 해결법 - 정리 끝판왕</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 문자열안에 문자열 Java]]></title>
            <link>https://velog.io/@jee_ji/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-Java</link>
            <guid>https://velog.io/@jee_ji/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-Java</guid>
            <pubDate>Wed, 02 Aug 2023 12:42:17 GMT</pubDate>
            <description><![CDATA[<h2 id="🐰-문제">🐰 문제</h2>
<ul>
<li>문자열 str1, str2가 매개변수로 주어집니다. str1 안에 str2가 있다면 1을 없다면 2를 return하도록 solution 함수를 완성해주세요.</li>
</ul>
<p><strong>제한사항</strong>
1 ≤ str1의 길이 ≤ 100
1 ≤ str2의 길이 ≤ 100
문자열은 알파벳 대문자, 소문자, 숫자로 구성되어 있습니다.</p>
<p><strong>입출력 예</strong>
str1    str2    result
&quot;ab6CDE443fgh22iJKlmn1o&quot;    &quot;6CD&quot;    1
&quot;ppprrrogrammers&quot;    &quot;pppp&quot;    2
&quot;AbcAbcA&quot;    &quot;AAA&quot;    2</p>
<p><strong>입출력 예 #1</strong></p>
<ul>
<li>&quot;ab6CDE443fgh22iJKlmn1o&quot; str1에 str2가 존재하므로 1을 return합니다.</li>
</ul>
<p><strong>입출력 예 #2</strong></p>
<ul>
<li>&quot;ppprrrogrammers&quot; str1에 str2가 없으므로 2를 return합니다.</li>
</ul>
<p><strong>입출력 예 #3</strong></p>
<ul>
<li>&quot;AbcAbcA&quot; str1에 str2가 없으므로 2를 return합니다.</li>
</ul>
<br>


<h2 id="내-풀이">내 풀이</h2>
<pre><code class="language-java">class Solution {
    public int solution(String str1, String str2) {

            if(str1.contains(str2)) {
                return 1;
            }

        return 2;
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[배열과 연결 리스트, 알고리즘]]></title>
            <link>https://velog.io/@jee_ji/%EB%B0%B0%EC%97%B4%EA%B3%BC-%EC%97%B0%EA%B2%B0-%EB%A6%AC%EC%8A%A4%ED%8A%B8-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@jee_ji/%EB%B0%B0%EC%97%B4%EA%B3%BC-%EC%97%B0%EA%B2%B0-%EB%A6%AC%EC%8A%A4%ED%8A%B8-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Tue, 01 Aug 2023 14:32:13 GMT</pubDate>
            <description><![CDATA[<p>🐰 배열과 연결 리스트 비교</p>
<ul>
<li><p>비교하고 정리하는 과정에서 내가 두리뭉실하게만 알고 있었던 어느 상황에서 써야 더 효율적으로 사용할 수 있는지 시간복잡도를 통해서 보니 확실히 비교할 수 있었다.</p>
</li>
<li><p>비교 정리</p>
<ul>
<li>배열은 정적 자료구조로, 크기를 미리 정해놓고 연속된 메모리에 요소들을 저장합니다. 이로 인해 메모리 상에서 효율적으로 관리되며, 인덱스를 통해 빠르게 요소에 접근할 수 있습니다. 또한 요소를 추가하거나 삭제할 때에는 다른 요소들을 이동시켜야 하므로 O(n) 시간이 걸립니다.
반면, 연결 리스트는 동적 자료구조로, 동적으로 크기가 조절될 수 있습니다. 각 요소는 독립적인 노드로 구성되어 있고, 노드들은 포인터를 통해 서로 연결되어 있습니다. 요소를 추가하거나 삭제할 때에는 단순히 노드의 연결만 조정하면 되기 때문에 O(1) 시간이 걸립니다. 다만 리스트 앞이나 중간에 요소를 추가/삭제하는 경우 노드를 찾는 시간이 추가적으로 필요할 수 있습니다.
결론적으로, 배열은 데이터의 접근, 탐색할 때 유용하고 연결 리스트는 데이터의 추가, 삭제할 때 유용하게 사용됩니다.</li>
</ul>
</li>
</ul>
<p><a href="https://velog.io/@jee_ji/%EB%B0%B0%EC%97%B4-%EC%97%B0%EA%B2%B0-%EB%A6%AC%EC%8A%A4%ED%8A%B8">배열과 연결 리스트 비교</a></p>
<br>

<p>🐰 플러스 과제</p>
<p><img src="https://velog.velcdn.com/images/jee_ji/post/175f8fb4-cb5c-45e3-901a-420499e9cc37/image.png" alt=""></p>
<ul>
<li><p>이 중 Error 메시지 관리와 예외 공통화 처리를 이런식으로 하는게 맞는지 좀 더 효율적인 방법은 없는지에 대해 고민을 많이하고 검색도 많이했지만 내가 할 수 있는 최선이였다.
이 부분에 대해서는 튜터님에게 물어보기!!</p>
</li>
<li><p>PostServiceImpl</p>
<pre><code class="language-java">public Post findPost(Long id) {
      return postRepository.findById(id).orElseThrow(
              () -&gt; new NotFoundException(messageSource.getMessage(
                      &quot;not.found.post&quot;,
                      null,
                      &quot;Not Found Post&quot;,
                      Locale.getDefault()
              ))
      );
  }</code></pre>
</li>
<li><p>GlobalExceptionHandler</p>
</li>
</ul>
<pre><code class="language-java">@ExceptionHandler({NotFoundException.class})
    public ResponseEntity&lt;StatusResponseDto&gt; notFoundProductExceptionHandler(NotFoundException ex) {
        StatusResponseDto statusResponseDto = new StatusResponseDto(ex.getMessage(), HttpStatus.NOT_FOUND.value());
        return new ResponseEntity&lt;&gt;(
                statusResponseDto,
                HttpStatus.NOT_FOUND
        );
    }</code></pre>
<ul>
<li>NotFoundException</li>
</ul>
<pre><code class="language-java">public class NotFoundException extends RuntimeException{
    public NotFoundException(String message) {
        super(message);
    }
}</code></pre>
<ul>
<li>messages.properties<pre><code class="language-java">not.found.post = 해당 게시글이 존재하지 않습니다.
</code></pre>
</li>
</ul>
<p>//나머지 부분 생략</p>
<p>```</p>
<br>

<p>🐰 알고리즘</p>
<ol>
<li><p><a href="https://velog.io/@jee_ji/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%82%BC%EA%B0%81%ED%98%95%EC%9D%98-%EC%99%84%EC%84%B1%EC%A1%B0%EA%B1%B4-1-Java">[프로그래머스] 삼각형의 완성조건 (1) Java</a></p>
</li>
<li><p><a href="https://velog.io/@jee_ji/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%B5%9C%EB%8C%93%EA%B0%92-%EB%A7%8C%EB%93%A4%EA%B8%B0-1-Java">[프로그래머스] 최댓값 만들기 (1) Java</a></p>
<ul>
<li>삼각형의 완성조건과 최댓값 만들기는 둘 다 비슷한 결이라서 Arrays.sort()를 이용해 문제해결을 했다. </li>
</ul>
</li>
<li><p><a href="https://velog.io/@jee_ji/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%88%A8%EC%96%B4%EC%9E%88%EB%8A%94-%EC%88%AB%EC%9E%90%EC%9D%98-%EB%8D%A7%EC%85%88-1-Java">[프로그래머스] 숨어있는 숫자의 덧셈 (1) Java</a></p>
<ul>
<li>지금까지 사용한 함수를 적절히 사용해서 풀어야 하는 느낌이였다.
첫 시도때는 string을 정수로 바꿀 생각만 했었다.
그 결과, 입출력 예 #1 에서 1+2+3+4가 아닌 1234+1234+... 이런식으로 계속 string의 길이만큼 더해져서 4936 가 나왔다...</li>
<li>최종적으로 split을 이용해 하나 하나 자르고 배열에 저장한뒤 향상된 포문에서 Integer.parseInt()를 사용해 정수로 바꿔 더해줬다.</li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 숨어있는 숫자의 덧셈 (1) Java]]></title>
            <link>https://velog.io/@jee_ji/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%88%A8%EC%96%B4%EC%9E%88%EB%8A%94-%EC%88%AB%EC%9E%90%EC%9D%98-%EB%8D%A7%EC%85%88-1-Java</link>
            <guid>https://velog.io/@jee_ji/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%88%A8%EC%96%B4%EC%9E%88%EB%8A%94-%EC%88%AB%EC%9E%90%EC%9D%98-%EB%8D%A7%EC%85%88-1-Java</guid>
            <pubDate>Tue, 01 Aug 2023 13:12:54 GMT</pubDate>
            <description><![CDATA[<h2 id="🐰-문제">🐰 문제</h2>
<ul>
<li>문자열 my_string이 매개변수로 주어집니다. my_string안의 모든 자연수들의 합을 return하도록 solution 함수를 완성해주세요.</li>
</ul>
<p><strong>제한사항</strong>
1 ≤ my_string의 길이 ≤ 1,000
my_string은 소문자, 대문자 그리고 한자리 자연수로만 구성되어있습니다.</p>
<p><strong>입출력 예</strong>
my_string    result
&quot;aAb1B2cC34oOp&quot;    10
&quot;1a2b3c4d123&quot;    16</p>
<p><strong>입출력 예 #1</strong></p>
<ul>
<li>&quot;aAb1B2cC34oOp&quot;안의 한자리 자연수는 1, 2, 3, 4 입니다. 따라서 1 + 2 + 3 + 4 = 10 을 return합니다.</li>
</ul>
<p><strong>입출력 예 #2</strong></p>
<ul>
<li>&quot;1a2b3c4d123Z&quot;안의 한자리 자연수는 1, 2, 3, 4, 1, 2, 3 입니다. 따라서 1 + 2 + 3 + 4 + 1 + 2 + 3 = 16 을 return합니다.</li>
</ul>
<p><strong>유의사항</strong></p>
<ul>
<li>연속된 숫자도 각각 한 자리 숫자로 취급합니다.</li>
</ul>
<br>

<h2 id="내-풀이">내 풀이</h2>
<ul>
<li><p>첫 시도</p>
<pre><code class="language-java">class Solution {
  public int solution(String my_string) {
      int answer = 0;

      my_string = my_string.replaceAll(&quot;[a-zA-Z]&quot;, &quot;&quot;);
      int num = Integer.parseInt(my_string);

      for (int i = 0; i &lt; my_string.length(); i++) {
          answer += num;
      }

      return answer;
  }
}</code></pre>
</li>
<li><p>최종 풀이</p>
<pre><code class="language-java">class Solution {
  public int solution(String my_string) {
      int answer = 0;

      my_string = my_string.replaceAll(&quot;[a-zA-Z]&quot;, &quot;&quot;);
      String[] string = my_string.split(&quot;&quot;);

      for(String i : string) {
          answer += Integer.parseInt(i);
      }

      return answer;
  }
}</code></pre>
</li>
</ul>
<p>🐾 첫 시도때는 string을 정수로 바꿀 생각만 했었다.
그 결과, 입출력 예 #1 에서 1+2+3+4가 아닌 1234+1234+... 이런식으로 계속 string의 길이만큼 더해져서 4936 가 나왔다...<del>정신차려</del></p>
<p>🐾 여러 단계를 걸쳤지만 생략하고 최종적으로 split을 이용해 하나 하나 자르고 배열에 저장한뒤 향상된 포문에서 Integer.parseInt()를 사용해 정수로 바꿔 더해줬다. 성공!!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 최댓값 만들기 (1) Java]]></title>
            <link>https://velog.io/@jee_ji/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%B5%9C%EB%8C%93%EA%B0%92-%EB%A7%8C%EB%93%A4%EA%B8%B0-1-Java</link>
            <guid>https://velog.io/@jee_ji/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%B5%9C%EB%8C%93%EA%B0%92-%EB%A7%8C%EB%93%A4%EA%B8%B0-1-Java</guid>
            <pubDate>Tue, 01 Aug 2023 12:43:34 GMT</pubDate>
            <description><![CDATA[<h2 id="🐰-문제">🐰 문제</h2>
<ul>
<li>정수 배열 numbers가 매개변수로 주어집니다. numbers의 원소 중 두 개를 곱해 만들 수 있는 최댓값을 return하도록 solution 함수를 완성해주세요.</li>
</ul>
<p><strong>제한사항</strong>
0 ≤ numbers의 원소 ≤ 10,000
2 ≤ numbers의 길이 ≤ 100</p>
<p><strong>입출력 예</strong>
numbers    result
[1, 2, 3, 4, 5]    20
[0, 31, 24, 10, 1, 9]    744</p>
<p><strong>입출력 예 #1</strong></p>
<ul>
<li>두 수의 곱중 최댓값은 4 * 5 = 20 입니다.</li>
</ul>
<p><strong>입출력 예 #1</strong></p>
<ul>
<li>두 수의 곱중 최댓값은 31 * 24 = 744 입니다.</li>
</ul>
<br>

<h2 id="내-풀이">내 풀이</h2>
<pre><code class="language-java">import java.util.*;

class Solution {
    public int solution(int[] numbers) {

        Arrays.sort(numbers);

        return numbers[numbers.length-1] * numbers[numbers.length-2];
    }
}</code></pre>
]]></description>
        </item>
    </channel>
</rss>