-Creation, Mounting, Updating, Destruction 으로 나눌 수 있음.

Creation : 컴포넌트 초기화 단계
-컴포넌트 초기화단계.
-사이클 중에 가장먼저 실행됨.
-컴포넌트가 DOM에 추가되기전임, 따라서 this.$el을 사용할 수 없음.
-created 훅은 먼저 부모 created 훅이 실행되고 자식이 created 훅이 실행됨.
-beforeCreate 훅과 created 훅이 존재함.

Mounting : DOM 삽입단계
-초기 렌더링 직전에 컴포넌트에 직접 접근할 수 있음. 서버렌더링에서는 지원하지 않음.
-컴포넌트 초기에 셋팅되어야할 데이터는 created 훅 단계에서 사용하는게 좋음.
-beforeMount 훅은 템플릿과 렌더함수들이 컴파일된 후에 첫 렌더링이 일어나기 직전에 실행됨.
-mounted 훅은 컴포넌트, 템플릿, 렌더링된 돔에 접근 가능.
-mounted 훅에서 mounted 훅 순서는 자식 mounted 훅이 실행되고 부모 mounted 훅이 실행됨.
-beforeMount 훅과 mounted 훅이 존재함.

Updating : 재랜더링 단계
-컴포넌트에서 사용되는 반응형 속성들이 변경되거나 어떤 이유로 재 렌더링이되면 실행됨.
-디버깅이나 프로파일링 등을 위해 컴포넌트 재 랜더링 시점을 알고싶을 때 사용하면됨.
-서버렌더링에서는 호출되지 않음.
-beforeUpdate 훅은 컴포넌트의 데이터가 변하여 업데이트 사이클이 시작될때 실행됨.
-beforeUpdate 훅은 DOM이 재 렌더링되고 패치되기 직전에 실행됨.
-beforeUpdate 훅은 재 랜더링 전의 새 상태의 데이터를 얻을 수 있고 더 많은 변경이 가능함. 이변경은 재 랜더링은 트리거되지 않음.

-updated 훅은 데이터가 변하여 재 렌더링이 일어날 후에 실행됨.
-updated 훅은 여기서 상태를 변경하면 무한루프에 빠질 수 있음. 모든 자식컴포넌트의 재 랜더링 상태를 보장하지는 않음.

Destruction : 해제 단계

-beforeDestroy 훅은 해제 되기 직전에 호출됨.
-beforeDestroy 훅은 이벤트리스너 또는 reactive subscription을 제거하고 싶으면 여기서 하면 좋음. 서버렌더링시 호출안됨.
-destroyed 훅은 해제된 후에 호출됨.
-destroyed 훅은 모든 리스너 하위인스턴스도 제거 및 해제됨. 서버렌더링시 호출안됨.

-------------------------------------------------------------------------------------------------------------------

컴포넌트에는 3가지로 이루어짐
- template : html, vue에서 제공하는 디렉티브, 템플릿, 다른 컴포넌트
- script : js 파일들
- style : css, scss 스타일 파일들

-------------------------------------------------------------------------------------------------------------------

assets : 정적인 자원 (img, js, css, font 등등)
components : .vue 파일 존재 (컴포넌트 존재)
router : .js 파일 존재 (http 사용, 또는 컴포넌트간에 통신을 위한 스크립트)
store : : .js 파일 존재 (vuex ??? 내용 존재)
view : .vue 파일 존재 (template, html, script, css 등등 내용이 존재)

Vue.js (JavaScript Framework) , 레퍼런스 : https://ojava.tistory.com/185

개발환경
-VS Code (툴)
-Node.js


1.VS Code 설치

URL = https://code.visualstudio.com/

-시스템 버전으로 설치한다 (유저버전도 있음)

2.Node.js 설치

URL = https://nodejs.org

cmd에서 버전확인 명령어
node -v
npm -v

vscode 터미널에서 npm init -y 명령어 실행하면 package.json 파일이 생성된다.

npm을 통해 Node Module를 설치하는 방법은 npm install [module] [option]이다.

express 설치 : npm install express --save


3. 크롬 브라우저에서 Vue.js devtools를 설치

https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd


4.vue CLI 3.0 설치

npm install -g @vue/cli 또는 yarn global add @vue/cli

버전확인 
vue --version

터미널에서 버전확인
vue.cmd --version


5.프로젝트 생성
vue create 프로젝트명 (케밥식으로 작성, ex : test-vue)

터미널에서 프로젝트 생성된다
vue.cmd create 프로젝트명

vue/cli 3.x 미만(1.x 혹은 2.x) 인 경우 : vue init webpack 프로젝트명

6.프로젝트 실행

실행 : npm run serve (프로젝트폴더로 이동 후 실행)
종료 : Ctrl + c

7.프로젝트 UI 실행

 

IntelliJ CE(CommunityEdition) 버전에서 SpringBoot 프로젝트 생성 기능을 제공하지 않는다.

그럼 CE 버전에서 SpringBoot 프로젝트를 개발 할 수 있는 방법은 https://start.spring.io/ 에서 프로젝트를 생성하고 Import 하면 된다.

