반응형

바로 JSP로 만든 게시판으로 들어가지는 않겠습니다.


왜냐하면 JSP는 서블릿 기반 기술이기 때문입니다. 서블릿에 대한 기본적인 이해를 한 다음  JSP를 하는 것이 낫다고  생각하기

때문입니다.


JSP가 서블릿 기반 기술이라는 것은 확장자가 jsp인 파일은 톰캣과 같은 서블릿 엔진에 의해 결국은 서블릿으로 변환된 다음에

서비스되기 때문입니다.


서블릿은 CGI 프로그래밍에 대한 자바측 기술로 등장하게 됩니다.

JSP는 마이크로소프트 진영의 ASP가 인기를 끌자 ASP에 대응하기 위한 자바측 기술로 나타납니다.


서블릿 문법


서블릿 아키텍처는
javax.servletjavax.servlet.http 두개의 팩키지로 구성됩니다.

javax.servlet 팩키지는
모든 서블릿이 상속하거나 구현하는 일반적인 인터페이스와 클래스로 구성되어 있습니다.

javax.servlet.http 팩키지는 HTTP 프로토콜에 맞춘 서블릿 클래스로 구성됩니나.

javax.servlet.Servlet 인터페이스는 서블릿 아키텍처의 핵심으로 모든 서블릿의 기초 클래스인 Servlet 인터페이스는

5개의 메소드를 정의합니다.


그 중 가장 중요한 3개의 메소드는 다음과 같다.

init() : 서블릿을 초기화
service() : 클라이언트 요청에 대한 서비스
destory() : 자원반납
이들 메소드는 서블릿 라이프사이클 메소드를 구성합니다.

상속을 통해서든 아니면 직접적인 구현을 통해서 모든 서블릿은 반드시 Servlet 인터페이스를 구현해야 합니다.

서블릿 프레임워크

사용자 삽입 이미지

GenericServlet 과 HttpServlet 클래스서블릿 아키텍처에서 보이는 2개의 중요한 클래스는 GenericServletHttpServlet 클래스입니다.

HttpServlet 클래스는 GenericServlet 클래스를 상속합니다.

GenericServletServlet를 구현한 클래스입니다.

HttpServletGenericServlet는 서블릿을 개발할때 이들 중 하나를 사용합니다.

GenericServlet클래스를 상속하면 service()메소드를 구현해야 합니다.
GenericServlet.service()메소드는 프레임워크를 따르기 위해서 반드시 구현하도록 추상 메소드로 정의됩니다.

GenericServlet.service() 프로토타입

public abstract void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;

 

추상 메소드이므로 프로그래머가 반드시 구현해야 합니다.

service()메소드로 전달되는 2개의 파라미터는 ServletRequest ServletResponse 객체입니다.

ServletRequest 는 서블릿으로 전달되어진 모든 정보를 가지고 있습니다.
ServletResponse 는 클라이언트에게 보내고자 하는 데이터가 위치하는 곳입이다.

HttpServlet 클래스를 확장했을때는, service()메소드를 일반적으로 구현할 필요가 없습니다.
HTTPServlet 클래스는 이미 service()메소드를 구현하고 있기 때문입니다.

HttpServlet.service() 프로토타입


Protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException,IOException;

HttpServlet.service()메소드가 호출되면
이 메소드는 request 안에서 메소드 타입값을 읽어내고 이 값에 따라서 호출할 메소드를 결정합니다.

이 메소드는 우리가 오버라이딩 해야하는 메소드입니다.

메소드 타입이 GET 이면 우리가 오버라이팅 할 메소드는
doGet(),  POST 이면 doPost() 입니다.

service()메소드는 5가지 메소드타입을 가지고 있지만 doGet()과 doPost()만 관심을 가지면 됩니다.

HttpServlet 클래스에 전달되는 파라미터, HttpServletRequest와 HttpServletResponse는
Servlet 클래스에 전달되는 파라미터였던 ServletRequest, ServletResponse 각각을 상속한 클래스입니다.

서블릿의 라이프 사이클
자바서블릿의 라이프사이클은 매우 논리적인 순서를 따르고 있습니다.
라이프사이클 메소드를 선언하고 있는 인터페이스가 javax.servlet.Servlet 인터페이스 입니다.

서블릿 라이프사이클 메소드는 init(), service(), destory() 입니다.

1. init() 메소드를 이용하여 서블릿이 로딩되고 초기화 됩니다.

2. 서블릿이 로딩되면 클라이언트이 요청에 응답을 하는 서비스를 시작하는데 이때 servie() 메소드가 이용됩니다.

3. 서블릿이 shutdown 될때 이용되는 메소드가 destory() 메소드입니다

init()


init() 메소드는 서블릿이 그 일생을 시작하게 하는 메소드입니다.
이 메소드는 서블릿이 인스턴스가 된 후 바로 호출되고, 단 한번만 호출됩니다.
init() 메소드는 request 를 다룰 때 사용하는 자원을 만들고 이 자원을 초기화할때 사용합니다.
init() 메소드의 모습은 다음과 같습니다.

public void init(ServletConfig config) throw ServletException;

init() 메소드는 파라미터로 ServletConfig 객체를 전달받습니다.
init() 메소드는 또한 ServletException을 던질 수 있도록 선언되어 있습니다.

만약 서블릿이 request를 핸들링할 수 있는 자원을 초기화할 수 없게 되었을 때 init() 메소드는 ServletException 을 해당 에러 메시지와 함께 던집니다.

service()


service()메소드는 request/response 패턴을 사용하는 클라이언트로부터 받은 모든 request에 대해 서비스합니다.

service()메소드의 모습은 다음과 같습니다.
public void service( ServletRequest req, ServletResponse res) throws ServletException, IOException;

service()메소드는 2개의 파라미터를 가집니다.
하나는 ServletRequest 객체인데, 클라이언트가 제공한 정보를 담고 있습니다.
다른 하나는 ServletResponse 객체인데, 클라이언트에 보내는 정보를 담고 있습니다.

service() 메소드를 가장 일반적인 구현은 HttpServlet 클래스에서 이루어진다.
HttpServlet 클래스는 GenericSevlet를 상속하므로서 Servlet을 구현합니다.
 
destory()


이 메소드는 서블릿 라이프의 끝을 의미합니다.
웹 애플리케이션이 shutdown 될때, 서블릿의 destory() 메소드가 호출됩니다.
그러면 init() 메소드에 의해 만들어진 모든 자원이 반납됩니다.

destory() 메소드의 모습은 다음과 같습니다.

public void destroy(); 

간단한 서블릿 예제와 설명이제 서블릿이 무엇이고 어떻게 작동하는에 관한 기본적인 이해를 가지게 되었습니다.
간단한 서블릿에 예제를 만들어 보겠습니다.

***
SimpleServlet.java ***


package example;

 

import javax.servlet.*;

import javax.servlet.http.*;

import java.io.*;

import java.util.*;

 

public class SimpleServlet extends HttpServlet{

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

                           doPost(req,res);

             }

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

 

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

                           PrintWriter out=res.getWriter();

 

                           out.println("<html>");

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

                           out.println("<body>");

 

                           //요청한 클라이언트의 IP를 출력합니다.

                           out.println("Your address is " + req.getRemoteAddr() + "\n");

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

                           out.close();

             }

}

 

※ 여기서 주의하여 볼 것은 SimpleServlet가 init() 과 destory()메소드를 구현하고 있지 않는다는 것입니다.
이들 메소드는 GenericServlet 이 기본적으로 두개의 메소드를 구현하고 있기에 구현하지 않아도 되는 것이죠

SimpleServlet을 컴파일, 실행

0. http://www.okjsp.pe.kr 에서 Frequently Asked Question 의 서블릿 접근이 안되는 경우에서 web.xml 파일을

{TOMCAT_HOME}/conf 에 복사합니다. (그전에 기존의 web.xml 파일은 백업을 하는 것이 좋겠습니다)
1. servlet.jar를 CLASSPATH에 추가시킵니다.
2. SimpleServlet 컴파일합니다. 
javac –d . SimpleServlet.java
3. http://localhost:8080/bbs/servlet/example.SimpleServlet 를 방문해서 결과를 확인합니다.

<결과 화면>

사용자 삽입 이미지

※ 전 글에서 아파치와 연동을 위한 작업을 했기 때문에 localhost 다음에 포트 번호가 빠져도 실행이 됩니다.

SimpleServlet에 접근하기 위한 URL에 /servlet 이 포함되어 있어야 합니다.
이렇게 하므로써 컨테이너에게 서블릿을 찾고 있음을 알리게 됩니다.

SimpleServlet 코드 설명


SimpleServlet 에서 doGet()과 doPost()
이 두 메소드는 SimpleServlet 에서 오버라이드한 메소드입니다.
모든 비즈니스 로직이 이곳에 존재합니다.
예제에서 doGet() 메소드는 단순히 doPost() 메소드를 호출합니다.

doPost() 의 첫번째 실행라인

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

이는 response에 대한 컨텐츠타입을 셋팅하는 작업입니다.
이것은 단 한번만 사용이 가능합니다.
또한 OutputStream으로서 PrintWriter를 코딩하기에 앞서 위 코딩 작업이 이루어져야 합니다.

다음은 PrintWriter 을 획득해야 합니다.

왜냐하면 클라이언트의 웹 브라우저에 IP를 나타내기 위해서 입니다.
PrintWriter 의 획득은 ServletResponse 의 getWriter() 을 호출함으로써 이루어집니다.

PrintWriter out = res.getWriter();

PrintWrtier는 클라이언트 응답에 보내지는 스트림에 글을 쓸 수 있게 합니다.
그러면 클라이언트의 브라우저에서 이 글을 볼 수 있게 됩니다.

클라이언트에 텍스트를 보낼 수 있는 객체에 대한 레퍼런스(out)를 얻었으므로,
이 객체를 사용하여 클라이언트에게 메시지를 전달할 수 있는 것입니다.

이 메시지는 HTML를 포함하고 있습니다.
이는 메시지가 클라이언트의 웹브라우저에 보이게 하기 위함입니다.
다음 몇 라인은 이것이 어떻게 행해지는지 보여준다.

out.println("<html>");
out.println("<head><title>Simple Servlet</title></head>");
out.println("<body>");

//요청한 클라이언트의 IP를 출력합니다.
out.println("Your address is " + req.getRemoteAddr() + "\n");

위에서 보듯이 SimpleServlet는 클라이언트에게 HTML을 보내기 위해 PrintWriter의 println()메소드를 사용하고 있습니다.

//요청한 클라이언트의 IP를 출력합니다.

out.println("Your address is " + req.getRemoteAddr() + "\n");


