[spring] 스프링 MVC 인터페이스 구현 클래스


스프링 MVC 인터페이스 구현 클래스


스프링 MVC를 이용하면, 웹 어플리케이션에서 모델과 뷰, 컨트롤러 사이에 있는 의존관계를 의존 관계 주입 컨테이너인 스프링에서 관리하게 된다.

스프링 MVC는 org.springframework.web 패키지와 org.springframework.servlet.패키지에 포함된 클래스를 사용한다.


1. HandlerMapping 인터페이스 구현 클래스

(1) org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping

웹 요청 URL과 스프링 설정 파일에 정의한 컨트롤러의 name 속성을 맵핑시켜 컨트롤러를 찾는다. 스프링 설정 파일에  HandlerMapping을 전혀 정의하지 않을 때의 기본 클래스

BeanNameUrlHandlerMapping 클래스는 스프링 설정 파일에 컨트롤러를 정의하면서 지정한 name 속성의 값과 웹 요청 URL을 맵핑하는 HandlerMapping 구현 클래스이다.

<bean id="indexController" name="/index.html" class="controller.IndexController"

p:shopService-ref="shopService">

</bean>

BeanNameUrlHandlerMapping 클래스는 기본인 HandlerMapping 구현 클래스이기 때문에 스프링 설정 파일에 정의하지 않아도 된다.

Controller 클래스의 name 속성에 지정한 값을 그대로 경로로 사용한다. 다음 웹 요청 URL을 사용할 때만 IndexController 클래스가 호출된다.

http://localhos:8080/shopping3-1/index.html


(2) org.springframework.web.servlet.handler.SimpleUrlHandlerMapping

웹 요청 URL과 컨트롤러의 맵핑을 일괄 정의한다. 스프링 설정 파일에 컨트롤러의 정의가 분산되는 것을 방지한다.

스프링 MVC에서는, 어떤 URL에 요청이 들어오면 어느 컨트롤러가 처리할지를 컨트롤러와 URL의 맵핑으로 연관 짓는데, SimpleUrlHandlerMapping 클래스를 사용하면 그 맵핑을 설정 파일 한 곳에 모아 작성할 수 있다.

따라서, 스프링 MVC는 컨트롤러 클래스와 URL의 맵핑을 한곳에서 관리하기 위한 SimpleUrlHandlerMapping 클래스를 제공한다.

<!-- HandlerMapping -->

<bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

<property name="mappings">

<value>

/index.html=indexController

/detail.html=detailController

</value>

</property>

</bean>


<!-- Controller -->

<bean id="indexController" class="controller.IndexController" p:shopService-ref="shopService"></bean>


<bean id="detailController" class="controller.DetailController"

p:shopService-ref="shopService"> 

</bean>

SimpleUrlHanlerMapping 클래스에는 Properties 타입 maapings 프로퍼티가 있다. 이 mapping 프로퍼티에 웹 요청 URL과 컨트롤러를 지정한다. 


(3) org.springframework.web.servlet.handler.ClassNameHandlerMapping

컨트롤러에 어노테이션을 부여해서 웹 요청 URL과의 관련을 정의한다.


(4) org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping

ControllerClassNameHandlerMapping 클래스는 컨트롤러의 클래스 이름에서 URL을 추출한다. 클래스 이름에서 'Controller'를 뺀 나머지를 모두 소문자로 바꾼 문자열이 URL이 된다.

ex.) IndexController : /index*


2. ViewResolver 인터페이스 구현

(1) org.springframework.web.servlet.view.InternalResolverViewResolver

WEB-INF 폴더 안에 있는 뷰 자원을 해결한다. 스프링 설정 파일에 ViewResolver를 전혀 정의하지 않을 때의 기본 클래스이다.

InternalResolverViewResolver 클래스는 컨트롤러가 반환한 뷰 정보를 컨텍스트 상의 경로로 변화시켜 처리하는 클래스이다.

스프링 MVC는 기본 ViewResolver인 InternalResolverViewResolver를 암묵적으로 사용한다.

하지만 뷰 정보에 prefix 프로퍼티나 suffix 프로퍼티를 추가하거나, 뷰의 구현 클래스를 지정할 수 있다.(이를 이용하면 프로그램에 직접 경로를 기술하지 않고, 이동할 뷰 파일을 배치하는 규칙에 유연하게 대응할 수 있다.)

<bean id="internalResourceViewResolver"

class="org.springframework.web.servlet.view.InternalResourceViewResolver">

<property name="viewClass">

<value>org.springframework.web.servlet.view.JstlView</value>

</property>

<property name="prefix">

<value>/WEB-INF/jsp/</value>

</property>

<property name="suffix">

<value>.jsp</value>

</property>

</bean>


(2) org.springframework.web.servlet.view.ResourceBundleViewResolver

프로퍼티 파일에서 뷰 이름과 그 실체인 뷰를 관련 짓는다. 프로퍼티의 파일은 클래스패스 상에 배치한다.

ResourceBundleViewResolver 클래스는 View 인터페이스를 구현하는 클래스와, 이동할 뷰의 지정과 뷰 이름의 맵핑을 프로퍼티 파일로 관리한다.

InternalResolverViewResolver 클래스는 prefix, suffix를 지정해서 이동할 뷰 이름을 간략하게 할 수 있지만, 실제 뷰 이름을 변경하면 관련된 컨트롤러나 설정 파일도 수정해야 한다.

하지만, ResourceBundleViewResolver 클래스에서는 컨트롤러에서 지정한 것은 프로퍼티 파일에 정의된 뷰 이름이고, 뷰 이름은 설제 뷰 파일 이름이 아닌 임의의 이름을 붙일 수 있다.

때문에 뷰 파일 이름을 변경하더라도, 뷰 이름을 변경할 필요가 없고, 프로퍼티 파일 맵핑 내용을 수정할 뿐이다. 컨트롤러를 수정할 필요도 없다.

ResourceBundleViewResolver 클래스에서 사용하는 프로퍼티 파일 이름은 설정 파일의 basename 프로퍼티에 지정한다. 

<!-- ViewResolver -->

<bean id="resourceBundleViewResolver"

class="org.springframework.web.servlet.view.ResourceBundleViewResolver">

<property name="basename">

<value>views</value>

</property>

</bean>

basename 프로퍼티에 'views'라고 지정하고 있으므로, 스프링 MVC는 확장자 '.properties'를 추가해서 'views.properties'를 참조한다.

#userEntry View

userEntry.(class)=org.springframework.web.servlet.view.JstlView

userEntry.url=WEB-INF/jsp/userEntry.jsp

프로퍼티 파일에는, '뷰 이름.(class)'를 키로 해서 값에 View 인터페이스를 구현하는 클래스를, '뷰이름.url'을 키로 해서 값에 이동할 뷰 파일을 지정한다. 뷰 이름은 임의로 정할 수 있다.


(3) org.springframework.web.servlet.view.velocity.VelocityViewResolver

벨로시티 템플릿으로 만든 뷰를 해결한다.


3. View 인터페이스 구현

(1) org.springframework.web.servlet.view.internalResourceView

JSP 등 자원용 뷰, 요청 속성에 모델을 지정하고, RequestDispather클래스를 참조해서 지정된 뷰에 전달한다.


(2) org.springframework.web.servlet.view.JstlView

JSTL를 사용한 페이지용 뷰, InternalResourceView 클래스의 서브 클래스, 스프링의 메시지 자원 파일을 JSTL 포맷 태그에서 참조할 수 있게 된다.

JstlView 클래스는 JSTL을 사용해서 JSP를 만드는 것을 지원하는 클래스이며, View 인터페이스를 구현하고 있다. JstlView 클래스를 사용하면, JSTL 포맷 태그에서 스프링의 메시지 자원에 접근할 수 있다.

JstlView 클래스는 앞에서 사용한 InternalReaourceView 클래스의 서브 클래스이다. 


(3) org.springframework.web.servlet.view.velocity.VelocityView

벨로시티 템플릿용 뷰


org.springframework.web.servlet.view.json.MappingJacksonJsonView

JSON 형식으로 출력하기 위한 뷰, JSON으로의 변환 라이브러리로서 Jackson 라이브러리가 필요




'Programing > Spring' 카테고리의 다른 글

[Spring] iBatis 1  (0) 2014.12.16
[Spring] web.xml 기본 설정  (1) 2014.12.13
[Spring] 스프링 MVC 패턴 개요  (0) 2014.12.13
[Spring] AOP 용어 설명  (0) 2014.12.13
[Spring] 의존관계 주입  (0) 2014.12.13

[Spring] 스프링 MVC 패턴 개요

스프링 MVC 패턴 개요


1. 스프링 MVC 패턴

‘MVC(Model View Controller)’란 비즈니스 규칙은 표현하는 도메인 모델(Model)과 프레젠테이션을 표현하는 View를 분리하기 위하여 양측 사이에 컨트롤러를 배치하도록 설계한 디자인 패턴이다.

‘스프링 MVC ’ 란 스프링이 제공하는 웹 어플리케이션 구축 전용의 MVC 프레임워크이다. 스프링 MVC를 이용함으로써 웹 어플리케이션의 Model, View, Controller 사이의 의존 관계를 DI 컨테이너에서 관리하고 통일된 유연한 웹 어플리케이션을 구축할 수 있다.


2. 스프링 MVC 처리 흐름


스프링 MVC는 스트릿츠 등 웹 어플리케이션 프레임워크와 동일하게 Front Controller 패턴을 채용하고 있다. 

FrontController 패턴이란 핸들러 오브젝트를 매개로 하여 요청을 분배함으로써 요청을 통합하고, 요청에 대한 통일된 처리를 기술할수 있도록하기 위한 패턴이다.

다음 그림에서 보듯이 브라우저로부터 송신된 요청은 모두 스프링 MVC에 의해 제공되는DispatherServlet 클래스에 의해 관리되고 있다.