zip파일을 다운로드 받고 압축 해제 후 IntelliJ에서 Open 한다

 

 sudo 명령어를 사용하여 제한적으로 실행하는 것이 시스템의 보안 측명에서 용이하다.

 

설정파일 위치 : /etc/sudoers 

 

계정명 호스트명=(실행 계정명) [NOPASSWD:] 명령어

 

항목  의미 
 계정명  명령어 실행 권한을 줄 계정명이나 그룹명. 모두에게 줄 경우 ALL
 호스트  실행할 대상 서버명이나 IP. 모든 서버가 대상이라면 ALL
 실행 계정명  명령어를 실행할 때 어떤 계정의 권한을 갖는지 설정하며 생략시 root 로 실행
 NOPASSWD  설정할 경우 명령어를 실행할 때 계정 암호를 물어보지 않음.
 명령어  실행을 허용하는 명령어의 경로. ALL 일 경우 모든 명령어를 허용

 

 

특정 사용자의 sudo를 사용할 수 있는 설정

userid    ALL=(ALL)    ALL

 

 

그룹에 포함된 모든 사용자가 sudo를 사용할 수 있는 설정

%wheel    ALL=(ALL)    ALL

패스워드 생략 설정

userid    ALL=(ALL)    NOPASSWD: ALL

%wheel    ALL=(ALL)    NOPASSWD: ALL

 

 

 

1. yum 이란

- RPM 기반 시스템용 패키지 설치/삭제/업데이트 도구

 

2. 기본사용법



 기능 명령어 
패키지 설치  yum install 패키지명 
패키지 삭제  yum remove 패키지명
패키지 업데이트  yum update 패키지명 
패키지 정보확인  yum info 패키지명 
패키지 검색  yum search 검색어 
패키지 목록 보기  yum list 
설치된 패키지 목록보기  yum list installed

 

※ 메이븐 저장소

- 중앙 저장소 : 오픈소스 라이브러리, 메이븐 플러그인, 메이븐 아키타입을 관리하는 저장소. 메이븐 2.0의 중앙 저장소 URL은 http://repo1.maven.org/maven2/  이다. 중앙 저장소는 원격 저장소 중의 하나이다. 중앙 저장소는 개발자가 임의로 라이브러리르 배포할 수 없다.

- 원격 저장소 : 메이븐 기반으로 프로젝트를 진행하는 경우 프로젝트에 필요한 모든라이브러리가 메이븐 중앙 저장소에 있는 것은 아니다. 이처럼 중앙 저장소에 없는 라이브러리를 한 곳에 모아두기 위하여 별도의 메이븐 저장소를 설치해 관리하는 것이 가능하다. 원격 저장소는 회사내에서만 사용하기 위한 용도의 사내 원격 저장소와 스프링소스에서 제공하는 메이븐 저장소처럼 외부에 위치하는 외부(공개) 원격 저장소가 있다.

- 로커 저장소 : 로컬 저장소는 메이븐을 빌드할 때 다운로드하는 라이브러리, 플러그인을 관리하는 개발자 pc의 저장소이다. 기본 로컬 저장소는 USER_HOME/.m2/repository 디렉토리이다.

http://mvnrepository.com  메이븐 중앙저장소에서 관리하는 라이브러리를 검색할 수 있도록 지원한다.

※ 의존 라이브러리 버전

메이븐은 의존 관계에 있는 라이브러리의 버전을 효율적으로 관리할 수 있도록 몇 가지 옵션을 제공한다.

(,) : 해당 버전을 제외

[,] : 해당 버전을 포함

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>[3.8, 4.8)</version>
</dependency>

JUnit 라이브러리 버전 중에 4.8보다 작으면서, 3.8보다 크거나 같은 버전중에서 가장 최신 버전과 의존 관계를 가진다. JUnit 라이브러리는 4.8보다 작은 버전 중 최신 버전인 4.7버전과 의존 관계를 갖도록 설정된다.

라이브러리 버전이 변경될 때마다 버전을 변경하는 것이 불편할 수 있다. 버전 번호를 변경하지 않고 가장 최신 버전의 라이브러리와 의존관계를 갖도록 설정하는 방법이 있다.

<version>LATEST</version> 또는 <version>RELEASE</version>

하지만, 라이브러리가 최신버전이라 기능이 비정상적으로 동작할 가능성이 있기 때문에 좋은 선택은 아니다.

Maven

※ 프로젝트 초반에 구축해야 할 것으로 생각하는 개발환경

- 빌드 환경을 자동화하기 위한 툴

- 개발을 위한 통합 개발환경(IDE)

- 소스 코드와 문서 관리를 위한 형상관리 툴

- 소스 코드의 지속적인 테스트 및 통합을 위한 지속적 통합

 

프로젝트 생성

명령 프롬프트에서

mvn archetype:generate -DgroupId=net.javajigi -DartifactId=myfirst -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false 입력한다.

 

groupId : 일반적으로 생성하는 프로젝트의 도메인명

artifactId : 프로젝트 이름

 

maven archetype list

명령 프롬프트에서 mvn archetype:generate -DarchetypeCatalog=internal (명령어) 입력한다.

 

※ 메이븐 설정 파일

- settings.xml : 메이븐 빌드 툴과 관련한 설정 파일

