<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jin-chang-ho.log</title>
        <link>https://velog.io/</link>
        <description>백엔드 개발자</description>
        <lastBuildDate>Mon, 15 May 2023 01:12:19 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>jin-chang-ho.log</title>
            <url>https://velog.velcdn.com/images/jin-chang-ho/profile/972e9e98-4148-4a05-ac24-d832c718d5f8/social_profile.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. jin-chang-ho.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jin-chang-ho" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Vue 6일차]]></title>
            <link>https://velog.io/@jin-chang-ho/Vue-6%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@jin-chang-ho/Vue-6%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Mon, 15 May 2023 01:12:19 GMT</pubDate>
            <description><![CDATA[<h3 id="vue는-vuex를-지원한다">Vue는 Vuex를 지원한다.</h3>
<p>Vuex는 Vue.js app에 대한 상태관리패턴 + 라이브러리이다.</p>
<p>Vuex를 사용하면 컴포넌트 간 통신을 아래와 같이 수행할 수 있다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/1724a9d5-1e27-494c-9e9e-85666492d3fb/image.png" alt=""></p>
<p>Vue의 핵심 구성요소는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/697c6938-0470-472a-b95a-4dbfd9d3bbd1/image.png" alt=""></p>
<p>Actions의 의미는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/f46641db-1b3d-4323-912a-b52e9b9e726f/image.png" alt=""></p>
<p>Mutations의 의미는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/b74417a4-7cbe-45f9-ab55-14cf41d20a36/image.png" alt=""></p>
<p>State의 의미는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/d285389c-0387-40a5-88f8-57da314a3767/image.png" alt=""></p>
<p>State가 변했을 때 출력되는 화면을 변하게 하기 위해서 Getters를 쓴다.
Getters의 의미는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/a09ff09e-1961-413f-9487-37da2fc1cd66/image.png" alt=""></p>
<p>원래는 아래와 같이 컴포넌트 통신을 해야 한다.</p>
<pre><code>// Step00View.vue

&lt;template&gt;
  &lt;div class=&quot;text-center&quot;&gt;
    &lt;h2&gt;당신이 좋아하는 파트를 선택하세요&lt;/h2&gt;
    &lt;result-component :total=&quot;count&quot; /&gt;
    &lt;subject-component @add-tot-count=&quot;addTotalCount&quot; title=&quot;코딩&quot;&gt;&lt;/subject-component&gt;
    &lt;subject-component @add-tot-count=&quot;addTotalCount&quot; title=&quot;알고리즘&quot;&gt;&lt;/subject-component&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import ResultComponent from &quot;@/components/step00/ResultComponent&quot;;
import SubjectComponent from &quot;@/components/step00/SubjectComponent&quot;;

export default {
  data() {
    return {
      count: 0,
    };
  },
  components: {
    ResultComponent,
    SubjectComponent,
  },
  methods: {
    addTotalCount() {
      this.count += 1;
    },
  },
};
&lt;/script&gt;
&lt;style scoped&gt;
.text-center {
  text-align: center;
}
&lt;/style&gt;</code></pre><pre><code>// ResultComponent.vue

&lt;template&gt;
  &lt;h2&gt;{{ total }}&lt;/h2&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  // props: [&quot;total&quot;],
  computed: {
    total() {
      return this.$store.state.count;
    },
  },
};
&lt;/script&gt;

&lt;style&gt;&lt;/style&gt;</code></pre><pre><code>// SubjectComponent.vue

&lt;template&gt;
  &lt;button @click=&quot;addCount&quot;&gt;{{ title }} - {{ count }}&lt;/button&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  name: &quot;SubjectComponent&quot;,
  props: [&quot;title&quot;],
  data() {
    return {
      count: 0,
    };
  },
  methods: {
    addCount: function () {
      this.count += 1;
      // this.$emit(&quot;addtotcount&quot;);
      this.$store.state.count++;
    },
  },
};
&lt;/script&gt;

&lt;style&gt;&lt;/style&gt;</code></pre><p>하지만 Vuex를 쓰면 아래와 같이 컴포넌트 통신을 할 수 있다.</p>
<pre><code>// store/index.js

export default new Vuex.Store({
  state: {
    count: 0,
  },
  actions: {
    asyncAddOne(context) { // 첫번째 인자로 context가 자동 주입
      setTimeout(() =&gt; {
        context.commit(&quot;addOne&quot;);
      }, 2000);
    },
  },
  mutations: {
    ADD_ONE(state) { // 첫번째 인자로 state가 자동 주입
      state.count += 1;
    },
    ADD_TEN_COUNT(state, payload) {
      state.count += payload;
    },
    ADD_OBJ_COUNT(state, payload) {
      state.count += payload.num;
    },
  },
  getters: {
    // 복잡한 계산식을 처리 : computed
    countMsg(state) { // 첫번째 인자로 state가 자동 주입
      let msg = &quot;10번보다 &quot;;
      if (state.count &gt; 10) {
        msg += &quot;많이 &quot;;
      } else {
        msg += &quot;적게 &quot;;
      }
      return msg + &quot; 호출됨(&quot; + state.count + &quot;)&quot;;
    },
  },
});</code></pre><pre><code>// Step07View.vue

&lt;template&gt;
  &lt;div class=&quot;text-center&quot;&gt;
    &lt;h2&gt;당신이 좋아하는 파트를 선택하세요&lt;/h2&gt;
    &lt;result-component /&gt;
    &lt;subject-component title=&quot;코딩&quot;&gt;&lt;/subject-component&gt;
    &lt;subject-component title=&quot;알고리즘&quot;&gt;&lt;/subject-component&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import ResultComponent from &quot;@/components/step07/ResultComponent&quot;;
import SubjectComponent from &quot;@/components/step07/SubjectComponent&quot;;

export default {
  components: {
    ResultComponent,
    SubjectComponent,
  },
};
&lt;/script&gt;
&lt;style&gt;
.text-center {
  text-align: center;
}
&lt;/style&gt;    </code></pre><pre><code>// ResultComponent.vue

&lt;template&gt;
  &lt;div&gt;
    &lt;h2&gt;{{ total }}&lt;/h2&gt;
    &lt;h2&gt;{{ countMsg }}&lt;/h2&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import { mapGetters } from &quot;vuex&quot;;
export default {
  computed: {
    // countMsg() {
    //   return this.$store.getters.countMsg;
    // },
    ...mapGetters([&quot;countMsg&quot;]),

    total() {
      return this.$store.state.count;
    },
  },
};
&lt;/script&gt;

&lt;style&gt;&lt;/style&gt;</code></pre><pre><code>// SubjectComponent.vue

&lt;template&gt;
  &lt;div&gt;
    &lt;button @click=&quot;addCount&quot;&gt;{{ title }} - {{ count }}&lt;/button&gt;
    &lt;button @click=&quot;addTenCount&quot;&gt;{{ title }} - {{ count }}&lt;/button&gt;
    &lt;button @click=&quot;addObjCount&quot;&gt;{{ title }} - {{ count }}&lt;/button&gt;
    &lt;button @click=&quot;asyncCount&quot;&gt;Action {{ title }} - {{ count }}&lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import { mapMutations, mapActions } from &quot;vuex&quot;;
export default {
  name: &quot;SubjectComponent&quot;,
  props: [&quot;title&quot;],
  data() {
    return {
      count: 0,
    };
  },
  methods: {
    ...mapMutations({
      addMOne: &quot;ADD_ONE&quot;,
      addMTenCount: &quot;ADD_TEN_COUNT&quot;,
      addMObjCount: &quot;ADD_OBJ_COUNT&quot;,
    }),
    ...mapActions([&quot;asyncAddOne&quot;]),
    addCount: function () {
      this.count += 1;
      // this.$store.commit(&#39;addOne&#39;);
      this.addMOne();
    },
    addTenCount: function () {
      this.count += 10;
      // this.$store.commit(&#39;addCount&#39;, 10);
      this.addMTenCount(10);
    },
    addObjCount: function () {
      let num = Math.round(Math.random() * 100);
      this.count += num;
      // this.$store.commit(&#39;addObjCount&#39;, { num });
      this.addMObjCount({ num });
    },
    asyncCount() {
      // this.$store.dispatch(&quot;asyncAddOne&quot;);
      this.asyncAddOne();
    },
  },
};
&lt;/script&gt;

