<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>yang_11.log</title>
        <link>https://velog.io/</link>
        <description>-</description>
        <lastBuildDate>Sat, 02 Sep 2023 13:49:21 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>yang_11.log</title>
            <url>https://velog.velcdn.com/images/yang_11/profile/83efb0ef-b1a2-4651-84b7-b8ca91b6d8ef/image.jfif</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. yang_11.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/yang_11" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[엑셀 다운로드 기능 시 마주한 에러]]]></title>
            <link>https://velog.io/@yang_11/%EC%97%91%EC%85%80-%EB%8B%A4%EC%9A%B4%EB%A1%9C%EB%93%9C-%EA%B8%B0%EB%8A%A5-%EC%8B%9C-%EB%A7%88%EC%A3%BC%ED%95%9C-%EC%97%90%EB%9F%AC</link>
            <guid>https://velog.io/@yang_11/%EC%97%91%EC%85%80-%EB%8B%A4%EC%9A%B4%EB%A1%9C%EB%93%9C-%EA%B8%B0%EB%8A%A5-%EC%8B%9C-%EB%A7%88%EC%A3%BC%ED%95%9C-%EC%97%90%EB%9F%AC</guid>
            <pubDate>Sat, 02 Sep 2023 13:49:21 GMT</pubDate>
            <description><![CDATA[<blockquote>

<p>엑셀 다운로드 기능을 구현하는 상황에 마주하였다.</p>
<p><em>&quot;다운로드 폴더에 저장하는 기능을 구현해야지&quot;</em></p>
<p>그 때 나는 막연히, 비동기 통신(ajax)으로 개발하면 어떨까 생각하였다.</p>
<p>그런데 ajax 통신을 송신하여도 Controller로 전송은 잘되지만, 계속 에러가 발생하였다. </p>
<p>답답한 나는 원인이 무엇인지 파고들었다. </p>
<p>기본적으로 파일을 다운로드 하는 기능의 경우 ajax를 사용하지 못한다고 한다. 
  </blockquote></p>
<p><strong>그렇다고..? 그러면 그러한 이유는?</strong></p>
<blockquote>

<p>ajax를 사용할 경우 파일 다운로드 응답을 브라우저에서 처리하지 않고 </p>
<p>ajax 내부에서 처리하기 때문에 브라우저에서의 파일 다운로드 사용이 불가능하다.</p>
<p>그러므로 submit, a태그 등의 동기 통신으로 처리해야 한다. </p>
</blockquote>]]></description>
        </item>
        <item>
            <title><![CDATA[[데이터베이스 여러 개 쓸 때, 어느 DataSource를 쓰는지 확인하는 방법]]]></title>
            <link>https://velog.io/@yang_11/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EC%97%AC%EB%9F%AC-%EA%B0%9C-%EC%93%B8-%EB%95%8C-%EC%96%B4%EB%8A%90-DataSource%EB%A5%BC-%EC%93%B0%EB%8A%94%EC%A7%80-%ED%99%95%EC%9D%B8%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@yang_11/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EC%97%AC%EB%9F%AC-%EA%B0%9C-%EC%93%B8-%EB%95%8C-%EC%96%B4%EB%8A%90-DataSource%EB%A5%BC-%EC%93%B0%EB%8A%94%EC%A7%80-%ED%99%95%EC%9D%B8%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Mon, 10 Apr 2023 16:23:53 GMT</pubDate>
            <description><![CDATA[<h3>sqlSessionTemplate을 지나 BaseExecutor 클래스 내 다음 메서드 내 파라미터를 확인하면 된다. </h3>


<pre><code class="language-java">
// 다음의 메서드 내 ms &gt; configuration &gt; environment &gt; dataSource &gt; url에 명시되어 있다.

private &lt;E&gt; List&lt;E&gt; queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException
</code></pre>
<h3>나같은 경우, 로그로 쿼리를 확인하기 위해 log4j를 세팅하는 과정에서 우선순위에 영향을 주었는지, Default로 잡힌 DataSource가 DB Connection되지 않고, 다른 DataSource가 Connection되어서 한 번 내부까지 까보았다. 이 방법을 몰라서 엄한 곳을 뒤지느라 시간 낭비를 하였다. </h3>


<h3>이렇듯, 데이터베이스 다중 연동을 통해 개발하다, 해당 sql문이 수행되는 DB의 주소를 알고 싶다면 참고하면 좋을 것 같다.</h3>]]></description>
        </item>
        <item>
            <title><![CDATA[[퀵정렬]]]></title>
            <link>https://velog.io/@yang_11/%ED%80%B5%EC%A0%95%EB%A0%AC</link>
            <guid>https://velog.io/@yang_11/%ED%80%B5%EC%A0%95%EB%A0%AC</guid>
            <pubDate>Sun, 09 Apr 2023 16:39:13 GMT</pubDate>
            <description><![CDATA[<h2>퀵정렬</h2>

<blockquote>

<p>  기준 원소를 하나 잡아 기준 원소보다 작은 원소와 큰 원소 그룹으로 나눠, 기준 원소의 좌우로 분할한 다음 각각을 정렬하는 방식이다. 평균적으로 가장 좋은 성능을 가져, 가장 많이 쓰이는 정렬 알고리즘이다. </p>
<p>  [31, 8, 48, 73, 11, 3, 20, 29, 65, 15]</p>
<p>  1) 기준 원소를 15로 잡는다는 전제하에, 15을 중심으로 이보다 작은 원소들은 15의 왼쪽에, 나머지 원소들은 15의 오른쪽에 재배치한다. </p>
<p>  [8, 11, 3, ((15)), 31, 48, 20, 29, 65, 73]</p>
<p>  2) 왼쪽과 오른쪽에 위치한 원소들을 독립적으로 정렬한다. </p>
<p>  [3, 8, 11, ((15)), 20, 29, 31, 48, 65, 73]</p>
<p>  3) 결론적으로 크기가 섞이지 않는 두 배열을 나눠놓고 양쪽 배열을 재귀적으로 정렬하는 특징을 갖는다. </p>
</blockquote>


<h3>분할의 작동 과정</h3>



<p><img src="https://velog.velcdn.com/images/yang_11/post/73732e7d-1331-4fb7-8fed-69dd8ac75127/image.png" alt=""></p>
<hr>
<h3>퀵 정렬의 장점 및 단점</h3>



<h4>장점</h4>

<ol>
<li><p>특정 상태가 아닌 이상 평균 시간 복잡도는 NlogN이며, 다른 NlogN 알고리즘에 비해 대체적으로 속도가 매우 빠르다.</p>
</li>
<li><p>추가적인 별도의 메모리를 필요로하지 않으며 재귀 호출 스택프레임에 의한 공간복잡도는 logN으로 메모리를 적게 소비한다.</p>
</li>
</ol>
<h4>단점</h4>

<ol>
<li><p>특정 조건하에 성능이 급격하게 떨어진다.</p>
<ul>
<li><p>크기가 1억인 정렬에서 각 원소가 평균 100개씩 중복되면 시간이 1.7배로 늘어나고, 평균 1000개씩 중복되면 시간이 7배로 늘어난다. </p>
</li>
<li><p>이미 정렬되어 있거나, 거의 정렬되어 있는 경우, 역순으로 정렬되어 있는 경우 최악의 경우에 해당된다.  </p>
<ul>
<li>해당 경우에서, 분할 과정에서 pivot을 선택할 때 최소값이나 최대값을 선택하는 경우가 발생할 가능성이 높다. 
이 경우, 분할된 두 개의 부분 배열 중 한 쪽이 매우 작아져서 퀵 정렬의 장점을 활용하지 못하고, 
다른 한 쪽은 대부분의 원소를 가지고 있어서 분할 과정에서 많은 비교와 교환이 필요된다.</li>
</ul>
</li>
</ul>
</li>
<li><p>재귀를 사용하기 때문에 재귀를 사용하지 못하는 환경일 경우 그 구현이 매우 복잡해진다.</p>
</li>
</ol>
<h3>구현 코드</h3>

<pre><code class="language-java">
public class QuickSort {