- pom.xml : 메이븐 기반 프로젝트에서 사용하는 설정 파일 (다른이름을 사용하여도 된다)

1.pom.xml의 기본 구성요소

- 프로젝트 기본 정보

- 빌드 설정

- 프로젝트 관계 설정

- 빌드 환경

 

※ 메이븐 라이프사이클

3개의 라이프사이클을 제공함

1.소스 코드를 컴파일, 테스트, 압축, 배포를 담당하는 기본 라이프사이클

2.빌드한 결과물을 제거하기 위한 clean 라이프사이클

3.프로젝트 문서 사이트를 생성하는 site 라이프사이클

Annotation

@Requried : 필수 프로퍼티 검사를 위한 용도로 활용됨.

- RequiredAnnotationBeanPostProcessor

@AutoWired : 의존 관계를 자동으로 설정할 때 사용되는 기능이며, 생성자, 필드, 메서드의 3곳에 적용 가능함. 의존관계는 Bean간의 의존관계로 생각하면 됨. 

AutoworedAnnotationBeanPostProcessor

@Resource : java 6 및 jee5 버전에 추가된 어노테이션 기능으로 어플리케이션에서 필요로 하는 자원을 자동으로 연결할 때 사용함. AutoWired와 유사함. 하지만 어노테이션 뒤에 name 속성이 들어감.

- CommonAnnotationBeanPostProcessor

ex) @Resource(name="hello")

리소스 어노테이션을 사용하기 위해서는 CommonAnnotationBeanPostProcesser을 등록하거나 <context:annotation-config>를 사용하면 됨.

 

※ AutoWired와 Resource의 차이점

- AutoWired는 Spring Framework에서 지원하는 Dependency 정의 용도의 annotation으로, 스프링에 종속적이긴하지만 정밀한 Dependency Injection이 필요한 경우에 유요함.

- Resource는 JSR-250 표준 annotation으로 스프링2.5 이상부터 지원 가능한 annotation임. annotation으로 인해 특정 프레임워크에 종속적인 어플리케이션을 구성하지 않기 위해서 @Resource를 사용함. 사용하기 위해서는 클래스패스 내에 jsr250-api.jar 파일이 추가되어야 함.

 

@Repository 스프링 2.0부터 제공함.

- 스프링 2.5부터 아래의 어노테이션 추가됨.

@Component

@Service - 비지니스로직을 처리하는 클래스에 적용함

@Contorller - 요청을 처리하는 부분에 적용함

Spring MVC를 이용하여 MVC 기반의 웹 어플리케이션을 개발하는 방법을 살펴본다.

Spring MVC

비록, Spring이 스트러츠를 비롯하여 다양한 웹 프레임워크와 비교적 잘 연동되는 편이긴 하지만, 서로 다른 두 프레임워크를 연동하기 위해서는 설정의 중복 등 개발 과정에서 불편함이 존재한다. 서로 잘 맞지 않는 단추를 억지로 끼워 맞추는 것 같다.

Spring 자체적으로 제공하는 MVC 프레임워크를 사용하면, Spring이 제공하는 AOP, 트랜잭션 처리, DI 등의 기능을 그대로 사용하면서 MVC 패턴에 기반하여 웹 어플리케이션을 개발할 수 있다. 또한, 스트러츠와 Spring을 연동하기 위해 설정의 중복과 같은 개발 과정상의 불편을 해소할 수도 있다.

본 글에서는 Spring MVC의 구성에 대해서 살펴보고, 실제로 Spring MVC를 사용하여 웹 어플리케이션을 개발하는 기본적인 방법을 살펴보도록 하겠다. 그외 Spring MVC를 이용한 웹 어플리케이션에 대해 좀더 자세한 내용이 알고 싶다면 http://www.springframework.org/documentation 사이트를 참고하기 바란다.

Spring MVC의 구성 및 실행 흐름

다른 MVC 기반의 프레임워크와 마찬가지로 Spring MVC도 컨트롤러를 사용하여 클라이언트의 요청을 처리하게 된다. 이 컨트롤러의 역할을 하는 것이 DispatcherServlet인데, DispatcherServlet을 비롯하여 Spring MVC의 주요 구성 요소는 표 1과 같다.

구성 요소 설명
DispatcherServlet 클라이언트의 요청을 전달받는다. Controller에게 클라이언트의 요청을 전달하고, Controller가 리턴한 결과값을 View에 전달하여 알맞은 응답을 생성하도록 한다.
HandlerMapping 클라이언트의 요청 URL을 어떤 Controller가 처리할지를 결정한다.
Controller 클라이언트의 요청을 처리한 뒤, 그 결과를 DispatcherServlet에 알려준다. 스트러츠의 Action과 동일한 역할을 수행한다.
ViewResolver Commander의 처리 결과를 보여줄 View를 결정한다.
View Commander의 처리 결과를 보여줄 응답을 생성한다.


이들 주요 구성 요소간의 메시지 흐름은 그림 1과 같다.


