반응형

참고

http://java.sun.com/products/javamail/index.jsp
http://java.sun.com/javase/technologies/desktop/javabeans/glasgow/jaf.html
http://java.sun.com/developer/onlineTraining/JavaMail/contents.html

http://java.sun.com/products/javamail/javadocs/index.html
관련 시리즈
http://javacan.madvirus.net/main/search/search.tle?type=all&keyword=mail

주로 작성된 메일을 송신하고 수신하는 API를 제공하는 것이다. 이러한 기능은

메일 서버의 역할과는 구별되는 것이다.


메일 서버는 송신된 메일을 받아들이고 메일 내용을 저장하거나 재전송을 하는  Agent 역할을 한다.


JavaMail Package는 메일 서버에게 메일을 전송하고 메일 서버에 저장된 메일을 수신하는데 유용한 클레스 및 API를 제공한다.


ex) MicroSoft사의 OutLook


 JavaMail API를 구조적으로 살펴보면 우선 메시지 구성, 저장, 수신 구조를 추상화해놓은absctruct layer가 있다. 이러한 추상 계층의 목적은  특정 프로토콜과는 상관없이 메일 구조 체계를 제공하겠다는 목적이다. 즉 인터넷 메일 뿐만 아니라 모바일이나 또 다른 메일 체계에도 적용되는 구조를 제공하는 것이다.


 이러한 추상 계층 이외에 JavaMail API는 가장 흔히 사용하는 인터넷 메일을 위한 클레스 및 API를 제공한다. 이 클레스들은 기본적인 abstruct layer를 인터넷 메일이하는 측면에서 구현 즉 implementation한 클레스들이다. JavaMail API를 가지고 직접적으로 응용프로그램을 작성할 수 있는 방법은 이 인터넷 메일 구현 계층을 사용하는 것이다.


인터넷 메일에 대하여 잘 이해하려면 우선 인터넷 메일 시스템에서 사용되는 통신 프로토콜 표준에 대하여 이해할 필요가 있다. 이러한 프로토콜들은 IETF(Internet Engineering Task Force)에 의하여

소정의 절차를 거친 후 RFC라는 형태로 발표되는데 인터넷 메일과 관련된 주요 표준 프로토콜은