    public static void main(String[] args) {
        int[] arr = {31, 8, 48, 73, 11, 3, 20, 29, 65, 15};
        printArray(arr, arr.length); // 정렬 전 배열 출력
        System.out.println();
        quickSort(arr); // 퀵정렬 수행
        System.out.println();
        printArray(arr, arr.length); // 정렬 후 배열 출력

    }

    // 퀵정렬 함수 호출을 위한 Wrapper 함수
    private static void quickSort(int[] arr) {
        quickSort(arr, 0, arr.length - 1);
    }

    // 퀵정렬 함수
    private static void quickSort(int[] arr, int start, int end) {
        // pivot을 중심으로 분할한 뒤, 분할된 배열에 대해 퀵정렬 함수를 재귀적으로 호출한다.
        int part2 = partition(arr, start, end);

        if (start &lt; part2 - 1) {
            quickSort(arr, start, part2 - 1);
        }
        if (part2 &lt; end) {
            quickSort(arr, part2, end);
        }
    }

    // pivot을 중심으로 분할하는 함수
    private static int partition(int[] arr, int start, int end) {
        // pivot은 배열의 중간값으로 선택한다.
        int pivot = arr[(start + end) / 2];

        // start와 end를 이용하여 pivot보다 큰 값과 작은 값으로 나눈다.
        while (start &lt;= end) {
            while (arr[start] &lt; pivot) start++;
            while (arr[end] &gt; pivot) end--;
            if (start &lt;= end) {
                // start와 end의 값을 swap해준다.
                swap(arr, start, end);
                start++;
                end--;
            }
        }
        // 분할된 배열 중, 왼쪽 파트의 끝 지점을 리턴한다.
        return start;
    }

    // 배열의 두 요소를 swap해주는 함수
    private static void swap(int[] arr, int start, int end) {
        int temp = arr[start];
        arr[start] = arr[end];
        arr[end] = temp;
    }