웹 브라우저로부터의 요청(Request)은 DispatcherServlet 인스턴스로 송신된다. 요청을 받은 DispatcherServlet 인스턴스는 어플리케이션 안에서 공통 처리를 실행한 다음, requestURL 고유의 처리를 실행하는 Request 컨트롤러(Controller 인스턴스)를 호출한다. 일반적으로 Request 컨트롤러는 처리 단위 별로 개발자가 작성하기 때문에 DispatcherServlet 인스턴스는 지정된 RequestURL이 어느 Request 컨트롤러에 맵핑되어 있는기를 알아야 한다. 그러나 DispatcherServlet은 어플리케이션에서 하나의 인스턴스일 뿐 랩핑 정보를 관리하는 기능을 갖고 있지 않는다. 

RequestURL과 Request 컨트롤러의 맵핑을 관리하고 있는 것은 HanadlerMapping 인스턴스이다. DispatcherSerγlet 인스턴스 HandlerMapping 인스턴스를 참조하여 HandlerMapping 인스턴스로부터 반환된 Controller 인스턴스로 처리를 전달한다. 처리가 전달된 Controller 인스턴스는 필요한 비즈니스 로직을 호출하여 처리 결과(모델)와 이동할 View 정보를 DispatcherServlet에 반환한다. 이들의 정보(모델과 View)는 스프링MVC가 제공하는 ModeAndView 인스턴스로 취급된다. 

그리고 Controller 인스턴스로부터 반환된 View는 논리 정보이기 때문에 DispatcherServlet 인스턴스는 그 View의 실체를 ViewResolver 인스턴스에 문의한다. DispatcherServlet은 ViewResolver 인스턴스에 의해 해결된 View 인스턴스에 대해 모댈을 rendering하여 처리 결과를 브라우저에 표시한다 이상이 스프링 MVC 처리의 흐름이다.


위의 그림에 있는 HandlerMapping, Controller, ViewResolver, View는 모두 스프링 MVC가 제공하는 인터페이스이다. 

그러나 인터페이스만으로는 어플리케이션이 이루어지지 않으므로 인터페이스를 구현한 클래스가 필요하다. 

하지만 어플리케이션 개발자가 각각의 인터페이스의 구현 클래스를 준비해야만 하는 것은 아니다. 스프링 MVC에는 인터페이스뿐만 아니라 각각의 인터페이스의 구현 클래스도 포함하고 있다.

통상 개발에서는 Controller를 제외한 HandlerlMapping, Viewresolver, View 인터페이스의 구현 클래스는 스프링 MVC에서 제공히는 구현 클래스를 활용하면 된다(Controller 인터페이스를 구현한 편리한 클래스도 준비되어 있다).

스프링 MVC는 이들의 구성 정보를 DI 컨테이너에서 관리하고 있다. 스프링 설정 파일을 어느 HandlerMapping의 구현 클래스를 사용할 것인지는 Controller 클래스로부터 호출할 비즈니스 로직을 연관 지음으로써 어플리케이션의 구성을 관리하면 된다.


(1) DispatcherServlet

웹 브라우저로부터 송신된 Request를 일괄적으로 관리한다 .

웹 브라우저로부터 요청은 DispatherServlet 인스턴스로 송신된다. DispatherSerlvet 인스턴스는 지정된 RequestURL이 어느 Request 컨트롤러에 맵핑되어 있는 가를 알아야 한다.


cf.) DispatherServlet 설정과 ApplicationContext 관계

DispatherServlet은 클라이언트의 요청을 중앙에서 처리하는 스프링 MVC의 핵심 구성 요소이다. 

web.xml 파일에 한 개 이상의 DispatherServlet을 설정할 수 있으며, 각 DispatherServle은  한 개의 WebApplicationContext를 갖게 된다.

또한, 각 DispatherServlet이 공유할 수 있는 빈을 설정할 수도 있다. 

DispatherServlet과 웹 어플리케이션을 위한 설정 방법 및 둘 사이의 관계에 대해서 살펴보자.


(2) HandlerMapping

- RequestURL과 Controller 클래스의 맵핑을 관리한다.

- HandlerMapping 인스턴스의 정의에 정의된 정보로부터 Controller에 해당하는 클래스(Request 컨트롤러)가 결정된다.

- BeanNameUrlHandlerMapping 클래스는 스프링 설정 파일 내에 정의된 Controller 클래스의 name 속성과 RequestURl과 맵핑하는 HandlerMapping 인터페이스의 구현 클래스이다.

- BeanNameUrlHandlerMapping 클래스는 name 속성으로 지정된 값을 그대로 context root 이하의 패스로 처리한다. 즉, 다음의 RequestURL이 웹 브라우저에서 보내졌을 경우에 여기에서 지정한 Controller 클래스가 호출되게 된다. HandlerMapping 인터페이스의 구현 클래스 중 디폴트 클래스:BeanNameUrlHandlerMapping


(3) Controller

Controller 인스턴스는 필요한 비즈니스 로직을 호출하여 처리 결과(모델)와 이동할 View 정보를 DispatherServlet에 반환된다. 

이들의 정보(모델과 view)는 스프링 MVC가 제공하는 ModelAndView 인스턴스로 취급된다. 

그리고 Controller 인스턴스로부터 반환된 View는 논리정보이기 때문에 DispatherServlet 인스턴스는 그 View의 실체를 ViewResolver 인스턴스에 문의한다. 

DispatherServlet은 ViewResolver 인스턴스에 의해 해결된 View 인스턴스에 대해 모델을 rendering하여 처리 결과를 브라우저에 표시한다. 

cf.) HandlerMapping, Controller, ViewResolver, View는 모두 스프링 MVC가 제공하는 인터페이스이다. 그러나 인터페이스만으로는 어플리케이션이 이루어지지 않으므로 인터페이스를 구현 클래스가 필요한다.

스프링 MVC에는 인터페이스뿐만 아니라 각각의 인터페이스의 구현 클래스도 포함하고 있다.

통상 개발에서는 Controller를 제외한 HandlerMapping, Viewresolver, View 인터페이스의 구현 클래스는 스프링 MVC에서 제공하는 구현 클래스를 활용하면 된다.(Controller 인터페이스를 구현한 편리한 클래스도 준비되어 있다.) 

스프링 MVC는 이들의 구성 정보를 DI 컨테이너에서 관리하고 있다.


(4) ModelAndView

1) Controller 처리 결과 후 응답할 view와 veiw에 전달할 값을 저장.

2) 생성자 

- ModelAndView(String viewName) : 응답할 view설정

- ModelAndView(String viewName, Map values) : 응답할 view와 view로 전달할 값들을 저장 한 Map 객체 

- ModelAndView(String viewName, String name, Object value) : 응답할 view이름, view로 넘길 객체의 name-value

3) 주요 메소드

- setViewName(String view) : 응답할 view이름을 설정

- addObject(String name, Object value) : view에 전달할 값을 설정 – requestScope에 설정됨

- addAllObjects(Map values) : view에 전달할 값을 Map에 name-value로 저장하여 한번에 설정 - requestScope에 설정됨

4) Redirect 방식 전송

- view이름에 redirect: 접두어 붙인다.ex) mv.setViewName(“redirect:/welcome.html”);


protected ModelAndView HandlerequestInternal(HttpServletRequest req,  HttpServletResponse res) throws Exception{

//Business Logic 처리

ModelAndView mv = new ModelAndView();      

mv.setViewName(“/hello.jsp”);

mv.addObject(“greeting”, “hello world”);

return mv;

}


(5) ViewResolver

Controller 클래스로부터 반환된 View 정보가 논리적인 View 이름일 경우에는 bean 설정파일에 정의되어 있는 ViewResolver 클래스를 이용하여 클라이언트에게 출력할 View 객체를 얻게 된다.

InternalResource ViewResolver 클래스는 Request 컨트롤러로부터 반환된 View 정보를 context root 이하의 패스로서 처리한다.

1) Controller가 넘긴 view이름을 통해 알맞은 view를 찾는 역할

- Controller는 ModelAndView 객체에 응답할 view이름을 넣어 return.

- DispatchServlet은 ViewResolver에게 응답할 view를 요청한다.

- ViewResolver는 View 이름을 이용해 알 맞는 view객체를 찾는다.

2) 다양한 ViewResolver를 SpringFramework는 제공한다.

- InternalResourceViewResolver : 뷰의 이름을 JSP, HTML등과 연동한 View를 return

- ViewResolver – Spring 설정파일에 등록한다.

Controller

ModelAndView mv = new ModelAndView();

mv.setViewName(“hello”)

위의 경우

/WEB-INF/jsp/hello.jsp 를 찾는다.


(6) View

프레젠테이션층으로의 출력 데이터를 설정한다.



'Programing > Spring' 카테고리의 다른 글

[Spring] iBatis 1  (0) 2014.12.16
[Spring] web.xml 기본 설정  (1) 2014.12.13
[spring] 스프링 MVC 인터페이스 구현 클래스  (0) 2014.12.13
[Spring] AOP 용어 설명  (0) 2014.12.13
[Spring] 의존관계 주입  (0) 2014.12.13

[Spring] AOP 용어 설명


AOP 용어 설명



1. Advice

언제 공통 관심 기능을 핵심 로직에 적용할 지를 정의하고 있다. 예를 들어, '메서드를 호출하기 전'(언제)에 '트랜잭션을 시작한다.'(공통기능)기능을 적용한다는 것을 정의하고 있다.

Target 클래스에 조인 포인트에 삽입되어져 동작(적용할 기능)할 수 있는 코드를 '어드바이스'라 한다.

관점으로서 분리되고 실행시 모듈에 위빙된 구체적인 처리를 AOP에서는 Advice라고 한다. Advice를 어디에서 위빙하는지는 뒤에 나오는 PointCut이라는 단위로 정의한다.

또한 Advice가 위빙되는 인스턴스를 '대상객체'라고 한다.

advice는 Pointcut에서 지정한 Jointpoint에서 실행되어야하는 코드이다.


cp.) 스프링의 Advice 타입

- Around Advice: Joinpoint 앞과 뒤에서 실행되는 Adcvice

- Before Advice: Joinpoint 앞에서 실행되는 Advice

- After Returning Advice: Jointpoint 메서드 호출이 정상적으로 종료된 뒤에 실행되는 Advice

- After Throwing Advice: 예외가 던져질 때 실행되는 Advice

- Introduction:  클래스에 인터페이스와 구현을 추가하는 특수한 Advice


2. JoinPoint

Advice를 적용 가능한 지점을 의미한다. 메서드 호출, 필드 값 변경 등이 Joinpoint에 해당한다.

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

