[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

[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

[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

[Servlet] 데이터 저장 영역

데이터 저장 영역


서블릿에서는 데이터를 저장하는 영역으로 페이지 객체, 요청 객체, 세션 객체, ServletContext 객체 네 가지를 사용할 수 있다.

1) 페이지 객체는 현재 페이지 내에서만 사용할 변수를 저장하는 영역.

2) 요청 객체는 요청 객체가 유지되는 영역에서 사용할 변수를 저장하는 영역.

3) 세션 객체는 웹 브라우저가 종료되기 전가지나 세션이 끊어지기 전까지 사용할 변수를 저장하는 영역.

클라이언트마다 독립적으로 데이터를 저장하고 관리할 수 있는 최고 범위의 데이터 저장 영역이다. 여기에 저장되는 데이터는 클라이언트가 웹 브라우저를 종료하기 전까지나 세션이 끊어지기 전까지는 사라지지 않는다.

4) ServletContext 객체는 서버가 종료되기 전까지 사용할 변수를 저장하는 영역.


이들 각 영역에 저장된 데이터를 사용해서 여러 페이지에 걸쳐 필요한 범위까지 변수를 선언할 수 있다.


1. 요청 객체

(1) 객체: ServletRequest 또는 HttpServletRequest 객체

(2) 추가: request.setAtrtribute("키","값");

(3) 삭제: request.removeAttribute("키","값");

(4) 획득: Object obj = request.getAttribute("키");


2. 세션객체

(1) 객체: HttpSession 객체

(2) 생성: session = request.getSession() 또는 request.getSession(boolean); 

cf.) getSession(true): 기존에 세션 객체가 없으면 새오룬 HttpSession 객체를 생성하라는 의미이다.

(3) 추가: session.setAtrtribute("키","값");

(4) 삭제: session.removeAttribute("키","값");

(5) 획득: Object obj = session.getAttribute("키");

세션 객체를 사용하려면 각 페이지마다 객체를 사용해야 한다. 세션 객체에 저장된 데이터는 클라이언트별로 데이터를 저장하고 관리한다.

때문에 요청 객체로부터 세션 객체를 생성한다. 데이터늬 추가나 삭제, 획득은 요청 객체에서와 방법이 같다.


3. Servletcontext 객체

(1) 객체: ServletContext 객체

(2) 생성: application = this.getServletContext();

(3) 추가: application.setAttribute("키","값");

(4) 삭제:application.removeAttribute("키","값");

(5) 획득: Object obj = application.getAttribute("키");

특이한 점이자 중요한 점은 현재의 서블릿에서 Servletcontext 객체를 획득한다는 것이다. 이것은 서버 자체의 저장 영역을 사용한다는 의미이다.

서블릿은 서버에서 실행이 되기 때문에 this는 서블릿 자체를 이야기하고, 서블릿과 연결되어 있는 서버는 모든 클라이언트에 공통적인 사항이다. 정리하면 서버의 데이터 저장 영역인 ServletContext 객체를 획득하면 

여기에 저장된 데이터는 클라이언트가 모두 공유할 수 있다는 의미이다.




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

[Servlet] 서블릿 필터  (0) 2014.12.10
[Servlet] 서블릿 기초  (0) 2014.12.10
[Servlet] 초기화 파라미터  (0) 2014.12.09
[Servlet] web.xml 주요 태그  (0) 2014.12.09
[Servlet] 웹 프로그램 기본파일(tomcat환경)  (0) 2014.12.09

[Servlet] 초기화 파라미터


초기화 파라미터


초기화 매개변수는 웹 페이지가 실행될 때 필요한 데이터를 전달해 준다. 그리고 초기화 매개 변수는 서블릿 프로그램이 처음 실행될 때 클라이언트가 아닌 서버로부터 넘겨받는 값이다.

웹 프로그램은 모든 실행 시작점이 웹 서버의 구동이다. 이때 web.xml 파일이 자동으로 로드된다.

여기에 초기화 매개변수를 등록해서 웹 페이지가 매개변수의 값을 읽어들인다.

이렇게 해서 서블릿을 재컴파일하지 않고서도 원하는 초기값을 웹 페이지에 전달할 수 있다.


import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;