req.getRemoteAddr() 부분은 클라이언트에서 보내온 정보를 이용합니다.
즉, HttpServletRequest 의 getRemoteAddr() 메소드를 호출하여 클라이언트의 주소를 반환받고 있습니다.
이렇게, HttpServeltRequest 는 클라이언트가 보내거나, 클라이언트에 관한 정보를 담고 있습니다.

HttpServletRequest와 HttpServletResponse 객체에 관한 자세한 정보는 썬의 웹사이트에서 찾을 수 있습니다.


http://java.sun.com/products/servlet/

다음은 기본적으로 한번은 읽어 봐야 할 서블릿 클래스와 그의 메소드를 정리해 놓은 것입니다.

하나 하나 다 설명은 없지만 서블릿 API를 통해서 한번쯤은 읽고 넘어간다면 웬만한 JSP에 관한 책은 모두 이 범위 안에 있기에 이해가 쉬울 것입니다.

 

서블릿 클래스 요약

 

Servlet

init()

service()

destroy()

getServletConfig()

getServletInfo()

 

ServletConfig

getInitParameter()

getInitParameterNames()

getServletContext()

 

GenericServlet

log()

 

HttpServlet

doGet()

doPost()

 

ServletContext

setAttribute()

getAttribute()

getRequestDispatcher()

getRealPath()

getResource()

 

RequestDispatcher

forward()

include()

 

ServletRequest

getInputStream()

getParameter()

getParameterValues()

 

HttpServletRequest

getCookie()

getSession()

getSession(boolean created)

 

ServletResponse

getOutputStream()

getWriter()

 

HttpServletResponse

addCookie()

sendRedirect()

 

Servlet API Spec 은 다음 사이트에서 다운로드 받을 수 있습니다.

http://java.sun.com/products/servlet

 

서블릿 연습하기

 

Hello Servlet ! : HelloServlet.java

 

package example;

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

 

public class HelloServlet extends HttpServlet {

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

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

                           PrintWriter out=res.getWriter();

                           out.println("<HTML>");

                           out.println("<HEAD><TITLE>Hello Servlet</TITLE></HEAD>");

                           out.println("<BODY>");

                           out.println("Hello Servlet!");

                           out.println("</BODY>");

                           out.println("</HTML>");

                           out.close();

             }

}

 

<설명>

1.HttpServlet 클래스를 상속받은 서블릿 클래스는 public class 로 선언해야 합니다.

 

2.HTTP 의 GET 방식으로 웹 브라우저가 요청해오면 doGet() 메소드를 작성합니다.

(일반적으로 웹서버의 자원을 요청하는 것은 GET 방식의 요청입니다.)

 

3.doGet() 메소드는 HttpServletRequest 와 HttpServletResponse 타입의 아규먼트를 가집니다.

이 메소드는 예외가 발생할 수 있으므로 다음 문장으로 예외를 처리합니다.

throws ServletException, IOExcepiton

 

4. res.setContentType(“text/html;charset=euc-kr”);

은 웹브라우저에 응답으로 출력될 문서의 MIME 타입을 기술합니다.

;charset=euc-kr을 쓰지 않으면 한글이 깨지는 경우가 발생합니다.

setContentType()메소드는 HttpServletResponse 의 메소드입니다.

 

5. PrintWriter out = res.getWriter();

웹브라우저에 대한 출력 스트림을 얻습니다.

out의 plintln() 메소드안에 문자열을 넣으면 그대로 흘러 흘러서 클라이언트의 웹브라우저에 출력된다고 생각하시면 됩니다.

 

6. 주소창에서 /bbs/servlet/ 는 /bbs/WEB-INF/classes 로 접근하기 위한 일종의 약속입니다.

 

7. HelloServlet 서블릿이 어떻게 작동하는가?

클라이언트, 즉 웹브라우저가 서버의 HelloSerlvet 서블릿 자원을 요청합니다.

서블릿엔진인 톰캣은 클라이언트의 요청을 캡슐화한 HttpSerlvetRequest 인터페이스를 구현한 객체와

요청에 대한 응답을 캡슐화한 HttpSerlvetResponse 인터페이스를 구현한 객체를 service(,) 메소드의 아규먼트로 넘깁니다.

HttpServlet은 GenericServlet 의 추상 sevice(,)메소드를 구현한 클래스입니다.

구현내용은 단지 웹브라우저가 헤더로 보낸 HTTP 메소드(GET,POST)에 따라 자동적으로 doGet(,) 또는 doPost(,)메소드를 호출하도록 하는 것이 전부입니다.

(따라서 doGet(,)이나 doPost(,)를 생각하지 않으려면 service(,)메소드를 오버라이딩하면 됩니다.)

객체로 된 HelloServlet 서블릿은 클라이언트의 각각의 요청을 개발자가 구현한 doGet(,), doPost(,) 혹은 service(,) 메소드가 병행적으로 처리하므로써 클라이언트의 요청에 응답하게 됩니다.

 

"Hello Servlet" 을 출력하는 기본적인 예제를 실행해 봤습니다.

이제는 웹브라우저, 즉 클라이언트가 보내는 정보를 어떻게 서블릿에서 다룰 수 있는지 알아봅니다.

정확하게 클라이언트가 보내는 문자열 정보를 서블릿에서 catch하는 코드를 설명합니다.

 

웹 브라우저가 서버에 문자열을 전송하는 방법

HTML FORM 태그를 이용하여 웹브라우저가 서버로 문자열 데이터를 전달하는 방법과 서블릿에서 그 정보를 받는 코드조각은

다음과 같습니다.

                                               è

HTML

서블릿

<input type=text name=addr>

req.getParameter(“addr”);

<input type=radio name=os value=win98>

<input type=radio name=os value=win2000>

req.getParameter(“os”);

<input type=hidden name=cur_page value=1>

req.getParameter(“cur_page”);

<input type=password name=passwd>

req.getParamter(“passwd”);

<input type=checkbox name=hw value=intel>

<input type=checkbox name=hw value=amd>

….

req.getParameterValues(“hw”);

<select name=os multiple>

<option value=”windows”>windows</option>

<option value=”linux”>linux</option>

<option value=”solaris”>solaris</option>

</select>

req.getParameterValues(“os”);

(참고: multiple 속성이 없다면

req.getParameter(“os”)도 가능)

 

위의 내용을 하나 하나 예로 들어 설명합니다.

 

GetData.html / GetData.java

 

HTML FORM 태그의 텍스트필드를 이용한 문자열 전송

 

파일 위치 : /bbs/example/GetData.html , /bbs/WEB-INF/classes/GetData.java

*** GetData.html ***

 

<html><body>

<center><h1>GET 테스트</h1></center>

<form method=POST action=../servlet/example.GetData>

이름 : <input type=text name=name size=20><br>

주소 : <input type=text name=addr size=20><br>

<input type=submit value="전송"><input type=reset value="취소">

</form>

</body></html>

 

*** GetData.java ***

 

package example;

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

 

public class GetData extends HttpServlet {

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

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

                  PrintWriter out = res.getWriter();

                  req.setCharacterEncoding("euc-kr");

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

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

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

                  out.println("<center><h2>GET TEST</h2></center>");

                  out.println("<li>이름 : "+name);

                  out.println("<li>주소 : "+addr+"<br>");

                  String path = req.getContextPath();

                  out.println("<a href="+path+"/example/GetData.html>뒤로</a>");

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

                  out.close();

         }

}

 

<설명>

 

1. HTML문서와 서블릿간의 상대경로에 주의합니다.

HTML이나 JSP에서 서블릿을 링크할때는 /servlet/을 컨텍스트 루트처럼 생각하고 상대경로를 걸면 해결됩니다.

하지만 서블릿 코드에서 HTML문서나 JSP문서에 링크를 걸때는 req.getContextPath() 메소드를 통해 풀패스를 얻어서 경로를 걸어야 확실합니다.

 

2. 서블릿 소스에 package 가 선언되어 있다면 그 서블릿은 팩키지명.서블릿클래스명 으로 접근합니다.

 

3. HttpServletRequest 의 setCharacterEncoding(“euc-kr”)은 웹브라우저,즉 클라이언트가 보내는 한글 데이터를 한글 인코딩으로 받기 위한 것입니다.

이 코드조각이 없다면 클라이언트가 보낸 한글 데이터는 깨질 것입니다.

반면 HttpServletResponse.setContentType() 메소드는 서블릿이 만드는 HTML문서의 타입과 문자셋을 지정하는 것입니다.

혼동하지 말기 바랍니다.

 

4. HttpServletRequest 의 getParameter() 메소드는 가장 보편적으로 웹브라우저에서 사용자가 보내는 데이터를 받기 위한 메소드입니다.

 

6. 상대경로 문제

JSP 나 HTML 문서에서 서블릿을 링크시킬때는 /bbs/servlet/까지를 Context Base 라고 생각하고 일반적인 상대경로 개념으로 접근합니다.

서블릿에서 JSP 나 HTML문서를 링크시킬때는

req.getContextPath() 로 일단 Context base 경로를 구한후에 이를 이용해 경로를 링크시키면 됩니다.

 

톰캣4.1.30 버전에서 테스트 할 때는 GET 방식으로 클라이언트가 보낸 한글 이름과 주소가 정상적으로 출력이 되었으나 5.0.28 에서 테스트 할 때에는 한글이 깨져서 나옵니다.

근본적인 해결책은 아직 못찾아보았고, 대신 GET방식이 아닌 POST 방식으로만 서버에 정보를 보내도록 프로그래밍하면 되겠습니다.

GET 방식으로도 html form 에 입력한 한글을 정상적으로 출력하도록 하는 근본적인 해결책은 찾으시면 제게도 알려주시면 감사하겠습니다.

 

MultiCheck.html / MultiCheck.java

 

HTML FORM 태그의 체크박스를 이용한 문자열 전송

 

파일 위치 : /bbs/example/MultiCheck.html , /bbs/WEB-INF/classes/MultiCheck.java

 

*** MultiCheck.html ***

 

<html><body>

<center><h2>체크박스 다중 선택 테스트</h2></center>

<form method=POST action="../servlet/example.MultiCheck"><br>

다음중 사용중인 소프트웨어를 선택해 주세요<br>

<input type=checkbox name=sw value="jdk1.4">jdk1.4<br>

<input type=checkbox name=sw value="한글">한글<br>

<input type=checkbox name=sw value="MS오피스">MS오피스<br>

<input type=submit value="전송">

<input type=reset value="취소">

</form>

</body></html>

 

*** MultiCheck.java ***

 

package example;

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

 

public class MultiCheck extends HttpServlet {

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

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

                  PrintWriter out = res.getWriter();

                  req.setCharacterEncoding("euc-kr");

                  String[] values = req.getParameterValues("sw");

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

                  out.println("선택한 사용중의 소프트웨어는 아래와 같습니다.");

                  if(values!=null){

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

                                   out.print("<li>");

                                   out.print(values[i]);

                                   out.println("<br>");

                           }

                  }

         }

}

 