각 흐름을 좀더 자세하게 설명하면 다음과 같다.

  1. 클라이언트의 요청이 DispatcherServlet에 전달된다.
  2. DispatcherServlet은 HandlerMapping을 사용하여 클라이언트의 요청이 전달될 Controller 객체를 구한다.
  3. DispatcherServlet은 Controller 객체의 handleRequest() 메소드를 호출하여 클라이언트의 요청을 처리한다.
  4. Controller.handleRequest() 메소드는 처리 결과 정보를 담은 ModelAndView 객체를 리턴한다.
  5. DispatcherServlet은 ViewResolver로부터 처리 결과를 보여줄 View를 구한다
  6. View는 클라이언트에 전송할 응답을 생성한다.

여기서 개발자가 직접 개발해주어야 하는 부분은 클라이언트의 요청을 처리할 Commander 클래스와 클라이언트에 응답 결과 화면을 전송할 JSP나 Velocity 템플릿 등의 View 코드이다. 나머지, DispatcherServlet이나 HandlerMapping, ViewResolver 등은 Spring이 제공하는 기본 구현체를 사용하면 된다.

Spring MVC를 이용한 웹 어플리케이션 개발

Spring MVC를 이용하여 웹 어플리케이션을 개발하는 과정은 다음과 같다.

  1. 클라이언트의 요청을 받을 DispatcherServlet을 web.xml 파일에 설정한다.
  2. 요청 URL과 Controller의 매핑 방식을 설정한다.
  3. Controller의 처리 결과를 어떤 View로 보여줄 지의 여부를 결정하는 ViewResolver를 설정한다.
  4. Controller를 작성한다.
  5. 뷰 영역의 코드를 작성한다.

DispatcherServlet 설정 및 Spring 콘텍스트 설정

Spring MVC를 사용하기 위해서는 가장 먼저 web.xml 파일에 DispatcherServlet 설정을 추가해주어야 한다. DispatcherServlet은 서블릿 클래스로서 다음과 같이 서블릿 설정 및 서블릿 매핑 설정을 web.xml 파일에 추가해주면 된다.

<?xml version="1.0" ?>

<web-app version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
                        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <servlet>
        <servlet-name>example</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>example</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
</web-app>


위 설정은 모든 *.do로 들어오는 요청을 DispatcherServlet이 처리하도록 하고 있다.

DispatcherServlet은 설정 파일에서 지정한 서블릿 이름을 사용하여 Spring 설정 파일을 로딩한다. 예를 들어, 위 코드의 경우 DispatcherServlet의 이름이 "example"인데, 이 경우 사용되는 Spring 설정 파일은 'WEB-INF/example-servlet.xml' 이다.

만약 기본적으로 사용되는 Spring 콘텍스트 설정 파일이 아닌 다른 이름의 파일을 사용하고 싶다면 다음과 같이 contextConfigLocation 초기화 파라미터에 사용할 설정 파일의 목록을 지정해주면 된다.

    <servlet>
        <servlet-name>multipleConfig</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                /WEB-INF/mvc1.xml,
                /WEB-INF/mvc2.xml
            </param-value>
        </init-param>
        <load-on-startup>3</load-on-startup>
    </servlet>


이때 각 설정 파일은 콤마를 사용하여 구분한다. 만약 각 설정 파일에서 동일한 이름의 빈을 지정했다면 더 뒤에 위치한 설정 파일에 명시된 빈이 우선순위를 갖는다.

HandlerMapping 설정

클라이언트의 요청을 Spring의 DispatcherServlet이 처리하도록 설정했다면, 다음으로 해야 할 작업은 어떤 HandlerMapping을 사용할지의 여부를 지정하는 것이다. HandlerMapping은 클라이언트의 요청을 어떤 Commender가 수행할 지의 여부를 결정해주는데, 표 2와 같이 두 개의 구현체가 주로 사용된다.

구현체 설명
BeanNameUrlHandlerMapping 요청 URI와 동일한 이름을 가진 Controller 빈을 매핑한다.
SimpleUrlHandlerMapping Ant 스타일의 경로 매핑 방식을 사용하여 URI와 Controller 빈을 매핑한다.


BeanNameUrlHandlerMapping

BeanNameUrlHandlerMapping은 요청 URI와 동일한 이름을 갖는 Controller 빈으로 하여금 클라이언트의 요청을 처리하도록 한다. 예를 들어, http://some.com/hello.do 와 같은 요청 URL에 대해 "/hello.do" 라는 이름을 가진 Controller 빈이 해당 요청을 처리하도록 한다. 아래 코드는 BeanNameUrlHandlerMapping를 사용하는 경우의 Spring 설정 파일의 예를 보여주고 있다.

<?xml version="1.0" encoding="UTF-8" ?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <bean id="beanNameUrlMapping" 
        class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
    
    <bean name="/hello.do"
        class="net.daum.ts.techReport.report2.springmvc.HelloController" />
    
    <bean name="/login.do"
        class="net.daum.ts.techReport.report2.springmvc.LoginController" />
    
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/view/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>


만약 요청 URL이 http://some.com/login.do 였다면, 이름이 "/login.do"인 LoginController가 해당 요청을 처리하게 된다. 비슷한 이유로, http://some.com/hello.do 요청은 HelloController가 처리하게 된다.