public class Round14_01_Servlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {

ServletConfig config = this.getServletConfig();

//ServletConfig 객체를 획득한다.

//실제로는 HttpServlet이 ServletConfig를 구현했기 때문에

//이렇게 객체를 획득할 필요 없이 this를 사용해도 무방하다.

String start = config.getInitParameter("start");

String end = this.getInitParameter("end");

//config 객체를 통해서도 this를 통해서도 초기화 매개변수를 획득할 수 있다.

int start_su = Integer.parseInt(start);

int end_su = Integer.parseInt(end);

//초기화 매개변수로 전달된 값은 문자열이므로 숫자로 변환한다.

int hap = 0;

for(int i = start_su; i <= end_su; ++i) 

hap += i;

//시작 수에서 끝 수까지의 총합을 구한다.

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

//응답에 대한 MIME과 Encode를 설정한다.

PrintWriter out = response.getWriter();

//출력 객체를 생성한다.

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

out.println(start_su + " ~ " + end_su + "사이의 합은 ");

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

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

//결과를 출력한다.

out.close();

//출력 객체를 종료한다.

}

}


web.xml 파일에 서블릿을 등록하면서 다음과 같이 초기화 매개변수로 start와 end의 값을 등록한다. 등록되는 모든 데이터는 자료형이 String이다.

<servlet>

<servlet-name>My01</servlet-name>

<servlet-class>Round14_01_Servlet</servlet-class>

<init-param>

<param-name>start</param-name> // String start = config.getInitParameter("start");에서 start의 초기값은 '1'이다.

<param-value>1</param-value>

</init-param>

<init-param>

<param-name>end</param-name> // String end = this.getInitParameter("end");에서 end의 초기값은 '10'이다.

<param-value>10</param-value>

</init-param>

</servlet>

<servlet>

<servlet-name>My01</servlet-name>

<servlet-class>Round14_01_Servlet</servlet-class>

</servlet>


1. Servlet 초기화 파라미터의 종류


(1) 초기화 파라미터

처음 WAS가 기동될 때 읽어 들이는 파라미터값을 초기화 파라미터라고 합니다.

종류에는 1) 서블릿 초기화 파리미터 와 2) 컨텍스트 초기화 파라미터가 있습니다.


(2) 서블릿 초기화 파라미터(Servlet Initialize Parameter)

1) web.xml에 다음과 같이 기술하고

<servlet>

     <init-param><!-- 초기화 파라미터라고 불리는 설정 값을 지정할 때 사용한다.-->

          <param-name>AdminEmail</param-name><!-- 초기화 파라미터의 이름을 지정한다.-->

          <param-value>admin@admin.com</param-value><!-- 초기화 파라미터의 값을 지정한다.-->

     </init-param>

</servlet>


2) Servlet Code에서 

getServletConfig().getInitParameter("AdminEmail"));  와 같은 코드로 초기화 파라미터 값을 얻을 수 있습니다.

서블릿 초기화 파라미터는 컨텍스트 초기화 파라미터와 달리 서블릿에서만 읽어 들일 수 있습니다.

이 값들을 JSP에서 사용하기 위해서는 HttpServletRequest의 Attribute 속성을 이용해서 JSP로 모델 정보를 넘겨야 합니다.

example)

< TODO Servlet>

String AdminEmail = (String)getServletConfig.getInitParameter("AdminEmail");

request.setAttribute("AdminEmail",AdminEmail);

<TODO JSP>

String AdminEmail = (String)request.getAttribute("AdminEmail");


(3) 컨텍스트 초기화 파라미터(Context Initialize Parameter)

1) web.xml에 다음과 같이 기술하고

<context-param>

     <param-name>adminEmail</param-name>

     <param-value>admin@admin.com</param-value>

</context-param>

주의 : <context-param>은 <web-app> 하위에 존재하지 <servlet> 하위에 존재하지 않습니다.


2) Servlet혹은 JSP에서

getServletContext().getInitParameter("adminEmail");    

와 같은 코드로 코딩하면 값을 얻을 수 있습니다.


(4) 정리

정리하면. 서블릿 초기화 파라미터는 ServetConfig 에서 읽어들이며, ServletConfig는 서블릿 당 하나가 생성됩니다.

컨텍스트 초기화 파라미터는 ServetContext에서 읽어들이고, 웹 어플리케이션 당 하나가 생성됩니다.