<설명>

 

1. 웹브라우저를 통해 사용자가 다중선택을 하여 전송하는 데이터의 경우는 HttpServletRequet 의

getParamter() 메소드가 아닌 getParamterValues() 메소드가 쓰입니다.

이 메소드의 리턴값은 사용자가 선택한 값들만으로 구성된 String 배열입니다.

 

SelectItems.html / SelectItems.java

 

HTML FORM 태그의 Select 태그를 이용한 문자열 전송

 

파일 위치 : /bbs/chapter3/SelectItems.html , /bbs/WEB-INF/classes/SelectItems.java

 

*** SelectItems.html ***

 

<HTML><BODY>

<center><h2>SELECT 테스트</h2></center>

<form method=POST action=../servlet/example.SelectItems>

개발환경 운영 체제는?<br>

<select name=os size=3 multiple>

         <option value="윈도우">윈도우</option>

         <option value="리눅스">리눅스</option>

         <option value="솔라리스">솔라리스</option>

         <option value="기타">기타</option>

</select>

<br><br>

사용중인 초고속통신망은?<br>

<select name="초고속통신서비스" multiple>

         <option value="매가패스">매가패스</option>

         <option value="하나포스">하나포스</option>

         <option value="두루넷">두루넷</option>

         <option value="기타">기타</option>

</select>

<input type=submit value="전송">

<input type=reset value="취소">

</form></BODY></HTML>

 

*** SelectItems.java ***

 

package example;

import java.io.*;

import java.util.*;

import javax.servlet.*;

import javax.servlet.http.*;

public class SelectItems extends HttpServlet {

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

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

                  PrintWriter out = res.getWriter();

                  req.setCharacterEncoding("euc-kr");

                  Enumeration e = req.getParameterNames();

                  while(e.hasMoreElements()){

                           String name = (String)e.nextElement();

                           String values[] = req.getParameterValues(name);

                           if(values!=null){

                                   out.println("<li>");

                                   out.println(name + "중 아래 항목을 선택하셨습니다.<br>");

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

                                            out.println(values[i]);

                                            out.println("|");

                                   }

                           }

                           out.println("<br>");

                  }

                  String path = req.getContextPath();

                  out.println("<a href=" + path + "/example/SelectItems.html>뒤로</a>");

         }

}

 

<설명>

 

만약 사용자가 어떤 파라미터명으로 데이터를 보내는지 알수 없다고 가정을 합니다(그럴 경우는 거의 없지만)

이때 사용자가 보내는 파라미터명을 알 수 있는 메소드가 HttpServletRequest getParamterNames()입니다.

getParameterNames() 메소드는 리턴값으로 Enumeration 타입을 반환합니다.

(Enumeration 은 hasMoreElements() , nextElement() 2개의 메소드를 이용할 줄 알면 됩니다.)

 

MultiItems.html / MultiItems.java

 

HTML FORM 태그의 라디오버튼을  이용한 문자열 전송

 

파일 위치 : /bbs/chapter3/MultiItems.html, /bbs/WEB-INF/classes/MultiItems.java

 

*** MultiItems.html ***

 

<HTML><BODY>

<center><h2>라디오 버튼 테스트</h2></center>

<form method=POST action=../servlet/example.MultiItems>

다음 사항을 선택해 주세요<br>

사용중인 운영체제는?<br>

<input type=radio name=os value="windowsXP">windowsXP<br>

<input type=radio name=os value="windowsMe">windowMe<br>

<input type=radio name=os value="window98">windows98<br>

<input type=radio name=os value="redhat90">redhat90<br>

사용중인 컴퓨터 하드웨어는?<br>

<input type=radio name=hw value="intel">intel<br>

<input type=radio name=hw value="amd">amd<br>

<input type=radio name=hw value="기타">기타<br>

사용중인 초고속통신회사는?<br>

<input type=radio name="telecom" value="매가패스">매가패스<br>

<input type=radio name="telecom" value="하나포스">하나포스<br>

<input type=radio name="telecom" value="두루넷">두루넷<br>

<input type=submit value="전송">

<input type=reset value="취소">

</form></BODY></HTML>

 

*** MultiItems.java ***

 

package example;

import java.io.*;

import java.util.*;

import javax.servlet.*;

import javax.servlet.http.*;

 

public class MultiItems extends HttpServlet{

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

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

                  PrintWriter out = res.getWriter();

                  req.setCharacterEncoding("euc-kr");

                  Enumeration e = req.getParameterNames();

                  while(e.hasMoreElements()){

                           String name=(String)e.nextElement();

                           String value=req.getParameter(name);

                           out.println("<li>");

                           out.println(name + "|");

                           out.println(value);

                           out.println("<br>");

                  }

         }

}

 

 

RequestDispatcher 사용 예제

 

파일 위치 : /bbs/WEB-INF/classes/IncludingServlet.java , /bbs/WEB-INF/classes/In.java

 

*** IncludingServlet.java ***

 

package example;

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

public class IncludingServlet extends HttpServlet {

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

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

                           PrintWriter out = res.getWriter();

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

                           out.println("<center><h2>Including Servlet</h2></center>");

                           out.println("다음 내용은 다른 서블릿의 내용을 inlcude한 것입니다<hr>");

                           ServletContext sc = getServletContext();

                           RequestDispatcher rd= sc.getRequestDispatcher("/servlet/example.In");

                           rd.include(req,res);

                           out.println("<hr>이곳은 다시 IncludingServlet 입니다.");

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

             }

}

 

*** In.java ***

 

package example;

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

public class In extends HttpServlet {

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

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

                           PrintWriter out = res.getWriter();

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

                           out.println("IN 서블릿입니다.");

             }

}

 

ServletConfig 의 getInitParameter() 사용 예제

 

파일 위치 : /bbs/WEB-INF/classes/InitParam.java

 

*** InitParam.java ***

 

package example;

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

 

public class InitParam extends HttpServlet {

             String file;

             long  counter;

             public void init() throws ServletException {

                           ServletContext cxt = getServletContext();

                           file = getInitParameter("file");

                           if(file != null) {

                                        try {

                                                     file = cxt.getRealPath(file);

                                                     DataInputStream in = new

                                                                  DataInputStream(new FileInputStream(file));

                                                     counter = in.readLong();

                                                     in.close();

                                        } catch (Exception e) { }

                           }

             }

             public void service(HttpServletRequest req,

             HttpServletResponse res) throws IOException, ServletException {

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

                           PrintWriter out = res.getWriter();

                           out.println("<html><head><title>방문자 수</title></head>");

                           out.println("<body> <center><h2>방문자 수</h2>");

                           out.println("</center><hr>");

                           out.print("file = " + file + "<br>");

                           counter++;

                           out.print(counter);

                           out.println(" 번째 손님입니다.");

             }

public void destroy() {

                           if(file != null) {

                                        try {

                                                     DataOutputStream out = new

                                                                  DataOutputStream(new FileOutputStream(file));

                                                     out.writeLong(counter);

                                                     out.close();

                                        } catch(Exception e) {

                                                     System.out.println(e);

                                        }

                           }           

             }

}

 

위 파일을 실행하기에 앞서 /bbs/WEB-INF/web.xml 파일을 아래를 추가합니다.

<servlet>

        <servlet-name>example.InitParam</servlet-name>

        <servlet-class>example.InitParam</servlet-class>

        <init-param>

               <param-name>file</param-name>

               <param-value>counter.dat</param-value>

        </init-param>

</servlet>

 

(전체 내용에 대해서는 제가 여기까지 설정한 /bbs/WEB-INF/web.xml 파일을 올립니다 첨부파일을 참고하세요)

 

그런 다음 counter.dat 란 파일을 /bbs 에 생성합니다.

다음으로 톰캣을 재시동합니다.

어느정도 InitParam 서블릿을 실행한 다음 InitParam 서블릿을 강제로 내리기 위해서 톰캣을 재시동합니다.

그런 다음 다시 InitParam 서블릿을 요청하여 방문횟수가 저장되었는지 확인합니다.

 

http://localhost/bbs/servlet/InitParam

 

 

서버에서 클라이언트로 이미지 전송시키는데 이용하는 메소드 소개

res.setContentType(“image/gif”); // jpg 이미지는 (“image/jpeg”)

ServletOutputStream out = res.getOutputStream(); // 바이너리 데이터 전송이므로

 

서버에서 클라이언트로 MS오피스 타입의 자료 전송하는데 이용하는 메소드 소개

엑셀의 경우 : res.setContentType(“application/vnd.ms-excel;charset=euc-kr”);

워드의 경우 : res.setContentType(“application/vnd.msword;charset=euc-kr”);

 

파일 업로드을 위한 MultipartRequest 팩키지 사용 방법

MultipartRequest 팩키지는 썬에서 만든 표준 라이브러리가 아니지만 현재 파일 업로드에 널리 이용되고 있는 팩키지입니다.

(파일로 첨부합니다)

 

MultipartRequest 클래스의 생성자 소개

MultipartRequest(HttpServletRequest req, String dir)

dir 디렉토리에 파일을 업로드할 MultipartRequest 객체 생성

MultipartRequest(HttpServletRequest req, String dir, int max)

아규먼트의 max는 업로드 가능한 파일의 최대크기를 나타낸다.

MultipartRequest(HttpServletRequest req, String dir, int max, boolean overwrite, boolean save)

아규먼트의 overwrite는 파일시스템에 동일한 파일이 있으면 덮어쓰는가 여부를 나타낸다.

아규먼트의 save는 파일시스템에 저장하는지 여부를 나타낸다.

 

MultipartRequest 메소드 소개

<input type=file name=pic01> ç 파일찾기로 images.gif 를 업로드했다고 가정하면,

서버에서 MultipartRequest를 사용했다면 아래 메소드를 이용할 수 있습니다.

 

getContentType(“pic01”) : 업로드된 파일의 MIME 타입 리턴 (image/gif)

getFile(“pic01”) : 업로드되어 서버에 저장된 File 객체 리턴

getFileNames() : 업로드된 모든 파일들의 이름을 리턴 (여기서는 Enumeration 에 pic01 저장)

getFilesystemName(“pic01”) : 파일의 파일시스템 이름을 리턴 (images.gif)

 

HttpServletRequest 와 같은 인터페이스 제공하기 위한 메소드를 제공합니다.

getParameter()

getParameterNames()

getParameterValues()

 

MultipartRequest 를 이용한 파일 업로드 예제

파일위치 : /bbs/example/upload.html , /bbs/WEB-INF/classes/UploadTest.java

 

*** upload.html ***

 

<HTML><BODY>

<center><h2>파일 업로드</h2></center>

<form action=../servlet/example.UploadTest method=POST ENCTYPE=multipart/form-data>

이름 : <input type=text name=submitter><br>