HandlerMapping 빈을 따로 생성하지 않은 경우 DispatcherServlet은 기본적으로 HandlerMapping의 구현체로 BeanNameUrlHandlerMapping을 사용한다. 따라서, 위 코드에서 HandlerMapping과 관련된 설정은 생략할 수 있다.

SimpleUrlHandlerMapping

SimpleUrlHandlerMapping은 Ant 스타일의 매핑 방식을 사용하여 Controller를 매칭한다. 아래 코드는 SimpelUrlHandlerMapping을 사용하여 클라이언트의 요청 URL과 매핑될 Controller를 지정하는 예를 보여주고 있다.

<?xml version="1.0" encoding="UTF-8" ?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <bean id="beanNameUrlMapping" 
        class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <value>
                /content/*.html=contentController
                /**/help.html=helpController
            </value>
        </property>
    </bean>
    
    <bean name="contentController" 
        class="net.daum.ts.techReport.report2.springmvc.ContentController" />
    
    <bean name="helpController" 
        class="net.daum.ts.techReport.report2.springmvc.HelpController" />
    
    <bean id="viewResolver" 
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/view/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>


SimpleUrlHandlerMapping은 mappings 프로퍼티를 통해서 매핑 설정 목록을 입력받는다. 이때 설정의 이름은 Ant 스타일의 URL 경로를 의미하며, 값은 매핑될 Controller 빈의 이름을 의미한다. 예를 들어, 위 예제의 경우 http://some.com/content/1.html 이나 http://some.com/content/mvc.html 요청이 들어오면 contentController가 처리하도록 매핑하였다.

SimpleUrlHandlerMapping에서 사용되는 규칙은 다음과 같다.

  • ? - 한 글자에 매칭된다.
  • * - 0 개 이상의 글자에 매칭된다.
  • ** - 0개 이상의 디렉토리에 매칭된다.

아래는 org.springframework.util.AntPathMatcher API 문서에 예시로 나온 몇 가지 매핑 설정의 예이다.

  • com/t?st.jsp - com/test.jsp, com/tast.jsp 또는 com/txst.jsp 등에 매칭된다.
  • com/*.jsp - com 디렉토리에 있는 모든 .jsp에 매칭된다.
  • com/**/test.jsp - com 경로 아래에 위치한 모든 test.jsp와 매칭된다.
  • org/springframework/**/*.jsp - org/springframework 경로 아래에 위치한 모든 jsp와 매칭된다.

두 HandlerMapping 구현체의 공통 프로퍼티

앞서 살펴본 두 HandlerMapping 구현 클래스는 AbstractUrlHandlerMapping 클래스를 상속받고 있으며, AbstractUrlHandlerMapping 클래스는 AbstractHandlerMapping 클래스를 상속받고 있다. 이 두 클래스는 공통으로 사용되는 몇 가지 프로퍼티를 제공하고 있는데, 먼저 AbstractHandlerMapping 클래스는 다음과 같은 프로퍼티를 제공하고 있다.

프로퍼티 설명
interceptors 사용할 인터셉터의 목록
defaultHandler 매칭되는 핸들러를 찾지 못할 때 사용할 기본 핸들러
order 하나의 서블릿 콘텍스트에서 다수의 HandlerMapping을 사용할 수 있는데, 이 경우 HandlerMapping 간의 우선순위를 지정한다.


AbstractUrlHandlerMapping 클래스가 제공하는 프로퍼티 목록은 표 4와 같다.

프로퍼티 설명
alwaysUseFullPath 웹 어플리케이션 콘텍스트의 경로를 포함할 지의 여부를 결정한다. 예를 들어, 콘텍스트 경로가 /main 일때, http://some.com/main/a.html 에 대해, 이 값이 true면 /main/a.html 이 사용된다. 이 값이 false이면 /a.html이 사용된다. 기본값은 false이다.
urlDecode HandlerMapping에 요청 URL을 전달하기 전에 특정 인코딩을 사용해서 디코딩할지의 여부를 결정한다. 이 값을 true로 지정하면 요청에 명시된 인코딩이나 ISO-8859-1을 사용하여 디코딩한다. 기본값은 false이다.
lazyInitHandlers 싱글톤 타입의 핸들러에 대해 lazy initialization을 적용할지의 여부를 지정한다. 기본 값은 false이다.


ViewResolver 설정

HandlerMapping을 설정했다면, 이제 ViewResolver를 설정할 차례이다. ViewResolver는 Controller의 실행 결과를 어떤 뷰를 보여줄지의 여부를 결정하는 기능을 제공한다. 주로 사용되는 ViewResolver에는 다음의 두 가지가 존재한다.

  • InternalResourceViewResolver - JSP를 사용하여 뷰를 생성한다.
  • VelocityViewResolver - Velocity 템플릿 엔진을 사용하여 뷰를 생성한다.

InternalResourceViewResolver

InternalResourceViewResolver는 JSP를 사용하여 Commander의 결과 뷰를 생성할 때 사용된다. 아래 코드는 InternalResourceViewResolver의 설정 예를 보여주고 있다.

<?xml version="1.0" encoding="UTF-8" ?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <bean id="beanNameUrlMapping"
        class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
    
    <bean name="/hello.do"
        class="net.daum.ts.techReport.report2.springmvc.HelloController" />

    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/view/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>