즉 웹 어플리케이션 전체의 전역적인 파라미터 설정을 원한다면 컨텍스트 초기화 파라미터에 정의 하시면 되고,특정 서블릿에서 처리 하기 위한 어떤 값을, 즉 서블릿범위 정도에서 처리하기 위한 값을 정의 한다면 서블릿 초기화 파라미터를 사용하면 되겠습니다.


(5) 잘 정리된 표




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

[Servlet] 서블릿 필터  (0) 2014.12.10
[Servlet] 서블릿 기초  (0) 2014.12.10
[Servlet] 데이터 저장 영역  (0) 2014.12.10
[Servlet] web.xml 주요 태그  (0) 2014.12.09
[Servlet] 웹 프로그램 기본파일(tomcat환경)  (0) 2014.12.09

[Servlet] web.xml 주요 태그


web.xml 주요 태그


web.xml파일은 웹 컨테이너와 웹 프로그램의 파일을 서로 연결하고 관리하는 설정 파일이다.

웹 프로그램은 항상 자바를 지원하는 웹 컨테이너에서 실행된다. 때문에 해당 웹 컨테이와의 연게를 반드시 염두에 두어야 한다. 프로젝트별로 환경을 설정하고 파일들 간에 관계를 설정할 때는 web.xml 파일이 기준이 된다. 

web.xml 파일은 웹 서버가 서블릿 파일을 인식하게 해준다.

이 파일은 서블릿의 등록뿐 아니라 필터 클래스의 등록과 맵핑 등 다양한 설정을 지원한다.

주목할 점은 web.xml이 웹 서버를 구동할 때 읽혀진다는 것이다. 만일 특정 작업에 필요해서 web.xml 파일을 수정하고 웹 서버를 재구동하지 않으면 당연히 web.xml 파일은 인식되지 않는다.


<web-app>

<display-name> 프로젝트명 </display-name>


<filter>  <filter> 전체

<filter-name> 필터 닉 네임 </filter-name>  <filter-name>

<filter-class> 필터 클래스 풀 네임(패키지 명까지) </filter-name>  ⓓ 

<init-param> ⓔ <init-param> 전체

<param-name> 매개변수 명 </param-name>

<param-value> 값 </param-value>

</init-param>

</filter> 

<filter-mapping>  ⓕ <filter-mapping> 전체

<filter-name> 필터 닉 네임 </filter-name> 

<url-pattern> 필터 클래스가 실행될 위치 </url-pattern>

</filter-mapping>


<serlvet> ⓙ <serlvet> 전체

<servlet-name> 서블릿 닉 네임 </servlet-name>

<serlvet-class> 서블릿 클래스 풀네임(패키지 명까지) </servlet-class> ⓜ </servlet-class> 전체

<init-param>

<param-name> 매개변수명 </param-name>

<param-value> 값 </param-value>

</init-param>

<load-on-startup> 실행 순서 값(0값은 서버임의실행) </load-on-startup>

</servlet>

<servlet-mapping>  <servlet-mapping> 전체

<servlet-name> 서블릿 닉 네임 </servlet-name>

<url-pattern> url 패턴 </url-pattern>  

</servlet-mapping>


<welcome-file-list> <welcome-file-list> 전체

<welcome-file> 기본 파일 </welcome-file>

</welcom-file-list>

</wep-app>


ⓐ web.xml 파일이 속한 프로젝트의 이름을 적는다.


ⓑ 프로젝트에서 사용될 필터 클래스를 등록한다.


ⓒ 필터 클래스의 닉네임을 적는다. 임의로 정해도 된다.


ⓓ 해당 클래스에 대해 패키지의 이름까지 전체를 등록한다. 패키지가 아니면 클래스 이름만 등록한다.


ⓔ 해당 필터 클래스가 실행되면서 기본적으로 갖는 초기화 매개 변수를 적는다. 여러 개를 등록해도 된다. void main(String [] ar) 메서드의 ar[0], ar[1] 등과 같은 개념이라고 보면된다.

void main() 메서드에서는 ar이라는 이름으로 사용하지만 여기서는 변수의 이름과 값을 모두 등록해야 한다.


ⓕ 해당 필터 클래스가 실행되는 시점을 등록한다.


ⓗ 실행될 필터 클래스의 닉네임을 적는다. ⓒ에서 적은 이름과 대소문자까지 같아야 한다.


ⓘ 실행될 시점을 지정한다.


ⓙ 서블릿을 웹 컨테이너에 등록하고 있다. 여러 개를 등록해도 된다.