SMTP, POP3, IMAP, MIME 등이 있다. (http://www.ietf.org/)


- SMTP(Simple Mail Transfer Protocol)

RFC 0788에서 정의 되었는데 이후에도 많은 수정이 있다.

SMTP는 기본적으로 인터넷 메일을 서버로 송신하고 서버가 이 메일을 수신하는데 필요한 커멘트 및 표준 절차등을 정의하고 있다.

Java Mail API의 주요 구성 요소

이 글에서는 Java Mail API의 모든 클래스에 대해서 알아보지는 않을 것이며, 가장 중심적인 역할을 하는 클래스인 javax.mail.Session, javax.mail.Store, javax.mail.Transport, javax.mail.Folder, javax.mail.Message 클래스에 대해서 알아볼 것이다. 실제로 이 다섯개의 클래스만 알맞게 사용하면 매우 손쉽게 메일 시스템을 구축할 수 있다.

javax.mail.Session

javax.mail.Session은 Java Mail API를 사용하는 출발점이 되는 클래스로서 다양한 메일 프로토콜을 위한 서비스 프로바이더 구현(Service Provider Implementation; SPI)을 나타내는 클래스를 로딩하고 제어할 수 있는 메소드를 제공하고 있다. 예를 들어, javax.mail.Store 클래스의 인스턴스는 javax.mail.Session 클래스를 통해서 구할 수 있다. (여기서 서비스 프로바이더는 Java Mail API를 이용하여 구현 클래스 계층을 제공하는 개발자는 벤더를 의미한다. 현재 Java Mail API는 IMAP, SMTP, POP3 프로토콜에 대한 구현 계층을 제공하고 있다.)

javax.mail.Store

javax.mail.Store 클래스는 특정한 메일 프로토콜을 이용하여 메일의 읽기, 쓰기, 감시, 검색 등을 할 수 있도록 해 준다. Session 클래스를 사용하여 구할 수 있으며, 메일 저장소를 추상화한 javax.mail.Folder에 접근할 수 있도록 해 준다. 서비스 프로바이더는 Store 클래스를 알맞게 구현해야 한다.

javax.mail.Folder

javax.mail.Folder 클래스는 메일 메세지에 계층적 구조를 제공하며 메일 메세지에 접근할 수 있도록 해 준다. 메일 메세지는 javax.mail.Message 클래스의 객체로 표현된다. 서비스 프로바디어는 Folder 클래스를 알맞게 구현해야 한다.

javax.mail.Transport

javax.mail.Transport 클래스는 특정한 프로토콜을 사용하여 메세지를 전송할 때 사용된다. 서비스 프로바이더는 이 클래스를 알맞게 구현해야 한다.

javax.mail.Message

javax.mail.Message 클래스는 주제, 수신자의 이메일주소, 발송자의 이메일 주소, 보낸 날짜와 같은 실제 이메일 메세지의 세부 사항을 나타낸다. 서비스 프로바이더는 자신이 사용하는 프로토콜에 알맞게 Message를 구현해야 한다.

Java Mail API와 JAF

Java Mail API는 메시지에 다양한 포맷을 사용할 수 있도록 하기 위해 JAF를 사용한다. JAF는 별도의 확장 API로서 다양한 데이터 형식을 이용하여 작업하는 방법을 통합하기 위해 작성되었다. 실제로 JAF를 이용하면 간단한 텍스트 데이터에서부터 이미지, 비디오 등의 매우 복잡한 멀티 미디어 데이터로 구성된 문서까지 다양한 데이터를 제공할 수 있다.

반응형
Enumeration : 자바 초기버젼에서 개발된 것으로, HashTable과 Vector에서 사용가능
Iterator : jdk 1.2버젼에서 개발된 것으로, Collection 인터페이스를 구현한 모든 클래스에서 사용가능.

API를 확인해볼까요??
Vector와 HashTable에 있는 메소드입니다.
사용자 삽입 이미지
(HashTable에는 Enumeration 타입의 key()메소드도 존재합니다.)

하지만, ArrayList, LinkedList, HashMap에서는 찾아볼 수 없었습니다.
iterator는 HashTable이든 HashMap이든, Vector든 LinkedList든,
모두 쓸 수 있다는 것이죠.

Iterator에 대해서는 저번에 알아봤으니까.
이번에는 Enumeration의 API를 간단하게 뒤져봐야겠네요.

hasMoreElements

boolean hasMoreElements()
Tests if this enumeration contains more elements.
Returns:
true if and only if this enumeration object contains at least one more element to provide; false otherwise
Iterator의 hasNext()와 똑같은 일을 하는군요!!

nextElement

E nextElement()
Returns the next element of this enumeration if this enumeration object has at least one more element to provide.
Returns:
the next element of this enumeration.
Throws:
NoSuchElementException - if no more elements exist.
다음 elements가 존재하지 않으면, Exception이 발생하네요 ㅋㅋ
이것 또한 Iterator의 next()와 같아 보이는군요..ㅋㅋ

Vector의 요소들을 출력하는 예제입니다.
for (Enumeration e = v.elements() ; e.hasMoreElements() ;) {
System.out.println(e.nextElement());

}
자 그럼, 본격적으로 차이점에 대해서 알아보도록 합시다.

Snap Shot
Enumeration과 Iterator의 가장 큰 차이점은 바로 Snap Shot입니다.
Enumeration은 Snap Shot을 지원합니다. 여기서 'fail-fast
'라는 개념이 나오는데요.
Iterator는 fail-fast 방식이라고 합니다.
그럼 과연 이것이 무엇일까요?? 좋은 아티클이 있어서 긁어왔습니다...-ㅅ-;;

Fail-Fast

자바 2 이전 버전에서 사용되던 Vector, Hashtable의 뷰 객체인 Enumeration은 fail-fast 방식이 아니었으나, 자바 2의 콜렉션 프레임워크에서 콜렉션 뷰인 Iterator, ListIterator 객체는 fail-fast 방식이라는 점이다.

콜렉션 뷰는 콜렉션 객체에 저장된 객체들에 대한 순차적 접근을 제공한다. 그러나, 뷰 객체인 Enumeration 또는 Iterator 객체를 얻고 나서 순차적 접근이 끝나기 전에 뷰 객체를 얻은 하부 콜렉션 객체에 변경이 일어날 경우, 순차적 접근에 실패하게 된다. 여기서 변경이라는 것은 콜렉션에 객체가 추가되거나 제거되는 것과 같이 콜렉션 구조의 변경이 일어나는 경우를 말한다.

이런 상황은 멀티쓰레드 구조와 이벤트 구동 모델에서 일어날 수 있으며, 개발자가 혼자 테스트할 경우 발견하기 어려운 문제이다. 따라서 정확한 이해와 예상이 필요하며, 이에 대한 대처 방안을 마련해야 한다.

하부 콜렉션 객체에 변경이 일어나 순차적 접근에 실패하면 Enumeration 객체는 실패를 무시하고 순차적 접근을 끝까지 제공한다. Iterator 객체는 하부 콜렉션 객체에 변경이 일어나 순차적 접근에 실패하면 ConcurrentModificationException 예외를 발생한다. 이처럼 순차적 접근에 실패하면 예외를 발생하도록 되어 있는 방식을 fail-fast라고 한다.

Iterator는 fail-fast 방식으로 하부 콜렉션에 변경이 발생했을 경우, 신속하고 결함이 없는 상태를 만들기 위해 Iterator의 탐색을 실패한 것으로 하여 예외를 발생하며, 이렇게 함으로써 안전하지 않을지도 모르는 행위를 수행하는 위험을 막는다. 왜냐하면 이러한 위험은 실행 중 불특정한 시간에 멋대로 결정되지 않은 행위를 할 가능성이 있기 때문에 안전하지 않다고 할 수 있기 때문이다.


멋집니다..-ㅅ-; 더이상 설명할 것이 없을 것 같은데요.
흐음.. 일단 정리를 해보면, iterator는 일종의 pointer가 있습니다.
예전에 LinkedList 개념을 그림으로 그려보았는데요.
그거랑 매우 비슷합니다.

사용자 삽입 이미지

포인터가 Array의 자기자신과 다음 객체를 가르키는 것이지요.
그래서 위에 아티클에 써져있는 것처럼 삭제나 수정시 참조무결성 원칙에 어긋나게되어서
에러가 발생하게 되는것입니다.

아티클에 SnapShot에 대한 좋은 내용도 있더군요.

스냅샷

이처럼 콜렉션 뷰 객체인 Iterator와 ListIterator 객체가 fail-fast 방식인 이유는 스냅샷에 대한 보장을 포함하고 있지 않기 때문이다. 즉, 콜렉션의 뷰인 Iterator 객체를 얻었을 때 그 순간의 상태를 따로 생성하지 않기 때문에, Iterator 객체에서 순차적으로 하부 콜렉션 객체를 접근할 때, 콜렉션 객체의 변경에 영향을 받게 된다.

따라서, 콜렉션 뷰인 Iterator를 통하여 순차적 접근을 행하는 도중에 하부 콜렉션 객체에 변경이 일어날 가능성이 있는 경우 스냅샷을 명시적으로 생성하는 것이 좋다. ArrayList를 이용한 스냅샷을 생성하는 간단한 방법은 다음과 같다.

public Iterator snapshotIterator(Collection collection) {
return new ArrayList(collection).iterator();
}

이렇게 스냅샷을 이용하면 스냅샷이 생성된 순간의 상태에 대하여 Iterator를 통한
콜렉션의 뷰를 생성하게 된다. 하부 콜렉션의 변경이 일어나도 스냅샷에는 반영되지
않으며 Iterator는 실패없이 실행된다.

콜렉션 계열 중에 ArrayList를 사용하는 이유는 다른 콜렉션 계열 클래스들보다 생성과순차적 접근이 빠르기 때문이다. ArrayList가 삽입과 삭제에 불리한 단점이 있으나
이 경우에는 삽입과 삭제가 없으므로 고려되지 않는다.


조금 더 쉽게 정리를 해보자면,
Enumeration은 객체를 복사해서 저장합니다. 그래서 삭제나 수정시 전체 콜렉션에는
큰 타격을 주지 않는다는 것이죠.

Synchronization

제가 원래 알고 있던 지식은 "Enumeration은 동기화를 지원한다." 였는데,
어디서 잘 못 주워들었나봅니다. -ㅛ-
아티클에 <<콜렉션 프레임워크의 클래스들은 동기화를 보장하고 있지 않다.>>
라고 써져있더라구요. 그래서 찾아보았습니다. 역시 API에서 Enumeration부분을 봐도,
동기화에 대해서 정의된 부분은 찾을 수 없더라구요.
하지만,  Vector와 ArrayList의 차이점을 공부한 글에서도 알 수 있을 듯이
Vector는 동기화가 아주 넘쳐납니다-ㅅ-; 그러한 사실은 이클립스에서 Vector.class를
가보면, synchronized로 도배가 되어있는 것을 볼 수 있답니다.

아티클에는,
<<멀티쓰레드에서 콜렉션 구현 객체에 동시에 추가, 삭제를 위한 접근이 행해진다면, 그러한 행위가 발생하는 부분에 동기화를 명시적으로 해주어야 한다.>>
라고 써져있더군요. 방법까지 친절하게 명시해주고 있었습니다.
요렇게-ㅅ-;

Collection c = Collections.synchronizedCollection(myCollection);

결론적으로, Enumeration과 Iterator 사이에서 뚜렷하게 차이를 보이는 점은
 "스냅샷을 지원하느냐 하지 않느냐" 라는 것 같습니다.
아티클에서는 "Fail-fast Iterator에 대한 멀티쓰레드 무결성 해결방법" 이라는 제목아래 글을 써내려가고 있는데요. 스냅샷과 동기화가 Iterator의 멀티쓰레드 무결성 해결방법으로 제시되었고, 그와 함께 예시 소스코드도 보여주고 있습니다. 그러니까 Iterator가 스냅샷을 지원하지 않아도, 스냅샷을 명시적으로 생성할 수 있다는 것입니다. 이런건 한번 소스코드를 작성해봐야 확실히 알 수 있겠네요. 일단 이번 포스팅은 여기서 마치고, 소스코딩을 야심차게 시작해보도록 하겠습니다.-ㅛ-; 아자 +ㅅ+ ㅋ
< 출처: http://happystory.tistory.com >
반응형
Vector or ArrayList -- which is better and why?

Sometimes Vector is better; sometimes ArrayList is better; sometimes you don't want to use either. I hope you weren't looking for an easy answer because the answer depends upon what you are doing. There are four factors to consider:

Vector가 더 나을 때도 있고, ArrayList가 더 나을 때도 있다. 또는, 둘 다 사용하길 원하지 않을 수도 있다. 나는 당신이 쉬운 답을 찾으려 하지 않기를 바란다. 왜냐하면 답은 당신이 하는 방식에 따라 달라질 테니까 말이다. 고려해야 할 다음 4가지 요인이 있다.

API
In The Java Programming Language (Addison-Wesley, June 2000) Ken Arnold, James Gosling, and David Holmes describe the Vector as an analog to the ArrayList. So, from an API perspective, the two classes are very similar. However, there are still some major differences between the two classes.

The Java Programming Language 에 Ken Arnold, James Gosling, and David Holmes는 Vector를 ArrayList의 상사형(서로 형이 같은)이라고 묘사한다. 그래서 API를 보면 두 개의 클래스는 매우 유사하다. 하지만 여전히 두 클래스 사이에는 중요한 차이점이 존재한다.

Synchronization
Vectors are synchronized. Any method that touches the Vector's contents is thread safe. ArrayList, on the other hand, is unsynchronized, making them, therefore, not thread safe. With that difference in mind, using synchronization will incur a performance hit. So if you don't need a thread-safe collection, use the ArrayList. Why pay the price of synchronization unnecessarily?

Vector는 동기화 되어있다. Vector의 내용에 접근하는 어떤 메소드는 thread safe1 하다. 반면에ArrayList는 동기화 되어있지 않다. 그러므로 ArrayList로 만들어진 것은 thread safe하지 않다. thread safe가 필요하지 않는데도 동기화를 사용하면, performance hit2 을 초래할 것이다. 만약 당신이 thread-safe 컬렉션을 필요로 하지 않는다면, ArrayList를 사용하라. 왜 불필요하게 synchronization의 비용을 지불하려 하는가?

Data growth
Internally, both the ArrayList and Vector hold onto their contents using an Array. You need to keep this fact in mind while using either in your programs. When you insert an element into an ArrayList or a Vector, the object will need to expand its internal array if it runs out of room. A Vector defaults to doubling the size of its array, while the ArrayList increases its array size by 50 percent. Depending on how you use these classes, you could end up taking a large performance hit while adding new elements. It's always best to set the object's initial capacity to the largest capacity that your program will need. By carefully setting the capacity, you can avoid paying the penalty needed to resize the internal array later. If you don't know how much data you'll have, but you do know the rate at which it grows, Vector does possess a slight advantage since you can set the increment value.

내부적으로 ArrayList와 Vector둘 다 Array를 사용하면서 그들의 컨텐츠를 유지한다. 당신은 당신의 프로그램에서 둘 중에 하나를 사용하는 동안에 이 사실을 명심할 필요가 있다. ArrayList 또는 Vector의 요소를 삽입할 때, 만약 그 용량을 다 써버린다면, object는 자신의 내부array를 확장시킬 필요가 있다. Vector는 자신의 array 크기의 배수만큼 초기화 한다. 반면에 ArrayList는 자신의 array 크기의 50%만큼 씩 증가시킨다. 당신이 이러한 클래스들을 사용하는데 의존한다면, 당신은 새로운 요소들을 추가하는 동안에 결국 대량의 performance hit을 초래할 것이다. 당신의 프로그램이 필요로 하는 최대의 용량만큼 객체의 초기화 용량을 정하는 것이 최선이다. 신중하게 용량을 셋팅해라. 그러면, 당신은 후에 내부 array를 resize하는데 필요한 요금 지불을 피할 있다. 만약 당신이 얼마나 데이터를 가지게 될지는 모른지만, 그것이 증가하는 비율을 안다면 , Vector는 당신이 증가값을 정할 수 있기 때문에 근소한 이점을 가진다.(아래 글 참조)

Usage patterns
Both the ArrayList and Vector are good for retrieving elements from a specific position in the container or for adding and removing elements from the end of the container. All of these operations can be performed in constant time -- O(1). However, adding and removing elements from any other position proves more expensive -- linear to be exact: O(n-i), where n is the number of elements and i is the index of the element added or removed. These operations are more expensive because you have to shift all elements at index i and higher over by one element. So what does this all mean?

ArrayList와 Vector 둘 다 컨테이너의 특정 위치에서 요소들을 되찾거나, 컨테이너의 끝에서 요소들을 더하거나, 삭제할때 유용하다. 이러한 모든 기능은 constant time-- O(1)(맨 아래 글을 참조하세요.)에서 수행될 수 있다. 하지만, 어떤 다른 자리에서 요소들을 더하거나 제거하는 것은 더 많은 비용을 발생시킨다. 정확하게 직선위에서..-ㅅ-?? n은 요소들의 수이고, i는 더해지거나 제거되는 요소의 인덱스다. 당신이 하나의 요소에 때문에 모든 요소들을 index i에 그 이상의 값으로 옮겨야만 하기때문에 이러한 operation들은 더 많은 비용이 든다. 그렇다면 이러한 것은 무엇을 의미하는가?

It means that if you want to index elements or add and remove elements at the end of the array, use either a Vector or an ArrayList. If you want to do anything else to the contents, go find yourself another container class. For example, the LinkedList can add or remove an element at any position in constant time -- O(1). However, indexing an element is a bit slower -- O(i) where i is the index of the element. Traversing an ArrayList is also easier since you can simply use an index instead of having to create an iterator. The LinkedList also creates an internal object for each element inserted. So you have to be aware of the extra garbage being created.

그것은 만약 당신이 요소들을 검색하거나, Array의 끝에서 요소들을 더하거나 제거하기를 원한다면 Vector나 ArrayList 둘 중에 하나를 사용하라는 것을 의미한다. 만약 당신이 그 밖의 무엇인가를 하길 원한다면, 스스로 또다른 콘테이너 클래스를 찾아라. 예를들어, LikedList는 constant time -- O(1) 에서 어디서든지 요소를 더하거나 제거할 수 있다. 하지만, 요소를 찾는 것은 조금 느리다. ArrayList을 왔다갔다 하는 것은 또한 당신이 iterator을 만들어야만 하는 대신에 인덱스를 더욱 간편하게 사용할 수 있기 때문에 더 쉽다. LinkedList는 또한 삽인된 각각의 요소에 대한 내부 객체를 만든다. 그래서 당신은 만들어지는 여분의 garbage에 대해서 알아야만 한다.

Finally, in "PRAXIS 41" from Practical Java (Addison-Wesley, Feb. 2000) Peter Haggar suggests that you use a plain old array in place of either Vector or ArrayList -- especially for performance-critical code. By using an array you can avoid synchronization, extra method calls, and suboptimal resizing. You just pay the cost of extra development time.

마지막으로 Practical Java "PRAXIS 41"에 Peter Haggar은 당신이 Vector 나 ArrayList 둘 중의 하나 대신에 명백한 old array를 사용할 것을 제안한다. -특히 비판적인 코드에서??? array를 사용함으로써, 당신은 동기화, 여분의 메소드를 부르는 것. 그리고 차선의 resizing을 피할 수 있다. 당신은 단지 여분의 개발시간비용만을 지불할 것이다.

어허...ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 해석하는데 무지 오래걸렸습니다..-ㅅ-
하지만 해놓고보니.. 뿌듯하군요.
그러니까, ArrayList와 Vector의 가장 큰 차이점으로 꼽을 수 있는 것은 "동기화"입니다.
하지만, 여러 문서를 찾아보니 ArrayList가 동기화되는 Vector보다 퍼포먼스가 좋다는
이야기가 많더라구요. 즉, 적절한 곳에 ArrayList를 동기화 해서 사용하는게 더 좋다는 의견이
많았습니다. 저는 아직 Vector를 한번 더 사용해 본적도 없고, 개발 경험이 거의 전무해서
잘 와닿지는 않고, 공감할래야 공감할 수도 없지만... 이해했다는 것에 만족해야겠습니다.
-ㅅ-... 화잇힝...ㅋㅋ

Vector - Data Growth 추가사항(API문서)
The Vector class implements a growable array of objects. Like an array, it contains components that can be accessed using an integer index. However, the size of a Vector can grow or shrink as needed to accommodate adding and removing items after the Vector has been created.

Vector 클래스는, 오브젝트의 가변장 배열을 구현합니다. 여기에는 배열과 같이, 정수 인덱스를 사용해 액세스 할 수 있는 요소가 격납되고 있습니다. 그러나, Vector 의 사이즈는 작성 후에 추가 및 삭제된 객체를 격납할 수 있듯이 필요에 따라서 늘리거나 줄이거나 할 수가 있습니다.

Each vector tries to optimize storage management by maintaining a capacity and a capacityIncrement. The capacity is always at least as large as the vector size; it is usually larger because as components are added to the vector, the vector's storage increases in chunks the size of capacityIncrement. An application can increase the capacity of a vector before inserting a large number of components; this reduces the amount of incremental reallocation.

각 Vector 는,capacity (용량)와 capacityIncrement (증가량)를 관리하는 것으로써 기억 관리를 최적화하려고 합니다.capacity 는 항상 Vector 의 요소수에 가까운 값이며, 통상은 요소수부터 커집니다. 이것은 Vector 에 요소가 더해질 때, Vector 의 기억 영역은 capacityIncrement 만 늘려지기 때문입니다. 많은 요소를 삽입하기 전에 애플리케이션으로 용량을 필요한 값으로 설정해 두면, 메모리의 재배분의 회수를 줄일 수가 있습니다.


Constant Time : TimeComplexity 단위의 하나로, 입력 n의 크기의 증감과 상관 없이 주어진 문제를 푸는데에 걸리는 시간(See DiscreteTime)이 동일한 것을 말하며, BigONotation으로는 O(1)이라고 표시합니다. 예를 들어 배열의 i번째 원소를 가져오는 연산은 배열의 크기 n과 무관하게 동일한 속도로 수행됩니다.
TimeComplexity : 시간 복잡도. Automaton으로 어떠한 문제를 풀기 위해 소모되는 이산시간(See DiscreteTime)의 크기를 말합니다.
Automaton : 물리적/논리적인 자동기계-ㅅ-.. 라는데... 그냥 컴퓨터로 이해하겠습니다.
BigONotation : 아.. 이건 진짜 모르겠습니다-ㅅ-;;;;;;;;;;;;;;;;;;;;;;; 살려주세요 ㅠ
출처 : http://jania.pe.kr/wiki/jwiki/moin.cgi
반응형
일단, LikedList에 대하여 살펴봐야겠군요.
1학년때 교재로 썼던 <<Absolute Java>>를 보면,
Liked Data Strutures라는 챕터가 있습니다.
아래는 Introduction에 있는 내용인데요. 야심차게 해석을..-ㅅ-;

A linked data structure consists of capsules of data, known as nodes, that are connected via things called links. These links can be viewed as arrows and thought of as ane-way passages from one node to another. The simplest kind of liked data structure consists of a single chain of nodes, each connected to the next by a link; this is known as a linked list.

linked data structure은 node라고 알려져 있는 data의 캡슐로 구성되어 있다.
이는 link라 불리우는 것을 매개로 하여 연결된다. 이러한 link는 하나의 node에서 다른 node로 가는 한방향의 통로로 간주 될 수 있다. (화살표로 표시된다.)
linked data structure의 가장 간단한 종류는 일련의 단일 node로 구성되어 있다.
각각은 다음 link까지 연결된다. 이러한 것을 linked list라 한다.

워... 큰일났다... 무지하게.. 난해하네요..-ㅅ-;
이걸 이해하려면.. 자료구조를 공부해야겠는데요...-_ㅠ

그러는 와중에.. 저의 구세주 zerry82님께서 등장하셨습니다.!!!
친절한 설명 감사드립니다 ^ ^
그림으로 표현해보면,

사용자 삽입 이미지

멋진 것이었군요+ㅁ+
그렇다면, ArrayList와 LinkedList의 차이점 쯤은 금방 알 수 있겠군요.

여러가지 문서가 있었는데.. '속도'부분에서 많은 논란이 있더라구요.
일단은 괜찮은 영어문서가 있길래.. 무턱대고 해석 들어갔습니다-ㅅ-;

There are two general-purpose List implementations in the Collection Framework, ArrayList and LinkedList, which of the two List implementations you use depends on your specific needs. If you need to support random access, without inserting or removing elements from any place to other than the end, then ArrayList offers you the optimal collection, the LinkedList class provides uniformly named methods to get, remove and insert an element at the beginning and end of the list.

콜렉션 프레임워크에는 ArrayListLinkedList를 병용하는 List implementations1 이 있다.
이것은 당신이 특정한 필요에 의해서 사용하는 두가지 List implementations이다.
만약 당신이 끝 이외에 어디에서든지 요소를 제거하거나 삽입하는 것 없이 자유롭게 접근하는 것이 필요하다면, 그땐, ArrayList가 당신에게 최적의 콜렉션을 제공한다.
LinkedList
클래스는 리스트의 처음과 끝에 요소을 제거하거나 삽입하는 메소드를 제공한다.

Each ArrayList instance has a capacity. The capacity is the size of the array used to store the elements in the list. It is always at least as large as the list size. As elements are added an ArrayList, its capacity grows automatically. The details of the growth policy are not specified beyond the fact that adding an element has constant amortized time cost.

각각의 ArrayList 인스턴스는 용량을 가지고 있다. 용량은 리스트에서 요소들을 저장하기 위해 사용되는 array 크기이고, 언제나 적어도 리스트의 크기만큼 커야한다. 요소들이 ArrayList 추가될 , 그것의 용량은 자동으로 증가한다. 증가방법에 대한 자세한 사항은 지속적으로 상환되는 시간비용을 가진 요소를 더하는 사실 이외에는 기술되어지지 않는다.

An application can increase the capacity of an ArrayList instance before adding a large number of elements using the ensureCapacity operation. This may reduce the amount of incremental reallocation.

에플리케이션은 ensureCapacity 기능을 사용하여 많은 수의 요소들을 추가하기 전에ArrayList 인스턴스의 용량을 증가시킬 있다.
이러한 것은 많은량의 재배치 증가를 감소시킨다.

그렇지요!! 정리를 해보자면,

more..


출력은 다음과 같습니다.
                    [뎅뎅이, 붉은돼지, zerry, Real Study, java, jsp, html/css]
                    첫번째 : 뎅뎅이
                    [Real Study, 뎅뎅이, 붉은돼지, zerry, java, jsp, html/css]
                    [Real Study, 뎅뎅이, 붉은돼지, zerry, java, jsp]
                    첫번째 : Real Study

소스코드를 보면 아시겠지만, addFirst()라던지.. removeLast()라던지
LinkedList에는 ArrayList의 메소드 이외에 추가, 삭제하는 메소드가 추가되어있습니다.
(API 참조 !!)
제가 작성한 코드는 간단한 코드라 아직까지는 그 중요성이 와닿지 않지만,
이러한 것들이 모이다보면..-ㅅ-;
LinkedList가 ArrayList보다 훨씬 빠른성능을 보여주겠지요??
(스택,큐,양방향큐 를 만들 때 편리하게 사용된다는데요. 이건 뭔지 잘 몰라서-ㅅ-;)

< 출처: http://happystory.tistory.com >
반응형
Enum..일단 에자일 책에서 처음 본 신개념입니다.
일단 정의부터 살펴보도록 하지요.

Enum : 정해진 리스트에서만 값을 선택할 수 있다.
            컴파일러가 지원하는 primitive타입이 아니라
            컴퍼일러가 클래스로 변환시킨다.
            불필요한 상수값 부여를 막을 수 있다.
            코드가 간결해진다.

책에 나와있는 소스코드를 보면,
               
enum Grade { A, B, C, D, F };

요런식으로 선언해줍니다.
Grade enum은 다섯 개의 가능한 값을 가지고, 각각은 객체 인스턴스를 표현합니다.

               public static void main(String[] args){

                     System.out.println(Grade.A);

               }

이런식으로 써줄 수 있지요.

이렇듯, Enum은 기본적으로 static입니다.
Enum클래스를 상속받은 static final class로서,
내부요소들은 해당클래스의 인스턴스를 가지게 되지요.

이걸 증명해줄만한, 재밌는 내용이 있어서 가져와봤습니다.1

enum으로 작성한 것을 jad라는 역컴파일러를 통해서 풀어준 코드입니다.

사용자 삽입 이미지

↓ jad로 변환

사용자 삽입 이미지

신기하지요?+ㅅ+ 스터디시간에 발표했던 내용인데, 복습할 겸.. 다시한번 올려봅니다.ㅎ

그때 알고 넘어간 Enum에 관한 사항은 여기까지입니다.
정말 더 깊이 공부하고 싶은 마음은 굴뚝 같으나..-ㅅ-;
아직까지는 너무 어렵네요.
너무 신개념이라 API를봐도 메소드의 정확한 사용법을
알아내기가 쉽지가 않네요.

일단 저 멀리 안드로메다 수준까지 정리를 해 놓으신 zerry님의 글을
트랙백으로 남겨놓겠습니다.-ㅅ-;
두고두고,, 천천히 봐야지.. 한번에 보려니까 머리가 너무 아프네여 ㅠ ㅎ
반응형
아래 그림에서 볼 수 있듯이 Collection과 Map은 따로 존재합니다.
저는 지금까지 Collection 인터페이스를 Map, Set, List가 구현하는 줄 알았는데,
아니더라구요. 이러한 사실은 API를 봐도 알 수 있습니다.

사용자 삽입 이미지

                        List : 순서(index)를 알고 있는 컬렉션.
                        Set : 중복된 것을 허용하지 않는 컬렉션.
                        Map : 키-값 기능 제공.

이러한 개념은 실제 코드를 작성해봐야 알 수 있지요?
에자일 자바책 9장에 이러한 내용이 깊~~게 언급되므로
그때 좀 더 자세히 알아보도록 하겠습니다.-ㅅ-ㅎ


에자일자바 5장을 보면 Collections.sort()가 등장합니다.
Collection이라는 인터페이스 외에, Collections라는 유틸리스 클래스가 또 존재하는데요.
API를 살펴보니, Collection에는 메소드가 거의 없드라구요.
sort()또한 보이지 않았습니다.
sort()는 Collections에 static으로 선언이 되어있습니다.
아래 Collections API를 보면,
사용자 삽입 이미지
-ㅅ-;;;
난해합니다. -_ㅠ
일단 필드와 메소드를 보고 유추해본 결과,
Collections클래스는 List, Set, Map에서 공통으로 사용되는 메소드를 모은
유틸리티 클래스라고 볼 수 있지 않을까 생각됩니다.

static으로 선언되어 있기 때문에
Collections.sort()로 편하게 사용할 수 있습니다.

다음으로 정말 중요한 iterator()입니다.
iterator()는 Iterator타입의 객체를 리턴하는데요.
이 객체를 사용해서 콜렉션 안에 있는 모든 엘리먼트를 하나하나 검색할 수 있습니다.
참 바보스럽게도, 전 여지껏 Iterator라는 인터페이스 없이
iterator()메소드만 Collection, Set, List에 각각 존재하는 줄 알았습니다.-ㅅ-;
하지만, 아니더라구요 ㅎ API를 보면 알 수 있습니다.
Collection, Set, List 인터페이스는 Iterable인터페이스를 구현합니다.
Iterable인터페이스를 보면,
사용자 삽입 이미지
iterator()메소드가 있는것을 볼 수 있습니다.
보면, 메소드가 Iterator형인 것이 확인되지요??
짧은 영어로 해석을 해보면,
<T>타입 요소의 집합을 건네주는 iterator을 리턴한다.-ㅅ-;

그니까.. 제너릭으로 한정한 타입의 요소의 집합으로 iterator을 리턴한다는 뜻이겠지요?

그렇다면.. 이번에는 Iterator인터페이스를 뒤져보도록 하겠습니다.
다음과 같은 메소드들이 존재합니다.

사용자 삽입 이미지

boolean hasNext()
Returns true if the iteration has more elements. (In other words, returns true if next would return an element rather than throwing an exception.)
Returns:
true if the iterator has more elements.
=> 만약 다음에 불러올 요소들이 더 있다면 true을 리턴한다.
    다시말해서, 만약 next가 엘리먼트를 리턴하면 true를 리턴한다.

직역을 하면 도저히 이해하기가 힘들 것 같아서, 엄청난 의역을 해야만 했습니다.ㅎ
제가 이해한 바로는 next()메소드를 통해서 콜렉션에 저장된 다음 요소가 리턴되면
hasNext()는 true를 리턴하고, 리턴될 다음 요소가 없어도
exception은 발생하지 않는다는 것이지요..?ㅋㅋㅋ

그렇다면, 다음으로 next()메소드를 살펴봅시다. 이것을 보면 더욱 이해가 잘됩니다.
E next()
Returns the next element in the iteration. Calling this method repeatedly until the hasNext() method returns false will return each element in the underlying collection exactly once.
Returns:
the next element in the iteration.
Throws:
NoSuchElementException - iteration has no more elements.
=> 반복하면서 다음 요소를 리턴한다.
    이 메소드는 hasNext()메소드가 false를 리턴할 때까지
    기초가되는 콜렉션에 있는 각각의 요소를 정확하게 한번씩
    반복적으로 리턴할 것이다.

영어는 역시 어렵습니다..-_ㅠ
위에 hasNext()메소드에 대한 설명을 보충해주고 있지요??
이래서 API는 보고나면 재밌습니다... 볼때는 괴롭지만 ㅎㅎ

마지막으로 remove()가 있는데, 이것은 Collection안에 있는 모든 요소를 검색하여
어떤 조건을 만족하지 않는 요소를 제거할 때 사용하는데요.
좋은 소스코드가 있습니다.

                        static void filter(Collection c) {
                            Iterator i = c.iterator();
                            while (i.hasNext()) {
                            if (!cond(i.next())) i.remove();
                            }
                        }

                    hasNext()가 true일 경우에만 if문을 반복하는 것입니다.
                    제시하는 조건을 만족하지 않을경우,
                    remove()메소드를 사용해서 해당하는 요소를 제거해줍니다.

iterator() 이전에 Enumeration이 쓰였다고 하는데요.
iterator()와 Enumeration의 차이점은 다음에 포스팅 하도록 하겠습니다.
차이점을 공부하다보면, iterator()에 대해서도 더 자세히 알 수 있겠지요?
출처 : http://happystory.tistory.com
반응형
향상된 for 루프는 J2SE 5.0에서 새로운 언어기능으로 소개된 것으로,
Iterator를 생성하거나, 카운트 변수의 시작과 끝을 계산할 필요 없이
콜렉션을 반복 할 수 있게 해줍니다.

일단, 기본적인 Array에서 향상된 for loop의 사용을 비교해도록 하겠습니다.

more..


이전에 제가 작성한 코드입니다. 이것을 향상된 for문으로 더 간단하게 만들어보겠습니다.

more..



무지 신기하지요??+ㅛ+
자 이제, 이게 어떻게 변하는 가를 설명하도록 하겠습니다.
기존에 for문은 카운트 변수의 시작과 끝을 계산해야했습니다.
즉, row = 0 이고, row가 rowLand(지뢰의 세로 길이 - scanner을 통해서 받은 값)보다
작을 때까지만.. row을 계속 늘려줘라-ㅅ-; 뭐 요런 것인데요.
향상된 for문을 보면
for(String[] row : landMine)

이런식으로 간단하게 줄여졌습니다.
이는, "landMine이라는 이름의 배열의 엘리멘트(row) 반복"으로 읽을 수 있습니다.
자동으로 엘리멘트의 길이를 측정한다고 볼 수 있겠네요..

향상된 for loop의 기본 syntax을 다음과 같이 나타낼 수 있습니다.
   	EnhancedForStatement:
for ( Type Identifier : Expression )
Statement   
Expression must be an instance of a new interface
    called java.lang.Iterable, or an array.

Expression java.lang.Iterable 또는 array라 일컬어지는
새로운 인터페이스의 인스턴스야만 한다.


향상된 for loop에도 단점이 있다고 합니다.

So when should you use the for-each loop? Any time you can. It really beautifies your code. Unfortunately, you cannot use it everywhere. Consider, for example, the expurgate method. The program needs access to the iterator in order to remove the current element. The for-each loop hides the iterator, so you cannot call remove. Therefore, the for-each loop is not usable for filtering. Similarly it is not usable for loops where you need to replace elements in a list or array as you traverse it. Finally, it is not usable for loops that must iterate over multiple collections in parallel.

당신은 for-each(향상된 for) 루프를 언제 사용하여야 하는가?
언제든지 가능하다. 그러면 당신의 코드를 정말 아름답게 할 것 이다..-ㅅ-;;
허나.. 불행하게도, 당신은 for-each를 어디에서든지 사용할 수 없다.
예들들어, 삭제 메소드를 고려해보라. 프로그램은 현재 element을 제거하기 위해
iterator에 접근하는 것을 필요로 한다. for-each loop는 iterator를 숨긴다.
그래서 당신은 remove을 부를 수 없다.
그러므로, for-each loop는 필터링에 쓰기에는 편리하지 않다.
유사하게, 당신은 콜렉션을 순회하면서,
list나 array에 element들을 바꾸는 것을 필요로 할 때, 적합하지 않다.
마지막으로, 동시에 복합적인 콜렉션을 되풀이하는 것은 적합하지 않다.

아 ! 그리고,
지뢰찾기 자료 입력 부분도 for-each문으로 바꿔보고자 했는데,
잘되지가 않아서.. 많은 블로그를 돌아다니면서 예제를 찾아보았는데요.
자료를 입력해주는 부분에는
향상된 for 루프를 사용하지 않고, 일반 for loop를 사용하드라구요.
좀 더 조사해봐야 할 것 같네요.-ㅛ-

자자자자자 그렇다면,
ArrayList와 같은 콜렉션에서 향상된 for loop(for-each)는
어떻게 쓰여질까요??(제너릭과 iterator(), hasNext()등등의 사용..-ㅅ-)
그것은...............
콜렉션에 대해 좀 더 공부하는 시간을 가진 후에,
그때 다시 포스팅하도록 하겠습니다. +ㅅ+ ㅋㅋ
위에 해석한 단점도.. 그때서야 비로소 이해할 수 있을 것 같네요-ㅛ-;

< 출처: http://happystory.tistory.com >
반응형

게시판 연습

 

[여기서는 먼저 전 게시물의 JDBC 프로그래밍을 복습한 후에 내용을 보시기 바랍니다.]

 

JDBC 프로그래밍에서 실습한 GetEmp.java 순수 애플리케이션을 서블릿으로 바꾸고 실행해 보세요(servlet API 참고)

[참고] JDBC 드라이버 (ORACLE_HOME/jdbc/lib/classes12.jar, nls_charset12.jar)를 {애플리케이션홈}/WEB-INF/lib 에

복사합니다.

 

문제 1 답:

 

package example;

 

import java.sql.*;

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;


public class GetEmp extends HttpServlet {

         private String DB_URL;

         private String DB_USER;

         private String DB_PASSWORD;

        

         public void init(ServletConfig config) throws ServletException {

                  super.init(config);

                  //설치과정에서 자신이 정한 정보에 맞게 바꾼다.

                  DB_URL="jdbc:oracle:thin:@127.0.0.1:1521:orcl";

                  DB_USER="scott";

                  DB_PASSWORD="tiger";

                 

                  try {

                           //드라이버를 로딩합니다.

                           Class.forName("oracle.jdbc.driver.OracleDriver");

                  }catch(ClassNotFoundException e){

                           e.printStackTrace();

                  }

         }

 

         public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException,ServletException {

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

                  PrintWriter out = res.getWriter();

                  Connection conn = null;

                  Statement stmt = null;

                  ResultSet rs = null;

                  String query="select * from emp";

                  try {

                           //데이터베이스의 연결을 설정합니다.

                           conn=DriverManager.getConnection(DB_URL,DB_USER,DB_PASSWORD);

                           //Statement를 가져온다.

                           stmt=conn.createStatement();

                           //SQL문을 실행합니다.

                           rs=stmt.executeQuery(query);

                           while(rs.next())  {

                                   String empno=rs.getString(1);

                                   String ename=rs.getString(2);

                                   String job=rs.getString(3);

                                   String mgr=rs.getString(4);

                                   String hiredate=rs.getString(5);

                                   String sal=rs.getString(6);

                                   String comm=rs.getString(7);

                                   String depno=rs.getString(8);

                                   //결과를 출력합니다.

                                    out.println(empno+" : "+ename+" : "+job+" : "+mgr+" : "+hiredate+" : "+sal+" : "+comm+" : "+depno+"<br>");

                           }

                  } catch (SQLException e) {

                           e.printStackTrace(out);

                  }

                  finally {

                           try{

                                   rs.close();

                                   stmt.close();

                                   conn.close();

                           }catch(SQLException e){}

                  }

         }

}


7369 : SMITH : CLERK : 7902 : 1980-12-17 00:00:00.0 : 800 : null : 20
7499 : ALLEN : SALESMAN : 7698 : 1981-02-20 00:00:00.0 : 1600 : 300 : 30
7521 : WARD : SALESMAN : 7698 : 1981-02-22 00:00:00.0 : 1250 : 500 : 30
7566 : JONES : MANAGER : 7839 : 1981-04-02 00:00:00.0 : 2975 : null : 20
7654 : MARTIN : SALESMAN : 7698 : 1981-09-28 00:00:00.0 : 1250 : 1400 : 30
7698 : BLAKE : MANAGER : 7839 : 1981-05-01 00:00:00.0 : 2850 : null : 30
7782 : CLARK : MANAGER : 7839 : 1981-06-09 00:00:00.0 : 2450 : null : 10
7788 : SCOTT : ANALYST : 7566 : 1987-04-19 00:00:00.0 : 3000 : null : 20
7839 : KING : PRESIDENT : null : 1981-11-17 00:00:00.0 : 5000 : null : 10
7844 : TURNER : SALESMAN : 7698 : 1981-09-08 00:00:00.0 : 1500 : 0 : 30
7876 : ADAMS : CLERK : 7788 : 1987-05-23 00:00:00.0 : 1100 : null : 20
7900 : JAMES : CLERK : 7698 : 1981-12-03 00:00:00.0 : 950 : null : 30
7902 : FORD : ANALYST : 7566 : 1981-12-03 00:00:00.0 : 3000 : null : 20
7934 : MILLER : CLERK : 7782 : 1982-01-23 00:00:00.0 : 1300 : null : 10

 

위와 같은 결과 화면을 웹 브라우저에서 확인하셨습니까?

GetEmp 서블릿의 57번째 줄에서 에러가 발생한다는 메시지를 보신다면 /bbs/WEB-INF/lib 에 classes12.jar 파일을 복사하지 않으셨거나 오라클이 가동중이 아니거나 리슨너가 가동중이 아니거나 한 경우입니다.

윈도우에서 오라클을 설치하셨다면 나중 2개는 무시하시고 JDBC 드라이버를 올바른 위치에 복사했는지 확인하시기 바랍니다.

 

문제 2 : 위 서블릿을 JSP로 바꾸어 보세요

 

문제 2 답: 파일명 getEmp.jsp

 

<%@ page contentType="text/html;charset=euc-kr" %>

<%@ page import="java.sql.*" %>

<%

         String DB_URL="jdbc:oracle:thin:@127.0.0.1:1521:orcl";

         String DB_USER="scott";

         String DB_PASSWORD="tiger";

         //설치과정에서 자신이 정한 정보에 맞게 바꾼다.

         try {

                  //드라이버를 로딩합니다.

                  Class.forName("oracle.jdbc.driver.OracleDriver");

         } catch(ClassNotFoundException e){

                           e.printStackTrace();

         }

 

         Connection conn = null;

         Statement stmt = null;

         ResultSet rs = null;

         String query="select * from emp";

         try {

                  //데이터베이스의 연결을 설정합니다.

                  conn=DriverManager.getConnection(DB_URL,DB_USER,DB_PASSWORD);

                  //Statement를 가져온다.

                  stmt=conn.createStatement();

                  //SQL문을 실행합니다.

                  rs=stmt.executeQuery(query);

                  while(rs.next()) {

                           String empno=rs.getString(1);

                           String ename=rs.getString(2);

                           String job=rs.getString(3);

                           String mgr=rs.getString(4);

                           String hiredate=rs.getString(5);

                           String sal=rs.getString(6);

                           String comm=rs.getString(7);

                           String depno=rs.getString(8);

                           //결과를 출력합니다.

                           out.println(empno+" : "+ename+" : "+job+" : "+mgr+" : "+hiredate+" : "+sal+" : "+comm+" : "+depno+"<br>");

                  }

         } catch (SQLException e) {

                  out.println("SQLException: " + e.getMessage());

         }

         finally {

                  try {

                           rs.close();

                           stmt.close();

                           conn.close();

                  } catch(SQLException e){}

         }

%>

 

문제 1 에서와 같은 결과를 확인했습니까?

문제1의 서블릿과 지금 JSP는 코드가 조금 다릅니다.

서블릿에서는 init 메소드에서 JDBC 드라이버에 대한 설정을 했습니다.

서블릿의 라이트 사이클에서 살펴 보았듯이 init 메소드안의 내용은 처음 사용자가 요청한 경우를 제외하고는 다음 요청 부터는 JDBC 드라이버 설정을 하지 않으므로 그렇지 않은 코드보다는 성능이 좋습니다.

JSP에서도 서블릿의 init 메소드와 같은 메소드가 있을 것입니다. 이것은 여러분이 찾아서 고치시기 바랍니다.

 

 

ConnectionPool 사용법

 

데이터베이스에 대한 Connection 을 관리하는 것은 매우 바람직한 일입니다.
왜냐하면 매 페이지마다 데이터베이스에 연결을 시도하는 것(= 커넥션 객체를 얻는것)은 시간이 많이 걸리는 작업입니다.
그럼에도 불구하고 위에서 우리는 Connection 을 얻은 후 사용 후 바로 자원을 반납했습니다
.

 

Database Connection Pool 이란 이전에 연결된 Connection 을 종료하지 않고 웹 클라이언트의 요구시 기존의 Connection을

통하여 데이터베이스에 접근할 수 있도록 하는 free Connection list 입니다.

즉, 시간이 오래 걸리는 커넥션 객체를 쓰고 난 다음에 리스트에서 넣고 관리하겠다는 의미입니다.

적절하게 리스트를 관리하면 시간을 절약하는데 크게 기여하게 하는 기법입니다.

 

. 전체 클래스 요약

 

Log.java
에러 메시지를 콘솔화면에 표시하기 위한 클래스입니다.

 

DBConnectionPoolManager.java

각 데이터베이스의 커넥션풀을 관리하기 위한 클래스입니다.

 

DBConnectionPool.java
DBConnectionPoolManager가 관리하는 데이터베이스당 가지는 커넥션 풀
실제로 이 클래스가 이미 생성된 커넥션을 관리
합니다.

 

ConnectionManager.java
DBConnectionPoolManager 클래스에 일을 시키는 클래스인데
여러 데이터베이스를 고려한 추상클래스입니다.
데이터베이스에 따라서 이 클래스를 상속받아 알맞는 클래스
를 만듭니다.

 

OracleConnectionManager.java 
데이터베이스 오라클을 사용하기 위해 ConnectionManager 클래스를 상속한 서브 클래스입니다.

 

oracle.properties
오라클 설정 파일입니다.
최대 커넥션 수, 초기 커넥션 수 등의 셋팅을 담당합니다.

이렇게 설정 내용을 코드가 아닌 파일에 저장하면 관리하기가 쉽습니다.

 

. 커넥션 풀 관련 소스

 

Log.java


package net.java_school.util;

 

import java.io.*;

import java.util.Date;

 

public class Log {

         public String dbgFile = "H:\\debug\\error.dbg"; // 윈도우  계열

         //public String dbgFile = "/debug/error.dbg"; // 유닉스 계열

 

         FileWriter fw = null;

         public Log() {

                  super();

                  try{

                           fw = new FileWriter(dbgFile, true);

                  }catch(IOException e){}

         }

 

         public void close() {

                  try{

                           fw.close();

                  }catch(IOException e){}

         }

 

         public void close(FileWriter fw) {

                  try{

                           fw.close();

                  }catch(IOException e){}

         }

 

         public void debug(String msg) {

                  try{

                           fw.write("-------------------------------------------------\r\n");

                           fw.write(new java.util.Date()+ " : ");

                           fw.write(msg + " \r\n");

                           fw.write("-------------------------------------------------\r\n");

                           fw.flush();

                  }catch(IOException e){

                           System.err.println("IOException.......!!");

                  }

         }

 

         public static void out(String msg) {

                  System.out.println(new Date() + ": "+msg);

         }

 

         public static void err(String msg) {

                  System.out.println(new Date() + ": "+msg);

         }

 

         public static void err(Throwable e,String msg) {

                  System.err.println(new Date() + ": "+msg);

                  e.printStackTrace(System.out);

         }

}


DBConnectionPool.java


package net.java_school.db.dbpool;


import java.util.*;
import java.sql.*;
import java.util.Date;
import net.java_school.util.Log;


// Connection Pool을 관리하는 클래스
class DBConnectionPool {
 
    // 현재 사용 중인 Connection 개수
    private int checkedOut;
 
    // Free Connection List
    private Vector freeConnections = new Vector();

    // Connection 최대 개수
    private int maxConn;

    // Connection 초기 개수
    private int initConn;

    // Waiting time (pool에 connection이 없을때 기다리는 최대시간)
    private int maxWait;

    // Connection Pool Name
    private String name;

    // DB Password
    private String password;

    // DB URL
    private String URL;

    // DB UserID
    private String user;

    // Constructor
    public DBConnectionPool(String name, String URL, String user, String password, int maxConn, int initConn, int waitTime) {
        this.name = name;
        this.URL = URL;
        this.user = user;
        this.password = password;
        this.maxConn = maxConn;
        this.maxWait = waitTime;
 
        for (int i = 0; i < initConn; i++) {
            freeConnections.addElement(newConnection());
        }
    }
 
    // Connection 반납
    // @param con : 반납할 Connection
    public synchronized void freeConnection(Connection con) {
        freeConnections.addElement(con);
        checkedOut--;
        // Connection을 얻기 위해 대기하고 있는 thread에 알림
        notifyAll();
    }
 
    // Connection 을 얻음
    public synchronized Connection getConnection() {
        Connection con = null;

        // Connection이 Free List에 있으면 List의 처음 것을 얻음
        if (freeConnections.size() > 0) {
            con = (Connection) freeConnections.firstElement();
            freeConnections.removeElementAt(0);
            try {
                // DBMS에 의해 Connection이 close 되었으면 다시 요구
                if (con.isClosed()) {
                    Log.err("Removed bad connection from " + name);
                    con = getConnection();
                }
            } // 요상한 Connection 발생하면 다시 요구
            catch (SQLException e) {
                Log.err(e, "Removed bad connection from " + name);
                con = getConnection();
            }
        } // Connection이 Free List에 없으면 새로 생성
        else if (maxConn == 0 || checkedOut < maxConn) {
            con = newConnection();
        }
        if (con != null) {
            checkedOut++;
        }
        return con;
    }
 
    // Connection을 얻음
    // @param timeout : Connection을 얻기 위한 최대 기다림 시간
    public synchronized Connection getConnection(long timeout) {
        long startTime = new Date().getTime();
        Connection con;

        while ((con = getConnection()) == null) {
            try {
                wait(timeout * maxWait);
            } catch (InterruptedException e) {}
            if ((new Date().getTime() - startTime) >= timeout) {
                // 기다림 시간 초과
                return null;
            }
        }
        return con;
    }
 
    // Connection 생성
    private Connection newConnection() {
        Connection con = null;

        try {
            if (user == null) {
                con = DriverManager.getConnection(URL);
            } else {
                con = DriverManager.getConnection(URL, user, password);
            }
            Log.out("Created a new connection in pool " + name);
        } catch (SQLException e) {
            Log.err(e,
                    "Can't create a new connection for " + URL + " user : "
                    + user + " passwd : " + password);
            return null;
        }
        return con;
    }
}



DBConnectionPoolManager.java


package net.java_school.db.dbpool;

 

import java.sql.*;

import java.util.*;

import net.java_school.util.Log;


public class DBConnectionPoolManager {

         // 인스턴스를 하나만 유지하기 위해 static 으로 선언

         static private DBConnectionPoolManager instance=null;

         //JDBC 드라이버 관리

         private Vector drivers = new Vector();

         // DB Connection Pool List

         private Hashtable pools = new Hashtable();

         // DBConnectionPoolManager의 instance를 얻음

         // @return DBConnectionManger

         static synchronized public DBConnectionPoolManager getInstance() {

                  if (instance == null) {

                           instance = new DBConnectionPoolManager();

                  }

                  return instance;

         }

        

         // Default Constructor

         private DBConnectionPoolManager() {}

 

         // 현재 Connection을 Free Connection List로 보냄

         // @param name : Pool Name

         // @param con : Connection

         public void freeConnection(String name, Connection con) {

                  DBConnectionPool pool = (DBConnectionPool) pools.get(name);

                  if (pool != null) {

                           pool.freeConnection(con);

                  }

                  Log.out("One Connection of " + name + " was freed");

         }

 

         // Open Connection을 얻음. 현재 열린 커넥션이 없고 최대 커넥션 개수가

         // 사용 중이 아닐 때는 새로운 커넥션을 생성. 현재 열린 커넥션이 없고

         // 최대 커넥션 개수가 사용 중일 때 기본 대기 시간을 기다림

         // @param name : Pool Name

         // @return Connection : The connection or null

         public Connection getConnection(String name) {

                  DBConnectionPool pool = (DBConnectionPool) pools.get(name);

                  if (pool != null) {

                           return pool.getConnection(10);

                  }

                  return null;

         }

 

         // Connection Pool을 생성

         // @param poolName : 생성할 Pool Name

         // @param url : DB URL

         // @param user : DB UserID

         // @param password : DB Password

         private void createPools(String poolName, String url, String user, String password, int maxConn, int initConn, int maxWait) {

                  DBConnectionPool pool = new DBConnectionPool(poolName, url, user, password, maxConn, initConn, maxWait);

                  pools.put(poolName, pool);

                  Log.out("Initialized pool " + poolName);

         }

 

         // 초기화 작업

         public void init(String poolName, String driver, String url, String user, String passwd, int maxConn, int initConn, int maxWait) {

                  loadDrivers(driver);

                  createPools(poolName, url, user, passwd, maxConn, initConn, maxWait);

         }

 

         // JDBC Driver Loading

         // @param driverClassName : 사용하고자 하는 DB의 JDBC 드라이버

         private void loadDrivers(String driverClassName) {

                  try {

                           Class.forName(driverClassName);

                           drivers.addElement(driverClassName);

                           Log.out("Registered JDBC driver " + driverClassName);

                  } catch (Exception e) {

                           Log.err(e, "Can't register JDBC driver: " + driverClassName);

                  }

         }

        

         public Hashtable getPools() {

                  return pools;

         }

        

         public int getDriverNumber() {

                  return drivers.size();

         }

}



ConnectionManager.java


package net.java_school.db.dbpool;

 

import java.sql.*;

import java.io.*;

import java.util.*;

import net.java_school.util.Log;

 

public abstract class ConnectionManager {

         protected DBConnectionPoolManager connMgr=null;

         protected String poolName, dbServer, dbName, port, userID, passwd;

         int maxConn,initConn, maxWait;

         private Properties dbProperties;

         private String configFile;

 

         public ConnectionManager(String pool) {

                  poolName = pool;

                  // mnd 컨텍스트 베이스에 config디렉토리에 Property파일이 있음을 가정

                  configFile = "F:\\apps\\tomcat\\webapps\\mnd\\config\\"+poolName+".properties";

                  try {

                           dbProperties = readProperties();

                           dbServer = getProperty( "dbServer" );

                           port = getProperty( "port" );

                           dbName = getProperty( "dbName" );

                           userID = getProperty( "userID" );

                           passwd = getProperty( "passwd" );

                           maxConn = Integer.parseInt(getProperty("maxConn"));

                           initConn = Integer.parseInt(getProperty("initConn"));

                           maxWait = Integer.parseInt(getProperty("maxWait"));

                  } catch( IOException ioe ) {

                           Log.err( "Error reading properties of " + configFile);

                  }

         }

 

         public Connection getConnection() {

                  return (connMgr.getConnection(poolName));

         }

 

         public void freeConnection(Connection conn) {

                  connMgr.freeConnection(poolName,conn);

         }

 

         private String getProperty( String prop ) throws IOException {

                  return ( dbProperties.getProperty( prop ) );

         }

 

         protected synchronized Properties readProperties() throws IOException {

                  Properties tempProperties = new Properties();

                  FileInputStream in = new FileInputStream(configFile);

                  tempProperties.load(in);

                  return tempProperties;

         }

        

         public int getDriverNumber() {

                  return connMgr.getDriverNumber();

         }

}


OracleConnectionManager.java


package net.java_school.db.dbpool;

 

public class OracleConnectionManager extends ConnectionManager {

         public OracleConnectionManager() {

                  super("oracle");

                  String JDBCDriver = "oracle.jdbc.driver.OracleDriver";

                  // 오라클용 JDBC thin driver

                  String JDBCDriverType = "jdbc:oracle:thin";

                  String url = JDBCDriverType+":@"+dbServer + ":" + port + ":" + dbName;

                  connMgr = DBConnectionPoolManager.getInstance();

                  connMgr.init(poolName, JDBCDriver, url, userID, passwd, maxConn, initConn, maxWait);

         }

}

 

oracle.properties

 

#########################################
# Database Connection Properties for Oracle 9i
#########################################

# Database Server Name OR IP address
dbServer=127.0.0.1

# The port number your DB server listents to.
port=1521

# Database Name
dbName=ORCL

# Database User
userID=scott

# Database Password
passwd=tiger

# Maximum Connection Number
maxConn=20

# Inital Connection Number
initConn=5

# Maximum Wait Time
maxWait=5

 

문제 1

getEmp.jsp 를 ConnectionPool을 이용하게 고쳐보세요

 

 

getEmpWithPool.jsp

 

<%@ page contentType="text/html;charset=euc-kr" %>

<%@ page import="java.sql.*, net.java_school.db.dbpool.*" %>

<jsp:useBean id="dbmgr" class="net.java_school.db.dbpool.OracleConnectionManager" scope="application" />

<%

Connection conn = null;

Statement stmt = null;

ResultSet rs = null;

String query="select * from emp";

try {

          //데이터베이스의 연결을 설정합니다.커넥션풀 이용

          conn=dbmgr.getConnection();

          //Statement를 가져온다.

          stmt=conn.createStatement();

          //SQL문을 실행합니다.

          rs=stmt.executeQuery(query);

          while(rs.next()) {

                   String empno=rs.getString(1);

                   String ename=rs.getString(2);

                   String job=rs.getString(3);

                   String mgr=rs.getString(4);

                   String hiredate=rs.getString(5);

                   String sal=rs.getString(6);

                   String comm=rs.getString(7);

                   String depno=rs.getString(8);

                   //결과를 출력합니다.

                   out.println(empno+" : "+ename+" : "+job+" : "+mgr+" : "+hiredate+" : "+sal+" : "+comm+" : "+depno+"<br>");

          }

} catch (SQLException e) {

         out.println("SQLException: " + e.getMessage());

} finally {

         try {

                  rs.close();

                  stmt.close();

                  dbmgr.freeConnection(conn);

         } catch(SQLException e){}

}

%>

 

문제 2 : 위 파일을 로그 클래스(Log.java)를 이용해서 SQLException이 일어날때 이를 로그 파일(error.dbg)에 기록하게 고치세요

 

: getEmpWithPooldbg.jsp

 

<%@ page contentType="text/html;charset=euc-kr" %>

<%@ page import="java.sql.*, net.java_school.db.dbpool.*, net.java_school.util.*" %>

<jsp:useBean id="dbmgr" class="net.java_school.db.dbpool.OracleConnectionManager"

scope="application" />

<%

Log log = new Log();

Connection conn = null;

Statement stmt = null;

ResultSet rs = null;

String query="select * from emp";

try {

         //데이터베이스의 연결을 설정합니다.커넥션풀 이용

         conn=dbmgr.getConnection();

         //Statement를 가져온다.

         stmt=conn.createStatement();

         //SQL문을 실행합니다.

         rs=stmt.executeQuery(query);

         while(rs.next()) {

                  String empno=rs.getString(1);

                  String ename=rs.getString(2);

                  String job=rs.getString(3);

                  String mgr=rs.getString(4);

                  String hiredate=rs.getString(5);

                  String sal=rs.getString(6);

                  String comm=rs.getString(7);

                  String depno=rs.getString(8);

                  //결과를 출력합니다.

                  out.println(empno+" : "+ename+" : "+job+" : "+mgr+" : "+hiredate+" : "+sal+" : "+comm+" : "+depno+"<br>");

         }

} catch (SQLException e) {

         log.debug("Error Source:getEmpWithPooldbg.jsp : SQLException");

         log.debug("SQLState : " + e.getSQLState());

         log.debug("Message : " + e.getMessage());

         log.debug("Oracle Error Code : " + e.getErrorCode());

         log.debug("Query : " + query);

} finally {

         try {

                  rs.close();

                  stmt.close();

                  dbmgr.freeConnection(conn);

                  log.close();

         } catch (SQLException e){}

}

%>

 

위 파일에서 select * from emp 란 스트링을 일부러 에러가 나게 select * fromemp 라고 고치고 다시 테스트해봅니다.

 

로그파일은 Log.java 파일에서 정한대로의 위치에 error.dbg 란 파일을 내용없이 만들어 위치시켜야 합니다.

 

그러면 다음과 같이 로그 파일에 기록이 쌓이는 것을 확인할 수 있습니다.

 

Sat Jun 19 14:01:58 KST 2004 : Error Source:getEmpWithPooldbg.jsp : SQLException
Sat Jun 19 14:01:58 KST 2004 : SQLState : 42000
Sat Jun 19 14:01:58 KST 2004 : message : ORA-00923: FROM 키워드가 있어야할 곳에 없습니다
Sat Jun 19 14:01:58 KST 2004 : Oracle Error Code : 923
Sat Jun 19 14:01:58 KST 2004 : Query : select * fromemp

여기까지 오셨다면 게시판을 위한 준비가 다 된 것입니다.

파일에 로그 파일 쌓이지 않은다면 ConnectionManager.java 의 코드에서 명시한 디렉토리에 error.dbg 파일이 없기 때문입니다.


 

 게시판 연습

 

먼저 테이블을 만듭니다. (오라클에 대한 내용은 오라클 카테고리의 글을 참고하세요)

 

-- 게시판 연습 테이블
create table board(
 num number primary key,
 subject varchar2(200) not null,
 sogae varchar2(4000) not null,
 content varchar2(4000),
 wdate date
);

create sequence seq_board_num
start with 1
increment by 1;

 

적당한 디렉토리에 board.sql로 위 내용으로 만들고 scott 계정으로 접속하여 (C:\에 저장했다면)

 

@C:\board.sql

 

하면 테이블과 시퀀스가 생성됩니다.

 

여기서의 게시판은 단순한 기본적인 기능만을 가진 것을 만들어 보겠습니다.

다음은 게시판을 위해 쓸 파일 흐름도 입니다.

(서블릿과 JSP 를 모두 이용하기 위해 애쓴것이지 이와 같이 프로그래밍하지는 않습니다.)

 

list.jsp ---> write_form.jsp

                  |              |--------->BoardWriter.java(서블릿) - DB insert 문 실행

                  |                                         

                  |---> view.jsp : 게시물의 내용을 보여준다.

                             |

                             |

                             |---> modify_form.jsp

                             |            |----------> BoardModifier.java(서블릿) --- DB update 문 실행

                             |

                             |---> delete_confirm.jsp

                                          |-----------> BoardDeleter.java(서블릿) -- DB delete 문 실행

 

list.jsp : 게시물을 모두 보여줍니다.(페이지분할 기능, 페이지 직접 이동 기능, 검색 기능은 후에 붙이도록 합니다.)

write_form.jsp : 새글 입력 폼 화면

BoardWriter.java : 새글 입력을 실제로 DB에 입력하는 서블릿

view.jsp : 해당 게시물의 상세 정보를 출력하는 페이지

modify_form.jsp : 수정 입력 폼 화면

BoardModifier.java : 수정을 위해 실제로 DB 테이블을 수정을 행하는 서블릿

delete_confirm.jsp : 삭제를 사용자가 선택했을 때 삭제를 정말로 할 것인가 확인하는 화면

BoardDeleter.java : 테이블에서 해당 레코드를 삭제하는 서블릿

 

각각의 소스

 

/bbs/bbs01/list.jsp


<%@ page contentType="text/html;charset=euc-kr" %>

<%@ page import="java.sql.*,net.java_school.util.*,net.java_school.db.dbpool.*" %>

<jsp:useBean id="dbmgr" scope="application" class="net.java_school.db.dbpool.OracleConnectionManager" />

<html>

<body>

<%

Log log = new Log();

Connection conn = null;

PreparedStatement prepare = null;

ResultSet rs = null;

String query = null;

try{

         conn = dbmgr.getConnection();

         query = "select num,subject,wdate from board order by num desc";

         prepare = conn.prepareStatement(query);

         rs = prepare.executeQuery();

         while(rs.next()){

         int num = rs.getInt("num");

         String subject = rs.getString("subject");

         Date wdate = rs.getDate("wdate");

%>

<a href="view.jsp?num=<%= num %>"><%= subject%></a>&nbsp;&nbsp;<%= wdate.toString() %><br>

<%

         }

} catch(SQLException e){

         log.debug("Error Source:bbs/list.jsp : SQLException");

         log.debug("SQLState : " + e.getSQLState());

         log.debug("Message : " + e.getMessage());

         log.debug("Oracle Error Code : " + e.getErrorCode());

         log.debug("Query : " + query);

} finally {

         try {

                  rs.close();

                  prepare.close();

                  dbmgr.freeConnection(conn);

                  log.close();

         } catch (SQLException e){}

}

%>

<br>

<br>

<p>

<a href="write_form.jsp">새글 쓰기</a>

</body>

</html>

 

/bbs/bbs01/write_form.jsp

 

<%@ page contentType="text/html;charset=euc-kr" %>
<html>
<body>
<center><h1>새글 쓰기</h1></center>
<hr>
<table cellspacing="0" cellpadding="0" border="0" width="600" align="center">
<form name="frm" method="POST" action="../servlet/bbs01.BoardWriter">
<tr>
 <td width="100" align="center">제목</td><td><input type="text" name="subject" size="45"></td>
</tr>
<tr>
 <td width="100" align="center">소개글</td><td><textarea name="sogae" rows="10"

cols="60"></textarea></td>
</tr>
<tr>
 <td width="100" align="center">본문</td><td><textarea name="content" rows="10"

cols="60"></textarea></td>
</tr>
<tr>
 <td colspan="2" align="center"><input type="submit" value="전송">&nbsp;&nbsp;&nbsp;<input type="reset" value="취소"></td>
</tr>
</form>
</table>
<br>
<center><a href="list.jsp">목록으로</a></center>
</body>
</html>

 

/bbs/WEB-INF/classes/BoardWriter.java

 

package bbs01;

 

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

import java.sql.*;

import net.java_school.db.dbpool.*;

import net.java_school.util.*;

 

public class BoardWriter extends HttpServlet {

         PreparedStatement prepare = null;

         OracleConnectionManager dbmgr = null;

         // 입력 순서 : 시퀀스 , 제목, 소개글, 본문

         String query = "insert into board values (seq_board_num.nextval,?,?,?,sysdate)";

 

         public void init()  throws ServletException {

           ServletContext sc = getServletContext();
           dbmgr = (OracleConnectionManager)sc.getAttribute("dbmgr");
         }
 

         public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

                  req.setCharacterEncoding("euc-kr");

                  Log log = new Log();

                  String subject = req.getParameter("subject");

                  String sogae = req.getParameter("sogae");

                  String content = req.getParameter("content");

                  Connection con = dbmgr.getConnection();

                  try {

                           prepare = con.prepareStatement(query);

                           prepare.setString(1,subject); //제목 부분

                           prepare.setString(2,sogae); // 소개글 부분

                           prepare.setString(3,content); // 본분 부분

                           prepare.executeUpdate();      // 쿼리 실행

                  } catch (SQLException e){

                           log.debug("Error Source:BoardWriter.java : SQLException");

                           log.debug("SQLState : " + e.getSQLState());

                           log.debug("Message : " + e.getMessage());

                           log.debug("Oracle Error Code : " + e.getErrorCode());

                           log.debug("Query : " + query);

                  } finally {

                           try {

                                   prepare.close();

                                   dbmgr.freeConnection(con);

                                   log.close();

                           } catch(SQLException e){}

                           String path = req.getContextPath();

                           res.sendRedirect(path+"/bbs01/list.jsp");

                  }

         }

}

 