업로드할 파일 : <input type=file name=file1><br>

업로드할 파일 : <input type=file name=file2><br>

<input type=submit value="전송">

</form>

</BODY></HTML>

 

*** UploadTest.java ***

 

package example;

import java.io.*;

import java.util.*;

import javax.servlet.*;

import javax.servlet.http.*;

import com.oreilly.servlet.MultipartRequest;

public class UploadTest extends HttpServlet {

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

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

                  PrintWriter out = res.getWriter();

                  req.setCharacterEncoding("euc-kr");

                  ServletContext cxt = getServletContext();

                  String dir = cxt.getRealPath("tmp");

                  try{

                           MultipartRequest multi = new MultipartRequest(req,dir,5*1024*1024);

                           out.println("<html>");

                           out.println("<head><title>파일 업로드</title></head>");

                           out.println("<body>");

                           out.println("<h2>파일 업로드</h2>");

                           out.println("<h3>Params</h3>");

                           out.println("<pre>");

                           Enumeration params = multi.getParameterNames();

                           while(params.hasMoreElements()){

                                   String name=(String)params.nextElement();

                                   String value=multi.getParameter(name);

                                   out.println(name+"="+value);

                           }

                           out.println("</pre>");

                           out.println("<h3>업로드된 파일</h3>");

                           out.println("</pre>");

                           Enumeration files=multi.getFileNames();

                           while(files.hasMoreElements()){

                                   String name=(String)files.nextElement();

                                   String filename=multi.getFilesystemName(name);

                                   String type=multi.getContentType(name);

                                   File f=multi.getFile(name);

                                   out.println("파라메터 이름 : "  + name + "<br>");

                                   out.println("파일 이름 : " + filename + "<br>");

                                   out.println("파일 타입 : " + type + "<br>");

                                   if(f!=null){

                                            out.println("크기: " + f.length() + "<br>");

                                            out.println("<br>");

                                   }

                           }

                           out.println("</pre>");

                  }catch(Exception e){

                           out.println("<pre>");

                           e.printStackTrace(out);

                           out.println("</pre>");

                  }

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

         }

}

 

<설명>

 

1. 테스트는 /bbs/tmp 라는 디렉토리를 만듭니다.

2. 컴파일을 위해 cos.jar 파일을 CLASSPATH에 추가하고 컴파일합니다.

3. cos.jar 파일을 /bbs/WEB-INF/lib 아래 복사 후 톰캣 재가동합니다.

 

2 단계에서 컴파일이 안된다고요?

cos.jar 파일안의 MultiparFormRequest 팩키지에 대한 클래스 패스가 잡히지 않아서입니다.

cos.jar 파일의 클래스 패스를 잡아줍니다.

클래스 패스를 잡기 위해서는 cos.jar 파일을 적당한 위치에 복사한다음 그 경로를 CLASSPATH 에 추가하면 됩니다.

jar 파일이므로 cos.jar 라는 이름까지 추가하셔야 합니다.

제 경우는 F:\javaschool_lib 라는 폴더를 만들고 그 아래에 cos.jar 파일을 복사했습니다.

그리고 F:\javaschool_lib\cos.jar 라는 경로를 CLASSPATH에 추가한다음 컴파일을 했습니다.

 

모두 잘 한것 같은데 파일 업로드를 시도하니 HTTP Status 500 - 에러가 나온다고요?

에러 메시지를 잘 보시면

 

java.lang.NoClassDefFoundError: javax/activation/DataSource

 

위와 같은 메시지가 있습니다. 여기서 힌트를 얻어서 해결책을 찾아보면 ...

JavaBeans(TM) Activation Framework 라는 팩키지가 필요한데 이것에 대한 팩키지는 j2sdk에 들어있지 않습니다.

따라서 http://java.sun.com 에 방문해서 jaf라는 이름으로 검색해서 팩키지를 다운로드 받아야 합니다.

그리고 이 파일을 {JAVA_HOME}/jre/lib/ext 폴더에 복사합니다.

그런 다음 톰캣을 재가동한 후 다운로드를 다시 시도합니다.

꼭 필요한 것 같으나 j2sdk에 포함되지 않은 팩키지가 이것 말고 javamail 팩키지 입니다.

메일과 관련된 프로그램을 위해서도 이 팩키지를 다운로드 받고 압축을 풀고 mai.jar 파일을

{JAVA_HOME}/jre/lib/ext 폴더에 복사하도록 합니다.

 

에러가 없다면 /bbs/tmp 폴더로 가서 확인합니다.

파일명이 바뀌었습니다.

이 팩키지는 MultipartRequest 원본이 아니고 최종명씨가 저자인 "웹 프로그래머를 위한 서블릿/JSP" 란 책에 첨부된 팩키지입니다.

아마도 파일명이 절대로 같게 하지 않게 소스를 변경해서 컴파일한 후 배포한 것으로 생각합니다.

(파일명 뒤에 시스템의 시간이 붙는 것 같습니다)

cos.jar 팩키지에는 소스가 없습니다.

따라서 이것이 마음에 들지 않다면 MultipartRequest 팩키지를 이용하기 위해서는 다른 곳에서 구해야 합니다.

(저는 개인적으로 이게 더 좋습니다.)

 

쿠키

 

HTTP 전송방식의 특징상 각각의 웹 브라우저가 서버와 통신에서 세션을 유지하지 못하는 것을 보완하기 위한 기술입니다.

서버가 쿠키를 전송하면 웹 브라우저는 그 다음 요청마다 쿠키 값이 서버로 전달하여 사용자 정보를 유지할 수 있게 됩니다.

(쇼핑몰의 장바구니, 회원로그인이 필요한 웹 사이트에 쓰임)

 

서버 à 웹 브라우저 (쿠키를 굽는다고 표현되는데 아래와 같은 정보가 클라이언트의 웹 브라우저로 날아가서 셋팅합니다)

 

Set-Cookie : name = value ; expires = date ; path = path ; domain = domain ; secure

 

웹 브라우저 à 서버 (쿠키가 웹브라우저에 셋팅되면 그 다음부터의 요청시마다 웹 브라우저는 아래와 같은 문자열을 쿠키를 준 서버로 보내게 됩니다. 단 쿠키를 구어준 서버가 아니면 이런 정보를 보내지 않습니다)

 

Cookie ; name = value1 ; name2 = value2 ; …

 

쿠키값이 이름과 값으로 얼마든지 만들 수 있는 것은 아닙니다.

 

쿠키 설정 절차

 

1. Cookie 객체를 만든다. Cookie(String name, String value) 이때 value에 해당하는 값을 인코딩

2. 쿠키에 속성을 부여 : setValue(),setDomain(),setMaxAge(),setPath(),setSecure()

3. 쿠키를 전송 : res.addCookie(cookie);

 

서블릿에서 쿠키 이용

...

Cookie[] cookie = req.getCookie();

String name = cookie[i].getName();

If(name.equals(“id”){

        

}

...

 

String value = cookie[I].getValue();

 

서블릿에서 쿠키 삭제

 

삭제하고자 하는 쿠키와 같은 이름의 쿠키를 생성하고 setMaxAge(0) 을 호출합니다.

...

Cookie name = new Cookie(“name”,””);

name.setMaxAge(0);

res.addCookie(name);

...

 

세션

 

세션은 쿠키 기반 기술로 쿠키의 보안상 약점을 극복하기 위한 기술입니다.

쿠키와 다른 점(즉, 보안상 개선된 점) : 웹브라우저는 서버가 정해준 세션ID만을 쿠키값으로 저장합니다.

세션이 생성되면(즉, 세션ID 쿠키가 구워지면) 세션ID 쿠키만을 서버로 전송하게 되고,

서버에서는 세션ID로 해당 HttpSession 객체를 호출하게 되어(이 작업을 서블릿 컨테이너가 해야 함)

웹브라우저와 세션과의 통신이 이루지게 됩니다.

 

HttpSession 의 메소드 소개

 

setAttribute(String name , Object value)

getAttribute(String name)

removeAttribute(String name)

invalidate();

 

사용법

세션 생성 : HttpSession session = req.getSession(true); //true 일때 세션이 없으면  생성합니다.

HttpSession session = req.getSession(false); // false 일때 세션이 없다면 null 을 리턴

세션에 정보 저장 : session.setAttribue(“data”,value); //data 이름으로 value 객체 저장

 

File 클래스

 

자바에서는 파일을 표현하기 위해 File 클래스를 사용합니다.

디렉토리도 File 클래스로 표현됩니다.

주의할 것은 File 클래스는 파일을 읽거나 쓰는 메소드는 가지고 있지 않습니다.

파일을 읽거나 쓰기 위해서는 입출력 클래스를 사용합니다.

 

File 클래스로 할 수 있는 작업

 

디렉토리 내용을 알아본다.

파일의 속성을 알아보거나 설정합니다.

파일의 이름을 변경하거나 삭제합니다.

 

File 클래스 생성

객체 생성 : File dir = new File(path);

주의) 여기서 path 에 해당하는 파일이나 디렉토리는 시스템의 풀패스가 되어야 한다는 것입니다.

 

File 클래스 중요 메소드 소개와 사용법

 

isDirectory()  : dir.isDirectory(); // dir 이 디렉토리이면 true 리턴

isFile() : dir.isFile(); // dir 이 파일이면 true 리턴

list() : dir.list() : // dir 이 디렉토리일 때 디렉토리에 있는 파일명이 String[] 값으로 리턴

listFiles() : dir.listFiles(); // 디렉토리에 있는 파일의 파일 객체 배열 리턴

mkdir() : dir.mkdir(); //  File객체의 이름을 가진 디렉토리를 만든다

getName() : 파일명을 리턴

getPath() : 경로를 리턴

delete() : 파일을 지운다.

exists() : 파일이 존재하는지 여부를 알려준다.

 

이것으로 아주 간단하게 서블릿 문법을 살펴보았습니다.

서블릿에 대한 이해가 있어야 JSP 할때에 이해가 쉽습니다.

그리고 성능향상을 위해서 JSP 프로젝트에서 서블릿이 종종 쓰입니다.

 

그럼 다음은 JSP 문법으로 넘어갑니다.

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

반응형

목차

가. JDBC 프로그래밍 환경 셋업
나. JDBC 프로그래밍 방법

가. JDBC 프로그래밍 환경 셋업

(1) 데이터베이스에 맞는 JDBC 드라이버를 구합니다.
Oracle용 JDBC Thin 드라이버는 오라클을 설치하면 [ORACLE_HOME]/jdbc 디렉토리에 자동으로 설치가 됩니다.

보통은 이 파일을 그대로 쓰시면 됩니다.

더 자세한 사항은 http://www.oracle.com/technology/global/kr/index.html 에서 찾으시기 바랍니다.

(2)[ORACLE_HOME]/jdbc 디렉토리에 있는 다음 파일을 CLASSPATH에 추가합니다.

