집PC는 윈도우라서 개발용 환경 리눅스 세팅을 하려합니다. 리눅스 환경으로 개발환경을 잡는 이유는 여러가지가 있습니다. 실제 운영하는 서버는 대부분 리눅스 계열입니다. 물론, 윈도욱 계열을 사용하는 서버도 있지만 비중이 높지는 않습니다. 개발환경을 리눅스로 만들어 적응력을 가지는 것도 많은 도움이 됩니다. 그런데 집PC에 윈도우를 삭제하고 리눅스로 설치를 하는 것은 매우 비효율 적입니다. 그래서 VMware 라는 가상머신을 만들어주는 프로그램을 사용하려 합니다.
가상머신 소프트웨어란? 컴퓨터에 설치된 운영체제 안에 가상의 컴퓨터를 만들고, 그 가상의 컴퓨터 안에서 또 다른 운영체제를 설치/운영할 수 있도록 제작된 소프트웨어 입니다.
물론 멀티부팅등으로 리눅스를 따로 설치하는 것도 방법이지만, 그렇게 구성하는 것도 쉽지 않기 때문에 가상머신을 만드는 것이 시간이 절약됩니다. 저는 윈도우 10 에 VMware 최신버전(현재 16.1.2)을 설치하도록 하겠습니다.
사이트로 이동하면 다운로드 메뉴가 [참고자료 -> 제품다운로드] 에 있으니 클릭하여 다운로드 사이트로 이동합니다.
제품은 "VMware Workstation Player" 입니다. 많은 제품중에 해당 제품을 찾아 "Download Product"를 선택하여 줍니다.
해당 페이지에서 자신의 운영체제에 맞는 제품을 찾아서 다운로드 합니다. 저는 윈도우 10 64bit 사용중이기 때문에 아래 그림과 같이 Windows 64-bit Operating-Systems 를 다운로드 하였습니다.
중요한 부분을 체크해봐야 합니다. 바로 라이센스 입니다. Workstation Player 의 경우 개인 사용은 무료라고 합니다.
2. 설치받은 파일을 실행하여 설치를 진행합니다.
라이센스 관련 부분은 동의를 클릭하여 진행하여 줍니다.
키보드 드라이버 관련 부분을 체크하고 다음으로 넘어갑니다.
시작프로그램으로 제품 업데이트 등록할지, 그리고 사용 개선 프로그램에 참여할건지 묻는 화면인데 저는 둘다 해제하고 진행하였습니다.
VMware 단축아이콘 위치 지정인데 기본값으로 두고 진행합니다.
모슨 설정이 끝났으면 설치 준비가 완료됩니다. "Install" 버튼을 눌러 설치를 진행합니다.
설치가 진행이 되고 완료가 되면 "Finish" 버튼을 클릭합니다. 라이센스가 있는 사용자는 라이센스 버튼을 클릭하여 가지고있는 라이센스를 넣어주면 됩니다. 저는 개인용으로 무료버전이므로 "Finish" 버튼을 클릭하였습니다. 그러니 컴퓨터를 재부팅하라고 나옵니다. 컴퓨터를 재부팅하면 설치는 완료됩니다.
컴퓨터를 재시작 후 프로그램 을 실행하여 보면, 아래와 같은 창을 보게됩니다. 라이센스키를 묻는데 위의 옵션 "Use VMware Workstation 16 Player for free for non-commercial use"를 선택합니다. 그리고 다음 창까지 "Finish" 버튼을 눌러줍니다.
VMware 가 정상적으로 실행이 됩니다. 음, 이제 어떤 리눅스를 깔아야 할지 고민을 해봐야 겠습니다.
지난 글에 이어서 컴포넌트에 대하여 알아보도록 하겠습니다. 이번에는 컴포넌트 간 통신에 대하여 자세히 알아 봅니다.
컴포넌트
- 컴포넌트 통신하기
. 컴포넌트 간 통신과 유효범위
뷰는 컴포넌트로 화면을 구성하므로 같은 웹 페이지라도 데이터를 공유할 수 없습니다. 그 이유는 컴포넌트마다 자체적으로 고유한 유효 범위를 갖기 때문입니다. 이것은 뷰 프레임워크 내부적으로 정의된 특징이라고 합니다. 각 컴포넌트의 유효 범위가 독립적이기 때문에 다른 컴포넌트의 값을 직접적으로 참조할 수가 없다는 것 입니다.
뷰 프레임워크 자체에서 정의한 컴포넌트 데이터 전달 방법을 따라야 값을 참조할 수 있습니다. 가장 기본적인 데이터 전달 방법은 바로 상위(부모) - 하위(자식) 컴포넌트 간의 데이터 전달 방법입니다.
상위 컴포넌트의 HTML 코드에 등록된 child-component 컴포넌트 태그에 v-bind 속성을 추가합니다. v-bind 속성의 왼쪽 값은 하위 컴포넌트에서 정의한 props 속성을 넣고, 오른쪽 값은 하위 컴포넌트에 전달할 상위 컴포넌트의 data 속성을 지정합니다.
<child-component v-bind:props 속성이름="상위 컴포넌트의 data 속성"></child-component>
Vue.component() 를 이용하여 하위 컴포넌트 child-component를 등록
child-component 내용에 props 속성으로 propsdata 를 정의
HTML에 컴포넌트 태그 추가 v-bind 속성 propsdata="message" 는 상위 컴포넌트의 message 속성 값을 하위 컴포넌트의 propsdata로 전달 함
child-component 의 template 속성에 정의된 값으로 message 에 정의된 텍스트가 됨
여기서 인스턴스가 상위 컴포넌트가 되며, child-component가 하위 컴포넌트가 됩니다. 이렇게 새 컴포넌트를 등록한 인스턴스를 최상위 첨포넌트라고도 부릅니다.
. 하위에서 상위 컴포넌트로 이벤트 전달하기
이번에는 하위 컴포넌트에서 상위 컴포넌트로 이벤트를 발생시켜 보겠습니다. 상위 컴포넌트는 하위 컴포넌트의 특정 이벤트가 발생하기를 기다리고 있다가 하위 컴포넌트에서 특정 이벤트가 발생하면 상위 컴포넌트에서 해당 이벤트를 수신하여 상위 컴포넌트의 메서드를 호출하는 방식 입니다.
이벤트 발생과 수신은 $emit() 과 v-on: 속성을 사용하여 구현합니다. 각각의 형식은 아래와 같습니다.
// 이벤트 발생 this.$emit('이벤트명');
// 이벤트 수신 <child-component v-on:이벤트명="상위 컴포넌트의 메서드명"></child-component>
$emit()을 호출하면 괄호 안에 정의된 이벤트가 발생합니다. $emit()을 호출하는 위치는 일반적으로 하위 컴포넌트의 특정 메스트 내부입니다. 이때 this는 하위 컴포넌트를 가리킵니다.
호출한 이벤트는 하위 컴포넌트를 등록하는 태그에서 v-on:으로 받습니다. 속성의 값에 이벤트가 발생했을 때 호출될 상위 컴포넌트의 메서드를 지정합니다. 아래는 예제 코드입니다.
showLog() 메서트 안에서 this.$emit('show-log') 가 실행되어 show-log 이벤트가 발생
show-log 이벤트는 <child-component> 에 정의한 v-on:show-log 에 전달되고 지정한 printText() 를 실행
printText() 에서 콘솔에 로그를 출력
뷰에서는 미리 정의해 놓은 데이터 전달 방식에 따라 일관된 구조로 애플리케이션을 작성하게 됩니다. 그러므로 개발자 개개인의 스타일대로 구정되지 않고, 애플리케이션의 모두 동일한 데이터 흐름을 갖습니다. 이는 다른 사람의 코드를 빠르게 파악할 수 있어서 협업하기에 좋습니다.
. 이벤트 버스
상위에서 하위로 props를 전달하고 하위에서 상위로 이벤트를 전달하는 방법을 알아보았습니다. 이번에는 같은 레벨에 있는 컴포넌트 혹은 관계가 없는 컴포넌트 간 통신은 어떻게 해야할까요? 이럴 경우 이벤트 버스를 활용하면 원하는 컴포넌트에 바로 데이터를 전달할 수 있습니다. 이벤트 버스의 형식은 다음과 같습니다.
// 이벤트 버스를 위한 추가 인스턴스 1개 생성 var eventBus = new Vue();
요즘 많은 사이트들이 https 프로토콜을 사용을 합니다. 개발을 할때도 http 가 아닌 https 로 통신해야하는 경우가 있는데, SSL 인증서를 구입하기에는 비용이 비싼것으로 알고 있습니다. 간단하게 개발을 위한 사설 인증서를 발급받아서 https로 Tomcat을 구동하는 방법을 알아 보기로 합니다. 준비 사항이 있는데, 개발 PC에 JDK 와 Tomcat이 설치가 되어 있어야 합니다. 설치에 대한 내용은 간단한 것이므로 생략하도록 합니다.
* 명령어 중 빨간 글씨는 자신이 원하는 것으로 바꾸어도 됩니다.
JDK를 이용한 KeyStore 생성
JDK에서 제공하고 있는 keytool을 이용해 keystore를 생성합니다. Windows의 명령프롬프트를 관리자로 실행하여 아래와 같이 keytool을 실행합니다.
keytool은 다른 목적으로 storepass와 keypass를 사용합니다. storepass는 키 저장소에 액세스하는 데 사용됩니다. keypass는 특정 키 쌍의 개인 키에 액세스하는 데 사용됩니다. keyalg 는 key algorithm name 을 이야기하며 RSA라는 것으로 지정합니다. 그리고 저장장소는 "F:\Project\ssl\.keystore" 로 지정합니다.
C:\WINDOWS\system32>keytool -genkey -alias tomcat -keypass changeit -storepass changeit -keyalg RSA -keystore F:\Project\ssl\.keystore
이름과 성을 입력하십시오.
[Unknown]: localhost
조직 단위 이름을 입력하십시오.
[Unknown]:
조직 이름을 입력하십시오.
[Unknown]:
구/군/시 이름을 입력하십시오?
[Unknown]:
시/도 이름을 입력하십시오.
[Unknown]:
이 조직의 두 자리 국가 코드를 입력하십시오.
[Unknown]:
CN=localhost, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown이(가) 맞습니까?
[아니오]: 예
Warning:
JKS 키 저장소는 고유 형식을 사용합니다. "keytool -importkeystore -srckeystore F:\Project\ssl\.keystore -destkeystore F:\Project\ssl\.keystore -deststoretype pkcs12"를 사용하는 산업 표준 형식인 PKCS12로 이전하는 것이 좋습니다.
C:\WINDOWS\system32>
C:\에 .keystore가 생성되었습니다. 그런데 키 생성시 경고가 발생했습니다. 생성된 keystoretype 이 JKS 키로 생성되었는데, 이는 "Java KyeStore"의 준말로 Java 환경에서만 사용이가능하니, 산업 표준 형식인 PKCS12(Public Key Cryptogrephic Standards)로 변환을 하라는 것 입니다. PKCS12 는 여러 플랫폼에서 사용이 가능합니다. 변환은 아래 명령어로 변환합니다.
명령어를 실행하면 tomcat.cer 파일이 F:\Project\ssl 폴더에 생성됩니다.
Tomcat 설정
저는 이클립스를 사용할 것이기 때문에 아래와 같이 간단하게 Tomcat 서버 설정 후 Test 라는 프로젝트를 만들어 테스트를 진행하였습니다. 우선 http 통신과 Test 프로젝트가 동작되는 환경을 구성합니다.
1. 이클립스 [Window → Show View → Servers] 를 클릭합니다.
2. 아래와 같은 Servers 탭이 나타나는데 파란색 글씨를 클릭합니다.
3. Tomcat 을 추가하기 위하여 리스트의 apache 폴더 안의 Tomcat 을 자신의 PC에 맞는 버전으로 선택하여 줍니다. 저는 Tomcat 8.5가 설치되어 있기 때문에 "Tomcat v8.5 Server"를 선택하였습니다. 그리고 Tomcat 이 설치된 경로를 잡아주고 완료합니다.
4. 간단한 Test 프로젝트를 생성하고 "index.html" 파일을 만들어 줍니다. 그리고 Severs 탭에서 Tomcat v8.5에 마우스 오른쪽 버튼으로 나오는 메뉴 [Add and Remove] 선택합니다. Test 프로젝트를 Add 버튼으로 오른쪽으로 옮겨 줍니다.
5. 서버를 기동하여 "http://localhost:8080/Test/" URL로 접근하면 아래와 같이 화면이 나타납니다.
그렇다면 이제 Tomcat 설정 파일 server.xml 파일을 열어 SSL 통신을 위한 Connector 에 등록합니다. server.xml 파일은 아래와 같은 위치에 있으니 참고하십시오.
설정이 완료되었다면 Tomcat을 구동하여 "https://localhost:8443/Test/" 로 접속합니다. 그런데 아래 그림과 같이 안전하지 않은 사이트라고 판단을 하여 위험 화면이 나타납니다. 이는 신뢰하는 보안 인증서가 아니기 때문에 아래와 같이 위험 화면이 나타나는 것으로 화면 하단의 "고급" 버튼을 클릭하여 "localhost(안전하지않음)으로 이동" 을 클릭하면 정상적으로 페이지가 출력됩니다.
이러한 위험 페이지가 계속 나타난다면 개발하기 귀찮아 집니다. 그래서 아래와 같이 인증서를 브라우저에 등록하여 위험 페이지가 나오지 않다록 설정할 수 있습니다. 저는 크롬을 기반으로 설명을 하도록 하겠습니다.
1. 크롬에서 "chrome://settings/security" 를 입력하여 아래 "인증서 관리"를 클릭합니다.
2. 인증서 팝업창에서 "가져오기"를 선택하여 줍니다.
3. 인증서 가져오기 마법사가 실행되며 다음을 눌러 진행합니다. 이때 파일을 선택하는 화면에서 위에서 만들어준 "tomcat.cer" 파일을 찾아보기하여 선택합니다.
4. 인증서를 저장하는 부분은 "모든 인증서를 다음 장소에 저장" 선택 후, 인증서 저장장소는 찾아보기로 "신최할 수 있는 루트 인증 기관"을 선택하여 다음으로 진행하고 마법사를 완료합니다. "마침" 버튼을 클릭하면 보안 경고가 나오는데, "예"를 눌러 설치를 마무리 합니다.
이제 크롬을 재기동 후 "https://localhost:8443/Test/" 로 접속하면 위험페이지 없이 원하는 index.html 페이지가 표시되는 것을 확인 할 수 있습니다.
알고리즘 문제를 풀다보면 정렬을 해야하는 경우가 많이 발생합니다. 기본적으로 제공되는 Arrays.sort() 함수가 있지만 이것만으로 문제를 풀기에는 한계가 있습니다. 특히 다중차순을 요하는 문제는 직접 구현하는 것이 빠르고 이해가 쉽습니다.
기본적인 정렬 코드
아래는 오름차순, 내림차순, 다중차순의 기본 정렬 구현 코드입니다.
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Arrays;
import java.util.Comparator;
class Node implements Comparable<Node>{
int a;
int b;
public Node(int a, int b){
this.a = a;
this.b = b;
}
@Override
public int compareTo(Node tar) {
// tar 기준으로 tar vs this 중 tar 우선순위가 더 높으면 1
// tar 기준으로 우선순위가 동등하면 0
// tar 기준으로 tar vs this 중 tar 우선순위가 더 낮으면 -1
if(tar.a > this.a) return 1;
if(tar.a < this.a) return -1;
// 첫 수가 우선쉰위가 도등할때 아래 조건을 따른다.
if (tar.b < this.b) return 1;
if (tar.b > this.b) return -1;
return 0;
}
}
public class Sort_ex01 {
// 정렬
// 1. 오름차순
// 2. 내림차순
// 3. 다중차순
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
public static void main(String[] args) throws IOException {
Integer[] arr = {5,4,5,4,4,5};
//1. 오름차순
Arrays.sort(arr);
//2. 내림차순
Arrays.sort(arr, Comparator.reverseOrder());
//3. 다중차순
Node[] arrNode = new Node[6];
arrNode[0] = new Node(5,8);
arrNode[1] = new Node(4,2);
arrNode[2] = new Node(5,1);
arrNode[3] = new Node(4,9);
arrNode[4] = new Node(4,7);
arrNode[5] = new Node(5,3);
// 정렬조건
// 1) 첫번째 수가 큰수 우선
// 2) 두번째 수가 작은 수 우선
Arrays.sort(arrNode);
int a=1;
br.close();
bw.close();
}
}
오름차순, 내림차순은 Arrays.sort() 함수를 이용하여 구현이 간단합니다. 하지만 다중차순의 경우 정렬 조건이 1) 첫번째 수가 큰수, 2) 두번째 수가 작은 수 우선이라고 한다면 위 코드와 같이 class 를 만들어 Comparable 을 이용하여 구현하여 줍니다. 정렬 우선순위는 compareTo() 함수를 오버라이드 하여 구현하는데, tar 기준으로 tar vs this 중 tar 우선순위가 더 높으면 1, tar 기준으로 우선순위가 동등하면 0, tar 기준으로 tar vs this 중 tar 우선순위가 더 낮으면 -1이 중요합니다.
이러한 방법을 통하여 "숫자와 문자를 다음과 같은 우선순위 조건으로 맞추어 정렬 후 출력" 하는 문제도 해결이 가능합니다. (ex, 1)짝수 우선 2)숫자 오름차순 3)문자 오름차순)
컴포넌트란 조합하여 화면을 구성할 수 있는 블록을 의미합니다. 화면을 빠르게 구조화하여 일괄적인 패턴으로 개발할 수 있습니다. 화면의 영역을 컴포넌트로 쪼개서 재활용할 수 있는 형태로 관리하면 나중에 코드를 다시 사용하기가 편리합니다. 참고로 컴포넌트 간의 관계는 자료구조의 트리(Tree) 모양과 유사합니다.
- 컴포넌트 등록하기
컴포넌트를 등록하는 방법은 전역과 지역 두 가지가 있습니다.
지역(Local) 컴포넌트 : 특정 인스턴스에서만 유효한 범위를 가지고 있음, 특정 범위에서만 사용
전역(Global) 컴포넌트 : 여러 인스턴스에서 공통으로 사용할 수 있음, 뷰로 접근 가능한 모든 범위에서 사용 가능
전역 컴포넌트 등록
뷰 라이브러리를 로딩하고 나면 접근 가능한 Vue 변수를 이용하여 등록합니다. Vue 생성자에 .component()를 호출하여 됩니다. 형식은 아래와 같습니다.
간단한 화면부터 복잡한 화면까지, 멋진 화면을 만들기 위해서는 UI를 생각해 봐야합니다. 이를 설계라고 하는데, 인스턴스와 컴포넌트가 있어야 합니다. 이 두가지에 대해서 알아보도록 하겠습니다.
인스턴스와 컴포넌트를 레고에 비유한다면 인스턴스는 레고를 조립하는 기본 판을, 컴포넌트는 레고 블록을 의미한다.
뷰 인스턴스
뷰로 화면을 개발하기 위해 필수적으로 생성해야하는 기본 단위입니다. 인스턴스의 생성은 아래와 같은 형식으로 생성을 합니다.
new Vue({ ... });
위에서 new Vue() 로 인스턴스를 생성할 때 Vue를 생성자라고 합니다. Vue 생성자는 뷰 라이브러리를 로딩하고 나면 접근할 수 있습니다. 뷰로 개발할 때 필요한 기능들을 생성자에 미리 정의해 놓고 사용자가 그 기능을 재정의하여 편리하게 사용하도록 하기 위해서 입니다.
- 옵션
옵션 속성은 인스턴스를 생성할 때 재정의할 data, el, template 등의 속성을 의미합니다.
el : 뷰로 만든 화면이 그려지는 시작점을 의미, 뷰 인스턴스로 화면을 렌더링할 때 화면이 그려질 위치의 돔 요소를 지정해 주어야 한다.
template : 화면에 표시할 HTML, CSS 등의 마크업 요소를 정의하는 속성
methods : 화면 로직 제어와 관계된 메서드를 정의하는 속성
created : 뷰 인스턴스가 생성되자마자 실행할 로직을 정의할 수 있는 속성
- 유효 범위
뷰 인스터스를 생성하면 HTML의 특정 범위 안에서만 옵션 속성들이 적용되어 나타납니다.이것을 유효 범위라고 합니다. 인스턴스의 유효범위는 el 속성과 밀접한 관계가 있습니다. 아래는 new Vue()로 인스턴스를 생성하고 나서 화면에 인스턴스 옵션 속성을 적용하는 과정입니다.
뷰 라이브러리 파일 로딩 → 인스턴스 객체 생성 → 특정 화면 요소에 인스턴스를 붙임 → 인스턴스 내용이 화면 요소로 변관 → 변환된 화면 요소를 사용자가 최종확인
인스턴스의 유효 범위를 확인하기 위해서는 아래와 같이 유효 범위를 벗어나게 코딩을 해 보면 됩니다.
<div id='app'>
</div>
{{ message }}
인스턴스의 유효 범위는 el 속성으로 지정한 <div id='app'> 태그 아래 요소입니다. 위의 코드와 같이 {{ message }}가 유효범위 밖에 있으면 뷰에서 인식하지 못하기 때문에 화면에는 {{ message }} 그대로 출력됩니다.
- 라이프 사이클
인스턴스의 상태에 따라 호출할 수 있는 속성이 있습니다. 이것을 라이프 사이클 속성이라고 합니다. 그리고 라이프 사이클 속성에서 실행되는 커스텀 로직을 라이프 사이클 훅(hook)이라고 합니다. (옵션 부분에서 살펴본 created 와 같은 속성) 라이프 사이클 속성에는 총 8개가 있습니다.
라이프 사이클 단계를 크게 나누면 인스턴스의 생성, 생성된 인스턴스를 화면에 부착, 화면에 부착된 인스턴스의 내용이 갱신, 인스턴스가 제거되는 소멸의 4단계로 이루어 집니다. 각 단계 사이에 라이프 사이클 속성 created, mounted, updated 등이 실행됩니다.
beforeCreate : 인스턴스가 생성되고 나서 가장 처음으로 실행되는 라이프 사이클 단계, data 속성과 method 속성이 아직 인스턴스에 정의되어 있지 않음. 화면 요소에도 접근 불가
created : beforeCreate 라이프 사이클 단계 다음에 실행되는 단계, data 속성과 method 속성에 정의된 값에 접근하여 로직을 실행할 수 있지만, 아직 인스턴스가 화면 요소에 부착되지 전이기 때문에 template 속성에 정의된 돔 요소로 접근 불가, 컴포넌트가 생성되고 나서 실행되는 단계이기 때문에 서버에 데이터를 요청하여 받아오는 로직을 수행하기 좋음.
beforeMount : created 단계 이후 template 속서에 지정한 마크업 속성을 render() 함수로 변환한 후 el 속성에 지정한 화면 요소에 인스턴스를 부착하기 전에 호출되는 단계, render()함수가 호출되기 직전의 로직을 추가하기 좋음
mounted : el 속성에서 지정한 화면 요소에 인스턴스가 부착되고 나면 호출되는 단계, 화면 요서에 접근이 가능하여 제어를 하는 로직을 수행하기 좋음.
beforeUpdate : el 속성에서 지정한 화면 요소에 인스턴스가 부착되고 나면 인스턴스에 정의한 속성들이 화면에 치환됨. 치환된 값은 뷰의 반응성을 제공하기 위해 $watch 속성으로 감시함. 이를 데이터 관찰이라함. 관찰하고 있는 데이터가 변경되면 가상 돔으로 화면을 다시 그리기 전에 호출되는 단계, 변경 예정인 새 데이터에 접근할 수 있어 변경 예정 데이터의 값과 관련된 로직을 미리 넣을 수 있음.
updated : 데이터가 변경되고 나서 가상 돔으로 다시 화면을 그리고 나면 실행되는 단계, 데이터 변경 후 화면 요소 제어와 관련된 로직을 추가하기 좋은 단계
beforeDestroy : 뷰 인스턴스가 파괴되기 직전에 호출되는 단계, 아직 인스턴스에 접근 가능, 뷰 인스턴스의 데이터를 삭제하기 좋은 단계
destoryed : 뷰 인스턴스가 파괴되고 나서 후출되는 단계, 뷰 인스턴스에서 정의한 모든 속성이 제거되고 하위에 선언한 인스턴스들 또한 모두 파괴됨
개발자 도구의 Console 을 보면 뷰 라이프 사이클의 흐름대로 beforeCreate, created, mounted, updated 가 표시되는 것을 확인할 수 있습니다. updated는 mounted 에서 this.message 의 값을 변경하여 데이터 변경이 일어나 화면이 다시 그려지며 호출이 됩니다.