InternalResourceViewResolver는 다음과 같이 두 개의 프로퍼티를 입력받는다.

  • prefix - Controller가 리턴한 뷰 이름 앞에 붙을 접두어
  • suffix - Controller가 리턴한 뷰 이름 뒤에 붙을 확장자

예를 들어, HelloController가 처리 결과를 보여줄 뷰의 이름으로 "hello"를 리턴했다고 하자. 이 경우 InternalResourceViewResolver에 의해 사용되는 뷰는 "/view/hello.jsp"가 된다. 따라서, /view/hello.jsp가 생성한 응답 결과 화면이 클라이언트에 전달된다.

VelocityViewResolver

VelocityViewResolver는 Velocity 템플릿을 사용하여 뷰를 생성할 때 사용된다. 아래 코드는 VelocityViewResolver의 설정 예를 보여주고 있다.

<?xml version="1.0" encoding="UTF-8" ?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <bean name="/hello.mul"
        class="net.daum.ts.techReport.report2.springmvc.HelloController" />
    
    <bean id="velocityConfig" 
        class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
        <property name="resourceLoaderPath" value="/view_vm/" />
        <property name="velocityProperties">
            <value>
                input.encoding=UTF-8
                output.encoding=UTF-8
            </value>
        </property>
    </bean>
    
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
        <property name="contentType" value="text/html; charset=UTF-8" />
        <property name="cache" value="true" />
        <property name="prefix" value="" />
        <property name="suffix" value=".vm" />
    </bean>
</beans>


VelocityViewResolver를 사용하기 위해서는 먼저 Velocity의 설정 정보를 관리해주는 VelocityConfigurer를 생성해주어야 한다. VelocityConfigurer에서 사용가능한 주요 프로퍼티는 다음과 같다.

  • resourceLoaderPath - Velocity 템플릿이 위치하는 경로 (웹 콘텍스트 루트 기준)
  • velocityProperties - Velocity 설정 프로퍼티

예를 들어, 위 코드의 경우는 웹 어플리케이션 루트에 위치한 /view_vm/ 디렉토리에 Velocity 템플릿 파일이 위치한다는 것을 의미한다.

VelocityViewResolver를 설정할 때에는 다음의 프로퍼티를 알맞게 지정해준다.

  • contentType - 응답의 컨텐트 타입을 지정한다.
  • prefix - InternalResourceViewResolver와 동일
  • suffix - InternalResourceViewResolver와 동일

위 설정의 경우, Controller가 선택한 뷰가 "hello"라고 한다면 /view_vm/hello.vm 파일이 템플릿으로 선택된다. 또한 생성되는 뷰의 컨텐트 타입은 "text/html" 이고 캐릭터셋은 UTF-8이 된다.

Controller 구현

지금까지는 환경 설정과 관련된 부분에 대해서 설명했는데, 이제 본격적으로 클라이언트의 요청을 처리하는 데 사용되는 Controller의 구현에 대해서 살펴보도록 하자. Controller를 구현하는 가장 간단한 방법은 Controller 인터페이스를 implements 하는 것이다. 하지만, Controller 인터페이스를 직접적 implements 하기 보다는, Controller 인터페이스를 implements 하고 몇 가지 추가적인 기능을 구현하고 있는 클래스들을 상속받아 Controller를 구현하는 것이 일반적이다.

Controller 인터페이스

org.springframework.web.servlet.mvc.Controller 인터페이스는 다음과 같이 정의되어 있다.

public interface Controller {
    
    ModelAndView handleRequest(HttpServletRequest request,
                               HttpServletResponse response)
                               throws Exception

}


Controller를 구현하는 가장 단순한 방법은 Controller 인터페이스를 구현한 뒤, handleRequest() 메소드를 알맞게 구현하는 것이다. 아래 코드는 구현 예이다.

package net.daum.ts.techReport.report2.springmvc;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

public class SimpleController implements Controller {

    public ModelAndView handleRequest(HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        // request를 사용하여 클라이언트 요청 분석 후
        // 클라이언트 요청에 따른 알맞은 처리
        ModelAndView mav = new ModelAndView("hello");
        mav.addObject("greeting", "안녕하세요");
        return mav;
    }

}


handleRequest() 메소드는 파라미터로 전달받은 request 객체와 response 객체를 사용하여 클라이언트가 요청한 기능을 알맞게 구현하면 된다.

handleRequest() 메소드는 ModelAndView 객체를 리턴한다. ModelAndView 객체는 클라이언트의 요청을 처리한 결과를 보여줄 뷰 페이지와 관련해서 다음과 같은 정보를 제공한다.

  • 결과를 보여줄 뷰 이름 지정 : 위 코드의 경우 "hello"를 뷰로 선택
  • 뷰에서 사용할 모델 데이터 : 위 코드의 경우 addObject() 메소드로 추가한 객체, 뷰에서는 "greeting" 이라는 이름을 사용하여 데이터에 접근할 수 있다.

예를 들어, ViewResolver를 다음과 같이 설정했다고 해 보자.

    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/view/" />
        <property name="suffix" value=".jsp" />
    </bean>