/bbs/bbs01/view.jsp

 

<%@ page contentType="text/html;charset=euc-kr" import="java.sql.*,

net.java_school.util.*,net.java_school.db.dbpool.*" %>

<jsp:useBean id="dbmgr" scope="application"

class="net.java_school.db.dbpool.OracleConnectionManager" />

<html>

<body>

<%

int num = Integer.parseInt(request.getParameter("num"));

Log log = new Log();

Connection conn = null;

PreparedStatement prepare = null;

ResultSet rs = null;

String query = null;

try{

         conn = dbmgr.getConnection();

         query = "select num,subject,sogae,content,wdate from board where num="+num;

         prepare = conn.prepareStatement(query);

         rs = prepare.executeQuery();

         while(rs.next()){

                  String subject = rs.getString("subject");

                  String sogae = rs.getString("sogae");

                  String content = rs.getString("content");

                  Date wdate = rs.getDate("wdate");

%>

<%= subject %></a><br>

<hr>

<%= sogae %><br>

<hr>

<%= content %><br>

<hr>

<%= wdate.toString() %><br>

<%

         }

} catch(SQLException e){

         log.debug("Error Source:bbs/view.jsp : SQLException");

         log.debug("SQLState : " + e.getSQLState());

         log.debug("Message : " + e.getMessage());

         log.debug("Oracle Error Code : " + e.getErrorCode());

         log.debug("Query : " + query);

} finally{

         try {

                  rs.close();

                  prepare.close();

                  dbmgr.freeConnection(conn);

                  log.close();

         } catch(SQLException e){}

}