ⓚ 서블릿의 닉네임을 등록한다. 닉네임은 클래스의 이름이 너무 길 때 편의상 사용한다. 클래스 이름이 짧으면 클래스 이름과 동일하게 등록해도 무방하다.


ⓜ 필터 클래스처럼 서블릿이 실행될 때 초기값으로 전달될 매개변수를 적고 있다. 여러 개를 등록해도 무방하다.


ⓝ 웹 서버가 구동될 때 서블릿의 init() 메서드를 미리 실행할지 지정하고 있다. 각 서블릿의 생성/초기화 순서를 의미한다.

(값이 작은 것이 먼저 실행)


ex.) B 서블릿 -> A 서블릿 -> C 서블릿 순: B:1, A:2, C:3으로 지정한다.


ⓞ 앞서 등록한 서블릿을 웹 브라우저에서 호출하면서 사용하는 이름을 등록하는 코드이다. 


ⓟ 실행 시점을 지정한다. ex.) <url-pattern> /*.do </url-pattern> 로 지정하면, URL do로 끝나면 해당 서블릿이 실행된다.


ⓠ 클라이언트의 사용자가 웹 브라우저로 웹 서버에 접속할 때 기본적으로 보여주는 메인 페이지를 등록하고 있다.





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

[Servlet] 서블릿 필터  (0) 2014.12.10
[Servlet] 서블릿 기초  (0) 2014.12.10
[Servlet] 데이터 저장 영역  (0) 2014.12.10
[Servlet] 초기화 파라미터  (0) 2014.12.09
[Servlet] 웹 프로그램 기본파일(tomcat환경)  (0) 2014.12.09

[Servlet] 웹 프로그램 기본파일(tomcat환경)


웹 프로그램 기본파일(tomcat환경)


또 찾아서 있으면 추가하겠음



WEB-INF/web.xml:  프로젝트의 속성을 설정하는 파일


META-INF/context.xml: 서버 환경을 설정하는 파일


%JAVA_HOME%/jre/lib/ext: 로컬 응용 프로그램을 실행하기 위한 폴더


tomcat7/common/lib: 톰캣을 이용하는 웹 프로그램을 실행하기 위한 폴더, 모든 프로젝트에 공통으로 적용되는 라이브러리 파일을 인식한다.

cf.) %JAVA_HOME%/jre/lib 폴더나 %JAVA_HOME%/jre/lib/ext  폴더 내의 JAR 파일들도 자동으로 인식된다.


C:\\Web_Java\eclipse\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\webapps: 이클립스에서 웹 프로그램이 실행될 때 파일 구조가 변경


tomcat7/conf/server.xml: 웹 서버를 구동하면서 사용할 포트를 설정하기 위해 인식한다.


tomcat7/conf/web.xml: 모든 프로젝트에 공통으로 적용되는 환경을 설정하기 위해 인식한다.


[프로젝트 이름]/WEB-INF/web.xml: 프로젝트별로 적용되는 환경을 설정하기 위해 인식한다.


[프로젝트 이름]/WEB-INF/lib: 프로젝트별로 적용되는 라이브러리 파일을 인식한다.


[프로젝트 이름]/WEB-INF/classes: 프로젝트별로 적용되는 서블릿 파일을 인식하고 설정에 따라 init() 메서드를 실행한다. <load-on-start> 태그로 정의한다.



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

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

[Java] 인터페이스의 이해


인터페이스의 이해


1. 인터페이스의 이해 서두

먼저 인터페이스를 이해하기 위해서는 다음의 두 가지 사항을 반드시 염두에 두고 있어야 한다.

1) 클래스를 사용하는 쪽(User)과 클래스를 제공하는 쪽(Provider)이 있다.

2) 메서드를 사용(호출)하는 쪽(User)에서는 사용하려는 메서드(Provider)의 선언부만 알면 된다. (내용은 몰라도 된다.)


class A{

public void method( B b){

b.method();

}

}


class B {

public void methodB(){

System.out.println("methodB()");

}

}


class InterfaceTest{

public static void main(String args[]){

A a = new A();

a.methodA(new B());

}

}

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

실행결과

methodB()


클래스 A(User)는 클래스 B(Provider)의 인스턴스를 생성하고 메서드를 호출한다. 이 두 클래스는 서로 직접적인 관계에 있다. 이것을 간단히 'A(User)-->B(Provider)'라고 표현하다.

이 경우 클래스 A를 작성하기 위해서는 클래스 B가 이미 작성되어 있어야 한다. 그리고 클래스의 B의 methodB()의 선언부가 변경되면, 이를 사용하는 클래스 A도 변경되어야 한다.

이와 같이 직접적인 관계의 두 클래스는 한쪽(Provider)이 변경되면 다른 한 쪽(User)도 변경되어야 한다는 단점이 있다.

그러나 클래스 A가 클래스 B를 직접 호출하지 않고 인터페이스를 매개체로 해서 클래스 A가 인터페이스를 통해서 클래스 B의 메서드에 접근하도록 하면, 클래스 B에 변경사항이 생기거나 클래스 B와 같은 기능의 다른 클래스로 대체 되어도 클래스 A는 전혀 영향을 받지 않도록 하는 것이 가능하다.


2. 두 클래스간의 관계를 간접적으로 변경하기

두 클래스간의 관계를 간접적으로 변경하기 위해서는 먼저 인터페이스를 이용해서 클래스B(Provider)의 선언과 구현을 분리해야 한다.


먼저 다음과 같이 클래스 B에 정의된 메서드를 추상메서드로 정의하는 인터페이스 I를 정의한다.

interface I {

public abstract void methodB();

}


그 다음에는 클래스 B가 인터페이스 I를 구현하도록 한다.

class B implements I {

public void methodB(){

System.out.println("methodB in class");

}

}


이제 클래스 A는 클래스 B 대신 인터페이스 I를 사용해서 작성할 수 있다.

class A {

public void methodA(I i){

i.methodB();

}

}

cf.) methodA가 호출될 때 인터페이스 I를 구현한 클래스의 인스턴스(클래스 B의 인스턴스)를 제공받아야 한다.


--> 클래스 A를 작성하는데 있어서 클래스 B가 사용되지 않았다는 점에 주목하자. 이제 클래스 A와 클래스 B는 'A-B'의 직접적인 관계에서 'A-I-B'의 간접적인 관계로 바뀐 것이다.

결국 클래스 A는 여전히 클래스 B의 메서드를 호출하지만, 클래스 A는 인터페이스 I하고만 직접적인 관계에 있기 때문에 클래스 B의 변경에 영향을 받지 않는다.

클래스 A는 인터페이스를 통해 실제로 사용하는 클래스의 이름을 몰라도 되고 심지어는 실제로 구현된 클래스가 존재하지 않아도 문제되지 않는다. 클래스 A는 오직 직접적인 관계에 있는 인터페이스의 I의 영향만 받는다.

인터페이스 I는 실제 구현 내용(클래스 B)을 감싸고 있는 껍데기이며, 클래스 A는 껍데기안에 어떤 알맹이(클래스)가 들어 있는지 몰라도 된다.


 class A {

    void autoPlay(I i) {

          i.play();

     }

 }


 interface I {

      public abstract void play();

 }


 class B implements I {

     public void play() {

          System.out.println("play in B class");

     }

 }


 class C implements I {

     public void play() {

          System.out.println("play in C class");

     }

 }


class InterfaceTest2 {

public static void main(String[] args) {

A a = new A();

a.autoPlay(new B());

a.autoPlay(new C());

}

}

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

실행결과

play in B class

play in C class


클래스 A가 인터페이스 I를 사용해서 작성되긴 하였지만, 이처럼 매개변수를 통해서 인터페이스 I를 구현한 클래스의 인스턴스를 동적으로 제공받아야 한다.



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

[Java] 변수의 종류  (0) 2014.12.14
[Java] abstract  (0) 2014.12.11
[Java] 형변환  (0) 2014.12.02
[Java] 실행  (0) 2014.12.02
[Java] Java SE, JDK, JRE  (0) 2014.12.02

[Java] 형변환


형변환


형 변환(Type Conversion)이란 데이터의 타입을 변경하는 것이다. 예를 들어 int 타입의 정수 200의 bit 값은 아래와 같다.

00000000 00000000 00000000 11001000

프로그래밍을 처음 시작하는 사람도 컴퓨터는 모든 정보가 0과 1로 만들어진다는 이야기를 들어봤을 것이다. 여러분이 200이라는 숫자를 입력하면 컴퓨터에는 위와 같이 0과 1로 이루어진 조합으로 저장된다. 바로 이 0과 1을 bit라고 부른다. 위의 데이터는 8X4개의 자릿수로 이루어져 있다. 이것을 32bit라고 부른다. 위의 데이터는 int 형으로 숫자 200을 저장했을 때 메모리상에 만들어지는 내용이다. 그럼 실수형인 float 타입으로 정수 200.0을 저장하면 어떻게 될까? 사람에게는 똑같은 수인 정수 200과 실수 200.0을 컴퓨터는 전혀 다른 방식으로 저장한다. float 타입의 정수 200.0의 bit 값은 아래와 같다.


01000011 01001000 00000000 00000000

정수 200과 실수 200.0의 bit 값이 완전히 다른 것을 알 수 있다. 이렇게 형식이 다른 데이터들을 더하려면 한쪽의 데이터 타입을 다른 쪽의 데이터 타입으로 전환(Conversion)해야 한다. 자바는 이러한 형 변환을 자동으로 처리해주는데 이러한 전환작업을 자동(암시적) 형 변환(implicit Conversion)이라고 부른다.


1. 자동 형 변환

아래 예제를 보자. 

double a = 3.0F;

위의 코드는 double 타입의 변수 a에 float 타입의 값을 대입하고 있다. 이 때 3.0F의 값은 자동으로 double 타입으로 형 변환이 일어난다. 이것이 가능한 이유는 double 타입이 float 타입보다 더 많은 수를 표현 할 수 있기 때문이다. 타입을 변경해도 정보의 손실이 일어나지 않는 경우 자동 형 변환이 일어난다.


반대로 아래의 예제는 오류가 발생한다. 상수 3.0은 상수인데, 이 상수는 double 형이다. 이 값을 표현 범위가 좁은 float에 넣으려고 하기 때문에 오류가 발생한다. 

float a = 3.0;

자동 형 변환의 원칙은 표현범위가 좁은 데이터 타입에서 넓은 데이터 타입으로의 변환만 허용된다는 것이다.

아래는 자동 형 변환이 일어나는 규칙을 보여준다.


byte 타입은 short가 될 수 있지만 short는 byte 타입이 될 수 없다. long은 float가 될 수 있지만, float는 long이 될 수 없다.

상수와 상수를 연산한다면 어떻게 될까? 다음 예제를 보자. 

int a = 3;

float b = 1.0F;

double c = a + b;

위의 연산은 두 번의 형 변환이 일어난다. 우선 a와 b를 더하기 위해서 정수 a와 실수 b 중 하나가 형 변환을 해야 한다. 위의 그림에 따르면 int와 float가 붙으면 int가 float가 되기 때문에 변수 a에 담겨있는 값 3은 float 타입이 된다. 연산 결과는 float 타입이다. 하지만 이 값이 담겨질 변수 C의 타입은 double이다. float가 double 타입의 변수에 담기기 위해서는 float가 double로 형 변환을 해야 한다. 이렇게 해서 최종적으로 형 변환된 값이 변수 c에 담겼다.


2. 명시적 형 변환

자동 형 변환이 적용되지 경우에는 수동으로 형 변환을 해야 한다. 이를 명시적(Explicit Conversion)이라고 한다. 아래 예제는 모든 행의 코드에서 오류가 발생한다. 자동 형 변환이 이루어지지 않기 때문이다. (실행)

float a = 100.0;

int b = 100.0F;


위의 예제를 조금 수정해보자. 아래 코드는 오류가 발생하지 않는다. 

float a = (float)100.0;

int b = (int)100.0F;

아래와 같이 괄호 안에 데이터 타입을 지정해서 값 앞에 위치시키는 것을 명시적인 형 변환이라고 부른다.


형 변환은 한 번에 설명할 수 있는 주제는 아니다. 여러분이 객체지향까지 진입하면 다양한 방법으로 형 변환이라는 주제가 다시 언급될 것이다. 일단은 이정도로 언급하고 후속 수업을 통해서 형 변환에 대해서 좀 더 심화된 내용을 알아가자.




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

[Java] 변수의 종류  (0) 2014.12.14
[Java] abstract  (0) 2014.12.11
[Java] 인터페이스의 이해  (0) 2014.12.06
[Java] 실행  (0) 2014.12.02
[Java] Java SE, JDK, JRE  (0) 2014.12.02