classes12.jar , nls_charset12.jar 파일의 경로를 CLASSPATH에 추가합니다(현재는 . 만 되어 있습니다.)

예).;C:\oracle\product\10.1.0\db_1\jdbc\lib\classes12.jar;C:\oracle\product\10.1.0\db_1\jdbc\lib\nls_charset12.jar

다음에 명령 프롬프트를 새로 띄우고 set classpath 입력합니다.

CLASSPATH가 제대로 잡혔는지 확인합니다.


(3) GetEmp.java 파일로 JDBC 연동 테스트

파일명: GetEmp.java

import java.sql.*;


public class GetEmp {
    public static void main(String[] args) {
        // 위 부분은 설치과정에서 자신이 정한 정보에 맞게 바꾼다.
        String DB_URL = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
        String DB_USER = "scott";
        String DB_PASSWORD = "tiger";
        Connection conn;
        Statement stmt;
        ResultSet rs;
        String query = "select * from emp";

        try {
            // 드라이버를 로딩한다.
            Class.forName("oracle.jdbc.driver.OracleDriver");
            // 데이터베이스의 연결을 설정한다.
            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);

                // 결과를 출력한다.
                System.out.println(
                        empno + " : " + ename + " : " + job + " : " + mgr
                        + " : " + hiredate + " : " + sal + " : " + comm + " : "
                        + depno);
            }
            // ResultSet를 닫는다.
            rs.close();
            // Statement를 닫는다.
            stmt.close();
            // Connection를 닫는다.
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }// main()의 끝
}// 클래스의 끝

 


컴파일하고 실행시킨 결과 다음의 결과가 나오면 JDBC 프로그래밍 준비 완료가 된 겁니다.

주의할 것은 String DB_URL="jdbc:oracle:thin:@127.0.0.1:1521:orcl";  이 부분입니다.

여기서 orcl 은 SID 명인데 설치시에 입력한 것으로 지정합니다.

> javac GetEmp.java 엔터

> java Getemp 엔터


------------- 실행 결과 -------------
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
7934 : MILLER : CLERK : 7782 : 1982-01-23 00:00:00.0 : 1300 : null : 10
..


나. JDBC 프로그래밍 방법

(1) JDBC 드라이버 로딩 :

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


(2) Connection 맺기 :

String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
Connection con = DriverManager.getConnection(url,"scott", "tiger");


(3) SQL 실행


(4) [SQL문이 select문이었다면 ResultSet을 이용한 실행결과 처리]


(5) 자원 반환

위 순서가 JDBC 프로그래밍 방법입니다.

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

반응형

1. HelloServlet

서블릿의 첫번째 예제는 "안녕! 2008년" 를 출력하는 예제입니다.
앞으로 나오는 모든 예제는 ROOT 웹 애플리케이션에서 실행합니다.
아래 파일을 ROOT 웹 애플리케이션의 WEB-INF/classes 폴더에 저장합니다.

/WEB-INF/classes/HelloServlet.java

package example;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class HelloServlet extends HttpServlet {
  public void doGet( HttpServletRequest req, HttpServletResponse res )
    throws ServletException,IOException {
    res.setContentType( "text/html;charset=euc-kr" );
    PrintWriter out = res.getWriter();
    out.println( "<HTML>" );
    out.println( "<BODY>" );
    out.println( "안녕! 2008년" );
    out.println( "</BODY>" );
    out.println( "</HTML>" );
    out.close();
  }
}

(1) web.xml 파일 편집

web.xml 파일을 열고 web-app 엘리멘트안에 아래를 추가합니다.

/WEB-INF/web.xml

<servlet>
    <servlet-name>HelloServlet</servlet-name>
    <servlet-class>example.HelloServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>HelloServlet</servlet-name>
    <url-pattern>/servlet/HelloServlet</url-pattern>
</servlet-mapping>

(2) HelloServlet.java 컴파일

WEB-INF/classes 에 위 파일을 편집하여 복사하고 컴파일합니다.
(CLASSPATH에 {TOMCAT_HOME}/common/lib/servlet-api.jar 파일을 추가했다면)
javac -d . HelloServlet.java
(CLASSPATH에 servlet-api.jar 파일을 추가하지 않은 경우)
javac -d . -classpath D:\apps\Tomcat\common\lib\servlet-api.jar HelloServlet.java

(3) http://localhost:8998/servlet/HelloServlet 로 방문하여 테스트

톰캣을 재시작하고
http://localhost:8998/servlet/HelloServlet 을 방문하여 실행이 되는지 확인합니다.

(4) HelloServlet.java 서블릿 소스 설명

① HttpServlet 클래스를 상속받은 서블릿 클래스는 public class 로 선언해야 합니다.
② HTTP 의 GET 방식으로 웹 브라우저가 요청해오면 doGet() 메소드를 작성합니다.
(일반적으로 웹서버의 자원을 요청하는 것은 HTTP 프로토콜의 GET 방식의 요청입니다.)
③ doGet() 메소드는 HttpServletRequest 와 HttpServletResponse 타입의 아규먼트를 가집니다.
이 메소드는 예외가 발생할 수 있으므로 다음 문장으로 예외를 처리합니다.
throws ServletException, IOExcepiton
④ res.setContentType("text/html;charset=euc-kr");
은 웹브라우저에 응답으로 출력될 문서의 MIME 타입을 설정합니다.
;charset=euc-kr을 쓰지 않으면 한글이 깨지는 경우가 발생합니다.
setContentType()메소드는 HttpServletResponse 의 메소드입니다.
⑤ PrintWriter out = res.getWriter();
웹브라우저으로의 문자열에 대한 출력 스트림을 얻습니다.
PrintWriter의 plintln() 메소드안에 문자열을 넣으면 그대로 클라이언트의 웹브라우저에 출력된다고 생각하시면 됩니다.
⑥ http://localhost:8998/servlet/HelloServlet 는 web.xml에서 매핑한 내용대로 접근해야 합니다.
⑦ HelloServlet 서블릿이 작동 원리
클라이언트, 즉 웹브라우저가 서버의 HelloSerlvet 서블릿 자원을 요청합니다.
서블릿엔진인 톰캣은 클라이언트의 요청을 캡슐화한 HttpSerlvetRequest 인터페이스를 구현한 객체와
요청에 대한 응답을 캡슐화한 HttpSerlvetResponse 인터페이스를 구현한 객체를 아규먼트로 받는 protected void service(HttpServletRequest req,HttpServletResponse res) 메소드를 호출합니다.
이 메소드의 내용은 단지 웹브라우저가 헤더로 보낸 HTTP 메소드타입(GET,POST)에 따라 자동적으로 doGet(,) 또는 doPost(,)메소드를 호출하도록 하는 것이 전부입니다.
(따라서 doGet(,)이나 doPost(,)를 생각하지 않으려면 service(,)메소드를 직접 오버라이딩해도 됩니다.)
객체로 된 HelloServlet 서블릿은 클라이언트의 각각의 요청을 개발자가 구현한 doGet(,), doPost(,) 메소드가 병행적으로 처리하므로써 클라이언트의 요청에 응답하게 됩니다.

"안녕! 2008년" 을 출력하는 기본적인 예제를 실행해 봤습니다.
이제는 웹브라우저, 즉 클라이언트가 보내는 정보를 어떻게 서블릿에서 다룰 수 있는지 알아봅니다.
정확하게 클라이언트가 보내는 문자열 정보를 서블릿에서 catch하는 코드를 설명합니다.

2. 웹 브라우저가 서버에 문자열을 전송하는 방법

HTML FORM 태그를 이용하여 웹브라우저가 서버로 문자열 데이터를 전달하는 방법과 서블릿에서 그 정보를 받는 코드조각은 다음과 같습니다.

HTML 서블릿
<input type="text" name="addr"/> req.getParameter( "addr" );
<input type="radio" name="os" value="win98"/>
<input type="radio" name="os" value="win2000"/>
req.getParameter( "os" );
<input type="hidden" name="cur_page" value="1"/> req.getParameter( "cur_page" );
<input type="password" name="passwd"/> req.getParamter( "passwd" );
<input type="checkbox" name="hw" value="intel"/>
<input type="checkbox" name="hw" value="amd"/>
req.getParameterValues( "hw" );
<select name="os" multiple>
  <option value="win">windows</option>
  <option value="linux">linux</option>
  <option value="solaris">solaris</option>
</select>
req.getParameterValues( "os" );
multiple 속성이 없다면
req.getParameter( "os" )도 가능

HttpServletRequest.getParameter()

HttpServletRequest 의 getParameter() 메소드는 웹브라우저에서 사용자가 보내는 데이터를 서블릿에서 받기 위해 사용하는 가장 보편적인 메소드입니다. 라디오 버튼은 name 속성이 같게 두면 같은 name 속성의 라디오 버튼들은 그룹이 됩니다.
그룹화되어 있는 라디오 버튼은 사용자가 한개 항목만을 선택할 수 있습니다.
따라서 HttpServletRequest 의 getParameter() 메소드로 클라이언트가 보낸 데이터를 받습니다.
이 밖에 FORM 태그의 <input type="password" ../> 이나 <input type="hidden" ../> 도 역시 마찬가지로 HttpServletRequest 의 getParameter() 메소드를 이용해서 사용자가 전달한 파라미터 값을 받습니다.
클라이언트, 즉 웹 브라우저에서 서버로는 문자열만을 전송할 수 있습니다.
(물론 서버 사이드에서는 서버자원에서 서버자원으로 문자열 뿐만이 아닌 다른 객체를 만들어 전달 할 수 있습니다.)

HttpServletRequest.getParameterValues()

웹브라우저를 통해 사용자가 다중 선택을 하여 전송하는 데이터의 경우는 HttpServletRequet 의 getParamter() 메소드가 아닌 getParamterValues() 메소드가 쓰입니다.
이 메소드의 리턴값은 사용자가 선택한 값들만으로 구성된 String 배열입니다.

HttpServletRequest.getParamterNames()

만약 사용자가 어떤 파라미터명으로 데이터를 보내는지 알수 없다고 가정을 합니다.(그럴 경우는 거의 없지만) 이때 사용자가 보내는 파라미터명을 알 수 있는 메소드가 HttpServletRequest 의 getParamterNames()입니다.
getParameterNames() 메소드는 리턴값으로 Enumeration 타입을 반환합니다.
(Enumeration 의 hasMoreElements() , nextElement() 2개의 메소드가 기억나지 않는다면 Java Basic 에서 지금 바로 확인하세요.)

실습 1 - 2008년 투자 포트폴리오 설문조사