%>

<form name="modify" method="POST" action="modify_form.jsp">

<input type="submit" value="수정">

<input type="hidden" name="num" value="<%= num %>">

</form>

<form name="delete" method="POST" action="delete_confirm.jsp">

<input type="submit" value="삭제">

<input type="hidden" name="num" value="<%= num %>">

</form>

<br>

<a href="list.jsp">목록으로</a>

</body>

</html>

 

/bbs/bbs01/modify_form.jsp

 

<%@ page contentType="text/html;charset=euc-kr"

import="java.sql.*,net.java_school.util.*,net.java_school.db.dbpool.*" %>

<jsp:useBean id="dbmgr" scope="application"

class="net.java_school.db.dbpool.OracleConnectionManager" />

<%

Log log = new Log();

int num = Integer.parseInt(request.getParameter("num"));

Connection conn = null;

PreparedStatement prepare = null;

ResultSet rs = null;

String subject = null;

String sogae = null;

String content = null;

String query = "select subject,sogae,content from board where num ="+num;

try {

         conn = dbmgr.getConnection();

         prepare = conn.prepareStatement(query);

         rs = prepare.executeQuery();

 

         while(rs.next()){

                  subject = rs.getString("subject");

                  sogae = rs.getString("sogae");

                  content = rs.getString("content");

         }

} catch(SQLException e){

         log.debug("Error Source:modify_form.jsp : SQLException");

         log.debug("SQLState : " + e.getSQLState());

         log.debug("Message : " + e.getMessage());

         log.debug("Oracle Error Code : " + e.getErrorCode());

         log.debug("Query : " + query);

} finally{

         try {

                  rs.close();

                  prepare.close();

                  dbmgr.freeConnection(conn);

                  log.close();

         } catch(SQLException e){}

}