&lt;style&gt;&lt;/style&gt;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Vue 5일차]]></title>
            <link>https://velog.io/@jin-chang-ho/Vue-5%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@jin-chang-ho/Vue-5%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Fri, 12 May 2023 06:54:24 GMT</pubDate>
            <description><![CDATA[<h3 id="vue는-axios를-지원한다">Vue는 axios를 지원한다.</h3>
<p>Vue에서 권고하는 Promise 기반의 HTTP 통신 라이브러리를 axios라고 한다.
axios를 사용하기 위해선 아래와 같은 과정을 거친다.</p>
<blockquote>
<ol>
<li><code>npm install axios</code> 로 axios를 설치한다.</li>
<li><code>import axios from &quot;axios&quot;</code>로 axios를 불러온다.</li>
<li><code>axios.get(URL)</code> or <code>axios.post(URL)</code> .. 으로 Request를 정의한다. </li>
<li><code>.then()</code>로 일반적인 동작을, <code>.catch()</code>로 오류 발생 시 동작을 정의한다.</li>
</ol>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Vue 4일차]]></title>
            <link>https://velog.io/@jin-chang-ho/Vue-4%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@jin-chang-ho/Vue-4%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 11 May 2023 05:20:36 GMT</pubDate>
            <description><![CDATA[<h3 id="vue는-vue-router를-지원한다">Vue는 Vue-Router를 지원한다.</h3>
<p>URL에 따라 Component를 연결하고 설정된 Component를 보여줄 때 Vue-Router를 사용한다.</p>
<p>Vue-Router 설정 예시는 아래와 같다.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;style&gt;
      .router-link-exact-active {
        color: red;
      }
    &lt;/style&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/vue-router@3.5.3/dist/vue-router.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;

  &lt;body&gt;
    &lt;!-- 현재 라우트에 맞는 컴포넌트가 렌더링 --&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;h1&gt;Board - Router&lt;/h1&gt;
      &lt;p&gt;
        &lt;router-link to=&quot;/&quot;&gt;메인&lt;/router-link&gt;
        &lt;router-link to=&quot;/board&quot;&gt;자유게시판&lt;/router-link&gt;
        &lt;router-link to=&quot;/qna&quot;&gt;질문게시판&lt;/router-link&gt;
        &lt;router-link to=&quot;/gallery&quot;&gt;사진게시판&lt;/router-link&gt;
        &lt;router-view&gt;&lt;/router-view&gt; 
      &lt;/p&gt;
    &lt;/div&gt;

    &lt;script&gt;
      // 라우트 컴포넌트
      const Main = {
        template: &quot;&lt;div&gt;메인 페이지&lt;/div&gt;&quot;,
      };
      const Board = {
        template: &quot;&lt;div&gt;자유 게시판&lt;/div&gt;&quot;,
      };
      const QnA = {
        template: &quot;&lt;div&gt;질문 게시판&lt;/div&gt;&quot;,
      };
      const Gallery = {
        template: &quot;&lt;div&gt;갤러리 게시판&lt;/div&gt;&quot;,
      };

      // 라우터 객체 생성
      const router = new VueRouter({
        routes: [
          {
            path: &quot;/&quot;,
            component: Main
          },
          {
            path: &quot;/board&quot;,
            component: Board
          },
          {
            path: &quot;/qna&quot;,
            component: QnA
          },
          {
            path: &quot;/gallery&quot;,
            component: Gallery
          },
        ]
      });

      const app = new Vue({
        el: &quot;#app&quot;,
        router, // Vue 인스턴트 라우터 주입
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>실행 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/3ce40c94-e3ff-4592-b4bf-ad61e152d49e/image.png" alt=""></p>
<p>아래와 같이 router 안 mode를 &quot;history&quot;로 설정해보자.</p>
<pre><code>const router = new VueRouter({
  mode: &quot;history&quot;,
  routes: [
    {
      path: &quot;/&quot;,
      name: &#39;main&#39;,
      component: Main
    },
    {
      path: &quot;/board&quot;,
      name: &#39;board&#39;,
      component: Board
    },
    {
      path: &quot;/qna&quot;,
      name: &#39;qna&#39;,
      component: QnA
    },
    {
      path: &quot;/gallery&quot;,
      name: &#39;gallery&#39;,
      component: Gallery
    },
  ]
});</code></pre><p>그럼 아래처럼 일반적인 링크로 출력된다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/8df8839e-676f-4c95-8cdb-6b6654b33740/image.png" alt=""></p>
<p>router에 값을 넘겨줄 땐 아래와 같이 값을 넘겨준다.</p>
<pre><code>export default {
  template: `&lt;div&gt;
    자유 게시판
    &lt;ul&gt;
      &lt;li v-for=&quot;i in 5&quot;&gt;
        &lt;router-link :to=&quot;&#39;/board/&#39; + i&quot;&gt;{{i}}번 게시글&lt;/router-link&gt;
        &lt;!-- &lt;router-link :to=&quot;{name: &#39;boardview&#39;, params: {no: i}}&quot;&gt;{{i}}번 게시글&lt;/router-link&gt; 랑 동일 --&gt;
        &lt;!-- &lt;a :href=&quot;&#39;#&#39; + i&quot; @click=&quot;$router.push({name: &#39;boardview&#39;, params: {no: i}})&quot;&gt;{{i}}번 게시글&lt;/a&gt; 랑 동일 --&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;`,
};</code></pre><p>중앙에서 값을 받고 다시 넘겨주는 건 아래와 같다.</p>
<pre><code>const router = new VueRouter({
  routes: [
    ...
      path: &#39;/board/:no&#39;,
      name: &#39;boardview&#39;,
      component: BoardView,
    },
    ...
  ],
});</code></pre><p>값을 다시 받는 방법은 아래와 같다.</p>
<pre><code>export default {
  template: `&lt;div&gt;
    {{no}}번 게시물 상세정보
    &lt;hr&gt;
    &lt;router-link :to=&quot;/board&quot;&gt;목록&lt;/router-link&gt;
    &lt;!-- &lt;router-link :to=&quot;{name: &#39;board&#39;}&quot;&gt;목록&lt;/router-link&gt; 랑 동일 --&gt;
    &lt;!-- &lt;a href=&quot;#board&quot; @click=&quot;$router.push(&#39;/board&#39;)&quot;&gt;게시판&lt;/a&gt; 랑 동일 --&gt;
   &lt;/div&gt;`,
  data() {
    return {
      no: 0,
    };
  },
  created() {
    this.no = this.$route.params.no;
  },
};</code></pre><p>아래와 같이 라우트를 중첩할 수 있다.</p>
<pre><code>const router = new VueRouter({
  mode: &#39;history&#39;,
  routes: [
    ... 
    {
      path: &#39;/board&#39;,
      name: &#39;board&#39;,
      component: Board,
      redirect: &#39;/board/list&#39;,
      children: [
        {
          path: &#39;list&#39;,
          name: &#39;boardlist&#39;,
          component: BoardList,
        },
        {
          path: &#39;write&#39;,
          name: &#39;boardwrite&#39;,
          component: BoardWrite,
        },
        {
          path: &#39;detail/:no&#39;,
          name: &#39;boardview&#39;,
          component: BoardView,
        },
        {
          path: &#39;update/:no&#39;,
          name: &#39;boardupdate&#39;,
          component: BoardUpdate,
        },
      ],
    },
    ...
  ],
});</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Vue 3일차]]></title>
            <link>https://velog.io/@jin-chang-ho/Vue-3%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@jin-chang-ho/Vue-3%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 11 May 2023 04:45:08 GMT</pubDate>
            <description><![CDATA[<h3 id="vue는-sfc-구조를-지원한다">Vue는 SFC 구조를 지원한다.</h3>
<p>Template + Script + Style로 이뤄진 vue 파일을 SFC라고 한다.
각 구성요소의 의미는 아래와 같다.</p>
<blockquote>
<ol>
<li>&lt;<inline>template&gt; : 구조, 단 하나만 포함 가능<ol start="2">
<li>&lt;<inline>script&gt; : 기능, 단 하나만 포함 가능</li>
<li>&lt;<inline>style&gt; : 스타일, 여러 개 포함 가능</li>
</ol>
</li>
</ol>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Vue 2일차]]></title>
            <link>https://velog.io/@jin-chang-ho/Vue-2%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@jin-chang-ho/Vue-2%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Wed, 10 May 2023 04:20:40 GMT</pubDate>
            <description><![CDATA[<h3 id="vue는-여러-instance를-지원한다">Vue는 여러 Instance를 지원한다.</h3>
<p>Vue는 다양한 Instance를 지원한다. 그 예시는 아래와 같다.</p>
<blockquote>
<ol>
<li>Method : 특정 기능을 수행함</li>
</ol>
</blockquote>
<p>예시는 아래와 같다.</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;script&gt;
      let vm = new Vue({
        data: {
          count: 1,
        },
        created() {
          console.log(this.count);
        },
        methods: {
          incCount() {
            console.log(&quot;incCount 호출됨&quot;);
            this.count++;
          },
        },
      });
      vm.incCount();
      console.log(vm.count); // 2
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>method 안에서 data에 접근하기 위해선 this를 사용해야 한다.</p>
<p>실행 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/73cf8c20-2193-449e-af19-f2836e1fb20c/image.png" alt=""></p>
<blockquote>
<ol start="2">
<li>Filter : 텍스트 형식을 쉽게 변환함</li>
</ol>
</blockquote>
<p>filter는 전역 filter와 지역 filter로 나뉜다. 예시는 아래와 같다.</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;

&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot; /&gt;
  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
  &lt;title&gt;Vue.js&lt;/title&gt;
  &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
&lt;/head&gt;

&lt;body&gt;
  &lt;div id=&quot;app&quot;&gt;
    &lt;div&gt;
      &lt;input type=&quot;text&quot; v-model=&quot;msg&quot; /&gt;
    &lt;/div&gt;
    &lt;div&gt;
      &lt;h2&gt;결과 :&lt;/h2&gt;
      &lt;h3&gt;{{ msg | count1 }}&lt;/h3&gt;
      &lt;h3&gt;{{ msg | count2(&#39;문자를 넣어보세요&#39;) }}&lt;/h3&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;script&gt;
      // 전역 필터
    Vue.filter(&#39;count1&#39;, (val) =&gt; {
      if (val.length == 0) {
        return;
      }
      return `${val} : ${val.length}자`;
    });
    new Vue({
      el: &#39;#app&#39;,
      data: {
        msg: &#39;&#39;,
      },
      // 지역 필터
      filters: {
        count2(val, alternative) {
          if (val.length == 0) {
            return alternative;
          }
          return `${val} : ${val.length}자`;
        },
      },
    });
  &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<p><code>{{ msg | count1 }}</code> 에서 count1의 매개 변수인 val가 msg가 된다.</p>
<p>실행 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/aa5d0840-b7c9-4e11-93f3-880d3b17555d/image.png" alt=""></p>
<blockquote>
<ol start="3">
<li>Computed : 특정 데이터를 변경이 없을 경우 캐싱해 사용하다가 데이터가 변경되면 이를 반영함</li>
</ol>
</blockquote>
<p>예시는 아래와 같다.</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;

&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot; /&gt;
  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
  &lt;title&gt;Vue.js&lt;/title&gt;
  &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
&lt;/head&gt;

&lt;body&gt;
  &lt;div id=&quot;app&quot;&gt;
    &lt;input type=&quot;text&quot; v-model=&quot;message&quot; /&gt;
    &lt;p&gt;원본 메시지: &quot;{{ message }}&quot;&lt;/p&gt;
    &lt;p&gt;역순으로 표시한 메시지1: &quot;{{ reversedMsg }}&quot;&lt;/p&gt;
    &lt;p&gt;역순으로 표시한 메시지2: &quot;{{ reversedMsg }}&quot;&lt;/p&gt;
    &lt;p&gt;역순으로 표시한 메시지3: &quot;{{ reversedMsg }}&quot;&lt;/p&gt;
  &lt;/div&gt;
  &lt;script&gt;
    var vm = new Vue({
      el: &#39;#app&#39;,
      data: {
        message: &#39;안녕하세요 여러분&#39;,
      },
      computed: {
        reversedMsg: function () {
          console.log(&#39;꺼꾸로 찍기&#39;);
          return this.message.split(&#39;&#39;).reverse().join(&#39;&#39;);
        },
      },
    });
  &lt;/script&gt;
&lt;/body&gt;

&lt;/html&gt;</code></pre>
<p>실행 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/03848d3f-80b9-4eee-8f39-40f6ccd24ca2/image.png" alt=""></p>
<p>만약 Computed를 Method로 쓰면 아래와 같다.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;

  &lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;input type=&quot;text&quot; v-model=&quot;message&quot; /&gt;
      &lt;p&gt;원본 메시지: &quot;{{ message }}&quot;&lt;/p&gt;
      &lt;p&gt;역순으로 표시한 메시지1: &quot;{{ reversedMsg() }}&quot;&lt;/p&gt;
      &lt;p&gt;역순으로 표시한 메시지2: &quot;{{ reversedMsg() }}&quot;&lt;/p&gt;
      &lt;p&gt;역순으로 표시한 메시지3: &quot;{{ reversedMsg() }}&quot;&lt;/p&gt;
    &lt;/div&gt;
    &lt;script&gt;
      var vm = new Vue({
        el: &#39;#app&#39;,
        data: {
          message: &#39;안녕하세요 여러분&#39;,
        },
        methods: {
          reversedMsg: function () {
            console.log(&#39;꺼꾸로 찍기&#39;);
            return this.message.split(&#39;&#39;).reverse().join(&#39;&#39;);
          },
        },
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>실행 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/a5deaba6-2c0e-4f39-8ede-e1b6b06a2eb2/image.png" alt="">
Computed와 달리 함수가 여러번 호출됨을 알 수 있다.</p>
<blockquote>
<ol start="4">
<li>Watch : 특정 데이터가 변경될 경우 다른 데이터에 이를 반영함</li>
</ol>
</blockquote>
<p>예시는 아래와 같다.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;p&gt;원본 메시지: &quot;{{ message }}&quot;&lt;/p&gt;
      &lt;p&gt;역순으로 표시한 메시지: &quot;{{ reversedMsg }}&quot;&lt;/p&gt;
      &lt;input type=&quot;text&quot; v-model=&quot;message&quot; /&gt;
    &lt;/div&gt;
    &lt;script&gt;
      const app = new Vue({
        el: &#39;#app&#39;,
        data: {
          message: &#39;Hello&#39;,
          reversedMsg: &#39;&#39;,
        },
        watch: {
          message: function (newVal, oldVal) {
            console.log(newVal, oldVal);
            this.reversedMsg = newVal.split(&#39;&#39;).reverse().join(&#39;&#39;);
          },
        },
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>실행 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/c9d1164e-220a-4a1a-8784-f6fbafd12fcf/image.png" alt=""></p>
<br>

<h3 id="vue는-여러-event를-지원한다">Vue는 여러 Event를 지원한다.</h3>
<p>Vue는 다양한 Event를 지원한다. 
종류는 아래 3가지가 있다. 하나씩 살펴보자.</p>
<blockquote>
<ol>
<li>v-on directive</li>
</ol>
</blockquote>
<p>예시는 아래와 같다.</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;

  &lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;button v-on:click=&quot;greet&quot;&gt;Greet&lt;/button&gt;
    &lt;/div&gt;
    &lt;script&gt;
      var vm = new Vue({
        el: &quot;#app&quot;,
        data: {
          name: &quot;SAMSUNG&quot;,
        },
        methods: {
          greet: function (event) {
            alert(&quot;Hello &quot; + this.name + &quot;!&quot;);
            console.dir(event.target);
          },
        },
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>실행 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/7420dc79-85b2-4146-8406-4d70b21d297f/image.png" alt=""></p>
<blockquote>
<ol start="2">
<li>inline method handler</li>
</ol>
</blockquote>
<p>예시는 아래와 같다.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;form action=&quot;http://www.naver.com&quot;&gt;
        &lt;button v-on:click=&quot;greet1(&#39;SAMSUNG&#39;)&quot;&gt;Greet&lt;/button&gt;
        &lt;button v-on:click=&quot;greet2($event, &#39;SAMSUNG&#39;)&quot;&gt;Greet&lt;/button&gt;
      &lt;/form&gt;
    &lt;/div&gt;
    &lt;script&gt;
      new Vue({
        el: &#39;#app&#39;,
        methods: {
          greet1: function (msg) {
            alert(&#39;Hello &#39; + msg + &#39;!&#39;);
            console.dir(event.target);
          },
          greet2: function (e, msg) {
            if (e) e.preventDefault(); // event의 새로 고침을 막는 역할
            alert(&#39;Hello &#39; + msg + &#39;!&#39;);
            console.dir(e.target);
          },
        },
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>1번 버튼을 누른 최종 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/08403a98-5048-4c8b-bdf7-d829c6a54171/image.png" alt=""></p>
<p>alert 창으로 Hello SAMSUNG을 띄우고 페이지를 이동한다.</p>
<p>2번 버튼을 누른 최종 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/198fdcdb-2ba7-4d75-9368-430a25c0a2ed/image.png" alt=""></p>
<p>alert 창으로 Hello SAMSUNG을 띄우고 페이지를 이동하지 않는다.</p>
<blockquote>
<ol start="3">
<li>Event Modifier</li>
</ol>
</blockquote>
<p>예시는 아래와 같다.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;h2&gt;페이지 이동&lt;/h2&gt;
      &lt;a href=&quot;test29.html&quot; @click.prevent=&quot;sendMsg&quot;&gt;페이지 이동 막기&lt;/a&gt;&lt;br /&gt;
    &lt;/div&gt;
    &lt;script&gt;
      new Vue({
        el: &#39;#app&#39;,
        methods: {
          sendMsg() {
            alert(&#39;이동할까요?&#39;);
          },
        },
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>그럼 페이지 이동이 되지 않는다.</p>
<p>Vue에선 $refs 속성을 이용해 DOM에 접근할 수 있다. 예시는 아래와 같다.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
    &lt;style&gt;
      .success {
        color: dodgerblue;
      }

      .fail {
        color: darkred;
      }
    &lt;/style&gt;
  &lt;/head&gt;

  &lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;h2&gt;엘리먼트 참조하기&lt;/h2&gt;
      &lt;!-- 아이디 : &lt;input type=&quot;text&quot; v-model=&quot;id&quot;&gt; --&gt;
      아이디 : &lt;input type=&quot;text&quot; v-model=&quot;id&quot; ref=&quot;id&quot; @keyup=&quot;idCheck&quot; /&gt;
      &lt;button @click=&quot;idCheck&quot;&gt;아이디 중복 체크&lt;/button&gt;
      &lt;div v-bind:class=&quot;{success : isSuccess, fail : isFail}&quot; v-bind:style=&quot;myStyle&quot; v-html=&quot;msg&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;script&gt;
      new Vue({
        el: &#39;#app&#39;,
        data: {
          id: &#39;&#39;,
          msg: &#39;&#39;,
          isSuccess: false,
          isFail: false,
          myStyle: {
            fontSize: &#39;25px&#39;,
          },
        },
        methods: {
          idCheck() {
            if (this.id.length &lt; 5 || this.id.length &gt; 12) {
              this.msg = `아이디는 5자이상 12자리 이하입니다.`;
              this.$refs.id.focus();
              console.dir(this.$refs.id);
              this.isSuccess = false;
              this.isFail = false;
              return;
            } else {
              if (this.id === &#39;samsung&#39;) {
                this.msg = `&lt;b&gt;${this.id}&lt;/b&gt;는 사용할 수 없습니다.`;
                this.isSuccess = false;
                this.isFail = true;
              } else {
                this.msg = `&lt;b&gt;${this.id}&lt;/b&gt;는 사용할 수 있습니다.`;
                this.isSuccess = true;
                this.isFail = false;
              }
            }
            console.log(this.$refs.id.value);
          },
        },
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>실행 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/09dd8b2e-403d-4a01-8279-3f571590b77a/image.png" alt=""></p>
<p>※ Vue의 가장 중요한 목적 중 하나가 개발자가 DOM을 사용하지 않게 하는 것이므로 $refs가 권장되진 않는다.</p>
<br>

<h3 id="vue는-css-class-binding을-지원한다">Vue는 CSS Class Binding을 지원한다.</h3>
<p>v-bind:class는 true, false로 CSS를 지정할 수 있다.</p>
<p>예시는 아래와 같다.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
    &lt;style type=&quot;text/css&quot;&gt;
      .completed {
        text-decoration: line-through;
        font-style: italic;
      }
    &lt;/style&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;ul&gt;
        &lt;li :class=&quot;{completed: todo.done}&quot; :style=&quot;myStyle&quot; v-for=&quot;todo in todos&quot;&gt;
          {{todo.msg}}
          &lt;button @click=&quot;complete(todo)&quot; class=&quot;btn&quot;&gt;완료&lt;/button&gt;
        &lt;/li&gt;
      &lt;/ul&gt;
    &lt;/div&gt;
    &lt;script&gt;
      new Vue({
        el: &#39;#app&#39;,
        data: {
          todos: [
            {
              msg: &#39;5시간 잠자기&#39;,
              done: false,
            },
            {
              msg: &#39;알고리즘 1시간 공부하기&#39;,
              done: false,
            },
            {
              msg: &#39;Vue 1시간 공부하기&#39;,
              done: false,
            },
          ],
          myStyle: {
            fontSize: &#39;20px&#39;,
          },
        },
        methods: {
          complete: function (todo) {
            todo.msg = todo.msg + &#39;완료&#39;;
            todo.done = !todo.done;
          },
        },
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>실행 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/82f5b458-0227-49db-8fcf-5ecefc081bbc/image.png" alt=""></p>
<br>

<h3 id="vue는-form-input-binding을-지원한다">Vue는 Form Input Binding을 지원한다.</h3>
<p>v-model 디렉티브를 사용하여 Form에 양방향 데이터 바인딩을 생성할 수 있다. 하나씩 살펴보자.</p>
<blockquote>
<ol>
<li>text, textarea</li>
</ol>
</blockquote>
<p>예시는 아래와 같다.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;

  &lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;div&gt;
        아이디 :
        &lt;input v-model.trim=&quot;id&quot; placeholder=&quot;아이디를 입력하세요&quot; /&gt;
        &lt;!-- v-model은 기본적으로 모든 key stroke가 발생할 때마다 값을 업데이트 시킨다.
            .lazy 수식어를 추가하여 change 이벤트 이후에 동기화 할 수 있습니다. --&gt;
        &lt;input v-model.lazy=&quot;id&quot; placeholder=&quot;아이디를 입력하세요&quot; /&gt;
      &lt;/div&gt;
      &lt;div&gt;
        메세지 :
        &lt;textarea v-model=&quot;message&quot; placeholder=&quot;내용을 입력하세요&quot;&gt;&lt;/textarea&gt;
      &lt;/div&gt;
      &lt;p&gt;{{ id }} 님에게 보내는 메세지 : {{ message }}&lt;/p&gt;
    &lt;/div&gt;
    &lt;script&gt;
      new Vue({
        el: &#39;#app&#39;,
        data: {
          id: &#39;&#39;,
          message: &#39;&#39;,
        },
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>실행 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/d6a57430-a28e-485f-a909-52315c38031f/image.png" alt=""></p>
<blockquote>
<ol start="2">
<li>checkbox</li>
</ol>
</blockquote>
<p>예시는 아래와 같다.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;

  &lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;div&gt;당신이 가고 싶은 지역을 선택하시오&lt;/div&gt;
      &lt;input type=&quot;checkbox&quot; id=&quot;buk&quot; value=&quot;부울경&quot; v-model=&quot;checkedAreas&quot; /&gt;
      &lt;label for=&quot;buk&quot;&gt;부울경&lt;/label&gt;
      &lt;input type=&quot;checkbox&quot; id=&quot;gwangju&quot; value=&quot;광주&quot; v-model=&quot;checkedAreas&quot; /&gt;
      &lt;label for=&quot;gwangju&quot;&gt;광주&lt;/label&gt;
      &lt;input type=&quot;checkbox&quot; id=&quot;gumi&quot; value=&quot;구미&quot; v-model=&quot;checkedAreas&quot; /&gt;
      &lt;label for=&quot;gumi&quot;&gt;구미&lt;/label&gt;
      &lt;input type=&quot;checkbox&quot; id=&quot;daejeon&quot; value=&quot;대전&quot; v-model=&quot;checkedAreas&quot; /&gt;
      &lt;label for=&quot;daejeon&quot;&gt;대전&lt;/label&gt;
      &lt;input type=&quot;checkbox&quot; id=&quot;seoul&quot; value=&quot;서울&quot; v-model=&quot;checkedAreas&quot; /&gt;
      &lt;label for=&quot;seoul&quot;&gt;서울&lt;/label&gt;
      &lt;br /&gt;
      &lt;span&gt;체크한 이름: {{ checkedAreas }}&lt;/span&gt;
    &lt;/div&gt;
    &lt;script&gt;
      new Vue({
        el: &#39;#app&#39;,
        data: {
          checkedAreas: [],
        },
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>실행 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/89b4b10a-6ff9-42af-93be-3f1af7700b07/image.png" alt=""></p>
<blockquote>
<ol start="3">
<li>radio</li>
</ol>
</blockquote>
<p>예시는 아래와 같다.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;

  &lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;div&gt;수업을 듣는 지역을 선택하시오&lt;/div&gt;
      &lt;div&gt;
        &lt;input type=&quot;radio&quot; id=&quot;buk&quot; value=&quot;부울경&quot; v-model=&quot;ckArea&quot; /&gt;
        &lt;label for=&quot;buk&quot;&gt;부울경&lt;/label&gt;
        &lt;input type=&quot;radio&quot; id=&quot;gwangju&quot; value=&quot;광주&quot; v-model=&quot;ckArea&quot; /&gt;
        &lt;label for=&quot;gwangju&quot;&gt;광주&lt;/label&gt;
        &lt;input type=&quot;radio&quot; id=&quot;gumi&quot; value=&quot;구미&quot; v-model=&quot;ckArea&quot; /&gt;
        &lt;label for=&quot;gumi&quot;&gt;구미&lt;/label&gt;
        &lt;input type=&quot;radio&quot; id=&quot;daejeon&quot; value=&quot;대전&quot; v-model=&quot;ckArea&quot; /&gt;
        &lt;label for=&quot;daejeon&quot;&gt;대전&lt;/label&gt;
        &lt;input type=&quot;radio&quot; id=&quot;seoul&quot; value=&quot;서울&quot; v-model=&quot;ckArea&quot; /&gt;
        &lt;label for=&quot;seoul&quot;&gt;서울&lt;/label&gt;
      &lt;/div&gt;
      &lt;span&gt;선택한 지역 : {{ ckArea }}&lt;/span&gt;
    &lt;/div&gt;
    &lt;script&gt;
      new Vue({
        el: &#39;#app&#39;,
        data: {
          ckArea: &#39;광주&#39;,
        },
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>실행 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/35e43f61-375f-45f8-82f4-0425be951097/image.png" alt=""></p>
<blockquote>
<ol start="4">
<li>select</li>
</ol>
</blockquote>
<p>단일 선택 가능 실행 예시는 아래와 같다.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;

  &lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;div&gt;
        &lt;p&gt;수업을 듣는 지역을 선택하시오&lt;/p&gt;
        &lt;select v-model=&quot;selectedArea&quot;&gt;
          &lt;option disabled value=&quot;&quot;&gt;선택하세요&lt;/option&gt;
          &lt;option value=&quot;buk&quot;&gt;부울경&lt;/option&gt;
          &lt;option value=&quot;gwangju&quot;&gt;광주&lt;/option&gt;
          &lt;option value=&quot;gumi&quot;&gt;구미&lt;/option&gt;
          &lt;option value=&quot;daejeon&quot;&gt;대전&lt;/option&gt;
          &lt;option value=&quot;seoul&quot;&gt;서울&lt;/option&gt;
        &lt;/select&gt;
      &lt;/div&gt;
      &lt;span&gt;선택한 지역 : {{ selectedArea }}&lt;/span&gt;&lt;br /&gt;
    &lt;/div&gt;
    &lt;script&gt;
      new Vue({
        el: &#39;#app&#39;,
        data: {
          selectedArea: &#39;&#39;,
        },
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>실행 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/8cf33a4e-6aaa-4063-82c9-5fd38b861ab5/image.png" alt=""></p>
<p>다중 선택 가능 실행 예시는 아래와 같다.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;

  &lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;div&gt;
        &lt;p&gt;수업을 듣고자하는 지역을 선택하시오(다중가능)&lt;/p&gt;
        &lt;select v-model=&quot;selectedArea&quot; multiple&gt;
          &lt;option disabled value=&quot;&quot;&gt;선택하세요&lt;/option&gt;
          &lt;option value=&quot;buk&quot;&gt;부울경&lt;/option&gt;
          &lt;option value=&quot;gwangju&quot;&gt;광주&lt;/option&gt;
          &lt;option value=&quot;gumi&quot;&gt;구미&lt;/option&gt;
          &lt;option value=&quot;daejeon&quot;&gt;대전&lt;/option&gt;
          &lt;option value=&quot;seoul&quot;&gt;서울&lt;/option&gt;
        &lt;/select&gt;
      &lt;/div&gt;
      &lt;span&gt;선택한 지역 : {{ selectedArea }}&lt;/span&gt;
    &lt;/div&gt;
    &lt;script&gt;
      new Vue({
        el: &#39;#app&#39;,
        data: {
          selectedArea: [],
        },
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>실행 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/0a2bec0b-3d74-41a9-a55e-7b0a69ea66f4/image.png" alt=""></p>
<br>

<h3 id="vue는-component를-지원한다">Vue는 Component를 지원한다.</h3>
<p>HTML을 확장하여 재사용 가능한 코드로 캡슐화한 것이 Component이다.
Component는 전역 Component와 지역 Component로 나뉜다. 예시는 아래와 같다.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div id=&quot;app1&quot;&gt;
      &lt;my-global&gt;&lt;/my-global&gt; // 케밥 케이스 필수!!
      &lt;my-global&gt;&lt;/my-global&gt;
      &lt;my-local&gt;&lt;/my-local&gt; // 케밥 케이스 필수!!
      &lt;my-local&gt;&lt;/my-local&gt;
    &lt;/div&gt;
    &lt;div id=&quot;app2&quot;&gt;
      &lt;my-global&gt;&lt;/my-global&gt;
      &lt;my-global&gt;&lt;/my-global&gt;
      &lt;my-local&gt;&lt;/my-local&gt;
      &lt;my-local&gt;&lt;/my-local&gt;
    &lt;/div&gt;
    &lt;script&gt;
      // 전역 Component
      Vue.component(&quot;MyGlobal&quot;, { // 케밥 케이스 권장
        template: &quot;&lt;h2&gt;전역 컴포넌트임&lt;/h2&gt;&quot;,
      });
      new Vue({
        el: &quot;#app1&quot;,
        components: {
          // 지역 Component
          MyLocal: { // 케밥 케이스 권장
            template: &quot;&lt;h2&gt;지역 컴포넌트&lt;/h2&gt;&quot;,
          },
        },
      });
      new Vue({
        el: &quot;#app2&quot;,
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>실행 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/cc460a30-52d6-4d53-8edd-54e0bb9f9e20/image.png" alt=""></p>
<p>Component 간 변수는 공유된다. 아래 예시를 살펴보자.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;

  &lt;body&gt;
    &lt;h2&gt;컴포넌트 데이터 공유 문제&lt;/h2&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;count-view&gt;&lt;/count-view&gt;
      &lt;count-view&gt;&lt;/count-view&gt;
      &lt;count-view&gt;&lt;/count-view&gt;
    &lt;/div&gt;
    &lt;template id=&quot;countview&quot;&gt;
      &lt;div&gt;
        &lt;span&gt;{{ count }}&lt;/span&gt;
        &lt;button @click=&quot;count++&quot;&gt;클릭&lt;/button&gt;
      &lt;/div&gt;
    &lt;/template&gt;
    &lt;script&gt;
      let num = {
        count: 0,
      };
      Vue.component(&quot;count-view&quot;, {
        data() {
          return num;
        },
        template: &quot;#countview&quot;,
      });
      new Vue({
        el: &quot;#app&quot;,
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>실행 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/b7f13738-35bf-498b-81c4-f535b469a1e7/image.png" alt=""></p>
<p>따라서 각 태그마다 데이터를 관리하게 할 수 있다. 아래 예시를 살펴보자.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;

  &lt;body&gt;
    &lt;h2&gt;컴포넌트 데이터 공유 문제 해결&lt;/h2&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;count-view&gt;&lt;/count-view&gt;
      &lt;count-view&gt;&lt;/count-view&gt;
      &lt;count-view&gt;&lt;/count-view&gt;
    &lt;/div&gt;
    &lt;template id=&quot;countview&quot;&gt;
      &lt;div&gt;
        &lt;span&gt;{{ count }}&lt;/span&gt;
        &lt;button @click=&quot;count++&quot;&gt;클릭&lt;/button&gt;
      &lt;/div&gt;
    &lt;/template&gt;
    &lt;script&gt;
      Vue.component(&quot;count-view&quot;, {
        template: &quot;#countview&quot;,
        data() {
          return {
            count: 0,
          };
        },
      });
      new Vue({
        el: &quot;#app&quot;,
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>실행 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/0b17c0c2-a24c-4ac3-8cdf-cd9257a404c1/image.png" alt=""></p>
<br>

<h3 id="vue는-component-간-통신을-지원한다">Vue는 Component 간 통신을 지원한다.</h3>
<p>Vue는 Component 간 데이터 전달을 지원한다.
부모에서 자식은 props라는 특별한 속성, 자식에서 부모는 event로만 데이터 전달이 가능하다.</p>
<p>부모에서 자식으로 데이터를 전달하는 경우부터 살펴보자. 해당 예시는 아래와 같다.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;

  &lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;h2&gt;props test&lt;/h2&gt;
      &lt;!-- 동적 props --&gt;
      &lt;child-component v-bind:props-data=&quot;message&quot;&gt;&lt;/child-component&gt;
    &lt;/div&gt;
    &lt;script&gt;
      //하위 컴포넌트
      Vue.component(&quot;child-component&quot;, {
        props: [&quot;propsData&quot;],
        template: &quot;&lt;span&gt;{{ propsData }}&lt;/span&gt;&quot;,
      });
      new Vue({
        el: &quot;#app&quot;,
        data() {
          return {
            message: &#39;hello samsung&#39;,
          };
        },
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>원리는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/1d325824-275b-445c-895f-8f813ddc91a1/image.png" alt=""></p>
<p>따라서 출력 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/3ad9be8b-e9e0-4bb5-a828-a61cf02e738b/image.png" alt=""></p>
<p>props로 객체를 전달할 때 객체 이름으로 전체 객체 데이터를 넘길 수 있다. 아래 예시를 살펴보자.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;

  &lt;body&gt;
    &lt;h2&gt;컴포넌트 객체 데이터 전달&lt;/h2&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;member-view v-bind:member=&quot;user&quot;&gt;&lt;/member-view&gt;
    &lt;/div&gt;
    &lt;template id=&quot;memberview&quot;&gt;
      &lt;div&gt;
        &lt;div&gt;이름 : {{ member.name }}&lt;/div&gt;
        &lt;div&gt;나이 : {{ member.age }}&lt;/div&gt;
        &lt;div&gt;이메일 : {{ member.email }}&lt;/div&gt;
      &lt;/div&gt;
    &lt;/template&gt;
    &lt;script&gt;
      Vue.component(&quot;member-view&quot;, {
        props: [&quot;member&quot;],
        template: &quot;#memberview&quot;,
      });
      new Vue({
        el: &quot;#app&quot;,
        data() {
          return {
            user: {
              name: &quot;홍길동&quot;,
              age: 22,
              email: &quot;hong@ssafy.com&quot;,
            },
          };
        },
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>출력 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/fb301d72-edc7-4fe9-8115-703d34836530/image.png" alt=""></p>
<p>다음은 자식에서 부모로 데이터를 전달하는 경우를 살펴보자.
자식은 이벤트를 발생시키기 위해 $emit 메서드를, 부모는 이벤트를 수신하기 위해 $on 메서드를 사용한다.</p>
<p>예시는 아래와 같다.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;

  &lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;h4&gt;당신이 좋아하는 파트를 선택하세요&lt;/h4&gt;
      &lt;h2&gt;총 투표수 : {{ total }}&lt;/h2&gt;
      &lt;subject v-on:add-total-count=&quot;addTotalCount&quot; title=&quot;코딩&quot;&gt;&lt;/subject&gt;
      &lt;subject v-on:add-total-count=&quot;addTotalCount&quot; title=&quot;알고리즘&quot;&gt;&lt;/subject&gt;
    &lt;/div&gt;
    &lt;script&gt;
      Vue.component(&quot;Subject&quot;, {
        template: &#39;&lt;button v-on:click=&quot;addCount&quot;&gt;{{title}} - {{ count }}&lt;/button&gt;&#39;,
        props: [&quot;title&quot;],
        data: function () {
          return {
            count: 0,
          };
        },
        methods: {
          addCount: function () {
            this.count += 1;
            // 부모 v-on:이름 에 해당하는 이름의 이벤트를 호출
            this.$emit(&quot;add-total-count&quot;, &quot;인자도 넘길수 있어요.&quot;); // payload
          },
        },
      });

      new Vue({
        el: &quot;#app&quot;,
        data: {
          total: 0,
        },
        methods: {
          addTotalCount: function (msg) {
            console.log(msg);
            this.total += 1;
          },
        },
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>출력 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/e69ae632-bc88-4213-8b51-29c7b4a254e8/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Vue 1일차]]></title>
            <link>https://velog.io/@jin-chang-ho/Vue-1%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@jin-chang-ho/Vue-1%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Wed, 03 May 2023 00:21:53 GMT</pubDate>
            <description><![CDATA[<h3 id="vue는-mvvm-패턴을-사용한다">Vue는 MVVM 패턴을 사용한다.</h3>
<p>Vue는 Model + View + ViewModel 패턴을 사용한다. 형태는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/d4f1e026-9a50-446c-8939-a2de73d73fbc/image.png" alt="MVVM"></p>
<p>각 요소의 설명은 아래와 같다.</p>
<blockquote>
<ol>
<li>Model : 순수 JS 객체</li>
<li>View : 웹 페이지의 DOM</li>
<li>ViewModel : View와 Model을 연결하고 자동으로 바인딩하여 양방향 통신을 지원</li>
</ol>
</blockquote>
<p>MVC 패턴과 MVVM 패턴의 차이점은 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/1ed6cccd-7142-41dc-bb60-4ecb1281fe0f/image.png" alt=""></p>
<blockquote>
<p>MVC 패턴 : View가 화면 갱신, Model이 데이터 갱신을 수행한다.
MVVM 패턴 : View가 화면 갱신하면 ViewModel이 이를 인식하고 Model에 데이터 갱신을 요청한다.</p>
</blockquote>
<br>

<h3 id="vue는-vue-객체를-생성할-수-있도록-지원한다">Vue는 Vue 객체를 생성할 수 있도록 지원한다.</h3>
<p>Vue 객체의 형태는 아래와 같다.</p>
<pre><code class="language-java">new Vue({
    el: &quot;#app&quot;, // querySelector랑 똑같음
    data() {
        return {
            message: &quot;Hello Vuejs!!!!&quot;,
        };
    },
});</code></pre>
<p>Vuew 객체 속성의 의미는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/5b3cead2-82b8-4ae6-9b5c-6c263f7510b4/image.png" alt=""></p>
<p>Vue 객체의 Life Cycle은 아래와 같다.</p>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/a5f4b487-0f59-4652-be2e-8f9a4dd8170a/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/2697f790-57a9-4884-9267-60836e6d06c0/image.png" alt=""></p>
<p>Life Cycle 속성의 의미는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/08e269f5-5f70-4223-a3c7-a95b096b627a/image.png" alt=""></p>
<p>실제 사용 예시는 아래와 같다.</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;h2&gt;{{message}}&lt;/h2&gt;
    &lt;/div&gt;
    &lt;script&gt;
      new Vue({
        el: &quot;#app&quot;,
        data: {
          message: &quot;Life Cycle Hooks.&quot;,
        },
        beforeCreate() {
          console.log(&quot;beforeCreate!!!&quot;);
        },
        created() {
          console.log(&quot;created!!!&quot;);
        },
        mounted() {
          console.log(&quot;mounted!!!&quot;);
        },
        updated() {
          console.log(&quot;updated!!!&quot;);
        },
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>Console 화면은 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/ff9ad4c5-4749-403f-9e0c-3a9f2c659d4d/image.png" alt=""></p>
<br>

<h3 id="vue는-여러-directive를-지원한다">Vue는 여러 Directive를 지원한다.</h3>
<p>Vue는 기능 지원을 위해 다양한 Directive를 지원한다. 그 종류는 아래와 같다.</p>
<blockquote>
<ol>
<li>v-model : 양방향 바인딩 처리</li>
</ol>
</blockquote>
<p>실행 예시는 아래와 같다.</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;input type=&quot;text&quot; v-model=&quot;msg&quot;/&gt;
      &lt;div&gt;{{msg}}&lt;/div&gt;
    &lt;/div&gt;
    &lt;script&gt;
      let app = new Vue({
        el: &quot;#app&quot;,
        data: {
          msg: &quot;Hello Vue~!&quot;,
        },
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>실행 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/3cbfb3ce-e412-4868-9945-25f2ca1f186b/image.png" alt=""></p>
<p>이 때 input의 값이 바뀌면 div, data의 값도 바뀐다.</p>
<blockquote>
<ol start="2">
<li>v-bind : 엘리먼트의 속성과 바인딩 처리</li>
</ol>
</blockquote>
<p>실행 예시는 아래와 같다.</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;!-- 속성을 바인딩 합니다. --&gt;
      &lt;div v-bind:id=&quot;idValue&quot;&gt;v-bind 지정 연습&lt;/div&gt;
      &lt;button v-bind:[key]=&quot;btnId&quot;&gt;버튼&lt;/button&gt;

      &lt;!-- 약어를 이용한 바인딩. 주로 이걸 사용 --&gt;
      &lt;div :id=&quot;idValue&quot;&gt;v-bind 지정 연습&lt;/div&gt;
      &lt;button :[key]=&quot;btnId&quot;&gt;버튼&lt;/button&gt;&lt;br /&gt;

      &lt;a v-bind:href=&quot;link1&quot;&gt;삼성&lt;/a&gt;
      &lt;a :href=&quot;link2&quot;&gt;네이버&lt;/a&gt;
    &lt;/div&gt;
    &lt;script&gt;
      new Vue({
        el: &quot;#app&quot;,
        data: {
          idValue: &quot;test-id&quot;,
          key: &quot;class&quot;,
          btnId: &quot;btn1&quot;,
          link1: &quot;http://www.samsung.com&quot;,
          link2: &quot;http://www.naver.com&quot;,
        },
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>실행 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/17fa061a-21ca-46ad-a872-0a677d3fd900/image.png" alt=""></p>
<blockquote>
<ol start="3">
<li>v-show : 조건에 따라 엘리먼트를 출력한다.</li>
</ol>
</blockquote>
<p>실행 예시는 아래와 같다.</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;div v-show=&quot;isShow&quot;&gt;{{msg}}&lt;/div&gt;
    &lt;/div&gt;
    &lt;script&gt;
      new Vue({
        el: &quot;#app&quot;,
        data: {
          isShow: true,
          msg: &quot;보이나요?&quot;,
        },
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>isShow가 true일 때 출력은 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/7c89ad8b-7d02-4977-b542-efd0dadb20f9/image.png" alt=""></p>
<p>isShow가 false일 때 출력을 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/6f010d2c-fd24-4b65-ac69-fb62439b77e4/image.png" alt=""></p>
<p>이 때, msg는 렌더링이 된다는 점을 기억하자. </p>
<blockquote>
<ol start="4">
<li>v-if, v-else-if, v-else : 조건에 따라 엘리먼트를 화면에 렌더링</li>
</ol>
</blockquote>
<p>실행 예시는 아래와 같다.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;div&gt;
        &lt;span&gt;나이 : &lt;/span&gt;
        &lt;input type=&quot;number&quot; v-model=&quot;age&quot;/&gt;
      &lt;/div&gt;
      &lt;div&gt;
        요금 :
        &lt;span v-if=&quot;age &lt; 10&quot;&gt;무료&lt;/span&gt;
        &lt;span v-else-if=&quot;age &lt; 30&quot;&gt;7000원&lt;/span&gt;
        &lt;span v-else-if=&quot;age &lt; 60&quot;&gt;10000원&lt;/span&gt;
        &lt;span v-else&gt;3000원&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;script&gt;
      const vm = new Vue({
        el: &quot;#app&quot;,
        data: {
          age: 0,
        },
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>실행 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/d06a88f1-7058-438f-86ef-63464a9a32b5/image.png" alt=""></p>
<blockquote>
<ol start="5">
<li>v-for : 배열이나 객체의 반복</li>
</ol>
</blockquote>
<p>실행 예시는 아래와 같다.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;!-- 범위 반복문, 배열 반복문 처리 --&gt;
    &lt;h2&gt;v-for&lt;/h2&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;h2&gt;범위지정(4)&lt;/h2&gt;
      &lt;span v-for=&quot;i in 4&quot;&gt; {{i}} &lt;/span&gt;

      &lt;h2&gt;문자열 배열&lt;/h2&gt;
      &lt;ul&gt;
        &lt;li v-for=&quot;name in regions&quot;&gt;{{name}}&lt;/li&gt;
      &lt;/ul&gt;

      &lt;h2&gt;문자열 배열 - 위치&lt;/h2&gt;
      &lt;ul&gt;
        &lt;li v-for=&quot;(name, i) in regions&quot;&gt;번호 : {{i}}, 지역 : {{name}}&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/div&gt;
    &lt;script&gt;
      new Vue({
        el: &quot;#app&quot;,
        data: {
          regions: [&quot;광주&quot;, &quot;구미&quot;, &quot;대전&quot;, &quot;서울&quot;, &quot;부울경&quot;],
        },
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>실행 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/a1bdf0f8-5eae-41b1-a643-54125e8fdd24/image.png" alt=""></p>
<blockquote>
<ol start="6">
<li>template : 여러 개의 태그들을 묶어서 처리</li>
</ol>
</blockquote>
<p>실행 예시는 아래와 같다.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Vue.js&lt;/title&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h2&gt;template 태그 사용하기&lt;/h2&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;label&gt;반수 : &lt;/label&gt;
      &lt;input type=&quot;number&quot; v-model.number=&quot;count&quot; /&gt;
      &lt;template v-if=&quot;count % 2 == 0&quot;&gt;
        &lt;h4&gt;여러개의 태그를 묶어서 처리해야 한다면??&lt;/h4&gt;
        &lt;h4&gt;template 태그를 사용해 보자&lt;/h4&gt;
        &lt;h4&gt;만약에 template가 없다면?? 각태그마다 v-if?&lt;/h4&gt;
      &lt;/template&gt;
      &lt;template v-for=&quot;(region, index) in samsung&quot; v-if=&quot;region.count === count&quot;&gt;
        &lt;h3&gt;지역 : {{region.name}} ({{region.count}}개반)&lt;/h3&gt;
      &lt;/template&gt;
    &lt;/div&gt;
    &lt;script&gt;
      new Vue({
        el: &quot;#app&quot;,
        data: {
          count: 0,
          show: false,
          samsung: [
            {
              name: &quot;광주&quot;,
              count: 2,
            },
            {
              name: &quot;구미&quot;,
              count: 2,
            },
            {
              name: &quot;대전&quot;,
              count: 3,
            },
            {
              name: &quot;서울&quot;,
              count: 12,
            },
            {
              name: &quot;부울경&quot;,
              count: 2,
            },
          ],
        },
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>실행 결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/32f26830-a41e-49f6-a129-d4b67b673f84/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring 7일차]]></title>
            <link>https://velog.io/@jin-chang-ho/Spring-7%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@jin-chang-ho/Spring-7%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 27 Apr 2023 00:12:22 GMT</pubDate>
            <description><![CDATA[<h3 id="springboot는-spring을-더-편하게-쓰도록-지원한다">SpringBoot는 Spring을 더 편하게 쓰도록 지원한다.</h3>
<p>SpringBoot의 특징은 아래와 같다.</p>
<blockquote>
<ol>
<li>자주 사용되는 library들이 미리 조합되어 있다.</li>
<li>xml 같은 복잡한 설정을 자동으로 처리한다.</li>
<li>내장 서버를 포함해서 tomcat같은 WAS를 추가로 설치하지 않아도 개발 가능하다.</li>
<li>JAR 파일로 Web Application을 개발할 수 있다.</li>
</ol>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring 6일차]]></title>
            <link>https://velog.io/@jin-chang-ho/Spring-6%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@jin-chang-ho/Spring-6%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Wed, 26 Apr 2023 01:09:07 GMT</pubDate>
            <description><![CDATA[<h3 id="spring은-rest-api를-지원한다">Spring은 REST API를 지원한다.</h3>
<p>OPEN API는 프로그래밍에서 사용할 수 있는 개방되어 있는 상태의 인터페이스이다.
대부분의 OPEN API는 REST 방식으로 지원된다.</p>
<p>REST는 Representational State Transfer의 약어로, 개념은 아래와 같다.</p>
<blockquote>
<p>하나의 URI는 하나의 고유한 리소스를 대표하도록 설계 + 전송방식 -&gt; 원하는 작업 지정</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/f88dad67-512c-4cb3-8a99-139a92e941d7/image.png" alt=""></p>
<p>REST의 구성은 아래와 같다.</p>
<blockquote>
<ol>
<li>자원 : URI(JSON, XML)</li>
<li>행위 : 전송방식(HTTP Method)</li>
<li>표현 </li>
</ol>
</blockquote>
<p>기존 Service와 REST Service의 차이는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/6d25ebc9-66bb-40d8-b349-305a4204b57e/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/f6cf8e6e-241a-4f76-9eac-8929db6b1a57/image.png" alt=""></p>
<p>REST Service는 기본 Service와 달리 View에 대한 신경 쓸 필요없이 반환될 데이터만 JSON이나 XML로 전달하면 된다.
또한, 기본 Service는 GET과 POST만으로 자원에 대한 CRUD를 처리하고, URI는 액션을 나타낸다. 하지만 Rest Service는 GET, POST, PUT, DELETE를 사용하여 CRUD를 처리하고, URI는 제어하려는 자원을 나타낸다.</p>
<p>REST는 정해진 표준이 없고 관습적인 표준만 존재한다. 내용은 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/83daafc7-6b52-475c-b70b-c4748a0b85ed/image.png" alt=""></p>
<p>REST 관련 Annotation은 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/e2ab1e34-070d-41bc-8766-7a433ff29b4c/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring 5일차]]></title>
            <link>https://velog.io/@jin-chang-ho/Spring-5%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@jin-chang-ho/Spring-5%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Tue, 25 Apr 2023 01:04:40 GMT</pubDate>
            <description><![CDATA[<h3 id="spring은-mybatis를-지원한다">Spring은 MyBatis를 지원한다.</h3>
<p>MyBatis를 사용하는 Data Access Layer는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/0caf3b17-c9d6-410c-ab84-56bb26c628ae/image.png" alt="MyBatis"></p>
<p>MyBatis-Spring의 주요 컴포넌트의 역할은 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/59decd38-21ea-48c9-b8b4-57edad7e5c90/image.png" alt=""></p>
<p>주요 컴포넌트의 설명은 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/48b5236c-55fc-407d-99f7-88b26be3ec96/image.png" alt=""></p>
<p>Spring에서 Tomcat 서버를 연결할 때 아래와 같은 설정을 거친다.
Tomcat -&gt; server.xml -&gt; context.xml -&gt; web.xml -&gt; root-context.xml -&gt; member.xml -&gt; ...
주요 사항만 알아보자.</p>
<blockquote>
<ol>
<li>context.xml</li>
</ol>
</blockquote>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;Context&gt;
    &lt;Resource name=&quot;jdbc/samsung&quot; auth=&quot;Container&quot; type=&quot;javax.sql.DataSource&quot; 
            maxTotal=&quot;100&quot; maxIdle=&quot;30&quot; maxWaitMillis=&quot;10000&quot; 
            username=&quot;samsung&quot; password=&quot;samsung&quot; driverClassName=&quot;com.mysql.cj.jdbc.Driver&quot;     
            url=&quot;jdbc:mysql://localhost:3306/samsungweb?serverTimezone=UTC&amp;amp;useUniCode=yes&amp;amp;characterEncoding=UTF-8&quot;/&gt; 
    &lt;WatchedResource&gt;WEB-INF/web.xml&lt;/WatchedResource&gt;
&lt;/Context&gt;</code></pre>
<p>현재까진 클라이언트가 필요로 하면 DB에 연결해 DataSource를 만들었다.
이제는 DB 연결을 톰캣에게 맡겨 DB를 미리 연결해둔다. 따라서 DataSource를 미리 만든다.</p>
<blockquote>
<ol start="2">
<li>root-context.xml</li>
</ol>
</blockquote>
<pre><code class="language-xml">&lt;bean id=&quot;dataSource&quot; class=&quot;org.springframework.jndi.JndiObjectFactoryBean&quot;&gt;
    &lt;property name=&quot;jndiName&quot; value=&quot;java:comp/env/jdbc/samsung&quot;&gt;&lt;/property&gt;
&lt;/bean&gt;</code></pre>
<p>가져올 DataSource는 java:comp/env/jdbc/samsung 안에 있는 걸 알려준다.</p>
<pre><code class="language-xml">&lt;bean id=&quot;sqlSessionFactoryBean&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:mybatis-config.xml&quot;/&gt;
    &lt;property name=&quot;mapperLocations&quot;&gt;
        &lt;list&gt;
            &lt;value&gt;classpath:mapper/member.xml&lt;/value&gt;
        &lt;/list&gt;
    &lt;/property&gt;
&lt;/bean&gt;</code></pre>
<p>sqlSessionFactoryBean을 만든다. 이 때, DB, mybatis, mapper 정보를 넘겨준다.</p>
<pre><code class="language-xml">&lt;bean id=&quot;sqlSession&quot; class=&quot;org.mybatis.spring.SqlSessionTemplate&quot;&gt;
    &lt;constructor-arg ref=&quot;sqlSessionFactoryBean&quot;&gt;&lt;/constructor-arg&gt;
&lt;/bean&gt;</code></pre>
<p>sqlSession을 만든다.</p>
<blockquote>
<ol start="3">
<li>member.xml (mapper)</li>
</ol>
</blockquote>
<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;com.samsung.member.model.mapper.MemberMapper&quot;&gt;

    &lt;resultMap type=&quot;memberDto&quot; id=&quot;member&quot;&gt;
        &lt;result column=&quot;user_id&quot; property=&quot;userId&quot;/&gt;
        &lt;result column=&quot;user_name&quot; property=&quot;userName&quot;/&gt;
    &lt;/resultMap&gt;

    &lt;select id=&quot;idCheck&quot; parameterType=&quot;String&quot; resultType=&quot;int&quot;&gt;
        select count(user_id)
        from members
        where user_id = #{userid}
    &lt;/select&gt;

    &lt;insert id=&quot;joinMember&quot; parameterType=&quot;memberDto&quot;&gt;
        insert into members (user_name, user_id, user_password, email_id, email_domain, join_date)
        values (#{userName}, #{userId}, #{userPwd}, #{emailId}, #{emailDomain}, now())
    &lt;/insert&gt;

    &lt;select id=&quot;loginMember&quot; parameterType=&quot;map&quot; resultMap=&quot;member&quot;&gt;
        select user_id, user_name
        from members
        where user_id = #{userid} and user_password = #{userpwd}
    &lt;/select&gt;

&lt;/mapper&gt;</code></pre>
<p>mapper의 sql을 정의한다.</p>
<blockquote>
<ol start="4">
<li>MemberServiceImpl.java</li>
</ol>
</blockquote>
<pre><code class="language-java">import java.util.Map;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.samsung.member.model.MemberDto;
import com.samsung.member.model.mapper.MemberMapper;

@Service
public class MemberServiceImpl implements MemberService {
    private SqlSession sqlSession;

    @Autowired
    public MemberServiceImpl(SqlSession sqlSession) {
        super();
        this.sqlSession = sqlSession;
    }

    @Override
    public int idCheck(String userId) throws Exception {
        return sqlSession.getMapper(MemberMapper.class).idCheck(userId);
    }

    @Override
    public void joinMember(MemberDto memberDto) throws Exception {
        sqlSession.getMapper(MemberMapper.class).joinMember(memberDto);
    }

    @Override
    public MemberDto loginMember(Map&lt;String, String&gt; map) throws Exception {
        return sqlSession.getMapper(MemberMapper.class).loginMember(map);
    }
}</code></pre>
<p>sqlSession에서 설정된 함수를 실제로 실행한다.</p>
<br>

<h3 id="spring은-mapper-interface를-지원한다">Spring은 Mapper Interface를 지원한다.</h3>
<p>Mapper Interface는 mapping 파일에 기재된 SQL을 호출하는 Interface이다.
이를 사용하면 위의 예제에서 바뀌는 부분은 아래와 같다.</p>
<blockquote>
<ol>
<li>root-context.xml</li>
</ol>
</blockquote>
<pre><code class="language-xml">&lt;bean id=&quot;sqlSessionFactoryBean&quot; class=&quot;org.mybatis.spring.SqlSessionFactoryBean&quot;&gt;
  &lt;property name=&quot;dataSource&quot; ref=&quot;dataSource&quot;/&gt;
  &lt;property name=&quot;typeAliasesPackage&quot; value=&quot;com.samsung.*.model&quot;/&gt; &lt;!-- Alias 지정 가능 --&gt;
  &lt;property name=&quot;mapperLocations&quot; value=&quot;classpath:mapper/*.xml&quot;/&gt;
&lt;/bean&gt;</code></pre>
<blockquote>
<ol start="2">
<li>MemberServiceImpl.java</li>
</ol>
</blockquote>
<pre><code class="language-xml">import java.util.Map;

import org.springframework.stereotype.Service;

import com.samsung.member.model.MemberDto;
import com.samsung.member.model.mapper.MemberMapper;

@Service
public class MemberServiceImpl implements MemberService {
    private MemberMapper memberMapper;

    public MemberServiceImpl(MemberMapper memberMapper) {
        super();
        this.memberMapper = memberMapper;
    }

    @Override
    public int idCheck(String userId) throws Exception {
        return memberMapper.idCheck(userId);
    }

    @Override
    public void joinMember(MemberDto memberDto) throws Exception {
        memberMapper.joinMember(memberDto);
    }

    @Override
    public MemberDto loginMember(Map&lt;String, String&gt; map) throws Exception {
        return memberMapper.loginMember(map);
    }
}</code></pre>
<br> 

<h3 id="spring은-transaction-관리를-지원한다">Spring은 transaction 관리를 지원한다.</h3>
<p>Spring은 자동 트랜잭션 관리를 지원한다. 해당 코드는 아래와 같다.</p>
<pre><code>&lt;!-- root-context.xml --&gt;

&lt;bean id=&quot;transactionManager&quot; class=&quot;org.springframework.jdbc.datasource.DataSourceTransactionManager&quot;&gt;
    &lt;property name=&quot;dataSource&quot; ref=&quot;dataSource&quot; /&gt;
&lt;/bean&gt;

&lt;tx:annotation-driven transaction-manager=&quot;transactionManager&quot;/&gt;</code></pre><p>Exception이 일어나면 rollback, 일어나지 않으면 commit을 자동으로 수행한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring 4일차]]></title>
            <link>https://velog.io/@jin-chang-ho/Spring-4%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@jin-chang-ho/Spring-4%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Mon, 24 Apr 2023 06:40:03 GMT</pubDate>
            <description><![CDATA[<h3 id="spring은-file-upload를-지원한다">Spring은 File Upload를 지원한다.</h3>
<p>File Upload를 하기 위해선 몇 개의 추가 기능을 넣어줘야 한다. 그 기능은 아래와 같다.</p>
<blockquote>
<ol>
<li>pom.xml : commons-fileupload Library 추가</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/48fc5097-3987-4b1d-a29b-4fa88f87a521/image.png" alt="그림"></p>
<blockquote>
<ol start="2">
<li>servlet-context.xml : property 추가</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/bce7ae03-61cb-4d47-8b34-dadd1eefd13a/image.png" alt=""></p>
<ol>
<li>maxUploadSize : 최대 업로드 가능한 파일의 바이트 크기</li>
<li>maxInMemorySize : 디스크에 임시 파일을 생성하기 전 메모리에 보관할 수 있는 최대 바이트 크기</li>
</ol>
<blockquote>
<ol start="3">
<li>write.jsp : form 설정</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/b17ba701-347f-4244-94ba-b7c24ab72012/image.png" alt=""></p>
<blockquote>
<ol start="4">
<li>BoardDto.java : 멤버변수 추가</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/70a7b471-8c3a-4457-95b3-4ed4d38867c9/image.png" alt=""></p>
<blockquote>
<ol start="5">
<li>FileInfoDto.java : 멤버변수 추가</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/0d278e92-d7d8-4e9f-9e07-a1c7e51768bf/image.png" alt=""></p>
<ol>
<li>saveFolder : 저장된 폴더</li>
<li>originFile : 원본 파일의 이름</li>
<li>saveFile : 실제 저장된 파일의 이름</li>
</ol>
<blockquote>
<ol start="6">
<li>BoardServiceImpl.java : 전체적인 수정</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/4d021674-990f-4489-adfb-883b9328efd9/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/9007c52b-f66e-498d-9118-ef074194f88d/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/80806f02-fae4-43ef-af25-7e3e53374356/image.png" alt=""></p>
<p>mfile.transferTo가 일어난 시점부터 사용자의 컴퓨터에 파일이 저장된다. 
그리고 DB에는 파일의 이름만 저장된다.</p>
<ol start="7">
<li>board.xml : 전체적인 수정</li>
</ol>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/1ca471ac-077a-4d2b-8a31-fb10725092ed/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/df74acde-6b83-4b6f-a544-50bebed6c0c0/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/d57cc1cf-69bd-4e16-8bb3-8a399ef822d3/image.png" alt=""></p>
<br>

<h3 id="spring은-file-download를-지원한다">Spring은 File Download를 지원한다.</h3>
<p>File Download를 하기 위해선 몇 개의 추가 기능을 넣어줘야 한다. 그 기능은 아래와 같다.</p>
<blockquote>
<ol>
<li>list.jsp</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/a57ee966-c1e4-4d5c-83c8-c1c4cea9d53e/image.png" alt=""></p>
<blockquote>
<ol start="2">
<li>servlet-context.xml </li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/819fc9cd-4592-487a-96ba-513da42642d4/image.png" alt=""></p>
<blockquote>
<ol start="3">
<li>BoardController.java</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/19e4bfc5-e049-4287-aa6a-cc3c203b06de/image.png" alt=""></p>
<blockquote>
<ol start="4">
<li>FileDownLoadView.java</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/22c602a3-afac-45c9-8e61-6dbf084a5b98/image.png" alt=""></p>
<br>

<h3 id="spring은-interceptor를-지원한다">Spring은 Interceptor를 지원한다.</h3>
<p>실제 비즈니스 로직과는 분리되어 처리해야 하는 기능들을 넣을 때 Interceptor를 이용한다.
비슷한 기능으론 Filter와 AOP가 있다. 차이점은 아래와 같다.</p>
<blockquote>
<p>Filter : Servlet Context -&gt; Dispatcher Servlet에 적용됨.
Intercept : Handler Adapter -&gt; Controller에 적용됨.
AOP : Controller -&gt; Model에 적용됨.</p>
</blockquote>
<p>Interceptor를 사용하기 위해선 HandlerInterceptor를 상속받아야 한다.
HandlerInterceptor가 제공하는 메서드는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/7485159a-0027-47dd-9417-5d04b075adbf/image.png" alt="해당 메서드"></p>
<p>각 메서드의 차이점은 아래 그림을 참고하자.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/7bebe51a-5895-4403-b4fa-ba92ef9f1547/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring 3일차]]></title>
            <link>https://velog.io/@jin-chang-ho/Spring-3%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@jin-chang-ho/Spring-3%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Wed, 19 Apr 2023 00:01:56 GMT</pubDate>
            <description><![CDATA[<h3 id="spring은-mvc-pattern을-지원한다">Spring은 MVC Pattern을 지원한다.</h3>
<p>MVC Pattern은 확장성을 위한 웹 구조이다. 자세한 내용은 <a href="https://velog.io/@jin-chang-ho/BackEnd-3%EC%9D%BC%EC%B0%A8">해당 링크</a>를 참고하자.</p>
<p>Spring MVC의 구성요소는 아래와 같다.</p>
<blockquote>
<ol>
<li>DispatcherServlet</li>
</ol>
</blockquote>
<p>모든 클라이언트의 요청을 전달받는다.
Controller에게 Client의 요청을 전달하고, Controller가 리턴한 결과값을 View에게 전달하여 알맞은 응답을 생성한다.</p>
<blockquote>
<ol start="2">
<li>HandlerMapping</li>
</ol>
</blockquote>
<p>클라이언트의 요청 URL을 어떤 Controller가 처리할지를 결정한다.</p>
<blockquote>
<ol start="3">
<li>Controller</li>
</ol>
</blockquote>
<p>클라이언트의 요청을 처리한 뒤, Model을 호출하고 그 결과를 DispatcherServlet에 알려준다.</p>
<blockquote>
<ol start="4">
<li>ModelAndView</li>
</ol>
</blockquote>
<p>Controller가 처리한 데이터 및 화면에 대한 정보를 보유한 객체</p>
<blockquote>
<ol start="5">
<li>ViewResolver</li>
</ol>
</blockquote>
<p>Controller가 리턴한 뷰 이름을 기반으로 Controller의 처리 결과를 보여줄 View를 결정한다.</p>
<blockquote>
<ol start="6">
<li>View</li>
</ol>
</blockquote>
<p>Controller의 처리결과를 보여줄 응답하면을 생성한다.</p>
<p>아래는 Spring MVC 요청 흐름을 보여준다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/abb317a1-c51e-4a4e-b51d-cf7a5a4e6094/image.png" alt="Spring MVC 요청 흐름"></p>
<p>2, 3번 과정과 6, 7번 과정은 Spring에서 자동으로 해준다.
5번 과정에서 String을 리턴하기도 한다.</p>
<br>

<h3 id="spring-mvc의-동작-원리는-체계적이다">Spring MVC의 동작 원리는 체계적이다.</h3>
<p>Spring MVC의 동작 원리는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/def06c39-8f2a-43f6-8b51-76ed80ca8312/image.png" alt="Spring MVC의 동작 원리"></p>
<p>해당 과정은 web.xml로 설정할 수 있다. web.xml의 예시는 아래와 같다.</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt; &lt;!-- 1번 과정 --&gt;
&lt;web-app version=&quot;2.5&quot; xmlns=&quot;http://java.sun.com/xml/ns/javaee&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&quot;&gt;

    &lt;!-- The definition of the Root Spring Container shared by all Servlets and Filters --&gt; 
    &lt;context-param&gt;
        &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt; 
        &lt;param-value&gt;/WEB-INF/spring/root-context.xml&lt;/param-value&gt; &lt;!-- 3번 과정 --&gt;
    &lt;/context-param&gt;

    &lt;!-- Creates the Spring Container shared by all Servlets and Filters --&gt;
    &lt;listener&gt; 
        &lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt; &lt;!-- 2번 과정 --&gt;
    &lt;/listener&gt;

    &lt;!-- Processes application requests --&gt;
    &lt;servlet&gt;
        &lt;servlet-name&gt;appServlet&lt;/servlet-name&gt;
        &lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt;
        &lt;init-param&gt;
            &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt; &lt;!-- 7번 과정 --&gt;
            &lt;param-value&gt;/WEB-INF/spring/appServlet/servlet-context.xml&lt;/param-value&gt;
        &lt;/init-param&gt;
        &lt;load-on-startup&gt;1&lt;/load-on-startup&gt; &lt;!-- 이 줄 때문에 WAS가 실행될 때 DispatcherServlet가 같이 생성됨. --&gt; &lt;!-- 따라서 6번 과정은 생략됨. --&gt;

    &lt;/servlet&gt;

    &lt;servlet-mapping&gt;
        &lt;servlet-name&gt;appServlet&lt;/servlet-name&gt; &lt;!-- 5번 과정 --&gt;
        &lt;url-pattern&gt;/&lt;/url-pattern&gt; &lt;!-- / 이하의 모든 걸 받는다는 의미 --&gt;
    &lt;/servlet-mapping&gt;
&lt;/web-app&gt;

&lt;!-- 4번 과정은 개발자가 Service, DAO 등 로직을 만듦. --&gt;
&lt;!-- 8번 과정은 DispatcherServlet이 적절한 Controller가 실행됨. --&gt;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring 2일차]]></title>
            <link>https://velog.io/@jin-chang-ho/Spring-2%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@jin-chang-ho/Spring-2%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Mon, 17 Apr 2023 23:50:56 GMT</pubDate>
            <description><![CDATA[<h3 id="spring은-aop를-지원한다">Spring은 AOP를 지원한다.</h3>
<p>AOP가 주목하는 관심 사항은 아래와 같다.</p>
<blockquote>
<ol>
<li>핵심 관심 사항 : 문제를 해결하기 위함. </li>
<li>공통 관심 사항 : 전체에 적용하기 위함.</li>
</ol>
</blockquote>
<p>이 때, 공통 관심 사항을 Aspect라는 독특한 모듈 형태로 사용함으로써 객체지향적인 개념을 지키는 것이 AOP의 핵심 기능이다.</p>
<p>AOP는 아래와 같은 상황에 적용된다.</p>
<blockquote>
<p>메서드 성능 검사, 트랜잭션 처리, 예외 반환 등</p>
</blockquote>
<br>

<h3 id="spring은-aop의-일부를-지원한다">Spring은 AOP의 일부를 지원한다.</h3>
<p>Spring에서 알아야 할 AOP 용어는 아래와 같다.</p>
<blockquote>
<ol>
<li>Target : 부가기능을 부여할 대상. 핵심 기능을 담고 있는 모듈.</li>
<li>Advice : 어느 시점에 어떤 Aspect를 적용할 지 정의한 것.</li>
<li>JoinPoint : Aspect가 적용될 수 있는 지점. Target이 구현한 모든 메서드는 JoinPoint</li>
<li>PointCut : Aspect가 적용될 JoinPoint</li>
<li>Aspect(Advice + PointCut) : 여러 객체에서 적용되는 공통 관심 사항. Singleton 형태</li>
<li>Advisor(Advice + PointCut) : Spring에서만 사용되는 Aspect의 특별한 용어.</li>
<li>Weaving : PointCut에 Advice를 삽입하는 과정.</li>
</ol>
</blockquote>
<p>PointCut 표현식은 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/40964ee9-1cac-4cd2-97fd-c21946ecaa2b/image.png" alt="PointCut 표현식"></p>
<p>Execution 표현식은 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/9c8f64c7-d121-42d6-be10-e6d4896ac143/image.png" alt="Execution 표현식"></p>
<p>Execution 표현식의 예시는 아래와 같다.</p>
<pre><code>&lt;aop:pointcut id=&quot;pointCut&quot; expression=&quot;execution(public * entity.Person.*(..))&gt;&quot;</code></pre><p>이는 entity 패키지에 있는 Person 클래스의 접근 제한자가 public인 모든 메서드를 의미한다.</p>
<p>package에서 .은 해당 package만, ..은 해당 package와 하위 package까지 가리킨다.
class에서 +는 해당 class를 구현한 자식 class를 가리킨다.
method .. 은 매개변수에 영향을 받지 않고 모든 method를 가리킨다.</p>
<p>기존 프로그래밍과 AOP 프로그래밍의 차이는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/74223737-5b68-4acd-9aa4-3d040dea28b5/image.png" alt=""></p>
<p>Spring에서 사용하는 AOP의 특징은 아래와 같다.</p>
<blockquote>
<ol>
<li>Proxy 기반 AOP</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/52a4324b-5313-4098-987f-7fcbb3161583/image.png" alt="">
Proxy는 Advice를 Target 객체에 적용하면서 생성되는 객체이다. 
따라서 Proxy는 런타임에 생성된다.</p>
<blockquote>
<ol start="2">
<li>Intercept (Proxy가 호출을 가로챔)</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/47c8c5fb-09ad-4cfc-b5b3-0214282dcf05/image.png" alt=""></p>
<p>(전처리 Advice)
Proxy는 Target 객체에 대한 호출을 가로챈 다음 Advice의 부가기능 로직을 수행한다.
그 후, Target의 핵심기능 로직을 호출한다.</p>
<p>(후처리 Advice)
또는 Target의 핵심기능 로직을 호출한 후 Advice의 부가기능 로직을 수행한다.</p>
<blockquote>
<ol start="3">
<li>method JoinPoint만 지원</li>
</ol>
</blockquote>
<p>Target의 Method가 호출되는 Runtime에만 Advice를 적용할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring 1일차]]></title>
            <link>https://velog.io/@jin-chang-ho/Spring-1%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@jin-chang-ho/Spring-1%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Mon, 17 Apr 2023 01:26:11 GMT</pubDate>
            <description><![CDATA[<h3 id="spring은-framework이다">Spring은 Framework이다.</h3>
<p>Framework란 엔터프라이즈 급 애플리케이션을 만들기 위한 모든 기능을 종합적으로 제공하는 경량화된 솔루션이다.</p>
<p>Spring Framework란 자바로 엔터프라이즈 애플리케이션을 만들 때 포괄적으로 사용하는 프로그래밍 및 컨피그레이션 모델을 제공해 주는 Framework이다.</p>
<p>아래는 Spring 삼각형이다. 이를 통해 Spring Framework의 구조를 파악해보자.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/c224a8fa-c4ce-4598-b367-08b6e6cc8cf3/image.png" alt="Spring"></p>
<blockquote>
<ol>
<li>POJO(Plain Old Java Object)</li>
</ol>
</blockquote>
<p>객체지향적인 원리에 충실하면서, 환경과 기술에 종속되지 않고 필요에 따라 재활용될 수 있는 방식으로 설계된 오브젝트이다.</p>
<blockquote>
<ol start="2">
<li>PSA(Portable Service Abstraction)</li>
</ol>
</blockquote>
<p>환경의 변화와 관계없이 일관된 방식의 기술로의 접근 환경을 제공하는 추상화 구조이다.
즉, 잘 만든 인터페이스를 의미한다.</p>
<blockquote>
<ol start="3">
<li>IoC(Inversion of Control) / DI(Dependency Injection)</li>
</ol>
</blockquote>
<p>IoC란 객체 간의 관계가 느슨하게 연결됨을 의미한다. 이를 구현하는 방법 중 하나가 DI 이다.</p>
<blockquote>
<ol start="4">
<li>AOP(Aspect-Oriented Programming)</li>
</ol>
</blockquote>
<p>OOP를 돕는 보조적인 기술로, 기능 분리의 문제를 해결하기 위해 만들어진 프로그래밍 패러다임이다.</p>
<p>Spring Framework의 모듈은 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/0c3f0820-fe01-444f-a52a-37dd47b0a83c/image.png" alt="Spring 모듈"></p>
<p>각 모듈의 설명은 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/1ef9fa58-4daf-4449-b6a7-4d907dd38118/image.png" alt="Spring 설명"></p>
<p>※ Framework와 Library의 차이는 아래와 같다.</p>
<blockquote>
<p>Framework는 프레임워크가 제어권을 가지지만, Library는 개발자가 제어권을 가진다.</p>
</blockquote>
<br>

<h3 id="spring은-ioc--di를-지원한다">Spring은 IoC / DI를 지원한다.</h3>
<p>IoC란 객체 간의 관계가 느슨하게 연결됨을 의미한다. 
IoC의 유형은 아래와 같다. 하나씩 살펴보자.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/b6254cdd-6b7e-4e88-bd13-581f6892aaf7/image.png" alt="IoC의 유형"></p>
<blockquote>
<ol>
<li>Dependency Lookup</li>
</ol>
</blockquote>
<p>컨테이너가 lookup context를 통해서 필요한 자원이나 오브젝트를 얻는 방식이다.
그 중 대표적인 방식이 JNDI이다.</p>
<blockquote>
<ol start="2">
<li>Dependency Injection</li>
</ol>
</blockquote>
<p>Object에 lookup 코드를 사용하지 않고 컨테이너가 직접 의존 구조를 Object에 설정한다.
setter 삽입, 생성자 삽입, 함수 삽입 방식이 존재한다.</p>
<p>IoC를 지원하는 데 컨테이너가 반드시 필요하다. 컨테이너의 정의는 아래와 같다.</p>
<blockquote>
<p>객체의 생성, 사용, 소멸에 해당하는 생명주기를 관리하는 컴포넌트이다.</p>
</blockquote>
<p>그 중 Spring DI 컨테이너는 빈이라는 객체의 생명주기를 관리한다. 그래서 빈팩토리라고도 한다. 빈팩토리에 여러 가지 컨테이너 기능을 추가하여 ApplicationContext라고 한다. 
자세한 내용은 아래 그림을 참고하자.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/ef3fdecc-2ad7-40d6-ae7b-5daa9af09011/image.png" alt="빈팩토리"></p>
<p>빈팩토리와 ApplicationContext의 상속 관계는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/b7d1dac2-2f39-46ef-972c-f53970cb1dbb/image.png" alt="빈팩토리"></p>
<br>

<h3 id="spring은-빈에-대한-여러-설정을-지원한다">Spring은 빈에 대한 여러 설정을 지원한다.</h3>
<p>스프링에서 빈에 대한 설정은 생성범위, 아이디 등 다양하다.</p>
<p>스프링에서 빈에 대한 설정은 3가지 방법으로 가능하다.</p>
<blockquote>
<ol>
<li>XML 문서</li>
<li>Annotation</li>
<li>Java 코드</li>
</ol>
</blockquote>
<p>하나씩 살펴보자.</p>
<br>

<h3 id="spring은-xml-문서로-빈에-대한-설정을-할-수-있다">Spring은 XML 문서로 빈에 대한 설정을 할 수 있다.</h3>
<p>App에서 사용할 Spring 자원들을 설정하는 파일이 XML 문서이다.
Root tag는 &lt;<inline>beans</inline>&gt;이며 파일명은 상관없으나 applicationContext.xml을 권장한다.
아래 사진을 참고하자.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/54424944-173f-4aa2-ad01-5074bb5db507/image.png" alt="XML 문서"></p>
<p>빈 객체 생성 및 주입은 &lt;<inline>bean</inline>&gt; 태그를 통해 이루어진다. 아래 사진을 참고하자.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/952e9ffb-451f-4795-875f-62d5ddf176c2/image.png" alt="빈 객체 생성 및 주입"></p>
<p>기본 속성의 의미는 아래와 같다.</p>
<blockquote>
<p>name : 주입 받을 곳에서 호출할 이름 설정
id : 주입 받을 곳에서 호출할 유일한 이름 설정
class : 주입할 객체의 클래스
scope : 생성 범위 설정. 기본값은 singleton</p>
</blockquote>
<p>scope의 종류는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/32961e01-49fe-440d-a710-2b099a371121/image.png" alt="scope의 종류"></p>
<p>설정한 빈을 java 파일에서 가져오는 방법은 아래와 같다.</p>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/0585d4dc-127f-4985-ad06-95e9802493d0/image.png" alt="빈 가져오기"></p>
<p>스프링 빈의 의존 관계를 설정할 땐 2가지 방법을 사용한다.</p>
<p>첫번째 방법은 생성자를 통해 의존 관계를 설정하는 방법이다. 아래 예시를 살펴보자.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/2fe63085-63e2-4248-80a8-67614a6972d5/image.png" alt="첫번째 방법"></p>
<p>만약 위와 같은 클래스를 bean으로 설정한다고 생각해보자. 그러면 아래와 같이 bean을 생성한다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/531db3e8-c9e9-4a80-8fa8-ad7c07af378b/image.png" alt="bean을 생성"></p>
<p>순서를 생각하지 않으려면 type, index, name 등으로 유일하게 구분해줘야 한다. 
그 방법은 아래와 같다.</p>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/dd947bdf-657b-4007-bf2a-1242f8146765/image.png" alt="그 방법"></p>
<p>만약 주입 받는 매개변수가 참조형일 경우 아래와 같이 설정한다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/3bed32ea-49e7-4f24-9f8a-78ceb7a01879/image.png" alt="참조형"></p>
<p>이때, PlayerService가 playerDao에 의존된다고 정의한다.</p>
<p>두번째 방법은 속성을 통해 의존 관계를 설정하는 방법이다. 아래 예시를 살펴보자.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/9b21f12c-472d-44c8-8ea8-3bdec97905ca/image.png" alt="속성을 통해 의존 관계를 설정"></p>
<p>아래는 Player 클래스의 setter이다. 이 때, setter 이름을 property에서 name으로 사용한다. 
아래 예시를 살펴보자.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/9578b53a-414e-4865-a995-7adbb8d42021/image.png" alt="Player 클래스의 setter"></p>
<p>만약 주입 받는 매개변수가 참조형일 경우 아래와 같이 설정한다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/6d6f3f27-faf8-4a8d-89bc-cda1737ad1e6/image.png" alt="매개변수가 참조형">
이 때는 bean의 id 값을 ref의 값으로 넣는다. </p>
<p>List, Set 등 Collection 계열은 각각의 주입 방식이 존재한다. 하나씩 살펴보자.</p>
<blockquote>
<ol>
<li>List</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/f02301f5-4d07-42d4-b769-856780998e9b/image.png" alt=""></p>
<blockquote>
<ol start="2">
<li>Set</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/440c3f8d-40b2-4546-94dd-bd67b4fa293e/image.png" alt=""></p>
<blockquote>
<ol start="3">
<li>Map</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/b1d77f8e-198f-45a1-9599-d9eff84075dd/image.png" alt=""></p>
<blockquote>
<ol start="4">
<li>Properties</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/7f74641c-65dc-4ec9-9924-90b7c6614061/image.png" alt=""></p>
<br>

<h3 id="spring은-annotation으로-빈에-대한-설정을-할-수-있다">Spring은 Annotation으로 빈에 대한 설정을 할 수 있다.</h3>
<p>생성자나 setter가 아닌 Annotation으로 빈에 대한 설정을 할 수 있다.</p>
<p>빈의 특성이나 종류를 나타내는 Annotation을 Stereotype Annotation이라 한다.
이를 통해 빈을 자동등록할 수 있다. 자세한 내용은 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/34bdb7f6-fcf5-4b75-b134-655800b58e81/image.png" alt="Stereotype"></p>
<p>DI를 설정하는 Annotation은 @Autowired, @Resource, @Inject 등이 있다. 
자세한 내용은 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/5c95242d-7601-48e8-a4f8-edeeba19b9f8/image.png" alt="Annotation"></p>
<p>@Autowired의 사용 예시는 아래와 같다.</p>
<blockquote>
<ol>
<li>멤버변수 사용 예시</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/37f76079-dbc8-499e-80a6-b352b09c3d45/image.png" alt="@Autowired"></p>
<blockquote>
<ol start="2">
<li>생성자 사용 예시</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/82c32f42-d7da-4bb7-aff4-f422673602be/image.png" alt="@Autowired"></p>
<blockquote>
<ol start="3">
<li>일반메서드 사용 예시</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/5087776d-be8d-421d-adf8-733bea199f55/image.png" alt="@Autowired"></p>
<p>Qualifier는 동일 타입의 빈이 여러 개일 경우 이름을 주어 구분할 수 있게 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MySQL 6일차]]></title>
            <link>https://velog.io/@jin-chang-ho/MySQL-6%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@jin-chang-ho/MySQL-6%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Fri, 14 Apr 2023 00:44:13 GMT</pubDate>
            <description><![CDATA[<h3 id="db-모델링은-체계적인-순서를-가진다">DB 모델링은 체계적인 순서를 가진다.</h3>
<p>DB 모델링 순서는 개념적 모델링 -&gt; 논리적 모델링 -&gt; 물리적 모델링을 거친다.</p>
<p>위 과정을 통해 실제 업무에 필요한 DB가 만들어진다. 하나씩 살펴보자.</p>
<br>

<h3 id="db-모델링의-첫번째-과정은-개념적-모델링이다">DB 모델링의 첫번째 과정은 개념적 모델링이다.</h3>
<p>개념적 DB 모델링의 정의는 아래와 같다.</p>
<blockquote>
<p>업무분석을 바탕으로 우선 개체를 추출하고 개체 내에 속성을 구성하며 개체 간의 관계를 정의해서 ER-Diagram을 정의하는 단계</p>
</blockquote>
<p>개념적 DB 모델링은 아래와 같이 이뤄진다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/d26a2432-19fe-4031-a6d4-1499ff9b2ae3/image.png" alt="개념적 DB 모델링"></p>
<p>ER-Diagram의 예시는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/512faf6d-fb8b-49db-9f3c-070cf5878d3e/image.png" alt="ER-Diagram의 예시">
네모는 개체, 타원은 속성, 마름모는 관계를 의미한다.</p>
<p>개체의 정의는 아래와 같다.</p>
<blockquote>
<p>사용자와 관계가 있는 주요 객체로써 업무 수행을 위해 데이터로 관리되어야 하는 사람, 사물, 장소, 사건 등</p>
</blockquote>
<p>개체를 찾는 법은 아래와 같다.</p>
<blockquote>
<ol>
<li>영속적으로 존재한다.</li>
<li>새로 식별이 가능한 데이터 요소를 가진다.</li>
<li>개체는 반드시 속성을 가진다.</li>
<li>명사적으로 표현이 가능하다.</li>
</ol>
</blockquote>
<p>속성의 정의는 아래와 같다.</p>
<blockquote>
<p>개체의 성질, 분류, 수량 등을 나타내는 세부사항</p>
</blockquote>
<p>속성의 종류는 아래와 같다.</p>
<blockquote>
<ol>
<li>기초 속성 : 기본적으로 제공되는 속성</li>
<li>추출 속성 : 기초 속성에서 계산을 통해 얻어지는 속성</li>
<li>설계 속성 : 실제로 존재하진 않치만 시스템의 효율성을 위해 설계자가 임의로 부여하는 속성</li>
</ol>
</blockquote>
<p>식별자의 정의는 아래와 같다.</p>
<blockquote>
<p>한 개체 내에서 인스턴스를 유일하게 구분할 수 있는 단일 속성 또는 속성 그룹</p>
</blockquote>
<p>식별자의 종류는 아래와 같다.</p>
<blockquote>
<ol>
<li>후보키 : 개체 내에서 인스턴스를 구분할 수 있는 속성</li>
<li>기본키 : 후보키 중 각 인스턴스를 유일하게 식별하기 위해 선정된 하나의 속성</li>
<li>대체키 : 후보키 중에서 기본키로 선정되지 않은 속성</li>
<li>복합키 : 둘 이상의 속성을 묶은 속성</li>
<li>대리키 : 필요에 의해 인위적으로 추가한 속성</li>
</ol>
</blockquote>
<p>관계의 정의는 아래와 같다.</p>
<blockquote>
<p>두 개체간의 업무적인 연관성</p>
</blockquote>
<p>관계를 설정하는 순서는 아래와 같다.</p>
<blockquote>
<ol>
<li>관계가 있는 두 실체를 실선으로 연결하고 관계를 부여한다.</li>
</ol>
</blockquote>
<p>예시는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/27ad1532-4dc2-4c01-94b4-ceb99635dd52/image.png" alt="예시 1"></p>
<blockquote>
<ol start="2">
<li>관계 차수를 표현한다.</li>
</ol>
</blockquote>
<p>차수성이란 한 실체의 인스턴스가 다른 실체의 몇 개의 인스턴스와 관련될 수 있는가를 말해준다.</p>
<p>예시는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/33aef787-87be-42a2-b963-87082af1a128/image.png" alt="예시 2"></p>
<p>1:1, 1:N, N:1 N:M 관계가 가능하다.</p>
<blockquote>
<ol start="3">
<li>선택성을 표시한다.</li>
</ol>
</blockquote>
<p>선택성이란 있어도 되는지 없어도 되는지를 말해준다.</p>
<p>예시는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/c6507317-ca74-4c55-95e2-7339e4318a3d/image.png" alt="예시 3"></p>
<p>optional이면 개체가 없어도 된다.</p>
<br>

<h3 id="db-모델링의-두번째-과정은-논리적-모델링이다">DB 모델링의 두번째 과정은 논리적 모델링이다.</h3>
<p>논리적 DB 모델링의 정의는 아래와 같다.</p>
<blockquote>
<p>ER-Diagram을 Mapping Rule을 적용하여 관계형 DB 이론에 입각한 스키마를 설계하고 필요하다면 정규화를 하는 단계</p>
</blockquote>
<p>Mapping Rule은 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/2b8f5238-40cd-43d1-ad23-18525e38f6b6/image.png" alt="Mapping Rule"></p>
<p>Mapping Rule을 적용한 사례는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/c090cd8a-293d-415f-9f14-d8fcd52aaf49/image.png" alt="사례"></p>
<p>정규화의 정의는 아래와 같다.</p>
<blockquote>
<p>속성간에 존재하는 함수적 종속성을 분석해서 관계형 스키마를 더 좋은 구조로 정제하는 과정</p>
</blockquote>
<p>정규화 단계는 아래와 같다. 한 단계씩 살펴보자.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/284a169b-2bbe-4e5a-b07b-4c6c0cb74889/image.png" alt="정규화"></p>
<blockquote>
<ol>
<li>제 1 정규화 : 반복되는 그룹 속성을 제거한다.</li>
</ol>
</blockquote>
<p>아래는 제 1 정규화 전 테이블을 보여준다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/e6f90955-8d22-4ffc-965b-e798210c54a0/image.png" alt="제 1 정규화 전 테이블"></p>
<p>주문번호, 주문일, 회원번호, 회원명, 회원등급이 중복해서 저장됨을 알 수 있다.</p>
<p>따라서 중복성을 없애기 위해 해당 테이블에 제 1 정규화를 적용하면 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/071ef568-3c36-4283-87b6-374a03c457c7/image.png" alt="제 1 정규화 후 테이블"></p>
<p>따로 테이블을 만듬으로써 데이터의 중복없이 데이터를 저장할 수 있다.</p>
<blockquote>
<ol start="2">
<li>제 2 정규화 :     복합키 중 하나의 속성에 다른 속성이 의존하는 속성을 제거한다.</li>
</ol>
</blockquote>
<p>아래는 제 2 정규화 전 테이블을 보여준다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/5294ff84-c5bf-4549-89db-9044eeb60208/image.png" alt="제 2 정규화 전 테이블"></p>
<p>기본키가 (주문번호, 상품코드) 인데, 상품코드 속성에만 의존하는 상품명, 단위, 단가 속성이 존재한다.</p>
<p>따라서 종속성을 없애기 위해 해당 테이블에 제 2 정규화를 적용하면 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/b6789f3f-c164-4e1c-a359-592294793f29/image.png" alt="제 2 정규화 후 테이블"></p>
<blockquote>
<ol start="3">
<li>제 3 정규화 : 기본키가 의존하지 않고 일반 속성에 의존하는 속성을 제거한다.</li>
</ol>
</blockquote>
<p>아래는 제 3 정규화 전 테이블을 보여준다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/eaa59437-c56e-4eae-bac7-16e456a86fdc/image.png" alt="제 3 정규화 전 테이블"></p>
<p>회원번호 속성은 기본키가 아님에도 회원명, 회원등급 속성은 회원번호 속성에 의존한다.</p>
<p>따라서 종속성을 없애기 위해 해당 테이블에 제 3 정규화를 적용하면 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/2575949b-6726-4475-a6cd-a31bcc350ae5/image.png" alt="제 3 정규화 후 테이블"></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MySQL 5일차]]></title>
            <link>https://velog.io/@jin-chang-ho/MySQL-5%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@jin-chang-ho/MySQL-5%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 13 Apr 2023 04:47:09 GMT</pubDate>
            <description><![CDATA[<h3 id="mysql은-join을-지원한다">MySQL은 JOIN을 지원한다.</h3>
<p>둘 이상의 테이블에서 데이터가 필요한 경우 JOIN을 사용한다.</p>
<p>JOIN의 특징은 아래와 같다.</p>
<blockquote>
<ol>
<li>일반적으로 JOIN 조건을 포함하는 where 절을 테이블 수 - 1개 만큼 작성한다.</li>
<li>일반적으로 테이블의 기본 키나 외래 키로 구성된다.</li>
</ol>
</blockquote>
<p>JOIN에는 INNER JOIN과 OUTER JOIN이 있다. 하나씩 알아보자.</p>
<br>

<h3 id="mysql은-inner-join을-지원한다">MySQL은 INNER JOIN을 지원한다.</h3>
<p>N개의 테이블 간 교집합을 이용하여 합쳐지는 가장 일반적인 JOIN을 INNER JOIN이라고 한다.</p>
<p>아래는 INNER JOIN의 예시이다.</p>
<pre><code class="language-sql">select e.employee_id, e.first_name, e.salary, e.department_id, d.department_name
from employees e (inner) join departments d
on e.department_id = d.department_id
where e.employee_id = 100;</code></pre>
<p>일반적으로 join하는 테이블은 모두 alias로 별칭을 붙여준다. 
또한, join 조건은 on 절에 일반 조건은 where 절에 사용한다.</p>
<p>USING을 사용하여 INNER JOIN을 할 수도 있다.</p>
<pre><code class="language-sql">select e.employee_id, e.first_name, e.salary, e.department_id, d.department_name
from employees e (inner) join departments d
using (department_id)
where e.employee_id = 100;</code></pre>
<p>두 sql 모두 사번이 100인 사원을 출력한다.</p>
<p>조건을 명시하지 않은 INNER JOIN을 NATURAL JOIN이라고 한다. 아래 예시를 살펴보자.</p>
<pre><code>select d.department_id, d.department_name, l.city
from departments d natural join locations l
where d.department_id = 10;</code></pre><p>NATURAL JOIN은 자동으로 JOIN 되는 테이블들 중 이름과 타입이 같은 열을 모두 JOIN 조건으로 묶어준다. 
따라서 department_id가 10인 부서가 출력된다.</p>
<p>※ NATURAL JOIN은 이름과 타입이 같은 열을 모두 JOIN 조건으로 묶기 때문에 의도하지 않은 결과를 부를 수도 있으므로 사용에 주의가 필요하다.</p>
<br>

<h3 id="mysql은-outer-join을-지원한다">MySQL은 OUTER JOIN을 지원한다.</h3>
<p>INNER JOIN은 한쪽 테이블에는 데이터가 존재하지만 다른 테이블에는 데이터가 존재하지 않을 때 출력되지 않는다는 단점이 있다. 이를 극복하고자 MySQL은 OUTER JOIN을 지원한다.</p>
<p>OUTER JOIN의 종류는 LEFT OUTER JOIN, RIGHT OUTER JOIN이 있다. 하나씩 살펴보자.</p>
<p>왼쪽 테이블 중 JOIN 조건에 일치하지 않는 데이터를 출력하고자 할 때 LEFT OUTER JOIN을 사용한다. 사용 예시는 아래와 같다.</p>
<pre><code class="language-sql">select e.employee_id, e.first_name, d.department_name
from employees e left outer join departments d
using (department_id);</code></pre>
<p>출력 결과에는 부서가 없는 사원도 출력된다.</p>
<p>오른쪽 테이블 중 JOIN 조건에 일치하지 않는 데이터를 출력하고자 할 때 RIGHT OUTER JOIN을 사용한다. 사용 예시는 아래와 같다.</p>
<pre><code class="language-sql">select d.department_name, e.employee_id, e.first_name
from employees e right outer join departments d
using (department_id);</code></pre>
<p>출력 결과에는 직원이 없는 부서도 출력된다.</p>
<br>

<h3 id="mysql은-subquery를-지원한다">MySQL은 SubQuery를 지원한다.</h3>
<p>SubQuery란 다른 쿼리 내부에 포함되어 있는 Select 문을 의미한다.
SubQuery 사용 시 주의점은 아래와 같다.</p>
<blockquote>
<ol>
<li>반드시 ()로 감싸진다.</li>
<li>반드시 단일 행 또는 다중 행 비교 연산자와 함께 사용된다.</li>
</ol>
</blockquote>
<p>SubQuery의 종류는 아래와 같다.</p>
<blockquote>
<ol>
<li>중첩 서브 쿼리 : where 문에 작성하는 서브 쿼리</li>
<li>인라인 뷰 : from 문에 작성하는 서브 쿼리</li>
<li>스칼라 서브 쿼리 : select 문에 작성하는 서브 쿼리</li>
</ol>
</blockquote>
<br>

<h3 id="mysql은-중첩-서브-쿼리를-지원한다">MySQL은 중첩 서브 쿼리를 지원한다.</h3>
<p>where절에 사용되는 서브 쿼리를 중첩 서브 쿼리라고 한다.
중첩 서브 쿼리는 단일 행 혹은 다중 행 혹은 다중 열을 반환한다. </p>
<p>단일 행 반환 예시부터 알아보자. 아래 예시를 살펴보자.</p>
<pre><code class="language-sql">select employee_id, first_name, department_id
from employees
where department_id = (
                        select department_id
                        from employees
                        where first_name = &#39;adam&#39;
                        );</code></pre>
<p>위 경우에서 이름이 adam인 사람은 단 한 명임을 보장한다. 
따라서 adam과 같은 department_id를 가진 직원들을 출력한다.</p>
<p>다음엔 다중 행 반환에 대해 알아보자. 다중 행 비교 연산자는 아래와 같다.</p>
<blockquote>
<ol>
<li>in : 서브 쿼리 결과 중 단 하나라도 일치하면 참</li>
<li>any : 서브 쿼리 결과 중 단 하나라도 만족하면 참</li>
<li>all : 서브 쿼리 결과를 모두 만족해야 참</li>
</ol>
</blockquote>
<p>다중 행 사용 예시는 아래와 같다.</p>
<pre><code class="language-sql">select employee_id, first_name
from employees
where salary &gt; any (
                    select salary
                    from employees
                    where department_id = 30
                    )
order by salary;</code></pre>
<p>위 코드를 실행하면 모든 직원들 중 department_id가 30인 사람들의 급여 중 하나라도 급여가 높으면 출력된다. 
이 때, 급여로 오름차순되어 출력된다.</p>
<p>마지막으로 다중 열 반환 예시를 살펴보자. 아래 예시를 살펴보자.</p>
<pre><code class="language-sql">select employee_id, first_name
from employees
where (salary, department_id) in (
                                    select salary, department_id
                                    from employees
                                    where commission_pct is not null
                                    and manager_id = 148
                                    );</code></pre>
<p>위 코드를 실행하면 manager_id가 148번이고, 커미션은 받는 직원의 급여와 department_id가 같은 직원이 출력된다.</p>
<br>

<h3 id="mysql은-인라인-뷰를-지원한다">MySQL은 인라인 뷰를 지원한다.</h3>
<p>FROM절에 사용되는 서브 쿼리를 인라인 뷰라고 한다.
인라인 뷰는 임시적인 뷰이기 때문에 데이터베이스에는 저장되지 않는다.</p>
<p>인라인 뷰 사용 예시는 아래와 같다.</p>
<pre><code class="language-sql">select e.employee_id, e.first_name, e.salary, e.department_id
from (
    select distinct department_id
    from employees
    where salary &lt; (select avg(salary) from employees)
    ) d join employees e
on d.department_id = e.department_id;</code></pre>
<p>위 코드를 실행하면 모든 사원의 평균 급여보다 급여가 낮은 사원들과 같은 부서에서 일하는 사원들이 출력된다.</p>
<br>

<h3 id="mysql은-스칼라-서브-쿼리를-지원한다">MySQL은 스칼라 서브 쿼리를 지원한다.</h3>
<p>SELECT절에 사용되는 서브 쿼리를 스칼라 서브 쿼리라고 한다.
스칼라 서브 쿼리는 하나의 행만 반환한다.</p>
<p>스칼라 서브 쿼리 사용 예시는 아래와 같다.</p>
<pre><code class="language-sql">select e.employee_id, e.first_name, salary, department_id,
    (select avg(salary) from employees where department_id = 60) as avg60
from employees e
where department_id = 60;</code></pre>
<p>위 코드를 실행하면 department_id가 60인 사람들이 출력된다. 이 때 모든 출력 결과에 department_id가 60인 사람들의 평균 급여가 함께 출력된다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MySQL 4일차]]></title>
            <link>https://velog.io/@jin-chang-ho/BackEnd-5%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@jin-chang-ho/BackEnd-5%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Wed, 12 Apr 2023 00:00:43 GMT</pubDate>
            <description><![CDATA[<h3 id="mysql은-ddl을-지원한다">MySQL은 DDL을 지원한다.</h3>
<p>DDL로 데이터 구조를 생성, 변경, 제거할 수 있다.</p>
<p>DB 생성, 변경, 삭제 DDL은 아래와 같다.</p>
<blockquote>
<ol>
<li>생성</li>
</ol>
</blockquote>
<p>DB 생성 시에는 아래와 같은 방법으로 생성한다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/447468b1-a0e5-4ac7-a6fb-b57d2a100e00/image.png" alt="생성"></p>
<blockquote>
<ol>
<li>default character set : 문자를 컴퓨터에 저장할 때 사용하는 규칙들의 집합</li>
<li>collate : 문자들을 서로 비교할 때 사용하는 규칙들의 집합</li>
</ol>
</blockquote>
<p>실제 사용 예시는 아래와 같다.</p>
<pre><code class="language-sql">create database dbtest
default character set utf8mb3 collate utf8mb3_general_ci;</code></pre>
<blockquote>
<ol start="2">
<li>변경</li>
</ol>
</blockquote>
<p>DB 변경 시에는 아래와 같은 방법으로 변경한다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/ca928b6a-d585-4dee-a652-f8d2eb0e29e3/image.png" alt="변경"></p>
<p>실제 사용 예시는 아래와 같다.</p>
<pre><code class="language-sql">alter database dbtest
default character set utf8mb3 collate utf8mb3_general_ci;</code></pre>
<blockquote>
<ol start="3">
<li>삭제</li>
</ol>
</blockquote>
<p>DB 삭제 시에는 아래와 같은 방법으로 삭제한다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/0316ddb7-6719-4fe3-82be-23407428bd05/image.png" alt="삭제"></p>
<p>실제 사용 예시는 아래와 같다.</p>
<pre><code class="language-sql">drop database dbtest;</code></pre>
<p>테이블 생성 시에는 아래와 같은 방법으로 생성한다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/3099d123-fc4a-423d-a2fa-e93403d84dd9/image.png" alt="테이블 생성"></p>
<p>제약 조건의 종류는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/4c8e5bcd-84e0-4d50-84f7-b136adaa4c02/image.png" alt="제약 조건"></p>
<p>실제 사용 예시는 아래와 같다.</p>
<pre><code class="language-sql">CREATE TABLE samsung_member (
    idx INT NOT NULL AUTO_INCREMENT,
    userid VARCHAR(16) NOT NULL,
    username VARCHAR(20),
    userpwd VARCHAR(16),
    emailid VARCHAR(20),
    emaildomain VARCHAR(50),
    joindate TIMESTAMP NOT NULL DEFAULT current_timestamp,
    constraint samsung_member.pk PRIMARY KEY (idx)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;</code></pre>
<p>제약 조건은 아래 따로 설정해주고, 이름도 붙여주는 것이 좋다.</p>
<br>

<h3 id="mysql은-데이터에-접근할-수-있도록-인덱스를-지원한다">MySQL은 데이터에 접근할 수 있도록 인덱스를 지원한다.</h3>
<p>인덱스를 사용하면 데이터의 검색, 입력, 수정, 삭제 시간을 줄일 수 있다.
인덱스는 클러스터형 인덱스와 보조 인덱스가 있다. 각 인덱스의 특징은 아래와 같다.</p>
<p>특정 나열된 데이터들을 일정 기준으로 정렬해 주는 인덱스를 클러스터형 인덱스라고 한다.
클러스터형 인덱스의 특징은 아래와 같다.</p>
<blockquote>
<ol>
<li>테이블 당 하나만 생성 가능하다.</li>
<li>보조 인덱스보다 검색은 더 빠르지만, 입력과 수정과 삭제는 더 느리다.</li>
<li>MySQL에선 PK -&gt; UNIQUE &amp; NOT NULL -&gt; 임의로 보이지 않는 컬럼 순으로 
클러스터형 인덱스를 지정한다.</li>
</ol>
</blockquote>
<p>후보키에 부여 가능한 인덱스를 보조 인덱스라고 한다.
보조 인덱스의 특징은 아래와 같다.</p>
<blockquote>
<ol>
<li>테이블 당 여러개 생성 가능하다.</li>
<li>생성시 데이터 페이지는 그냥 둔 상태에서 별도의 페이지에 인덱스를 구성한다.</li>
<li>클러스터형 인덱스보다 입력과 수정과 삭제는 더 빠르지만, 검색은 더 빠르다.</li>
</ol>
</blockquote>
<p>인덱스의 문제점은 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/dff8220d-7884-4b54-87f0-ff481a79ae18/image.png" alt="인덱스의 문제점"></p>
<p>따라서 인덱스를 생성할 때는 아래와 같은 전략을 따른다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/feaa1b58-7aea-4390-9f3c-13510643f61c/image.png" alt="인덱스 생성 전략"></p>
<br>

<h3 id="mysql은-사용자가-인덱스를-지정할-수-있도록-지원한다">MySQL은 사용자가 인덱스를 지정할 수 있도록 지원한다.</h3>
<p>클러스터형 인덱스는 alter table로, 보조 인덱스는 create index로 인덱스를 생성할 수 있다.</p>
<p>보조 인덱스 생성 예시를 살펴보자. 단순 보조 인덱스는 아래와 같이 생성 가능하다.</p>
<pre><code class="language-sql">create index samsung_address_area_idx
on samsung(address_area)</code></pre>
<p><code>show index from samsung;</code> 로 인덱스를 확인해보면 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/0078cfea-03ee-46b6-a5c4-6e1368d34eaf/image.png" alt="확인"></p>
<blockquote>
<p>첫번째 인덱스는 클러스터형 인덱스로 기본키라 클러스터형 인덱스로 자동 설정됐다.
두번째 인덱스가 설정한 단순 보조 인덱스이다.</p>
</blockquote>
<p>고유한 보조 인덱스는 아래와 같이 생성한다.</p>
<pre><code class="language-sql">create unique index samsung_user_name_idx
on samsung(user_name);</code></pre>
<p>이 때, user_name이 unique 하지 않으면 오류가 발생한다.</p>
<p><code>show index from samsung;</code> 로 인덱스를 확인해보면 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/b92c8bb2-7fc1-4cfe-b2c0-6e955819772a/image.png" alt="확인"></p>
<p>두번째 인덱스가 고유한 보조 인덱스이다.
고유한 보조 인덱스가 설정된 후 해당 열에 값이 중복되는 데이터를 insert 하면 
오류가 발생한다.</p>
<p>클러스터형 인덱스는 alter table로, 보조 인덱스는 drop index로 인덱스를 삭제할 수 있다.
인덱스를 모두 삭제할 때는 보조 인덱스부터 삭제한다.</p>
<p>아래는 보조 인덱스 삭제 예시이다.</p>
<pre><code class="language-sql">drop index samsung_user_name_idx on samsung;</code></pre>
<p><code>show index from samsung;</code> 로 인덱스를 확인해보면 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/f7b03d5c-e5dc-47c8-b727-36bf515f0982/image.png" alt="확인"></p>
<br>

<h3 id="mysql은-view를-지원한다">MySQL은 View를 지원한다.</h3>
<p>데이터베이스에 존재하는 가상의 테이블을 View라고 한다.
View는 필요한 데이터만 보여줌으로써 보안성이나 편의성을 확보하는 데 활용된다.</p>
<p>View의 특징은 아래와 같다.</p>
<blockquote>
<ol>
<li>실제 행과 열을 가지고 있다.</li>
<li>테이블처럼 물리적으로 저장되는 것은 아니다.</li>
<li>테이블과 달리 실제 데이터가 없고 SQL만 저장한다.</li>
<li>삽입, 삭제, 갱신 작업에 많은 제약이 걸리지만 가능하다.</li>
</ol>
</blockquote>
<p>View는 아래와 같은 방법으로 생성한다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/1be93544-de27-4739-9305-6c465638f45b/image.png" alt="View 생성"></p>
<p>실제 사용 예시는 아래와 같다.</p>
<pre><code class="language-sql">create or replace view vsam 
as 
select * 
from sam99 
where a &gt; 3</code></pre>
<p>위 코드의 의미는 아래와 같다.</p>
<blockquote>
<p>sam99 table에서 a 속성값이 3 초과인 행만 모아 vsam 이란 View를 만들거나 교체한다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Algorithm 27일차]]></title>
            <link>https://velog.io/@jin-chang-ho/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-27%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@jin-chang-ho/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-27%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Tue, 11 Apr 2023 01:44:03 GMT</pubDate>
            <description><![CDATA[<h3 id="알고리즘에서-정렬할-때-카운팅-정렬을-활용할-수-있다">알고리즘에서 정렬할 때 카운팅 정렬을 활용할 수 있다.</h3>
<p>카운팅 정렬의 정의는 아래와 같다.</p>
<blockquote>
<p>항목들의 순서를 결정하기 위해 집합에 각 항목이 몇 개씩 있는지 세는 작업을 하여 
시간 복잡도 O(리스트 길이 + 정수의 최대값)에 정렬하는 효율적인 정렬</p>
</blockquote>
<p>카운팅 정렬의 제한 사항은 아래와 같다.</p>
<blockquote>
<ol>
<li>정수나 정수로 표현할 수 있는 자료에만 적용할 수 있다.</li>
<li>집합 내의 가장 큰 정수를 알아야 한다.</li>
</ol>
</blockquote>
<p>{0, 4, 1, 3, 1, 2, 4, 1}을 카운팅 정렬해보자. 그 과정은 아래와 같다.</p>
<blockquote>
<p>1번 과정</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/fd0a55d5-9ae8-48f8-9a5e-99ff2d87a806/image.png" alt="실행 화면">
Data에서 각 항목들의 발생 횟수를 세어 Counts 배열에 저장한다.</p>
<blockquote>
<p>2번 과정</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/9974f1b9-be39-4fc5-a7b7-7c6448521441/image.png" alt="실행 화면">
Counts의 원소 바로 앞 원소의 값을 원래 원소 값에 배열의 앞에서부터 더해준다.</p>
<blockquote>
<p>3번 과정 </p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/00f69eda-3776-4fde-ad80-d60ae4950c55/image.png" alt="실행 화면">
Data의 끝에서부터 Data의 값을 접근한다.
이 때, Data의 값을 인덱스로 Counts의 값을 1 줄여준다.
그리고 줄어든 Counts의 값을 인덱스로 Temp 배열에 Data의 값을 저장한다.</p>
<blockquote>
<p>4번 과정</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/7b3872dc-5bfc-4290-a7b3-2938dde34937/image.png" alt="실행 화면">
Data를 모두 접근할 때까지 3번 과정을 반복한다.</p>
<br>

<h3 id="알고리즘에서-정렬할-때-선택-정렬을-활용할-수-있다">알고리즘에서 정렬할 때 선택 정렬을 활용할 수 있다.</h3>
<p>선택 정렬의 정의는 아래와 같다.</p>
<blockquote>
<p>가장 작은 값의 원소부터 차례대로 선택하여 위치를 교환하는 방식으로
시간 복잡도 O(N^2)에 정렬하는 정렬</p>
</blockquote>
<p>선택 정렬의 정렬 과정은 아래와 같다.</p>
<blockquote>
<p>1번 과정</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/8f611863-7bfd-4fce-9cff-d4e9cd469c5f/image.png" alt="실행 화면">
주어진 리스트 중에서 최소값을 찾는다.</p>
<blockquote>
<p>2번 과정</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/467a6fcb-acdd-46d2-9abe-20de86542c7a/image.png" alt="실행 화면">
그 값을 리스트의 맨 앞에 위치한 값과 교환한다.</p>
<blockquote>
<p>3번 과정 </p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/fb4b06d7-6d87-4ace-b13d-d82ba77de7fb/image.png" alt="실행 화면">
리스트의 끝에 도달하기 바로 전까지 1, 2번 과정을 반복한다.</p>
<br>

<h3 id="알고리즘에서-정렬할-때-퀵-정렬을-활용할-수-있다">알고리즘에서 정렬할 때 퀵 정렬을 활용할 수 있다.</h3>
<p>퀵 정렬의 정의는 아래와 같다.</p>
<blockquote>
<p>특정 값을 기준으로 작은 것은 왼쪽으로 큰 것은 오른쪽으로 위치하는 작업을 반복하여
시간 복잡도 O(Nlog(N))에 정렬하는 정렬</p>
</blockquote>
<p>퀵 정렬의 정렬 과정은 아래와 같다.</p>
<blockquote>
<p>1번 과정</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/145c7723-bf88-4c0e-88fa-d8ef80fec4c5/image.png" alt="1번 과정">
임의의 기준 값을 잡는다. 여기선 가장 왼쪽 값을 기준 값으로 잡았다.</p>
<blockquote>
<p>2번 과정</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/27912a11-aa60-4b18-8593-dafbd3a1f7e3/image.png" alt="2번 과정">
기준 값을 제외한 가장 왼쪽부터 기준 값보다 더 크거나 같을 때까지 인덱스를 이동한다.
또한 가장 오른쪽부터 기준 값보다 작을 때까지 인덱스를 이동한다.
위의 두 가지 조건을 모두 만족하면 두 값을 교환한다.</p>
<blockquote>
<p>3번 과정</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/e303af52-b810-4cc5-8381-9ea3f82bd979/image.png" alt="3번 과정"></p>
<p>2번 과정을 반복하다가 왼쪽 포인터가 오른쪽 포인터보다 커지면 
기준 값과 오른쪽 포인터 값을 교환한다.</p>
<blockquote>
<p>4번 과정</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/9f3b2e60-58ac-4336-bbdd-ea0105a02cf5/image.png" alt="4번 과정_1"></p>
<p><img src="https://velog.velcdn.com/images/jin-chang-ho/post/60b1f91d-297d-47fa-b2bb-1b2e2f02aa17/image.png" alt="4번 과정_2"></p>
<p>배열의 모든 요소가 확정될 때까지 1, 2, 3번 과정을 반복한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Algorithm 26일차]]></title>
            <link>https://velog.io/@jin-chang-ho/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-26%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@jin-chang-ho/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-26%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 06 Apr 2023 11:11:01 GMT</pubDate>
            <description><![CDATA[<h3 id="알고리즘에-명제와-논리를-활용할-수-있다">알고리즘에 명제와 논리를 활용할 수 있다.</h3>
<p>명제란 참과 거짓을 명확히 판별할 수 있다는 문장이다. 예시는 아래와 같다.</p>
<blockquote>
<p>두 변의 길이가 같다면 이등변 삼각형이다. (참)</p>
</blockquote>
<p>명제가 참이면 대우는 참이고, 명제가 거짓이면 대우는 거짓이다. 예시는 아래와 같다.</p>
<blockquote>
<p>이등변 삼각형이 아니면 어느 두 변의 길이를 선택해도 길이가 다르다. (참)</p>
</blockquote>
<p>알아야 하는 명제는 아래와 같다.</p>
<blockquote>
<ol>
<li>2로 나눠지는 자연수는 짝수고, 2로 나눠지지 않는 자연수는 홀수다.</li>
<li>마방진은 각 행의 합, 열의 합, 대각선들의 합이 모두 같다.</li>
<li>유리수는 서로소인 두 정수의 나눗셈으로 표현할 수 있고, 표현할 수 없으면 무리수다.</li>
<li>0이 아닌 수로 다른 수를 나눴을 때 나머지가 0이면 나눈 수는 나눠진 수의 약수이다.</li>
</ol>
</blockquote>
<br>

<h3 id="알고리즘에-수학-이론을-활용할-수-있다">알고리즘에 수학 이론을 활용할 수 있다.</h3>
<p>활용할 수 있는 수학 이론은 아래와 같다.</p>
<blockquote>
<ol>
<li>페르마의 소정리 : p가 소수고 p가 a의 약수가 아니면 a^p-1 = 1 (mod p) 이다.</li>
<li>배열 차원 변환 : A가 1차원이고 B가 2차원이다. 
그럼 A[i] = B[i/col][i%col], B[i][j] = A[i*col+j] 이다.</li>
</ol>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Algorithm 25일차]]></title>
            <link>https://velog.io/@jin-chang-ho/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-25%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@jin-chang-ho/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-25%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Tue, 04 Apr 2023 00:15:48 GMT</pubDate>
            <description><![CDATA[<h3 id="알고리즘에서-문자열-패턴을-찾을-수-있다">알고리즘에서 문자열 패턴을 찾을 수 있다.</h3>
<p>문자열 패턴 매칭 문제의 정의는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/ba3c71db-7878-47c4-9982-4e68e96ae3f1/image.png" alt="문자열 패턴 매칭"></p>
<blockquote>
<p>이 때, 문자열 X 안에 문자열 Y가 존재하는가?</p>
</blockquote>
<p>이를 완전 탐색으로 풀면 아래와 같이 풀 수 있다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/2dc7dcbe-0a39-44c2-a254-41fc11565598/image.png" alt="완전 탐색"></p>
<p>해당 알고리즘의 시간 복잡도는 O(MN) 이다. 좀 더 효율적인 방법을 찾아보자.</p>
<br>

<h3 id="문자열-패턴-매칭-문제에-라빈-카프-알고리즘을-활용할-수-있다">문자열 패턴 매칭 문제에 라빈-카프 알고리즘을 활용할 수 있다.</h3>
<p>문자열 검색을 위해 해시 값 함수를 사용하는 알고리즘을 라빈-카프 알고리즘이라 한다.
원리는 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/3bb08be9-d478-4047-98fd-7f87a10fe4c3/image.png" alt="라빈-카프 알고리즘">
찾으려는 패턴의 해시 값은 패턴을 숫자로 바꾼 4321이라 가정해보자.</p>
<p>그럼 숫자 문자열을 패턴의 길이만큼 잘라 해시 값을 구해 해시 값이 같으면 패턴이 있다고 판단한다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/cb90384d-620e-42a0-847b-d51ffbce2c50/image.png" alt="숫자 문자열"></p>
<p>이 때 아래처럼 슬라이딩 윈도우를 활용할 수 있다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/4d12d05e-eb0b-462e-862b-1346618b7e6b/image.png" alt="슬라이딩 윈도우"></p>
<p>해당 알고리즘의 고려사항은 아래와 같다.</p>
<blockquote>
<ol>
<li>패턴이 문자열이며 길이가 길어지면 길이에 제한을 두기 위해 mod 연산을 취한다.</li>
<li>1번 연산으로 인해 해시 값이 일치하는 해시 충돌이 일어날 수 있고, 이 때는 문자열이 일치하는 지 하나하나씩 다시 검사한다.</li>
</ol>
</blockquote>
<p>해당 알고리즘의 시간 복잡도는 최악의 경우 O(MN) 이지만, 대부분 O(1)에 가깝다.</p>
<br>

<h3 id="문자열-패턴-매칭-문제에-보이어-무어-알고리즘을-활용할-수-있다">문자열 패턴 매칭 문제에 보이어 무어 알고리즘을 활용할 수 있다.</h3>
<p>문자열을 오른쪽에서 왼쪽으로 비교하는 알고리즘을 보이어 무어 알고리즘이라 한다.
원리는 아래와 같다.</p>
<p>문자열의 오른쪽 끝에 있는 문자가 불일치하고 이 문자가 패턴 내에 존재하지 않을 때를 살펴보자.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/5acfc6cf-dde0-43e9-93ee-50ea38272853/image.png" alt="문자열 비교">
비교 문자열 크기만큼 점프가 가능하다.</p>
<p>이번엔 문자열의 오른쪽 끝에 있는 문자가 불일치하고 이 문제가 패턴 내에 존재할 때를 살펴보자.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/dd636c9a-a179-4708-b2c4-1a548a6e9d9c/image.png" alt="문자열 비교">
일치하는 문자가 있는 곳까지 점프가 가능하다.</p>
<p>따라서 패턴 불일치가 발생할 때 본문 포인터의 점프 횟수를 기록한 skip 배열을 만든다. 
아래는 rithm 패턴 문자열의 skip 배열 예시다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/45a97a66-fed6-434f-8160-6d18605bc09f/image.png" alt="rithm 패턴 문자열"></p>
<p>skip 배열을 이용하면 아래와 같이 비교된다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/b767cf5d-22fd-44b9-877a-9122853191f2/image.png" alt="skip 배열"></p>
<p>해당 알고리즘의 시간 복잡도는 최악의 경우 O(MN) 이지만, 최선의 경우 O(N/M) 이다.
평균적으로 가장 빠른 속도를 가지는 알고리즘이기도 하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Algorithm 24일차]]></title>
            <link>https://velog.io/@jin-chang-ho/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-24%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@jin-chang-ho/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-24%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Mon, 03 Apr 2023 01:29:38 GMT</pubDate>
            <description><![CDATA[<h3 id="알고리즘에서-최단-경로를-찾는-데-플로이드-워샬을-활용할-수-있다">알고리즘에서 최단 경로를 찾는 데 플로이드 워샬을 활용할 수 있다.</h3>
<p>플로이드 워샬은 다익스트라와 달리 음의 가중치에서도 최단 경로를 찾을 수 있다.
따라서 음의 가중치에서 최단 경로를 찾을 때 주로 사용한다.</p>
<p>플로이드 워샬의 주요 아이디어는 아래와 같다.</p>
<blockquote>
<p>1~n 까지의 모든 정점을 경유 가능한 정점들로 고려하며 모든 쌍의 최단 경로를 계산한다.</p>
</blockquote>
<p>이는 1~n 까지의 모든 정점들을 반드시 경유하는 경로를 의미하지 않음을 주의하자.</p>
<p>플로이드 워샬의 부분 문제는 아래와 같이 정의된다.</p>
<blockquote>
<p>Dijk = 정점 {1, 2, ..., k} 중 경유 가능한 정점들로 고려하여, i부터 j까지의 최단 경로</p>
</blockquote>
<p>플로이드 워샬의 도출 과정은 아래와 같다.</p>
<blockquote>
<ol>
<li>k = 1일 때</li>
</ol>
</blockquote>
<p>i != j != k인 상황에서 1을 첫번째 경유지로 고려해보자.
그럼 i에서 j까지의 경로는 1을 거쳐서 가는 경로, 1을 거치지 않는 경로가 있다.
이 중 거리가 짧은 경로가 최단 경로로 정의된다.</p>
<p>아래 그림은 위 상황을 잘 보여준다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/b9315582-7b1f-4507-9e39-ee62bde2e770/image.png" alt="k=1"></p>
<p>※ Dij0은 아무 것도 경유하지 않은 경로를 의미한다.</p>
<blockquote>
<ol start="2">
<li>k = 2일 때</li>
</ol>
</blockquote>
<p>이번엔 2를 두번째 경유지로 고려해보자. 
이 때 1을 경유지로 할지 말지를 고려한 결과가 사용된다.
그럼 i에서 j까지의 경로는 2를 거쳐서 가는 경로, 2를 거지치 않는 경로가 있다.
이 중 거리가 짧은 경로가 최단 경로로 정의된다.</p>
<p>아래 그림은 위 상황을 잘 보여준다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/3749815b-64c9-4b32-93ab-ef516703d603/image.png" alt="k=2"></p>
<p>※ Dij1은 첫 번째 경유지를 고려한 최단 경로를 의미한다.</p>
<blockquote>
<ol start="3">
<li>k = n일 때</li>
</ol>
</blockquote>
<p>이번엔 n을 n번째 경유지로 고려해보자.
이 때 n-1을 경유지로 할지 말지를 고려한 결과가 사용된다.
그럼 i에서 j까지의 경로는 n을 거쳐서 가는 경로, n을 거지치 않는 경로가 있다.
이 중 거리가 짧은 경로가 최단 경로로 정의된다.</p>
<p>아래 그림은 위 상황을 잘 보여준다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/1938ca20-af2b-40b5-a442-189a66e3f381/image.png" alt="k=n"></p>
<p>이를 일반식으로 정리하면 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/5acd0839-b2f3-42fd-a38c-fc609f4c1c40/image.png" alt="일반식"></p>
<p>따라서 플로이드 워샬의 구현은 아래와 같다.
<img src="https://velog.velcdn.com/images/jin-chang-ho/post/2b42a7de-6338-49b9-b316-646e77d62902/image.png" alt="플로이드 워샬">
이 때 D는 정점 간 거리로 초기화가 필요하다. 플로이드 워샬의 시간 복잡도는 O(N^3)이다.</p>
<p>플로이드 워샬을 실제로 구현하면 아래와 같다.</p>
<pre><code class="language-java">import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Floyd {

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(br.readLine());

        int[][] arr = new int[N][N];

        for (int i = 0; i &lt; N; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());

            for (int j = 0; j &lt; N; j++) {
                arr[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        for (int k = 0; k &lt; N; k++) {
            for (int i = 0; i &lt; N; i++) {
                for (int j = 0; j &lt; N; j++) {
                    arr[i][j] = Math.min(arr[i][j], arr[i][k] + arr[k][j]);
                }
            }
        }

        for (int i = 0; i &lt; N; i++) {
            for (int j = 0; j &lt; N; j++) {
                System.out.print(arr[i][j] + &quot; &quot;);
            }

            System.out.println();
        }
    }
}</code></pre>
<p>입력값은 아래와 같다.</p>
<blockquote>
<p>4
0 10 1 5
10 0 2 4
1 2 0 3
5 4 3 0</p>
</blockquote>
<p>출력 결과는 아래와 같다.</p>
<blockquote>
<p>0 3 1 4 
3 0 2 4 
1 2 0 3 
4 4 3 0</p>
</blockquote>
]]></description>
        </item>
    </channel>
</rss>