이 예제는 사이트의 회원으로부터 2008년의 투자 포트폴리오를 설문조사하는 예제입니다.
portfolio2008.html 은 사용자로부터 입력을 받는 페이지입니다.
Portfolio2008Servlet.java 는 portfolio2008.html에서 사용자가 입력한 정보를 데이터베이스에 인서트하는 JDBC 코드를 포함합니다.
portfolio2008.sql 은 관련 테이블 쿼리문입니다.

/example/portfolio2008.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitonal.dtd">	
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR" />
<title>2008년 투자 포트폴리오</title>
</head>
<body>
  <form action="../servlet/Portfolio2008Servlet" method="post">
   기관 : <input type="text" name="company"/><br />
   제안자 : <input type="text" name="name"/><br />
   제안일 : <input type="text" name="signdate"/><br />
   투자액 : <input type="text" name="money"/><br />
   투자성격 : <input type="radio" name="type" value="aggressive" />공격적
   <input type="radio" name="type" value="passive"/>위험회피<br />
   투자형태 :<br />
   <select name="investments" multiple="multiple">
   <option value="koreafund">국내펀드</option>
   <option value="overseasfund">해외펀드</option>
   <option value="direct">직접투자</option>
   <option value="bank">CMA 또는 은행</option>
   </select><br />
   국내펀드 1 <input type="text" name="koreafund1_nm"/>
   투자액 <input type="text" name="koreafund1_money"/>원<br />
   국내펀드 2 <input type="text" name="koreafund2_nm"/>
   투자액 <input type="text" name="koreafund2_money"/>원<br />
   국내펀드 3 <input type="text" name="koreafund3_nm"/>
   투자액 <input type="text" name="koreafund3_money"/>원<br /><br />
   해외펀드 1 <input type="text" name="overseasfund1_nm"/>
   투자액 <input type="text" name="overseasfund1_money"/>원<br />
   해외펀드 2 <input type="text" name="overseasfund2_nm"/>
   투자액 <input type="text" name="overseasfund2_money"/>원<br />
   해외펀드 3 <input type="text" name="overseasfund3_nm"/>
   투자액 <input type="text" name="overseasfund3_money"/>원<br /><br />
   직접투자 <input type="text" name="directp"/>원<br />
   CMA 또는 은행 <input type="text" name="bankp"/>원<br />
   <input type="submit" value="전송"/>
  </form>
</body>
</html>

/WEB-INF/classes/Portfolio2008Servlet.java

package example;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class Portfolio2008Servlet extends HttpServlet {
  public void doPost( HttpServletRequest req, HttpServletResponse res )
  throws IOException,ServletException {
    res.setContentType( "text/html;charset=euc-kr" );
    PrintWriter out = res.getWriter();
    req.setCharacterEncoding( "euc-kr" );

    String company = req.getParameter("company");
    String name = req.getParameter("name");
    String signdate = req.getParameter("signdate");
    String money = req.getParameter("money");
    String type = req.getParameter("type");
    String[] investments = req.getParameterValues("investments");

    String koreafund1_nm = req.getParameter("koreafund1_nm");
    String koreafund2_nm = req.getParameter("koreafund2_nm");
    String koreafund3_nm = req.getParameter("koreafund3_nm");

    String koreafund1_money = req.getParameter("koreafund1_money");
    String koreafund2_money = req.getParameter("koreafund2_money");
    String koreafund3_money = req.getParameter("koreafund3_money");

    String overseasfund1_nm = req.getParameter("overseasfund1_nm");
    String overseasfund2_nm = req.getParameter("overseasfund2_nm");
    String overseasfund3_nm = req.getParameter("overseasfund3_nm");

    String overseasfund1_money = req.getParameter("overseasfund1_money");
    String overseasfund2_money = req.getParameter("overseasfund2_money");
    String overseasfund3_money = req.getParameter("overseasfund3_money");

    String directp = req.getParameter("directp");
    String bankp = req.getParameter("bankp");

    out.println( "<html><body>" );
    out.println( "<h1>portfolio.html 에서 보내온 데이터는 다음과 같습니다.</h1>" );
    out.println( "<ul>" );
    out.println( "<li>기관 : " + company + "</li>");
    out.println( "<li>제안자 : " + name + "</li>");
    out.println( "<li>제안일 : " + signdate + "</li>");
    out.println( "<li>투자액 : " + money + "만원 </li>");
    out.println( "<li>투자성격 : " + type + "</li>");
    out.println( "</ul>" );
    out.println("<h3>투자형태</h3>");
    out.println( "<ul>" );
    if( investments != null ) {
      for( int i=0; i < investments.length; i++ ) {
        out.print( "<li>" );
        out.print( investments[i] );
        out.print( "</li>" );	
      }
    }
    out.println( "</ul>" );
    out.println("<h3>국내펀드</h3>");
    out.println( "<ul>" );
    out.println( "<li>" + koreafund1_nm + ": " + koreafund1_money + "만원 </li>");
    out.println( "<li>" + koreafund2_nm + ": " + koreafund2_money + "만원 </li>");
    out.println( "<li>" + koreafund3_nm + ": " + koreafund3_money + "만원 </li>");
    out.println( "</ul>" );

    out.println("<h3>해외펀드</h3>");
    out.println( "<ul>" );
    out.println( "<li>" + overseasfund1_nm + ": " + overseasfund1_money + "만원 </li>");
    out.println( "<li>" + overseasfund2_nm + ": " + overseasfund2_money + "만원 </li>");
    out.println( "<li>" + overseasfund3_nm + ": " + overseasfund3_money + "만원 </li>");
    out.println( "</ul>" );

    out.println("<h3>직접투자</h3>");
    out.println( "<ul>" );
    out.println( "<li>" + directp + "만원</li>");
    out.println( "</ul>" );

    out.println("<h3>CMA 또는 은행</h3>");
    out.println( "<ul>" );
    out.println( "<li>" + bankp + "만원 </li>");
    out.println( "</ul>" );

    String path = req.getContextPath();
    out.println( "<a href=" + path + "/example/portfolio2008.html>뒤로</a>" );
    out.println( "</body></html>" );
  }
}

HttpServletRequest.getContextPath()

HTML문서와 서블릿간의 상대경로에 주의를 기울려야 합니다.
서블릿 코드에서 HTML문서나 JSP문서에 링크를 걸때는 req.getContextPath() 메소드 로 일단 Context base 경로를 구한 후에 이를 이용해 경로를 링크시키면 됩니다.

HttpServletRequest.setCharacterEncoding()

HttpServletRequest 의 setCharacterEncoding("euc-kr")은 웹브라우저, 즉 클라이언트가 보내는 한글 데이터를 한글 인코딩으로 받기 위한 것입니다.
이 부분이 없다면 클라이언트가 보낸 한글 데이터는 깨져 보일 겁니다.

HttpServletResponse.setContentType()

HttpServletResponse 의 setContentType() 메소드는 서블릿이 만드는 HTML문서의 타입과 문자셋을 지정하는 것입니다.
HttpServletRequest 의 setCharacterEncoding() 와 구별하여서 기억해야 합니다.

portfolio2008.sql

create table portfolio (
  portfolio_no   int(11) not null,
  company   varchar(30)	not null,
  name   varchar(10) 	not null,
  signdate   varchar(16)	not null,
  money   int(11) default '0' not null,
  type   varchar(12)	not null,
  koreafund   enum('Y','N') not null default 'Y',
  overseasfund   enum('Y','N') not null default 'Y',
  direct   enum('Y','N') not null default 'Y',
  bank   enum('Y','N') not null default 'Y',
  directp   int(11) default '0' not null,
  bankp   int(11) default '0' not null,
  primary key (portfolio_no),
  index portfolio_no_idx  (portfolio_no)
);

create table koreafundp (
  koerafundp_no   int(11)	not null,
  portfolio_no   int(11)	not null,
  koreafund_nm   varchar(40) not null,
  koreafund_money   int(11) default '0' not null,
  primary key (koerafundp_no)
);

create table overseasfundp (
  overseasfundp_no   int(11)	not null,
  portfolio_no   int(11)	not null,
  overseasfund_nm   varchar(40) not null,
  overseasfund_money   int(11) default '0' not null,
  primary key (overseasfundp_no)
);

위 예제를 실행하려면, portfolio2008.html 의 form action 속성이 ../servlet/Portfolio2008Servlet 로 되어 있으므로 이에 맞게 web.xml 파일을 열어서 web-app 엘리멘트 안에 아래를 추가합니다.

/WEB-INF/web.xml

<servlet>			
    <servlet-name>Portfolio2008Servlet</servlet-name>
    <servlet-class>example.Portfolio2008Servlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>Portfolio2008Servlet</servlet-name>
    <url-pattern>/servlet/Portfolio2008Servlet</url-pattern>
</servlet-mapping>

Portfolio2008Servlet.java 를 컴파일하여 Portfolio2008Servlet.class 파일이 /WEB-INF/classes/example 디렉토리에 생기도록 하고 톰캣을 재시동한 후 http://localhost:8998/example/portfolio2008.html 를 방문하여 테스트합니다.

Portfolio2008Servlet.java 에서 JDBC 관련 소스를 입력해 보기 바랍니다.
다음은 간단한 서블릿을 이용한 회원가입 예제입니다.
이 예제를 먼저 실습해 보면 응용이 가능하리라 생각합니다.
sendTF.html에서 이름과 주소를 입력받고 GetTFData.java서블릿은 sendTF.html 에서 사용자가 전달한 값을 JDBC 를 이용해서 memtest 테이블에 인서트를 합니다.
실습에 필요한 테이블은
memtest.sql이고 이 예제는 오라클을 사용해야 합니다.

3. RequestDispatcher 사용 예제

javax.servlet.RequestDispathcer 클래스는 클라이언트의 요청을 서버상의 다른 자원(서블릿,JSP)으로 보내는 작업을 할 때 사용됩니다.
RequestDispathcer 는 include() 와 forward() 2개의 메소드가 있습니다.
include() 메소드는 요청을 다른 자원으로 보냈다가 다른 자원에서 실행이 끝나면 다시 요청을 가져오는 메소드입니다. 결론적으로 말하면 요청을 전달한 자원의 결과를 포함해서 클라이언트에게 보여주게 됩니다.
forward() 메소드는 이름 그대로 클라이언트의 요청을 서버상의 다른 자원에게 넘기는 메소드입니다.
forward() 메소드가 가장 많이 사용됩니다.

/WEB-INF/classes/ControllerServlet.java