위 viewResolver는 "/view/" + 뷰이름 + ".jsp"를 뷰로 사용하게 된다. SimpleController는 뷰 이름으로 "hello"를 리턴하므로, "/view/hello.jsp"가 뷰로 사용된다. 또한, 이 뷰에서는 다음과 같이 ModelAndView에 저장된 객체를 사용할 수 있게 된다.

<%@ page contentType="text/html; charset=UTF-8" %>

<strong>${greeting}</strong> ..


AbstractController를 이용한 구현

Controller를 구현할 때에는 Controller 인터페이스를 직접 구현하기보다는, AbstractController 추상 클래스를 상속 받아 구현하는 경우가 더 많다. AbstractController 클래스는 Controller 인터페이스를 implements 하여 추가적인 기능을 제공하고 있다.

AbstractController 클래스는 표 5와 같은 프로퍼티를 제공하고 있으며, 이 프로퍼티를 사용하여 HTTP Session, 캐시 등의 설정을 제어할 수 있다.

프로퍼티 설명
supportedMethods Controller가 처리할 수 있는 메소드를 지정한다. GET과 POST 등 처리할 수 있는 메소드를 지정할 수 있다. 만약 지원되지 않는 메소드를 사용하여 요청이 들어오면 ServletException 예외를 발생시킨다.
requiresSession Controller가 HTTP Session을 필요로 하는 지의 여부를 지정한다. 이 값이 true인 경우, 클라이언트와 관련된 세션이 존재하지 않으면 ServletException 예외를 발생시킨다.
synchronizeSession HTTP Session을 사용하여 Controller에 대한 처리를 동기화 할지의 여부를 지정한다.
cacheSeconds HTTP 응답에 캐시와 관련된 디렉티브를 생성할지의 여부를 지정한다. 기본 값은 -1이며, 이 경우 캐시 디렉티브가 응답 결과에 포함되지 않는다.
useExpiresHeader HTTP 1.0에 호환되는 "Expires" 헤더의 사용 여부를 지정한다. 기본값은 true 이다.
useCacheHeader HTTP 1.1에 호환되는 "Cache-Control' 헤더의 사용 여부를 지정한다. 기본값은 true 이다.


AbstractController 클래스를 상속받아 Controller를 구현하는 클래스는 아래 코드와 같이 handleRequestInternal() 메소드를 구현해주면 된다.

package net.daum.ts.techReport.report2.springmvc;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;

public class HelloController extends AbstractController {

    @Override
    protected ModelAndView handleRequestInternal(HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        ModelAndView view = new ModelAndView("hello");
        view.addObject("greeting", "안녕하세요");
        return view;
    }

}


AbstractController 클래스의 handleRequest() 메소드는 내부적으로 필요한 작업을 수행한 뒤, handleRequestInternal() 메소드를 호출한다. 따라서, AbstractController 클래스를 상속받는 경우에는 handleRequest() 메소드가 아닌 handlerRequestInternal() 메소드를 구현해주어야 한다.

AbstractCommandController를 이용한 파라미터 값 전달

요청 파라미터의 값을 특정한 객체에 저장하고 싶다면 AbstractCommandController 클래스를 사용하면 된다. AbstractCommandController 클래스를 상속받은 클래스는 다음과 같이 handle() 메소드를 알맞게 구현해주면 된다.

package net.daum.ts.techReport.report2.springmvc;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractCommandController;

public class LoginController extends AbstractCommandController {

    @Override
    protected ModelAndView handle(HttpServletRequest request,
            HttpServletResponse response, Object command, BindException errors)
            throws Exception {
        LoginCommand loginCommand = (LoginCommand) command;
        authService.authenticate(loginCommand.getId(), loginCommand.getPassword());
        return new ModelAndView("loginSuccess", "loginCommand", loginCommand);
    }

}


handle() 메소드의 세 번째 파라미터는 파라미터의 값을 저장한 command 객체이다. 이 command 객체의 타입을 지정하기 위해서는 다음과 같이 Spring 설정 파일에서 commandClass 프로퍼티의 값으로 클래스의 이름을 지정해주면 된다.

    <bean name="/login.do"
        class="net.daum.ts.techReport.report2.springmvc.LoginController">
        <property name="commandClass" 
            value="net.daum.ts.techReport.report2.springmvc.LoginCommand" />
    </bean>


handle() 메소드에 전달되는 command 파라미터는 commandClass 프로퍼티에 지정한 타입의 객체가 된다. 이때 파라미터와 생성할 command 객체의 프로퍼티 사이의 매핑은 자바빈 스타일을 따른다. 예를 들어, 파라미터 이름이 id 인 경우 setId() 메소드를 통해 파라미터 값이 전달되며, 파라미터 이름이 address 인 경우 setAddress() 메소드를 통해 파라미터 값이 전달된다.

SimpleFormController를 이용한 폼 전송 처리

SimpleFormController는 AbstractCommandController와 마찬가지로 파라미터의 값을 객체에 저장할 때 사용된다. 차이점이 있다면, SimpleFormController는 폼 전송 개념이 적용되어 있다는 것이다. SimpleFormController는 POST 방식으로 요청이 들어올 경우 doSubmitAction() 메소드를 통해 요청을 처리하는 반면에, GET 방식으로 요청이 들어오면 "formView" 프로퍼티로 지정한 뷰를 출력한다.

