<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>hyeon_geun.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Thu, 17 Aug 2023 03:13:19 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>hyeon_geun.log</title>
            <url>https://velog.velcdn.com/images/hyeon_geun/profile/22b76587-5e99-459e-92f3-212073f962bd/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. hyeon_geun.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hyeon_geun" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[JS] Vanilla javascript 로 테트리스 만들기]]></title>
            <link>https://velog.io/@hyeon_geun/JS-Vanilla-javascript</link>
            <guid>https://velog.io/@hyeon_geun/JS-Vanilla-javascript</guid>
            <pubDate>Thu, 17 Aug 2023 03:13:19 GMT</pubDate>
            <description><![CDATA[<h2 id="🧸-intro">🧸 Intro</h2>
<p>Vanilla javascript 로 할만한 간단한 프로젝트가 뭐가 있을까 고민을 하다가 유튜브 강의 중에 바닐라 자바스크립트로 테트리스 만들기가 있어서 한 번 따라 만들어 봤다.</p>
<blockquote>
<p><a href="https://www.youtube.com/watch?v=1lNy2mhvLFk">https://www.youtube.com/watch?v=1lNy2mhvLFk</a></p>
</blockquote>
<hr>
<h2 id="🎲-function">🎲 Function</h2>
<p>기본적인 테트리스 게임의 기능만 구현했다.
<em>(시간이 된다면 CSS 및 다른 기능들을 추가할 예정이다)</em></p>
<h3 id="블록-생성-및-제거">블록 생성 및 제거</h3>
<ul>
<li><p>게임을 시작했을 때와 블록이 다 내려왔을 때, 새로운 블록을 랜덤으로 생성한다. 생성된 블록은 일정한 속도로 내려온다. </p>
</li>
<li><p>(점수가 높아질수록 속도 추가예정 ..)*</p>
</li>
<li><p>한 줄이 블록으로 모두 차게 되면, 해당 라인을 제거하고 최상단에 새로운 라인을 추가한다.</p>
</li>
<li><p>라인을 제거하면 점수를 추가한다.</p>
</li>
<li><p>(한 번에 많이 제거하면 점수 ++ 예정)* </p>
</li>
</ul>
<p><strong>주요 코드</strong></p>
<pre><code class="language-js">function prependNewLine(){
    const li = document.createElement(&quot;li&quot;);
    const ul = document.createElement(&quot;ul&quot;);
    for (let j = 0; j &lt; GAME_COLS; j++) {
        const matrix = document.createElement(&quot;li&quot;);
        ul.prepend(matrix);
    }
    li.prepend(ul);
    playground.prepend(li);
}

function renderBlocks(moveType=&quot;&quot;){
    //변수에 바로 접근할 수 있도록 선언.
    const { type, direction, top, left } = tmpMovingItem;
    const movingBlocks = document.querySelectorAll(&quot;.moving&quot;);
    movingBlocks.forEach((moving) =&gt;{
        moving.classList.remove(type, &quot;moving&quot;);
    })
    // forEach 대신 some 사용 &gt; 원하는 시점에 멈출 수 있게
    BLOCKS[type][direction].some(block=&gt;{
        const x = block[0] + left;
        const y = block[1] + top;
        const target = playground.childNodes[y] ? playground.childNodes[y].childNodes[0].childNodes[x] : null;
        const isAvailable = checkEmpty(target);
        if (isAvailable) {
            target.classList.add(type, &quot;moving&quot;);
        } else {
            tmpMovingItem = { ... movingItem }
            if(moveType === &#39;retry&#39;){
                clearInterval(downInterval);
                showGameOverText();
            }
            //콜스택 에러방지
            setTimeout(()=&gt;{
                renderBlocks(&#39;retry&#39;);
                if(moveType === &quot;top&quot;){
                    seizeBlock();
                }
            }, 0)
            return true;
        }
    })
    movingItem.left = left;
    movingItem.top = top;
    movingItem.direction = direction;
}</code></pre>
<h3 id="블록의-위치">블록의 위치</h3>
<ul>
<li>좌,우 방향키를 눌렀을 때 블록 위치를 좌,우로 옮긴다.</li>
<li>아래 방향키를 눌렀을 때 블록을 아래로 내린다.</li>
<li>위 방향키를 눌렀을 때 블록의 모양을 바꾼다.</li>
<li>블록을 이동시킬 때 격자를 넘어가지 못하게 한다.</li>
<li>블록이 더이상 내려가지 못하면 새로운 블록을 생성한다.</li>
</ul>
<p><strong>주요 코드</strong></p>
<pre><code class="language-js">document.addEventListener(&quot;keydown&quot;, (e)=&gt;{
    switch (e.keyCode){
        case 39:
            moveBlock(&quot;left&quot;, 1);
            break;
        case 37:
            moveBlock(&quot;left&quot;, -1);
            break;
        case 40:
            moveBlock(&quot;top&quot;, 1);
            break;
        case 38:
            chageDirection();
            break;
        case 32:
            dropBlock();
            break;
        default :
            break;
    }
})</code></pre>
<h3 id="게임-시작-및-종료">게임 시작 및 종료</h3>
<ul>
<li>새로운 블록이 생성될 수 없을 때 게임 종료 메세지를 띄운다.</li>
<li>게임 종료 시 다시 시작 버튼을 누르면 게임을 시작할 수 있다.</li>
<li>재시작시 점수와 게임 화면을 리셋한다.</li>
<li><em>주요 코드*</em><pre><code class="language-js">function init(){
   // 값만 따오는 것이기 때문에 tmpMovingItem 은 변경 x &gt;&gt; 값을 복사
   tmpMovingItem = { ...movingItem };
   for (let i = 0; i &lt; GAME_ROWS; i++) {
       prependNewLine();
   }
   generateNewBlock();
}</code></pre>
</li>
</ul>
<br>

<h3 id="github-전체-코드">GitHub [전체 코드]</h3>
<blockquote>
<p><a href="https://github.com/hyeongeunee/ToyPJ_TETRIS">https://github.com/hyeongeunee/ToyPJ_TETRIS</a></p>
</blockquote>
<hr>
<h2 id="💡-만들면서-배운-것">💡 만들면서 배운 것</h2>
<br>

<h3 id="🔎-반복문-사용하기">🔎 반복문 사용하기</h3>
<p>반복문을 사용할 때 상황에 따라 <code>some()</code>이나 <code>every()</code>를 사용해보자 !</p>
<p><i><code>forEach</code>를 쓰게 되면 반복문을 중단할 수 없다.</i> </p>
<blockquote>
<p><strong><code>some()</code></strong>
성능을 위해 <strong>조건을 만족하는 값</strong>이 발견되면 그 즉시 순회가 중단된다 (Return True)</p>
</blockquote>
<p><strong>사용 예시</strong></p>
<pre><code class="language-js">var testArr = [1, 2, 3, 4, 5]

testArr.some(el =&gt; {
    if(el === 2) { return true }
    console.log(el)
})


// 출력
&gt; 1

--------------
var testArr = [1, 2, 3, 4, 5]

testArr.some(el =&gt; {
    if(el === 2) { return false }
    console.log(el)
})

// 출력
&gt; 1
&gt; 3
&gt; 4
&gt; 5</code></pre>
<blockquote>
<p><strong><code>every()</code></strong>
<strong>모든</strong> 원소가 <strong>조건을 만족</strong>하면 <code>true</code>, 하나라도 <strong>만족하지 않으면</strong> <code>false</code>를 반환</p>
</blockquote>
<p><strong>사용 예시</strong></p>
<pre><code class="language-js">var testArr = [1, 2, 3, 4, 5]

testArr.every(el =&gt; el &gt; 3); // false
testArr.every(el =&gt; el &gt;= 1); // true</code></pre>
<hr>
<h3 id="🔎-wrapper의-개념">🔎 Wrapper의 개념</h3>
<p><strong>wrapper</strong>는 <strong>단일 요소를 감싸는 경우 사용</strong>한다 !</p>
<blockquote>
<p><strong>단일 요소</strong>를 감싸는 <code>div</code>인 경우 <code>wrapper</code>를,
<strong>여러 요소</strong>를 감싸는 경우 <code>container</code>를 사용한다고 한다.</p>
</blockquote>
<p><strong>사용 예시</strong></p>
<pre><code class="language-js">&lt;ul class=&quot;items-container&quot;&gt;
    &lt;li class=&quot;item-wrapper&quot;&gt;
        &lt;div class=&quot;item&quot;&gt;...&lt;/div&gt;
    &lt;/li&gt;
    &lt;li class=&quot;item-wrapper&quot;&gt;
        &lt;div class=&quot;item&quot;&gt;...&lt;/div&gt;
    &lt;/li&gt;
    &lt;li class=&quot;item-wrapper&quot;&gt;
        &lt;div class=&quot;item&quot;&gt;...&lt;/div&gt;
    &lt;/li&gt;
&lt;/ul&gt;</code></pre>
<hr>
<h3 id="🔎-얕은-복사에-대해서">🔎 얕은 복사에 대해서...</h3>
<p>객체를 복사할 때 얕은 복사를 조심하자 !
<code>movingItem</code>은 이전의 상태를 불러오기 위해 사용하는 객체이므로 <strong>spread 연산자</strong>를 활용하여 프로퍼티를 깊은 복사했다.</p>
<blockquote>
<p><code>const tempMovingItem = { ...movingItem }</code>
이와 같이 객체를 복사하면 얕은 복사가 되기 때문에 <code>tempMovingItem</code>의 값을 변경하게 되면 원본인 <code>movingItem</code>도 같이 변하게 된다.</p>
</blockquote>
<br>

<h3 id="🤔-얕은-복사-shllow-copy">🤔 얕은 복사 (Shllow Copy)</h3>
<blockquote>
<p><strong>얕은 복사</strong>란 객체를 복사할 때 기존 값과 복사된 값이 <strong>같은 참조를 가리키고 있는 것</strong>을 말한다.</p>
</blockquote>
<p>객체 안에 객체가 있을 경우 <strong>한 개의 객체라도 기존 변수의 객체를 참조</strong>하고 있다면 이를 <strong>얕은 복사</strong>라고 한다.</p>
<p><strong>사용 예시</strong></p>
<pre><code class="language-js">const obj = { a: 1 };
const copyObj = obj;

copyObj.a = 2;

console.log(obj.a); // 2
console.log(obj === copyObj); // true</code></pre>
<h3 id="🤔-깊은-복사-deep-copy">🤔 깊은 복사 (Deep Copy)</h3>
<blockquote>
<p><strong>깊은 복사</strong>된 객체는 객체 안에 객체가 있을 경우에도 <strong>원본과의 참조가 완전히 끊어진 객체</strong>를 말한다.</p>
</blockquote>
<p><strong>사용 예시</strong></p>
<pre><code class="language-js">const a = 1;
const b = a;

b = 2;

console.log(a); // 1
console.log(b); // 2
console.log(a === b); // false</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[React Lifecycle]]></title>
            <link>https://velog.io/@hyeon_geun/React-Lifecycle</link>
            <guid>https://velog.io/@hyeon_geun/React-Lifecycle</guid>
            <pubDate>Thu, 17 Aug 2023 02:50:11 GMT</pubDate>
            <description><![CDATA[<h2 id="🌱-react-lifecycle">🌱 React Lifecycle</h2>
<p><strong>React</strong>는 컴포넌트 기반의 <strong>view</strong>를 중심으로 한 라이브러리이다. 각각의 컴포넌트에는 라이프 사이클 즉, 컴포넌트의 생명 주기가 존재한다.
<img src="https://velog.velcdn.com/images/hyeon_geun/post/c9c44e0b-eac9-4c26-8297-727da532f249/image.png" alt=""></p>
<blockquote>
<p><strong>React</strong>에서는 <code>생성(Mount)</code> -&gt; <code>업데이트(Update)</code> -&gt; <code>제거(Unmount)</code>의 <strong>생명주기</strong>를 갖는다.</p>
</blockquote>
<hr>
<h3 id="🤔-mount">🤔 Mount</h3>
<blockquote>
<p>DOM이 생성된 후, <u>웹 브라우저에 <strong>최종적으로 나타나는 것</strong></u>을 <strong>mount</strong>라고 한다.</p>
</blockquote>
<ul>
<li><p><strong>constructor</strong>
컴포넌트 생성자 메서드이자, 컴포넌트가 생성되면 가장 먼저 실행되는 메서드.
이 메서드에서는 초기 state를 정할 수 있다.</p>
</li>
<li><p><strong>render</strong>
컴포넌트를 렌더링하는 메서드. 가장 기초적이자 가장 중요한 메서드이다.</p>
</li>
<li><p><strong>componenetDidMount</strong>
컴포넌트의 첫 렌더링이 끝난 후 실행되는 메서드이고, 이 메서드가 실행되는 시점에는 이미 컴포넌트가 화면에 출력된 상태
여기서는 주로 DOM을 사용해야 하는 외부 라이브러리 연동, <code>axios</code>, <code>fetch</code>등을 사용해서 <strong>데이터를 요청하는 작업</strong>들을 진행한다.</p>
</li>
</ul>
<hr>
<h3 id="🤔-update">🤔 Update</h3>
<blockquote>
<p>컴포넌트가 업데이트 되는 시점 즉, <strong>리렌더링을 완료한 후에 실행</strong>된다.</p>
</blockquote>
<ul>
<li><strong>getDerivedStateFromProps</strong>
리액트에서의 컴포넌트 업데이트 감지는 현재 컴포넌트에서 state나 props의 변경 유무로만 판단한다.
이 때 사용되는 메서드가 getDerivedStateFromProps이다.</li>
</ul>
<blockquote>
<p> <strong>if, state의 변경이 일어났다면?</strong>
리액트는 효율적으로 state의 <u>변경사항을 감지</u>해 다시 변경된 부분을 그려준다.</p>
</blockquote>
<ul>
<li><strong>componentDidUpdate</strong>
컴포넌트의 변경이 완료되었을 때 실행되는 메서드이다.
의존성 배열이 변할때만 useEffect가 실행하는 것과 같다.</li>
</ul>
<hr>
<h3 id="🤔-unmount">🤔 Unmount</h3>
<blockquote>
<p><strong>unmount</strong>는 <strong>컴포넌트가 화면에서 사라지는 것</strong>을 뜻한다.</p>
</blockquote>
<ul>
<li><strong>componentWillUnmount</strong>
이 메서드는 컴포넌트가 사라지기 전에 호출된다. 주로 DOM에서 직접 등록했던 이벤트를 제거하는 등의 작업을 한다.
여기서는 컴포넌트 내부에서 타이머나 비동기 API를 사용하고 있을 때, 이를 제거하기에 유용하다. (setInterval, eventListener 등)</li>
</ul>
<hr>
<h4 id="참고">참고</h4>
<p><a href="https://react.vlpt.us/basic/25-lifecycle.html">https://react.vlpt.us/basic/25-lifecycle.html</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React #1]]></title>
            <link>https://velog.io/@hyeon_geun/React-1</link>
            <guid>https://velog.io/@hyeon_geun/React-1</guid>
            <pubDate>Thu, 17 Aug 2023 02:21:53 GMT</pubDate>
            <description><![CDATA[<h3 id="💡-react-생성">💡 React 생성</h3>
<blockquote>
</blockquote>
<ol>
<li><code>Node.js</code> install</li>
<li><code>npm / yarn</code> install</li>
<li><code>IDE</code> install (visual studio code)</li>
<li><code>Git</code> install</li>
<li>터미널에 <code>create-react-app</code> 명령어로 프로젝트 생성</li>
</ol>
<pre><code>npx create-react-app 프로젝트명</code></pre><hr>
<h3 id="🤔-usestate">🤔 useState</h3>
<blockquote>
<p><strong>useState</strong> 는 가장 기본적인 <code>Hook</code> 으로서, 함수형 컴포넌트에서도 <strong>가변적인 상태</strong>를 지니고 있을 수 있게 해준다.</p>
</blockquote>
<p>만약 <strong>함수형 컴포넌트에서 상태를 관리</strong>해야 되는 일이 발생한다면 <strong>useState</strong>를 사용하면 된다.</p>
<p><strong>사용 예시</strong></p>
<pre><code class="language-jsx">import React, { useState } from &#39;react&#39;;

const Counter = () =&gt; {
  const [count, setCount] = useState(0);
  return (
    &lt;div&gt;
      &lt;p&gt;
        현재 카운터 값은 &lt;b&gt;{count}&lt;/b&gt; 입니다.
      &lt;/p&gt;
      &lt;button onClick={() =&gt; setCount(count + 1)}&gt;+1&lt;/button&gt;
      &lt;button onClick={() =&gt; setCount(count - 1)}&gt;-1&lt;/button&gt;
    &lt;/div&gt;
  );
};</code></pre>
<hr>
<h3 id="🤔-useeffect">🤔 useEffect</h3>
<blockquote>
<p><strong>useEffect</strong>는 리액트 컴포넌트가 <u>렌더링 될 때마다 특정 작업을 수행하도록 설정</u> 할 수 있는 <code>Hook</code>이다.</p>
</blockquote>
<p><strong>사용 예시</strong></p>
<pre><code class="language-jsx">const UnmountTest = () =&gt; {
    useEffect(() =&gt; {
        console.log(&#39;Mount!&#39;);

        return () =&gt; {
            // Unmount 시점에 실행되게 함
            console.log(&#39;Unmount!&#39;);
        };
    }, []);
    return &lt;div&gt;Unmount Testing Component&lt;/div&gt;;
};</code></pre>
<p>주로, <strong>마운트 시에 하는 작업</strong>들은 다음과 같은 사항들이 있다.</p>
<ul>
<li>props 로 받은 값을 컴포넌트의 로컬 상태로 설정</li>
<li>외부 API 요청 (REST API 등)</li>
<li>라이브러리 사용 (D3, Video.js 등...)</li>
<li>setInterval 을 통한 반복작업 혹은 setTimeout 을 통한 작업 예약</li>
</ul>
<p><strong>언마운트 시에 하는 작업</strong>들은 다음과 같은 사항이 있다.</p>
<ul>
<li>setInterval, setTimeout 을 사용하여 등록한 작업들 clear 하기 (clearInterval, clearTimeout)</li>
<li>라이브러리 인스턴스 제거</li>
</ul>
<hr>
<h3 id="🤔-usecontext">🤔 useContext</h3>
<p>일반적인 React 데이터는 <code>props</code>를 통해서 부모에서 자식에게 전달 되지만, 어플리케이션 안의 <u>여러 컴포넌트들에게 props를 전달해줘야 하는 경우</u> <strong>context를 이용</strong>하면 명시적으로 <strong>props를 넘겨주지 않아도 값을 공유</strong>할 수 있게 해주는 것이다.</p>
<blockquote>
<p>데이터가 필요할 때마다 props를 통해 전달할 필요가 없이 <strong>context 를 이용해 공유</strong>한다</p>
</blockquote>
<p><strong>createContext</strong> 
-context 객체 생성
<strong>Provider **
-생성한 context를 하위 컴포넌트에게 전달
**Consumer</strong> 
-context의 변화를 감시</p>
<pre><code class="language-jsx">const ThemeContext = React.createContext();

function App() {
  const theme = /* some theme data */;
  return (
    &lt;ThemeContext.Provider value={theme}&gt;
      &lt;Header /&gt;
      &lt;MainContent /&gt;
    &lt;/ThemeContext.Provider&gt;
  );
}

function Header() {
  const theme = useContext(ThemeContext);
  // Header 컴포넌트에서 theme 사용
}

function MainContent() {
  const theme = useContext(ThemeContext);
  // MainContent 컴포넌트에서 theme 사용
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Maven & Gradle]]></title>
            <link>https://velog.io/@hyeon_geun/Gradle</link>
            <guid>https://velog.io/@hyeon_geun/Gradle</guid>
            <pubDate>Thu, 17 Aug 2023 01:09:55 GMT</pubDate>
            <description><![CDATA[<h2 id="🤔-maven">🤔 Maven</h2>
<p><img src="https://velog.velcdn.com/images/hyeon_geun/post/9694e527-e9f5-4645-ac0d-2dc44374d5a5/image.png" alt=""></p>
<p><strong>Maven</strong>은 자바 프로젝트의 빌드(build)를 자동화 해주는 빌드 툴(build tool)이다.</p>
<p><i>Maven에 관한 자세한 내용은 아래 링크에 정리되어 있다. </i></p>
<blockquote>
<p><a href="https://velog.io/@hyeon_geun/Maven">https://velog.io/@hyeon_geun/Maven</a></p>
</blockquote>
<hr>
<h2 id="📖-gradle">📖 Gradle</h2>
<p><img src="https://velog.velcdn.com/images/hyeon_geun/post/8a10328f-06c6-424a-a0cf-b98646c7ac01/image.png" alt=""></p>
<blockquote>
<p><strong>Gradle</strong>이란 기본적으로 빌드 배포 도구(Build Tool)이다. 안드로이드 앱을 만들때 필요한 공식 빌드시스템이기도 하며 <code>JAVA</code>, <code>C/C++</code>, <code>Python</code> 등을 지원한다.</p>
</blockquote>
<p>기본 메이븐의 경우 XML로 라이브러리를 정의하고 활용하도록 되어 있으나, <strong>Gradle</strong>의 경우 <u>별도의 빌드스크립트를 통하여 사용할 어플리케이션 버전, 라이브러리등의 항목을 설정 할 수 있다</u>.</p>
<p>장점으로는 <strong>스크립트 언어로 구성</strong>되어 있기때문에, XML과 달리 <strong><code>변수선언</code>, <code>if-else</code>, <code>for</code>등의 로직이 구현가능</strong>하여 간결하게 구성 가능하다.</p>
<ul>
<li><p><strong>라이브러리 관리</strong> : 메이븐 레파지토리를 동일하게 사용할 수 있어서 설정된 서버를 통하여 라이브러리를 다운로드 받아 모두 동일한 의존성을 가진 환경을 수정할 수 있다. 자신이 추가한 라이브러리도 레파지토리 서버에 올릴 수 있다.</p>
</li>
<li><p><strong>프로젝트 관리</strong> : 모든 프로젝트가 일관된 디렉토리 구조를 가지고 빌드 프로세스를 유지하도록 도와준다.</p>
</li>
<li><p><strong>단위 테스트 시 의존성 관리</strong> : junit 등을 사용하기 위해서 명시한다.</p>
</li>
</ul>
<p>** 사용 예시 **</p>
<pre><code>// 자바를 컴파일하기 위해 java plugin을 설정한다. 
apply plugin: &#39;java&#39; 
// application으로 컴파일하기 위해 설정한다. 
apply plugin: &#39;application&#39; 

//저장소를 입력하는 섹션이다. 주로 Maven의 저장소를 그대로 사용한다.
repositories { 
    mavenCentral()
}
//종속성을 입력하는 섹션이다. 기존에는 compile이 있었으나 3.0버전부터 deprecated 되었다.
dependencies {
    //&#39;group:name:version&#39; 순으로 적는다. group: &#39;junit&#39;, name: &#39;junit&#39;, version: &#39;4.12&#39;식으로도 가능하다.
    api &#39;com.google.guava:guava:22.0&#39; //간접 의존, 직접 의존하는 모든 모듈을 rebuild 한다
    implementation &#39;junit:junit:4.12&#39; //직접 의존하는 모듈만 rebuild 한다.
} 
application {
    // 메인 class의 위치와 이름을 적는다.
    mainClass = &#39;package.name.AppClass&#39;
}</code></pre><h3 id="gradle-특징">Gradle 특징</h3>
<ul>
<li><strong>가독성이 좋다</strong>
: 코딩에 의한 간결한 정의가 가능하므로 가독성이 좋다.</li>
<li><strong>재사용에 용이</strong>
: 설정 주입 방식(Configuration Injection)을 사용하므로 재사용에 용이하다.</li>
<li>*<em>구조적인 장점 *</em>
: Build Script를 Groovy 기반의 DSL(Domail Specific Language)를 사용하여 코드로서 설정 정보를 구성하므로 구조적인 장점이 있다.</li>
<li><strong>편리함</strong>
: Gradle 설치 없이 Gradle wrapper를 이용하여 빌드를 지원한다.</li>
<li><strong>멀티 프로젝트</strong>
: Gradle은 멀티 프로젝트 빌드를 지원하기 위해 설계된 빌드 관리 도구이다.</li>
<li><strong>지원</strong>
: Maven을 완전 지원한다.</li>
</ul>
<hr>
<h3 id="💡-gradle-vs-maven">💡 Gradle vs Maven</h3>
<p><img src="https://velog.velcdn.com/images/hyeon_geun/post/a8d78177-792c-4394-9b46-07e24833cb67/image.png" alt=""></p>
<blockquote>
<p>빌드 속도가 Maven에 비해 10~100배 가량 빠르다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring Boot #2]]></title>
            <link>https://velog.io/@hyeon_geun/Spring-Boot-2</link>
            <guid>https://velog.io/@hyeon_geun/Spring-Boot-2</guid>
            <pubDate>Thu, 17 Aug 2023 00:55:40 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-component">📌 Component</h2>
<p>구성요소라는 뜻으로 독립적인 단위 모듈을 뜻한다.
스프링 부트에선 <strong>IoC 컨테이너에 등록된 클래스</strong>를 뜻한다.</p>
<p><i><code>@Component</code> 어노테이션을 사용해 직접 작성한 클래스를 IoC 컨테이너에 등록 할 수 있다.</i></p>
<blockquote>
<h3 id="controller-component란">Controller Component란?</h3>
<p>Client의 요청을 직접적으로 받는 Component이다.
Cleint가 url을 통한 요청을 보내면 해당 url에 매칭되는 Controller가 해당 요청을 handle한다.</p>
</blockquote>
<h2 id="🤔-controller">🤔 Controller</h2>
<p><code>@Controller</code> 어노테이션을 통해 생성한 컨트롤러는 전통적인 <code>Spring MVC Framework</code>에서 주로 사용하는 컨트롤러이다. 이 컨트롤러의 주요 목적은 <u>View를 반환하기 위함</u>이다. 즉, <strong>Client에 요청에 따라 그에 맞는 View를 찾아 반환해주는 역할을 수행</strong>한다.</p>
<p><strong>사용 예시</strong></p>
<pre><code class="language-java">@Controller
@RequestMapping(&quot;/user&quot;)
public class UserController {

    @Resource(name = &quot;userService&quot;)
    private UserService userService;

    @PostMapping(value = &quot;/info&quot;)
    public @ResponseBody User info(@RequestBody User user){
        return userService.retrieveUserInfo(user);
    }

    @GetMapping(value = &quot;/infoView&quot;)
    public String infoView(Model model, @RequestParam(value = &quot;userName&quot;, required = true) String userName){
        User user = userService.retrieveUserInfo(userName);
        model.addAttribute(&quot;user&quot;, user);
        return &quot;/user/userInfoView&quot;;
    }

}</code></pre>
<h3 id="restcontroller">@RestController</h3>
<p><code>@RestController</code>는 <code>@Controller</code>에 <code>@ResponseBody</code> 어노테이션을 활용해 데이터를 반환하던 것과 같은 역할을 수행한다. 즉, <code>@RestController</code>는 View가 아니라 <strong>JSON와 같은 데이터를 반환하는 용도로 사용</strong>된다.</p>
<p><strong>사용 예시</strong></p>
<pre><code class="language-java">@RestController
@RequestMapping(&quot;/user&quot;)
public class UserController {

    @Resource(name = &quot;userService&quot;)
    private UserService userService;

    @PostMapping(value = &quot;/info1&quot;)
    public User info1(@RequestBody User user){
        return userService.retrieveUserInfo(user);
    }

    @PostMapping(value = &quot;/info2&quot;)
    public ResponseEntity&lt;User&gt; info2(@RequestParam(value = &quot;userName&quot;, required = true) String userName){
        User user = userService.retrieveUserInfo(userName);

        if(user == null){
            return ResponseEntity.noContent().build()
        }

        return ResponseEntity.ok(user)
    }

    @PostMapping(value = &quot;/info3&quot;)
    public ResponseEntity&lt;User&gt; info3(@RequestParam(value = &quot;userName&quot;, required = true) String userName){
        return Optional.ofNullable(userService.retrieveUserInfo(userName))
                .map(user -&gt; ResponseEntity.ok(user))
                .orElse(ResponseEntity.noContent().build());
    }
}</code></pre>
<hr>
<h3 id="🤔-webconfig">🤔 WebConfig</h3>
<p><strong>SpringBoot</strong>에서 <strong>WebConfig</strong> 설정을 할 때,<code>@EnableWebMvc</code>, <code>WebMvcConfigurer</code>를 설정하는 방법이 있다. </p>
<p><code>@EnableWebMvc</code>를 사용하거나 <strong>WebMvcConfigurer</strong>를 구현하지 않으면 아래와 같이 WebConfig 설정 시 <code>Bean</code>을 <strong>직접 등록</strong>해줘야하는 등으로 권장하지 않는 방법이라고 한다.</p>
<pre><code class="language-java">@Configuration
public class WebConfig {
    @Bean 
    public InternalResourceViewResolver viewResolver() {
           InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
           viewResolver.setPrefix(&quot;/WEB-INF/jsp/&quot;);
           viewResolver.setSuffix(&quot;.jsp&quot;);
           return viewResolver;
    }
}</code></pre>
<p><strong>WebMvcConfigurer</strong>는 SpringBoot의 자동 설정(WebMvcAutoConfiguration)을 유지하면서 기능을 쉽게 확장할 수 있게 해준다.</p>
<pre><code class="language-java">@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.jsp(&quot;/WEB-INF/jsp/&quot;,&quot;.jsp&quot;);
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring Boot #1]]></title>
            <link>https://velog.io/@hyeon_geun/Spring-Boot-1</link>
            <guid>https://velog.io/@hyeon_geun/Spring-Boot-1</guid>
            <pubDate>Mon, 17 Jul 2023 07:03:15 GMT</pubDate>
            <description><![CDATA[<h2 id="📖-aop">📖 AOP</h2>
<blockquote>
<p><strong>Aspect Oriented Programming(관점 지향 프로그래밍)</strong>의 약어</p>
</blockquote>
<p>어떠한 기준을 정하고, 관점을 나누어서 각 관점 별로 모듈화를 하여 사용하는 방식이다.</p>
<h3 id="aop-의-필요성">AOP 의 필요성</h3>
<p>일반적인 자바 애플리케이션은 웹 계층, 비즈니스 계층, 데이터 계층 등 여러 계층으로 응용 프로그램을 개발한다. </p>
<p>이때 각 계층의 책임은 다르지만 <u>로깅, 트랜잭션, 보안, 인증, 캐싱 등 공통적인 로직이 필요</u>하다. </p>
<p>이러한 공통적인 로직을 <strong>횡단 관심사(cross-cutting concern)</strong>이라고 부른다.</p>
<p>공통 로직을 각 계층에서 <strong>개별적으로 구현</strong>하면, <strong>코드 유지관리가 어려워</strong>진다.</p>
<p>이 문제를 <strong>극복하기 위해</strong> <u><strong>AOP는 횡단 관심사 구현</strong></u>하는 해결책을 제공한다.
<img src="https://velog.velcdn.com/images/hyeon_geun/post/43a16f75-a80c-4013-a66b-a3200fc860a7/image.png" alt=""></p>
<h3 id="aopaspect-oriented-programming의-장점">AOP(Aspect Oriented Programming)의 장점</h3>
<ol>
<li><strong>공통 관심 사항</strong>을 핵심 관심사항으로부터 <strong>분리</strong>시켜 핵심 로직을 깔끔하게 유지할 수 있다.</li>
<li>그에 따라 <strong>코드의 가독성, 유지보수성</strong> 등을 높일 수 있다.</li>
<li>각각의 모듈에 수정이 필요하면 다른 모듈의 수정 없이 해당 로직만 변경하면 된다.</li>
<li><strong>공통 로직을 적용할 대상을 선택</strong>할 수 있다</li>
</ol>
<blockquote>
<p>AOP는 <strong>횡단 관심사의 분리</strong>를 통해 <u>공통 기능을 한 곳에 정의</u>하여 모듈성을 증가시킨다.</p>
</blockquote>
<p>스프링은 내부에서 <strong>트랜잭션 관리, 캐싱, 보안</strong> 등의 선언적인 서비스를 구현하기 위해 <code>Spring AOP</code> 프레임워크를 제공한다. </p>
<blockquote>
</blockquote>
<p>스프링 프레임워크 대신 <code>AspectJ</code>를 애플리케이션에서 <strong>AOP 프레임워크로 사용</strong>할 수도 있다. </p>
<p><img src="https://velog.velcdn.com/images/hyeon_geun/post/4ba9290a-6259-44b6-8522-ea7293cf5335/image.png" alt=""></p>
<hr>
<h3 id="📌-1-의존성-추가">📌 1. 의존성 추가</h3>
<p><strong>Maven</strong></p>
<pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-aop&lt;/artifactId&gt;
    &lt;version&gt;2.5.5&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
<p><strong>Gradle</strong></p>
<pre><code class="language-xml">implementation group: &#39;org.springframework.boot&#39;, name: &#39;spring-boot-starter-aop&#39;, version: &#39;2.5.5&#39;</code></pre>
<hr>
<h3 id="📌-2-enableaspectautoproxy-적용">📌 2. @EnableAspectAutoProxy 적용</h3>
<blockquote>
<p><code>main</code> 메소드를 갖는 <code>Application</code> 클래스에 <code>@ Annotation</code>을 추가</p>
</blockquote>
<p><strong>예시</strong></p>
<p><strong>JavaConfig</strong></p>
<pre><code class="language-java">@Configuration
@EnableAspectJAutoProxy
public class JavaConfig {

    // MessengerAspect 를 bean 으로 만들기
    @Bean
    public MessengerAspect msa() {
        return new MessengerAspect();
    }
}</code></pre>
<p><strong>Application</strong></p>
<pre><code class="language-java">@SpringBootApplication
public class Boot02AopApplication {

    public static void main(String[] args) {
        ApplicationContext ctx = SpringApplication.run(Boot02AopApplication.class, args);

        Messenger m1 = ctx.getBean(Messenger.class);
        String msg = m1.getMessage();
        System.out.println(&quot;Messenger 객체로부터 받은 메세지 : &quot; + msg);

        m1.sendGreeting(&quot;안녕하세요&quot;);
        m1.sendGreeting(&quot;안녕 바보야&quot;);
        m1.sendGreeting(&quot;또 만났군요!&quot;);
    }
}</code></pre>
<hr>
<h3 id="📌-3-공통기능-정의와-공통기능-사용될-시점-정의advice-or-aspect">📌 3. 공통기능 정의와 공통기능 사용될 시점 정의(Advice or Aspect)</h3>
<ul>
<li>@Aspect, @Component 라는 어노테이션을 함께 붙여준다.</li>
<li>Advice 어노테이션 @Before, @After, @Around 등의 어노테이션을 메서드 단위에 붙여준다.</li>
<li>Advice 어노테이션에는 Point-cut 문법으로 부가기능을 적용할 대상을 설정한다.</li>
<li>부가기능의 적용 대상은 메서드 단위이다.</li>
<li>실제 부가기능을 수행하는 메서드를 Advice라고 부르기도 한다.</li>
<li>Advice 어노테이션, Point-cut 문법, Advice 메서드를 통틀어 Aspect라고 한다.</li>
</ul>
<h3 id="advice-종류">Advice 종류</h3>
<blockquote>
<ul>
<li><strong>@Before</strong> 
Target 메소드 호출 전에 적용 </li>
</ul>
</blockquote>
<ul>
<li><strong>@AfterReturning</strong>
Target 메소드 호출 후 적용  </li>
<li><strong>@AfterThrowing</strong>
Target에서 예외 발생 후 적용</li>
<li><strong>@After</strong>
Target 메소드 호출 후 예외 발생에 상관없이 적용  </li>
<li><strong>@Around</strong>
Target 메소드 호출 전/후 적용</li>
</ul>
<p>** 실행순서**
<img src="https://velog.velcdn.com/images/hyeon_geun/post/2cb9ad6c-fba5-4a77-bb4f-2d5bf0584383/image.png" alt=""></p>
<p>** 사용 예시 **</p>
<pre><code class="language-java">@Aspect
public class MessengerAspect {

    @Around(&quot;execution(void send*(..))&quot;)
    public void checkGreeting(ProceedingJoinPoint joinPoint) throws Throwable {

        // aspect 가 적용된 메소드가 호출되기 직전에 할 작업은 여기서 한다.

        // 메소드에 전달된 인자들 목록 얻어내기
        Object[] args = joinPoint.getArgs();
        for (Object tmp : args) {
            // 만일 String type 이면
            if (tmp instanceof String) {
                // 원래 type 으로 casting
                String msg = (String) tmp;
                System.out.println(&quot;aspect 에서 읽어낸 내용: &quot; + msg);
                if (msg.contains(&quot;바보&quot;)) {
                    System.out.println(&quot;바보는 금지된 단어입니다.&quot;);
                    return; // 메소드 끝내기
                }
            }
        }

        // aspect 가 적용된 메소드가 호출되기 직전에 할 작업은 proceed() 호출 전에 한다.

        // proceed() 를 호출해야 aspect 가 적용된 메소드가 실행이 된다.
        joinPoint.proceed();

        // aspect 가 적용된 메소드가 호출되기 직전에 할 작업은 proceed() 호출 이후에 한다.

        System.out.println(&quot;aspect 가 적용된 메소드가 리턴했습니다.&quot;);
    }

    /*
        return type 은 String 이고
        get 으로 시작은 메소드 이고
        메소드에 전달되는 인자는 없다
        java.lang 패키지에 있는 type 은 패키지명 생략 가능
     */
    @Around(&quot;execution(String com.example.aop.util.*.get*())&quot;)
    public Object checkReturn(ProceedingJoinPoint joinPoint) throws Throwable {

        // aspect 가 적용된 메소드를 수행하고 리턴되는 데이터 받아오기
        Object obj = joinPoint.proceed();

        // 원래 type 으로 casting 해서 조사해볼 수가 있다.
        String a = (String) obj;

        // 조사 후 아예 다른 값을 리턴해 줄 수도 있다.
        return &quot;놀자 ~~&quot;;
    }
}</code></pre>
<hr>
<h3 id="🤔-정리">🤔 정리</h3>
<blockquote>
</blockquote>
<ul>
<li><strong>AOP</strong>는 <strong>핵심기능(Core Concerns)</strong>과 <strong>부가기능 (Cross Cutting Concerns)</strong>을 <strong>분리</strong>하여 개발할 수 있게 해 준다.<blockquote>
<br></blockquote>
</li>
<li>부가기능에 해당하는 코드인 <strong>어드바이스</strong>와 적용한 위치를 문법적으로 표현한 포인트 컷을 합친 개념이 <strong>Aspect</strong>이다.<blockquote>
<br></blockquote>
</li>
<li>스프링 AOP는 메소드 조인 포인트만 지원하여 간단하게 쉽게 AOP를 구현할 수 있다.<blockquote>
<br></blockquote>
</li>
<li><strong>포인트 컷의 문법을 이용하여 원하는 위치에 부가기능 어드바이스를 추가</strong>할 수 있다.<blockquote>
<br></blockquote>
</li>
<li><strong>Advice</strong>는 타깃 객체 이전과 이후 그리고 이전/이후 모두에 적용 가능하다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring #4]]></title>
            <link>https://velog.io/@hyeon_geun/Spring-4</link>
            <guid>https://velog.io/@hyeon_geun/Spring-4</guid>
            <pubDate>Tue, 11 Jul 2023 02:47:50 GMT</pubDate>
            <description><![CDATA[<h2 id="📖-인터셉터interceptor">📖 인터셉터(Interceptor)</h2>
<blockquote>
<p>&#39;<u>가로채다</u>&#39; 라는 의미가 있다.
위의 의미와 같이 <strong>Client</strong>에서 <strong>Server</strong>로 보낸 <code>Request</code>를 <code>Controller</code>에 도달하기 전 가로채도록 하는 역할을 한다.
<strong>Dispatcher Servlet이 Controller를 호출하기 전 / 후에 인터셉터가 끼어들어 요청과 응답을 참조하거나 가공할 수 있는 기능을 제공</strong>한다.</p>
</blockquote>
<p>웹 컨테이너에서 동작하는 필터와 달리 <strong>인터셉터는 스프링 컨텍스트에서 동작</strong>한다.</p>
<p>디스패처 서블릿이 핸들러 매핑을 통해 컨트롤러를 찾도록 요청하는데, 그 결과로 실행 체인(HandlerExecutionChain)을 돌려준다.
여기서 1개 이상의 인터셉터가 등록되어 있다면 순차적으로 인터셉터들을 거쳐 컨트롤러가 실행되도록 하고,
인터셉터가 없다면 바로 컨트롤러를 실행한다.</p>
<blockquote>
<p>실제로 Interceptor가 직접 Controller로 요청을 위임하는 것은 아니다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/hyeon_geun/post/020eaa93-d41b-4542-971e-e60d71da3bf8/image.png" alt=""></p>
<h3 id="💡-interceptor-의-장점">💡 Interceptor 의 장점</h3>
<blockquote>
<ul>
<li>누락에 대한 위험 감수</li>
</ul>
</blockquote>
<ul>
<li>코드 재사용성을 증가 시켜 메모리 낭비, 서버 부하 감소 가 있다.</li>
</ul>
<h3 id="📌-interceptor-의-메소드-종류">📌 Interceptor 의 메소드 종류</h3>
<p>인터셉터를 추가하기 위해서 org.springframework.web.servlet의 HandlerInterceptor 인터페이스를 구현(implements) 해야 하며, 다음과 같은 메소드를 가진다.</p>
<pre><code class="language-java">public interface HandlerInterceptor {

    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
// View의 모든 작업이 완료된 후 실행된다.
// 리소스를 반환해주기 적당한 메소드이다.
        return true;
    }

    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            @Nullable ModelAndView modelAndView) throws Exception {
// Controller 가 실행 후 View 가 생성되기 이전에 호출한다.
// ModelAndView 를 통해 View 에 들어가는 데이터를 조작할 수 있다.
    }

    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
            @Nullable Exception ex) throws Exception {
// Controller 가 호출되기 전에 실행된다.     // Controller 실행 전 처리할 작업이나 정보를 가공, 추가하는 경우 사용된다.
// return 값이 true 일 경우 정상적으로 Controller 로 접근하고
// false 일 경우 Controller 에 접근하지 않는다.
    }</code></pre>
<blockquote>
</blockquote>
<ul>
<li><strong>preHandle()</strong><ul>
<li>Controller가 <strong>호출되기 전에 실행</strong>된다.</li>
<li><u>Controller 실행 전 처리할 작업이나 정보를 가공, 추가하는 경우 사용</u>된다.</li>
<li>return 값이 true일 경우 정상적으로 Controller로 접근하고</li>
<li>false일 경우 Controller에 접근하지 않는다.<br>
></li>
</ul>
</li>
<li><strong>postHandle()</strong><ul>
<li>Controller가 실행 후 <strong>View가 생성되기 이전에 호출</strong>한다.</li>
<li><strong>ModelAndView</strong>를 통해 <u>View에 들어가는 데이터를 조작</u>할 수 있다.<br>
></li>
</ul>
</li>
<li><strong>afterCompletion()</strong><ul>
<li>View의 <strong>모든 작업이 완료된 후 실행</strong>된다.</li>
<li><strong>리소스를 반환</strong>해주기 적당한 메소드이다.</li>
</ul>
</li>
</ul>
<br>

<p><strong>사용 예시 LoginInterceptor</strong></p>
<pre><code class="language-java">// 로그인된 사용자인지 검사할 인터셉터
public class LoginInterceptor implements HandlerInterceptor {
    // Controller 메소드 수행직전에 로그인된 사용자 인지 검증을 해서
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception {
        // 세션 객체의 참조값을 얻어와서
        HttpSession session = request.getSession();
        String id = (String) session.getAttribute(&quot;id&quot;);
        // 만일 로그인을 하지 않았다면
        if (id == null) {
            // 로그인 페이지로 리다일렉트 이동시키고 false 를 리턴한다.

            // 원래 가려던 url 정보 읽어오기
            String url = request.getRequestURI();
            // GET 방식 전송 파라미터를 query 문자열로 읽어오기 ( a=xxx&amp;b=xxx&amp;c=xxx )
            String query = request.getQueryString();
            // 특수 문자는 인코딩을 해야한다.
            String encodedUrl;
            if (query == null) {// 전송 파라미터가 없다면
                encodedUrl = URLEncoder.encode(url);
            } else {
                // 원래 목적지가 /test/xxx.jsp 라고 가정하면 아래와 같은 형식의 문자열을 만든다.
                // &quot;/test/xxx.jsp?a=xxx&amp;b=xxx ...&quot;
                encodedUrl = URLEncoder.encode(url + &quot;?&quot; + query);
            }

            // 3. 로그인을 하지 않았다면  /users/loginform 페이지로 리다일렉트 이동 시킨다. (HttpServletResponse)
            String cPath = request.getContextPath();
            response.sendRedirect(cPath + &quot;/users/loginform?url=&quot; + encodedUrl);
            return false;
        }
        // 로그인을 했다면 흐름을 이어간다.
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
        throws Exception {

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

<h3 id="🤔-필터filter와-인터셉터interceptor의-차이-및-비교">🤔 필터(Filter)와 인터셉터(Interceptor)의 차이 및 비교</h3>
<p>필터는 <code>Request</code>와 <code>Response</code>를 조작할 수 있지만, 인터셉터는 조작할 수 없다.</p>
<pre><code class="language-java">public class MyFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    throws IOException, ServletException {
        // 다른 request와 response를 넣어줄 수 있음
        chain.doFilter(request, response);
    }
}</code></pre>
<blockquote>
<p><strong>필터</strong>가 다음 필터를 호출하기 위해서는 필터 체이닝(다음 필터 호출)을 해주어야 한다.
이때 <code>request</code>, <code>response</code> 객체를 넘겨주므로 우리가 원하는 <code>request</code>, <code>response</code> 객체를 넣어줄 수 있다.</p>
</blockquote>
<p>하지만 인터셉터는 처리 과정이 필터와 다르다.</p>
<pre><code class="language-java">public class MyInterceptor implements HandlerInterceptor {

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 
    throws Exception {
        // Request, Response를 교체할 수 없고 boolean 값만 반환 가능
        return true;
    }
}</code></pre>
<blockquote>
<p>디스패처 서블릿이 여러 인터셉터 목록을 가지고 있고, 순차적으로 실행시킨다.
<code>true</code>를 반환하면 다음 인터셉터가 실행되거나 컨트롤러로 요청이 전달되며, <code>false</code>가 반환되면 요청이 중단된다.
그러므로 다른 <code>request</code>, <code>response</code> 객체를 넘겨줄 수 없다.</p>
</blockquote>
<h3 id="filter-와-interceptor-의-사용-사례">Filter 와 Interceptor 의 사용 사례</h3>
<p><strong>Filter 의 사용 사례</strong></p>
<ul>
<li>보안 및 인증/인가 관련 작업</li>
<li>모든 요청에 대한 로깅 또는 검사</li>
<li>이미지/데이터 압축 및 문자열 인코딩</li>
<li>Spring과 분리되어야 하는 기능</li>
</ul>
<blockquote>
<p><strong>필터</strong>는 기본적으로 스프링과 무관하게 <strong>전역적으로 처리해야 하는 작업들을 처리</strong>할 수 있다.
또한, <u>이미지나 데이터의 압축, 문자열 인코딩과 같이 웹 어플리케이션에 전반적으로 사용되는 기능을 구현</u>하기에 적당하다.</p>
</blockquote>
<p><strong>Interceptor 의 사용 사례</strong></p>
<ul>
<li>세부적인 보안 및 인증/인가 공통 작업</li>
<li>API 호출에 대한 로깅 또는 검사</li>
<li>Controller로 넘겨주는 정보(데이터)의 가공</li>
</ul>
<blockquote>
<p><strong>인터셉터</strong>에서는 <strong>클라이언트의 요청과 관련되어 전역적으로 처리해야 하는 작업들을 처리</strong>할 수 있다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring #3]]></title>
            <link>https://velog.io/@hyeon_geun/Spring-3</link>
            <guid>https://velog.io/@hyeon_geun/Spring-3</guid>
            <pubDate>Mon, 10 Jul 2023 09:04:16 GMT</pubDate>
            <description><![CDATA[<h2 id="mybatis">MyBatis</h2>
<blockquote>
<p>SQL Mapping 프레임워크로 흔히 분류된다.
개발자들은 JDBC 코드의 복잡하고 지루한 작업을 피하기 위해 사용한다.</p>
</blockquote>
<p><strong>&lt;전통적인 JDBC프로그램과 MyBatis의 구조 비교&gt;</strong></p>
<ul>
<li><p><strong>전통적인 JDBC프로그램</strong></p>
<ul>
<li>직접 <strong>Connection</strong>을 맺고 마지막에 <code>close()</code></li>
<li><strong>PreparedStatement</strong> 직접 생성 및 처리</li>
<li>PreparedStatement의 <code>setXXX()</code> 등</li>
<li><code>Select</code> 경우 <strong>ResultSet</strong> 직접 처리</li>
</ul>
</li>
<li><p><strong>MyBatis</strong></p>
<ul>
<li>자동으로 <code>Connection close()</code> 가능</li>
<li>MyBatis <strong>내부적으로 PreparedStatement 처리</strong></li>
<li><strong><code>#{prop}</code></strong> 과 같이 속성 지정하여 자동 처리</li>
<li><u>리턴 타입을 지정</u>하는 경우 <strong>자동으로 객체 생성 및 ResultSet 처리</strong></li>
</ul>
</li>
</ul>
<p>스프링은 다른 프레임워크들과의 연동을 쉽게 하는 추가적인 라이브러리들이 많다. MyBatis 또한 mybatis-spring 이라는 라이브러리를 통해 쉽게 연동이 가능하다.
<img src="https://velog.velcdn.com/images/hyeon_geun/post/ea76e073-6ee3-44ff-9e0b-e2cdae6007f9/image.png" alt=""></p>
<hr>
<h3 id="mybatis-관련-라이브러리">MyBatis 관련 라이브러리</h3>
<pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;org.mybatis&lt;/groupId&gt;
    &lt;artifactId&gt;mybatis&lt;/artifactId&gt;
    &lt;version&gt;3.4.6&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
    &lt;groupId&gt;org.mybatis&lt;/groupId&gt;
    &lt;artifactId&gt;mybatis-spring&lt;/artifactId&gt;
    &lt;version&gt;1.3.2&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
    &lt;groupId&gt;org.springframework&lt;/groupId&gt;
    &lt;artifactId&gt;spring-tx&lt;/artifactId&gt;
    &lt;version&gt;${org.springframework-version}&lt;/version&gt;
&lt;/dependency&gt;


&lt;dependency&gt;
    &lt;groupId&gt;org.springframework&lt;/groupId&gt;
    &lt;artifactId&gt;spring-jdbc&lt;/artifactId&gt;
    &lt;version&gt;${org.springframework-version}&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
<p><strong>MyBatis</strong>의 주요 <strong>Component</strong>와 동작 과정을 그림으로 표현하면 다음과 같다.
<img src="https://velog.velcdn.com/images/hyeon_geun/post/ae027629-7e95-42ea-b3cb-8004522e0159/image.png" alt=""></p>
<blockquote>
<ol>
<li>MyBatis Config 파일을 읽어 <strong>SqlSessionFactoryBuilder 객체를 생성</strong>한다.
MyBatis Config 파일에는 DB설정 정보, mapper 파일 등록, typeAlias설정 등이 들어있다.</li>
<li>SqlSessionFactoryBuilder 객체를 이용해 <strong>SqlSessionFactory 객체를 생성</strong>한다.</li>
<li>SqlSessionFactoryBuilder는 단순히 <strong>SqlSessionFactory 객체를 생성</strong>해주기 위한 용도다.</li>
<li>앱 실행 중(런타임)에 CRUD처리가 들어오면 SqlSessionFactory로 SqlSession 객체를 생성한다.</li>
<li>SqlSession 객체를 이용해 DB요청을 한 후, 결과값을 받아온다.</li>
</ol>
</blockquote>
<p>먼저 <strong>MyBatis Config</strong> 파일은 <code>XML</code>로 작성하고, 다음과 같이 작성할 수 있다.</p>
<p>아래 <code>MyBatis Config XML</code> 파일은 4개의 정보를 설정하고 있다.</p>
<blockquote>
</blockquote>
<ol>
<li>&lt;properties&gt;: 프로퍼티 파일을 정의합니다.<blockquote>
</blockquote>
</li>
<li>&lt;typeAliases&gt;: mapper.xml에서 사용할 alias를 설정합니다. (긴 패키지 경로 대신 짧은 단어 하나로 사용하기 위해)<blockquote>
</blockquote>
</li>
<li>&lt;environments&gt;: DB 정보를 설정합니다. &lt;property&gt;에 ${driver}로 적은 것은 위 &lt;properties&gt;에서 가져온 내용을 대입한다는 의미입니다.<blockquote>
</blockquote>
</li>
<li>&lt;mappers&gt;: 어떤 XML 파일이 mapper 파일인지를 설정합니다.</li>
</ol>
<h3 id="sqlsessionfactory">SQLSessionFactory</h3>
<blockquote>
<p><strong>SQLSession</strong>은 개발자가 이를 통해 <strong>Connection을 생성</strong>하거나 <strong>원하는 SQL을 전달하고, 결과를 리턴</strong> 받는 구조로 작성하게 된다.</p>
</blockquote>
<pre><code class="language-xml">&lt;beans:bean id=&quot;sqlSessionFactory&quot; class=&quot;org.mybatis.spring.SqlSessionFactoryBean&quot;&gt;
    &lt;property name=&quot;dataSource&quot; ref=&quot;dataSource&quot;/&gt;
      &lt;property name=&quot;configLocation&quot; value=&quot;classpath:Configuraion.xml&quot;/&gt;
&lt;/beans:bean&gt;</code></pre>
<p><img src="https://velog.velcdn.com/images/hyeon_geun/post/d6d60950-0f7f-4c4e-a02e-c339d51ffa3a/image.png" alt=""></p>
<h3 id="mapper">Mapper</h3>
<p><strong>Mapper</strong>을 작성하는 것은 <code>XML</code>을 이용할 수도 있지만 <u>인터페이스로도 가능</u>하다.</p>
<p><strong>MyBatis</strong>가 동작할 때 이 <strong>Mapper</strong>를 인식할 수 있도록 <code>root-context.xml</code>에 설정을 해야한다. 가장 간단한 방법은 <code>&lt;mybatis:scan&gt;</code> 태그를 이용하는 것이다.</p>
<p><code>root-context.xml &gt; Namespaces &gt; mybatis-spring</code> 탭 선택
아래 코드 작성한다.</p>
<pre><code class="language-xml">&lt;mybatis-spring:scan base-package=&quot;com.test.mapper&quot;/&gt;</code></pre>
<p><code>base-package</code>속성은 지정된 패키지의 모든 MyBatis 관련 어노테이션을 찾아 처리한다.
<br>
** Mapper 사용 예시<strong><br>
**[Configuration.xml]</strong></p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE configuration
        PUBLIC &quot;-//mybatis.org//DTD Config 3.0//EN&quot;
        &quot;http://mybatis.org/dtd/mybatis-3-config.dtd&quot;&gt;
&lt;configuration&gt;
    &lt;!-- 자주 사용하는 type 의 별칭을 등록해놓고 Mapper xml 에서 사용할 수 있다. --&gt;
    &lt;typeAliases&gt;
        &lt;typeAlias type=&quot;com.gura.spring.users.dto.UsersDto&quot; alias=&quot;usersDto&quot;/&gt;
        &lt;typeAlias type=&quot;com.gura.spring.file.dto.FileDto&quot; alias=&quot;fileDto&quot;/&gt;
        &lt;typeAlias type=&quot;com.gura.spring.cafe.dto.CafeDto&quot; alias=&quot;cafeDto&quot;/&gt;
        &lt;typeAlias type=&quot;com.gura.spring.cafe.dto.CafeCommentDto&quot; alias=&quot;cafeCommentDto&quot;/&gt;
        &lt;typeAlias type=&quot;com.gura.spring.gallery.dto.GalleryDto&quot; alias=&quot;galleryDto&quot;/&gt;
    &lt;/typeAliases&gt;

    &lt;!-- sql 문을 작성한 Mapper xml 문서가 어디에 있는지 목록을 작성해야 한다. --&gt;
    &lt;mappers&gt;
        &lt;mapper resource=&quot;mapper/UsersMapper.xml&quot;/&gt;
        &lt;mapper resource=&quot;mapper/FileMapper.xml&quot;/&gt;
        &lt;mapper resource=&quot;mapper/CafeMapper.xml&quot;/&gt;
        &lt;mapper resource=&quot;mapper/CafeCommentMapper.xml&quot;/&gt;
        &lt;mapper resource=&quot;mapper/GalleryMapper.xml&quot;/&gt;
    &lt;/mappers&gt;
&lt;/configuration&gt;</code></pre>
<br>

<p><strong>[UserMapper.xml]</strong></p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE mapper PUBLIC &quot;-//mybatis.org//DTD Mapper 3.0//EN&quot;
        &quot;http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;&gt;
&lt;mapper namespace=&quot;users&quot;&gt;
    &lt;insert id=&quot;insert&quot; parameterType=&quot;usersDto&quot;&gt;
        INSERT INTO USER_TB
            (ID, PWD, EMAIL, REGDATE)
        VALUES (#{id}, #{pwd}, #{email}, SYSDATE)
    &lt;/insert&gt;

    &lt;select id=&quot;getData&quot; parameterType=&quot;string&quot; resultType=&quot;usersDto&quot;&gt;
        SELECT ID, PWD, EMAIL, PROFILE, REGDATE
        FROM USER_TB
        WHERE ID = #{id}
    &lt;/select&gt;

    &lt;update id=&quot;updatePwd&quot; parameterType=&quot;usersDto&quot;&gt;
        UPDATE USER_TB
        SET PWD = #{newPwd}
        WHERE ID = #{id}
    &lt;/update&gt;

    &lt;update id=&quot;update&quot; parameterType=&quot;usersDto&quot;&gt;
        UPDATE USER_TB
        SET EMAIL = #{email}, PROFILE = #{profile}
        WHERE ID = #{id}
    &lt;/update&gt;

    &lt;delete id=&quot;delete&quot; parameterType=&quot;string&quot;&gt;
        DELETE FROM USER_TB
        WHERE ID = #{id}
    &lt;/delete&gt;
&lt;/mapper&gt;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring 프로젝트 생성(IntelliJ + Maven)]]></title>
            <link>https://velog.io/@hyeon_geun/Spring-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%83%9D%EC%84%B1IntelliJ-Maven</link>
            <guid>https://velog.io/@hyeon_geun/Spring-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%83%9D%EC%84%B1IntelliJ-Maven</guid>
            <pubDate>Thu, 06 Jul 2023 02:41:19 GMT</pubDate>
            <description><![CDATA[<h2 id="인텔리제이intellij에서-스프링-mvc-프로젝트-생성"><strong>인텔리제이(IntelliJ)</strong>에서 <strong>스프링 MVC 프로젝트 생성</strong></h2>
<blockquote>
<p>프로젝트를 구성하는 방법은 여러 가지가 있겠지만, 여기선 우선 Maven으로 프로젝트를 생성하고 Spring MVC 프레임워크를 추가하여 기본 틀을 만든 뒤에 라이브러리를 Maven으로 관리할 수 있도록 설정할 것이다.<br>
<em>(이클립스와 최대한 개발 환경 맞추기...😥)</em></p>
</blockquote>
<hr>
<h3> 1. 프로젝트 생성 </h3>

<blockquote>
<p><strong>New Project</strong>에서 <strong>Maven</strong>을 선택하고 <strong>JDK 버전</strong>을 설정한 뒤, <strong>Archetype</strong>을 <code>org.apache.maven.archetypes:maven-archetype-webapp</code> 으로 선택한 뒤 생성한다.
<img src="https://velog.velcdn.com/images/hyeon_geun/post/9e21679b-7904-407d-b172-e4c545b602c8/image.png" alt=""></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/hyeon_geun/post/b39d8c1d-b17f-43bf-a0f0-df3ee1988c84/image.png" alt=""></p>
<br>

<h3> 2. pom.xml 에 dependency 추가</h3>

<blockquote>
<p>다른 블로그들을 참고해보면 프로젝트에서 <code>Add FrameWork Support ...</code> 를 통해서 <code>Spring MVC</code> 를 추가하는데, 나는 눈을 씻고 찾아봐도 안나와서 <code>dependency</code> 에서 직접 추가했다.. 🤮</p>
</blockquote>
<p><strong><a href="https://mvnrepository.com/">https://mvnrepository.com/</a></strong> 에서 필요한 <code>dependency</code> 를 찾아서 추가한다.
💡 종류가 여러 개 있어서 뭘 추가해야하는지 모를 땐 그냥 <strong>많이 다운받은 걸</strong>로 하면 된다 !</p>
<blockquote>
</blockquote>
<p><strong><code>pom.xml</code></strong> 
<strong>springMVC, tomcat, jstl, jsp, servelt 추가</strong></p>
<pre><code class="language-xml">&lt;dependencies&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;junit&lt;/groupId&gt;
            &lt;artifactId&gt;junit&lt;/artifactId&gt;
            &lt;version&gt;3.8.1&lt;/version&gt;
            &lt;scope&gt;test&lt;/scope&gt;
        &lt;/dependency&gt;
&gt;
        &lt;!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework&lt;/groupId&gt;
            &lt;artifactId&gt;spring-webmvc&lt;/artifactId&gt;
            &lt;version&gt;3.0.1.RELEASE&lt;/version&gt;
        &lt;/dependency&gt;
&gt;
        &lt;!-- https://mvnrepository.com/artifact/javax.servlet/jstl --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;javax.servlet&lt;/groupId&gt;
            &lt;artifactId&gt;jstl&lt;/artifactId&gt;
            &lt;version&gt;1.2&lt;/version&gt;
        &lt;/dependency&gt;
&gt;
        &lt;!-- https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-jsp-api --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.apache.tomcat&lt;/groupId&gt;
            &lt;artifactId&gt;tomcat-jsp-api&lt;/artifactId&gt;
            &lt;version&gt;8.5.88&lt;/version&gt;
        &lt;/dependency&gt;
&gt;
        &lt;!-- https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-servlet-api --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.apache.tomcat&lt;/groupId&gt;
            &lt;artifactId&gt;tomcat-servlet-api&lt;/artifactId&gt;
            &lt;version&gt;8.5.88&lt;/version&gt;
        &lt;/dependency&gt;
&gt;
    &lt;/dependencies&gt;</code></pre>
<p><strong><code>pom.xml</code></strong>에 <code>dependency</code> 를 작성하고 나면 우측에 Maven 마크가 뜨는데 누르면 알아서 라이브러리에 추가해준다.
<img src="https://velog.velcdn.com/images/hyeon_geun/post/1e7c1c6b-39c7-4f59-b180-67dfc7163bf2/image.png" alt=""></p>
<blockquote>
</blockquote>
<p><strong>Spring MVC에서 기본적으로 설정해야 하는 dependency</strong></p>
<blockquote>
</blockquote>
<p><code>slf4j</code></p>
<pre><code class="language-xml">https://mvnrepository.com/artifact/org.slf4j/slf4j-api
  &lt;dependency&gt;
      &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
      &lt;artifactId&gt;slf4j-api&lt;/artifactId&gt;
      &lt;version&gt;1.7.36&lt;/version&gt;
  &lt;/dependency&gt;</code></pre>
<p><code>lombok</code></p>
<pre><code class="language-xml">https://mvnrepository.com/artifact/org.projectlombok/lombok
  &lt;dependency&gt;
      &lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
      &lt;artifactId&gt;lombok&lt;/artifactId&gt;
      &lt;version&gt;1.18.22&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
  &lt;/dependency&gt;</code></pre>
<p><code>logback-classic</code></p>
<pre><code class="language-xml">https://mvnrepository.com/artifact/ch.qos.logback/logback-classic
  &lt;dependency&gt;
      &lt;groupId&gt;ch.qos.logback&lt;/groupId&gt;
      &lt;artifactId&gt;logback-classic&lt;/artifactId&gt;
      &lt;version&gt;1.2.10&lt;/version&gt;
  &lt;/dependency&gt;</code></pre>
<p><code>jackson-databind</code></p>
<pre><code class="language-xml">https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
  &lt;dependency&gt;
      &lt;groupId&gt;com.fasterxml.jackson.core&lt;/groupId&gt;
      &lt;artifactId&gt;jackson-databind&lt;/artifactId&gt;
      &lt;version&gt;2.13.1&lt;/version&gt;
  &lt;/dependency&gt;</code></pre>
<blockquote>
</blockquote>
<hr>
<p><strong>spring framework 관련 dependency</strong><br>
<code>spring-framework-bom</code></p>
<pre><code class="language-xml">https://mvnrepository.com/artifact/org.springframework/spring-framework-bom
이 dependency는 spring-framework의 version 관리를 해준다.
지금까지는 RELEASE의 최고 버전 사용 중.
  &lt;dependency&gt;
      &lt;groupId&gt;org.springframework&lt;/groupId&gt;
      &lt;artifactId&gt;spring-framework-bom&lt;/artifactId&gt;
      &lt;version&gt;5.2.19.RELEASE&lt;/version&gt;
      &lt;scope&gt;import&lt;/scope&gt;
      &lt;type&gt;pom&lt;/type&gt;
  &lt;/dependency&gt;</code></pre>
<p>bom에서 따로 버전을 관리하기 때문에 이름만 변경해주면 동일하게 사용할 수 있다.
<code>1. spring-web</code>
<code>2. spring-webmvc</code></p>
<pre><code class="language-xml">  &lt;dependency&gt;
      &lt;groupId&gt;org.springframework&lt;/groupId&gt;
      &lt;artifactId&gt;spring-`사용할 dependency명`&lt;/artifactId&gt;
  &lt;/dependency&gt;</code></pre>
<hr>
<p><strong>spring-framework-bom을 사용하지 않을 경우</strong>
<code>1. spring-web</code></p>
<pre><code class="language-xml">https://mvnrepository.com/artifact/org.springframework/spring-web
      &lt;dependency&gt;
          &lt;groupId&gt;org.springframework&lt;/groupId&gt;
          &lt;artifactId&gt;spring-web&lt;/artifactId&gt;
          &lt;version&gt;5.2.19.RELEASE&lt;/version&gt;
      &lt;/dependency&gt;</code></pre>
<p><code>2. spring-webmvc</code></p>
<pre><code class="language-xml">    https://mvnrepository.com/artifact/org.springframework/spring-webmvc
      &lt;dependency&gt;
          &lt;groupId&gt;org.springframework&lt;/groupId&gt;
          &lt;artifactId&gt;spring-webmvc&lt;/artifactId&gt;
          &lt;version&gt;5.2.19.RELEASE&lt;/version&gt;
      &lt;/dependency&gt;</code></pre>
<hr>
<p><strong>spring security 관련 dependency</strong>
<code>spring-security-bom</code></p>
<pre><code class="language-xml">https://mvnrepository.com/artifact/org.springframework.security/spring-security-bom
위의 spring-security-bom의 version 관리해준다.
원래 spring-framework-bom의 버전보다 낮은 버전을 사용하는 게 훨씬 안전하지만 둘 다 RELEASE 버전을 사용하고 있기 때문에 그냥 제일 높은 버전을 사용함.
  &lt;dependency&gt;
      &lt;groupId&gt;org.springframework.security&lt;/groupId&gt;
      &lt;artifactId&gt;spring-security-bom&lt;/artifactId&gt;
      &lt;version&gt;5.3.13.REALASE&lt;/version&gt;
      &lt;type&gt;pom&lt;/type&gt;
  &lt;/dependency&gt;</code></pre>
<br>
>
bom에서 버전 관리를 하기 때문에 이름만 변경해주면 동일한 코드가 사용 가능하다.
`spring-security-core`, `spring-security-web`,
`spring-security-config`, `spring-security-taglibs`
```xml
  <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-'사용할 dependency명'</artifactId>
  </dependency>
```
>
`servlet-api`
```
https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api
웹 관련 요청에 대하여 동적인 처리를 도와주는 기술
  <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
      <scope>provided</scope>
  </dependency>
  ```
`jsp-api`
```
https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api
java 언어를 기반으로 웹 서비스를 제공하기 위해 만든 기술
  <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>javax.servlet.jsp-api</artifactId>
      <version>2.3.3</version>
      <scope>provided</scope>
  </dependency>
  ```
`jstl`
```
https://mvnrepository.com/artifact/javax.servlet/jstl
 <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
  </dependency>
  ```
  ---
**SQL 관련 dependency**<br>
`spring-jdbc`
```
https://mvnrepository.com/artifact/org.springframework/spring-jdbc
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
  </dependency>
  ```
`commons-dbcp2`
```
https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2
  <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-dbcp2</artifactId>
      <version>2.9.0</version>
  </dependency>
  ```
`spring-data-jpa`
```
https://mvnrepository.com/artifact/org.springframework.data/spring-data-jpa
  <dependency>
      <groupId>org.springframework.data</groupId>
      <artifactId>spring-data-jpa</artifactId>
      <version>2.3.9.RELEASE</version>
  </dependency>
  ```
`hibernate-core`
```
https://mvnrepository.com/artifact/org.hibernate/hibernate-core
  <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>5.6.5.Final</version>
  </dependency>
  ```
`spring-orm`
```
https://mvnrepository.com/artifact/org.springframework/spring-orm
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-orm</artifactId>
  </dependency>
  ```
`ojdbc8`
```
  <dependency>
      <groupId>com.oracle.database.jdbc</groupId>
      <artifactId>ojdbc8</artifactId>
      <version>21.1.0.0</version>
  </dependency>
  ```
  ---
**MyBatis 관련 dependency**<br>
`mybatis`
```
https://mvnrepository.com/artifact/org.mybatis/mybatis
  <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.9</version>
  </dependency>
  ```
`mybatis-spring`
```
https://mvnrepository.com/artifact/org.mybatis/mybatis-spring
  <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>2.0.7</version>
  </dependency>
  ```
<br>

<h4 id="pomxml-전체-코드"><strong><code>pom.xml</code> 전체 코드</strong></h4>
<pre><code class="language-xml">&lt;project xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot;
         xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd&quot;&gt;
    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
    &lt;groupId&gt;org.example&lt;/groupId&gt;
    &lt;artifactId&gt;SpringPj&lt;/artifactId&gt;
    &lt;packaging&gt;war&lt;/packaging&gt;
    &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;
    &lt;name&gt;SpringPj Maven Webapp&lt;/name&gt;
    &lt;url&gt;http://maven.apache.org&lt;/url&gt;
    &lt;properties&gt;
        &lt;java-version&gt;1.8&lt;/java-version&gt;
        &lt;org.springframework-version&gt;4.0.0.RELEASE&lt;/org.springframework-version&gt;
        &lt;org.aspectj-version&gt;1.6.10&lt;/org.aspectj-version&gt;
        &lt;org.slf4j-version&gt;1.6.6&lt;/org.slf4j-version&gt;
    &lt;/properties&gt;
    &lt;dependencies&gt;
        &lt;!-- Spring --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework&lt;/groupId&gt;
            &lt;artifactId&gt;spring-context&lt;/artifactId&gt;
            &lt;version&gt;4.0.0.RELEASE&lt;/version&gt;
            &lt;exclusions&gt;
                &lt;!-- Exclude Commons Logging in favor of SLF4j --&gt;
                &lt;exclusion&gt;
                    &lt;groupId&gt;commons-logging&lt;/groupId&gt;
                    &lt;artifactId&gt;commons-logging&lt;/artifactId&gt;
                &lt;/exclusion&gt;
            &lt;/exclusions&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework&lt;/groupId&gt;
            &lt;artifactId&gt;spring-webmvc&lt;/artifactId&gt;
            &lt;version&gt;4.0.0.RELEASE&lt;/version&gt;
        &lt;/dependency&gt;

        &lt;!-- AspectJ --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.aspectj&lt;/groupId&gt;
            &lt;artifactId&gt;aspectjrt&lt;/artifactId&gt;
            &lt;version&gt;${org.aspectj-version}&lt;/version&gt;
        &lt;/dependency&gt;

        &lt;!-- Logging --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
            &lt;artifactId&gt;slf4j-api&lt;/artifactId&gt;
            &lt;version&gt;${org.slf4j-version}&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
            &lt;artifactId&gt;jcl-over-slf4j&lt;/artifactId&gt;
            &lt;version&gt;${org.slf4j-version}&lt;/version&gt;
            &lt;scope&gt;runtime&lt;/scope&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
            &lt;artifactId&gt;slf4j-log4j12&lt;/artifactId&gt;
            &lt;version&gt;${org.slf4j-version}&lt;/version&gt;
            &lt;scope&gt;runtime&lt;/scope&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;log4j&lt;/groupId&gt;
            &lt;artifactId&gt;log4j&lt;/artifactId&gt;
            &lt;version&gt;1.2.15&lt;/version&gt;
            &lt;exclusions&gt;
                &lt;exclusion&gt;
                    &lt;groupId&gt;javax.mail&lt;/groupId&gt;
                    &lt;artifactId&gt;mail&lt;/artifactId&gt;
                &lt;/exclusion&gt;
                &lt;exclusion&gt;
                    &lt;groupId&gt;javax.jms&lt;/groupId&gt;
                    &lt;artifactId&gt;jms&lt;/artifactId&gt;
                &lt;/exclusion&gt;
                &lt;exclusion&gt;
                    &lt;groupId&gt;com.sun.jdmk&lt;/groupId&gt;
                    &lt;artifactId&gt;jmxtools&lt;/artifactId&gt;
                &lt;/exclusion&gt;
                &lt;exclusion&gt;
                    &lt;groupId&gt;com.sun.jmx&lt;/groupId&gt;
                    &lt;artifactId&gt;jmxri&lt;/artifactId&gt;
                &lt;/exclusion&gt;
            &lt;/exclusions&gt;
            &lt;scope&gt;runtime&lt;/scope&gt;
        &lt;/dependency&gt;

        &lt;!-- @Inject --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;javax.inject&lt;/groupId&gt;
            &lt;artifactId&gt;javax.inject&lt;/artifactId&gt;
            &lt;version&gt;1&lt;/version&gt;
        &lt;/dependency&gt;

        &lt;!-- Servlet --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;javax.servlet&lt;/groupId&gt;
            &lt;artifactId&gt;javax.servlet-api&lt;/artifactId&gt;
            &lt;version&gt;3.1.0&lt;/version&gt;
            &lt;scope&gt;provided&lt;/scope&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;javax.servlet.jsp&lt;/groupId&gt;
            &lt;artifactId&gt;jsp-api&lt;/artifactId&gt;
            &lt;version&gt;2.2&lt;/version&gt;
            &lt;scope&gt;provided&lt;/scope&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;javax.servlet&lt;/groupId&gt;
            &lt;artifactId&gt;jstl&lt;/artifactId&gt;
            &lt;version&gt;1.2&lt;/version&gt;
        &lt;/dependency&gt;

        &lt;!-- Test --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;junit&lt;/groupId&gt;
            &lt;artifactId&gt;junit&lt;/artifactId&gt;
            &lt;version&gt;4.13.1&lt;/version&gt;
            &lt;scope&gt;test&lt;/scope&gt;
        &lt;/dependency&gt;
        &lt;!-- 추가 의존 라이브러리 --&gt;
        &lt;!-- MyBatis 라이브러리 --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.mybatis&lt;/groupId&gt;
            &lt;artifactId&gt;mybatis&lt;/artifactId&gt;
            &lt;version&gt;3.2.7&lt;/version&gt;
        &lt;/dependency&gt;

        &lt;dependency&gt;
            &lt;groupId&gt;org.mybatis&lt;/groupId&gt;
            &lt;artifactId&gt;mybatis-spring&lt;/artifactId&gt;
            &lt;version&gt;1.2.2&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;!-- Spring JDBC 라이브러리 --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework&lt;/groupId&gt;
            &lt;artifactId&gt;spring-jdbc&lt;/artifactId&gt;
            &lt;version&gt;4.0.0.RELEASE&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;!-- 파일업로드 처리를 위한 라이브러리 (SmartEditor 에서도 필요함)--&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;commons-io&lt;/groupId&gt;
            &lt;artifactId&gt;commons-io&lt;/artifactId&gt;
            &lt;version&gt;2.7&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;commons-fileupload&lt;/groupId&gt;
            &lt;artifactId&gt;commons-fileupload&lt;/artifactId&gt;
            &lt;version&gt;1.3.1&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;!--  json, xml 응답을 편하게 할수 있도록 도와 주는 라이브러리 --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;com.fasterxml.jackson.core&lt;/groupId&gt;
            &lt;artifactId&gt;jackson-databind&lt;/artifactId&gt;
            &lt;version&gt;2.12.7.1&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;!-- Aop 용 라이브러리 --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework&lt;/groupId&gt;
            &lt;artifactId&gt;spring-aop&lt;/artifactId&gt;
            &lt;version&gt;4.0.0.RELEASE&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.aspectj&lt;/groupId&gt;
            &lt;artifactId&gt;aspectjweaver&lt;/artifactId&gt;
            &lt;version&gt;1.8.0&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;!-- Spring Security 관련 라이브러리 --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework.security&lt;/groupId&gt;
            &lt;artifactId&gt;spring-security-web&lt;/artifactId&gt;
            &lt;version&gt;4.0.0.RELEASE&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;!-- 트렌젝션 처리를 위한 라이브러리 --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework&lt;/groupId&gt;
            &lt;artifactId&gt;spring-tx&lt;/artifactId&gt;
            &lt;version&gt;4.0.0.RELEASE&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;!-- 오라클 라이브러리 --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;com.oracle.database.jdbc&lt;/groupId&gt;
            &lt;artifactId&gt;ojdbc8&lt;/artifactId&gt;
            &lt;version&gt;21.1.0.0&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;com.vaadin.external.google&lt;/groupId&gt;
            &lt;artifactId&gt;android-json&lt;/artifactId&gt;
            &lt;version&gt;0.0.20131108.vaadin1&lt;/version&gt;
        &lt;/dependency&gt;
    &lt;/dependencies&gt;

    &lt;build&gt;
        &lt;plugins&gt;
            &lt;plugin&gt;
                &lt;groupId&gt;org.codehaus.mojo&lt;/groupId&gt;
                &lt;artifactId&gt;exec-maven-plugin&lt;/artifactId&gt;
                &lt;version&gt;1.2.1&lt;/version&gt;
                &lt;configuration&gt;
                    &lt;mainClass&gt;org.test.int1.Main&lt;/mainClass&gt;
                &lt;/configuration&gt;
            &lt;/plugin&gt;
            &lt;plugin&gt;
                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
                &lt;configuration&gt;
                    &lt;source&gt;1.8&lt;/source&gt;
                    &lt;target&gt;1.8&lt;/target&gt;
                &lt;/configuration&gt;
            &lt;/plugin&gt;
        &lt;/plugins&gt;
        &lt;finalName&gt;SpringPj&lt;/finalName&gt;
    &lt;/build&gt;
&lt;/project&gt;</code></pre>
<blockquote>
<p><code>pom</code> 요소만 추가하면 기본적인 세팅이 끝난다. 이후에 <code>servlet-context.xml</code>, <code>root-context.xml</code>, <code>Controller.java</code> 등은 개발 환경에 맞게 세팅하면 된다 !</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring #2]]></title>
            <link>https://velog.io/@hyeon_geun/Spring-2</link>
            <guid>https://velog.io/@hyeon_geun/Spring-2</guid>
            <pubDate>Sun, 02 Jul 2023 13:43:20 GMT</pubDate>
            <description><![CDATA[<h3 id="🧷-client---web-server---was---db">🧷 Client - Web Server - WAS - DB</h3>
<ul>
<li><p>Web server (정적 리소스 처리): HTML, 이미지 등을 처리하며 잘 죽지 않고 오류화면 HTML을 노출 시킬 수 있다.</p>
</li>
<li><p>WAS, Web Application Server (동적 리소스 처리): 업무 분담으로 과부하를 줄여주며 애플리케이션 로직을 실행시킨다.</p>
</li>
</ul>
<h3 id="📌-servlet">📌 Servlet</h3>
<p>: 자바를 사용해 웹 페이지를 동적으로 생성하는 서버측 프로그램 혹은 사양</p>
<p>서블릿은 서버에서 처리해야 하는 수많은 업무 중 <strong>비즈니스 로직</strong>을 제외한 모든 일을 대신 수행해준다.
이는 싱글톤으로 관리되어 <strong>공유 변수에 주의</strong>하여야 하며 소스코드는 싱글 스레드 프로그래밍하듯 개발하면 된다.</p>
<p>서블릿은 요청/응답 정보를 편리하게 사용할 수 있도록 <code>HttpServletRequest</code>, <code>HttpServletResponse</code>를 사용한다.</p>
<p>HTTP 요청을 하면 WAS는 <code>request</code>, <code>response</code> 객체를 새로 만들어 서블릿 객체를 호출한다. 그럼 그때 개발자는 request 객체에서 HTTP 요청 정보를 꺼내 쓰고, response 객체에 HTTP 응답 정보를 입력하면 된다.</p>
<p>WAS는 response 내용으로 HTTP 응답 정보를 생성해 브라우저로 전달해준다.</p>
<hr>
<h2 id="📖-spring-mvc">📖 Spring MVC</h2>
<p>서블릿으로 개발할 때는 뷰를 위한 HTML 코드가 자바 코드와 섞여 복잡했다.
이를 해결하기 위해 <code>JSP</code>를 사용해 뷰를 생성하는 <code>HTML</code> 작업을 분리시켰고 중간중간 동적인 작업이 필요한 부분만 자바 코드를 적용시켰다.
하지만 이 또한 많은 자바 코드가 JSP에 노출되어 JSP가 너무 많은 역할을 떠맡게 된다.</p>
<p>그래서 비즈니스 로직과 뷰를 그리는 작업을 분리하기 위하여 MVC 패턴을 사용하게 되었다.</p>
<blockquote>
</blockquote>
<h4 id="jsp-java-server-pages">JSP, Java Server Pages</h4>
<p>: HTML 코드에 자바 코드를 넣어 동적 웹 페이지를 생성하는 웹 어플리케이션 도구</p>
<p><code>MVC 패턴</code>이란 <code>JSP</code>가 처리하던 것을 컨트롤러와 뷰 영역으로 나눈 것이다.</p>
<ul>
<li><strong>컨트롤러</strong>
:HTTP 요청을 받아 파라미터를 검증하고 비즈니스 로직을 수행한다. 그리고 뷰에 전달할 결과 데이터를 조회해 모델에 담는다.</li>
<li><strong>모델</strong>
:뷰에 출력할 데이터를 담아둔다. 모델 덕분에 뷰는 화면을 렌더링하는 일에만 집중하면 된다.</li>
<li><strong>뷰</strong>
:모델에 담긴 데이터를 사용해 화면을 그린다. (HTML 생성)</li>
</ul>
<blockquote>
</blockquote>
<h2 id="controller-vs-service">[Controller vs Service]</h2>
<p>컨트롤러에 비즈니스 로직을 둘 수는 있지만, 이는 <strong>컨트롤러가 너무 많은 역할을 담당</strong>하게 된다.</p>
<blockquote>
</blockquote>
<p>그래서 비즈니스 로직을 <strong>Service 서비스 계층</strong>을 별도로 생성하여 처리한다.
그리고 <strong>Controller 컨트롤러는 비즈니스 로직이 있는 서비스를 호출하는 역할</strong>을 담당한다.</p>
<blockquote>
</blockquote>
<p>비즈니스 로직을 변경하면 비즈니스 로직을 호출하는 컨트롤러의 코드도 함께 변경될 수 있다.</p>
<h4 id="mvc-패턴-동작">MVC 패턴 동작</h4>
<p><img src="https://velog.velcdn.com/images/hyeon_geun/post/6ae5fcef-407a-46a3-bf10-4e79849f667d/image.png" alt=""></p>
<h3 id="📌-front-controller">📌 Front Controller</h3>
<p>초기 MVC 패턴은 컨트롤러의 역할과 뷰의 렌더링 역할을 명확히 구분하여 뷰의 코드가 깔끔하고 직관적이도록 해주었다. 하지만 컨트롤러는 중복이 많아 <strong>프론트 컨트롤러(Front Controller) 패턴</strong>을 도입하게 되었다.</p>
<p>프론트 컨트롤러는 <strong>프론트 컨트롤러라는 서블릿 하나</strong>로 클라이언트의 <strong>요청을 받은 다음 프론트 컨트롤러가 요청에 맞는 컨트롤러를 찾아 호출</strong>해주는 역할을 수행한다.</p>
<p>그래서 스프링에서는 <strong>DispatcherServlet</strong>이 FrontController 패턴으로 구현되어 있어 이를 사용할 수 있다.</p>
<hr>
<h2 id="spring-mvc-구조">Spring MVC 구조</h2>
<p>스프링 MVC의 전체 구조를 보면 아래와 같다
<img src="https://velog.velcdn.com/images/hyeon_geun/post/f68bffad-8b04-4486-91e3-1f4b6b243e47/image.png" alt=""></p>
<ul>
<li><strong>DispatcherServlet(Front Controller)</strong>
: 제일 앞단에서 HTTP Request를 처리하는 컨트롤러</li>
<li><strong>Controller(Handler)</strong>
: HTTP Request를 처리해 Model을 만들고 View 지정</li>
<li><strong>ModelAndView</strong>
: Controller에 의해 반환된 Model과 View가 Wrapping 된 객체
(Model은 데이터만 저장하고 ModelAndView는 데이터와 이동하고자 하는 view page를 함께 저장한다.)</li>
<li><strong>ViewResolver</strong>
: ModelAndView를 처리해 View 그리기</li>
</ul>
<blockquote>
<p><strong>[동작 순서]</strong></p>
</blockquote>
<ol>
<li>핸들러 조회</li>
<li>핸들러 어댑터 조회</li>
<li>핸들러 어댑터 실행</li>
<li>핸들러 실행</li>
<li>ModelAndView 반환</li>
<li>viewResolver 호출</li>
<li>View 반환</li>
<li>뷰 렌더링</li>
</ol>
<hr>
<h3 id="📌-controller의-requestmapping">📌 Controller의 @RequestMapping</h3>
<p>@RequestMapping는 실무에서 많이 쓰인다.</p>
<p>이는 <strong>요청 정보를 매핑하는 어노테이션으로 해당 URL이 호출되면 해당 메소드가 실행</strong>된다.</p>
<ul>
<li><strong>@GetMapping</strong></li>
<li><strong>@PostMapping</strong>
위와 같이 명확하게 써야한다.</li>
</ul>
<blockquote>
<h3 id="controller-vs-restcontroller">@Controller vs @RestController</h3>
</blockquote>
<p><strong>@Controller</strong>는 반환 값이 String일 때 뷰 이름으로 인식하여 뷰를 찾고 <strong>뷰가 랜더링</strong> 된다.
반면, <strong>@RestController</strong>는 반환 값으로 뷰를 찾는 것이 아닌, <strong>HTTP 메시지 바디에 바로 입력</strong>되어 반환된 문자열을 그대로 노출시킬 수 있다.</p>
<p>** Controller 사용 예시 [HomeController]**</p>
<pre><code class="language-java">@Controller
public class HomeController {

    // 이 프로젝트의 최상위 경로 요청이 오면
    @RequestMapping(&quot;/&quot;)
    //생성자에 임의로 객체를 선언할 수 있다.
    public String home(HttpServletRequest request) {
        // home.jsp 페이지에서 필요한 모델(data)를 HttpServletRequest 객체에 담아두기
        List&lt;String&gt; noticeList = new ArrayList&lt;String&gt;();
        noticeList.add(&quot;날씨가 많이 더워지고 있어요.&quot;);
        noticeList.add(&quot;어떡하죠&quot;);
        noticeList.add(&quot;물을 많이 마셔요&quot;);
        request.setAttribute(&quot;noticeList&quot;, noticeList);
        // /WEB-INF/views/home.jsp 페이지로 forward 이동해서 응답하겠다는 의미
        // &quot;home&quot;이라는 문자열을 리턴하면 앞에 &quot;/WEB-INF/views/&quot;뒤에 &quot;.jsp&quot;가 자동으로 붙는다.
        return &quot;home&quot;;
    }

    @RequestMapping(value = &quot;/fortune&quot;)
    public String fortune(HttpServletRequest request) {
        //오늘의 운세라고 가정하자
        // String fortuneToday = &quot;오늘은 되는게 없어요&quot;;
        String fortuneToday = &quot;오늘은 불금불금~~ 저녁에 맥주 한 잔하게 될 거에요&quot;;
        // &quot;fortuneToday&quot; 라는 키값으로 String type 데이터를 담는다
        request.setAttribute(&quot;fortuneToday&quot;, fortuneToday);
        // &quot;/WEB-INF/views/&quot; + &quot;test/fortune&quot; + &quot;.jsp&quot;
        return &quot;test/fortune&quot;;
    }

}</code></pre>
<p><strong>Controller 사용 예시 [UserController]</strong></p>
<pre><code class="language-java">@Controller
public class UsersController {
    // 의존 객체 주입 받기(DI)
    @Autowired
    private UsersService service;

    /*
        GET 방식 /users/signup_form 요청을 처리할 메소드
        - 요청방식이 다르면 실행되지 않는다.
     */
    @RequestMapping(method = RequestMethod.GET, value = &quot;/users/signup_form&quot;)
    public String signupForm() {

        return &quot;users/signup_form&quot;;
    }

    // 회원 가입 요청처리
    @RequestMapping(method = RequestMethod.POST, value = &quot;/users/signup&quot;)
    public ModelAndView signup(ModelAndView mView, UsersDto dto) {
        // 서비스를 이용해서 DB 에 저장하고
        service.addUser(dto);
        // view page 로 forward 이동해서 응답
        mView.setViewName(&quot;users/signup&quot;);
        return mView;
    }

    // 로그인 폼 요청 처리
    @RequestMapping(method = RequestMethod.GET, value = &quot;/users/loginform&quot;)
    public String loginform() {
        return &quot;users/loginform&quot;;
    }

    // 로그인 요청 처리
    @RequestMapping(&quot;/users/login&quot;)
    public ModelAndView login(ModelAndView mView, UsersDto dto, String url, HttpSession session) {
        /*
            서비스에서 비즈니스 로직을 처리할 때 필요로 하는 객체를 컨트롤러에서 직접 전달을 해주어야 한다.
            주로, HttpServeltRequest, HttpServletResponse, HttpSession, ModelAndView
            등등의 객체이다.
         */
        service.loginProcess(dto, session);

        // 로그인 후에 가야할 목적지 정보를 인코딩 하지 않는 것과 인코딩한 것을 모두 ModelAndView 객체에 담고
        String encodedUrl = URLEncoder.encode(url);
        mView.addObject(&quot;url&quot;, url);
        mView.addObject(&quot;encodedUrl&quot;, encodedUrl);

        // view page 로 forward 이동해서 응답한다.
        mView.setViewName(&quot;users/login&quot;);
        return mView;
    }

    @RequestMapping(&quot;/users/logout&quot;)
    public String logout(HttpSession session) {
        // 세션에서 id 라는 키값으로 저장된 값 삭제
        session.removeAttribute(&quot;id&quot;);
        return &quot;users/logout&quot;;
    }

    // 개인정보 보기 요청 처리
    @RequestMapping(&quot;/users/info&quot;)
    public ModelAndView info(HttpSession session, ModelAndView mView) {
        service.getInfo(session, mView);

        mView.setViewName(&quot;users/info&quot;);
        return mView;
    }

    // 비밀번호 수정폼 요청 처리
    @RequestMapping(&quot;/users/pwd_updateform&quot;)
    public String pwdUpdateForm() {
        return &quot;users/pwd_updateform&quot;;
    }

    // 비밀번호 수정 요청 처리
    @RequestMapping(&quot;/users/pwd_update&quot;)
    public ModelAndView pwdUpdate(UsersDto dto, ModelAndView mView, HttpSession session) {
        // 서비스에 필요한 객체의 참조값을 전달해서 비밀번호 수정 로직을 처리한다.
        service.updateUserPwd(session, dto, mView);
        // view page 로 forward 이동해서 작업 결과를 응답한다.
        mView.setViewName(&quot;users/pwd_update&quot;);
        return mView;
    }

    // 개인정보 수정폼 요청 처리
    @RequestMapping(&quot;/users/updateform&quot;)
    public ModelAndView updateform(HttpSession session, ModelAndView mView) {
        service.getInfo(session, mView);
        mView.setViewName(&quot;users/updateform&quot;);
        return mView;
    }

    // ajax 프로필 사진 업로드 요청 처리
    @RequestMapping(value = &quot;/users/profile_upload&quot;, method = RequestMethod.POST)
    @ResponseBody
    public Map&lt;String, Object&gt; profileUpload(HttpServletRequest request, MultipartFile image) {
        // 서비스를 이용해서 이미지를 upload 폴더에 저장하고 리턴되는 Map 을 리턴해서 json 문자열 응답하기
        return service.saveProfileImage(request, image);
    }

    @RequestMapping(value = &quot;/users/update&quot;, method = RequestMethod.POST)
    public ModelAndView update(UsersDto dto, HttpSession session, ModelAndView mView) {
        // 서비스를 이용해서 개인정보를 수정하고
        service.updateUser(dto, session);
        // 개인정보 보기로 리다일렉트 이동시킨다.
        mView.setViewName(&quot;redirect:/users/info&quot;);
        return mView;
    }

    // 회원 탈퇴 요청 처리
    @RequestMapping(&quot;/users/delete&quot;)
    public ModelAndView delete(HttpSession session, ModelAndView mView){
        service.deleteUser(session, mView);
        mView.setViewName(&quot;users/delete&quot;);
        return mView;
    }
}</code></pre>
<p><strong>Service 사용 예시 [CafeService.interface]</strong></p>
<pre><code class="language-java">public interface CafeService {
    public void getList(HttpServletRequest request);

    public void getDetail(HttpServletRequest request);

    public void saveContent(CafeDto dto);

    public void updateContent(CafeDto dto);

    public void deleteContent(int num, HttpServletRequest request);

    public void getData(HttpServletRequest request); // 글 수정하기 위해 정보 불러오는 기능

    public void saveComment(HttpServletRequest request); // 댓글 저장

    public void deleteComment(HttpServletRequest request); // 댓글 삭제

    public void updateComment(CafeCommentDto dto); // 댓글 수정

    public void moreCommentList(HttpServletRequest request); // 댓글 더보기 기능
}</code></pre>
<p><strong>[CafeServiceImpl]</strong></p>
<pre><code class="language-java">@Service
public class CafeServiceImpl implements CafeService {
    @Autowired
    private CafeDao cafeDao;

    @Autowired
    private CafeCommentDao cafeCommentDao;

    // 페이징 처리, 검색어 기능을 고려한 비즈니스 로직 처리를 하는 메소드
    @Override
    public void getList(HttpServletRequest request) {
        // 한 페이지에 몇개씩 표시할 것인지
        final int PAGE_ROW_COUNT = 5;
        // 하단 페이지를 몇개씩 표시할 것인지
        final int PAGE_DISPLAY_COUNT = 5;

        // 보여줄 페이지의 번호를 일단 1이라고 초기값 지정
        int pageNum = 1;
        // 페이지 번호가 파라미터로 전달되는지 읽어와 본다.
        String strPageNum = request.getParameter(&quot;pageNum&quot;);
        // 만일 페이지 번호가 파라미터로 넘어 온다면
        if (strPageNum != null) {
            // 숫자로 바꿔서 보여줄 페이지 번호로 지정한다.
            pageNum = Integer.parseInt(strPageNum);
        }

        // 보여줄 페이지의 시작 ROWNUM
        int startRowNum = 1 + (pageNum - 1) * PAGE_ROW_COUNT;
        // 보여줄 페이지의 끝 ROWNUM
        int endRowNum = pageNum * PAGE_ROW_COUNT;

      /*
         [ 검색 키워드에 관련된 처리 ]
         -검색 키워드가 파라미터로 넘어올수도 있고 안넘어 올수도 있다.
      */
        String keyword = request.getParameter(&quot;keyword&quot;);
        String condition = request.getParameter(&quot;condition&quot;);
        // 만일 키워드가 넘어오지 않는다면
        if (keyword == null) {
            // 키워드와 검색 조건에 빈 문자열을 넣어준다.
            // 클라이언트 웹브라우저에 출력할때 &quot;null&quot; 을 출력되지 않게 하기 위해서
            keyword = &quot;&quot;;
            condition = &quot;&quot;;
        }

        // 특수기호를 인코딩한 키워드를 미리 준비한다.
        String encodedK = URLEncoder.encode(keyword);

        // CafeDto 객체에 startRowNum 과 endRowNum 을 담는다.
        CafeDto dto = new CafeDto();
        dto.setStartRowNum(startRowNum);
        dto.setEndRowNum(endRowNum);

        // 만일 검색 키워드가 넘어온다면
        if (!keyword.equals(&quot;&quot;)) {
            // 검색 조건이 무엇이냐에 따라 분기 하기
            if (condition.equals(&quot;title_content&quot;)) { // 제목 + 내용 검색인 경우
                // 검색 키워드를 CafeDto 에 담아서 전달한다.
                dto.setTitle(keyword);
                dto.setContent(keyword);
            } else if (condition.equals(&quot;title&quot;)) { // 제목 검색인 경우
                dto.setTitle(keyword);
            } else if (condition.equals(&quot;writer&quot;)) { // 작성자 검색인 경우
                dto.setWriter(keyword);
            } // 다른 검색 조건을 추가 하고 싶다면 아래에 else if() 를 계속 추가 하면 된다.
        }
        // 글 목록 얻어오기
        List&lt;CafeDto&gt; list = cafeDao.getList(dto);
        // 전체글의 갯수
        int totalRow = cafeDao.getCount(dto);

        // 하단 시작 페이지 번호
        int startPageNum = 1 + ((pageNum - 1) / PAGE_DISPLAY_COUNT) * PAGE_DISPLAY_COUNT;
        // 하단 끝 페이지 번호
        int endPageNum = startPageNum + PAGE_DISPLAY_COUNT - 1;


        // 전체 페이지의 갯수
        int totalPageCount = (int) Math.ceil(totalRow / (double) PAGE_ROW_COUNT);
        // 끝 페이지 번호가 전체 페이지 갯수보다 크다면 잘못된 값이다.
        if (endPageNum &gt; totalPageCount) {
            endPageNum = totalPageCount; // 보정해 준다.
        }
        // view page 에서 필요한 값을 request 에 담아준다.
        request.setAttribute(&quot;pageNum&quot;, pageNum);
        request.setAttribute(&quot;startPageNum&quot;, startPageNum);
        request.setAttribute(&quot;endPageNum&quot;, endPageNum);
        request.setAttribute(&quot;condition&quot;, condition);
        request.setAttribute(&quot;keyword&quot;, keyword);
        request.setAttribute(&quot;encodedK&quot;, encodedK);
        request.setAttribute(&quot;totalPageCount&quot;, totalPageCount);
        request.setAttribute(&quot;list&quot;, list);
        request.setAttribute(&quot;totalRow&quot;, totalRow);
    }

    @Override
    public void getDetail(HttpServletRequest request) {
        // 자세히 보여줄 글번호를 읽어온다.
        int num = Integer.parseInt(request.getParameter(&quot;num&quot;));
        // 조회수 올리기
        cafeDao.addViewCount(num);

      /*
         [ 검색 키워드에 관련된 처리 ]
         -검색 키워드가 파라미터로 넘어올수도 있고 안넘어 올수도 있다.
      */
        String keyword = request.getParameter(&quot;keyword&quot;);
        String condition = request.getParameter(&quot;condition&quot;);
        // 만일 키워드가 넘어오지 않는다면
        if (keyword == null) {
            // 키워드와 검색 조건에 빈 문자열을 넣어준다.
            // 클라이언트 웹브라우저에 출력할때 &quot;null&quot; 을 출력되지 않게 하기 위해서
            keyword = &quot;&quot;;
            condition = &quot;&quot;;
        }
        // CafeDto 객체를 생성해서
        CafeDto dto = new CafeDto();
        // 자세히 보여줄 글번호를 넣어준다.
        dto.setNum(num);
        // 만일 검색 키워드가 넘어온다면
        if (!keyword.equals(&quot;&quot;)) {
            // 검색 조건이 무엇이냐에 따라 분기 하기
            if (condition.equals(&quot;title_content&quot;)) {// 제목 + 내용 검색인 경우
                // 검색 키워드를 CafeDto 에 담아서 전달한다.
                dto.setTitle(keyword);
                dto.setContent(keyword);
            } else if (condition.equals(&quot;title&quot;)) { // 제목 검색인 경우
                dto.setTitle(keyword);
            } else if (condition.equals(&quot;writer&quot;)) { // 작성자 검색인 경우
                dto.setWriter(keyword);
            } // 다른 검색 조건을 추가 하고 싶다면 아래에 else if() 를 계속 추가 하면 된다.
        }

        // 글하나의 정보를 얻어온다.
        CafeDto resultDto = cafeDao.getData(dto);

        // 특수기호를 인코딩한 키워드를 미리 준비한다.
        String encodedK = URLEncoder.encode(keyword);

       /*
         [ 댓글 페이징 처리에 관련된 로직 ]
       */
        // 한 페이지에 몇개씩 표시할 것인지
        final int PAGE_ROW_COUNT = 10;
        // detail.jsp 페이지에서는 항상 1페이지의 댓글 내용만 출력한다.
        int pageNum = 1;
        // 보여줄 페이지의 시작 ROWNUM
        int startRowNum = 1 + (pageNum - 1) * PAGE_ROW_COUNT;
        // 보여줄 페이지의 끝 ROWNUM
        int endRowNum = pageNum * PAGE_ROW_COUNT;
        // 원글의 글번호를 이용해서 해당글에 달린 댓글 목록을 얻어온다.
        CafeCommentDto commentDto = new CafeCommentDto();
        commentDto.setRef_group(num);
        // 1페이지에 해당하는 startRowNum 과 endRowNum 을 dto 에 담아서
        commentDto.setStartRowNum(startRowNum);
        commentDto.setEndRowNum(endRowNum);
        // 1페이지에 해당하는 댓글 목록만 select 되도록 한다.
        List&lt;CafeCommentDto&gt; commentList = cafeCommentDao.getList(commentDto);

        // 원글의 글번호를 이용해서 댓글 전체의 갯수를 얻어낸다.
        int totalRow = cafeCommentDao.getCount(num);
        // 댓글 전체 페이지의 갯수
        int totalPageCount = (int) Math.ceil(totalRow / (double) PAGE_ROW_COUNT);

        // request scope 에 글 하나의 정보 담기
        request.setAttribute(&quot;dto&quot;, resultDto);
        request.setAttribute(&quot;condition&quot;, condition);
        request.setAttribute(&quot;keyword&quot;, keyword);
        request.setAttribute(&quot;encodedK&quot;, encodedK);
        request.setAttribute(&quot;totalRow&quot;, totalRow);
        request.setAttribute(&quot;commentList&quot;, commentList);
        request.setAttribute(&quot;totalPageCount&quot;, totalPageCount);
    }

    @Override
    public void saveContent(CafeDto dto) {
        // title, content, writer 정보가 들어있는 CafeDto 를 dao 에 전달해서 DB 에 저장되도록 한다.
        cafeDao.insert(dto);
    }

    @Override
    public void updateContent(CafeDto dto) {
        cafeDao.update(dto);
    }

    @Override
    public void deleteContent(int num, HttpServletRequest request) {
        // 세션에서 로그인된 아이디를 읽어와서
        String id = (String) request.getSession().getAttribute(&quot;id&quot;);
        // 글 작성자와 로그인된 아이디가 다르다면
        CafeDto dto = cafeDao.getData(num);
        // 예외를 발생시켜서 삭제가 안되도록 한다.
        if (!id.equals(dto.getWriter())) {
            throw new NotDeleteException(&quot;하지마라 ~&quot;);
        }
        cafeDao.delete(num);
    }

    // 글 수정 폼에 필요한 값을 HttpServletRequest 에 담아주는 메소드
    @Override
    public void getData(HttpServletRequest request) {
        // 수정할 글 정보
        int num = Integer.parseInt(request.getParameter(&quot;num&quot;));
        // 수정할 글의 정보 얻어와서
        CafeDto dto = cafeDao.getData(num);
        // request 에 담아준다.
        request.setAttribute(&quot;dto&quot;, dto);
    }

    @Override
    public void saveComment(HttpServletRequest request) {
        // 폼 전송되는 파라미터 추출
        int ref_group = Integer.parseInt(request.getParameter(&quot;ref_group&quot;)); // 원글의 글번호
        String target_id = request.getParameter(&quot;target_id&quot;); // 댓글 대상자의 아이디
        String content = request.getParameter(&quot;content&quot;); // 댓글의 내용
        /*
            원글의 댓글은 comment_group 번호가 전송이 안되고
            댓글의 댓글은 comment_group 번호가 전송이 된다.
            따라서 null 여부를 조사하면 원글의 댓글인지 댓글의 댓글인지 판단할 수 있다.
         */
        String comment_group = request.getParameter(&quot;comment_group&quot;);

        // 댓글 작성자는 session 영역에서 얻어내기
        String writer = (String) request.getSession().getAttribute(&quot;id&quot;);
        // 댓글의 시퀀스 번호 미리 얻어내기
        int seq = cafeCommentDao.getSequence();

        // 저장할 댓글의 정보를 dto 에 담기
        CafeCommentDto dto = new CafeCommentDto();
        dto.setNum(seq);
        dto.setWriter(writer);
        dto.setTarget_id(target_id);
        dto.setContent(content);
        dto.setRef_group(ref_group);
        // 원글의 댓글인 경우
        if (comment_group == null) {
            // 댓글의 글 번호를 comment_group 번호로 사용한다.
            dto.setComment_group(seq);
        } else {
            // 전송된 comment_group 번호를 숫자로 바꿔서 dto 에 넣어준다.
            dto.setComment_group(Integer.parseInt(comment_group));
        }
        // 댓글 정보를 DB에 저장하기
        cafeCommentDao.insert(dto);
    }

    @Override
    public void deleteComment(HttpServletRequest request) {
        int num = Integer.parseInt(request.getParameter(&quot;num&quot;));
        // 삭제할 댓글 정보를 읽어와서
        CafeCommentDto dto = cafeCommentDao.getData(num);
        String id = (String) request.getSession().getAttribute(&quot;id&quot;);
        // 글 작성자와 로그인된 아이디와 일치하지 않으면
        if (!dto.getWriter().equals(id)) {
            throw new NotDeleteException(&quot;남의 댓글 지우면 혼단다!&quot;);
        }
        // dao 를 이용해서 DB 에서 삭제하기
        cafeCommentDao.delete(num);
    }

    @Override
    public void updateComment(CafeCommentDto dto) {
        cafeCommentDao.update(dto);
    }

    @Override
    public void moreCommentList(HttpServletRequest request) {
        // 로그인된 아이디
        String id = (String) request.getSession().getAttribute(&quot;id&quot;);
        // ajax 요청 파라미터로 넘어오는 댓글의 페이지 번호를 읽어낸다.
        int pageNum = Integer.parseInt(request.getParameter(&quot;pageNum&quot;));
        // ajax 요청 파라미터로 넘어오는 원글의 글 번호를 읽어낸다.
        int num = Integer.parseInt(request.getParameter(&quot;num&quot;));
        /*
         [ 댓글 페이징 처리에 관련된 로직 ]
        */
        // 한 페이지에 몇개씩 표시할 것인지
        final int PAGE_ROW_COUNT = 10;

        // 보여줄 페이지의 시작 ROWNUM
        int startRowNum = 1 + (pageNum - 1) * PAGE_ROW_COUNT;
        // 보여줄 페이지의 끝 ROWNUM
        int endRowNum = pageNum * PAGE_ROW_COUNT;

        // 원글의 글번호를 이용해서 해당글에 달린 댓글 목록을 얻어온다.
        CafeCommentDto commentDto = new CafeCommentDto();
        commentDto.setRef_group(num);
        // 1페이지에 해당하는 startRowNum 과 endRowNum 을 dto 에 담아서
        commentDto.setStartRowNum(startRowNum);
        commentDto.setEndRowNum(endRowNum);

        // pageNum 에 해당하는 댓글 목록만 select 되도록 한다.
        List&lt;CafeCommentDto&gt; commentList = cafeCommentDao.getList(commentDto);
        // 원글의 글번호를 이용해서 댓글 전체의 갯수를 얻어낸다.
        int totalRow = cafeCommentDao.getCount(num);
        // 댓글 전체 페이지의 갯수
        int totalPageCount = (int) Math.ceil(totalRow / (double) PAGE_ROW_COUNT);

        // view page 에 필요한 값 request 에 담아주기
        request.setAttribute(&quot;commentList&quot;, commentList);
        request.setAttribute(&quot;num&quot;, num); // 원글의 글번호
        request.setAttribute(&quot;pageNum&quot;, pageNum); // 댓글의 페이지 번호
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring #1]]></title>
            <link>https://velog.io/@hyeon_geun/Spring-1-oj9ncar3</link>
            <guid>https://velog.io/@hyeon_geun/Spring-1-oj9ncar3</guid>
            <pubDate>Mon, 26 Jun 2023 05:33:12 GMT</pubDate>
            <description><![CDATA[<h2 id="spring">Spring</h2>
<blockquote>
<p>스프링은 <strong>자바 기반의 웹 어플리케이션을 만들 수 있는 프레임워크</strong>다.
<code>spring.io</code> 사이트에서 확인하면 &#39;<strong>스프링 프레임워크는 현대 자바 기반의 엔터프라이즈 어플리케이션을 위한 프로그래밍</strong> 및 <strong>Configuration Model</strong> 제공한다.&#39;라고 언급하고 있다.<br></p>
</blockquote>
<hr>
<h3 id="spring-구조">Spring 구조</h3>
<blockquote>
<p><strong>Spring Architect</strong><br>
Spring 프레임워크는 여러 모듈로 구성되어 있으며, 각각의 모듈은 특정한 기능과 역할을 수행한다. 가장 핵심적인 모듈은 다음과 같다</p>
</blockquote>
<p><strong>Core Container</strong>
: Spring의 핵심 기능을 제공한다. <u>Bean 관리, 의존성 주입(Dependency Injection), 이벤트 처리, 리소스 관리 등을 포함</u>한다.</p>
<p><strong>AOP (Aspect-Oriented Programming)</strong>
: <strong>관점 지향 프로그래밍을 지원</strong>하는 모듈로, 애플리케이션의 핵심 <strong>비즈니스 로직</strong>과 각각의 <strong>부가적인 기능</strong>을 <strong>분리</strong>하여 <strong>모듈화</strong>할 수 있다. 이를 통해 <u>코드의 재사용성을 높이고 관심사의 분리를 도모</u>한다.</p>
<p><strong>Web</strong>
: <strong>웹 애플리케이션 개발에 필요한 기능을 제공</strong>한다. 웹 애플리케이션의 <u>MVC (Model-View-Controller) 아키텍처를 지원</u>하며, <u>요청 처리</u>, <u>세션 관리</u>, <u>데이터 바인딩</u>, <u>검증</u>, <u>보안</u> 등을 <u>처리</u>한다.</p>
<p><strong>Data Access/Integration</strong>
: <strong>데이터베이스 연동과 관련된 작업을 처리</strong>하기 위한 기능을 제공한다. <code>JDBC</code>, <code>ORM</code> 프레임워크 (예: <code>Hibernate</code>), 트랜잭션 처리 등을 지원하여 데이터베이스와의 상호작용을 단순화한다.</p>
<p><strong>Test</strong>
: 단위 <strong>테스트를 위한 기능을 제공</strong>한다. <code>JUnit</code> 등과 통합하여 테스트 코드 작성 및 실행을 지원한다.</p>
<hr>
<h3 id="spring-주요-특징">Spring 주요 특징</h3>
<p>스프링 프레임워크의 특징은 아래와 같다.</p>
<blockquote>
<p><strong>POJO(Plain Old Java Object) 방식</strong>
: <strong>POJO</strong>는 <code>Java EE</code>의 <strong>EJB</strong> 를 사용하면서 해당 플랫폼에 종속되어 있는 무거운 객체들을 만드는 것에 반발하며 나타난 용어다. 별도의 프레임워크 없이 <code>Java EE</code>를 사용할 때에 비해 특정 인터페이스를 직접 구현하거나 상속받을 필요가 없어 기존 라이브러리를 지원하기가 용이하고, 객체가 가볍다.<br>
<strong>[필드, Getter, Setter 만 존재하는  POJO]</strong></p>
</blockquote>
<pre><code class="language-java">public class Person {
    private String name;
    private int age;
    &gt;
    public String getName(){
        return name;
    }
    &gt;
    public String getAge() {
        return age;
    }
    &gt;
    public void setName(String name){
        this.name = name;
    }
       &gt;
    public void setAge(int age){
        this.age = age;
    }
}</code></pre>
<p><strong>관점 지향 프로그래밍(Aspect Oriented Programming, AOP)</strong>
: 로깅, 트랜잭션, 보안 등 여러 모듈에서 공통적으로 사용하는 기능을 분리하여 관리할 수 있다. <code>AspectJ</code>를 포함하여 사용할 수 있고, 스프링에서 지원하는 실행에 조합하는 방식도 지원한다. <br>
<strong>[AOP 예 시]</strong></p>
<pre><code class="language-java">class OrderApp{
    ...
    public void 주문하기() {
        //공통 관심 사항
        로깅 관련 코드
        보안 관련 코드
       &gt;
       //핵심 관심 사항
       주문 관련 로직
      }
    &gt;
    public void 주문_변경하기() {
        //공통 관심 사항
        로깅 관련 코드
        보안 관련 코드
        &gt;
        //핵심 관심 사항
        주문 변경 관련 로직
    }
    &gt;
    public void 메뉴_등록하기() {
        //공통 관심 사항
        로깅 관련 코드
        보안 관련 코드
        &gt;
        //핵심 관심 사항
        메뉴 등록 관련 로직
    }
}</code></pre>
<p><strong>의존성 주입(Dependency Injection, DI)</strong>
: 프로그래밍에서 구성요소 간의 의존 관계가 소스코드 내부가 아닌 <strong>외부에서 설정을 통해 정의되는 방식</strong>이다. <u>코드 재사용</u>을 높여 소스코드를 다양한 곳에 사용할 수 있으며 모듈간의 결합도도 낮출 수 있다. <u>계층, 서비스 간에 의존성이 존재하는 경우 스프링 프레임워크가 서로 연결</u>시켜준다.<br>
<strong>제어 역전(Inversion of Control, IoC)</strong>
: 전통적인 프로그래밍에서는 개발자가 작성한 프로그램이 외부 라이브러리의 코드를 호출해서 이용했다. 제어 역전은 이와 반대로 <strong>외부 라이브러리 코드가 개발자의 코드를 호출</strong>하게 된다. 즉, 제어권이 프레임워크에게 있어 <u>필요에 따라 스프링 프레임워크가 사용자의 코드를 호출</u>한다.<br>
<strong>[DI + IoC example]</strong></p>
<pre><code class="language-java">// (1) A 가 사용하는 메소드를 인터페이스 I의 추상 메소드로 정의한 다음 (추상화)
interface I {
    void example();
}
&gt;
class A {
&gt;
    // (3) 그 다음, 인터페이스 타입의 필드를 선언하고,
    private I i;
&gt;    
    // (4) 생성자를 통해 외부로부터 인스턴스를 받아와 i를 초기화해준다. (다형성)
    public A (I i) {
        this.i = i;
    }
    &gt;
    public void methodOfA() {
        // (5) 외부로부터 받아온 인스턴스의 메소드를 호출
        i.example();
    }
}
&gt;
// (2) A 가 사용하는 메소드를 가진 객체들이 I 를 구현하도록 한다.
class B implements I {
&gt;
    public void example() {
        ...
    }
}
&gt;
class C implements I {
&gt;
    public void example() {
        ...
    }
}</code></pre>
<p><strong>생명주기 관리</strong>
: 스프링 프레임워크는 <strong><code>Java</code> 객체의 생성, 소멸을 직접 관리</strong>하며 필요한 객체만 사용할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[jQuery]]></title>
            <link>https://velog.io/@hyeon_geun/jQuery</link>
            <guid>https://velog.io/@hyeon_geun/jQuery</guid>
            <pubDate>Mon, 26 Jun 2023 03:49:11 GMT</pubDate>
            <description><![CDATA[<h2 id="📖-jquery">📖 jQuery</h2>
<blockquote>
<p> <code>javaScript</code>를 편리하게 사용할 수 있도록 해주는 <strong>Java Script Library</strong>이다.
(<code>HTML</code>의 요소들을 쉽게 조작하고 편리하게 사용할 수 있게 만든 라이브러리로 <code>Javascript</code>를 미리 작성해둔 것이다.)</p>
</blockquote>
<h3 id="📌-특징">📌 특징</h3>
<blockquote>
<ul>
<li>DOM 엘리먼트 선택</li>
</ul>
</blockquote>
<ul>
<li>DOM 트래버설 및 수정(CSS 1-3 지원. 기본적인 XPath를 플러그인 형태로 지원)
이벤트</li>
<li>CSS 조작</li>
<li>특수효과 및 애니메이션</li>
<li>AJAX 및 JSON, XML 파싱</li>
<li>JavaScript 플러그인을 통한 확장성</li>
<li>유틸리티 - 브라우저 종류와 버전, &quot;each&quot; 함수</li>
</ul>
<h3 id="🧨-jquery-vs-javascript">🧨 jQuery vs Javascript</h3>
<blockquote>
<p><code>Javascript</code>로 길고 복잡하게 써야 하는 것을 <code>JQuery</code>로 짧고 직관적으로 사용 가능</p>
</blockquote>
<p><strong>Javascript 사용</strong></p>
<pre><code class="language-js">let divs = document.querySelectorAll(&quot;div&quot;);
&gt;
for (let i = 0; i&gt;divs.length ; i++){
     let tmp = divs[i];
     tmp.innerText = &quot;hi&quot;;
}</code></pre>
<blockquote>
</blockquote>
<p><strong>jQuery 사용</strong></p>
<pre><code class="language-js">$(&quot;div&quot;).text(&quot;hi&quot;);</code></pre>
<hr>
<h3 id="📌-사용하기">📌 사용하기</h3>
<p><a href="https://www.w3schools.com/jquery/jquery_get_started.asp">https://www.w3schools.com/jquery/jquery_get_started.asp</a></p>
<blockquote>
<p>제이쿼리 임포트 하기 위해 &lt;head&gt;&lt;/head&gt; 사이에 넣어준다.</p>
</blockquote>
<pre><code class="language-js">&lt;script src=&quot;https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js&quot;&gt;&lt;/script&gt;</code></pre>
<hr>
<h3 id="📌-기본-구문">📌 기본 구문</h3>
<h4 id="jquery-기분-문법---selector-선택자">jQuery 기분 문법 - Selector (선택자)</h4>
<blockquote>
</blockquote>
<ul>
<li><strong>$(‘a’)</strong> 
: page 내 모든 &lt;a&gt;</li>
<li><strong>$(‘div a’)</strong> 
: page 내 &lt;div&gt; 하위에 있는  &lt;a&gt;</li>
<li><strong>$(&#39;#test’)</strong> 
: id가 test인 태그</li>
<li><strong>$(‘.btn’)</strong> 
: class가 btn인 모든 태그</li>
<li><strong>$(‘tr:odd’)</strong> 
: &lt;tr&gt; 태그들 중 홀수번째들</li>
<li><strong>$(‘tr:last tr:last’)</strong> 
: 문서내의 마지막 &lt;tr&gt; </li>
<li><strong>$(‘b:contains(‘hi’))</strong> 
: hi를 content로 가진 b태그</li>
<li><strong>$(‘div:has(‘ul’)</strong>
: &lt;ul&gt; 을 가진 &lt;div&gt; 태그 </li>
<li><strong>$(‘input:checkbox’)</strong> 
: input태그중 checkbox</li>
<li><strong>$(‘td nth-child(2n)’)</strong> 
: 2의 배수 번째 &lt;td&gt;</li>
</ul>
<h4 id="contentdom-변경-및-조회-메소드">Content/DOM 변경 및 조회 메소드</h4>
<blockquote>
</blockquote>
<p><strong>html()</strong></p>
<ul>
<li>선택요소의 html 내용을 가져옴. innerHTML과 동일<blockquote>
</blockquote>
</li>
<li><em>html(value)*</em></li>
<li>선택요소에 인수로 받은 value를 넣는다.</li>
<li>value내에 html태그가 있는 경우 태그로 들어간다.<blockquote>
</blockquote>
</li>
<li><em>text()*</em></li>
<li>선택요소 내의 html태그 요소를 제외한 내용을 가져옴.</li>
<li>innerText innerText와 동일.<blockquote>
</blockquote>
</li>
<li><em>text(value)*</em></li>
<li>선택요소 내에 인수로 받은 value를 넣는다.</li>
<li>value내의 html태그도 text로 들어간다.<blockquote>
</blockquote>
</li>
<li><em>val()*</em></li>
<li>input 태그의 value 값을 조회<blockquote>
</blockquote>
</li>
<li><em>val(value)*</em></li>
<li>인수로 받은 value를 input 태그의 value 값을 설정</li>
</ul>
<p><strong>사용 예시 1</strong></p>
<pre><code class="language-js">// 위의 input 요소에 문자열을 입력하고 전송버튼을 누르면 입력한 문자열을 
//p 요소의 innerText 에 출력되도록 프로그래밍
&lt;div class=&quot;container&quot;&gt;
    &lt;input type=&quot;text&quot; id=&quot;inputMsg&quot; placeholder=&quot;문자열 입력...&quot;/&gt;
    &lt;button id=&quot;sendBtn&quot;&gt;전송&lt;/button&gt;
    &lt;p id=&quot;result&quot;&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;script&gt;
    $(&quot;#sendBtn&quot;).on(&quot;click&quot;, () =&gt; {
        const msg = $(&quot;#inputMsg&quot;).val();
        $(&quot;#result&quot;).text(msg);
    });
&lt;/script&gt;</code></pre>
<p><strong>사용 예시 2 (css 변경)</strong></p>
<pre><code class="language-js">&lt;style&gt;
    .box {
        width: 100px;
        height: 100px;
        border: 1px solid red;
    }
&lt;/style&gt;
&lt;h1&gt;이벤트 리스너 함수 등록&lt;/h1&gt;
&lt;div class=&quot;box&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;box&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;box&quot;&gt;&lt;/div&gt;
&lt;script src=&quot;https://cdn.jsdelivr.net/npm/jquery@3.7.0/dist/jquery.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;
    // $(&quot;.box&quot;).on(이벤트명, 콜백함수)
    $(&quot;.box&quot;).on(&quot;mouseover&quot;, function (e) {
        // 이벤트가 발생한 바로 그 요소의 참조값은 e.target
        console.log(e.target);
        /*
             e.target.style.backgroundColor=&quot;yellow&quot;;
             e.target.style.width=&quot;200px&quot;;
             e.target.style.height=&quot;200px&quot;;
             e.target.innerText=&quot;mouseover!&quot;;
         */
        // $() 함수에 문서객체의 참조값을 전달하면 
          //해당 문서 객체를 jquery 의 기능을 통해서 조작할 수 있다.
        $(e.target).css(&quot;background-color&quot;, &quot;yellow&quot;)
            .css(&quot;width&quot;, &quot;200px&quot;)
            .css(&quot;height&quot;, &quot;200px&quot;)
            .text(&quot;mouseover!&quot;);
    });
&lt;/script&gt;</code></pre>
<p><strong>사용 예시 3 (요소 추가)</strong></p>
<pre><code class="language-js">&lt;h1&gt;이벤트 처리&lt;/h1&gt;
&lt;input type=&quot;text&quot; id=&quot;inputMsg&quot; placeholder=&quot;메세지 입력 ...&quot;&gt;
&lt;button id=&quot;sendBtn&quot;&gt;전송&lt;/button&gt;
&lt;p id=&quot;current&quot;&gt;&lt;/p&gt;
&lt;ul id=&quot;msgList&quot;&gt;

&lt;/ul&gt;
&lt;script src=&quot;https://cdn.jsdelivr.net/npm/jquery@3.7.0/dist/jquery.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;
    // 전송 버튼을 눌렀을 때 실행할 함수 등록
    $(&quot;#sendBtn&quot;).on(&quot;click&quot;, function () {
        // 1. 입력한 문자열을 읽어와서
        const msg = $(&quot;#inputMsg&quot;).val();
        // 2. li 요소를 만들어서 innerText 에 출력하고 id 가 msgList 인 요소에 추가하기
        $(&quot;&lt;li&gt;&quot;).text(msg).appendTo(&quot;#msgList&quot;);
    })

    $(&quot;#inputMsg&quot;).on(&quot;keyup&quot;, (e) =&gt; {
        console.log(e.keyCode);
        //만일 Enter 키를 눌렀다면
        if (e.keyCode === 13) {
            const msg = $(&quot;#inputMsg&quot;).val();
            $(&quot;&lt;li&gt;&quot;).text(msg).appendTo(&quot;#msgList&quot;);
            $(&quot;#inputMsg&quot;).val(&quot;&quot;).focus();
        }
        // 현재까지 입력한 문자열을 읽어와서
        const msg = $(e.target).val();
        // p 요소에 출력
        $(&quot;#current&quot;).text(msg);
    })
&lt;/script&gt;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Maven]]></title>
            <link>https://velog.io/@hyeon_geun/Maven</link>
            <guid>https://velog.io/@hyeon_geun/Maven</guid>
            <pubDate>Sat, 24 Jun 2023 13:44:50 GMT</pubDate>
            <description><![CDATA[<h2 id="maven">Maven</h2>
<h3 id="1-maven은-무엇인가">1. Maven은 무엇인가?</h3>
<blockquote>
<p><strong>Maven</strong>은 <u>자바 프로젝트의 빌드(build)를 자동화 해주는 빌드 툴(build tool)</u>이다.</p>
</blockquote>
<p>즉, 자바 소스를 <code>compile</code>하고 <code>package</code>해서 <code>deploy</code>하는 일을 자동화 해주는 것이다.</p>
<h3 id="2-maven이-참조하는-설정-파일">2. Maven이 참조하는 설정 파일</h3>
<p>Maven 전체를 보기보다 프로그래밍에 직접적인 연관이 있는 두 개의 설정파일을 알아보면 된다.</p>
<h4 id="1-settingsxml">1) <code>settings.xml</code></h4>
<blockquote>
<p><code>settings.xml</code>은 <u><strong>maven tool</strong> 자체에 관련된 설정을 담당</u>한다.</p>
</blockquote>
<p><code>MAVEN_HOME/conf/</code> 아래에 있다. ( * MAVEN_HOME은 환경변수에 설정한 경로)</p>
<blockquote>
</blockquote>
<p>Maven 자체에 설정 값을 바꾸는 일은 일단 잘 없으므로 넘어가고 기획한대로 pom.xml을 살펴본다.</p>
<h4 id="2-pomxml">2) <code>pom.xml</code></h4>
<blockquote>
<p>하나의 자바 프로젝트에 빌드 툴로 <strong>maven</strong>을 설정했다면, 프로젝트 최상위 디렉토리에 <code>pom.xml</code>이라는 파일이 생성되었을 것이다.</p>
</blockquote>
<p><code>pom.xml</code>은 <strong>POM(Project Object Model)</strong>을 설정하는 부분으로 <u>프로젝트 내 빌드 옵션을 설정하는 부분</u>이다.</p>
<p><strong><code>pom.xml</code> 분석</strong></p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;

    &lt;groupId&gt;com.example&lt;/groupId&gt;
    &lt;artifactId&gt;demo&lt;/artifactId&gt;
    &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;
    &lt;packaging&gt;jar&lt;/packaging&gt;

    &lt;name&gt;demo&lt;/name&gt;
    &lt;description&gt;Demo project for Spring Boot&lt;/description&gt;

    &lt;parent&gt;
        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
        &lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;
        &lt;version&gt;2.0.5.RELEASE&lt;/version&gt;
        &lt;relativePath/&gt; &lt;!-- lookup parent from repository --&gt;
    &lt;/parent&gt;

    &lt;properties&gt;
        &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;
        &lt;project.reporting.outputEncoding&gt;UTF-8&lt;/project.reporting.outputEncoding&gt;
        &lt;java.version&gt;1.8&lt;/java.version&gt;
    &lt;/properties&gt;

    &lt;dependencies&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
            &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
        &lt;/dependency&gt;

        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
            &lt;artifactId&gt;spring-boot-devtools&lt;/artifactId&gt;
            &lt;scope&gt;runtime&lt;/scope&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
            &lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
            &lt;scope&gt;test&lt;/scope&gt;
        &lt;/dependency&gt;
    &lt;/dependencies&gt;

    &lt;build&gt;
        &lt;plugins&gt;
            &lt;plugin&gt;
                &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
                &lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;
            &lt;/plugin&gt;
        &lt;/plugins&gt;
    &lt;/build&gt;
&lt;/project&gt;</code></pre>
<blockquote>
</blockquote>
<h4 id="1-프로젝트-정보">1) 프로젝트 정보</h4>
<blockquote>
</blockquote>
<p>&lt;modelVersion&gt; : 4.0.0이라고 써있는데 이것은 maven의 pom.xml의 모델 버전이다. 형식이 4.0.0 버전이라고 이해하면 된다.</p>
<blockquote>
</blockquote>
<p>&lt;groupId&gt; : 프로젝트를 생성한 조직 또는 그룹명으로 보통, URL의 역순으로 지정한다.</p>
<blockquote>
</blockquote>
<p>&lt;artifactId&gt; : 프로젝트에서 생성되는 기본 아티팩트의 고유 이름이다.</p>
<blockquote>
</blockquote>
<p>메이븐에 의해 생성되는 일반적인 artifact는 &lt;artifact&gt;-&lt;version&gt;.&lt;extention&gt;이다. (ex demo-0.0.1-SNAPSHOT.jar)</p>
<blockquote>
</blockquote>
<p>&lt;version&gt; : 애플리케이션의 버전. 접미사로 SNAPSHOT이 붙으면 아직 개발단계라는 의미이며, 메이븐에서 라이브러리를 관리하는 방식이 다르다고 한다.</p>
<blockquote>
</blockquote>
<p>&lt;packaging&gt; : jar, war, ear, pom등 패키지 유형을 나타낸다.</p>
<blockquote>
</blockquote>
<p>&lt;name&gt; : 프로젝트 명</p>
<blockquote>
</blockquote>
<p>&lt;description&gt; : 프로젝트 설명</p>
<blockquote>
</blockquote>
<p>&lt;url&gt; : 프로젝트를 찾을 수 있는 URL</p>
<blockquote>
<h4 id="2-의존성-라이브러리-정보">2. 의존성 라이브러리 정보</h4>
</blockquote>
<p>의존성 라이브러리 정보를 적을 수 있다.</p>
<blockquote>
</blockquote>
<p>최소한 <strong>groupId, artifactId, version</strong> 정보가 필요하다.</p>
<blockquote>
</blockquote>
<p>스프링부트의 spring-boot-starter 같은 경우에는 부모 <code>pom.xml</code>에서 이미 버전 정보가 있어서 version은 따로 지정할 필요가 없다. 특히 스프링부트는 해당 스프링버전에 잘 맞는 버전으로 이미 설정되어 있기 때문에 오버라이드해서 문제가 생기는 부분은 순전히 개발자 탓이다.</p>
<blockquote>
</blockquote>
<p>그리고 A라는 라이브러리를 사용하는데 B, C, D가 의존성을 가진다면 A를 dependency에 추가하면 자동으로 필요한 B,C,D도 가져오는 기능이 있다.</p>
<blockquote>
</blockquote>
<p><code>dependency</code>에 &lt;scope&gt;의 경우 <code>compile</code>, <code>runtime</code>, <code>provided</code>, <code>test</code>등이 올 수 있는데 해당 라이브러리가 언제 필요한지, 언제 제외되는지를 나타내는 것으로 따로 검색해보면 알 수 있다.</p>
<blockquote>
<h4 id="3-build-정보">3. build 정보</h4>
</blockquote>
<p>build tool : maven의 핵심인 빌드와 관련된 정보를 설정할 수 있는 곳이다.</p>
<blockquote>
</blockquote>
<p>&lt;build&gt; 부분에서 설정할 수 있는 값들에 대해 설명하기 전에 &quot;라이프 사이클(life-cycle&quot;에 대해서 알 필요가 있다.</p>
<blockquote>
</blockquote>
<p>객체의 생명주기처럼 maven에는 라이프 사이클이 존재한다.</p>
<blockquote>
</blockquote>
<p>크게 default, clean, site 라이프 사이클로 나누고 세부적으로 페이즈(phase) 있다. 아래 그림 참조
<img src="https://velog.velcdn.com/images/hyeon_geun/post/53abac05-4a4e-4383-b41b-b61e6f340b53/image.png" alt=""></p>
<blockquote>
</blockquote>
<p>메이븐의 모든 기능은 플러그인(plugin)을 기반으로 동작한다.</p>
<blockquote>
</blockquote>
<p>플러그인에서 실행할 수 있는 각각의 작업을 골(goal)이라하고 하나의 페이즈는 하나의 골과 연결되며, 하나의 플러그인에는 여러 개의 골이 있을 수 있다.</p>
<h3 id="구조">구조</h3>
<p><strong>Maven 프로젝트의 기본 디렉토리 정책</strong></p>
<blockquote>
<p><strong>application-core</strong></p>
</blockquote>
<ul>
<li>pom.xml</li>
<li>src<ul>
<li>main<ul>
<li>java<ul>
<li>com.package.dir</li>
</ul>
</li>
<li>resources</li>
</ul>
</li>
<li>test<ul>
<li>java<ul>
<li>com.package.dir</li>
</ul>
</li>
<li>resources</li>
</ul>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Vue]]></title>
            <link>https://velog.io/@hyeon_geun/Vue</link>
            <guid>https://velog.io/@hyeon_geun/Vue</guid>
            <pubDate>Tue, 20 Jun 2023 10:46:35 GMT</pubDate>
            <description><![CDATA[<h2 id="vuejs란-무엇인가">Vue.js란 무엇인가?</h2>
<blockquote>
<p>MVVM 패턴의 ViewModel 레이어에 해당하는 화면단 라이브러리</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/hyeon_geun/post/a3ec8c05-3b39-4f8d-8510-409fa4788f11/image.png" alt=""></p>
<blockquote>
<ul>
<li><strong>데이터 바인딩</strong>과 <strong>화면 단위를 컴포넌트 형태로 제공</strong>하며, <strong>관련 API 를 지원</strong>하는데에 궁극적인 목적이 있음</li>
</ul>
</blockquote>
<ul>
<li>Angular에서 지원하는 <strong>양방향 데이터 바인딩</strong>을 동일하게 제공</li>
<li>하지만 <strong>컴포넌트 간 통신</strong>의 기본 골격은 React의 <strong>단방향 데이터 흐름(부모 -&gt; 자식)</strong>을 사용</li>
<li>다른 프런트엔드 프레임워크(Angular, React)와 비교했을 때 상대적으로 가볍고 빠름.</li>
</ul>
<h3 id="💡-mvvm-패턴이란">💡 MVVM 패턴이란?</h3>
<p>Backend 로직과 Client 의 마크업 &amp; 데이터 표현단을 분리하기 위한 구조로 전통적인 <strong>MVC 패턴의 방식</strong>에서 기인하였다. 간단하게 생각해서 화면 앞단의 <strong>화면 동작 관련 로직</strong>과 뒷단의 <strong>DB 데이터 처리 및 서버 로직</strong>을 <strong>분리</strong>하고, 뒷단에서 넘어온 데이터를 <code>Model</code> 에 담아 <code>View</code> 로 넘겨준다.</p>
<p><img src="https://velog.velcdn.com/images/hyeon_geun/post/7b52fe78-da2f-465b-8c12-4f4a79967bad/image.png" alt=""></p>
<blockquote>
<p><strong>Vue.js 시작하기</strong></p>
</blockquote>
<pre><code>&lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;</code></pre><h3 id="📌-vue-instance-생성자">📌 <strong>Vue Instance 생성자</strong></h3>
<p>Vue를 사용할 때 <strong>필수로 생성이 필요한 코드</strong>
<strong>인스턴스 생성 시 Vue 개발자 도구에서 Root 컴포넌트로 인식</strong></p>
<blockquote>
<pre><code class="language-js">new Vue({
  // instance option properties
  template: &quot;&quot;,
  el: &quot;#app&quot;,
  data: {}
  methods: {}
  created: function() {}
});</code></pre>
</blockquote>
<pre><code>&gt;- `el`: app이라는 ID를 가진 태그를 찾아서 인스턴스를 붙여준다. 태그에 인스턴스를 붙여주면 view의 기능과 속성을 조작 가능
- `data`: 뷰의 반응성(Reactivity)이 반영된 데이터 속성
- `template` : 화면에 표시할 요소 (HTML, CSS 등)
- `methods` : 화면의 동작과 이벤트 로직을 제어하는 메서드
- `created` : 뷰의 라이프 사이클과 관련된 속성
- `watch` : data에서 정의한 속성이 변화했을 때 추가 동작을 수행할 수 있게 정의하는 속성&lt;br&gt;

---

### 📌 Components
**화면의 영역을 영역별로 구분해서 코드로 관리**
&gt;
- 화면의 영역을 구분하여 개발할 수 있는 뷰의 기능
- 코드의 재사용성이 올라가고 빠른 화면 제작 가능
- `전역 컴포넌트`는 기본적으로 모든 인스턴스에 등록이 되어 있음
- `지역 컴포넌트`는 인스턴스마다 새로 생성이 필요
- 다만 서비스를 구현할 때는 하나의 인스턴스에 컴포넌트를 붙여 나가는 형식으로 진행&lt;br&gt;
&gt; ** 예시 **
```js
&lt;h1&gt;component 사용예제&lt;/h1&gt;
&lt;div id=&quot;app&quot;&gt;
    &lt;h2&gt;친구 목록 입니다.&lt;/h2&gt;
    &lt;friends-component v-bind:friends=&quot;friends&quot;&gt;&lt;/friends-component&gt;
&gt;
    &lt;h2&gt;동물 친구 목록 입니다.&lt;/h2&gt;
    &lt;friends-component v-bind:friends=&quot;friends2&quot;&gt;&lt;/friends-component&gt;
&lt;/div&gt;
&lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;
    let app = new Vue({
        el        : &quot;#app&quot;,
        data      : {
            friends : [&quot;김구라&quot;, &quot;해골&quot;, &quot;원숭이&quot;],
            friends2: [&quot;강아지&quot;, &quot;고양이&quot;, &quot;두더지&quot;]
        },
        components: {
            &quot;friends-component&quot;: {
                template: `
                    &lt;ul&gt;
                    &lt;li v-for=&quot;item in friends&quot;&gt;{{ item }}&lt;/li&gt;
                    &lt;/ul&gt;
                `,
                props   : [&quot;friends&quot;]
            }
        }
    });
&lt;/script&gt;</code></pre><p><img src="https://velog.velcdn.com/images/hyeon_geun/post/3944369c-6179-468f-87e2-279a5079daf2/image.png" alt=""></p>
<hr>
<h3 id="📌-props">📌 props</h3>
<p>컴포넌트 간에 <strong>데이터를 전달</strong>할 수 있는 컴포넌트 통신 방법
<strong>상위 컴포넌트</strong>에서 <strong>하위 컴포넌트</strong>로 내려보내는 데이터 속성</p>
<blockquote>
<p><strong>상위 컴포넌트의 템플릿</strong></p>
</blockquote>
<pre><code class="language-js">&lt;!-- 상위 컴포넌트 --&gt;
&lt;div id=&quot;app&quot;&gt;
  &lt;!-- 하위 컴포넌트에 상위 컴포넌트가 갖고 있는 값을 전달함 --&gt;
  &lt;child-component v-bind:프롭스 속성 명=&quot;상위 컴포넌트의 data 속성&quot;/&gt;
&lt;/div&gt;</code></pre>
<p><strong>하위 컴포넌트의 컴포넌트</strong></p>
<pre><code class="language-js">var childComponent = {
  props: [&#39;프롭스 속성 명&#39;]
}</code></pre>
<p><strong>예 시</strong></p>
<pre><code class="language-js">&lt;body&gt;
  &lt;div id=&quot;app&quot;&gt;
    &lt;!-- &lt;app-header v-bind:프롭스 속성 이름=&quot;상위 컴포넌트의 데이터 이름&quot;&gt;&lt;/app-header&gt; --&gt;
    &lt;app-header v-bind:propsdata=&quot;message&quot;&gt;&lt;/app-header&gt;
    &lt;app-content v-bind:propsdata=&quot;num&quot;&gt;&lt;/app-content&gt;
  &lt;/div&gt;
&gt;
  &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;script&gt;
    var appHeader = {
      template: &#39;&lt;h1&gt;{{ propsdata }}&lt;/h1&gt;&#39;,
      props: [&#39;propsdata&#39;] // 하위 컴포넌트의 프롭스 속성명
    }
    var appContent = {
      template: &#39;&lt;div&gt;{{ propsdata }}&lt;/div&gt;&#39;,
      props: [&#39;propsdata&#39;] // 하위 컴포넌트의 프롭스 속성명
    }
&gt;
    new Vue({
      el: &#39;#app&#39;,
      components: {
        &#39;app-header&#39;: appHeader,
        &#39;app-content&#39;: appContent
      },
      data: {
        message: &#39;hi&#39;,
        num: 10
      }
    })
  &lt;/script&gt;
&lt;/body&gt;</code></pre>
<blockquote>
</blockquote>
<h4 id="같은-레벨의-컴포넌트-간-통신">같은 레벨의 컴포넌트 간 통신</h4>
<p>동일한 상위 컴포넌트를 가진 하위 컴포넌트들 간의 통신은 아래와 같이 해야 한다.</p>
<blockquote>
</blockquote>
<ul>
<li><code>Child(하위)</code> -&gt; <code>Parent(상위)</code> -&gt; <code>Children(하위 2개)</code><blockquote>
</blockquote>
📢 <strong>컴포넌트 간의 직접적인 통신은 불가능</strong>하도록 되어 있는게 Vue 의 기본 구조</li>
</ul>
<hr>
<h3 id="📌-event-bus">📌 Event Bus</h3>
<p>상위 ↔ 하위 관계가 아닌 컴포넌트 간의 통신을 위해 <strong>Event Bus</strong>를 활용할 수 있다.</p>
<blockquote>
<p><strong>Event Bus</strong>를 사용하기 위해 새로운 뷰 인스턴스를 아래와 같이 생성한다.</p>
</blockquote>
<pre><code class="language-js">// 화면 개발을 위한 인스턴스와 다른 별도의 인스턴스를 생성하여 활용
var eventBus = new Vue();
&gt;
new Vue({
  // ...
});</code></pre>
<p>** 이벤트를 발생시킬 컴포넌트에서 <code>$emit()</code> 호출 **</p>
<pre><code class="language-js">eventBus.$emit(&quot;refresh&quot;, 10);</code></pre>
<p><strong>이벤트를 받을 컴포넌트에서 $on() 이벤트 수신</strong></p>
<pre><code class="language-js">// 이벤트 버스 이벤트는 일반적으로 라이프 사이클 함수에서 수신
new Vue({
  created: function() {
    eventBus.$on(&quot;refresh&quot;, function(data) {
      console.log(data); // 10
    });
  }
});</code></pre>
<p><strong>만약, eventBus의 콜백 함수 안에서 해당 컴포넌트의 메서드를 참고하려면 vm 사용</strong></p>
<pre><code class="language-js">new Vue({
  methods: {
    callAnyMethod() {
      // ...
    }
  },
  created() {
    var vm = this;
    eventBus.$on(&quot;refresh&quot;, function(data) {
      console.log(this); // 여기서의 this는 이벤트 버스용 인스턴스를 가리킴
      vm.callAnyMethod(); // vm은 현재 인스턴스를 가리킴
    });
  }
});</code></pre>
<p><strong>사용 예시 1</strong></p>
<pre><code class="language-js">&lt;body&gt;
&lt;h1&gt;자식 component 에서 발생하는 이벤트&lt;/h1&gt;
&lt;div id=&quot;app&quot;&gt;
    &lt;my-component v-on:mom=&quot;feed&quot;&gt;&lt;/my-component&gt;
&lt;/div&gt;
&lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;
    Vue.component(&quot;my-component&quot;, {
        template: `
            &lt;div&gt;
            &lt;button v-on:click=&quot;callMom&quot;&gt;엄마!&lt;/button&gt;
            &lt;/div&gt;
        `,
        methods : {
            callMom() {
                // this.$emit(&quot;이벤트명&quot;, 전달할 data)
                this.$emit(&quot;mom&quot;, &quot;배고파&quot;);
            }
        }
    });
&gt;
    let app = new Vue({
        el     : &quot;#app&quot;,
        methods: {
            feed(data) {
                alert(data);
            }
        }
    });
&lt;/script&gt;
&lt;/body&gt;</code></pre>
<p>** 사용 예시 2**</p>
<pre><code class="language-js">&lt;body&gt;
&lt;h1&gt;event emit 예제&lt;/h1&gt;
&lt;div id=&quot;app&quot;&gt;
    &lt;!-- list 라는 props &quot;delete&quot; 이벤트, &quot;update&quot; 이벤트가 특정 시점에 발생한다. --&gt;
    &lt;friend-component
        v-bind:list=&quot;members&quot;
        v-on:delete=&quot;deleteMember&quot;
        v-on:update=&quot;updateMember&quot;&gt;&lt;/friend-component&gt;
&lt;/div&gt;
&lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;
    Vue.component(&quot;friend-component&quot;, {
        template: `
            &lt;ul&gt;
            &lt;li v-for=&quot;(item, index) in list&quot;&gt;
                {{ item }}
                &lt;button v-on:click=&quot;updateItem(index)&quot;&gt;수정&lt;/button&gt;
                &lt;button v-on:click=&quot;deleteItem(index)&quot;&gt;삭제&lt;/button&gt;
            &lt;/li&gt;
            &lt;/ul&gt;
        `,
        props   : [&quot;list&quot;],
        methods : {
            deleteItem(i) {
                this.$emit(&quot;delete&quot;, i);
            },
            updateItem(i) {
                const newName = prompt(&quot;수정할 이름을 입력하세요&quot;);
&gt;
                //this.$emit(&quot;update&quot;, {i:i, newName:newName});
                this.$emit(&quot;update&quot;, {i, newName});
            }
        }
    });
&gt;
    let app = new Vue({
        el     : &quot;#app&quot;,
        data   : {
            members: [&#39;김구라&#39;, &#39;해골&#39;, &#39;원숭이&#39;]
        },
        methods: {
            deleteMember(index) {
                //push 또는 splice 하면 배열의 방의 사이즈가 변경이 되기 때문에 UI 업데이트가 자동으로 된다.
                //this.members.splice(index, 1);
                //{ } 없이 return 예약어 없이 리턴할 값만 작성해도 된다.
&gt;
                //새로운 배열의 참조값으로 덮어쓰면 모델이 변경된 것이기 때문에 UI 업데이트가 자동으로 된다.
                this.members = this.members.filter((item, i) =&gt; index != i);
            },
            updateMember(data) {
                //아래처럼 배열을 변경하면 변경이 감지가 안되기 때문에 화면 업데이트가 안된다.
                //this.members[data.i] = data.newName;
&gt;
                //아래의 2가지 방법중 하나로 배열을 변경해야 한다.
                //Vue.set(this.members, data.i, data.newName);
                // $set(수정할 배열의 참조 값, 수정할 인덱스, 수정할 값)
                //this.$set(this.members, data.i, data.newName);
&gt;
                // this.members = 아이템이 수정된 새로운 배열의 참조값
&gt;
                //item 이 수정된 새로운 배열의 참조값을 얻어내서 모델을 변경해도 화면 update 가 일어난다.
                this.members = this.members.map(() =&gt; {
                    //만일 수정할 index 라면
                    if (index == data.i) {
                        //수정할 데이터를 리턴해준다.
                        return data.newName;
                    }
                    return item;
                });
            }
        }
    });
&lt;/script&gt;
&lt;/body&gt;</code></pre>
<hr>
<h3 id="📌-example">📌 Example</h3>
<blockquote>
<p>** 사용자 입력 폼 예시**</p>
</blockquote>
<pre><code class="language-js">&lt;template&gt;
  &lt;!-- button의 submit 동작 시 submitForm 메서드 호출--&gt;
  &lt;form v-on:submit.prevent=&quot;submitForm&quot;&gt;
    &lt;div&gt;
      &lt;label for=&quot;username&quot;&gt;id: &lt;/label&gt;
      &lt;input id=&quot;username&quot; type=&quot;text&quot; v-model=&quot;username&quot;&gt;
    &lt;/div&gt;
    &lt;div&gt;
      &lt;label for=&quot;password&quot;&gt;pw: &lt;/label&gt;
      &lt;input id=&quot;password&quot; type=&quot;password&quot; v-model=&quot;password&quot;&gt;
    &lt;/div&gt;
    &lt;button type=&quot;submit&quot;&gt;login&lt;/button&gt;
  &lt;/form&gt;
&lt;/template&gt;
&gt;
&lt;script&gt;
import axios from &#39;axios&#39;;
&gt;
export default {
  data: function() {
    return {
      username: &#39;&#39;,
      password: &#39;&#39;,
    }
  },
  methods: {
    submitForm: function() {
      // event.preventDefault(); -&gt; form 의 새로고침/이동 동작을 막기 위해 사용했던 것을 v-on:submit.prevent 로 해결
      var url = &#39;&#39;;
      var data = {
        username: this.username,
        password: this.password
      }
      axios.post(url, data)
        .then(function(response) {
          console.log(response);
        })
        .catch(function(error) {
          console.log(error);
        });
    }
  }
}
&lt;/script&gt;</code></pre>
<hr>
<h3 id="📖-axios">📖 Axios</h3>
<p>뷰에서 권고하는 HTTP 통신 라이브러리이다.
<code>Promise</code> 기반(JS 비동기 처리 패턴)이며 상대적으로 다른 <code>HTTP</code> 통신 라이브러리들에 비해 문서화가 잘되어 있고 <code>API</code>가 다양하다</p>
<blockquote>
</blockquote>
<h4 id="install-axios">Install Axios</h4>
<pre><code class="language-js">&lt;script src=&quot;https://unpkg.com/axios/dist/axios.min.js&quot;&gt;&lt;/script&gt;</code></pre>
<p><strong>사용 예시</strong></p>
<pre><code class="language-js">&lt;body&gt;
  &lt;div id=&quot;app&quot;&gt;
    &lt;button v-on:click=&quot;getData&quot;&gt;get user&lt;/button&gt;
    &lt;div&gt;
      {{ users }}
    &lt;/div&gt;
  &lt;/div&gt;
&gt;
  &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;script src=&quot;https://unpkg.com/axios/dist/axios.min.js&quot;&gt;&lt;/script&gt;
  &lt;script&gt;
    new Vue({
      el: &#39;#app&#39;,
      data: {
        users: []
      },
      methods: {
        getData: function() { 
          var vm = this;
          axios.get(&#39;https://jsonplaceholder.typicode.com/users/&#39;)
            .then(function(response) {
              console.log(response.data);
              vm.users = response.data;
            })
            .catch(function(error) {
              console.log(error);
            });
        }
      }
    })
  &lt;/script&gt;
&lt;/body&gt;</code></pre>
<hr>
<p>** fetch 를 이용한 json 요청**</p>
<pre><code class="language-js">&lt;body&gt;
&lt;h1&gt;ajax 요청을 통해서 받아온 데이터 사용하기&lt;/h1&gt;
&lt;p&gt;페이지 전환 없이 서버에 요청하는 것을 ajax 라고 생각하면 된다.&lt;/p&gt;
&lt;div id=&quot;app&quot;&gt;
    &lt;br&gt;
    &lt;table&gt;
        &lt;thead&gt;
        &lt;tr&gt;
            &lt;th&gt;번호&lt;/th&gt;
            &lt;th&gt;작성자&lt;/th&gt;
            &lt;th&gt;제목&lt;/th&gt;
        &lt;/tr&gt;
        &lt;/thead&gt;
        &lt;tbody&gt;
        &lt;!-- 글번호는 pk 이기 때문에 --&gt;
        &lt;tr v-bind:key=&quot;tmp.num&quot; v-for=&quot;tmp in list&quot;&gt;
            &lt;td&gt;{{tmp.num}}&lt;/td&gt;
            &lt;td&gt;{{tmp.writer}}&lt;/td&gt;
            &lt;td&gt;{{tmp.title}}&lt;/td&gt;
        &lt;/tr&gt;
        &lt;/tbody&gt;
    &lt;/table&gt;
&lt;/div&gt;
&lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;
    new Vue({
        el  : &quot;#app&quot;,
        data: {
            list: [],
        },
        created() {
            //Vue 가 준비가 되었을 때 (root component 가 준비되었을 때) 최초 한 번 호출된다.
            //fetch 를 이용해서 서버에 데이터를 요청한다.
            fetch(&quot;../cafe/json_list.jsp&quot;)
                .then(res =&gt; res.json())
                .then(data =&gt; {
                    //data 는 글목록이 들어 있는 배열이다.
                    this.list = data;
                });
        },
        methods: {},
    })
&lt;/script&gt;
&lt;/body&gt;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Javascript #7]]></title>
            <link>https://velog.io/@hyeon_geun/Javascript-7</link>
            <guid>https://velog.io/@hyeon_geun/Javascript-7</guid>
            <pubDate>Fri, 16 Jun 2023 04:15:42 GMT</pubDate>
            <description><![CDATA[<h2 id="fetch--ajax">Fetch &amp; Ajax</h2>
<blockquote>
<h3 id="fetch-api">Fetch API</h3>
<p><strong>fetch API</strong>는 <code>Promise</code> 기반으로 구성되어 있어 <strong>비동기 처리 프로그래밍 방식</strong>에 잘 맞는 형태이다. 그래서 <code>then</code>이나 <code>catch</code> 와 같은 체이닝으로 작성할 수 있다는 장점이 있다. 또한 <code>fetch API</code>는 <code>JS</code> 기본 기능 이기 때문에, 다른 작업을 하지 않아도 바로 사용할 수 있다.</p>
</blockquote>
<pre><code class="language-js">fetch(&#39;ajax_intro_data.txt&#39;)
    .then( response =&gt; response.text() )
    .then( text =&gt; { document.getElementById(&quot;#t&quot;).innerHTML = text; } )
&gt;
/* &#39;fetch(&#39;서버주소&#39;)&#39; 는 웹 브라우저에게 &#39;이 서버주소로 요청해줘&#39; 라는 의미이고, 
뒤에 .then이 붙으면 &#39;요청 끝나고나서 이 할일을 해줘!&#39; 라는 것이다. */</code></pre>
<br>

<blockquote>
<h3 id="fetch-→-json">fetch → json</h3>
<p><code>fetch</code>를 이용해서 <code>json</code> 형식으로 <strong>변환</strong>하는 순서는 다음과 같다.</p>
</blockquote>
<pre><code class="language-js">fetch(&quot;URL&quot;, option)
   .then(res =&gt; res.text())
   .then(data =&gt; {
      console.log(data);
      const result = JSON.parse(data);
      console.log(result);
   });</code></pre>
<p><img src="https://velog.velcdn.com/images/hyeon_geun/post/6c351937-752e-4f35-ac06-00a60e0ec0cc/image.png" alt=""></p>
<blockquote>
</blockquote>
<ol>
<li><code>fetch</code> 에는 기본적으로 첫 번째 인자에 요청할 <strong><code>url</code></strong>이 들어간다.</li>
<li>기본적으로 http 메소드 중 <code>GET</code>으로 동작한다.</li>
<li><code>fetch</code>를 통해 <code>ajax</code>를 호출 시 해당 주소에 요청을 보낸 다음, 응답 객체(Promise object Response)를 받는다.</li>
<li>그러면 첫 번째 <strong><code>then</code></strong>에서 그 응답을 받게되고, <strong><code>res.text()</code></strong> 메서드로 파싱한 text값을 리턴한다.</li>
<li>그러면 그 다음 <code>then</code>에서 리턴받은 <code>text</code> 값을 받고, 원하는 처리를 할 수 있게 된다.<blockquote>
<br>
💡**개발자 도구의 네트워크 탭**에 가보면 `fetch`를 통해 **얻어온 데이터**를 볼 수 있다.
![](https://velog.velcdn.com/images/hyeon_geun/post/a190087f-3441-4de3-895b-4da1e37b1bec/image.png)


</blockquote>
<h3 id="fetch--ajax-→-json">fetch &amp; ajax → json</h3>
<img src="https://velog.velcdn.com/images/hyeon_geun/post/85893912-ab02-4a1a-b30e-a053a7c9e2c9/image.png" alt=""><blockquote>
</blockquote>
</li>
</ol>
<p><strong>사용 예시</strong>
<strong>[GET]</strong></p>
<pre><code class="language-js">fetch(&#39;TARGET URL&#39;) // url 입력, GET메서드임
    .then(res =&gt; res.json())  //응답 결과를 json으로 파싱
    .then(data =&gt; { 
&gt;    
            //***여기서 응답 결과로 실행할 동작을 정의하면 됨***
            // [ data.키값 ] 이런 형태로 value 추출 가능 
&gt;            
            console.log(data); //응답 결과를 console 창에 출력
&gt;             
    })
    .catch(err =&gt; { // 오류 발생시 오류를 담아서 보여줌
        console.log(&#39;Fetch Error&#39;, err);
    });</code></pre>
<p><strong>[POST]</strong></p>
<pre><code class="language-js">//POST 메서드로 전송할 데이터
let formData = new FormData(); 
formData.append(&#39;key&#39;, value); // key-value (키-값)의 형태로 데이터 추가함
&gt;
//page 시작할 때 마다, db에 portfolio 데이터 요청
fetch(&#39;TARGET URL&#39;, { // url 입력 및 [options] 값 설정
    method: &#39;post&#39;, 
    body: formData  //전송할 데이터 body에 추가
    })
    .then(res =&gt; res.json()) //응답 결과를 json으로 파싱
    .then(data =&gt; {
&gt;    
            //***여기서 응답 결과로 실행할 동작을 정의하면 됨***
            // [ data.키값 ] 이런 형태로 value 추출 가능 
&gt;            
            console.log(data); //응답 결과를 console 창에 출력
&gt;              
    })
    .catch(err =&gt; { // 오류 발생시 오류를 담아서 보여줌
        console.log(&#39;Fetch Error&#39;, err);
    });</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Java Web #3]]></title>
            <link>https://velog.io/@hyeon_geun/Java-Web-3</link>
            <guid>https://velog.io/@hyeon_geun/Java-Web-3</guid>
            <pubDate>Tue, 13 Jun 2023 03:52:34 GMT</pubDate>
            <description><![CDATA[<h1 id="jstl">JSTL</h1>
<blockquote>
</blockquote>
<p><strong>JSTL</strong>의 정식 명칭은 <u>자바서버 페이지 표준 태그 라이브러리(JavaServer Pages Standard Tag Library)</u>이고 줄여서 JSTL이라 부른다.
일반적으로 알고있는 <strong>JSTL</strong>이란 <strong>JSTL + EL의 조합</strong>을 말한다.</p>
<blockquote>
<p><code>HTML</code> 코드 내에 <code>java</code> 코드인 스크립틀릿 <code>&lt;%= student %&gt;</code>를 <code>${student}</code>로, <code>&lt;%=if %&gt;</code>문을 <code>&lt;c:if&gt;</code>, <code>&lt;%=for%&gt;</code>문을 <code>&lt;c:forEach&gt;</code>로 대체하여 사용한다.</p>
</blockquote>
<ul>
<li><strong>JSTL</strong>은 <strong>JSP 페이지 내에서 자바 코드를 바로 사용하지 않고 로직을 내장하는 효율적인 방법</strong>을 제공한다. 표준화된 태그 셋을 사용하여 자바 코드가 들락거리는 것보다 더 코드의 <strong>유지보수</strong>와 응용 소프트웨어 코드와 사용자 인터페이스 간의 <strong>관심사의 분리</strong>로 이어지게 한다.</li>
<li>JSTL은 라이브러리이기 때문에 사용하기전에 <strong>core</strong>를 <code>header</code>에 추가해주어야 한다.<pre><code class="language-java">&lt;%@ taglib prefix=&quot;접두사&quot; uri=&quot;URI&quot; %&gt;
&lt;%@ taglib uri=&quot;http://java.sun.com/jstl/core&quot; prefix=&quot;c&quot; %&gt;</code></pre>
</li>
<li><strong>JSTL core의 태그</strong>
<img src="https://velog.velcdn.com/images/hyeon_geun/post/af376f0e-72f6-478c-b409-e69eb016e525/image.png" alt=""></li>
<li><em>사용 예제(JSP 형식과 비교)*</em>
<img src="https://velog.velcdn.com/images/hyeon_geun/post/8bf3f137-90f1-4b76-8311-ef5a5894fc02/image.png" alt=""><pre><code class="language-java">&lt;%@ taglib uri=&quot;http://java.sun.com/jsp/jstl/core&quot; prefix=&quot;c&quot;%&gt;
&lt;html&gt;
&lt;head&gt;
   &lt;title&gt;test_jstl/hello.jsp&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
   &lt;h1&gt;JSTL 의 core 라이브러리 사용해보기&lt;/h1&gt;
   &lt;c:forEach var=&quot;i&quot; begin=&quot;0&quot; end=&quot;9&quot; step=&quot;1&quot;&gt;
   &lt;p&gt;안녕 JSTL &lt;strong&gt;${i}&lt;/strong&gt;&lt;/p&gt;
   &lt;/c:forEach&gt;
   &gt;
&gt; ---------------------------------------------------------------------------
&gt;
   &lt;h1&gt;JSTL 을 사용하지 않고 java code 를 활용해서 위와 같은 동작을 해 보세요&lt;/h1&gt;
   &lt;%for(int i=0; i&lt;10; i++){%&gt;
       &lt;p&gt;안녕 JSTL &lt;strong&gt;&lt;%=i%&gt;&lt;/strong&gt;&lt;/p&gt;
   &lt;%}%&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
</li>
</ul>
<h2 id="cout-태그">&lt;c:out&gt; 태그</h2>
<blockquote>
<p><strong>출력문</strong>을 만드는 태그이다.</p>
</blockquote>
<blockquote>
<pre><code class="language-java">&lt;c:out value=&quot;출력값&quot; default=&quot;기본값&quot; /&gt;
&lt;c:out value=&quot;출력값&quot;&gt;기본값&lt;/c:out&gt;</code></pre>
</blockquote>
<pre><code>&gt;** 사용 예시**
```java
&lt;c:out value=&quot;Hello World&quot; /&gt;&lt;br&gt;             //Hello World
&lt;c:out value=&quot;${null}&quot;&gt;JSTL&lt;/c:out&gt;&lt;br&gt;        //JS
&lt;c:out value=&quot;Hello&quot;&gt;World&lt;/c:out&gt;&lt;br&gt;        //Hello
&lt;c:out value=&quot;${null}&quot; /&gt;                    //</code></pre><h2 id="cset-태그">&lt;c:set&gt; 태그</h2>
<blockquote>
<p><strong>변수를 다룰 때 사용</strong>한다.</p>
</blockquote>
<blockquote>
<p>이 태그로 생성한 변수는 JSP의 로컬 변수가 아니라 <strong>서블릿 보관소(JspContext, ServletRequest, HttpSession, ServletContext)에 저장</strong>된다.</p>
</blockquote>
<pre><code class="language-java">&lt;c:set var=&quot;변수명&quot; value=&quot;값&quot; scope=&quot;page(기본값)|request|session|application&quot; /&gt;
&lt;c:set var=&quot;변수명&quot; scope=&quot;page(기본값)|request|session|application&quot;&gt;값&lt;/c:set&gt;</code></pre>
<blockquote>
</blockquote>
<p><strong>사용 예시</strong></p>
<pre><code class="language-java">&lt;%--&lt;c:set&gt; 기본 사용 방법--%&gt;
&lt;c:set var=&quot;username1&quot; value=&quot;현근1&quot; /&gt;
&lt;c:set var=&quot;username2&quot;&gt;현근2&lt;/c:set&gt;
${username1}&lt;br&gt;                                        //현근1
${username2}&lt;br&gt;                                        //현근2
${pageScope.username1}&lt;br&gt;                                //현근1
${pageScope.username2}&lt;br&gt;                                //현근2
&lt;p&gt;&lt;/p&gt;
&gt;
&lt;%--보관소 지정(ServletRequest)--%&gt;
&lt;c:set var=&quot;username3&quot; scope=&quot;request&quot;&gt;현근3&lt;/c:set&gt;
${pageScope.username3}&lt;br&gt;                                //현근3
${requestScope.username3}&lt;br&gt;
&lt;p&gt;&lt;/p&gt;
 &gt;
&lt;%--기존 값 덮어씀--%&gt;
&lt;% pageContext.setAttribute(&quot;username4&quot;, &quot;현근4&quot;); %&gt;
기존 username4 : ${username4}&lt;br&gt;                        //기존 username4 : 현근4
&lt;c:set var=&quot;username4&quot; value=&quot;현근5&quot; /&gt;
변경 username4 : ${username4}&lt;br&gt;                        //변경 username4 : 현근5</code></pre>
<h3 id="💡-실행-결과">💡 실행 결과</h3>
<ol>
<li><strong>scope의 기본값</strong>은 <strong>page</strong>이다. scope를 생략하면 <code>JspContext</code>에 저장된다.</li>
<li><code>scope=&quot;request&quot;</code>와 같이 <strong>scope를 명시적으로 지정</strong>할 수도 있다.<blockquote>
</blockquote>
</li>
</ol>
<hr>
<h3 id="cset을-이용한-객체의-프로퍼티-값-설정">&lt;c:set&gt;을 이용한 객체의 프로퍼티 값 설정</h3>
<blockquote>
<pre><code class="language-java">&lt;c:set target=&quot;대상 객체&quot; property=&quot;설정할 프로퍼티&quot; value=&quot;프로퍼티 값&quot; /&gt;</code></pre>
</blockquote>
<pre><code>**사용 예시**
```java
&lt;%!
    public static class MyMember {
        int no;
        String name;
&gt; 
        public int getNo() {
            return no;
        }
&gt; 
        public void setNo(int no) {
            this.no = no;
        }
&gt; 
        public String getName() {
            return name;
        }
&gt; 
        public void setName(String name) {
            this.name = name;
        }
    }
%&gt;
&lt;%
    MyMember member = new MyMember();
    member.setNo(100);
    member.setName(&quot;김연아&quot;);
    pageContext.setAttribute(&quot;member&quot;, member);
%&gt;
${member.name}&lt;br&gt;                                            //김연아
&lt;c:set target=&quot;${member}&quot; property=&quot;name&quot; value=&quot;박지성&quot; /&gt;
${member.name}&lt;br&gt;                                            //박지성</code></pre><blockquote>
</blockquote>
<p><strong>Inner class MyMember</strong>의 인스턴스 <code>member</code>를 생성하고 <code>member</code>의 <code>name</code>을 <code>&lt;c:set&gt;</code> 태그를 사용해서 변경하는 코드이다.
<code>&lt;c:set&gt;</code>으로 객체의 프로퍼티 값을 설정할때는 <code>setter()</code>의 리턴 타입이 반드시 <code>void</code>여야 한다.</p>
<h2 id="cremove-태그">&lt;c:remove&gt; 태그</h2>
<blockquote>
<p>보관소에 <strong>저장된 값을 제거</strong>한다.</p>
</blockquote>
<blockquote>
</blockquote>
<pre><code class="language-java">&lt;c:remove var=&quot;변수명&quot; scope=&quot;page(기본값) | request | session | application&quot; /&gt;</code></pre>
<p><code>&lt;c:set&gt;</code>과 마찬가지로 <code>scope</code> 속성으로 <strong>보관소를 명시</strong>할 수 있고 <strong>보관소의 기본값은 page</strong>이다. <br>
<strong>사용 예시</strong></p>
<pre><code class="language-java">&lt;% pageContext.setAttribute(&quot;username1&quot;, &quot;황현근&quot;); %&gt;
${username1}&lt;br&gt;                                        //황현근
&lt;c:remove var=&quot;username1&quot; /&gt;
${username1}&lt;br&gt;                                        //</code></pre>
<h2 id="cif-태그">&lt;c:if&gt; 태그</h2>
<blockquote>
<p>test의 조건식이 true이면 &#39;내용&#39;이 실행된다.
var, scope 속성은 test 결과를 저장할때 사용한다.</p>
</blockquote>
<blockquote>
</blockquote>
<pre><code class="language-java">&lt;c:if test=&quot;조건식&quot; var=&quot;변수명&quot; scope=&quot;page(기본값) | request | session | application&quot;&gt;내용&lt;/c:if&gt;</code></pre>
<p><strong>사용 예시</strong></p>
<pre><code class="language-java">&lt;c:if test=&quot;${10 &gt; 20}&quot; var=&quot;result1&quot;&gt;
    10은 20보다 크다.&lt;br&gt;
&lt;/c:if&gt;
result1 : ${result1}&lt;br&gt;
&gt; 
&lt;c:if test=&quot;${10 &lt; 20}&quot; var=&quot;result2&quot;&gt;
    20은 10보다 크다.&lt;br&gt;
&lt;/c:if&gt;
result2 : ${result2}
---------------------------
// result1 : false
// 20은 10보다 크다.
// result2 : true</code></pre>
<h2 id="cforeach-태그">&lt;c:forEach&gt; 태그</h2>
<blockquote>
<p><strong>반복 작업</strong>에 <strong>사용</strong>한다. 특히 목록에서 <strong>값을 꺼내서 처리할 때 사용</strong>한다.</p>
</blockquote>
<pre><code class="language-java">&lt;c:forEach var=&quot;변수명&quot; items=&quot;목록 데이터&quot; begin=&quot;시작 인덱스&quot; end=&quot;종료 인덱스&quot;&gt;콘텐츠&lt;/c:forEach&gt;</code></pre>
<blockquote>
<p>items에는 다음을 지정할 수 있다.</p>
</blockquote>
<ul>
<li>배열</li>
<li>java.util.Collection 구현체(ArrayList, LinkedList, EnumSet, ...)</li>
<li>java.util.Iterator 구현체</li>
<li>java.util.Enumeration 구현체</li>
<li>java.util.Map 구현체</li>
<li>콤마(,) 구분자로 나열된 문자열<br></li>
<li><em>사용 예시*</em><pre><code class="language-java">&lt;%
   List&lt;String&gt; fruits = new ArrayList&lt;&gt;();
   fruits.add(&quot;apple&quot;);
   fruits.add(&quot;banana&quot;);
   fruits.add(&quot;pineapple&quot;);
   fruits.add(&quot;kiwi&quot;);
   fruits.add(&quot;melon&quot;);
   pageContext.setAttribute(&quot;fruits&quot;, fruits);
%&gt;
&lt;ul&gt;
   &lt;c:forEach var=&quot;fruit&quot; items=&quot;${fruits}&quot;&gt;
       &lt;li&gt;${fruit}&lt;/li&gt;
   &lt;/c:forEach&gt;
&lt;/ul&gt;</code></pre>
</li>
</ul>
<hr>
<p>apple
banana
pineapple
kiwi
melon</p>
<pre><code>
## 복합 조건문 태그 (if-else)
&gt;** &lt;c:choose&gt;, &lt;c:when&gt;, &lt;c:otherwise&gt; **세 가지를 사용한다.
```java
&lt;c:choose&gt;
&lt;c:when test=&quot;${data == &#39;A&#39;}&quot;&gt;data 값이 A이면 실행&lt;/c:when&gt;
&lt;c:when test=&quot;${data == &#39;B&#39;}&quot;&gt;data 값이 B이면 실행&lt;/c:when&gt;
&lt;c:when test=&quot;${data == &#39;C&#39;}&quot;&gt;data 값이 C이면 실행&lt;/c:when&gt;
&lt;c:otherwise&gt;data 값이 A, B, C값이 아닐 경우 실행&lt;/c:otherwise&gt;
&lt;/c:choose&gt;</code></pre><p><code>if-else</code> 문 처럼 사용 가능하며, <code>when</code> 이 <code>true</code> 이면 해당 블럭이 실행된다. 모든 <code>when</code> 이 <code>false</code> 이면 <code>otherwise</code> 블럭이 실행된다.</p>
<hr>
<h2 id="el">EL</h2>
<blockquote>
<p><strong>EL</strong>의 정식 명칭은 <strong>표현 언어(Expression Language)</strong>라고 하며 줄여서 EL이라고 부른다.</p>
</blockquote>
<blockquote>
<p><strong>사용법</strong></p>
</blockquote>
<pre><code class="language-java">&lt;%= name %&gt;
${name}</code></pre>
<p><strong>EL의 내장 객체</strong>
<img src="https://velog.velcdn.com/images/hyeon_geun/post/279b1abe-ae96-419e-b2f5-e6282c4b3723/image.png" alt="">
<strong>EL의 연산자 종류 및 표현법</strong>
<img src="https://velog.velcdn.com/images/hyeon_geun/post/84832525-55d7-4dc5-929c-b5023bad5a9a/image.png" alt="">
<strong>사용 예제 1</strong></p>
<pre><code class="language-java">&lt;% @taglib uri=&quot;http://java.sun.com/jstl/core&quot; prefix=&quot;c&quot; %&gt;
&lt;html&gt;
 &lt;body&gt;
  &lt;c:forEach var=&quot;i&quot; begin=&quot;1&quot; end=&quot;10&quot; step=&quot;1&quot;&gt;
   &lt;c:out value=&quot;${i}&quot;/&gt;
   &lt;br/&gt;
  &lt;/c:forEach&gt;
&gt;
  ${person.address.city}
&gt;
 &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p><strong>사용 예제 2 (전체 코드)</strong></p>
<pre><code class="language-java">&lt;%@ page contentType=&quot;text/html;charset=UTF-8&quot; language=&quot;java&quot; %&gt;
&lt;%
    String myName=&quot;김구라&quot;;
   /*
      page scope 에  &quot;myName&quot; 이라는 키값으로 myName 담기
      해당 jsp 페이지 에서만 사용할 수 있다.
   */
    pageContext.setAttribute(&quot;myName&quot;, myName);     //page scope
&gt;
    String yourName=&quot;해골&quot;;
   /*
      request scope 에 &quot;yourName&quot; 이라는 키값으로 yourName 담기
      request scope 에 담은 값은 응답하기 전까지 사용할 수 있다.
      (다른 페이지로 forward 이동해도 사용할 수 있다)
      (다른 페이지로 redirect 이동하면 사용할 수 없다)
   */
    request.setAttribute(&quot;yourName&quot;, yourName);     //request scope
&gt;
    String ourName=&quot;원숭이&quot;;
   /*
      session scope 에  &quot;ourName&quot; 이라는 키값으로 ourName 담기
      session scope 에 담은 값은 세션이 유지 되는 동안 사용할 수 있다.
      (다른 페이지로 forward, redirect 이동 해도 사용할 수 있다)
      (웹브라우저를 닫거나 세션을 초기화 하기 전까지 사용할 수 있다)
   */
    session.setAttribute(&quot;ourName&quot;, ourName);       //session scope
&gt;
    String companyName=&quot;에이콘&quot;;
   /*
      application scope 에 &quot;companyName&quot; 이라는 키값으로 companyName 담기
      application scope 에 담은 내용은 서버를 끄기 전까지 사용할 수 있다.
      (웹브라우저를 닫아도 지워지지 않는다)
   */
    application.setAttribute(&quot;companyName&quot;, companyName);       //application scope
&gt;
%&gt;
    -------------------------------------------------------------------------------
        &lt;h1&gt; EL 로 page scope 에 저장된 값 추출&lt;/h1&gt;
        &lt;p&gt;내 이름은 &lt;strong&gt;${pageScope.myName}&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;내 이름은 &lt;strong&gt;${myName}&lt;/strong&gt;&lt;/p&gt;
&gt;
        &lt;h1&gt; EL 로 request scope 에 저장된 값 추출&lt;/h1&gt;
        &lt;p&gt;너의 이름은 &lt;strong&gt;${requestScope.yourName}&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;너의 이름은 &lt;strong&gt;${yourName}&lt;/strong&gt;&lt;/p&gt;
        &lt;%-- 위의 EL 은 아래의 코드를 대신할 수 있다. --%&gt;
        &lt;%
            String result = (String)request.getAttribute(&quot;yourName&quot;);
        %&gt;
        &lt;p&gt;너의 이름은 &lt;strong&gt;&lt;%=result%&gt;&lt;/strong&gt;&lt;/p&gt;
&gt;
        &lt;h1&gt; EL 로 session scope 에 저장된 값 추출&lt;/h1&gt;
        &lt;p&gt;우리 이름은 &lt;strong&gt;${sessionScope.ourName}&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;우리 이름은 &lt;strong&gt;${ourName}&lt;/strong&gt;&lt;/p&gt;
        &lt;%-- 위의 EL 은 아래의 코드를 대신할 수 있다. --%&gt;
        &lt;%
            String result2 = (String)request.getAttribute(&quot;ourName&quot;);
        %&gt;
        &lt;p&gt;우리 이름은 &lt;strong&gt;&lt;%=result2%&gt;&lt;/strong&gt;&lt;/p&gt;
&gt;
        &lt;h1&gt; EL 로 application scope 에 저장된 값 추출&lt;/h1&gt;
        &lt;p&gt;학원 이름은 &lt;strong&gt;${applicationScope.companyName}&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;학원 이름은 &lt;strong&gt;${companyName}&lt;/strong&gt;&lt;/p&gt;</code></pre>
<p><strong>사용 예제 3</strong></p>
<pre><code class="language-java">&lt;%
    //CafeDto 객체를 생성해서 글 하나의 정보를 담고
    CafeDto dto = new CafeDto();
    dto.setNum(1);
    dto.setWriter(&quot;김구라&quot;);
    dto.setTitle(&quot;나는 구라다&quot;);
&gt;
    //&quot;dto&quot; 라는 키값으로 request scope 에 담기
    request.setAttribute(&quot;dto&quot;, dto);
%&gt;
-------------------------------------------------
    &lt;%
        CafeDto result = (CafeDto)request.getAttribute(&quot;dto&quot;);
    %&gt;
        &lt;p&gt;글번호 : &lt;strong&gt;&lt;%=result.getNum()%&gt;&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;작성자 : &lt;strong&gt;&lt;%=result.getWriter()%&gt;&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;제목 : &lt;strong&gt;&lt;%=result.getTitle()%&gt;&lt;/strong&gt;&lt;/p&gt;
&gt;
        &lt;h3&gt;EL 을 이용해서 위의 작업하기&lt;/h3&gt;
        &lt;p&gt;글번호 : &lt;strong&gt;${requestScope.dto.getNum()}&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;작성자 : &lt;strong&gt;${dto.getWriter()}&lt;/strong&gt;&lt;/p&gt;
        &lt;%-- 필드명만 적으면 자동으로 getter 메소드를 호출해준다. --%&gt;
        &lt;p&gt;제목 : &lt;strong&gt;${dto.title}&lt;/strong&gt;&lt;/p&gt;</code></pre>
<p><strong>사용 예제 4</strong></p>
<pre><code class="language-java">&lt;h1&gt;요청 파라미터도 el 로 추출할수 있다.&lt;/h1&gt;           --- test04.jsp
    &lt;form action=&quot;test05.jsp&quot; method=&quot;post&quot;&gt;
      &lt;input type=&quot;text&quot; name=&quot;msg&quot;/&gt;
      &lt;button type=&quot;submit&quot;&gt;전송&lt;/button&gt;
    &lt;/form&gt;
    &lt;br&gt;
    &lt;a href=&quot;test05.jsp?msg=hello&quot;&gt;test05.jsp&lt;/a&gt;
--------------------------------------------------
&lt;h1&gt;param.파라미터명 형식으로 추출할 수 있다&lt;/h1&gt;        --- test05.jsp
&lt;p&gt;전달된 파라미터 : &lt;strong&gt;${param.msg}&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;전달된 파라미터 : &lt;strong&gt;&lt;%=request.getParameter(&quot;msg&quot;)%&gt;&lt;/strong&gt;&lt;/p&gt;</code></pre>
<p><img src="https://velog.velcdn.com/images/hyeon_geun/post/d2d8119c-88d3-4df8-870a-09a6f88a4b53/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] @Annotation ]]></title>
            <link>https://velog.io/@hyeon_geun/Java</link>
            <guid>https://velog.io/@hyeon_geun/Java</guid>
            <pubDate>Thu, 08 Jun 2023 11:10:15 GMT</pubDate>
            <description><![CDATA[<h2 id="-자바-어노테이션java-annotation">@ 자바 어노테이션(Java Annotation)</h2>
<blockquote>
<p><strong>에노테이션(@)</strong>은 <strong>주석</strong>이라는 의미를 가진다.
자바 소스 코드에 사이에 @ 기호를 앞에 붙여서 사용하는데,  JDK 1.5 버전 이상에서 사용 가능하다.</p>
</blockquote>
<h3 id="🔎-어노테이션의-용도">🔎 어노테이션의 용도</h3>
<blockquote>
<ul>
<li>컴파일러에게 코드 작성 <strong>문법 에러를 체크</strong>하도록 정보를 제공</li>
</ul>
</blockquote>
<ul>
<li>소프트웨어 개발툴이 <strong>빌드나 배치시 코드를 자동으로 생성</strong>할 수 있도록 정보 제공</li>
<li><strong>실행시(런타임시)특정 기능을 실행</strong>하도록 정보를 제공</li>
</ul>
<h3 id="📌-어노테이션-종류">📌 어노테이션 종류</h3>
<blockquote>
<p><strong>자바 코드에 적용되는 대표적인 내장 어노테이션</strong></p>
</blockquote>
<ul>
<li><strong>@Override</strong>
선언한 메서드가 오버라이드 되었다는 것을 나타낸다.
만약 상위(부모) 클래스(또는 인터페이스)에서 해당 메서드를 찾을 수 없다면 컴파일 에러를 발생 시킨다.<pre><code class="language-java">class Parent{
 void parentMethod(){}
}
class Child extends Parent{
 void parentmethod(){} // 오버라이딩하려 했으나 실수로 이름을 잘못적음
 // 새로운 메서드가 만들어진 것
}</code></pre>
</li>
</ul>
<hr>
<p>class Child extends Parent{
//메소드 선언부 앞에 오버라이딩을 하면 위의 문제를 방지할 수 있다.
   @Override
   void parentMethod(){ }
}</p>
<pre><code>- **@SuppressWarnings**
선언한 곳의 컴파일 경고를 무시하도록 한다.
```java
// unchecked 경고를 억제
@SuppressWarnings(&quot;unchecked&quot;) 
ArrayList list = new ArrayList(); // 지네릭 클래스는 원시타입 쓸 수 없지만, 지정해주지 않음
list.add(obj); // 여기서 경고 발생</code></pre><ul>
<li><strong>@FunctionalInterface</strong>
함수형 인터페이스를 지정하는 어노테이션이다.
만약 메서드가 존재하지 않거나, 1개 이상의 메서드(default 메서드 제외)가 존재할 경우 컴파일 오류를 발생 시킨다.<pre><code class="language-java">@FunctionalInterface
public interface Runnable{
 public abstract void run(); // 추상메서드
}</code></pre>
</li>
</ul>
<h3 id="🔔-어노테이션-생성하기">🔔 어노테이션 생성하기</h3>
<blockquote>
<p><strong>어노테이션 생성</strong></p>
</blockquote>
<pre><code class="language-java">@interface 이름{
    타입 요소 이름(); // 어노테이션의 요소를 선언
        ...
}</code></pre>
<p><strong>사용 예시</strong></p>
<pre><code class="language-java">@interface DateTime{
    String yymmdd();
    String hhmmss();
}
&gt;
@interface TestInfo{
    int count() default 1;
    String testedBy();
    TestType testType();
    DateTime testDate();
}
&gt;
@TestInfo{
    testedBy=&quot;Hwang&quot;,
    testTools={&quot;JUnit&quot;, &quot;AutoTester&quot;},
    testType=TestType.FIRST,
    testDate=@DateTime(yymmdd=&quot;230613&quot;, hhmmss=&quot;165418&quot;)
)// count를 생략했으므로 default인 &quot;count=1&quot;이 적용된다.
public class NewClass{...}</code></pre>
<h4 id="어노테이션-요소-특징">어노테이션 요소 특징</h4>
<blockquote>
<ul>
<li>적용시 값을 지정하지 않으면, 사용될 수 있는 기본값을 지정할 수 있다.(위의 default)</li>
</ul>
</blockquote>
<ul>
<li>요소가 하나이고 이름이 value일 때는 요소의 이름 생략 가능하다.</li>
<li>요소의 타입이 배열인 경우, 괄호{ }를 사용해야 한다.
<a href="https://velog.io/@jkijki12/annotation">https://velog.io/@jkijki12/annotation</a></li>
</ul>
<h3 id="🔑-어노테이션-규칙">🔑 어노테이션 규칙</h3>
<p>어노테이션에도 반드시 지켜주어야 하는 4가지 규칙이 있다.</p>
<blockquote>
<ul>
<li>요소의 타입은 기본형, String, enum, 어노테이션, Class만 허용된다.</li>
</ul>
</blockquote>
<ul>
<li>괄호()안에 매개변수를 선언할 수 없다.</li>
<li>예외를 선언할 수 없다.</li>
<li>요소의 타입을 매개변수로 정의할 수 없다.(&lt; T &gt;)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Java Web #2]]></title>
            <link>https://velog.io/@hyeon_geun/Java-Web-2</link>
            <guid>https://velog.io/@hyeon_geun/Java-Web-2</guid>
            <pubDate>Thu, 08 Jun 2023 10:19:36 GMT</pubDate>
            <description><![CDATA[<h2 id="session">Session</h2>
<blockquote>
</blockquote>
<p>웹 서버 쪽의 <strong>웹 컨테이너에 상태를 유지하기 위한 정보를 저장</strong>한다.
그리고 정보를 유지를 위해 <code>javax.servlet.http</code>의 <code>HttpSession</code> 인터페이스를 구현해서 사용한다. 
<img src="https://velog.velcdn.com/images/hyeon_geun/post/80154e88-97db-47e2-9507-fe99e33df620/image.png" alt=""></p>
<p>** 🔔 세션의 주요 메소드**
<img src="https://velog.velcdn.com/images/hyeon_geun/post/38ca8fe8-5ebc-440b-8cc0-665ee114a1b4/image.png" alt=""></p>
<blockquote>
<p><strong>세션값 설정</strong></p>
</blockquote>
<pre><code class="language-java">session.setAttribute(&quot;설정한 세션아이디&quot;, 세션에 넣을 값);
session.setAttribute(&quot;id&quot;, id)</code></pre>
<p><strong>예 시</strong></p>
<pre><code class="language-java">&lt;% -----login.jsp
&gt;
  //1. 폼 전송되는 id, pwd 를 읽어와서
    String id = request.getParameter(&quot;id&quot;);
    String pwd = request.getParameter(&quot;pwd&quot;);
  //2. UsersDto 에 담기
    UsersDto dto = new UsersDto();
    dto.setId(id);
    dto.setPwd(pwd);
  //3. UsersDao 에 전달해서 유효한 정보인지 확인해서
    boolean isValid = UsersDao.getInstance().isValid(dto);
  /*
    4. 유효한 정보이면 로그인 처리를 하고 응답한다.
       유효한 정보가 아니면 아이디 혹은 비밀번호가 틀려요 라고 응답한다.
&gt;
       [ 로그인 처리 ]
       session scope 에 &quot;id&quot; 라는 키값으로 로그인된 아이디를 저장하면 된다.
       여기서 session scope 란 HttpSession 객체의 setAttribute() 메소드를 이용해서
       값을 저장하는 영역을 말한다.
   */
    if(isValid){
        //session scope 에 id 라는 키값으로 로그인된 아이디 담기
        session.setAttribute(&quot;id&quot;, id);
    }
&gt;
    //로그인 후 가야할 목적지 정보
    String url = request.getParameter(&quot;url&quot;);
    //로그인 실패를 대비해서 목적지 정보를 인코딩한 결과도 준비한다.
    String encodedUrl = URLEncoder.encode(url);
%&gt;</code></pre>
<hr>
<p><strong>세션에 저장된 값 가져오기</strong></p>
<pre><code class="language-java">session.getAttribute(&quot;id&quot;);</code></pre>
<p><strong>예 시</strong></p>
<pre><code class="language-java">&lt;% -----signup.jsp
  //아이디
  String id = request.getParameter(&quot;id&quot;);
  //비밀번호
  String pwd = request.getParameter(&quot;pwd&quot;);
  //직업
  String job = request.getParameter(&quot;job&quot;);
  //성별
  String gender = request.getParameter(&quot;gender&quot;);
  //취미
  String[] hobby = request.getParameterValues(&quot;hobby&quot;);
  String hobbyResult = &quot;&quot;;
  if (hobby != null){
    //반복문 돌면서
    for (int i = 0; i &lt; hobby.length; i++){
      //i번째 방에 있는 선택된 취미를 불러온다.
      String tmp = hobby[i];
      hobbyResult += tmp;
      if (i != hobby.length-1) hobbyResult += &quot;/&quot;;
    }
  }
  //문자열에서 특정문자(&quot;/&quot;)로 구분해서 String[] 을 얻어내기
  String [] result = hobbyResult.split(&quot;/&quot;);
&gt;
  //문자열에 특정 문자가 포함되어 있는지 여부
  boolean isContain = hobbyResult.contains(&quot;xxx&quot;);
&gt;
  // null 이면 체크를 안한 것이고 null 이 아니면 체크를 한 것이다.
  String allEmail = request.getParameter(&quot;allowEmail&quot;);
  String allMessage = request.getParameter(&quot;allowMessage&quot;);
  /*
     textarea 에 입력한 문자열은 개행, tab, 공백기호가 모두 포함되어 있다.
     해당 문자열을 DB 에 저장했다가 다시 불러와서 textarea 에 출력하고 싶으면
     textarea 의 innerText 에 출력하면 된다.
   */
  String comment = request.getParameter(&quot;comment&quot;);
%&gt;</code></pre>
<hr>
<p><strong>세션 값 삭제하기</strong></p>
<pre><code class="language-java">removeAttribute(String name);
//invalidate로 모든 세션을 한 번에 삭제할 수 있다.
invalidate();</code></pre>
<p><strong>예 시</strong></p>
<pre><code class="language-java">  &lt;%
    //session scope 에 id 라는 키값으로 저장된 값 삭제하기
    session.removeAttribute(&quot;id&quot;);
  %&gt;
  &lt;script&gt;
    alert(&quot;로그아웃 되었습니다.&quot;)
    //javascript 를 이용해서 페이지 이동
    location.href=&quot;../&quot;
  &lt;/script&gt;</code></pre>
<hr>
<h2 id="cookie">Cookie</h2>
<blockquote>
<p><strong>Cookie</strong>는 쉽게 말해서 <u>프로그램에서 <strong>흔적</strong>을 남기는 것</u>이다. 클라이언트와 서버가 연결을 시도한 흔적을 남겼다가, 후에 또 연결을 시도할 시 과거의 접속을 이어나가기 위해 흔적을 사용하는 방법이다.(서버가 아닌 클라이언트 쪽에 저장)
<strong>보안에 취약</strong>하므로, <strong>중요한 정보는 저장하지 않는다.</strong></p>
<ul>
<li>클라이언트의 웹브라우저에 특정 <code>key</code> 값으로 문자열을 저장할 수 있다.</li>
</ul>
</blockquote>
<ul>
<li>저장할 수 있는 문자열은 <code>Base64</code> 인코딩 형식의 <code>64가지 문자열</code>을 저장할 수 있다.
(Tomcat 8.5 는 자동으로 처리 되어서 인코딩이 필요 없다)<br>
></li>
<li><em>쿠키 생성*</em><pre><code class="language-java">//쿠키 객체 생성 new Cookie(&quot;key&quot;, value);
Cookie cook=new Cookie(&quot;savedMsg&quot;, msg);</code></pre>
<br>
></li>
<li><em>쿠키 확인하기*</em>
크롬에서 쿠키 확인하는 방법은 <code>개발자도구(F12) - Application Tap - Cookies</code> 에서 확인
<img src="https://velog.velcdn.com/images/hyeon_geun/post/547c8990-20fe-45ce-a0c8-075b95ce4a43/image.png" alt=""></li>
<li><em>사용 예시*</em><pre><code class="language-java">&lt;form action=&quot;cookie_save.jsp&quot; method=&quot;post&quot;&gt;                --- cookie_form.jsp
   &lt;label for=&quot;msg&quot;&gt;웹브라우저(client side)에 저장할 문자열 &lt;/label&gt;
   &lt;input type=&quot;text&quot; name=&quot;msg&quot; id=&quot;msg&quot;/&gt;
   &lt;button type=&quot;submit&quot;&gt;저장&lt;/button&gt;
&lt;/form&gt;</code></pre>
</li>
</ul>
<hr>
<p>&lt;%                                                            --- cookie_save.jsp
    //폼전송되는 문자열 읽어오기
    String msg=request.getParameter(&quot;msg&quot;);
    //모든 문자열을 다 저장하려면 tomcat 8 이하 버전에서는 인코딩을 해서 저장을 한다.
    String encodedMsg=URLEncoder.encode(msg, &quot;utf-8&quot;);
    //1. 쿠키 객체 생성 new Cookie(&quot;key&quot;, value);
    Cookie cook=new Cookie(&quot;savedMsg&quot;, encodedMsg);
    //2. 쿠키 유지시간 (초단위)
    cook.setMaxAge(60); //60초 테스트
    //3. HttpServletResponse  객체에 담는다.
    response.addCookie(cook);
    //4. 응답할때 쿠키가 자동으로 응답되고 클라이언트의 웹브라우저에 저장이 된다. 
%&gt;</p>
<body>
<p>웹 브라우저에 savedMsg 라는 키값으로 "<%=msg %>" 를 저장했습니다.</p>
<a href="cookie_read.jsp">저장된 문자열 확인 해보기</a>
</body>
----------------------------------------------------------------------
<%
    //HttpServletRequest 객체를 이용해서 요청과 함께 전달된 쿠키 읽어내기
    Cookie[] cooks=request.getCookies();                    --- cookie_read.jsp
    //"savedMsg" 라는 키값으로 저장된 문자열을 저장할 변수
    String savedMsg=null;
    if(cooks!=null){
        //반복문 돌면서 쿠키 객체를 하나씩 참조
        for(Cookie tmp:cooks){
            //쿠키의 키값을 읽어온다.
            String key=tmp.getName();
            if(key.equals("savedMsg")){//만일 우리가 찾는 키값이라면 
                //해당 키값으로 저장된 value 를 읽어내서 디코딩을 한다. 
                savedMsg=URLDecoder.decode(tmp.getValue(),"utf-8");
            }
        }
    }
%>
<body>
<p> savedMsg  라는 키값으로 저장된 문자열 : <%=savedMsg %></p>
<a href="cookie_form.jsp">다시 테스트</a>
</body>
```]]></description>
        </item>
        <item>
            <title><![CDATA[Javascript #6]]></title>
            <link>https://velog.io/@hyeon_geun/Javascript-6</link>
            <guid>https://velog.io/@hyeon_geun/Javascript-6</guid>
            <pubDate>Tue, 06 Jun 2023 07:04:51 GMT</pubDate>
            <description><![CDATA[<h2 id="동기--비동기">동기 &amp; 비동기</h2>
<blockquote>
<h3 id="동기">동기</h3>
</blockquote>
<ul>
<li><strong>동기(Synchronouse)</strong>는 코드가 <u>순차적으로 실행</u>된다는 의미다. 현재 작업이 끝나야만 다음 코드를 실행한다.</li>
<li>코드를 하나씩 실행하기 때문에, 코드에 대한 실행 순서가 보장된다.</li>
<li>다만, 작업이 끝나기 이전에는 다음 작업이 멈춰있는데, 이를 <strong>블로킹(Blocking)</strong>이라고 한다.</li>
</ul>
<blockquote>
<h3 id="비동기">비동기</h3>
</blockquote>
<ul>
<li><strong>비동기</strong>는 <u>실행 중인 코드가 완료되지 않더라도, 다음 코드로 넘어간다</u>.</li>
<li>비동기(보통, 시간이 걸리는)작업은 브라우저에 맡기고, 다음 코드로 넘어간다.</li>
<li>실행 순서가 보장되지 않지만, 블로킹을 막을 수 있다.</li>
<li>비동기란 현재 실행중인 작업을 멈추지 않고 다른 작업을 <strong>병렬적</strong>으로 수행하는 것을 의미한다. 그래서 <u>여러 작업(task)이 있을 때 비동기적으로 수행하면 작업들을 동시에 한번에 수행할 수 있어 최종 작업 수행이 빠르게 처리되게 된다.</u></li>
<li>이러한 비동기 방식으로 작업을 처리하는 방법 중 하나가 바로 <span color: red><strong>콜백(callback) 함수</strong></span>이다.<blockquote>
</blockquote>
<img src="https://velog.velcdn.com/images/hyeon_geun/post/69600e35-8ab9-43a1-ace2-b63eacbd6fa7/image.png" alt=""></li>
</ul>
<blockquote>
</blockquote>
<p><strong>자바스크립트</strong>는 한 번에 한 가지 일만 처리하는 <strong>싱글 쓰레드</strong>다.
하지만, 사진을 불러오는 중에도 사용자의 입력을 처리하는 등 
여러 작업을 하는 것 처럼 보이기 때문에 <strong>비동기 처리가 필요</strong>하다.</p>
<h2 id="콜백-함수">콜백 함수</h2>
<blockquote>
<p><strong>콜백(Callback) 함수</strong>는 간단히 말하면 <strong>매개변수로 함수 객체를 전달</strong>해서 호출 <strong>함수 내에서 매개변수 함수를 실행하는 것</strong>을 말한다. 예를 들어 아래 코드와 같이 <code>sayHello()</code> 함수를 호출할 때 입력 매개변수로 문자열과 <code>printing</code> 함수 자체를 전달하는 것을 볼 수 있다. 그리고 <code>sayHello()</code> 함수가 실행되면 실행문 안에서 함수가 들은 두번째 매개변수인 <code>callback</code> 을 괄호 <code>()</code> 를 붙여 호출한다.</p>
</blockquote>
<pre><code class="language-javascript">function sayHello(name, callback) {
    const words = &#39;안녕하세요 내 이름은 &#39; + name + &#39; 입니다.&#39;;
&gt;    
    callback(words); // 매개변수의 함수(콜백 함수) 호출
}
&gt;
sayHello(&quot;현근&quot;, function printing(name) {
    console.log(name); // 안녕하세요 내 이름은 현근 입니다.
});</code></pre>
<blockquote>
<p>콜백 함수란 파라미터로 일반적인 변수나 값을 전달하는 것이 아닌 <u><strong>함수 자체를 전달</strong>하는 것</u>을 말한다고 보면 된다. 또한 어차피 매개변수에 함수를 전달해 일회용으로 사용하기 때문에 굳이 함수의 이름을 명시할 필요가 없어 보통 콜백 함수 형태로 함수를 넘겨줄때 함수의 이름이 없는 &#39;익명 함수&#39; 형태로 넣어주게 된다.<br>
** Callback 함수를 이용해서 Ajax 결과값 출력**</p>
</blockquote>
<pre><code class="language-javascript">// fetch 메서드를 사용하여 서버로부터 JSON 데이터를 받아오고 콜백 함수로 화면에 출력
fetch(&quot;https://jsonplaceholder.typicode.com/users&quot;)
  .then(function (response) {
    // fetch 메서드가 성공하면 콜백 함수로 response 인자를 받음
    return response.json(); // response 객체의 json 메서드를 호출하여 JSON 데이터를 반환
  })
  .then(function (data) {
    // json 메서드가 성공하면 콜백 함수로 data 인자를 받음
    console.log(data);
  })</code></pre>
<h3 id="콜백-지옥-callback-hell">콜백 지옥 (Callback Hell)</h3>
<blockquote>
<p><strong>콜백 지옥</strong>이란 함수의 매개변수로 넘겨지는 <strong>콜백 함수가 반복</strong>되어 <u><strong>코드의 들여쓰기 수준이 감당하기 힘들어질 정도로 깊어지는 현상</strong></u>이다.
<img src="https://velog.velcdn.com/images/hyeon_geun/post/36792394-a440-4a99-af53-fc2f1d30c240/image.png" alt=""></p>
</blockquote>
<h3 id="promise">Promise</h3>
<blockquote>
<p><strong>프로미스</strong>는 주로 <strong>서버에서 받아온 데이터를 화면에 표시할 때 사용</strong>한다. 일반적으로 웹 애플리케이션을 구현할 때 <u>서버에서 데이터를 요청하고 받아오기 위해</u> 아래와 같은 API를 사용한다.</p>
</blockquote>
<pre><code class="language-javascript">$.get(&#39;url 주소/products/1&#39;, function(response) {
  // ...
});</code></pre>
<blockquote>
<h4 id="프로미스의-3가지-상태states">프로미스의 3가지 상태(states)</h4>
<p>프로미스를 사용할 때 알아야 하는 가장 기본적인 개념이 바로 프로미스의 상태(states)다. 여기서 말하는 상태란 프로미스의 처리 과정을 의미한다. <code>new Promise()</code>로 프로미스를 생성하고 종료될 때까지 3가지 상태를 갖는다.</p>
<ul>
<li>Pending(대기) : 비동기 처리 로직이 아직 완료되지 않은 상태</li>
<li>Fulfilled(이행) : 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태</li>
<li>Rejected(실패) : 비동기 처리가 실패하거나 오류가 발생한 상태
<img src="https://velog.velcdn.com/images/hyeon_geun/post/0ca6ddd3-7d8e-46a7-99ca-d5ca776361ce/image.png" alt=""></li>
<li><em>사용 예시*</em></li>
</ul>
</blockquote>
<pre><code class="language-javascript">unction getData() {
  return new Promise({
    // ...
  });
}
&gt;
// then() 으로 여러 개의 프로미스를 연결한 형식
getData()
  .then(function(data) {
    // ...
  })
  .then(function() {
    // ...
  })
  .then(function() {
    // ...
  });</code></pre>
<p>** 순서 **
<img src="https://velog.velcdn.com/images/hyeon_geun/post/281b2308-4be3-4cc1-96a0-903d8c6fb415/image.png" alt=""></p>
<h4 id="프로미스의-에러-처리-방법">프로미스의 에러 처리 방법</h4>
<blockquote>
<p>에러 처리 방법에는 다음과 같이 2가지 방법이 있다.</p>
<ol>
<li><code>then()</code>의 두 번째 인자로 에러를 처리하는 방법</li>
</ol>
</blockquote>
<pre><code class="language-js">getData().then(
  handleSuccess,
  handleError
);</code></pre>
<blockquote>
<ol start="2">
<li><code>catch()</code>를 이용하는 방법</li>
</ol>
</blockquote>
<pre><code class="language-js">getData().then().catch();</code></pre>
<blockquote>
<p>💡 가급적이면 <code>catch()</code>를 사용하자 !</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Javascript #5]]></title>
            <link>https://velog.io/@hyeon_geun/Javascript-5</link>
            <guid>https://velog.io/@hyeon_geun/Javascript-5</guid>
            <pubDate>Thu, 01 Jun 2023 14:04:50 GMT</pubDate>
            <description><![CDATA[<h2 id="scope">Scope</h2>
<blockquote>
<p><strong>자바스크립트</strong>에서 <strong>Scope</strong>란 <u><strong>변수에 접근할 수 있는 범위</strong></u>라고 할 수 있다. </p>
<ul>
<li><strong>전역 스코프(Global Scope)</strong><ul>
<li><strong>전역에 선언</strong>되어있어 <u>어느 곳에서든지 해당 변수에 접근할 수 있다</u>는 의미 <br></li>
</ul>
</li>
<li><strong>지역 스코프(Local Scope)</strong><ul>
<li><strong>해당 지역에서만 접근</strong>할 수 있어 <u>지역을 벗어난 곳에선 접근할 수 없다</u>는 의미<br></li>
</ul>
</li>
<li><ul>
<li>예시**</li>
</ul>
</li>
</ul>
</blockquote>
<pre><code class="language-javascript">var a = 1; // 전역 스코프
function print() { // 지역(함수) 스코프
 var a = 111;
 console.log(a);
}
print(); // 111
console.log(a); // 1</code></pre>
<hr>
<h2 id="settimeout--setinterval">SetTimeout() &amp; SetInterval()</h2>
<blockquote>
<h3 id="settimeout"><strong>setTimeout()</strong></h3>
</blockquote>
<ul>
<li>어떤 코드를 바로 실행하지 않고 <strong>일정 시간 기다린 후 실행</strong>해야하는 경우 <code>setTimeout()</code> 함수를 사용한다.<pre><code class="language-javascript">setTimeout(() =&gt; console.log(&quot;2초 후에 실행됨&quot;), 2000);</code></pre>
<blockquote>
<ul>
<li><code>setTimeout()</code> 함수는 <strong>타임아웃 아이디(Timeout ID)라고 불리는 숫자를 반환</strong>하는데, 타임아웃 아이디는 <code>setTimeout()</code> 함수를 호출할 때 마다 내부적으로 생성되는 <u>타이머 객체</u>를 가리키고 있다. 이 값을 인자로 <code>clearTimeout()</code> 함수를 호출하면 기다렸다가 실행될 코드를 취소할 수 있다.</li>
</ul>
</blockquote>
<pre><code class="language-javascript">const timeoutId = setTimeout(() =&gt; console.log(&quot;5초 후에 실행됨&quot;), 5000);
clearTimeout(timeoutId);</code></pre>
</li>
</ul>
<blockquote>
<h3 id="setinterval"><strong>setInterval()</strong></h3>
</blockquote>
<ul>
<li><p>웹페이지의 특정 부분을 <strong>주기적으로 업데이트</strong>해줘야 하거나, 어떤 API로 부터 <strong>변경된 데이터를 주기적으로 받아와야 하는 경우</strong>에 자바스크립트의 <code>setInterval()</code> 함수를 사용할 수 있다.</p>
</li>
<li><p><code>setInterval()</code> 함수는 <u>어떤 코드를 일정한 시간 간격을 두고 반복해서 실행하고 싶을 때 사용</u>한다.
```javascript
setInterval(() =&gt; console.log(new Date()), 2000);</p>
<blockquote>
</blockquote>
</li>
<li><p>-------console----------</p>
<blockquote>
</blockquote>
<p>Sun May 26 2023 12:29:06 GMT-0500 (Eastern Standard Time)
Sun May 26 2023 12:29:08 GMT-0500 (Eastern Standard Time)
Sun May 26 2023 12:29:10 GMT-0500 (Eastern Standard Time)
Sun May 26 2023 12:29:12 GMT-0500 (Eastern Standard Time)
Sun May 26 2023 12:29:14 GMT-0500 (Eastern Standard Time)
Sun May 26 2023 12:29:16 GMT-0500 (Eastern Standard Time)
Sun May 26 2023 12:29:18 GMT-0500 (Eastern Standard Time)</p>
<blockquote>
</blockquote>
</li>
<li><p>-- 0과 9 사이의 수를 무작위로 생성하여 2초마다 출력 ---
setInterval(() =&gt; console.log(Math.floor(Math.random() * 10)), 2000);</p>
</li>
<li><p>-------console----------
3
2
8
3
1</p>
<pre><code>#### ❗ &lt;주의&gt;
`setTimeout()` 함수와 `setInterval()` 함수를 사용한 후에는 반드시 `clearTimeout()` 함수와 `clearInterval()` 함수를 사용해서 타이머를 청소해야 한다.
👉 메모리 누수(memory leak)로 이어질 수 있기 때문에 !

## Canvas
&gt; **canvas** 는 페이지에 그래픽적인 요소를 그릴 때 사용되는 html5 의 새로운 태그이다.
```javascript
&lt;!-- canvas 요소는 width와 height를 속성으로 직접 지정할 수 있다. --&gt;
&lt;canvas id=&quot;myCanvas&quot; width=&quot;800&quot; height=&quot;500&quot;&gt;&lt;/canvas&gt;
&lt;script&gt;
   //canvas 요소의 참조값
   const canvas = document.querySelector(&quot;#myCanvas&quot;);
   //canvas에 그림을 그릴 도구(context) 객체 얻어내기
   const context = canvas.getContext(&quot;2d&quot;);
&lt;/script&gt;</code></pre><blockquote>
<ul>
<li>캔버스에 어떤 요소를 그리기 위해서 가장 처음으로 <code>getContext()</code>를 사용하여 위치를 정의할 필요가 있다. 기본적으로 <strong>2d로 정의</strong>되며, 위 요소를 사용하면 <strong>canvas에 2d 좌표로 위치를 지정</strong>할 수 있게 된다.</li>
</ul>
</blockquote>
<ul>
<li><code>beginPath()</code>: 도형을 그리기 전에 지정해줌<blockquote>
</blockquote>
<ul>
<li><code>closePath()</code> : 도형의 시작점과 끝 점 사이에 직선을 그어 완성된 도형으로 만들어줌<blockquote>
</blockquote>
</li>
<li><code>fill()</code> : 주어진 도형의 path를 채워줌 use with fillStyle<blockquote>
</blockquote>
</li>
<li><code>moveTo()</code> : 선을 그리지 않고 좌표를 이동시킨다.<blockquote>
</blockquote>
</li>
<li><code>stroke()</code> : 윤곽선을 이용하여 선을 그을 수 있게 해준다.<blockquote>
</blockquote>
</li>
<li><code>strokeStyle</code> : 윤곽선의 스타일을 지정해준다.<blockquote>
<ul>
<li><code>lineTo(x, y)</code> : 현재 위치에서 지정핸 위치까지 선을 그린다.</li>
</ul>
</blockquote>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<blockquote>
</blockquote>
<p>** 캔버스를 사용해서 게임 만들기 ** 
<a href="https://github.com/hyeongeunee/html-css-javascript/blob/master/javascript/Step09_example5.html">https://github.com/hyeongeunee/html-css-javascript/blob/master/javascript/Step09_example5.html</a></p>
<hr>
<h2 id="json">JSON</h2>
<blockquote>
<ul>
<li><strong>JSON</strong>은 <strong>JavaScript Object Notation</strong>의 약자다.<br></li>
<li>JSON은 사람이 읽을 수 있는 <strong>텍스트 기반의 데이터 교환 표준</strong>이다.<br></li>
<li><strong>JSON의 특징</strong><ul>
<li>JSON은 자바스크립트를 확장하여 만들어졌*다.</li>
<li>JSON은 자바스크립트 <strong>객체 표기법</strong>을 따른다.</li>
<li>JSON은 사람과 기계가 모두 읽기 편하도록 고안되었다.</li>
<li>JSON은 <strong>프로그래밍 언어와 운영체제에 독립적</strong>이다.<br></li>
</ul>
</li>
<li><strong>JSON 구조</strong><ul>
<li>JSON 데이터는 <u><strong>이름</strong>과 <strong>값</strong>의 쌍</u>으로 이루어집니다.</li>
<li>JSON 데이터는 <strong>쉼표(,)</strong>로 나열됩니다.</li>
<li><strong>객체(object)</strong>는 <strong>중괄호({})</strong>로 둘러쌓아 표현합니다.</li>
<li><strong>배열(array)</strong>은 <strong>대괄호([])</strong>로 둘러쌓아 표현합니다.</li>
</ul>
</li>
</ul>
</blockquote>
<pre><code class="language-json">&quot;데이터이름&quot;: 값
&quot;name&quot;: &quot;식빵&quot;</code></pre>
<blockquote>
<ul>
<li><strong>JSON 객체</strong>
JSON 객체는 <strong>중괄호({})로 둘러쌓아 표현</strong>한다.
JSON 객체는 <strong>쉼표(,)를 사용하여 여러 프로퍼티를 포함</strong>할 수 있다.</li>
</ul>
</blockquote>
<pre><code class="language-json">{
    &quot;name&quot;: &quot;식빵&quot;,
    &quot;family&quot;: &quot;웰시코기&quot;,
    &quot;age&quot;: 1,
    &quot;weight&quot;: 2.14
}</code></pre>
<blockquote>
<h3 id="javascript-⇄-json"><strong>Javascript ⇄ Json</strong></h3>
<ul>
<li><strong>JSON.stringify()</strong>
<code>JSON.stringify()</code> 메소드는 인수로 전달받은 자바스크립트 객체를 문자열로 변환하여 반환한다.</li>
</ul>
</blockquote>
<pre><code class="language-json">JSON.stringify(value)</code></pre>
<blockquote>
<ul>
<li><strong>JSON.parse()</strong> 
<code>JSON.parse()</code> 메소드는 <code>JSON.stringify()</code> 메소드와는 반대로 <strong>인수로 전달받은 문자열을 자바스크립트 객체로 변환하여 반환</strong>한다.</li>
</ul>
</blockquote>
<pre><code class="language-json">JSON.parse(text)</code></pre>
<blockquote>
<ul>
<li><strong>toJSON()</strong>
자바스크립트의 <code>toJSON()</code> 메소드는 자바스크립트의 <strong>Date 객체의 데이터를 JSON 형식의 문자열로 변환하여 반환</strong>합니다.</li>
</ul>
</blockquote>
<pre><code class="language-json">var date = new Date();   // 자바스크립트 Date 객체
&gt;
var str = date.toJSON(); // Date 객체를 JSON 형식의 문자열로 변환함.</code></pre>
]]></description>
        </item>
    </channel>
</rss>