package example;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class ControllerServlet extends HttpServlet {

  public void doPost( HttpServletRequest req, HttpServletResponse res ) 
    throws IOException, ServletException {
    String url = req.getParameter( "url" );
    if ( url.equals( "list" ) ) {
      url = "/example/list.jsp"; //구조에 맞게 설정하시요.
    }
    ServletContext sc = getServletContext();
    RequestDispatcher rd= sc.getRequestDispatcher( url );
    rd.forward( req, res );
  }

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

/example/list.jsp

<%@ page 
	language="java" 
	contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE 
	html 
	PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
	"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>Insert title here</title>
</head>
<body>
	게시판 목록을 보이는 페이지...
</body>
</html>

ControllerServlet 에서 "/example/list.jsp" 에 대한 RequestDispatcher 를 얻은 다음 forward() 메소드를 이용해서 사용자의 요청을 전달하고 있습니다.
ControllerServlet 을 등록하기 위해서 web.xml 파일을 열어 web-app 엘리멘트 안에 아래를 추가합니다.
추가한 다음 톰캣을 재가동하고 http://localhost:8998/bbs/ControllerServlet?url=list 를 방문하여 /example/list.jsp 파일이 보이는지 확인합니다.

/WEB-INF/web.xml

<servlet>
    <servlet-name>Controller</servlet-name>
    <servlet-class>example.ControllerServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>Controller</servlet-name>
    <url-pattern>/ControllerServlet</url-pattern>
</servlet-mapping>

4. ServletConfig 의 getInitParameter() 사용 예제

ServletConfig 의 getInitParameter() 메소드는 해당 서블릿에서만 사용할 수 있는 초기화 파라미터를 web.xml 으로부터 가져올 때 사용하는 메소드입니다.
다음은 예제에 대한 설명입니다.
이전에 사용했던 ConnectionPool 관련 소스는 JDBC 설정내용을 자바의 Properties 파일(oracle.properties, mysql.properties)을 이용했습니다.
예제에서는 이 JDBC 설정 파일을 XML 파일로 변경합니다.
XML 파일을 읽기 위해서 서블릿을 이용합니다.
해당 서블릿의 init 메소드내에 ServletConfig 의 getInitParameter() 메소드를 이용해서 JDBC 설정 XML 파일에 대한 실제 시스템상의 경로를 얻은 다음 SAX 파서를 사용해서 XML 파일의 내용을 읽어 ConnectionPool 관련 객체를 생성한 다음 그 객체를 ServletContext 에 저장합니다.
다음은 위에서 예제로 사용했던 ControllerServlet.java 에 아래와 같이 init 메소드를 추가합니다.
그리고 다음과 같은 import 문장을 추가해야 합니다.

  • import net.java_school.db.dbpool.*;
  • import javax.xml.xpath.*;
  • import org.xml.sax.*;

/WEB-INF/classes/ControllerServlet.java

public void init() throws ServletException {
  
  ServletContext cxt = getServletConfig().getServletContext();
  
  String pool = getInitParameter( "pool" );

  String dbServer = null;
  String port = null;
  String dbName = null;
  String userID = null;
  String passwd = null;
  int maxConn = 0;
  int initConn = 0;
  int maxWait = 0;

  if ( pool != null ) {
    try {
      XPathFactory xpathFactory = XPathFactory.newInstance();
      XPath xpath = xpathFactory.newXPath();

      pool = cxt.getRealPath( pool );

      InputSource xmlSource = new InputSource(pool);

      dbServer = xpath.evaluate("/DBproperties/dbServer",xmlSource);
      port = xpath.evaluate("/DBproperties/port",xmlSource);
      dbName = xpath.evaluate("/DBproperties/dbName",xmlSource);
      userID = xpath.evaluate("/DBproperties/userID",xmlSource);
      passwd = xpath.evaluate("/DBproperties/passwd",xmlSource);
      maxConn = Integer.parseInt(xpath.evaluate("/DBproperties/maxConn",xmlSource));
      initConn = Integer.parseInt(xpath.evaluate("/DBproperties/initConn",xmlSource));
      maxWait = Integer.parseInt(xpath.evaluate("/DBproperties/maxWait",xmlSource));
    } catch ( Exception e ) {}
  }
  ConnectionManager dbmgr = new OracleConnectionManager( dbServer, dbName, port, userID, 
  passwd, maxConn, initConn, maxWait );
  
  // OracleConnectionManager 객체를 ServletContext 에 dbmgr 이란 이름으로 저장
  cxt.setAttribute("dbmgr",dbmgr);
}

web.xml 열고 아래를 추가합니다.

/WEB-INF/web.xml

<servlet>			
  <servlet-name>Controller</servlet-name>
  <servlet-class>example.ControllerServlet</servlet-class>

  <init-param>
    <param-name>pool</param-name>
    <param-value>/WEB-INF/oracle.xml</param-value>
  </init-param>

  <load-on-startup>1</load-on-startup>

</servlet>

oracle.xml 파일을 /WEB-INF 에 아래와 같은 내용으로 만듭니다.

/WEB-INF/oracle.xml

<?xml version="1.0"?>
<DBproperties>
  <dbServer>10.10.10.10</dbServer>
  <port>1521</port>
  <dbName>orcl</dbName>
  <userID>scott</userID>
  <passwd>tiger</passwd>
  <maxConn>20</maxConn>
  <initConn>5</initConn>
  <maxWait>5</maxWait>
</DBproperties>

메인메뉴 JDBC 에서 실습한 ConnectionPool 관련 소스 중 ConnectionManager.java 와 OracleConnectionManager.java 를 각각 다음과 같이 고칩니다.

ConnectionManager.java

package net.java_school.db.dbpool;

import java.sql.*;

public abstract class ConnectionManager {

  protected DBConnectionPoolManager connMgr = null;
  protected String poolName, dbServer, dbName, port, userID, passwd;
  int maxConn,initConn, maxWait;

  public ConnectionManager() {}
  
  public ConnectionManager( String pool, String dbServer, String dbName, String port, 
    String userID, String passwd, int maxConn, int initConn, int maxWait ) {
    poolName = pool;
    this.dbServer = dbServer;
    this.dbName = dbName;
    this.port = port;
    this.userID = userID;
    this.passwd = passwd;
    this.maxConn = maxConn;
    this.initConn = initConn;
    this.maxConn = maxConn;
  }

  public Connection getConnection() {
    return ( connMgr.getConnection( poolName ) );
  }

  public void freeConnection( Connection conn ) {
    connMgr.freeConnection( poolName, conn );
  }

  public int getDriverNumber() {
    return connMgr.getDriverNumber();
  }
}

OracleConnectionManager.java

package net.java_school.db.dbpool;

public class OracleConnectionManager extends ConnectionManager {
  
  public OracleConnectionManager() {}

  public OracleConnectionManager( String dbServer, String dbName, String port, 
    String userID, String passwd, int maxConn, int initConn, int maxWait ) {
    
    super( "oracle", dbServer, dbName, port, userID, passwd, 
	maxConn, initConn, maxWait );
    
    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 );
  }
}

위에서 간단하게 테스트했던 /exmaple/list.jsp 파일을 아래와 같이 수정합니다.

/example/list.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 {
      if ( rs != null ) rs.close();
      if ( stmt != null) stmt.close();
      dbmgr.freeConnection( conn );
    } catch ( SQLException e ){}
  }
%>

톰캣을 재시작하고 http://localhost:8998/bbs/ControllerServlet?url=list 로 방문해서 테스트합니다.

5. 파일 업로드을 위한 MultipartRequest 팩키지

MultipartRequest 팩키지는 파일 업로드에 널리 이용되고 있는 팩키지입니다.
http://www.servlets.com/cos/index.html 에서 가장 최신 버전인 cos-05Nov2002.zip 를 다운로드 하여 압축을 풉니다.
lib 디렉토리에 있는 cos.jar 파일을 /WEB-INF/lib 디렉토리에 복사합니다.
MultipartRequest 클래스의 생성자는 아래 링크에서 확인할 수 있듯이 8가지나 됩니다.
http://www.servlets.com/cos/javadoc/com/oreilly/servlet/MultipartRequest.html
그 중 아래의 생성자는 한글 인코딩 문제를 해결할 수 있고, 또한 업로드되는 파일이 기존의 파일명과 중복될 때 파일명을 변경해서 업로드할 수 있습니다.
MultipartRequest ( HttpServletRequest req, String dir, int max, String encoding, FileRenamePolicy policy )

MultipartRequest 메소드

<input type="file" name="photo"/> 태그를 이용해서 logo.gif 를 업로드했다고 가정하에 설명합니다.

메소드 설명
getContentType( "photo" ); 업로드된 파일의 MIME 타입 리턴, 리턴값 "image/gif"
getFile( "photo" ); 업로드되어 서버에 저장된 파일의 File 객체 리턴
getFileNames(); 폼 요소 중 input 태그 속성이 file 로 된 파라미터의 이름을 Enumeration 타입으로 리턴
getFilesystemName( "photo" ); 업로드되어 서버 파일시스템에 존재하는 실제 파일명을 리턴
getOriginalFileName( "photo" ); 원래의 파일명을 리턴
HttpServletRequest 와 같은 인터페이스를 제공하기 위한 메소드
getParameter(String name); name 에 해당하는 파라미터의 값을 String 타입으로 리턴
getParameterNames(); 모든 파라미터의 이름을 String 으로 구성된 Enumeration 타입으로 리턴
getParameterValues(String name); name 에 해당하는 파라미터의 값들을 String[] 타입으로 리턴

MultipartRequest 를 이용한 파일 업로드 예제

/example/upload.html

<!--
파일명: upload.html
-->

<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=euc-kr">
</head>
<body>
<h2>MultipartRequest 를 이용한 파일 업로드 테스트</h2><
<form action="../servlet/UploadTest" method="post" enctype="multipart/form-data">
    이름 : <input type="text" name="name"/><br>
    파일1 : <input type="file" name="file1"/><br>
    파일2 : <input type="file" name="file2"/><br>
    <input type="submit" value="전송"/>
</form>
</body></html>

/WEB-INF/classes/UploadTest.java

package example;

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import com.oreilly.servlet.MultipartRequest;
import com.oreilly.servlet.multipart.DefaultFileRenamePolicy;

public class UploadTest extends HttpServlet {
  public void doPost( HttpServletRequest req, HttpServletResponse res ) 
  throws IOException, ServletException {
    
    res.setContentType( "text/html;charset=euc-kr" );
    PrintWriter out = res.getWriter();
    //req.setCharacterEncoding( "euc-kr" );
    ServletContext cxt = getServletContext();
    String dir = cxt.getRealPath( "upload" );

    try {
      MultipartRequest multi = new MultipartRequest( req, dir, 
        5*1024*1024, "euc-kr", new DefaultFileRenamePolicy());

      out.println( "<html>" );
      out.println( "<body>" );
      out.println( "<h1>사용자가 전달한 파라미터들</h1>" );
      out.println( "<ol>" );
      Enumeration params = multi.getParameterNames();

      while( params.hasMoreElements() ) {
        String name = (String)params.nextElement();
        String value = multi.getParameter( name );
        out.println( "<li>" + name + "=" + value + "</li>" );
      }
      out.println( "</ol>" );

      out.println( "<h1>업로드된 파일</h1>" );

      Enumeration files = multi.getFileNames();

      while( files.hasMoreElements() ) {
        out.println( "<ul>" );  
        String name = (String)files.nextElement();
        String filename = multi.getFilesystemName( name );
        String orginalname =multi.getOriginalFileName( name );
        String type = multi.getContentType( name );
        File f = multi.getFile( name );
        out.println( "<li>파라미터 이름 : "  + name + "</li>" );
        out.println( "<li>파일 이름 : " + filename + "</li>" );
        out.println( "<li>원래 파일 이름 : " + orginalname + "</li>" );
        out.println( "<li>파일 타입 : " + type + "</li>" );

        if( f != null ) {
        out.println( "<li>크기: " + f.length() + "</li>" );
        }

        out.println( "</ul>" );
      }
    } catch( Exception e ) {
      out.println( "<ul>" );
      e.printStackTrace( out );
      out.println( "</ul>" );
    }
    out.println( "</body></html>" );
  }
}