실행시의 처리 플로우에서 Advice를 위빙하는 포인트를 JointPoint라고 한다. 구체적으로는 메서드 호출이나 예외발생이라는 포인트를 Joinpoint라고 한다.

인스턴의 생성시점, 메소드를 호출하는 시점, Exception이 발생하는 시점과 같이 어플리케이션이 실행될 때 특정작업이 실행되는 시점을 의미한다.


3. Pointcut

Joinpoint의 부분 집합으로서 실제로 Advice가 적용되는 Jointpoint를 나타낸다. 스프링에서는 정규 표현식이나 AspectJ 문법을 이용하여 Pointcut을 정의할 수 있다.

여러 개의 조인포인트를 하나로 결합한 것을 포인트 컷이라 한다.

하나 또는 복수의 Jointpoint를 하나로 묶은 것을 Pointcut 이라고 한다. Advice의 위빙 정의는 Pointcut을 대상으로 설정한다. 하나의 Pointcut에는 복수 Advice를 연결할 수 있다. 반대로 하나의 Advice를 복수 Pointcut에 연결하는 것도 가능하다.

Pointcut(교차점)은 JoinPoint(결합점)들을 선택하고 결합점의 환경정보를 수집하는 프로그램의 구조물이다. Target 클래스와 Advice가 결합(Weaving)될 때 둘 사이의 결합 규칙을 정의하는 것이다.


4. Weaving

Advice를 핵심 로직 코드에 적용하는 것을 weaving 이라고 한다.(분리한 관점을 여러 차례 모률에 삽입하는 것을 AOP에서는 위빙 (Weaving: 엮기)이라고 부른다.) 즉 공통 코드를 핵심 로직 코드에 삽입하는 것이 weaving이다.

어드바이스를 핵심 로직 코드에 삽입하는 것을  위빙이라고 한다.

Aspect를 target 객체에 제공하여 새로운 프록시 객체를 생성하는 과정을 말한다.


5. Aspect

여러 객체에 공통으로 적용되는 공통 관심 사항을 Aspect라고 한다. 트랜잭션이나 보안 등이 Aspect의 좋은 예이다.

여러 객체에 공통으로 적용되는 공통 관점 사항을 에스펙트라 한다.

Aspect는 AOP의 중심단위, Advice와 Pointcut을 합친 것이다.(Advisor)


6.Target

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

충고를 받는 클래스를 대상(target)이라고 한다. 대상은 여러분이 작성한 클래스는 물론, 별도의 기능을 추가하고자 하는 써드파티 클래스가 될 수 있다.


7. advisor

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

advisor와 Pointcut을 하나로 묶어 다루는 것을 Advisor라고 한다. Advisor는 스프링 AOP에만 있는 것인데, 관점 지향에서 관점을 나타내는 개념이라고 할 수 있다.


8. proxy

대상 객체에 Advice가 적용된 후 생성된 객체




cp.) 언제,어디서,누가,무엇을,어떻게, 왜 할 때 AOP 걸어라.....

내가 원하는 메소드 실행할 때(언제)

객체(어디서)

로그를 찍는 기능(누가)

로그를(무엇을)

앞뒤로(어떻게)


cp.) AOP 핵심

1. 대상: Target

2. 적용할 기능: advice

3. 대상의 어디에서 적용할지 구체적인 명시:pointcut


aspect와 advice의 관계(추상 명사와 구체 명사의 관계)

advice라는 코드를 내가 만듬

로그를 찍는 기능 자체를 aspect라고 한다. 




'Programing > Spring' 카테고리의 다른 글

[Spring] iBatis 1  (0) 2014.12.16
[Spring] web.xml 기본 설정  (1) 2014.12.13
[spring] 스프링 MVC 인터페이스 구현 클래스  (0) 2014.12.13
[Spring] 스프링 MVC 패턴 개요  (0) 2014.12.13
[Spring] 의존관계 주입  (0) 2014.12.13

[Spring] 의존관계 주입

의존관계 주입


1. 참조 Bean 주입하기



(1) 소스상에서 보는 bean 참조를 주입하는 모습

1) beans.xml

<?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-3.0.xsd">

    <bean id="messageBean" class="sample1.MessageBeanImpl" >

        <constructor-arg>

            <value>Spring</value>

        </constructor-arg>

        <property name="greeting">

            <value>Hello, </value>

        </property>     

        <property name="outputter">

            <ref local="outputter" />

        </property>

    </bean>

    <bean id="outputter" class="sample1.FileOutputter">

        <property name="filePath">

            <value>out.txt</value>

        </property>

    </bean>

</beans>


2)  MessageBeanImpl.java

import java.io.IOException;

public class MessageBeanImpl implements MessageBean {

    

    private String name;

    private String greeting;

    private Outputter outputter;


    public MessageBeanImpl(String name) {

        this.name = name;

    }

        

    public void setGreeting(String greeting) {

        this.greeting = greeting;

    }

    

    public void sayHello() {

        String message = greeting + name + "!";

        System.out.println(message);

        try {

            outputter.output(message);

        } catch(IOException e) {

            e.printStackTrace();

        }

    }

    

    public void setOutputter(Outputter outputter) { 

        this.outputter = outputter;

    }

    // id=outputter 참조변수가 id=messageBean의 property=outputter의 매개변수로 온 형태--> 의존성 주입

}


2. @Autowired 방식으로 주입


의존관계를 설정하는 또다른 방법이 바로 @Autowired이다.

@Autowired 어노테이션을 사용하면 Autowiring은 'byType', 즉, Bean의 타입을 사용해서 연결하는 방법으로 실행된다. 그리고 설정 파일 beans.xml에 <context-annotation-config/> 요소를 추가한다.

MessageBeanImpl 클래스의 outputter 프로퍼티는 @Autowired 어노테이션에 의해 자동의로 스프링이 의존관계를 설정하기 때문에 설정 파일에서 제거한다.

덧붙이면, @Autowired를 어노테이션을 적용하려면, BeanFactory가 아니라 ApplicationContext를 사용해야 한다.

--> @Autowired를 사용할 경우 바뀌는 부분을 표시해보겠다.


(1) @Autowired 방식

1) beans.xml

<?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:context="http://www.springframework.org/schema/context"

xsi:schemaLocation="http://www.springframework.org/schema/beans

              http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

              http://www.springframework.org/schema/context

              http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:annotation-config/> 

   <bean id="messageBean" class="sample1.MessageBeanImpl" >

        <constructor-arg>

            <value>Spring</value>

        </constructor-arg>

        <property name="greeting">

            <value>Hello, </value>

        </property>        

        <property name="outputter">

            <ref local="outputter" />

        </property>

    </bean>

    <bean id="outputter" class="sample1.FileOutputter">

        <property name="filePath">

            <value>out.txt</value>

        </property>

    </bean>

</beans>



2) MessageBeanImpl.java

import java.io.IOException;

public class MessageBeanImpl implements MessageBean {

    

    private String name;

    private String greeting;

    private Outputter outputter;

    @Autowired

    private Outputter outputter;

    // MessageBeanImpl 클래스가 이름이 outputter인 프로퍼티를 갖고 있다면 이름(id)이 outputter인 빈 객체가 프로퍼티의 값으로 전달된다.

    // 이렇게 하면 설정(setter) 메서드를 기술할 필요가 없다. 스프링이 필드에 직접 주입한다.

    // 즉, <property>에 주입할 필요 없이 필드의 데이터 타입을 체크하여 일치하는 외부의 Bean 주입받아 사용할 수 있다. 

    public MessageBeanImpl(String name) {

        this.name = name;

    }

        

    public void setGreeting(String greeting) {

        this.greeting = greeting;

    }


   @Autowired

   public void setOuputter(Outputter outputter){

        this.outputter = outputter;

   }

    

    public void sayHello() {

        String message = greeting + name + "!";

        System.out.println(message);

        try {

            outputter.output(message);

        } catch(IOException e) {

            e.printStackTrace();

        }

    }

    

    public void setOutputter(Outputter outputter) {

        this.outputter = outputter;

    }

}




'Programing > Spring' 카테고리의 다른 글

[Spring] iBatis 1  (0) 2014.12.16
[Spring] web.xml 기본 설정  (1) 2014.12.13
[spring] 스프링 MVC 인터페이스 구현 클래스  (0) 2014.12.13
[Spring] 스프링 MVC 패턴 개요  (0) 2014.12.13
[Spring] AOP 용어 설명  (0) 2014.12.13

[DBMS_MySQL] MySQL 설치 및 사용자 추가,권한

MySQL 설치 및 사용자 추가,권한


1. MySQL 설치


다음과 같이 명령하면 MySQL이 설치됩니다.

yum install mysql-server


MySQL 서버를 실행시키는 명령어는 다음과 같습니다.

service mysqld start


root 사용자 비밀번호 생성

mysql -u root -p mysql

비밀번호를 입력하라고 나오는데 아직 비밀번호가 없으므로 엔터를 칩니다.


root의 비밀번호를 생성하는 명령은 다음과 같습니다. (new-password에 원하는 비밀번호를 넣으세요.)

mysql > update user set password=password('new-password') where user='root';


이제 권한 테이블을 업데이트합니다.

mysql > flush privileges;


다음과 같이 명령하여 MySQL에서 나옵니다.

mysql > quit;        



2. 사용자 추가 (권한추가)

mysql > create user 사용자ID; // 사용자 추가

mysql > create user userid@localhost identified by '비밀번호'; // 사용자(user)를 추가하면서 패스워드까지 설정


기존에 사용하던 계정에 외부 접근 권한을 부여하려면, Host를 '%' 로 하여 똑같은 계정을 추가한다

mysql > create user userid@'%' identified by '비밀번호';  // '%' 의 의미는 외부에서의 접근을 허용

mysql > FLUSH privileges; // 변경된 내용을 메모리에 반영(권한 적용)


cf.) 다른 방법으로는

mysql > USE mysql;  // mysql database 선택

mysql > INSERT INTO user (Host, User, Password) VALUES ('localhost', '계정아이디', password('비밀번호'));

mysql > INSERT INTO user (Host, User, Password) VALUES ('%', '계정아이디', password('비밀번호'));