SimpleFormController는 클라이언트가 POST로 전송한 데이터는 commandClass 프로퍼티로 지정한 타입의 객체에 저장되어 doSubmitAction() 메소드에 전달된다. 아래 코드는 SimpleFormController의 구현 예를 보여주고 있다.

package net.daum.ts.techReport.report2.springmvc;

import org.springframework.web.servlet.mvc.SimpleFormController;

public class LoginFormController extends SimpleFormController {

    @Override
    protected void doSubmitAction(Object command) throws Exception {
        LoginCommand loginCommand = (LoginCommand) command;
        if (!loginCommand.getId().equals("madvirus")) {
            throw new LoginFailException("invalid id: "+loginCommand.getId());
        }
    }

}


클라이언트가 요청한 작업을 성공적으로 수행하지 못한 경우, doSubmitAction() 메소드는 예외를 발생시켜서 올바르게 처리하지 못했음을 알리게 된다. 이 경우, 예외 타입에 따라 알맞게 예외 처리를 해 주어야 한다.

GET 방식으로 데이터를 전송하는 경우에는 doSubmitAction() 메소드가 호출되지 않는다. 대신, formView 프로퍼티로 지정한 뷰를 보여준다. 아래 코드는 SimpleFormController 클래스를 상속받은 클래스의 구현 예를 보여주고 있다.

    <bean name="/loginUsingForm.do"
        class="net.daum.ts.techReport.report2.springmvc.LoginFormController">
        <property name="commandClass" 
            value="net.daum.ts.techReport.report2.springmvc.LoginCommand" />
        <property name="formView" value="loginForm" />
        <property name="successView" value="loginSuccess" />
    </bean>


뷰 영역에 데이터를 전달하고 싶다면 다음과 같이 onSubmit() 메소드를 추가적으로 구현해주면 된다.

package net.daum.ts.techReport.report2.springmvc;

import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;

public class LoginFormController extends SimpleFormController {

    @Override
    protected void doSubmitAction(Object command) throws Exception {
        LoginCommand loginCommand = (LoginCommand) command;
        if (!loginCommand.getId().equals("madvirus")) {
            throw new LoginFailException("invalid id: "+loginCommand.getId());
        }
    }
    
    @Override
    protected ModelAndView onSubmit(Object command, BindException errors) 
    throws Exception {
        try {
            ModelAndView mav = super.onSubmit(command, errors);
            mav.addObject("loginCommand", command);
            return mav;
        } catch(Exception e) {
            throw e;
        }
    }
}


위 코드에서 super.doSubmit() 메소드를 호출하면 doSubmitAction() 메소드가 호출된다. 따라서, doSubmitAction() 메소드가 성공적으로 수행되면 ModelAndView.addObject() 메소드를 사용하여 뷰에 데이터를 전달할 수 있게 된다.

뷰의 구현

뷰에서는 ModelAndView 객체에 저장한 객체를 사용할 수 있다. 예를 들어, Controller에서 다음과 같이 ModelAndView에 데이터를 저장했다고 해 보자.

    protected ModelAndView handle(HttpServletRequest request,
            HttpServletResponse response, Object command, BindException errors)
            throws Exception {
        LoginCommand loginCommand = (LoginCommand) command;
        ModelAndView mav = new ModelAndView("loginSuccess");
        mav.addObject("loginCommand", loginCommand);
        return mav;
    }


이 경우 "loginSuccess" 뷰에 해당되는 JSP는 다음과 같이 EL(Expression Language)이나 request.getAttribute() 등의 메소드를 사용하여 ModelAndView 객체에 저장된 값을 사용할 수 있다.

로그인 정보: ${loginCommand.id}
<%
    LoginCommand cmd = (LoginCommand) request.getAttribute("loginCommand");
%>


Velocity 템플릿에서도 다음과 같이 Velocity의 템플릿 언어를 사용하여 ModelAndView 객체에 저장된 값을 사용할 수 있다.

<body>
인사말: ${greeting}
</body>

AOP (Aspect Oriented Programming) : 관점의 분리

- Joinpoint : '클래스의 인스턴스 생성 시점', '메소드 호출 시점' 및 '예외 발생시점'과 같이 어플리케이션을 실행할 때 특정 작업이 시작되는 시점을 '조인 포인트'라 한다.

- Advice : 조인포인트에 삽입되어져 동작할 수 있는 코드를 '어드바이스'라 한다.

- Pointcut : 여러 개의 조인포인트를 하나로 결합한(묶은) 것을 '포인트 컷' 이라고 부른다.

- Advisor : 어드바이스와 포인트컷을 하나로 묶어 취급하는 것을 '어드바이저'라 부른다.

- Weaving : 어드바이스를 핵심 로직 코드에 삽입하는 것을 '위빙' 이라 부른다.

- Target : 핵심 로직을 구현하는 클래스를 말한다.

- Aspect : 여러 객체에 공통으로 적용되는 공통 관점 사항을 '에스펙트' 라 부른다.

 

+ Recent posts