%>

<html>

<body>

<center><h1>글 수정</h1></center>

<hr>

<table cellspacing="0" cellpadding="0" border="0" width="600" align="center">

<form name="frm" method="POST" action="../servlet/bbs01.BoardModifier">

<input type="hidden" name="num" value="<%= num %>">

<tr>

         <td width="100" align="center">제목</td><td><input type="text" name="subject" size="45" value="<%= subject %>"></td>

</tr>

<tr>

         <td width="100" align="center">소개글</td><td><textarea name="sogae" rows="10" cols="60"><%= sogae %></textarea></td>

</tr>

<tr>

         <td width="100" align="center">본분</td><td><textarea name="content" rows="10" cols="60"><%= content %></textarea></td>

</tr>

<tr>

         <td colspan="2" align="center"><input type="submit" value="전송">&nbsp;&nbsp;&nbsp;<input type="reset" value="취소"></td>

</tr>

</form>

</table>

<br>

<center><a href="list.jsp">목록으로</a></center>

</body>

</html>

 

/bbs/WEB-INF/classes/BoardModifier.java

 

package bbs01;

 

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

import java.sql.*;

import net.java_school.db.dbpool.*;

import net.java_school.util.*;

 

public class BoardModifier extends HttpServlet {

         PreparedStatement prepare = null;

         OracleConnectionManager dbmgr = null;

         String query = "update board set subject=?, sogae=?, content=? where num=?";

        

         public void init()  throws ServletException {
           ServletContext sc = getServletContext();
           dbmgr = (OracleConnectionManager)sc.getAttribute("dbmgr");
         }
 

         public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

                  req.setCharacterEncoding("euc-kr");

                  Log log = new Log();

                  int num = Integer.parseInt(req.getParameter("num"));

                  String subject = req.getParameter("subject");

                  String sogae = req.getParameter("sogae");

                  String content = req.getParameter("content");

                  Connection con = dbmgr.getConnection();

                  try{

                           prepare = con.prepareStatement(query);

                           prepare.setString(1,subject);   //제목 부분

                           prepare.setString(2,sogae);    // 소개글 부분

                           prepare.setString(3,content);   // 본분 부분

                           prepare.setInt(4,num);     // 시퀀스 primary key

                           prepare.executeUpdate();    // 쿼리 실행

                  }catch(SQLException e){

                           log.debug("Error Source:BoardModifier.java : SQLException");

                           log.debug("SQLState : " + e.getSQLState());

                           log.debug("Message : " + e.getMessage());

                           log.debug("Oracle Error Code : " + e.getErrorCode());

                           log.debug("Query : " + query);

                  } finally {

                           try {

                                   prepare.close();

                                   dbmgr.freeConnection(con);

                                   log.close();

                           } catch(SQLException e){}

                           String path = req.getContextPath();

                           res.sendRedirect(path+"/bbs01/view.jsp?num="+num);

                  }

         }

}

 

/bbs/bbs01/delete_confirm.jsp

 

<%@ page contentType="text/html;charset=euc-kr"

import="java.sql.*,net.java_school.util.*,net.java_school.db.dbpool.*" %>

<jsp:useBean id="dbmgr" scope="application"

class="net.java_school.db.dbpool.OracleConnectionManager" />

<%

Log log = new Log();

int num = Integer.parseInt(request.getParameter("num"));

Connection conn = null;

PreparedStatement prepare = null;

ResultSet rs = null;

String subject = null;

String sogae = null;

String query = "select subject,sogae from board where num ="+num;