mysql > FLUSH privileges; 


cf.) 사용자 삭제

mysql > drop user userid@'%'; // 사용자 삭제

mysql > drop user userid@localhost;

mysql > select * from user;    // 등록된 모든 사용자 ID 조회

mysql > delete from user where user = '사용자ID';    // 사용자 삭제


3. 사용자 권한 부여

계정이 생성되었다면, 그 계정이 접근할 수 있는 데이터베이스를 생성하고 권한을 부여해야 한다

MySQL은 사용자 이름, 비밀번호, 접속 호스트로 여러분을 인증한다. MySQL은 로그인을 시도하는 위치가 어디인가 하는 것도 인증의 일부로 간주한다.

MySQL 에서 사용자 계정을 추가하고 권한을 추가하거나 제거하는 데 GRANT 와 REVOKE 명령을 사용하기를 권장한다. 사용자에게 허가된 것을 확인하려면 SHOW GRANTS 를 사용한다.

mysql > GRANT ALL PRIVILEGES ON DB명.테이블 TO 계정아이디@호스트 IDENTIFIED BY '비밀번호'; 

// 계정이 이미 존재 하는데 'identified by '비밀번호' 부분을 추가하면 비밀번호가 변경된다


(1) localhost 접속 권한 추가 

mysql > GRANT ALL privileges ON database명.* TO 사용자ID@localhost IDENTIFIED BY '비밀번호';

mysql > GRANT ALL privileges ON database명.* TO 사용자ID@127.0.0.1 IDENTIFIED BY '비밀번호';


(2) localhost 의 경우 host명으로 접속하게 되는 경우

mysql > GRANT ALL privileges ON database명.* TO 사용자ID@'audi' IDENTIFIED BY '비밀번호';


(3) 모든 원격지 에서의 접속 권한 추가 

mysql > GRANT ALL privileges ON database명.* TO 사용자ID@'%' IDENTIFIED BY '비밀번호';


(4) 특정 테이블에서만 접속 권한 추가 

mysql > GRANT ALL privileges ON test.* TO 사용자ID@localhost identified by '비밀번호';


(5) 모든 테이블에 모든 원격지에서 접속 권한 추가

mysql > GRANT ALL privileges ON *.* TO 사용자ID@'%' identified by '비밀번호' ;  


(6) 변경사항 적용

mysql > flush privileges;


cf.)

mysql> grant select, insert, update on test.* to user@localhost identified by '비밀번호';

// user 에게 test 데이터베이스 모든 테이블에 select, insert, update 권한 부여--> ALL은 모든 권한 부여


cf.) 사용자에게 데이터베이스 사용권한 제거

revoke all on DB명.테이블명 from 사용자ID;   // 모든 권한을 삭제




'Server > DBMS' 카테고리의 다른 글

[DBMS_Oracle] 뷰 2  (0) 2014.12.15
[DBMS_Oracle] 뷰 1  (0) 2014.12.15
[DBMS_Oracle] 인덱스  (0) 2014.12.10
[DBMS_Oracle] 시퀀스  (0) 2014.12.08
[DBMS_Oracle] dual  (0) 2014.12.08

CentOS USB 설치하기

http://foxrain93.blog.me/100188324661

http://joyrisk.blog.me/220112167043

'Recent Link' 카테고리의 다른 글

RSS란 무엇인가  (0) 2015.01.04
[DB] DB2 마이그레이션  (0) 2014.11.29
[OS] Windows 7 업데이트 구성 실패  (0) 2014.11.29

[Java] abstract

abstract


1.  추상화란

추상[抽象]: 낱낱의 구체적 표상이나 개념에서 공통된 성질을 뽑아 이를 일반적인 개념으로 파악하는 정신 작용

즉. 프로그래밍에서는 추상화는 기존의 클래스의 공통부분을 뽑아내서 조상클래스를 만드는 것이다.

추상화를 구체화와 반대되는 의미로 이해하면 보다 쉽게 이해할 수 있다. 상속계층도를 따라 내려갈수록 클래스는 점점 기능이 추가되어 구체와의 정도가 심해지며, 상속 계층도를 따라 올라갈수록 클래스는 추상화의 정도가 심해진다고 할 수 있다.

즉, 상속계층도를 따라 갈수록 세분화되며, 올라갈수록 공통요소만 남게 된다.

추상화: 클래스간의 공통점을 찾아내서 공통의 조상을 만드는 작업

구체화: 상속을 통해 클래스를 구현, 확장하는 작업


2. 추상클래스

클래스를 설계도에 비유한다면 추상클래스는 미완성 설계도에 비유할 수 있다.

미완성 설계도란, 단어의 뜻 그대로 완성되지 못한 채로 남겨진 설계도를 말한다.

클래스가 미완성이라는 것은 멤버의 개수에 관계된 것이 아니라, 단지 미완성 메서드(추상메서드)를 포함하고 있다는 의미이다.

미완성 설계도로 완성된 제품을 만들 수 없듯이 추상클래스로 인스턴스는 생성할 수 없다.

추상클래스는 상속을 통해서 자손클래스에 의해서만 완성될 수 있다.

추상클래스 자체로는 클래스로서의 역할을 다 못하지만, 새로운 클래스를 작성하는데 있어서 바탕이 되는 조상클래스로서 중요한 의미를 

갖는다. 새로운 클래스르 작성할 때 아무 것도 없는 상태에서 시작하는 것보다는 완전하지는 못하더라도 어느 정도 틀을 갖는 상태에서 

시작하는 것이 나을 것이다.

실생활에서 예를 들자면, 같은 크기의 TV라도 기능의 차이에 따라 여러 종류의 모델이 있지만, 사실 이 들의 설계도는 아마 90%정도는

동일할 것이다. 서로 다른 세 개의 설계도를 따로 그리는 것보다는 이들의 공통부분만을 그린 미완성 설계도를 만들어 놓고, 이 미완성 설계도

를 이용해서 각각의 설계도를 완성하는것이 훨씬 효율적이다.

추상클래스는 키워드 'abstract'를 붙이기만 하면 된다. 이렇게 함으로써 이 클래스를 사용할 때, 클래스 선언부의 abstract를 보고 이 

클래스에는 추상메서드가 있으니 상속을 통해서 구현해주어야 한다는 것을 쉽게 알 수 있을 것이다.

추상클래스는 추상메서드를 포함하고 있다는 것을 제외하고는 일반클래스와 전혀 다르지 않다. 추상클래스에도 생성자가 있으며,

멤버변수와 메서드도 가질 수 있다.

cf.) 추상메서드를 포함하고 있지 않은 클래스에도 키워드 'abstract'를 붙여서 추상클래스로 지정할 수도 있다. 추상 메서드가 없는 

완성된 클래스라 할지라도 추상클래스로 지정되면 클래스의 인스턴스를 생성할 수 없다.


3. 추상 메서드

메서드는 선언부와 구현부(몸통)로 구성되어 있다고 했다. 선언부만 작성하고 구현부는 작성하지 않은 채로 남겨 둔 것이 추상메서드이다.

즉 설계만 해 놓고 수행될 내용은 작성하지 않았기 때문에 미완성 메서드인 것이다.

메서드를 이와 같이 미완성 상태로 남겨 놓는 이유는 메서드의 내용이 상속받는 클래스에 따라 달라질 수 있기 때문에 조상 클래스에서는

선언부만을 작성하고, 주석을 덧붙여 어떤 기능을 수행할 목적으로 작성되었는지 알려 주고, 실제 내용은 상속받는 클래스에서 구현하도록

비워 두는 것이다. 그래서 추상클래스를 상속받는 자손 클래스는 조상의 추상메서드를 상황에 맞게 적절히 구현해주어야 한다.

추상메서드 역시 키워드 'abstract'를 앞에 붙여 주고, 추상메서드는 구현부가 없으므로 괄호{}대신 문장의 끝을 알리는 ';'을 적어준다.

추상클래스로부터 상속받는 자손클래스는 오버라이딩을 통해 조상인 추상클래스의 추상메서드를 모두 구현해주어야 한다.

만일 조상으로부터 상속받은 추상메서드 중 하나라도 구현하지 않는다면, 자손클래스 역시 추상클래스로 지정해 주어야 한다.

abstract class Player{

abstract void play(int pos);//추상 메서드

abstract void stop();// 추상 메서드

}

class AudioPlayer extends Player{

void play(int pos){.....}// 추상 메서드를 구현

void stop(){.....}//추상 메서드를 구현

abstract class AbstractPlayer extends Player{

void play(int pos){.....}//추상 메서드를 구현

}

실제 작업내용인 구현부가 없는 메서드가 무슨 의미가 있을까 싶기도 하겠지만, 메서드를 작성할 때 실제 작업내용인 구현부보다 더 중요한 부분이 선언부이다.

메서드의 이름과 메서드의 작업에 필요한 매개변수, 그리고 작업의 결과로 어떤 타입의 값을 반환할 것인가를 결정하는 것은 쉽지 않은 일이다.

선언부만 작성해도 메서드의 절반 이상이 완성된 것이라 해도 과언이 아니다.

메서드를 사용하는 쪽에서 메서드가 실제로 어떻게 구현되어있는지 몰라도 메서드의 이름과 매개변수, 리턴타입, 즉 선언부만 알고 있으면 되므로 내용이 없을 지라도

추상메서드를 사용하는 코드를 작성하는 것이 가능하며 실제로는 자손클래스에 구현된 완성된 메서드가 호출되도록 할 수 있다.


4. 추상클래스의 작성

아래에 Player라는 추상클래스를 작성해 보았다. 이 클래스는 VCR이나 Audio와 같은 재생 가능한 기기(Player)를 클래스로 작설할 때, 이 들의 조상클래스로 사용될 수 있을 것이다.

abstract class Player{

boolean pause;// 일시정지 상태를 저장하기 위한 변수

int currentPos;// 현재 play되고 있는 위치를 저장하기 위한 변수

Player(){// 추상클래스도 생성자가 있어야 한다.

pause= false;

currentPos = 0;

}// 저장된 위치(pos)에서 재생을 시작하는 기능이 수행하도록 작성되어야 한다.


abstract void play(int pos);// 추상메서드