테스트를 위해서는

  1. 웹 애플리케이션의 루트에 upload 라는 폴더를 만듭니다
  2. 컴파일을 위해 cos.jar 파일을 CLASSPATH 에 추가하고 컴파일합니다
  3. cos.jar 파일을 /WEB-INF/lib 에 복사합니다.
  4. /WEB-INF/web.xml 파일을 열어 UploadTest 서블릿을 등록합니다.(아래참조)
  5. 톰캣을 재가동하고 http://localhost:8998/bbs/example/upload.html 를 방문하여 테스트 합니다.
  6. 중복된 파일을 업로드 테스트하고 upload 폴더에 파일명을 확인합니다.

/WEB-INF/web.xml

<servlet>
    <servlet-name>UploadTest</servlet-name>
    <servlet-class>example.UploadTest</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>UploadTest</servlet-name>
    <url-pattern>/servlet/UploadTest</url-pattern>
</servlet-mapping>

java.lang.NoClassDefFoundError: javax/activation/DataSource

컴파일이 문제가 없었고 톰캣을 재가동한 후에 URL로 방문하여 테스트 하니 위와 같은 에러가 나왔다면 JavaBeans(TM) Activation Framework 라는 팩키지가 필요합니다.
http://java.sun.com 에 방문해서 jaf라는 이름으로 검색해서 팩키지를 다운로드를 한 다음 /WEB-INF/lib/ 폴더에 복사합니다.

jaf 다운로드
a. http://java.sun.com 에 방문해서 오른쪽 메뉴의 Popular Downloads: See All를 선택합니다.

b. 다음 페이지에서 JAVA SE 셀렉트박스에서 JavaBeans Activation Framework(JAF) 를 선택하여 다운로드 합니다.

c. 압축을 풀고 activation.jar 를 /WEB-INF/lib/ 디렉토리에 저장합니다.

쿠키

HTTP 전송방식의 특징상 각각의 웹 브라우저가 서버와 통신에서 세션을 유지하지 못하는 것을 보완하기 위한 기술입니다.
서버가 쿠키를 전송하면 웹 브라우저는 그 다음 요청마다 쿠키 값을 서버로 전달하여 사용자 정보를 유지할 수 있게 합니다.
서버 -> 웹 브라우저 (쿠키를 굽는다고 표현되는데 아래와 같은 정보가 클라이언트의 웹 브라우저를 통해서 파일로 저장됩니다.)
이때 전달되는 정보 형태는 아래와 같습니다.

Set-Cookie : name = value ; expires = date ; path = path ; domain = domain ; secure

웹 브라우저 -> 서버 (쿠키가 웹브라우저에 셋팅되면, 웹브라우저는 쿠기를 전달해준 서버로 요청시마다 아래와 같은 문자열을 서버로 보냅니다.)

Cookie ; name = value1 ; name2 = value2 ;

쿠키 이름과 값에는 []()="/?@:; 와 같은 문자는 올 수 없습니다.

(1) 쿠키 설정 절차

① Cookie 객체를 만든다. Cookie(String name, String value)
② 다음 메소드를 이용해 쿠키에 속성을 부여한다.

메소드 설명
setValue(String value) 생성된 쿠키의 값을 재설정할 때 사용한다.
setDomain(String pattern) 쿠키는 기본적으로 쿠키를 생성한 서버에만 전송된다.
같은 도메인을 사용하는 서버에 대해서 같은 쿠키를 보내기 위해서 setDomain()을 사용한다.
주의할 점은 쿠키를 생성한 서버와 관련이 없는 도메인을 setDomain()에 값으로 설정하면 쿠키가 구워지지 않는다는 것이다.
setMaxAge(int expiry) 쿠키의 유효기간을 초단위로 설정한다.
음수 입력시에는 브라우저가 닫으면 쿠키가 삭제된다.
setPath(String uri) 쿠키가 적용될 경로 정보를 설정한다.
경로가 설정되면 해당되는 경로로 방문하는 경우에만 웹브라우저가 쿠키를 웹서버에 전송한다.
setSecure(boolean flag) flag가 true이면 보안채널을 사용하는 서버의 경우에 한해 쿠키를 전송한다.
③ 웹브라우저에 생성된 쿠키를 전송 : res.addCookie(cookie);

(2) 구워진 쿠키 이용

① 서블릿에서 쿠키 이용

Cookie[] cookie = req.getCookies();

HttpServletRequest의 getCookies() 메소드를 사용해서 쿠키배열을 얻습니다.
만약 구워진 쿠키가 없다면 getCookies() 메소드는 null을 리턴합니다.
이제 쿠키 객체를 접근할 수 있게 되었습니다.
다음 메소드를 이용하면 쿠키에 대한 정보를 얻을 수 있습니다.
이중 getName()과 getValue()가 주로 쓰입니다.

Cookie 메소드 설명
getName() 쿠키의 이름을 구한다.
getValue() 쿠키의 값을 구한다.
getDomain() 쿠키의 도메인을 구한다.
getMaxAge() 쿠키의 유효시간을 구한다.

String id = null;
Cookie[] cookies = request.getCookies();
if ( cookies != null ) {
  for ( int i=0; i < cookies.length; i++ ) {
    String name = cookies[i].getName();
    if ( name.equals( "id" ) ) {
      id = cookies[i].getValue();
    }
  }
}

② 서블릿에서 쿠키 삭제
아래와 같이 삭제하고자 하는 쿠키와 같은 이름의 쿠키를 생성하고 setMaxAge(0) 을 호출합니다.

Cookie cookie = new Cookie( "id", "" );
cookie.setMaxAge( 0 );
res.addCookie( cookie );

(3) 쿠키 실습

다음은 간단한 쿠키예제입니다.
실습 후 cookieList.jsp 파일을 cookie 폴더 외에 다른 폴더에 복사하고 테스트해 보세요.

/cookie/setCookie.jsp

<%@ page contentType="text/html; charset=euc-kr" %>
<%
  String cookieName = "id";
  String cookieValue = "xman";

  Cookie cookie = new Cookie(cookieName,cookieValue);
  String path = request.getContextPath();
  path = path + "/cookie";
  cookie.setPath( path );
  response.addCookie(cookie);
%>
<a href="cookieList.jsp">쿠키 목록보기</a>			

/cookie/cookieList.jsp

<%@ page contentType="text/html; charset=euc-kr" %>
<html><body>
저장되어 있는 쿠키 목록입니다.<br />
<%
  Cookie[] cookies = request.getCookies();
  if ( cookies != null ) {
    for ( int i=0 ;i < cookies.length; i++ ) {
      out.println(cookies[i].getName());
      out.println("<br />");
      out.println(cookies[i].getValue());
      out.println("<br />");
    }
  }
%>
<a href="removeCookie.jsp">쿠키 제거하기</a> <a href="setCookie.jsp">쿠키 굽기</a>
</body></html>

/cookie/removeCookie.jsp

<%@ page contentType="text/html; charset=euc-kr" %>
<%
  Cookie cookie = new Cookie( "id", "" );
  String path = request.getContextPath();
  path = path + "/cookie";
  cookie.setPath( path );
  cookie.setMaxAge( 0 );
  response.addCookie( cookie );
%>
<a href="cookieList.jsp">쿠키 목록보기</a>

세션

세션은 쿠키 기반 기술로 쿠키의 보안상 약점을 극복하기 위한 기술입니다.
쿠키와 다른 점(즉, 보안상 개선된 점) : 웹브라우저는 서버가 정해준 세션ID 만을 쿠키값으로 저장합니다.
세션이 생성되면(즉, 세션ID 쿠키가 구워지면) 세션ID 쿠키만을 서버로 전송하게 되고,
서버에서는 세션ID로 해당 HttpSession 객체를 서블릿/JSP 컨테이너가 연결시켜 줍니다.
HttpSession 의 메소드
setAttribute( String name , Object value )
getAttribute( String name )
removeAttribute( String name )
invalidate();
사용법
세션 생성 : HttpSession session = req.getSession( true ); //세션이 없으면 생성합니다.
HttpSession session = req.getSession( false ); // 세션이 없다면 null 을 리턴
세션에 정보 저장 : session.setAttribue( "data", value ); //data 이름으로 value 객체 저장

File 클래스

자바에서는 파일을 표현하기 위해 File 클래스를 사용합니다.
디렉토리도 File 클래스로 표현됩니다.
주의할 것은 File 클래스는 파일을 읽거나 쓰는 메소드는 가지고 있지 않습니다.
파일을 읽거나 쓰기 위해서는 입출력 클래스를 사용합니다.
File 클래스로 할 수 있는 작업
① 디렉토리 내용을 알아본다.
② 파일의 속성을 알아보거나 설정합니다.
③ 파일의 이름을 변경하거나 삭제합니다.
File 클래스 생성
객체 생성 : File dir = new File( path );
주의) 여기서 path 에 해당하는 파일이나 디렉토리는 시스템의 풀패스가 되어야 한다는 것입니다.
File 클래스 중요 메소드 소개와 사용법
isDirectory() : dir.isDirectory(); // dir 이 디렉토리이면 true 리턴
isFile() : dir.isFile(); // dir 이 파일이면 true 리턴
list() : dir.list() : // dir 이 디렉토리일 때 디렉토리에 있는 파일명이 String[] 값으로 리턴
listFiles() : dir.listFiles(); // 디렉토리에 있는 파일의 파일 객체 배열 리턴
mkdir() : dir.mkdir(); // File 객체의 이름을 가진 디렉토리를 만든다
getName() : 파일명을 리턴
getPath() : 경로를 리턴
delete() : 파일을 지운다.
exists() : 파일이 존재하는지 여부를 알려준다.

이것으로 아주 간단하게 서블릿 문법을 살펴보았습니다.
서블릿에 대한 이해가 있어야 JSP 할때에 이해가 쉽습니다.
다음은 JSP 문법으로 넘어갑니다.

+ Recent posts