try {

         conn = dbmgr.getConnection();

         prepare = conn.prepareStatement(query);

         rs = prepare.executeQuery();

 

         while(rs.next()){

         subject = rs.getString("subject");

         sogae = rs.getString("sogae");

         }

} catch(SQLException e){

         log.debug("Error Source:delete_confirm.jsp : SQLException");

         log.debug("SQLState : " + e.getSQLState());

         log.debug("Message : " + e.getMessage());

         log.debug("Oracle Error Code : " + e.getErrorCode());

         log.debug("Query : " + query);

} finally{

         try {

                  rs.close();

                  prepare.close();

                  dbmgr.freeConnection(conn);

                  log.close();

         } catch(SQLException e){}

}

%>

<html>

<body>

<center><h1>삭 제 확 인</h1></center>

<hr>

<table cellspacing="0" cellpadding="0" border="0" width="600" align="center">

<form name="frm" method="POST" action="../servlet/bbs01.BoardDeleter">

<input type="hidden" name="num" value="<%= num %>">

<tr>

         <td width="100" align="center">제목</td><td><input type="text" name="subject" size="45" value="<%= subject %>"></td>

</tr>

<tr>

         <td width="100" align="center">소개글</td><td><textarea name="sogae" rows="10" cols="60"><%= sogae %></textarea></td>

</tr>

<tr>

         <td colspan="2" align="center">위 글을 정말로 삭제하겠습니까?</td>

</tr>

<tr>

         <td colspan="2" align="center"><input type="submit" value="삭제">&nbsp;&nbsp;&nbsp;

<input type="button" value="취소" onClick="javascript:history.go(-1)"></td>

</tr>

</form>

</table>

</body>

</html>

 

/bbs/WEB-INF/classes/BoardDeleter.java

 

package bbs01;

 

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

import java.sql.*;

import net.java_school.db.dbpool.*;

import net.java_school.util.*;

 

public class BoardDeleter extends HttpServlet {

         PreparedStatement prepare = null;

         OracleConnectionManager dbmgr = null;

         String query = "delete board where num=?";

 

         public void init()  throws ServletException {
           ServletContext sc = getServletContext();
           dbmgr = (OracleConnectionManager)sc.getAttribute("dbmgr");
         }
 

         public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

                  req.setCharacterEncoding("euc-kr");

                  Log log = new Log();

                  int num = Integer.parseInt(req.getParameter("num"));

                  Connection con = dbmgr.getConnection();

                  try{

                           prepare = con.prepareStatement(query);

                           prepare.setInt(1,num);

                           prepare.executeUpdate();    // 쿼리 실행

                  }catch(SQLException e){

                           log.debug("Error Source:BoardDeleter.java : SQLException");

                           log.debug("SQLState : " + e.getSQLState());

                           log.debug("Message : " + e.getMessage());

                           log.debug("Oracle Error Code : " + e.getErrorCode());

                           log.debug("Query : " + query);

                  } finally {

                           try {

                                   prepare.close();

                                   dbmgr.freeConnection(con);

                                   log.close();

                           } catch(SQLException e){}

                           String path = req.getContextPath();

                           res.sendRedirect(path+"/bbs01/list.jsp");

                  }

         }

}

<출처: http://cafe.naver.com/webprogramguide >

반응형

JSP 예제

 

[예제를 실습하기에 앞서 첨부 파일(example.zip)을 다운로드 한 후 /bbs 디렉토리에 압축을 풉니다.]

 

include 지시자를 이용한 파일 인클루드 예제

 

/bbs/ex1/main.jsp : main.jsp에서 include 지시자를 사용하여 디자인 페이지인 main.html 포함.

main.jsp 내에서 다음과 같이 main.html 페이지를 인클루드 합니다.

 

<%@ include file=”main.html” %>


유지 보수의 편리함 때문에 디자인 페이지를 include 지시자를 이용하여 포함시키는 경우가 많이 발생합니다.

이때 주의해야 할 사항은 인클루드 되는 파일(main.html)내에서의 링크는(<img src=..) 인클루드하는 파일(main.jsp)이 기준으로 해야 합니다는 점입니다.

이 예제에서 만약에 main.jsp 가 /bbs/ex1/ 에 위치하고 main.html 파일이 /bbs/ex1/inc 에 그리고 이미지 파일의 디렉토리가 /bbs/img 라고 가정한다면,

main.html 내에서의 이미지에 대한 링크는 <src img=../img/image.gif > 이어야지 <src img=../../img/image.gif>이면 안됩니다.

물론 main.html 만를 요청하면 main.html 내에서 이미지는 깨집니다. 하지만 깨지는 것이 정상입니다.

우리가 서비스하는 파일은 main.html 파일 단독이 아니기 때문입니다. main.jsp 가 웹 사이트가 방문자가 방문할 페이지이지 main.html 역시 단독으로 방문할 수 있는 페이지라면 디렉토리 구조부터 바꾸어야 합니다.

 

Form 태그의 텍스트필드를 이용해서 파라미터 값 전송 예제

 

main.jsp -> welcome.jsp

 

/bbs/ex2/main.jsp : main.jsp 에서 파라미터 값으로 uid, passwd를 welcome.jsp 에 전달

main.jsp 에서 <input type=”text” name=”uid”> 로 welcome.jsp 로 전송했다면 welcome.jsp에서는 사용자가 웹 브라우저를 통해 보내는 문자열 정보를 받는 코드 조각으로 받을 수 있습니다.


<% request.getParameter(“uid”) %>

 

파라미터 값을 자바빈에 설정하고 값 가져오기(set/get) 예제

 

/bbs/ex3/main.jsp 파일에서 디자인 파일 main.html 과 welcome.jsp 파일을 인클루드 하는데

welcome.jsp는 uid, passwd 값이 넘어 올때만 인클루드 됩니다. (main.jsp 소스를 확인해 보세요)

 

또한 이 예제에는 자바빈을 이용합니다.

이 때 자바빈을 어떻게 셋팅하고 자바빈에 저장된 값을 어떻게 가지고 오는지 확인합니다.


main.jsp 에서 아래와 같이 표준액션을 이용해서 자바빈을 생성합니다.

 

<%@ page import="kr.go.mnd.baby.*" info="Simple JSP" contentType="text/html; charset=euc-kr" %>

<jsp:useBean id="login" scope="page" class="kr.go.mnd.baby.User" />

<jsp:setProperty name="login" property="*"/>


여기서 <jsp:useBean>은 main.jsp 가 요청되면 id가 login이고 scope가 page인 객체를 찾아서 레퍼런스를 리턴하려 합니다.

그런데 찾는 객체가 없으면 객체를 생성합니다.

객체를 생성할 때는 페이지 지시자의 임포트된 팩키지에서 클래스를 찾아서 생성하게 됩니다.

두번째 표준액션인 <jsp:setProperty>는 넘어온 파라미터값으로 자바빈의 set 메소드를 호출하여 값을 저장하는 액션인데 처음 main.jsp를 호출하게 되면 아무런 작용도 하지 않는다.

main.jsp 에서 uid, passwd를 값을 자기 자신인 main.jsp에 넘기게 되면

 

<jsp:setProperty name="login" property="*"/>

 

의해 이미 생성한 User 자바빈의 setUid() 메소드와 setPasswd() 메소드를 호출하게 되어 자바빈을 설정하게 됩니다.

 

main.jsp

main.jsp

User.java

<input type=”text” name=”uid”>

<jsp:setProperty name=”login” property=”uid”>

setUid(String userid)


여기서 자바빈의 setUid 메소드에서 Uid가 대문자인 것에 의구심을 가질 수도 있는데

이는 자바 언어의 메소드 이름 규칙에 의한 것입니다.

자바 언어는 메소드나 변수의 이름을 작성할 때 첫 글자는 소문자로 시작하고 여러 단어가 붙을 때는 단어의 첫글자는 대문자로 함을 권고합니다.

클래스의 작명 규칙은 첫 글자는 대문자인 것만 빼고 메소드 작명 규칙과 같습니다.

실습 : 아래 자바빈은 /bbs/ex3/main.jsp 를 실행하기 위해서 필요한 자바빈입니다. 작성한 후 /bbs/WEB-INF/claases 에 넣고

컴파일하면 /bbs/ex3/main.jsp 가 실행이 됩니다.

 

package kr.go.mnd.baby;

public class User {

         String uid;

         String passwd;

         public User(){

                  uid = null;

                  passwd = null;

         }

         public String getUid(){

                  return uid;

         }

         public String getPasswd(){

                  return passwd;

         }

         public void setUid(String uid){

                  this.uid = uid;

         }

         public void setPasswd(String passwd){

                  this.passwd = passwd;

         }

}

 

 

사용자 유틸리티 클래스 사용 예제

 

파일 : /bbs/ex4/main.jsp, welcome.jsp

 

위 예제에서 uid 값에 한글을 넣고 테스트하면 한글이 깨집니다.

이를 보완하기 위해서 사용자 유틸리티 클래스를 만들어 사용해 봅니다.


/bbs/ex4/main.jsp -> welcome.jsp 로 uid 값을 한글로 보낼 때 welcome.jsp 에서 한글이 제대로 보이도록 하는 것이 목적입니다.


JSP 엔진에 따라서 입력된 한글이 깨져 나올 수 있습니다.

한글 처리가 미흡한 경우에는 코드에서 처리해 주어야 합니다.

JSP 내에서 한글을 처리하기 위해서는 입력 받은 한글을 euc-kr 이나 KSC5601 문자 세트로 변환합니다.

(이는 JSP엔진이나 OS에 따라서 달라질 수 있습니다. 여기서는 KSC5601로 변환했습니다)

데이터베이스에 한글을 삽입할 때도 문제가 생기면 같은 방법을 사용합니다.

 

아래 사용자 유틸리티 클래스를 작성하여 예제 실현


*** Hanguel.java ***

 

package kr.go.mnd.util;

 

import java.io.UnsupportedEncodingException;

public class Hanguel {

    public Hanguel() {}   

         public static String toHanguel(String s) {

                  try {

                           if (s != null)

                                   return (new String(s.getBytes("8859_1"),"KSC5601"));

                           return s;

                  } catch (UnsupportedEncodingException e) {

                           return "Encoding Error";

                  }

    }

}

 

welcome.jsp 에서 기존의 코드 request.getParameter("uid"); 다음과 같이 바꿉니다.

 

Hanguel.toHanguel(request.getParameter("uid"));

 

Hanguel 클래스의 toHanguel메소드를 사용하기 위해서는 welcome.jsp 의 페이지 지시자에서 다음과 같은 해당 클래스를 임포트해주어야 합니다.

 

<%@ page import="kr.go.mnd.util.Hanguel" %>


여기서 주의해야 것은 welcome.jsp 내에서 Hanguel 클래스의 객체 생성하지도 않고 바로 toHanguel 메소드를 사용할 있었다는 것입니다.

이는 Hanguel 클래스의 toHanguel 메소드가 static으로 선언된 클래스 메소드이기 때문에 객체 생성 없이 해당 메소드의 호출이 가능하기 때문입니다. (자바에 대한 기초 내용입니다)


welcome.jsp 파일을 아래와 같이 고치고 테스트해 봅니다.


<%@ page import="kr.go.mnd.util.Hanguel" %>
<center>
<h1>Hello,
<%
out.println(Hanguel.toHanguel(request.getParameter("uid")));
%>
</h1>
</center>

한글을 위해서 위와 같이 사용자 유틸리티 클래스를 이용하는 것대신에 request 의 setCharacterEncoding 메소드를 이용해도 됩니다.

Welcome.jsp 내에서 아래와 같이 사용합니다.


<%

request.setCharacterEncoding("euc-kr");

%>


setCharacterEncodeing 메소드는 최근 자바 버전부터 생긴 메소드로 이전의 웹 애플리케이션을 보면 거의다 위와 유사한 한글 컨버터 사용자 유틸리티 클래스를 쓰고 있습니다.

또한 문서에 의하면 setCharacterEncodeing 메소드가 아직 버그가 있어서 함께 혼용하여 사용하는 것이 낫다고 합니다.


이번에 다운로드 한 그대로의 welcome.jsp 파일를 이용하여 한글을 나오도록 해 보겠습니다.


<center>
<h1>Hello,
<jsp:getProperty name="login" property="uid" />
</h1>
</center>


위 파일이 원래의 welcome.jsp 파일입니다.


자바 빈을 이용하는 것이므로 자바 빈의 코드 안에 위에서 만든 Hanguel 사용자 유틸리티 클래스를 이용하도록 코드를 고칩니다.

아래와 같이 User 빈이 Hanguel 사용자 유틸리티 클래스를 이용하도록 고치고 테스트 합니다.


User.java


package kr.go.mnd.baby;


import kr.go.mnd.util.Hanguel;


public class User {
    String uid;
    String passwd;

    public User() {
        uid = null;
        passwd = null;
    }

    public String getUid() {
        return uid;
    }

    public String getPasswd() {
        return passwd;
    }

    public void setUid(String uid) {
        this.uid = Hanguel.toHanguel(uid);
    }

    public void setPasswd(String passwd) {
        this.passwd = Hanguel.toHanguel(passwd);
    }
}

<출처: http://cafe.naver.com/webprogramguide/>

반응형

JSP란?
Java Server Pages, 즉 JSP는 다이나믹 HTML를 생성하기 위한 자바진영의 기술입니다.

JSP는 마이크로소프트의 ASP에 대항하기 위한 자바진영의 기술로, 서블릿의 가지고 있는 디자인과 코드의 분리의 어려움을 개선한 기술입니다.
JSP 문서의 확장자는 반드시 .jsp 이어야 합니다.
다음 코드는 간단한 JSP파일의 예입니다.


<html>
<body>
<% out.println("Hello JSP Reader"); %>
</body>
</html>

보기에는 단순한 HTML 파일 같지만 사실 자바 코드를 포함하고 있습니다.
이제 이 파일을 클라이언트의 웹 브라우저에서 보기 위해 hello.jsp 로 우리가 만든 /bbs 디렉토리에 옮겨 놓으면 됩니다.


클라이언트가 hello.jsp를 요청하면, 서버는 .jsp 확장자를 인식하고 이것이 특별한 핸들링이 필요하다는 것을 판단하여 서블릿 컨테이너에게 이 파일을 보내게 됩니다. (이것은 웹서버와 PHP 파서와의 관계와 마찬가지입니다)


그러면 JSP엔진은 .jsp 파일을 받아서 이를 서블릿으로 변환합니다.
변환된 서블릿은 톰캣의 경우 <TOMCAT_HOME>/work 에서 확인할 수 있습니다.

 

위의 간단한 예제도 결국은 서블릿으로 변환됩니다.
hello.jsp 가 처음으로 불리워진다면 이 파일은 서블릿으로 변환되고 컴파일된 후에 상주 메모리에 로딩됩니다.


그런 후에 해당하는 출력내용을 요청한 클라이언트에게 보내게 됩니다.


이후 똑같은 요청이 들어오면, 서블릿 엔진은 원본 .jsp 소스가 변경되었는지를 체크합니다.

그리고 객체가 이미 로딩되었는지 확인합니다. 로딩이 되었다면 로딩된 객체가 서비스하고 로딩되지 않았다면 메모리에 로딩시킵니다.

소스가 변경되었다면 JSP엔진은 JSP소스를 다시 파싱하여 서블릿으로 변환합니다.


다음 그림은 JSP 소스의 파싱 과정을 나타낸다.

최초의 클라이어트가 접속하여 서비스를 요청할 때 컨테이너는 JSP 페이지가 서블릿으로 변환하고 서블릿을 컴파일하여 요청에 응답합니다.

일단 서블릿이 요청에 응답하면 메모리에 로딩되어 있는 상태로 다음 클라이언트의 요청을 기다리게 됩니다.