  // 재생을 즉시 멈추는 기능을 수행하도록 작성되어야 한다.

abstract void stop();// 추상메서드

play(currentPos); // 추상메서드를 사용할 수 있다.

}


void pause(){

if(pause){// pause가 true일 때(정지상태)에서 pause가 호출되면

pause = false;// pause의 상태를 false로 바꾸고,

play(currentPos);// 현재의 위치에서 play를 한다.

}else{//pause가 false일 때(play 상태)에서 pause가 호출되면,

pause=true;// pause의 상태를 true로 바꾸고

stop();// play를 멈춘다.

}

}

}


class CDPlayer extends Player{

// 조상 클래스의 추상메서드를 구현한다.

void play(int currentPos){

  ....실제 구현 내용

}

void stop(){

.... 실제 구현 내용

}

// CDPlayer 클래스에 추가로 정의된 멤버


int currentTrack;// 현재 재생중인 트랙

void nextTrack(){

currentTrack++;

....

}

void preTrack(){

if(currentTrack >1){

currentTrack--;

}

....

}

}


class CDPlayer extends Player{

// 조상 클래스의 추상메서드를 CDPlayer클래스의 기능에 맞게 완성해주고, CDPlayer만의 새로운 기능들을 추가하였다.

사실 Player클래스의 play(int pos)와 stop()을 추상메서드로 하는 대신, 아무 내용도 없는 메서드로 작성할 수도 있다. 아무런 내용도 없이 단지 괄호{}만 있어도,

추상메서드가 아닌 일반메서드로 간주되기 때문이다.


class Player{

...

void play(int pos){ }

void stop(){ }

...

}

어차피 자손 클래스에서 오버라이딩하여 자신의 클래스에 맞게 구현할 테니 추상메서드로 선언하는 것과 내용없는 빈 몸통만 만들어 놓는 것이나 별 차이가 없어 보인다.

그래도 굳이 abstract를 붙여서 추상메서드로 선언하는 이유는 자손클래스에서 추상메서드를 반드시 구현하도록 강요하기 위해서이다.

만일 추상메서드로 정의되어 있지 않고 위와 같이 빈 몸통만 가지도록 정의되어 있다면, 상속받는 자손 클래스에서는 이 메서드들이 온전히 구현된 것으로 인식하고 오버라이딩을 통해 자신의 클래스에 맞도록 구현하지 않을 수도 있기 때문이다.

하지만, abstract를 이용해서 추상메서드로 정의해 놓으면, 자손 클래스를 작성할 때 이들이 추상메서드이므로 내용을 구현해주어야 한다는 사실을 인식하고 자신의 클래스에 알맞게 구현할 것이다.


이번엔 기존의 클래스로부터 공통된 부분을 뽑아내어 추상클래스를 만들어 보도록 하자.

class Marine{ //보병

int x, y;// 현재 위치

void move(int x, int y){   }//지정된 위치로 이동

void stop(){   }//현재 위치에 정지

void stimPack(){   }// 스팀팩을 사용한다.

}


class Tank{

int x, y;// 현재 위치

void move(int x, int y){   }//지정된 위치로 이동

void stop(){   }//현재 위치에 정지

void changMode(){   }//공격 모드로 전환한다.

}


class Dropship{

int x, y;// 현재 위치

void move(int x, int y){   }//지정된 위치로 이동

void stop(){   }//현재 위치에 정지

void load(){   }// 선택된 대상을 태운다.

void unloas{   }//선택된 대상을 내린다.

}


이 유닛들은 각자 나름대로 기능을 가지고 있지만 공통부분만 뽑아내어 하나의 클래스로 만들고, 이 클래스로부터 상속받도록 변경해보자.

abstract class Unit{

int x,y;

abstract void move(int x, int y);

void stop(){//현재 위치에 정지

}


class Marine extends Unit{

void move(int x, int y){   }//지정된 위치로 이동

void stimPack(){   }// 스팀팩을 사용한다.

}


class Tank extends Unit{

void move(int x, int y){   }//지정된 위치로 이동

void changMode(){   }//공격 모드로 전환한다.

}


class Dropship extends Unit{

void move(int x, int y){   }//지정된 위치로 이동

void load(){   }// 선택된 대상을 태운다.

void unloas{   }//선택된 대상을 내린다.

}

이들 클래스에 대해서 stop메서드는 선언부와 구현부 모두 공통적이지만, Marine, Tank는 지상유닛이고 Dropship은 공중유닛이기 때문에 이동하는 방법이 서로 달라서 move메서드의 실제 구현 내용이 다를 것이다.

그래도 move메서드의 선언부는 같기 때문에 추상메서드로 정의할 수 있다. 최대한의 공통부분을 뽑아내기 위한 것이기도 하지만. 모든 유닛은 이동할 수 있어야 하므로 Unit클래스에는 move메서드가 반드시 필요한 것이기 때문이다.

move 메서드가 추상메서드로 선언된 것에는,  앞으로 Unit 클래스를 상속받아서 작성되는 클래스는 move 메서드를 자신의 클래스에 알맞게 반드시 구현해야 한다는 의미가 담겨 있는 것이기도 하다.


Unit[ ] group = new group[4];

group[0] = new Marine();

group[1] = new Tank();

group[2] = new Marine();

group[3] = new Dropship();


for(int i = 0; i <group.length; i++){

group[i].move(100,200);

}

위의 코드는 공통적인 Unit클래스 타입의 참조변수 배열을 통해서 서로 다른 종류의 인스턴스를 하나의 묶음으로 다룰 수 있다는 것을 보여 주기 위한 것이다. 다형성에서 배웠듯이 조상 클래스타입의 참조변수로 자손 클래스의 인스턴스를 참조하는 것이 가능하기 때문에 이처럼 조상 클래스타입의 배열에 자손 클래스의 인스턴스를 담을 수 있는 것이다.

만일 이들 클래스간의 공통 조상이 없다면 이처럼 하나의 배열로 다룰 수 없을 것이다. Unit클래스에 move메서드를 호출하는 것이 가능하다. 메서드는 참조변수의 타입에 관계없이 실제 인스턴스에 구현된 것이 호출되기 때문이다.

group[i].move(100,200)과 같이 호출하는 것이 Unit 클래스의 추상메서드인 move를 호출하는 것 같이 보이지만 실제로는 이 추상메서드가 구현된 Marine, Tank, Dropship인스턴스의 메서드가 호출되는 것이다.

모든 클래스의 조상인 Object클래스 타입의 배열로도 서로 다른 종류의 인스턴스를 하나의 묶음으로 다룰 수 있지만, Object클래스에는 move메서드가 정의되어 있지 않기 때문에 move메서드를 호출하는 부분에서 에러가 발생한다.


5. 인터페이스와 비교

인터페이스는 일종의 추상클래스이다. 인터페이스는 추상클래스처럼 추상메서드를 갖지만 추상클래스보다 추상화 정도가 높아서 추상클래스와 달리 몸통만 갖춘 일반메서드 또는 멤버변수를 구성원으로 가질 수 없다. 오직 추상메서드와 상수만을 멤버로 가질 수 있으며, 그 외의 다름 어떠한 요소도 허용하지 않는다.

추상클래스를 부분적으로만 완성된 '미완성 설계도'라고 한다면, 인터페이스는 구현된 것은 아무것도 없고 밑그림만 그려져 있는 '기본 설계도'라고 할 수 있다.

- 모든 멤버변수는 public static final 이어야 하며, 이를 생략할 수 있다.

- 모든 메서드는 public abstract 이어야 하며, 이를 생략할 수 있다.


 추상클래스

인터페이스 

 추상메서드+일반메서드, 멤버변수+상수

 추상메서드, 상수




'Programing > Java' 카테고리의 다른 글

[Java] 클래스멤버와 인스턴스멤버간의 참조와 호출  (0) 2014.12.14
[Java] 변수의 종류  (0) 2014.12.14
[Java] 인터페이스의 이해  (0) 2014.12.06
[Java] 형변환  (0) 2014.12.02
[Java] 실행  (0) 2014.12.02

[DBMS_Oracle] 인덱스


인덱스


1. 인덱스를 왜 사용하는 것일까요? 

이에 대한 답은 “빠른 검색을 위해서 인덱스를 사용합니다.” 입니다. 

여러분이 테이블 생성 방법을 책에서 찾으려고 할 때 어떻게 합니까? 책 첫 페이지부터 한 장씩 넘겨가면서 테이블 생성 방법이 기술되어 있는지 일일이 살펴보는 사람은 드물 것입니다. 

일반적으로 책 맨 뒤에 있는 색인(인덱스, 찾아보기)에서 해당 단어(테이블)를 찾아 그 페이지로 이동합니다. 

이렇게 원하는 단어를 쉽게 찾는 방법으로 색인, 인덱스가 사용되는 것처럼 오라클의 인덱스 역시 원하는 데이터를 빨리 찾기 위해서 사용됩니다. 


2. 인덱스의 장점

검색 속도가 빨라진다. 

시스템에 걸리는 부하를 줄여서 시스템 전체 성능을 향상시킨다.


3. 인덱스의 단점

인덱스를 위한 추가적인 공간이 필요하다.

인덱스를 생성하는데 시간이 걸린다.

데이터의 변경 작업(INSERT/UPDATE/DELETE)이 자주 일어날 경우에는 오히려 성능이 저하된다.


4. 인덱스 생성 확인 방법

USER_IND_COLUMNS 데이터 딕셔너리 뷰로 인덱스의 생성 유무를 확인해 봅시다. 

SELECT INDEX_NAME, TABLE_NAME , COLUMN_NAME

FROM USER_IND_COLUMNS

WHERE TABLE_NAME IN('EMP', 'DEPT');



5. 조회 속도 비교하기
- 인덱스가 조회 속도를 빠르게 해 준다는 것을 증명하기 위해서 기본 키나 유일 키로 지정하지 않는 컬럼인 사원 이름으로 검색해 봅시다. 
- 아마도 시간이 어느 정도 소요될 것입니다. 
- 검색을 위해서 WHERE 절에 사용되는 컬럼인 사원 이름 컬럼을 인덱스로 생성한 후에 다시 한번 사원 이름으로 검색해보면 검색시간이 현저하게 줄어드는 것을 확인할 수 있습니다. 

(1) 실습 [사원 테이블 복사하기]
다음은 인덱스로 인해 검색시간이 현저하게 줄어드는 것을 증명하기 위한 실습을 위해서 사원 테이블을 복사해서 새로운 테이블을 생성해 봅시다. 
1) 다음은 실습을 위해서 사원(emp) 테이블을 복사해서 새로운 테이블을 생성합니다. 
CREATE TABLE EMP01
AS
SELECT * FROM EMP;

2) EMP와 EMP01 테이블에 인덱스가 설정되어 있는지 확인합니다. 
SELECT TABLE_NAME, INDEX_NAME, COLUMN_NAME 
FROM USER_IND_COLUMNS
WHERE TABLE_NAME IN('EMP', 'EMP01');
결과 화면의 USER_IND_COLUMNS 를 살펴보면 EMP 테이블은 EMPNO 칼럼에 인덱스가 존재하지만 EMP를 서브 쿼리로 복사한 EMP01 테이블에 대해서는 어떠한 인덱스도 존재하지 않음을 확인할 수 있습니다. 서브 쿼리문으로 복사한 테이블은 구조와 내용만 복사될 뿐 제약 조건은 복사되지 않기 때문입니다.