    // 배열을 출력하는 함수
    private static void printArray(int[] arr, int size) {
        for (int cnt = 0; cnt &lt; size; cnt++) {
            System.out.print(arr[cnt] + &quot; &quot;);
        }
        System.out.println();
    }

}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[정렬 알고리즘]]]></title>
            <link>https://velog.io/@yang_11/%EC%A0%95%EB%A0%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-g39h2ksu</link>
            <guid>https://velog.io/@yang_11/%EC%A0%95%EB%A0%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-g39h2ksu</guid>
            <pubDate>Mon, 03 Apr 2023 13:02:10 GMT</pubDate>
            <description><![CDATA[  <hr>
<h2>정렬이란?<h2>

<h3>원소들을 기준에 맞춰 순서대로 위치시키는 것<h3>



  <hr>

<h2>정렬의 중요성에 대해 생각해본 결과<h2>

<h3>원하는 데이터를 탐색하는데에 있어서 용이한 정렬은 프로그래밍 및 알고리즘 이해에 도움이 된다는 것이었다. 예를들어 시간복잡도 개념과 for문에 대한 이해도 정도가 되겠다. <h3>

  <hr>

<h2>알고리즘 복잡도</h2>


<blockquote>

<p>입력 크기에 따른 단위 연산의 수행 횟수 변화를 함수로 나타낸 것을 의미한다.
  <br></p>
<p>알고리즘의 복잡도를 나타낼 땐, 점근적 표기(시간 복잡도 함수를 원소로 표현하는 법)를 사용한다.</p>
<p>점근적 복잡도 : 입력의 크기가 충분히 클 때의 복잡도</p>
<p>입력의 크기가 작으면 복잡한 알고리즘이든 효율적인 알고리즘이든 실제 수행 시간은 별 차이 없다.</p>
<p>점근적 복잡도에 있어서는 최고차항의 차수만 중요하고 나머지는 다 무시된다.
그 이유는 차수의 차이에 비하면 계수의 차이는 미미하기 때문이다. 
최고 차항이 아닌 항들도 영향이 미미하기는 마찬가지이다. </p>
<p>결론적으로 복잡도라 함은 어떤 알고리즘이 효율적인지를 판단하는 지표로 이해하면 편하다.</p>
</blockquote>



  <hr>


  <h2>대표적인 점근적 표기법</h2>


<blockquote>


<p>빅오 표기(O) : 점근적 상한 (최악의 경우의 복잡도)
오메가 표기(Ω) : 점근적 하한 (최적의 경우의 복잡도)
세타 표기(Θ) : 점근적 동일 (평균적인 복잡도)</p>
<p>빅오 표기법(Big-O notation)은 복잡도를 나타내는 점근 표기법 중 가장 많이 사용되는 표기법이다.</p>
<p>빅오 표기법이 가장 많이 사용되는 이유는 알고리즘 효율성을 상한선 기준으로 표기하기 때문이다.</p>
<p>  다시 말해 최악의 경우를 고려하는 데 가장 좋은 표기법이다
  (알고리즘 효율성은 값이 클수록, 즉 그래프가 위로 향할수록 비효율적임을 의미)</p>
<p>  최악의 경우를 고려하는 이유는 알고리즘이 복잡해짐에 따라 평균을 구하기 애매하여, 
  보통 최악의 경우인 빅오 표기법이 시간복잡도에 많이 사용된다.</p>
</blockquote>

  <hr>

  <h2>선택 정렬</h2>

<blockquote>
  배열에서 가장 큰 원소를 찾아 배열의 맨 끝자리 원소와 자리를 바꾼다. 
  <br>
  이처럼 맨 우측부터 자리를 잡아가며 같은 작업을 반복한다.
</blockquote>


<pre><code>private static void selectionSort(Integer[] a, int size) {
        // 사이즈가 10인 배열이 존재할 때,
        // [시작] 0번째 인덱스
        // [종료] 8번째 인덱스
        for (int i = 0; i &lt; size - 1; i++) {
            int min_index = i;
            // 사이즈가 10인 배열이 존재할 때,
            // [시작] 바깥 for문 시작 인덱스 + 1
            // [종료] 9번째 인덱스
            for (int j = i + 1; j &lt; size; j++) {
                // 만약 바깥 인덱스+1 데이터가 바깥 인덱스 데이터보다 작다면 [최소 인덱스 변수]값을 바깥인덱스+1값으로 변환한다.
                // a[j] : 내부 for문 내 인덱스 값
                // a[min_index] : 가장 작은 값을 가진 인덱스
                if (a[j] &lt; a[min_index]) {
                    min_index = j;
                }
            }
            // i번째 값과 찾은 최솟값을 서로 교환
            // 바깥 for문의 인덱스값에 가장 최저값을 swap 메서드를 통해 교환
            // 이로써 0번째 인덱스부터 차차 작은 값이 위치하게 된다.
            swap(a, min_index, i);
        }
    }
</code></pre><hr>

<h2>버블 정렬</h2>
<blockquote>
한 번 돌 때마다 마지막 요소가 정렬되는 것이 거품이 올라오는 것처럼 보여 버블 정렬이라고 한다.
  <br>
정렬할 배열이 주어지면, 왼쪽부터 시작한다.
  <br>
이후 이웃한 쌍을 2개씩 비교해나아간다. 
  <br>
순서대로 되어있지 않다면 자리를 바꾼다. 
  <br>
위 작업을 반복하며 나아가다, 맨 오른쪽 수의 경우 대상에서 제외한다. 
  <br>
마지막에는 0,1번째 인덱스를 비교하며 정렬이 완료된다. 
</blockquote>


<pre><code>    private static void bubbleSort(Integer[] a, int size) {
        // 사이즈가 10인 배열이 존재할 때,
        // [시작] 1번째 인덱스
        // [종료] 9번째 인덱스
        for (int i = 1; i &lt; size; i++) {
            // 사이즈가 10인 배열이 존재할 때,
            // [시작] 0번째 인덱스
            // [종료] 배열의 크기 - 바깥 for문의 초기식 변수
            for (int j = 0; j &lt; size - i; j++) {
                // 처음 for문이 도는 경우
                // 만약 0번째 인덱스값이 1번째 인덱스값보다 클 경우
                // 1번째 인덱스가 0번째 인덱스값으로 교환
                // 이로써 큰 수가 뒤에 위치하게 된다.
                if (a[j] &gt; a[j + 1]) {
                    swap(a, j, j + 1);
                }
            }
        }
    }</code></pre><hr>

<h2>삽입 정렬</h2>
<blockquote>
이미 정렬된 배열에서 자기 자신의 자리를 찾아서 삽입된다고 하여 삽입 정렬이라고 한다.
  <br>
매 순서마다 해당 요소를 앞의 정렬된 배열에서 삽입할 수 있는 위치를 찾아 해당 위치에 넣는다.
  <br>
해당 위치에 있던 요소부터 뒤의 요소들은 한 칸씩 밀린다. 
</blockquote>


<pre><code>    private static void insertionSort(Integer[] a, int size) {
        // 사이즈가 10인 배열이 존재할 때,
        // [시작] 1번째 인덱스
        // [종료] 9번째 인덱스
        for (int i = 1; i &lt; size; i++) {
            // 처음 수행 시 1번째 인덱스 원소를 target 변수에 초기화
            int target = a[i];
            // 변수 j는 바깥 for문 초기식 변수보다 1이 작다.
            // 처음 수행 시 0번째 인덱스을 의미한다.
            int j = i - 1;
            // 변수 j의 값이 0 이상이고,
            // 바깥 for문 초기식 변수 인덱스의 값이, 1값을 뺀 인덱스 값보다 작을 경우
            // 이전 원소값들을 한 칸씩 뒤로 미룬다.
            // 그 후 j의 값을 하나 감소시킨다.
            while (j &gt;= 0 &amp;&amp; target &lt; a[j]) {
                a[j + 1] = a[j];
                j--;
            }
            // 위 while문을 빠져나오는 경우는 앞의 원소가 타겟(바깥 for문 초기식 변수 원소)보다 작다는 뜻으로,
            // 타겟 원소는 j번째 원소 뒤에 와야한다.
            a[j + 1] = target;
        }
    }</code></pre><h4>삽입 정렬의 경우 코드만으로 이해가 어려울 수 있어 아래의 간단한 로그를 출력해보았다.</h4>


<pre><code>정렬 작업 전
1 5 7 8 6 4 2 3 9 
================= 바깥 for문 시작, i : 1 =================
target : 5, a[i] : 5
a[j+1] : 5
================= 바깥 for문 시작, i : 2 =================
target : 7, a[i] : 7
a[j+1] : 7
================= 바깥 for문 시작, i : 3 =================
target : 8, a[i] : 8
a[j+1] : 8
================= 바깥 for문 시작, i : 4 =================
target : 6, a[i] : 6
j : 3, target : 6, a[j] : 8
j : 2, target : 6, a[j] : 7
a[j+1] : 6
================= 바깥 for문 시작, i : 5 =================
target : 4, a[i] : 4
j : 4, target : 4, a[j] : 8
j : 3, target : 4, a[j] : 7
j : 2, target : 4, a[j] : 6
j : 1, target : 4, a[j] : 5
a[j+1] : 4
================= 바깥 for문 시작, i : 6 =================
target : 2, a[i] : 2
j : 5, target : 2, a[j] : 8
j : 4, target : 2, a[j] : 7
j : 3, target : 2, a[j] : 6
j : 2, target : 2, a[j] : 5
j : 1, target : 2, a[j] : 4
a[j+1] : 2
================= 바깥 for문 시작, i : 7 =================
target : 3, a[i] : 3
j : 6, target : 3, a[j] : 8
j : 5, target : 3, a[j] : 7
j : 4, target : 3, a[j] : 6
j : 3, target : 3, a[j] : 5
j : 2, target : 3, a[j] : 4
a[j+1] : 3
================= 바깥 for문 시작, i : 8 =================
target : 9, a[i] : 9
a[j+1] : 9

정렬 작업 후
1 2 3 4 5 6 7 8 9 
Process finished with exit code 0

</code></pre><hr>

<h2>정렬 알고리즘의 장, 단점</h2>
<blockquote>

<p>선택 정렬<br>
장점 : 구현이 간단하고, 비교하는 과정에 비해 실제 교환 횟수는 적어서 많은 교환 횟수를 요하는 자료 상태에서 효율적이다.<br>
단점 : 데이터의 개수가 많아질 시 성능이 떨어진다.<br><br>
버블 정렬<br>
장점 : 구현이 간단하다.<br>
단점 : 데이터의 개수가 많아질 시 성능이 떨어진다.<br><br>
삽입 정렬<br>
장점 : 구현이 간단하고 데이터가 이미 정렬되어 있을 경우 성능이 좋다<br>
단점 : 입력 데이터가 역순으로 정렬되어 있을 때 성능이 좋지 않다.<br><br></p>
</blockquote>

<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[Date, Calendar를 쓰면 안되는 이유]]></title>
            <link>https://velog.io/@yang_11/Date-Calendar%EB%A5%BC-%EC%93%B0%EB%A9%B4-%EC%95%88%EB%90%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</link>
            <guid>https://velog.io/@yang_11/Date-Calendar%EB%A5%BC-%EC%93%B0%EB%A9%B4-%EC%95%88%EB%90%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</guid>
            <pubDate>Wed, 22 Mar 2023 08:58:31 GMT</pubDate>
            <description><![CDATA[<p>자바에서 날짜, 시간 등을 표현할 때 Date, Calendar 클래스가 쓰인다. </p>
<p>Date, Calendar 클래스의 경우 자바 1버전에서 출시된 것으로 나온지 아주 오래된 놈이다. 
그렇기에 여러 문제점을 갖고 있다. </p>
<p>대표적인 문제점을 집어보겠다. </p>
<h3>Date의 클래스 문제점</h3>

<ul>
<li>Date 클래스는 내부적으로 mutable한 상태를 가지고 있기 때문에 set메서드를 통해 값이 바뀌어, mutable한 상태가 변경되어서 값이 변경되게 된다. 
이러한 경우에는 다른 곳에서도 같은 인스턴스를 참조하고 있을 경우에도 값이 변경되어 예기치 않은 결과가 발생할 수 있다. </li>
</ul>
<h3>Calander 클래스의 문제점</h3>

<ul>
<li>Calendar 클래스는 복잡하고 잘못 사용하면 버그가 발생할 수 있는 상황이 많다. 
그 중에서도 가장 대표적인 예시는 월(month) 정보를 다루는데 있다. 
Calendar 클래스에서 월 정보를 다루는 메서드들은 0부터 시작하며, 0은 1월을 의미하고, 11은 12월을 의미한다.
이러한 특징 때문에 다음과 같은 코드를 작성할 경우 버그가 발생할 수 있습니다.</li>
</ul>
<h3>그렇기에 우린 자바 8버전에서 출시된 java.time 패키지를 사용하자</h3>

<ul>
<li>자바 8부터는 java.time 패키지를 도입하여 새로운 API를 제공하는데, 이 API는 날짜와 시간 정보를 다루는 작업이 쉽고 간편하며, 불변 객체로 구현되어 있기 때문에 안전하게 사용할 수 있다.</li>
</ul>
<h4>다음의 코드를 통해 현재 날짜 및 이전의 날짜의 정보를 가져올 수 있다.</h4>

<pre><code class="language-java">
        ZoneId seoulZoneId = ZoneId.of(&quot;Asia/Seoul&quot;);
        LocalDateTime now = LocalDateTime.now(seoulZoneId);
        Instant threeDaysAgo = now.minusDays(3).with(LocalTime.MIN).atZone(seoulZoneId).toInstant();
        Instant nowInstant = now.atZone(seoulZoneId).toInstant();
</code></pre>
<p><img src="https://velog.velcdn.com/images/yang_11/post/adcc6936-7cfa-41ac-84fb-2f9a4868ce68/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/yang_11/post/9c357a26-0af4-4fb1-87df-0935f5acf26f/image.png" alt=""></p>
<h4>with 메서드의 인자로 LocalTime.MIN, LocalTime.MAX를 넣어 활용하면 해당 날짜의 00:00:00, 23:59:59의 유닉스 타임을 가져올 수 있는데, 아주 유용하다</h4>

<ul>
<li>now.with(LocalTime.MIN).atZone(seoulZoneId).toInstant();</li>
<li>now.with(LocalTime.MAX).atZone(seoulZoneId).toInstant();</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for getAntibioticsFrequency]]></title>
            <link>https://velog.io/@yang_11/Cause-java.lang.IllegalArgumentException-Mapped-Statements-collection-does-not-contain-value-for-getAntibioticsFrequency</link>
            <guid>https://velog.io/@yang_11/Cause-java.lang.IllegalArgumentException-Mapped-Statements-collection-does-not-contain-value-for-getAntibioticsFrequency</guid>
            <pubDate>Fri, 24 Feb 2023 09:50:08 GMT</pubDate>
            <description><![CDATA[<h3>스프링과 마이바티스를 쓰는 나는.. 어느 날, 에러를 마주하였다. </h3>


<h3>그것은 바로 SELECT을 하는 쿼리의 id값을 매핑된 상태에 포함하지 못하여 발생한 에러이다. </h3>


<h3>문제의 원인을 파악하지 못해 긴 시간을 허비하였으나, 끝내 문제를 해결하였다. </h3>


<h2>해결법은 다음과 같다.</h2>


<h3>마이바티스 세팅을 위해 dataSource 프로퍼티의 mapperLocations의 항목을 추가해주지 않아서이다. </h3>


<h3>사용하려는 마이바티스 쿼리 xml 파일을 프로퍼티에 추가시켜주어, 문제를 해결하였다. </h3>


<p><img src="https://velog.velcdn.com/images/yang_11/post/5d492530-d245-4e7e-a5ca-ead79da00246/image.png" alt=""></p>
<h3>결론은 새로 생성한 쿼리 작성 파일을 못읽어서 해당 value를 못찾는 에러였던 것이다. </h3>


<h3>하지만 이 에러의 경우 해당 경우 이외에 쿼리문을 잘못작성하는 등의 이유로도 발생한다고 하니, 다른 블로그 게시글을 참고하여야 할 수도 있다. </h3>


]]></description>
        </item>
        <item>
            <title><![CDATA[[MyBatis] <set> 태그 마지막 콤마(쉼표) ]]></title>
            <link>https://velog.io/@yang_11/MyBatis-set-%ED%83%9C%EA%B7%B8-%EB%A7%88%EC%A7%80%EB%A7%89-%EC%BD%A4%EB%A7%88%EC%89%BC%ED%91%9C</link>
            <guid>https://velog.io/@yang_11/MyBatis-set-%ED%83%9C%EA%B7%B8-%EB%A7%88%EC%A7%80%EB%A7%89-%EC%BD%A4%EB%A7%88%EC%89%BC%ED%91%9C</guid>
            <pubDate>Wed, 15 Feb 2023 17:19:20 GMT</pubDate>
            <description><![CDATA[<h3> set 태그의 경우 마지막에 붙여진 요소의 콤마(,)를 자동으로 삭제해주기 때문에, 
  <br>
  모든 요소에 콤마을 붙여도 무방하다는 특징을 갖는다. </h3>


<h4> - 예시 </h4>

<pre><code class="language-java">
        &lt;set&gt;
            &lt;if test=&quot;actionType != null&quot;&gt;actionType = #{actionType},&lt;/if&gt;
            &lt;if test=&quot;contents != null&quot;&gt;contents = #{contents},&lt;/if&gt;
        &lt;/set&gt;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MyBatis] #{}, ${}]]></title>
            <link>https://velog.io/@yang_11/MyBatis</link>
            <guid>https://velog.io/@yang_11/MyBatis</guid>
            <pubDate>Wed, 15 Feb 2023 17:16:39 GMT</pubDate>
            <description><![CDATA[<hr>
<h3>#{}</h3>

<ul>
<li><p>사용 시 PreparedStatement 생성한다. </p>
</li>
<li><p>PreparedStatement가 제공하는 set 계열의 메서드를 사용하여 물음표를 대체할 값을 지정한다. </p>
</li>
<li><p>들어오는 데이터를 문자열(String)로 인식하여, 자동 따옴표가 붙는다. </p>
</li>
<li><p>SQL Injection을 예방할 수 있어 보안 측면에서 유리함.</p>
</li>
<li><p>사용 이유</p>
<ul>
<li>PreparedStatement란 친구는 수행 시 물음표값에 Parameter가 바인딩되어 수행된다. </li>
<li>이는 Parameter 값이 바뀌어도 같은 쿼리로 인식한다는 의미로, 이렇게 파싱된 쿼리는 재활용되기에(캐싱) 성능 상 이점을 갖는다. </li>
</ul>
</li>
<li><p>결론</p>
<ul>
<li>#{} 값에 자동으로 따옴표가 붙고 성능이 좋다.</li>
</ul>
</li>
</ul>
<hr>
<h3>${}</h3>

<ul>
<li><p>사용 시 Statement를 생성한다. </p>
</li>
<li><p>Statement란 친구는 Parameter 값을 그대로 전달하기에 문자열에 따옴표가 붙지 않는다.</p>
</li>
<li><p>항상 쿼리문에 대한 파싱이 진행되어 처리 속도가 저하될 수 있다는 단점이 존재한다. </p>
</li>
<li><p>SQL Injection을 예방할 수 없어, 보안 상 불리하다는 단점이 존재한다. </p>
<ul>
<li>SQL Injection : 악의적인 사용자가 보안상의 취약점을 이용하여, 임의의 SQL 문을 주입하고 실행되게 하여 데이터베이스가 비정상적인 동작을 하도록 조작하는 행위</li>
</ul>
</li>
<li><p>사용 이유</p>
<ul>
<li>테이블, 컬럼명을 전달하고자 할 때 사용되곤 한다. </li>
</ul>
</li>
<li><p>결론</p>
<ul>
<li>ORDER BY하고 싶은 컬럼이 있을 때 파라미터를 통해 ASC, DESC를 설정하고 싶은 경우 #{}를 사용할 경우 따옴표가 붙어 &#39;ASC&#39;,&#39;DESC&#39;같이 변환되어, 원하는대로 동작되지 않기에 이 경우가 아니라면 굳이 ${}를 써야하나 싶다. </li>
</ul>
</li>
</ul>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[atime, ctime, mtime [리눅스]]]></title>
            <link>https://velog.io/@yang_11/atime-ctime-mtime-%EB%A6%AC%EB%88%85%EC%8A%A4</link>
            <guid>https://velog.io/@yang_11/atime-ctime-mtime-%EB%A6%AC%EB%88%85%EC%8A%A4</guid>
            <pubDate>Thu, 19 Jan 2023 09:18:55 GMT</pubDate>
            <description><![CDATA[<ul>
<li><p>리눅스 시스템에서 파일 시스템을 처리할 때 리눅스 전용 특수한 index를 사용한다. </p>
</li>
<li><p>이는 &quot;아이노드&quot;라고도 한다. </p>
<ul>
<li>아이노드<ul>
<li>index-node의 줄임말이다. </li>
<li>리눅스 시스템에서 파일을 빠르게 찾기 위한 데이터라고 할 수 있다. </li>
<li>모든 파일에 부여된 일종의 번호를 의미한다. </li>
<li>아이노드는 해당 파일에 대한 정보도 갖고 있다. </li>
</ul>
</li>
</ul>
<br>

</li>
</ul>
<blockquote>

<p>  atime (access time, 접근 시간)<br></p>
<ul>
<li><p>파일에 접근한 시간을 나타낸다. <br></p>
</li>
<li><p>파일을 open할 때마다 갱신되며 vi, cat 명령어로 파일 확인 시 atime값은 변한다. </p>
<br>
<br>

<p>mtime (modification time, 접근 시간)<br></p>
</li>
<li><p>파일의 내용이 수정될 때 mtime값은 변한다. </p>
<br>
<br>

<p>ctime (change time, 접근 시간)<br></p>
</li>
<li><p>inode의 값 (파일 속성, 권한, 크기 등)이 변경되면 ctime값은 변한다. </p>
</li>
</ul>
</blockquote>

<hr>
<h3>
  오해와 진실
</h3>

<ul>
<li><p>ctime의 경우 잘못 생각하면 creation time으로 이해할 수 있고 초기에는 이런 의미로 썼으나,
나중엔 의미가 변경되어 현재는 incode changed time 용도로 사용된다. </p>
</li>
<li><p>inode 변경이 발생하는 행동</p>
<ul>
<li>chmod(file permissions 변경)</li>
<li>chown(file 소유자 변경)</li>
<li>ln(하드 링크 생성)</li>
<li>rm(삭제)</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li>%x, %y, %z 지정자를 사용하여 사람이 읽기 좋게 파일의 atime, mtime, ctime을 표시해줄 수 있다. 
<img src="https://velog.velcdn.com/images/yang_11/post/c2b28282-c80f-420f-a82c-da2aca0a00ee/image.png" alt=""></li>
</ul>
<hr>
<ul>
<li><p>관련 링크</p>
<ul>
<li><a href="https://www.lesstif.com/lpt/atime-mtime-ctime-105644095.html">https://www.lesstif.com/lpt/atime-mtime-ctime-105644095.html</a></li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[리눅스 명령어 이슈 [Argument list too long]]]></title>
            <link>https://velog.io/@yang_11/%EC%9E%84%EC%8B%9C-%EC%A0%80%EC%9E%A5</link>
            <guid>https://velog.io/@yang_11/%EC%9E%84%EC%8B%9C-%EC%A0%80%EC%9E%A5</guid>
            <pubDate>Thu, 19 Jan 2023 08:22:25 GMT</pubDate>
            <description><![CDATA[<h3>원인</h3>


<ul>
<li>다음의 리눅스 명령어 사용 시 Argument list too long이 발생!</li>
</ul>
<p><img src="https://velog.velcdn.com/images/yang_11/post/b0bde157-6966-42a6-a84a-45ac7798bb39/image.png" alt=""></p>
<ul>
<li><p>이 에러는 find 명령어 수행 시 한 번에 리스팅(리스팅:작업 중에 있는 디렉토리에 있는 내용의 리스트)할 수 있는 파일의 개수를 초과했을 경우 나오는 메시지이다. </p>
</li>
<li><p>결론적으로 해당 디렉토리에 파일, 디렉토리 개수가 너무 많아 발생한 것이다. </p>
</li>
</ul>
<hr>
<h3>해결</h3>

<ul>
<li><p>그래서 찾은 후 수행할 작업 명령어를 추가해주었다. </p>
</li>
<li><p>exec 명령어 {} ; : 찾은 파일들에 대해서 쉘 명령어를 사용해서 특정명령실행</p>
<ul>
<li><p>{} : find로 찾은 파일리스트</p>
</li>
<li><p>; : -exec와 -ok는 반드시 escape 된 세미클론(;)으로 종료해야 하며 이는 옵션의 끝을 의미한다. </p>
</li>
</ul>
</li>
</ul>
  <h4>

<p>  <code>find /sec/1/nonverbal/*/*/ -name &quot;*.wav&quot; -mtime +30 -exec rm -rf {} \;</code></p>
  </h4>

  <br>


<ul>
<li><p>참고로 삭제하는 대상의 기준이 파일이 아닌 디렉토리일 경우 -name 옵션을 빼준 뒤 다음과 같이 수정해주는 방법도 있다. </p>
<h4>

<p><code>find /sec/*/nonverbal/*/* -type d -mtime +30 -exec rm -rf {} \;</code></p>
</h4>

</li>
</ul>
<hr>
<ul>
<li>관련 링크</li>
</ul>
<pre><code>- https://linuxism.ustd.ip.or.kr/365
- https://tyson.tistory.com/233
- https://yjshin.tistory.com/entry/Linux-%EB%A6%AC%EB%88%85%EC%8A%A4-%EC%98%A4%EB%9E%98%EB%90%9C-%ED%8C%8C%EC%9D%BC-%EC%82%AD%EC%A0%9C%ED%95%98%EA%B8%B0</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[SummaryStatistics 클래스]]></title>
            <link>https://velog.io/@yang_11/SummaryStatistics-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@yang_11/SummaryStatistics-%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Thu, 12 Jan 2023 06:08:29 GMT</pubDate>
            <description><![CDATA[<ul>
<li><p>자바 8버전에서 도입된 SummaryStatistics 클래스는 count, min, max, sum, average 등의 
statistics 정보를 계산해주는 클래스이며 스트림과 함께 사용할 수 있습니다. </p>
</li>
<li><p>SummaryStatistics(데이터 요약)는 Int, Long, Double 자료형을 지원하는 아래 클래스들을 사용할 수 있습니다. 
아래와 같이 지원하는 자료형마다 클래스 이름이 다르나, 사용법은 모두 동일하다. </p>
</li>
</ul>
<br>

<ul>
<li>IntSummaryStatistics</li>
<li>LongSummaryStatistics</li>
<li>DoubleSummaryStatistics</li>
</ul>
<hr>
<h4>사용 예제</h4>

<pre><code class="language-java">    private double getSensingDataAvg(List&lt;Double&gt; sensingDataList) {
        // mapToDouble : 스트림의 요소를 기본 타입형 스트림으로 반환하여 작업 효율을 높이기 위해 사용
        DoubleSummaryStatistics SummaryStatistics = sensingDataList.stream().mapToDouble(Double::doubleValue).summaryStatistics();
        return SummaryStatistics.getAverage();
    }</code></pre>
<hr>
<ul>
<li><p>관련 자료</p>
<ul>
<li><a href="https://www.techiedelight.com/ko/calculate-average-of-all-items-list-java/">https://www.techiedelight.com/ko/calculate-average-of-all-items-list-java/</a></li>
<li><a href="https://codechacha.com/ko/java8-summarystatistics/">https://codechacha.com/ko/java8-summarystatistics/</a></li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[에러] The content of element type "properties" must match "(comment?,entry*)"]]></title>
            <link>https://velog.io/@yang_11/%EC%97%90%EB%9F%AC-The-content-of-element-type-properties-must-match-commententry</link>
            <guid>https://velog.io/@yang_11/%EC%97%90%EB%9F%AC-The-content-of-element-type-properties-must-match-commententry</guid>
            <pubDate>Thu, 22 Dec 2022 15:01:32 GMT</pubDate>
            <description><![CDATA[<h4>다음의 에러가 발생하였다.</h4>

<p><img src="https://velog.velcdn.com/images/yang_11/post/906d87f6-7f70-4916-921a-5cc6626728c7/image.png" alt=""></p>
<h4>그에 대한 원인은 해당 설정 파일에 오타가 포함되어 태그 매칭에 에러가 발생하여 그렇다. </h4>


<pre><code class="language-java">&lt;entry key=&quot;influxdb.username&quot;&gt;testyang&lt;/entry&gt;ㅡ</code></pre>
<h4>다음과 같이 바꿔주어 해결한다.</h4>


<pre><code class="language-java">&lt;entry key=&quot;influxdb.username&quot;&gt;testyang&lt;/entry&gt;</code></pre>
<hr>
<ul>
<li>참조 링크 : <a href="http://blog.idmware.com/2012/01/im-trying-to-make-my-java-xml.html">http://blog.idmware.com/2012/01/im-trying-to-make-my-java-xml.html</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[기본형 변수와 참조형 변수의 차이(feat.boxing, unboxing, "==", "equals")]]></title>
            <link>https://velog.io/@yang_11/%EA%B8%B0%EB%B3%B8%ED%98%95-%EB%B3%80%EC%88%98%EC%99%80-%EC%B0%B8%EC%A1%B0%ED%98%95-%EB%B3%80%EC%88%98%EC%9D%98-%EC%B0%A8%EC%9D%B4feat.boxing-unboxing-equals</link>
            <guid>https://velog.io/@yang_11/%EA%B8%B0%EB%B3%B8%ED%98%95-%EB%B3%80%EC%88%98%EC%99%80-%EC%B0%B8%EC%A1%B0%ED%98%95-%EB%B3%80%EC%88%98%EC%9D%98-%EC%B0%A8%EC%9D%B4feat.boxing-unboxing-equals</guid>
            <pubDate>Mon, 10 Oct 2022 14:49:45 GMT</pubDate>
            <description><![CDATA[<h3>int (Primitive 자료형)</h3>
<blockquote>
    - 실제 값을 저장 장소로 갖는 자료형이다.   
      <br>
      - 산술 연산이 가능하다. 
      <br>
      - null값으로 초기화가 불가능하며, 0으로 초기화된다. 
</blockquote>


<h3>Integer (Wrapper 클래스, 객체)</h3>
<blockquote>
  - 실제 값이 아닌 객체의 주소를 저장하고 있는 객체형 변수로 참조형이다. 
  <br>
  - Unboxing하지 않으면 산술 연산이 불가능하나, null값은 처리할 수 있다. 
  <br>
  - null값 처리가 용이하여 SQL과 연동 시 처리가 효율적이다. 
</blockquote>


<pre><code class="language-java">
public static void main(String[] args) {
        Integer iA = new Integer(123);
        Integer iB = new Integer(123);

        int ia = (int) iA;              // 언박싱 (참조형 =&gt; 기본형)
        int ib = iB;                    // 오토 언박싱

        Integer iC = (Integer) 456;     // 박싱 (기본형 =&gt; 참조형)
        Integer iD = ia;                // 오토 박싱
    }
</code></pre>
<br>
<hr>
<br>


<blockquote>

<h3>equals 메서드</h3>

<p>비교하고자 하는 대상의 내용 자체를 비교한다. </p>
<h3>==</h3>

<p>비교하고자 하는 대상의 주소값을 비교한다. </p>
</blockquote>


<pre><code class="language-java">
    public static void main(String[] args) {
        String a = &quot;aaa&quot;;
        String b = a;
        String c = new String(&quot;aaa&quot;);

        System.out.println(a.equals(b));        // 내용 비교    -&gt; TRUE
        System.out.println(a == b);             // 주소값 비교  -&gt; TRUE
        System.out.println(a == c);             // 주소값 비교  -&gt; FALSE
        System.out.println(a.equals(c));        // 내용 비교    -&gt; TRUE


        System.out.println(a);                  // aaa
        System.out.println(b);                  // aaa
        System.out.println(c);                  // aaa
    }
</code></pre>
<br>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[IoC/DI(제어의 역전/의존성 주입)]]></title>
            <link>https://velog.io/@yang_11/IoCDI%EC%A0%9C%EC%96%B4%EC%9D%98-%EC%97%AD%EC%A0%84%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85</link>
            <guid>https://velog.io/@yang_11/IoCDI%EC%A0%9C%EC%96%B4%EC%9D%98-%EC%97%AD%EC%A0%84%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85</guid>
            <pubDate>Mon, 10 Oct 2022 14:13:30 GMT</pubDate>
            <description><![CDATA[<h3>의존성을 간단하게 정의내리면 다음과 같다. </h3>

<br>

<h4>의사 코드</h4>
<blockquote>
  운전자가 자동차를 생산한다. 
  <br>
  자동차는 내부적으로 타이어를 생산한다. 
</blockquote>

<h4>자바 코드</h4>
<blockquote>
  new Car();
  <br>
  Car 객체 생성자에서 new Tire();
</blockquote>

<h4>설명</h4>
<blockquote>
  의존성은 new로, new를 실행하는 Car가 Tire에 의존한다.
</blockquote>

<hr>

<br>

<h3>1. 스프링없이 의존성 주입하기 1 - 생성자를 통해 의존성을 주입</h3>

<h4>의사 코드</h4>
<blockquote>
  운전자가 타이어를 생산한다. 
  <br>
  운전자가 자동차를 생산하면서 타이어를 장착한다. 
</blockquote>

<h4>자바 코드 - 생성자 인자 이용</h4>
<blockquote>
  Tire tire = new koreaTire();
  <br>
  Car car = new Car(tire);
</blockquote>

<p>➜ 전략 패턴 사용 (전략 패턴의 3요소 : 클라이언트, 전략, 컨텍스트)
        1. 전략 : Tire를 구현한 koreaTire, americaTire (전략 메서드를 가진 전략 객체)
        2. 컨텍스트 : Car의 getTireBrand() 메서드 (전략 객체를 사용하는 컨텍스트)
        3. 클라이언트 : Driver의 main() 메서드 (전략 객체를 생성해 컨텍스트에 주입하는 제3자)</p>
<hr>

<br>

<h3>2. 스프링없이 의존성 주입하기 2 - 속성을 통해 의존성을 주입</h3>

<h4>의사 코드</h4>
<blockquote>
  운전자가 타이어를 생산한다. 
  <br>
  운전자가 자동차를 생산한다. 
  <br>
  운전자가 자동차에 타이어를 장착한다. 
</blockquote>

<h4>자바 코드 - 생성자 인자 이용</h4>
<blockquote>
  Tire tire = new koreaTire();
  <br>
  Car car = new Car();
  <br>
  car.setTire(tire);
</blockquote>

<hr>

<br>

<h3>3. 스프링을 통한 의존성 주입 - XML 파일 사용</h3>

<h4>의사 코드</h4>
<blockquote>
  운전자가 종합 쇼핑몰에서 타이어를 구매한다. 
  <br>
  운전자가 종합 쇼핑몰에서 자동차를 구매한다. 
  <br>
  운전자가 자동차에 타이어를 장착한다. 
</blockquote>

<h4>자바 코드 - 생성자 인자 이용</h4>
<blockquote>

<p>ApplicationContext context = new ClassPathXmlApplicationContext(&quot;main/java/expert002_01/expert002.xml&quot;);
<br>
<br>
// 종합 쇼핑몰에서 상품에 해당하는 Car, Tire 구매하는 코드
<br>
Car car = context.getBean(&quot;car&quot;, Car.class);
<br>
Tire tire = context.getBean(&quot;tire&quot;, Tire.class);
<br>
car.setTire(tire);</p>
</blockquote>

<pre><code class="language-java">    &lt;bean id=&quot;tire&quot; class=&quot;main.java.expert002.koreaTire&quot;/&gt;

    &lt;bean id=&quot;americaTire&quot; class=&quot;main.java.expert002.AmericaTire&quot;/&gt;

    &lt;bean id=&quot;car&quot; class=&quot;main.java.expert002.Car&quot;/&gt;</code></pre>
<hr>

<br>

<h3>4. 스프링을 통한 의존성 주입 - 스프링 설정 파일(XML)에서 속성 주입</h3>

<h4>의사 코드</h4>
<blockquote>
  운전자가 종합 쇼핑몰에서 자동차를 구매 요청한다. 
  <br>
  종합 쇼핑몰은 자동차를 생산한다. 
  <br>
  종합 쇼핑몰은 타이어를 생산한다. 
  <br>
  종합 쇼핑몰은 자동차에 타이어를 장착한다. 
  <br>
  종합 쇼핑몰은 운전자에게 자동차를 전달한다. 
</blockquote>

<h4>자바 코드 - 생성자 인자 이용</h4>
<blockquote>
   ApplicationContext context = new ClassPathXmlApplicationContext("expert003/expert003.xml");
<br>
Car car = context.getBean("car", Car.class);
</blockquote>

<pre><code class="language-java">    &lt;bean id=&quot;koreaTire&quot; class=&quot;main.java.expert003.koreaTire&quot;/&gt;

    &lt;bean id=&quot;americaTire&quot; class=&quot;main.java.expert003.AmericaTire&quot;/&gt;

    &lt;bean id=&quot;car&quot; class=&quot;main.java.expert003.Car&quot;&gt;
        &lt;property name=&quot;tire&quot; ref=&quot;koreaTire&quot;/&gt;
    &lt;/bean&gt;</code></pre>
<hr>

<br>

<h3>5. 스프링을 통한 의존성 주입 - @Autowired를 통한 속성 주입</h3>

<h4>의사 코드</h4>
<blockquote>
  운전자가 종합 쇼핑몰에서 자동차를 구매 요청한다. 
  <br>
  종합 쇼핑몰은 자동차를 생산한다. 
  <br>
  종합 쇼핑몰은 타이어를 생산한다. 
  <br>
  종합 쇼핑몰은 자동차에 타이어를 장착한다. 
  <br>
  종합 쇼핑몰은 운전자에게 자동차를 전달한다. 
</blockquote>

<h4>자바 코드 - 생성자 인자 이용</h4>
<blockquote>
ApplicationContext context = new ClassPathXmlApplicationContext("main/java/expert004/expert004.xml");
<br><br>

<p>Car car = context.getBean(&quot;car&quot;, Car.class);</p>
</blockquote>


<pre><code class="language-java">
     &lt;context:annotation-config /&gt;

    &lt;bean id=&quot;tire&quot; class=&quot;main.java.expert004.koreaTire&quot;/&gt;

    &lt;bean id=&quot;americaTire&quot; class=&quot;main.java.expert004.AmericaTire&quot;/&gt;

    &lt;bean id=&quot;car&quot; class=&quot;main.java.expert004.Car&quot; /&gt;


public class Car {
    @Autowired
    Tire tire;

    public String getTireBrand() {
        return &quot;장착된 타이어 : &quot; + tire.getBrand();
    }

}
</code></pre>
<hr>

<br>



<h3>@Autowired를 통한 속성 매칭 규칙(feat.@Resource)</h3>
<blockquote>

<ol>
<li>타입(인터페이스)을 구현한 Bean이 존재하고, 빈이 한 개 인가 
(예 =&gt; 유일한 빈 객체 할당, 아니오 =&gt; No Matching bean 에러)</li>
</ol>
<ol start="2">
<li>아니오 =&gt; id가 일치하는 하나의 빈이 있는가 
(예 =&gt; 유일한 빈 객체 할당, 아니오 =&gt; No Unique 에러)</li>
</ol>
<p>스프링의 @Autowired는 id 매칭보다 type 매칭이 우선이기에 스프링 설정 파일 내 
id가 존재하지 않더라도 클라이언트 측에서 클래스로 호출하여 의존성 주입 시 
정상적으로 구동된다. </p>
<p><br><br></p>
<p>@Resource : 자바 표준 어노테이션
-&gt; type과 id 가운데, 매칭 순위는 id가 더 높다. 고로 id로 매칭한 빈을 못찾을 경우 type으로 매칭할 빈을 찾게 된다. </p>
<p>@Autowired : 스프링 어노테이션 
-&gt; type과 id 가운데, 매칭 순위는 type이 더 높다. </p>
<p>스프링을 사용하지 않는다면 @Resource만을 사용해야 한다. </p>
</blockquote>


<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MyBatis <if>문 null 이슈 in INSERT]]]></title>
            <link>https://velog.io/@yang_11/MyBatis-if%EB%AC%B8-null-%EC%9D%B4%EC%8A%88-in-INSERT</link>
            <guid>https://velog.io/@yang_11/MyBatis-if%EB%AC%B8-null-%EC%9D%B4%EC%8A%88-in-INSERT</guid>
            <pubDate>Mon, 19 Sep 2022 09:07:45 GMT</pubDate>
            <description><![CDATA[<H3>이슈</H3>

<ul>
<li>MyBatis를 통해 RDB에 값을 넣는 과정에서 0인 Double 타입의 데이터가 null로 적재됨</li>
</ul>
<H3>원인</H3>

<ul>
<li>null을 판별하는 다음의 코드에서 파라미터가 0인 경우 공백으로 판단한다. </li>
</ul>
<pre><code class="language-java">        &lt;if test=&quot;currentValue != null and currentValue != &#39;&#39;&quot;&gt;, #{currentValue}&lt;/if&gt;</code></pre>
<H3>해결</H3>

<ul>
<li><p>유효성 검사는 자바 부분에서 처리하여 진행</p>
</li>
<li><p>MyBatis 쿼리문 내 0이 들어갈 수 있는 파라미터에 <if> 조건문을 없애고 &#39;#{currentValue}&#39;와 같이 작성</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ModelMapper로 객체 데이터 세팅]]]></title>
            <link>https://velog.io/@yang_11/ModelMapper%EB%A1%9C-%EA%B0%9D%EC%B2%B4-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%84%B8%ED%8C%85</link>
            <guid>https://velog.io/@yang_11/ModelMapper%EB%A1%9C-%EA%B0%9D%EC%B2%B4-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%84%B8%ED%8C%85</guid>
            <pubDate>Wed, 14 Sep 2022 08:26:57 GMT</pubDate>
            <description><![CDATA[<ul>
<li>ModelMapper : 객체의 프로퍼티를 다른 객체의 프로퍼티로 매핑해주는 유틸로, 서로 다른 Object간의 필트 값을 자동으로 매핑해주는 라이브러리이다. </li>
</ul>
<h3>의존성 주입</h3>

<blockquote>

<pre><code>&lt;!-- 모델매퍼 테스트 --&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.modelmapper&lt;/groupId&gt;
        &lt;artifactId&gt;modelmapper&lt;/artifactId&gt;
        &lt;version&gt;2.3.8&lt;/version&gt;
    &lt;/dependency&gt;</code></pre></blockquote>


<h3>Spring Bean 등록</h3>

<h4>다음과 같이 어노테이션으로 하던지, 아니면 xml 설정파일에 bean 등록하여 사용할 것</h4>

<pre><code class="language-java">@Configuration
public class AppConfig {

    @Bean
    public ModelMapper modelMapper(){
        return new ModelMapper();
    }

}</code></pre>
<h4>만들어지는 대상은 Getter, 만드는 대상은 Setter가 필요하다.</h4>

<h3>전달할 데이터 - DTO</h3>

<pre><code class="language-java">@AllArgsConstructor
@Getter
public class TestDTO {
    private String id;
    private String name;
}</code></pre>
<h3>전달받을 데이터 - VO</h3>

<pre><code class="language-java">@Setter
public class TestVO {
    private String id;
    private String name;
}</code></pre>
<h3>의존성 주입</h3>

<pre><code class="language-java">        // service단에서 다음의 로직을 수행

        // 생성자를 통해 값 세팅
        TestDTO testDTO = new TestDTO(&quot;1&quot;,&quot;임꺽정&quot;);

        // 해당 메서드로 값 전달 진행
        TestVO testVO = modelMapper.map(testDTO,TestVO.class); </code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Mybatis_#{}, ${}]]]></title>
            <link>https://velog.io/@yang_11/Mybatis</link>
            <guid>https://velog.io/@yang_11/Mybatis</guid>
            <pubDate>Tue, 13 Sep 2022 06:16:21 GMT</pubDate>
            <description><![CDATA[<h2>#{}</h2>

<ul>
<li>파라미터가 String 형태로 들어와 &quot;&quot;로 감싸진다.</li>
<li>쿼리문 작성 시 #{}의 경우에는 PreparedStatement를 생성하게 되는데 파라미터에 ?가 바인딩되어 수행된다. </li>
<li>예시로 #{user_id}의 user_id의 값이 abc일 경우 쿼리에는 &#39;abc&#39;의 형태가 된다</li>
<li>파싱된 쿼리문은 재활용(캐싱)되기 때문에 효율적이다. </li>
<li>쿼리 주입을 예방할 수 있어 보안 측면에서 유리하다. </li>
</ul>
<br>

<h2>${}</h2>

<ul>
<li><p>파라미터가 String 형태로 들어와 &quot;&quot;로 감싸지지 않아, 테이블이나 컬럼명을 파라미터로 전달하고 싶을 때 사용한다.</p>
<pre><code class="language-java">  &lt;select id=&quot;select&quot; resultType=&quot;String&quot; parameterType=&quot;Map&quot;&gt;
      SELECT
          name AS name
      FROM
          user_#{tableId} // 컬럼명에 &quot;&quot;가 안붙어 bad sql Exception 발생 X
      WHERE
          id = #{id}
  &lt;/select&gt;</code></pre>
</li>
<li><p>해당 컬럼의 자료형에 맞춰 파라미터의 자료형이 변경되기에 항상 쿼리문 파싱을 진행하여 성능상에 단점이 존재한다. </p>
</li>
<li><p>쿼리 주입을 예방할 수 없어 보안 측면에서 불리하다. </p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[서브쿼리 내 ORDER BY]]]></title>
            <link>https://velog.io/@yang_11/%EC%84%9C%EB%B8%8C%EC%BF%BC%EB%A6%AC-%EB%82%B4-ORDER-BY</link>
            <guid>https://velog.io/@yang_11/%EC%84%9C%EB%B8%8C%EC%BF%BC%EB%A6%AC-%EB%82%B4-ORDER-BY</guid>
            <pubDate>Tue, 30 Aug 2022 10:46:18 GMT</pubDate>
            <description><![CDATA[<br>
<br>
<h4> 서브쿼리 내에서 ORDER BY를 설정해도 효과가 없는 이유 </h4>
<br>
=> SQL standard에서 정한 DB 테이블의 정의에서는 테이블을 채우고 있는 데이터의 ORDER(정렬)은 아무런 의미가 없기 때문이라고한다.

<br>
<br>
<br>

<p>| 참고 자료
=&gt; <a href="https://mariadb.com/kb/en/why-is-order-by-in-a-from-subquery-ignored/">https://mariadb.com/kb/en/why-is-order-by-in-a-from-subquery-ignored/</a></p>
<br>
<br>


<h3>해결 방법</h3>
<br>
<h4>1. 서브쿼리 내 order by 뒤에 limit를 걸어라</h4>
    서브쿼리 내에 LIMIT를 걸어줄 경우 ORDER BY가 먹히는 이유는 LIMIT를 걸음으로써 인해 
    데이터의 순서 뿐만 아니라 갯수까지 제한되어 테이블의 본질적인 내용이 변화된다고 보기에 
    MYSQL, MARIA DB에서는 ORDER BY가 적용된다고 한다. 


<br>
<br>
<h4>2. ORDER BY절을 최상위 절로 옮겨라 (위 참고자료에서 추천하는 방식)</h4>

]]></description>
        </item>
        <item>
            <title><![CDATA[[@NotNull @NotEmpty @NotBlank]]]></title>
            <link>https://velog.io/@yang_11/NotNull-NotEmpty-NotBlank</link>
            <guid>https://velog.io/@yang_11/NotNull-NotEmpty-NotBlank</guid>
            <pubDate>Fri, 26 Aug 2022 01:52:08 GMT</pubDate>
            <description><![CDATA[<ul>
<li>API 개발 시 request parameter의 null 체크를 위한 어노테이션</li>
</ul>
<blockquote>

  <h4>
  <br>
  @NotNull : null은 허용하지 않으나, "", " "은 허용한다. 
  <br>
  <br>
  @NotEmpty : null, ""은 허용하지 않으나, " "은 허용한다.
  <br>
  <br>
  @NotBlank : null, "", " " 모두 허용하지 않는다.
  <br>
  </h4>

</blockquote>

<hr>


<h4>- 참고로 위 어노테이션을 사용하기 위해 컨트롤러의 DTO 파라미터에 


<p>  @Valid 어노테이션을 추가해줘야 제 기능을 수행한다. </h4></p>
<ul>
<li><p>String 타입에서 @NotBlank 사용</p>
</li>
<li><p>Integer 타입 등 숫자 관련 타입은 @NotNull 사용</p>
</li>
</ul>
<p>타입에 어노테이션을 제대로 사용하지 않을 경우 다음의 에러가 발생할 수 있다. </p>
<blockquote>
{
    "result": "error",
    "message": "HV000030: No validator could be found for type: java.lang.Integer.",
    "code": 500
}
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[자바와 절차적/구조적 프로그래밍-01]]]></title>
            <link>https://velog.io/@yang_11/%EC%9E%90%EB%B0%94%EC%99%80-%EC%A0%88%EC%B0%A8%EC%A0%81%EA%B5%AC%EC%A1%B0%EC%A0%81-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</link>
            <guid>https://velog.io/@yang_11/%EC%9E%90%EB%B0%94%EC%99%80-%EC%A0%88%EC%B0%A8%EC%A0%81%EA%B5%AC%EC%A1%B0%EC%A0%81-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</guid>
            <pubDate>Tue, 23 Aug 2022 00:30:22 GMT</pubDate>
            <description><![CDATA[<p>JDK : Java Development Kit / 자바 개발 도구
JRE : Java Runtime Environment / 자바 실행 환경
JVM : Java Virtual Machine / 자바 가상 기계</p>
<hr>
<h4>프로그램이 메모리 사용 방식</h4>

<ul>
<li>코드 실행 영역</li>
<li>데이터 저장 영역</li>
</ul>
<h4>객체 지향 프로그램의 메모리 사용 방식</h4>

<ul>
<li><p>코드 실행 영역</p>
</li>
<li><p>데이터 저장 영역</p>
<ul>
<li>static 영역</li>
<li>stack 영역</li>
<li>heap 영역</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/yang_11/post/06e3b1f9-2f99-4746-86af-fffdff2078e0/image.png" alt=""></p>
<hr>
<h4>함수를 쓰면 좋은 이유</h4>

<ul>
<li>중복 코드를 한 곳에 모아서 관리할 수 있다. </li>
<li>논리를 함수 단위로 분리해서 이해하기 쉬운 코드를 작성할 수 있다. </li>
</ul>
<br>

<p>멀티 프로세스 : 다수의 데이터 저장 영역, 즉 다수의 T 메모리를 갖는 구조이다. </p>
<p>멀티 스레드 : T 메모리 내 스택 영역을 스레드 개수만큼 분할하여 사용하는 것을 의미한다. </p>
<hr>
<h3>객체지향의 4대 특성</h3>
➜ 요리를 만들기 위한 불, 물, 칼 등의 주방 도구로 비유할 수 있다. 
<h3>객체지향 설계 5원칙</h3>
➜ 주방 도구를 올바르게 사용하는 방법으로 비유할 수 있다. 
<h3>디자인 패턴</h3>
➜ 요리법, 레시피로 비유할 수 있다. 

<hr>
<h4>객체지향의 4대 특성</h4>

<ul>
<li>추상화 (모델링)
  ➜ 객체들의 공통적인 특성(기능)을 뽑아 이름을 붙이는 것</li>
<li>다형성 (사용편의성)
  ➜ 오버라이딩(메서드 재정의), 오버로딩(메서드 중복 정의)을 통해 다형성을 제공하고 이는 개발자에게 사용 편의성을 제공한다. </li>
<li>캡슐화 (은닉화)
  ➜ 특정 객체가 독립적으로 역할을 수행하기 위해 필요한 기능을 묶은 것으로 정보에 대한 접근에 제한을 두는 것을 의미한다. </li>
<li>상속 (재사용성, 확장)
  ➜ 상위 개념을 하위 개념이 물려받음을 의미한다. </li>
</ul>
<BR>   

<h4>상위 클래스와 인터페이스</h4>

<p>➜ 상위 클래스는 물려줄 특성이 많을수록 이상적이다. (because of LSP)
➜ 인터페이스는 구현을 강제할 메서드가 적을수록 이상적이다. (because of ISP)</p>
<h4>다중 상속</h4>

<p>➜ 자바는 부모 클래스를 하나 이상 가질 수 없다. 허나 인터페이스는 추상클래스보다 더욱 추상적이기에 여러 인터페이스 상속을 받을 수 있기는 하다.</p>
<h4>추상 클래스</h4>

<p>사용하는 이유 1 : 객체 타입 강제를 위해 ➜ 단적인 예로 누가 실수로 &quot;동물&quot; 객체를 만들면 안되기 때문이다. 
사용하는 이유 2 : 메서드 내용 구현 자율화를 위해➜ 행위를 어떻게 구현할까(구체화)에 대한 자율성 부여</p>
<h4>final 키워드 출몰 지역</h4>

<ol>
<li>클래스 -&gt; 상속 금지</li>
<li>변수 -&gt; 데이터 변경 불가 (상수)</li>
<li>메서드 -&gt; 오버라이딩 금지</li>
</ol>
<blockquote>

<h4>객체지향 설계 5원칙</h4>

<p><img src="https://velog.velcdn.com/images/yang_11/post/4389b10d-ddb5-4704-88d6-41eee487d47e/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/yang_11/post/cdee4d86-ffb0-4800-b7f7-dae17ee13db9/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/yang_11/post/b99fc9dd-90fa-460b-8203-0fa9ea6b4eb2/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/yang_11/post/e8b36674-7138-478d-9947-fb96e711fc7b/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/yang_11/post/0da8207b-eb51-4dae-bb88-ccd59e8c2878/image.png" alt=""></p>
</blockquote>




<hr>
]]></description>
        </item>
    </channel>
</rss>