사용자 삽입 이미지

※ JSP도 서블릿 기반의 기술입니다.
따라서 JSP는 서블릿의 자원과 기능을 가집니다.

JSP Directives

이것은 JSP페이지의 전반적인 정보를 서블릿 엔진에게 제공합니다.
JSP 스펙에 의해 현재에 가능한 지시어는
page, include, taglib 입니다.

page Directive

용법 : <%@ page {attribute="value"} %>

 

페이지 지시어의 속성 설명

language="scriptLanguage"

페이지를 컴파일할 서버측 언어가 무엇인지 기술

extend="className"

페이지가 상속한 부모클래스를 정의

import="importList"

페이지가 import하는 자바팩키지 리스트 기술 (,로 구분)

session="true|false"

페이지에 session 데이터가 이용되는지의 여부를 결정

(디폴트값:true)

buffer="none|size in kb"

출력 스트림의 버퍼크기를 결정(디폴트값:8kb)

autoFlush="true|false"

출력버퍼가 자동적으로 비워지는가 또는 버퍼가 차면 익셉션을 발생할것인가 여부를 결정 (디폴트값:true)

isThreadSafe="true|false"

JSP엔진에게 이 페이지가 일시에 다중으로 서비스할 수 있는가의 여부를 알림

(디폴트값은 true, 만약 이 값이 false로 셋팅되었다면

SingleThreadModel 로 페이지가 작동합니다.)

info="text"

JSP페이지에 관한 정보를 나타낸다.

Servlet.getServletInfo()메소드를 이용해 접근가능

errorPage="error_uri"

JSP 익셉션을 다루는 에러 페이지의 상대경로를 나타냄

isErrorPage="true|false"

페이지가 에러핸들링하는 페이지인가를 기술(디폴트값:false)

contentType="ctinfo"        

클라이언트로 보내질 response의 MIME타입과 캐릭터셋


※ 디폴트 값이 적용되므로 개발자는 이 속성을 모두를 정의해 줄 필요가 없습니다.

java.util팩키지를 import하는 페이지 지시어 예


<%@ page import="java.util.*" %>

include Directive


inlcude 지시어는 JSP 변환때에 텍스트나 소스를 삽입하기 위해 사용합니다.


용법 : <%@ include file="relativeURLspec" %>

삽입되는 문서의 포맷을 html이거나 jsp이거나 상관없지만 웹 애플리케이션내에 존재해야 합니다.

예) <%@ include file="header.jsp" %> 상대경로 사용

※ include 지시어는 변환때 한번만 사용됩니다.
따라서 삽입되는 소스파일이 변경될때는 JSP/Servlet엔진이 재시작되기 전까지는 반영되지 않습니다.

taglib Directive


taglib 지시어는 JSP페이지가 커스텀 태그 라이브러리를 이용함을 기술합니다.
커스텀 태그 라이브러리는 각각의 커스텀 태그 집합을 구별하는 prefix와 uri로 유일하게 구별됩니다.

용법 : <%@ taglib uri="tagLibraryURI" prefix="tagPrefix" %>

태그라이브러리 지시어 속성


uri               커스텀태그 라이브러리를 고유하게 이름짓는 URI 참조
prefix            커스텀 태그 라이브러리를 구별하는데 쓰이는 Prefix 정의


 


Scripting


Scripting은 HTML페이지에 자바코드 조각을 바로 삽입하기 위해 사용합니다.
Scripting에는 Declarations, Exceptions, Scriplets 3가지가 있습니다.
이들 각각은 서블릿의 적절한 위치에서 변화되어 놓이게 됩니다.

Declarations


Declarations는 자바 변수와 메소드를 JSP페이지내에서 선언하기 위해선 사용됩니다.

JSP Declarations는 JSP페이지가 첫번째로 로딩될때 초기화되고 그 후에 같은 페이지내의
다른 Declarations, expressions, scriptlets에게 이용되어 진다.

용법 :
<%! declaration %>

변수 선언 예   : <%! String name = new String("BOB") %>
메소드 선언 예 : <%! public String getName() { return name; } %>

Declarations는 서블릿으로 변환될때 서블릿 클래스의 선언부분에 위치하게 됩니다.

 

Expressions


JSP Expressions는 컨테이너에 의해 결과값(문자열)으로 바뀌는 JSP 컴포넌트입니다.
JSP Expressions는 request타임에 .jsp 파일내에서 컨테이너에 의해 변환되어 삽입됩니다.
만약 결과값이 문자열로 변환되지 않는다면 번역시 에러가 발생합니다.
번역시 문자열이 검출되지 않는다면 ClassCastException 익셉션이 request타임에 발생합니다.
용법 :
<%=expression %>
) Hello <%= getName() %>

Scriptlets


Scriptlets는 모든 JSP 요소를 가져올 수 있는 JSP컴포넌트입니다.
이들은 request타임에 실행됩니다.

용법 :
<% scriptlets source %>

Scriptlets를 가지고 있는 페이지를 처음 요청하면 JSP는 서블릿코드로 변환되고 컴파일되고 상주메모리에 로딩됩니다.
<%...%>로 표현되는 Scriptlets는 서블릿의 service() 메소드내에 위치하게 됩니다.

JSP Error 핸들링

JSP 아키텍처는 오로지 에러만을 다룰 수 있는 JSP페이지로서 에러 핸들링의 해법을 제시합니다.
에러는 주로 런타임 에러가 대부분인데 이것은 JSP 바디안 이거나 또는 JSP 바디안 에서 호출하는 어떤 다른 객체에서 발생합니다.


request타임 에러는 호출한 JSP의 몸체에서 잡을 수 있고 또한 다룰 수 있는 에러가 던져졌을 때 발생합니다.

호출한 JSP의 몸체에서 다룰 수 없는 익셉션의 경우는 잡혀지지 않은 익셉션과 함께 클라이언트 request를 에러 페이지로 전송합니다.

JSP Error 페이지 만들기

JSP Error 페이지를 만드는 것은 간단하다.
기본적인 JSP페이지를 만들고 컨테이너에게 이 페이지가 에러 페이지임을 알리면 됩니다.
이것은 앞서 언급한 page Directives의 isErrorPage를 셋팅하면 됩니다.
다음은 에러페이지의 예입니다.

*** errorpage.jsp ***


<html>
<body>
<%@ page isErrorPage="true" %>
Bob there has been an error : <%= exception.getMessage() %> has been reported.
</body>
</html>

<설명>
<%@ page isErrorPage="true" %>
위 지시자는 이 페이지가 에러 페이지라는 것을 컨테이너에게 알리는 역활을 합니다.

<%= exception.getMessage() %>


는 에러페이지로 전달되어 온 익셉션의 에러 메시지를 출력하기 위한 부분입니다.
이때 exception이라는 내장객체를 사용합니다.

JSP Error 페이지 사용법


에러 페이지가 어떻게 작동하는지 알아보기 위해 잡히지 않는 익셉션을 발생시키는 간단한
JSP페이지를 만들어봅시다.

*** testerror.jsp ***

<%@ page errorPage="errorpage.jsp" %>
<%
   if(true){
      //Just throw an exception
      throw new Exception("An uncaght Exception");
   }
%>

에러페이지를 errorpage.jsp로 셋팅했다.

이렇듯 JSP페이지에게 에러페이지를 알리는 방법은 JSP페이지의 page directive에서
errorPage속성값을 정해주는 것입니다.
속성값에서 에러페이지의 위치는 페이지의 상대경로입니다.

이 예제을 실행해보기 위해서는 testerror.jsp 와 errorpage.jsp을
<TOMCAT_HOME>/webapps/bbs/에 위치시키고 testerror.jsp를 방문합니다.

Implicit Objects ( 내장 객체 )

내장 객체는 JSP문서내에서 이용되는 객체인데 특별히 레퍼런스를 얻기 위한 작업 없이 바로 사용할 수 있는 객체를 말합니다.

out

 

javax.servlet.jsp.JspWriter클래스의 인스턴스를 나타냅니다.
데이터를 응답 스트림으로 작성하는데 사용합니다.
이 객체의 일반적인 메소드는 out.println()입니다.
 사용예


*** out.jsp ***


<%@ page errorPage="errorpage.jsp" %>
<html><head><title>Use Out</title></head>
<body>
<%
   //Print a simple message using the implicit out object.
   out.println("<b> Hello Bob! </b>");
%>

</body></html>

request

 

javax.servlet.http.HttpServletRequest 인터페이스의 인스턴스
요청 파라미터나 헤더와 같은 사용자가 요청한 유용한 정보에 대해 접근할 수 있습니다.
request 객체는 모든 HTTP요청과 관련되어 있습니다.
이 객체는 request의 파라미터를 구하는데 일반적으로 사용되는데
getParamter()메소드를 사용함으로써 파라미터의 값을

리턴받습니다.

예)

*** request.jsp ***

<%@ page errorPage="errorpage.jsp" %>
<html>
<head>
   <title>UseRequest</title>
</head>
<body>
<%
   out.println("<b>Welcome: " + request.getParameter("user") + "</b>");
%>
</body>
</html>


실행하려면 다음 URL을 방문합니다. http://localhost/bbs/request.jsp?user=kim



response


javax.servlet.http.HttpServletResponse 인터페이스의 인스턴스입니다.

사용자에게 리턴할 현재 응답을 나타낸다.
하지만 대부분의 HTML 출력은 out객체를 이용합니다.


pageContext

 

jsp범위 내에서 이용 가능한 모든 자원 및 현재의 요청, 응답, ServletContext,

HttpSession, ServletConfig 같은 페이지 속성들에 접근할 수 있는 방법을 제공합니다.

pageContext 객체는 내장 객체를 접근할 수 있는 방법을 제공합니다.

session

session 객체는 javax.servlet.http.HttpSession 객체를 나타냅니다.
세션 데이타를 읽고 저장하는 데 사용됩니다.
 
session 객체의 사용예
*** session.jsp ***


<html> <lhead> <title>Session Example </title> </head>
<body>
<%
   //get a referece to the current count from the session
   Integer count = (Integer)session.getAttribute("COUNT");

   if(count==null){
      //If the count was not found, create one
      count = new Integer(1);
      //and add it to the HttpSession
      session.setAttribute("COUNT",count);
   } else {
      //Otherwise increment the value
      count = new Integer(count.intValue() +1);
      session.setAttribute("COUNT",count);
   }
   out.println("<b>This page has been accessed: " + count + " times.</b>");
%>
</body> </html>

이 예제를 사용하기 위해서는 session.jsp 파일을
<TOMCAT_HOME>/webapps/mnd에 복사하고 http://localhost/bbs/session.jsp 를 방문합니다.
리로드 버튼을 눌러 결과를 확인합니다.

application


application 객체는 javax.servlet.ServletContext 나타낸다.

이 객체는 주로 웹 컴포넌트가 공유할 수 있도록 ServletContext에 저장되어 있는 객체를 접근하기 위해 사용됩니다.


config


이 객체는 ServletConfig의 레퍼런스를 가지고 있습니다.
ServletConfig는 JSP/Servlet엔진의 관한 설정 정보를 담고 있습니다.
초기화 파라미터들에 접근하기위해 사용합니다.


page


이 객체는 현재 JSP페이지의 레퍼런스를 가지고 있습니다.
jsp페이지의 페이지 구현 클래스 인스턴스를 참조하며 Object형으로 선언되어 있습니다.
page변수는 스크립팅 엘리먼트들 안에서 가끔 사용되며, 단순히 jsp페이지와 구현 서블릿 사이의
연결 역할을 합니다.
 
exception


JSP페이지에서 발생한 잡히지 않은 익셉션에 접근을 제공하는 객체입니다.
이 객체는 page 지시어 중 isErrorPage가 true로 설정한 페이지내에서만 사용이 가능합니다.

, 페이지디렉티브를 이용해서 에러 페이지로 지정한 jsp에서만 유용한 객체입니다.


표준 액션

표준 액션이란 미리 제공된 커스텀 태그라 생각하면 됩니다.
6가지 표준액션이 제공됩니다.

<jsp:useBean>

이 표준액션은 자바빈을 생성하거나 생성된 자바빈을 찾기 위한 액션입니다.
<jsp:useBean>은 매우 유연합니다.


JSP문서내에서 <jsp:useBean>부분에 이르면 우선 같은 scope와 ID를 사용하는 객체를 찾습니다.
만약 찾는것에 실패하면 scope와 ID와 관련이 있는 객체를 생성하기 위해 시도합니다.

신택스


<jsp:useBean id="name" scope="page|request|session|application" typeSpec>
body
</jsp:useBean>

typeSpec :: =class="className" |
       class="className" type="typeName" |
       type="typeName" class="className" |
       beanName="beanName" type="typeName" |
       type="typeName" beanName="beanName" |
       type="typeName"

<jsp:useBean>의 속성 설명
id : 특정 scope 내에서 객체의 인스턴스와 관련되어 있는 키
scope : 참조되는 객체의 라이프 page | request | session | application

class : 객체의 구현을 정의하는 클래스
beanName : 자바빈의 레퍼런스
type : 정의된 변수의 타입(정의되지 않으면 class의 속성값과 같습니다)

<jsp:setProperty>

이 액션은 자바빈의 속성값을 셋팅하는 데 쓰입니다.

신택스 : <jsp:setProperty name="beanName" propexpr />
name 속성은 빈의 이름을 나타낸다.

propexpr

property="*" |
property="propertyName" |
property="propertyName" param="parameterName" |
property="propertyName" value="propertyValue"

<jsp:setProperty> 액션의 속성 설명

name  

<jsp:useBean>에서나 다른 액션에서 정의된 인스턴스의 이름


property  

셋팅을 원하는 곳의 속성
만약 propertyName에다가 * 라고 셋팅하면 ServletRequest로부터 차례대로 전달받은 파라미터로 모든 속성값을 세팅하게
됩니다.
만일 해당 파라미터가 비어있습니다면 수정되지 않는다.


param    

셋팅하기를 원하는 파라미터의 이름

value      

빈의 속성에 대응하는 값

<jsp:getProperty>

빈의 속성값을 가져와서 스트림으로 변환하고 이것을 output 스트림에 두는 액션
신택스    <jsp:getProperty name="name" property="propertyName" />

<jsp:getProperty> : 표준 액션 속성 설명
name   : 빈 인스턴스의 이름
property  : 얻고자 하는 빈 인스턴스의 속성값

<jsp:param>

이 액션은 표준 액션, <jsp:include>,<jsp:forward>,<jsp:plugin>에 파람값을 전달할때 이용합니다.

신택스 : <jsp:param name="name" value="value" />

<jsp:param> 의 속성 설명
name : 파리미터의 이름
value : 파리미터의 값

<jsp:include>


이 액션은 JSP페이지에 정적 또는 다이나믹 웹 컴포넌트를 추가할때 사용합니다.

신택스
<jsp:include page="urlSpec" flush="true">
   <jsp:param ... />
</jsp:include>

<jsp:include> 의 속성 설명
page :  인클루드 되는 소스의 상대경로
flush :  버퍼가 비워지는 여부

※ include 지시어와 include 표준 액션과의 차이점
지시어는 한번만 번역타임에 해석되지만 표준액션의 경우는 매 request타임마다 해석됩니다.
따라서 지시어를 사용한 인클루드는 인클루드되는 파일의 변화는 톰캣이 재시동되지 않으면 반영되지 않습니다.


<jsp:forward>

이 액션은 JSP엔진이 실행중에 request를 다른 자원(정적 문서,서블릿, JSP)에게 넘기는 것을 가능하게 합니다.
이 액션에서도 <jsp:param>가 쓰일 수 있는데 이는 포워딩할 대상자원에게 전달할 파라미터를 지정하기 위해 쓰입니다.