(2) 실습 [인덱스가 아닌 컬럼으로 검색하기]
EMP01 테이블은 인덱스 설정이 되어 있지 않기에 검색하는데 시간이 걸립니다. 이를 증명하기 위해서 EMP01 테이블에 수많은 데이터가 저장되어 있어야 합니다. 서브 쿼리문으로 INSERT 문을 여러 번 반복해서 EMP01 테이블의 데이터를 늘린 후에 사원이름으로 특정 사원을 찾아보도록 합시다. 속도의 차이가 현저하게 난다는 것을 느낄 수 있습니다. 

1) 서브 쿼리문으로 INSERT 문을 여러 번 반복합시다. 
INSERT INTO EMP01 SELECT * FROM EMP01;
:
:
INSERT INTO EMP01 SELECT * FROM EMP01;

2) 이제 검색용으로 사용할 행을 새롭게 하나 추가합니다.
INSERT INTO EMP01
(EMPNO, ENAME)
VALUES(1111, 'SYJ');


3) 시간을 체크하기 위해서 다음과 같은 명령을 입력합니다. 
SET TIMING ON

4) 사원 이름이 ‘SYJ'인 행을 검색해 봅시다. 
SELECT DISTINCT EMPNO, ENAME 
FROM EMP01 
WHERE ENAME='SYJ';

컴퓨터의 성능에 따라 검색하는데 소요되는 시간이 다르겠지만, 어느 정도의 시간은 소요됨을 확인할 수 있습니다.

6. 인덱스 생성하기
- 제약 조건에 의해 자동으로 생성되는 인덱스 외에 CREATE INDEX 명령어로 직접 인덱스를 생성할 수도 있습니다. 
- 다음은 인덱스를 생성하기 위한 기본 형식입니다.
CREATE INDEX index_name
ON table_name (column_name);
CREATE INDEX 다음에 인덱스 객체 이름을 지정합니다. 어떤 테이블의 어떤 컬럼에 인덱스를 설정할 것인지를 결정하기위해서 ON 절 다음에 테이블 이름과 컬럼 이름을 기술합니다. 

(1) 실습 [인덱스 설정하기]
인덱스가 지정하지 않은 컬럼인 ENAME 으로 조회하여 어느 정도의 시간은 소요됨을 확인하였으므로 이번에는 ENAME 컴럼으로 인덱스를 지정하여 조회 시간이 단축됨을 확인해봅시다. 

1) 이번에는 테이블 EMP01의 컬럼 중에서 이름(ENAME)에 대해서 인덱스를 생성해봅시다. 
CREATE INDEX IDX_EMP01_ENAME
ON EMP01(ENAME);

2) 사원 이름이 ‘SYJ'인 행을 검색해 봅시다. 
SELECT DISTINCT EMPNO, ENAME 
FROM EMP01 
WHERE ENAME='SYJ';

인덱스를 생성한 후에 사원 이름이 ‘SYJ'인 행을 다시 검색하면 수행속도가 매우 감소함을 알 수 있습니다.

7. 인덱스 제거하기
- 인덱스가 검색 속도를 현저하게 줄이는 것을 확인하기 위해서 위와 같은 예제를 실습해 보았습니다. 
- 이번에는 인덱스를 삭제해봅시다. 
- 이를 위해서 오라클은 DROP INDEX 명령어를 제공합니다
DROP INDEX index_name;

(1) 실습
EMP01 테이블의 직급 컬럼을 인덱스로 설정하되 인덱스 이름을 IDX_EMP01_JOB로 줍시다. 
SELECT INDEX_NAME, TABLE_NAME , COLUMN_NAME
FROM USER_IND_COLUMNS
WHERE TABLE_NAME IN('EMP01');


8. 인덱스를 사용해야 하는 경우 판단하기

- 인덱스가 검색을 위한 처리 속도만 향상시킨다고 했습니다. 

- 하지만, 무조건 인덱스를 사용한다고 검색 속도가 향상되는 것은 아닙니다. 

- 계획성 없이 너무 많은 인덱스를 지정하면 오히려 성능을 저하시킬 수도 있습니다. 

- 언제 인덱스를 사용하는 것이 좋을까요?

- 다음과 같은 조건에서 사원 테이블의 부서 번호에 인덱스를 거는 것이 좋을까요? 

테이블에 전체 행의 수는 10000 건이다.

위의 쿼리문을 전체 쿼리문 들 중에서 95% 사용된다.

쿼리문의 결과로 구해지는 행은 10건 정도이다. 


- 조건을 위 표를 비추어보고 판단해 보면 DEPTNO 컬럼을 인덱스로 사용하기에 알맞다는 결론이 납니다. 

- 위 결론에 따라 사원 테이블의 부서 번호(DEPTNO)를 인덱스로 지정합시다. 

CREATE INDEX IDX_EMP01_DEPTNO

ON EMP01(DEPTNO);




'Server > DBMS' 카테고리의 다른 글

[DBMS_Oracle] 뷰 1  (0) 2014.12.15
[DBMS_MySQL] MySQL 설치 및 사용자 추가,권한  (0) 2014.12.13
[DBMS_Oracle] 시퀀스  (0) 2014.12.08
[DBMS_Oracle] dual  (0) 2014.12.08
[DBMS] HAVING 조건  (0) 2014.12.02

[Servlet] 서블릿 필터

서블릿 필터


서블릿은 웹에서 실행되는 프로그램이기 때문에 네트워크 통신의 사이 사이에서 특별한 동작을 만들어 낼 수 있다.

예를 들면, 홈페이지에 접속하기 직전에 이벤트 창을 띄운다든지 아니면 데이터를 입력한 후 실제 저장하는 페이지로 넘어가지 전에 넘겨지는 데이터들에 대하여 한글 처리를 한다든지 등의 작업을 할 수 있다.

또한, 세션이 만들어지거나 삭제될 때 이것을 감지하는 작업도 할 수 있다.

이렇게 여러가지 동작에 있어서 사이 사이에 끼워져서 실행되는 서블릿의 클래스를 필터라 부르고 동작이 발생할 때 감지하는 것을 이벤트라 부른다.


1. 서블릿 필터


필터는 말 그대로 여과 기능을 수행한다. 웹 프로그램에서도 하나의 페이지에서 다른 페이지로 전달되는 데이터가 필터를 지나 가공되거나 걸러지게 된다.

일반적으로 웹 프로그램은 A->B라는 식으로 실행 흐름이 있다. 그러나 기존의 흐름에 C라는 작업을 끼워 넣을 수 있다면 도움이 될 것이다.

예를 들어 A에서 B로 넘겨지는 데이터에 인코딩을 한다든지 데이터에 세션을 확인해서 B 페이지를 보여 줄지 작업 등을 할 수 있다.


(1) 본문

필터는 데이터를 가로채서 처리를 한다고 생각하면 된다. 하나의 작업에서 다른 작업으로 넘어갈 때나 어떤 작업이 또 다른 작업으로 넘어갈 때 데이터를 가로채서 처리를 할 수 있다.

요청이나 세션에 담긴 데이터뿐 아니라 헤더에도 필터가 적용될 수 있다. 기존 작업이 일어나기 직전(전처리)이나 일어나 직후(후처리) 모두 필터가 적용되는 시점이다.


웹 관련 클래스가 모두 그러하듯이 필터 클래스의 메서드도 요청 객체와 응답 객체를 매개변수로 가진다.

여기에 추가적으로 FilterChain 객체를 매개 변수로 갖는데, 이유는 필터 기능 자체가 페이지의 분기점에 있기 때문이다.

따라서, FilterChain 객체는 필터 기능이 완료되고 다음 페이지로 연결하는 기능에 사용된다. 또한, 서블릿의 일반 클래스처럼 web.xml 파일에 등록해야 한다.

당연하겠지만, 일반 클래스가 아니므로 <servlet> 태그가 아니라, <filter> 태그를 사용한다.

필터 관련 클래스로 javax.servlet.Filter, javax.servlet.FilterConfig, javax.servlet.FilterChain 등이 있다.


(2) 필터가 웹 프로그램에서 사용되는 경우

- 전달받은 데이터를 인코딩하는 경우

- 세션 데이터를 인증하는 경우

- 이벤트나 공지 등 팝업을 추가 하는 경우


(3) 예제(전달받은 데이터를 인코딩하는 경우)

1) web.xml

  <filter> <!--<filter> 태그는 <servlet> 태그보다 앞에 놓여야 한다./ 필터를 지정하는 역할-->

<filter-name>My_Ft_01</filter-name> <!--getFilterName()-->

<filter-class>Round18_01_Filter</filter-class>

</filter>

  <filter-mapping>

<filter-name>My_Ft_01</filter-name>