신택스   
<jsp:forward page="relativeURL">
   <jsp:param .../>
</jsp:forward>

단일 속성 page는 포워딩할 대상자원을 상대주소로 나타낸 값입니다.

<jsp:plugin>

이 액션은 다운로드나 애플릿,자바빈의 실행을 일으키는 HTML 코드를 생성하는데 사용됩니다.
이 액션은 한번 해석되어 <object> 나 <embed>로 바뀝니다.
속성은 바뀌는 코드에 표현을 위한 설정데이터로 제공됩니다.

신택스
<jsp:plugin type="pluginType" code="classFile" codebase="relativeURLpath">
   <jsp:params>
   </jsp:params>
</jsp:plugin>

<jsp:plugin>의 속성 설명
type : 인클루드할 플러그인 타입 예를 들면 applet
code : 플러그인이 실행할 클래스의 이름
codebase : 클래스의 절대 또는 상대경로



서블릿컨텍스트와 웹 애플리케이션의 관계

 

서블릿컨텍스트와 웹 애플리케이션과의 관계에 대해 알기 전에 먼저 서블릿컨텍스트가 무엇인지 부터 알아야 합니다.
서블릿컨텍스트(ServletContext)는 javax.servlet 팩키지에 속하는 객체입니다.

이것은 웹 애플리케이션의 서브 사이드 컴포넌트와 서블릿 컨테이너와의 통신을 담당하는 메소드 집합을 정의합니다.

서블릿컨텍스트의 가장 일반적인 사용중 하나는, 웹 애플리케이션의 서버 사이드 컴포넌트들 모두에게 이용될 수 있는 객체를 위한 저장소로 이용되는 것입니다.
서블릿컨텍스트에 저장된 객체는 웹 애플리케이션의 일생동안 존재합니다.
4개의 서블릿컨텍스트의 메소드는 공유메모리기능를 제공하기 위해 쓰입니다.

다음은 각각의 메소드에 관한 설명입니다.

setAttribute(java.lang.String name,java.lang.Object object)


첫번째 파라미터값인 이름으로 객체를 바인딩하고 객체를 서블릿컨텍스트에 저장합니다.
만약 특정 이름이 이미 사용중이라면 기존의 이름으로 바인딩된 속성을 지우고 새로운 객체를 이 이름으로 바인딩합니다.

getAttribute(java.lang.String name)


첫번째 파라미터값을 이름으로 참조하는 객체를 반환합니다.
만약 주어진 이름으로 바인된 속성이 없다면 널을 반환합니다.

getAttributeNames()
서블릿컨텍스트에 저장된 속성이름을 Enumeration 타입으로 반환합니다.

웹 애플리케이션과 서블릿컨텍스트의 관계


우리는 이미 <TOMCAT_HOME>/conf/server.xml 파일에 새로운 Context를 추가했습니다. (톰캣 admin 툴을 이용해서).
이 작업을 하면 웹 애플리케이션을 생성한 것입니다.
웹 애플리케이션을 추가함과 동시에 새로운 서블릿컨텍스트를 또한 만든 것입니다.
이것이 웹 애플리케이션과 서블릿컨텍스트의 관계입니다.
모든 웹 애플리케이션마다 단 하나의 서블릿컨텍스트가 있습니다.
이는 서블릿 스펙에 의해 요구되어지고 모든 서블릿엔진에 의해 수행됩니다.

웹 애플리케이션이 웹 애플리케이션 컴포넌트에 어떻게 영향을 미치는지의 예

실제로 서블릿컨텍스트와 웹 애플리케이션과의 관계를 이해하기 위해,
우리는 이미 만든 /bbs 웹 애플리케이션을 외에 /bbs2 라는 웹 애플리케이션을 추가합니다.(톰캣 admin 툴 이용)
그리고 각각의 웹 애플리케이션에 아래와 같은 2개의 웹컴포넌트를 각각 배치합니다.


첫번째 웹 컴포넌트 서블릿

*** ContextText.java ***

 

package example;

import javax.servlet.*;

import javax.servlet.http.*;

import java.io.*;

import java.util.*;

 

public class ContextTest extends HttpServlet{

             private static final String CONTENT_TYPE="text/html;charset=euc-kr";

             public void init() throws ServletException {

             }

             public void doGet(HttpServletRequest request,HttpServletResponse response)

                           throws ServletException,IOException{

 

                           doPost(request,response);

             }

             public void doPost(HttpServletRequest request,HttpServletResponse response)

                           throws ServletException,IOException{

 

                           // ServletContext 레퍼런스를 얻는다.

                           ServletContext context=getServletContext();

                           // ServletContext로부터 count 속성값을 얻기를 시도합니다.

                           Integer count=(Integer)context.getAttribute("count");

                           // 만약 count 속성이 없다면 만든다.

                           // count 속성 초기값은 0 입니다.

                           if(count==null){

                                        count=new Integer(0);

                                        context.setAttribute("count",new Integer(0));

                           }

 

                           response.setContentType(CONTENT_TYPE);

                           PrintWriter out=response.getWriter();

                           out.println("<html>");

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

                           out.println("<body>");

                           // count 속성값의 현재값을 출력합니다.

                           out.println("<p>현재 COUNT 는 : "+count+".</p>");

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

                           // doPost메소드가 불릴때마다 count 속성값을 1씩 증가시킨다.

                           count=new Integer(count.intValue()+1);

                           // ServletContext에 증가한 count 속성을 저장합니다.

                           context.setAttribute("count",count);

             }

             public void destory(){

             }

}

 


코드 설명


1. getServletContext()메소드를 이용해서 ServletContext의 레퍼런스를 얻습니다.


ServletContext context = getServletContext();

2. 서블릿컨텍스트의 레퍼런스를 얻었다면 서블릿컨텍스트로부터 count 속성값을 얻고자 시도합니다.

이때 getAttribute()메소드를 사용합니다.

Integer count = (Integer)context.getAttribute("count");

3. 서블릿컨텍스트에 count라는 속성이 있는지 조사하고 만일 그런 속성이 존재하지 않는다면 만들고 서블릿컨텍스트에 추가합니다.

이때 setAttribute()메소드를 사용합니다.

if( count == null) {
   count = new Integer(0);
   
context.setAttribute("count",new Integer(0));
}

4. 속성이 발견되었다면 이 값을 출력스트림에 씁니다.


out.println("<p>The current COUNT is : " + count + ".</p>");

5. 서블릿컨텍스트의 속성값을 증가시키고 이 값을 서블릿컨텍스트에 추가합니다.

count = new Integer(count.intValue() + 1);

context.setAttribute("count", count);

서블릿을 2개의 웹 애플리케이션에 배치합니다.
위 서블릿 코드를 bbs/WEB-INF/classes와 bbs2/WEB-INF/classes 에 위치시킨후

javac -d . ContextTest.java


라는 명령어로 컴파일하고


http://localhost/bbs/servlet/example.ContextTest

http://localhost/bbs2/servlet/example.ContextTest


를 방문해 확인합니다.

2번째 웹컴포넌트 JSP페이지


파일위치 : /bbs/example/ , /bbs2/example/


***
ContextTest.jsp ***


<%@ page contentType="text/html;charset=euc-kr" %>

<HTML><head><title>ContextTest</title></head><body>

<h1>

<%

             // count 속성을 얻기를 시도합니다.

             Integer count=(Integer)application.getAttribute("count");

             // 만약 count 속성이 null이면 하나 만들어서 서블릿컨텍스트에 저장합니다.

             if(count==null){

                           count=new Integer(0);

                           application.setAttribute("count",count);

             }

%>

 

현재 COUNT 는 : <%=count%>

<%

             // count 속성을 1 증가시켜 서블릿컨텍스트에 새로 저장합니다.

             count=new Integer(count.intValue()+1);

             application.setAttribute("count",count);

%>

</h1>

</body></html>


이 파일을 bbs/example 와 bbs2/example 에 복사합니다.
각각의 분리된 웹 애플리케이션이 어떻게 이들 컴포넌트에 영향을 미치는지 확인합니다.
실험을 시작하기 위해 다음 URL를 방문합니다.

http://localhost/bbs/example/ContextTest.jsp

http://localhost/bbs2/example/ContextTest.jsp



Refresh 버튼을 여러번 누르고 count가 증가되는지 확인합니다.
새로운 브라우저를 열고 서블릿을 방문합니다.

http://localhost/bbs/servlet/example.ContextTest

http://localhost/bbs2/servlet/example.ContextTest



출력결과는 ContextTest.jsp 와 같을 것입니다.
count의 값에 주목합니다.


ContextTest.jsp에서보다 1만큼 증가된 값입니다.
이것은 서블릿과 JSP가 같은 서블릿컨텍스트를 공유하고 있습니다는 의미입니다.
서블릿 컨텍스트의 공유메모리 기능입니다. (공동 저장소 기능)
각각 JSP와 서블릿을 방문함으로써 count 객체가 어떻게 공유되는지 알 수 있습니다.

이제 /bbs2/ContextTest.jsp JSP페이지를 새로운 창으로 방문합니다.
http://localhost/bbs2/example/ContextTest.jsp count의 값이 0인 결과화면을 볼 수 있습니다.
이것이 의미하는 것은 /bbs 웹 애플리케이션이 사용하는 count와 지금의 count는 다르다는 것입니다.
이것이 웹 애플리케이션과 서블릿컨텍스트의 관계입니다.
/bbs2 와 관련이 있는 서블릿 컨텍스트는 이 웹 애플리케이션에 유일합니다.
그리고 다른 웹 애플리케이션 /bbs 안에 있는 웹 컨포넌트에 의해 영향을 받지 않는다는 것입니다.


다시 확인을 위해 /bbs2 의 서블릿을 방문합니다.
http://localhost/bbs2/servlet/example.ContextTest
/bbs2 에 배치된 JSP와 같은 count 레퍼런스를 사용함을 알 수 있습니다

 

JSP 문법에서 꼭 확인해야 할 사항들


1. <%@ page session=true>


Q. page 지시자에서 session 속성은 구체적으로 무엇을 의미하는가?

page 지시자에 session 속성이 false로 되어 있으면 웹 컨테이너에서는 해당 페이지가 session 객체를 생성하지도 못하고 또한 기존의 session 객체에 대한 레퍼런스도 얻을 수도 없습니다.

false로 되어 있는 상태에서 session 객체에 접근하고자 하면 에러가 발생하게 됩니다.

 

2.<jsp:useBean id="name" scope="page|request|session|application"  class=ClassName />


Q. 표준액션의 <jsp:useBean>에서 scope 속성은 무엇을 의미하는가?

scope 속성은 jsp:useBean 속성 중에서 가장 중요한 부분입니다.

일단 이 속성은 자바 빈즈를 객체화시킨 후 어느 범위까지 사용을 할 것인지를 결정하는 것입니다.

Scope 속성으로 지정한 영역의 수명에 따라서 빈 객체는 하나의 페이지가 아니라 여러 페이지에서 소멸하지 않고 참조되기고 합니다.

(예를 들어 scope 속성이 session 으로 설정되었다면 빈 객체는 세션이 종료할 때까지 소멸되지 않고 유지됩니다.)

빈 객체가 생성된 이후 어떤 페이지에서도 참조될 수 없을 때 자동으로 소멸됩니다.

Scope 속성은 기본 값은 page입니다.

scope 속성에는 4개의 값을 지정해 줄 수 있는데 각각의 값에 대해서 정리하면 다음과 같습니다.

 

page : 자바 빈즈가 현재의 JSP 페이지 내에서만 사용 가능하도록 설정할 때

기본 값이므로 특별히 지정하지 않으면 이 옵션이 적용됩니다.

빈 객체의 수명은 한 페이지 내에서만 유지됩니다.

Page 영역으로 생성된 객체는 요청된 페이지 내에서만 유효합니다.

같은 페이지를 요청해도 새로운 빈 객체가 생성됩니다.

페이지의 실행 종료와 함께 빈 객체는 소멸됩니다.

매 페이지마다 새로 생성되므로 객체가 생성자의 초기화 부분을 항상 실행합니다.

Page영역은 한 페이지에서만 유효하므로 <jsp:include> 태그나 <jsp:forward> 태그로 포함된 페이지에서

<jsp:useBean> 태그는 이미 만들어진 빈 객체를 참조하는 것이 아니라 같은 id 속성값을 가진 새로운 객체를 생성하게 됩니다.

또한 <jsp:include> 태그에서 생성한 빈 객체는 원 페이지에서 참조될 수 없습니다.

Page 영역의 빈 객체는 jsp 페이지가 불릴 때마다 먼저 생성된 빈 객체의 상태가 필요하지 않고 새로 생성되어도 되는 경우에 적합하다.

 

request : JSP 페이지는 jsp:forward, jsp:include 태그를 이용해서 다른 JSP 페이지와 함께 사용할 수 있는데 이 값으로 범위를 지정하면 현재의 JSP 페이지와 연결되어 있는 모든 JSP 페이지까지 영향을 미칩니다.

이럴 경우 이 자바 빈즈의 id는 다른 페이지에 동일한 이름의 id가 존재해서는 안됩니다.

반대로 page 속성으로 지정되어 있을 경우에는 현재 페이지에 jsp:forward와 jsp:include가 있을 지라도 해당 페이지까지 영향을 미치지는 않습니다. 즉, 해당 페이지가 원 페이지에서 참조하는 자바 빈즈를 참조하지 못합니다.

또한 request 영역으로 생성된 빈 객체를 request 객체에 저장하여 request 객체에서 찾아서 참조가 가능합니다.

<jsp:include> 태그와 <jsp:forward>태그를 사용하는 경우 같은 request 객체를 사용하게 됩니다.

 

session : 이 값으로 범위를 지정해 놓으면 세션에 유효할 때까지 자바 빈즈의 객체가 유효합니다.

세션이 유지되는 동안 같은 세션에서 호출되는 모든 페이지에서 빈 객체는 소멸되지 않고 유지됩니다.

Session 영역으로 생성된 빈은 session 객체에 저장됩니다.

각 사용자에 대하여 독립적으로 생성되는 session 객체는 세션이 종료될 때까지 호출되는 모든 페이지에서 id 속성으로 구분되는 객체들을 유지하고 사용할 수 있게 해준다.

한가지 주의할 점은 page 지시자에서 session 속성을 false로 해 놓았을 경우에는 이 자바 빈즈 객체는 사용할 수 없게 됩니다.

page,request  scope 속성으로 생성된 빈은 브라우저의 요청에 대하여 결과를 생성하여 돌려준 다음에는 소멸됩니다.

 

application : 이 값은 가장 광범위한 범위를 갖는 값입니다. 이 값으로 범위를 지정하면 모든 JSP 페이지에서 사용할 수 있으며 자바 빈즈 객체는 JSP 엔진을 정지시키거나 다시 시작시킬 때까지 계속 살아 있게 됩니다.

즉, JSP엔진에 의해 소멸되지 않고 유지됩니다.

application scope 속성으로 생성된 빈은 application 내장객체에 저장되어 같은 웹 애플리케이션을 사용하는 모든 사용자에게 사용되어 질 수 있게 됩니다. 이 옵션은 거의 사용되지 않습니다.

 

3. <%@ include file=”상대경로파일명” %> 과 <jsp:include page=”상대경로파일명” /> 의 정확한 차이는?

 

Include 디렉티브의 경우 포함되는 페이지와 현재 jsp 페이지가 합쳐져서 하나의 jsp 페이지(이는 곧 합쳐진 jsp페이지가 서블릿으로 변환됨을 의미)가 되는 반면에 <jsp:include>액션 태그로 포함되는 페이지와 포함하는 페이지가 합쳐지지 않고 그대로 존재하게 됩니다.

<출처:
http://cafe.naver.com/webprogramguide>

+ Recent posts