<url-pattern>/Servlet_01</url-pattern> /Servlet_01 서블릿에 접근하기 전에 필터를 거는 것이다.

    <!--<url-pattern>/*</url-pattern>--> URL 패턴에서 '/*' 와 같이 적으면 모든 페이지에 접근하기 전에 해당 필터 클래스가 실행된다.

</filter-mapping>

  <servlet>

<servlet-name>My_01</servlet-name>

<servlet-class>Round18_01_Servlet</servlet-class>

</servlet>


2) 자바코드

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;


public class Round18_01_Filter implements Filter {

// 필터는 Filter 인터페이스를 구현해야 한다.

public void init(FilterConfig fc) throws ServletException { } // 필터 초기화 작업

  // init() 메서드의 매개변수는 FilterConfig 객체이다.

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

   // 1. request 파라미터를 이용하여 요청의 필터 작업 수행

  // doFilter() 메서드를 사용하고, 매개 변수로는 반드시 ServletRequest, ServletResponse, FilterChain 세 가지를 사용한다. 

HttpServletRequest h_request = (HttpServletRequest)request;

String method = h_request.getMethod();

if(method.equalsIgnoreCase("POST")) {

request.setCharacterEncoding("euc-kr");

}

  

chain.doFilter(request, response);

    // 2. 체인의 다음 필터 처리

    // 3. response를 이용하여 응답의 필터링 작업 수행

    // 필터 메서드 내용부의 마지막 코드는 현재까지 작업한 내용을 적용하고 연결된 페이지로 이동하도록 만들어 준다. 이런 역할을 하는 메서드가 chain 객체의 doFilter()이다.

    // 세번째 매개변수인 FilterChain 클래스의 객체인 chain을 이용해서 다른 필터나 서블릿과 연결하는 코드를 반드시 작성해야 한다.

}

public void destroy() {

  // 4. 주로 필터가 사용한 자원을 반납

  }

}


(4)  web.xml 필터 설정하기
<web-app>    
     <filter><!-- 웹 어플리케이션에서 사용될 필터를 지정하는 역할 -->
        <filter-name>FilterName</filter-name><!-- getFilterName() -->
        <filter-class>javacan.filter.FilterClass</filter-class>
        <init-param><!-- getInitParameter() -->
           <param-name>paramName</param-name><!-- getInitParameter(String name)-->paramName은 파라미터 name 변수의 key값-->
 <!-- 필터가 초기화될 때, 즉 필터의 init() 메소드가 호출될 때 전달되는 파라미터 값, 이는 서블릿의 초기화 파라미터와 비슷한 역할을 하며 주로 필터를 사용하기 전에 
 초기화해야 하는 객체나 자원을 할당할 때 필요한 정보를 제공하기 위해 사용된다.-->
           <param-value>value</param-value><!-- getInitParameter(String name)에서 name 값--> value는 name 변수의 value값 -->
        </init-param>
     </filter>     
     <filter-mapping> <!-- 특정 자원에 대해 어떤 필터를 사용할지를 지정 -->
        <filter-name>FilterName</filter-name>
        <url-pattern>*.jsp</url-pattern>
        <!-- 클라이언트가 jsp 확장자를 갖는 자원을 요청할 경우 FilterName가 사용되도록 지정, 클라이언트가 요청한 특정 URI에 대해서 필터링을 할 때 사용 -->
     </filter-mapping>   
</web-app>
'/'로 시작하고 '/*'로 끝나는 url-pattern은 경로 매핑을 위해서 사용된다.
'*.'로 시작하는 url-pattern은 확장자에 대한 매핑을 할 때 사용된다.
오직 '/'만 포함하는 경우 어플리케이션의 기본 서블릿으로 매핑한다.
나머지 다른 문자열을 정확한 매핑을 위해서 사용된다.

   <filter-mapping>
        <filter-name>AuthCheckFilter</filter-name>
        <servlet-name>FileDownload</servlet-name>
     </filter-mapping>
     
     <servlet>
        <servlet-name>FileDownload</servlet-name>
        ...
     </servlet>
<url-pattern> 태그를 사용하지 않고 대신 <servlet-name> 태그를 사용함으로써 특정 서블릿에 대한 요청에 대해서 필터를 적용할 수도 있다. 예를 들면 다음과 같이 이름이 FileDownload인 서블릿에 대해서 AuthCheckFilter를 필터로 사용하도록 할 수 있다.

<filter-mapping>
<filter-name>AuthCheckFilter</filter-name>
<servlet-name>FileDownload</servlet-name>
<dispather>INCLUDE</dispather>
</filter-mapping>
<dispather> 태그는 실행되는 자원을 클라이언트가 요청한 것인지, 아니면 RequestDispather의 forward()를 통해서 이동한 것인지 아니면, 
아니면 include() 통해서 포함되는 것인지에 따라서 필터를 적용하도록 지정할 수 있다.

<dispather> 태그가 가질 수 있는 값은 다음과 같다.
REQUEST: 클라이언트의 요청인 경우에 필터를 사용한다.
FORWARD: forward()를 통해서 제어를 이동하는 경웽 필터를 사용한다.
INCLUDE: include()를 통해서 포함하는 경우에 필터를 사용한다.

2. Filter 인터페이스
Filter 인터페이스는 다음과 같은 메서드를 선언하고 있으며, 필터 기능을 제공할 클래스는 Filter 인터페이스를 알맞게 구현해주어야 한다.
1) public void init(FilterConfig filterConfig) throws ServletException 
--> 필터를 초기화할 때 호출한다.

2) public void doFilter(ServletRequest request, ServletResponse reponse, FilterChain chain) throws java.io.IOException, ServletException 
--> 체인을 따라 다음에 존재하는 필터로 이동한다. 체인의 가장 마지막에는 클라이언트가 요청한 최종 자원이 위치한다.

3) public void destory() 
--> 필터가 웹 컨테이너에서 삭제될 때 호출된다.
위 메서드에서 필터의 역할을 하는 메서드가 바로 doFilter() 메서드이다. 서블릿 컨테이너는 사용자가 특정한 자원을 요청했을 때 그 자원 사이에 필터가 종재할 경우 필터 객체의 doFilter() 메서드를 호출하며 바로 이 시점부터 필터가 작용하기 시작한다. 

public  class FirstFilter implements Filter{
public void init(FilterConfig filterConfig) throws ServletException{// 필터 초기화 작업
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException{
// 1. request 파라미터를 이용하여 요청의 필터 작업 수행
....
// 2. 체인의 다음 필터 처리
chain.doFilter(request, response);
// 3. response를 이용하여 응답의 필터링 작업 수행
....
}
  // 4. 주로 필터가 사용한 자원을 반납
public void destory{
}
}
위 코드에서 Filter 인터페이스의 doFilter() 메서드는 요청이 있을 때마다 매번 실행된다. 예를 들어, 클라이언트가 요청한 자원이 필터를 거치는 경우 클라이언트의 요청이 있을 때 마다 doFilter() 메서드가 호출되며, doFilter() 메서드는 JSP/서블릿과 마찬가지로 요청에 대해서 알맞은 작업을 처리하게 된다.

※ doFIilter() 메서드내에서 이루어지는 작업의 순서
1) request 파라미터를 이용하여 클라이언트의 요청 필터링: 1단계에서는 RequestWrapper 클래스를 사용하여 클라이언트의 요청을 변경한다.
2) chain.doFiter() 메서드 호출: 2단계에서는 요청의 필터링 결과를 다음 필터에 전달한다.
3) response 파라미터를 사용하여 클라이언트로 가는 응답 필터링: 3단계에서는 체인을 통해서 전달된 응답 데이터를 변경하여 그 결과를 클라이언트에 전송한다.

※ FilterConfig가 제공하는 메서드

 메서드

 리턴 타입

 설명

 getFilterName()

 String

 설정파일에서 <filter-name>에서 지정한 필터의 이름을 리턴한다.

 getInitParameter(String name)

 String

 설정파일의 <init-param>에서 지정한 초기화 파라미터의 값을 읽어온  다. 존재하지 않을 경우 null을 리턴한다.

 getInitParameterNames()

 Enumeration<String>

 초기화 파라미터의 이름 목록을 구한다.

 getServletContext()

 ServletContext

 서블릿 컨텍스트 객체를 구한다.


3. 요청 및 응답 래퍼 클래스

필터가 필터로서의 제기능을 하기 위해서는 클라이언트의 요청을 변경하고, 또한 클라이언트로 가는 응답을 변경할 수 있어야 할 것이다. 

이러한 변경을 할 수 있도록 해주는 것이 바로 ServletRequestWrapperServletResponseWrapper이다.

서블릿 요청/응답 래퍼 클래스를 이용함으로써 클라이언트의 요청 정보를 변경하여 최종 자원인 서블릿/JSP/HTML/기타 자원에 전달할 수 있고, 또한 최종 자원으로부터의 응답 결과를 변경하여 새로운 응답 정보를 클라이언트에 보낼 수 있게 된다.


서블릿 요청/응답 래퍼 클래스로서의 역할을 수행하기 위해서는 javax.servlet 패키지에 정의되어 있는 ServletRequestWrapper 클래스와 ServletResponseWrapper 클래스를 상속받으면 된다. 

하지만, 대부분의 경우 HTTP 프로토콜에 대한 요청/응답을 필터링 하기 때문에 이 두 클래스를 상속받아 알맞게 구현한 HttpServletRequestWrapper 클래스와HttpServletResponseWrapper 클래스를 상속받는 경우가 대부분일 것이다.


HttpServletRequestWrapper 클래스와 HttpServletResponseWrapper 클래스는 모두 javax.servlet.http 패키지에 정의되어 있으며, 이 두 클래스는 각각 HttpServletRequest 인터페이스와 HttpServletResponse 인터페이스에 정의되어 있는 모든 메소드를 이미 구현해 놓고 있다. 필터를 통해서 변경하고 싶은 정보가 있을 경우 그 정보를 추출하는 메소드를 알맞게 오버라이딩하여 필터의 doFilter() 메소드에 넘겨주기만 하면 된다. 예를 들어, 클라이언트가 전송한 "company" 파리머터의 값을 무조건 "JavaCan.com"으로 변경하는 요청 래퍼 클래스는 다음과 같이 HttpServletRequestWrapper 클래스를 상속받은 후에 getParameter() 메소드를 알맞게 구현하면 된다.


import java.util.Collections;

import java.util.Enumeration;

import java.util.HashMap;

import java.util.Map;


import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletRequestWrapper;


// 요청 레퍼 클래스로 동작하기 위해 HttpServletRequestWrapper 클래스를 상속받는다.

public class NullParameterRequestWrapper extends HttpServletRequestWrapper {


private Map<String, String[]> parameterMap = null;

public NullParameterRequestWrapper(HttpServletRequest request) {

super(request);

// 생성자는 전달받은 request의 파라미터의 정보를 parameterMap에 저장한다.

parameterMap = new HashMap<String, String[]>(request.getParameterMap());

}

// checkNull() 메서드는 검사할 파라미터의 이름 목록을 인자로 전달받는다. 인자로 전달받은 각각의 이름을 검사해서 해당 이름의 파라미터가 존재하지 않으면

// 기본값으로 빈 문자열을 저장한다.

public void checkNull(String[] parameterNames) {

for (int i = 0; i < parameterNames.length; i++) {

if (!parameterMap.containsKey(parameterNames[i])) {

String[] values = new String[] { "" };

parameterMap.put(parameterNames[i], values);

}

}

}


@Override

public String getParameter(String name) {

String[] values = getParameterValues(name);

if (values != null && values.length > 0)

return values[0];

return null;

}


@Override

public Map<String, String[]> getParameterMap() {

return parameterMap;

// 파라미터와 관련된 메서드를 구현해서 parameterMap으로부터 파라미터값을 읽어오도록 한다.

}


@Override

public Enumeration<String> getParameterNames() {

return Collections.enumeration(parameterMap.keySet());

}


@Override

public String[] getParameterValues(String name) {

return (String[]) parameterMap.get(name);

}

}




'Programing > JSP/Servlet' 카테고리의 다른 글

[JSP] 커넥션 풀  (2) 2014.12.19
[Servlet] 서블릿 이벤트  (0) 2014.12.18
[Servlet] 서블릿 기초  (0) 2014.12.10
[Servlet] 데이터 저장 영역  (0) 2014.12.10
[Servlet] 초기화 파라미터  (0) 2014.12.09

[Servlet] 서블릿 기초

서블릿 기초


-HttpServlet을 상속받는 클래스는 doGet() 메소드를 오버라이딩할 수 있기 때문에 이 클래스는 서블릿으로 동작할 수 있게된다.


1. 서블릿 기본

1 서블릿 규약에 따라 자바 코드를 작성한다.

2 자바 코드를 컴파일해서 클래스 파일을 생성한다.

3 클래스 파일을 /WEB-INF/classes 디렉토리에 패키지에 알맞게 위치시킨다.

4 web.xml 파일에 서블릿 클래스를 설정한다.(필요한 경우 진행)

5 톰캣 등의 컨테이러를 재실행한다.(서블릿 리로딩 기능이 있는 경우 생략)

6 웹 브라우저에서 확인한다.


MVC 패턴을 지원하는 서블릿 코드를 직접 구현하지 않더라도 서블릿 자체에 대해서 이해하는 것은 웹 개발을 하는데 있어서 중요한 부분이다.

HttpServlet 클래스는 서블릿 규약에 포함된 클래스로서, 이 클래스를 사용하려면 클래스패스에 /[톰캣]/lib/servlet-api.jar 파일을 포함시켜 주어야 한다.

서블릿 클래스를 구현하려면 먼저 HttpServlet 클래스를 상속받은 클래스를 작성해야 한다. 

HttpServlet 클래스를 상속 받았다면, 처리하고자 하는 HTTP 방식(method)에 따라 알맞은 메서드를 오버라이딩해서 구현해 주어야 한다.

예를 들어, doGet() 메서드를 오버라이딩 해주면 된다. doGet() 메서드는 HttpServletRequest와 HttpServletResponse의 두 파라미터를 갖는데,

이 두 파라미터는 각각 JSP의 request 기본 객체, response 기본 객체와 동일하다.

오버라이딩 한 메서드에서는 request를 이용해서 웹 브라우저의 요청 정보를 읽어오던가 response를 이용해서 응답을 전송할 수 있다.


2. 서블릿의 라이프사이클

① public void init( ) 또는 public void init(ServletConfig sc) {...} 메서드에 의한 초기화

web.xml 파일이 실행되면서나 최초 접속하는 클라이언트에 의해 실행된다.(한번 실행되면 서버가 종료될 때 까지 두번 다시 실행하지 않음)

② public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {...}

클라이언트의 요청에 의해 실행되는 메서드로 콘솔 프로그램의 main( ) 메서드와 같은 역할을 한다.

③ public void destroy( ) {...} 메서드에 의한 메모리 해제

웹 서버가 종료될 때 실행되어 메모리를 해제한다.(서버 종료시 실행)


3. 서블릿 설정

-web.xml 등록

서블릿 클래스를 생성했다면, 그 다음으로 할 작업은 WEB-INF 디렉터리의 web.xml 파일에 서블릿 클래스를 등록하는 것이다.

NowServlet 클래스를 web.xml 파일에 등록한 예를 보여주고 있다.

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

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns="http://java.sun.com/xml/ns/javaee"

xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 

http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"

id="chap20" version="3.0">


<servlet>// 서블릿 클래스를 서블릿으로 등록한다.

<servlet-name>now</servlet-name>// 해당 서블릿을 참조할 때 사용할 이름을 입력한다.

<servlet-class>mvjsp.chap20.NowServlet</servlet-class>// 서블릿으로 사용할 서블릿 클래스의 완전한 이름을 입력한다.

</servlet>

// 위의 경우 mvcjsp.chap20.NowSerlvet 클래스를 "now"라는 이름의 서블릿으로 등록하고 있다.

<servlet-mapping> 

<servlet-name>now</servlet-name>// 매핑할 서블릿의 이름을 지정한다.

<url-pattern>/now</url-pattern>// 매핑할 URL 패턴을 지정한다.

</servlet-mapping>

</web-app>

사용할 서블릿을 지정했다면 그 다음으로 할 작업은 해당 서블릿이 어떤 URL을 처리할 지에 대한 매핑 정보를 등록하는 것이다. 이는 <servlet-mapping> 태그를 이용해서 지정한다. 여기서는 now라는 이름의 서블릿이 /now라는 URL 패턴을 처리한다고 지정하고 있다. 앞서 NowServlet 클래스를 now 라는 이름의 서블릿으로 등록했으므로 결과적으로 /now 라는 URL을 NowServlet이 처리하게 된다.

서블릿을 등록하려면 다음의 두 가지 설정을 해주어야 한다.

1 서블릿으로 사용할 클래스

2 서블릿과 URL 간의 매핑


- 서블릿 파일

package mvjsp.chap20;

import java.io.IOException;

import java.io.PrintWriter;

import java.util.Date;


import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


public class NowServlet extends HttpServlet {

// NowServlet 클래스는 HttpServlet 클래스를 상속 받고 있으며, 따라서 NowServlet은 서블릿으로 동작할 수 있게 된다.


@Override

protected void doGet(HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException {

response.setContentType("text/html; charset=euc-kr");


PrintWriter out = response.getWriter();

out.println("<html>");

out.println("<head><title>현재시간</title></head>");

out.println("<body>");

out.println("현재 시간은");

out.println(new Date());

out.println("입니다.");

out.println("</body></html>");

}

}


4. 애노테이션으로 매핑하기

서블릿 2.5까지는 web.xml 파일에 서블릿으로 등록해주어야 서블릿 클래스를 사용할 수 있었는데, 서블릿 3.0 버전부터는 web.xml 파일에 따로 등록하지 않아도 @WebServlet 애노테이션을 사용하면 서블릿으로 자동으로 등록된다. 톰캣7 버전과 같이 서블릿 3.0을 지원하는 웹 컨테이너는 @WebServlet이 적용된 서블릿 클래스를 검색해서 사용할 서블릿으로 자동으로 등록해주는 기능을 제공하고 있다.

따라서, web.xml 파일에 따로 등록하지 않더라고 해당 클래스를 서블릿으로 사용할 수 있게 된다.


package mvjsp.chap20;

import java.io.IOException;

import java.io.PrintWriter;

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


@WebServlet(urlPatterns = "/hello")

// @WebServlet 애노테이션은 urlPattern 속성을 값으로 갖는데 이 속성은  해당 서블릿과 매핑될 URL 패턴을 지정할 째 사용된다.

위 코드의 경우 /hello로 들어오는 URL을 HelloServlet이 처리하도록 설정하고 있다.

이제 web.xml 파일에 별도의 설정을 하지 않더라도 HelloServlet을 실행할 수 있게 된다.

public class HelloServlet extends HttpServlet {


@Override

protected void doGet(HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException {

request.setCharacterEncoding("euc-kr");

response.setContentType("text/html; charset=euc-kr");

PrintWriter out = response.getWriter();

out.println("<html>");

out.println("<head><title>인사</title></head>");

out.println("<body>");

out.println("안녕하세요, ");

out.println(request.getParameter("name"));

out.println("님");

out.println("</body></html>");

}

}

@WebServlet 애노테이션을 사용할 때 고려할 점은 서블릿이 범용적으로 사용되는 서블릿인지의 여부이다.

예를 들어, MVC 프레임워크는 어떤 URL을 서블릿이 처리할지 미리 할 수 없다. 단지, 다양한 요청 URL을 MVC 프레임워크가 처리할 수 있는 기능을 구현할 수 있을 뿐이다.

이 얘기는 @WebServlet 애노테이션을 사용할 경우 서블릿이 처리해야 할 URL 패턴이 변경될 때 마다, 자바 소스 코드의 urlPatterns 속성의 값을 변경하고 다시 컴파일해야 한다는 것이다. 반면 @WebServlet을 사용하지 않고 web.xml 파일을 사용할 경우 URL 경로가 바뀔 경우 web.xml 파일만 변경해주면 된다. 따라서, 서블릿의 용도에 따라서 @WebServlet 애노테이션을 사용할지 아니면 web.xml 설정을 사용할지를 알맞게 결정해야 한다.




'Programing > JSP/Servlet' 카테고리의 다른 글

[Servlet] 서블릿 이벤트  (0) 2014.12.18
[Servlet] 서블릿 필터  (0) 2014.12.10
[Servlet] 데이터 저장 영역  (0) 2014.12.10
[Servlet] 초기화 파라미터  (0) 2014.12.09
[Servlet] web.xml 주요 태그  (0) 2014.12.09