반응형

서블릿(Servlet)

 

Servlet은 JSP표준이 나오기 전에 만들어진 표준 기술
자바에서 웹 어플리케이션 개발을 위해 만들어짐
JSP에 비해 Servlet개발 과정은 비교적 복잡
MVC패턴을 적용하여 개발하는 경우 Servlet 이해 필수

 

서블릿을 이용한 웹 어플리케이션 개발 과정
    1. 서블릿 규약에 따라 자바코드 작성 및 컴파일
    2. 클래스파일을 WAS의 /WEB-INF/classes 디렉터리에 위치
    3. web.xml파일에 서블릿 클래스 설정(필요 시 설정)
    4. WAS(Tomcat 등)를 재 실행(서블릿 리로드기능이 있다면 생략가능)
    5. 웹 브라우저를 통해 해당 서블릿을 요청하여 결과응답 페이지 확인

 

서블릿 클래스를 상속받아 요청을 처리하는 클래스를 작성
src/servletex/NowServlet.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package servletex;
 
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public class NowServlet extends HttpServlet{ 
    @Override
    protected void doGet(
            HttpServletRequest request,
            HttpServletResponse response)
                    throws ServletException, IOException{
 
        response.setContentType("text/html; charset=utf-8");
 
        PrintWriter out = response.getWriter();
 
        out.println("<html>");
        out.println("<head><title>현재시간 서블릿</title></head>");
        out.println("<body>");
        out.print("현재 시간은 ");
        out.print(new Date());
        out.println("입니다.");
        out.println("</body></html>");
    }
}
 
cs

 

위 코드를 보면 HttpServlet클래스를 상속받은 것을 확인할 수 있다.

그리고 상속 받은 HttpServlet의 메서드 중 doGet()메서드를 오버라이딩 한 것을 볼 수 있는데

이 메서드는 서블릿을 실행하는 서버(Tomcat)로 클라이언트의 get요청을 받으면 해당 메서드가 호출되도록 동작된다.

만약 POST메서드를 처리하려는 경우 상속받은 서블릿 클래스에 있는 doPost()를 오버라이딩한다. (하나의 서블릿 클래스에 둘 모두 정의 가능)

 

doGet()/doPost() 메서드가 전달받는 HttpServletRequest/HttpServletRespons
    - JSP에서 request/respons기본 객체와 동일
    - request를 이용하여 요청 정보를 읽거나 response를 이용하여 응답을 전송
    - response응답 전송 시 응답 컨텐츠 타입 지정(브라우저에서 응답을 해석할 방식)
    - 응답결과를 전송(PrintWriter로 응답 스트림에 지정된 컨텐츠 타입의 데이터를 출력)
    - 작성된 java코드를 컴파일하고 WAS의 /WEB-INF/classes/하위에 위치
      (이클립스의 Dynamic Web Application프로젝트를 이용하는 경우 생략.

      단 war배포 시에는 경로 확인필요)
    - WAS(이 실습에서는 Tomcat)에서 Servlet을 처리하려면 servlet-api.jar 필요
    - Tomcat에는 lib폴더에 포함되어 있으나 만약 없는 환경의 경우 포함 해야 함.

 

Servlet Mapping?

Servlet클래스를 생성했다면 /WEB-INF/web.xml 파일에 Servlet class 등록해야 함

등록된 정보를 이용해서 요청에 알맞는 서블릿 객체를 찾음

 

서블릿으로 사용할 클래스 등록 및 등록된 서블릿과 요청 URL간의 매핑

하나의 서블릿에 여러 경로 지정가능
웹 어플리케이션 경로는 제외하여 지정

 

매핑 설정 실습 예제

WebContent/WEB-INF/web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
    http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" 
    version="3.1">
  <display-name>ServletTest</display-name>
  
  <!-- 웹 서블릿 등록 -->
  <servlet>
      <servlet-name>now</servlet-name>
      <servlet-class>servletex.NowServlet</servlet-class>
  </servlet>
  
  <!-- 클라이언트의 요청 URL와 서블릿 객체를 연결(매핑) -->
  <servlet-mapping>
      <servlet-name>now</servlet-name>
      <url-pattern>/now</url-pattern>
  </servlet-mapping>
  
</web-app>
cs

 

이제 Tomcat(WAS) 서비스를 시작한다.


서비스가 시작되면 브라우저에서 web.xml에 매핑된 url 요청한 결과확인

(/now에 대한 get요청에 매핑된 서블릿 클래스의 doGet()메서드 처리 결과)


위에서 동작되는 개념을 꼭 이해하도록 한다. 그 후 다음의 예제들을 진행한다.

 

@WebServlet 어노테이션?

Servlet 2.5 버전까지는 반드시 web.xml에 서블릿을 등록해야만 했다.
Servlet 3.0 버전 부터는 @WebServlet어노테이션으로 서블릿 등록이 가능하다.

 

서블릿 클래스에 어노테이션으로 경로 매핑 예제

 

어노테이션 테스트용 클래스 작성
src/servletex/HelloServlet.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package servletex;
 
import java.io.IOException;
import java.io.PrintWriter;
 
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
@WebServlet(urlPatterns = "/hello")
public class HelloServlet extends HttpServlet{
    @Override
    protected void doGet(
        HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException{
        
        response.setContentType("text/html; charset=utf-8"); 
        
        PrintWriter out = response.getWriter();
        String name = request.getParameter("name");
        
        out.println("<html>");
        out.println("<head><title>인사서블릿</title></head>");
        out.println("<body>");
        out.print("안녕하세요, " + name + "님 :)");
        out.println("</body></html>");
    }
}
 
cs


여러 경로를 지정하는 경우 urlPetterns에 경로 배열을 등록해 줄 수 있다.


Tomcat 재실행 후 다음과 같이 name과 함께 요청하여 결과 확인

 

어노테이션 적용 시 고려사항

서블릿을 적용할 때 xml설정 파일에 등록하여 적용할 지 어노테이션을 사용하여 등록할 지 고민된다면 다음을 생각해보도록 하자.

 

- 서블릿이 범용적으로 사용 되는지 여부 중요(자주 변경되지 않는다면 어노테이션으로)
- MVC프레임워크는 어떤 URL경로를 서블릿이 처리할 지 미리 알 수 없음
- 즉 요청 URL이 변경되면 소스코드의 urlPatterns속성을 일일이 변경해야 함
- web.xml에 지정했다면 설정파일 하나로 관리가 가능
- 서블릿의 용도에 따라 자주 URL이 변경된다면 web.xml에 설정을 권장
- 둘 다 설정하는 경우 각각의 객체를 생성하여 url에 매핑 됨


Servlet 초기화 및 로딩

서블릿이 작동되기 전 초기화 작업이 필요한 경우
web.xml <init-param>, <param-name>, <param-value>로 초기화 파라미터 지정

 

다음 실습을 통해 DB를 연동하도록 초기화 파라미터를 지정하는 예제 확인

 

드라이버 검색 서블릿 작성(Loader.java)
src/servletex/Loader.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package servletex;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
 
public class Loader extends HttpServlet{
    @Override
    public void init() throws ServletException{
        try{
            String driver = getInitParameter("jdbcdriver");
            Class.forName(driver);
            System.out.println("DriverLoading Success!");
        }catch(Exception e){
            System.out.println("DriverLoading Failed!");
            throw new ServletException(e);
        }
    }
}
cs

 

web.xml파일에 서블릿 등록 및 초기화 파라미터 설정
WebContent/WEB-INF/web.xml 파일에 추가

1
2
3
4
5
6
7
8
9
10
...<!-- 기존 코드 -->
  <servlet>
      <servlet-name>JDBCDriverLoader</servlet-name>
      <servlet-class>servletex.Loader</servlet-class>
      <init-param>
          <param-name>jdbcdriver</param-name>
          <param-value>oracle.jdbc.driver.OracleDriver</param-value>
      </init-param>
      <load-on-startup>1</load-on-startup>
  </servlet>
cs

위 설정은 web.xml에 드라이버 라이브러리 경로를 초기화 파라미터로 등록(Loader에서 사용)
<load-on-startup>을 통해 서버 시작 시 드라이버 검색 완료되도록 한다.(우선순위 설정 태그)

 

Loader클래스가 서버실행 시 드라이버를 로드하도록 설정했으므로 Connection만 생성하여 오라클 DB버전을 응답하는 서블릿 작성하여 테스트를 해보도록 한다.


그리고 이 서블릿에서 Connection을 만들 때 사용할 DB접속 경로 url, 계정, 비밀번호를 초기화 파라미터로 설정하여 테스트를 진행한다.

 

등록할 InitParamEx서블릿 클래스 작성

src/servletex/InitParamEx.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package servletex;
 
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
 
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public class InitParamEx extends HttpServlet{
 
    @Override
    protected void doGet(HttpServletRequest request, 
                    HttpServletResponse response)
        throws ServletException, IOException{
 
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        
        ServletConfig config = this.getServletConfig();
        String url = config.getInitParameter("url");
        String account = config.getInitParameter("account");
        String password = config.getInitParameter("password");
        
        try{
            conn = DriverManager.getConnection(
                            url, account, password);
            System.out.println("Create new Connection!");
            String query = "select * from v$version";
            stmt = conn.createStatement();
            rs = stmt.executeQuery(query);
            PrintWriter out = response.getWriter();
            while(rs.next()){
                out.println(rs.getString(1));
            }
        }catch(SQLException e){
            e.printStackTrace();
        } finally{
            try{
            if(rs != null){ rs.close();}
            if(stmt != null){ stmt.close(); }
            if(conn != null){ conn.close(); }
            }catch(SQLException e){
                e.printStackTrace();
            }
        }
    }
 
}
cs

 

위 서블릿 클래스를 등록하기 위해 다음 설정 작성

WebContent/WEB-INF/web.xml 서블릿 등록 추가(초기화 파라미터 지정)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- ...기존코드 -->
  <servlet>
      <servlet-name>InitParamEx</servlet-name>
      <servlet-class>servletex.InitParamEx</servlet-class>
      <init-param>
          <param-name>url</param-name>
          <param-value>jdbc:oracle:thin:@localhost:1521:xe</param-value>
      </init-param>
      <init-param>
          <param-name>account</param-name>
          <param-value>scott</param-value>
      </init-param>
      <init-param>
          <param-name>password</param-name>
          <param-value>tiger</param-value>
      </init-param>
      <load-on-startup>2</load-on-startup>
 
  </servlet>
   <servlet-mapping>
      <servlet-name>InitParamEx</servlet-name>
      <url-pattern>/init</url-pattern>
  </servlet-mapping>
cs

 

위에서 어떤 JSP/Servlet 에서도 드라이버 로드작업 없이 Connection만 생성이 가능하다.

설정파일이 변경되었으므로 서버를 재시작한다.

 

요청 확인

 

위에서 설정한 내용을 어노테이션을 사용하여 적용해보자.

 

먼저 @WebServlet어노테이션 설정을 위해 InitParamEx에 관련된 web.xml설정을 모두 지운다.

다음 @WebServlet어노테이션 설정하기

src/servletex/InitParamEx.java 클래스에 @WebServlet설정 추가(나머지 코드는 변경 없음)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package servletex;
 
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
 
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
//서블릿 등록 및 초기화 파라미터 설적 적용
@WebServlet(
        urlPatterns="/init"
        initParams = { 
            @WebInitParam(name="url", value="jdbc:oracle:thin:@localhost:1521:xe"),
            @WebInitParam(name="account", value="scott"),
            @WebInitParam(name="password", value="tiger")
            }
)
//-- 나머지 코드는 변경 없음
public class InitParamEx extends HttpServlet{
 
    @Override
    protected void doGet(HttpServletRequest request, 
                    HttpServletResponse response)
        throws ServletException, IOException{
 
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        
        ServletConfig config = this.getServletConfig();
        String url = config.getInitParameter("url");
        String account = config.getInitParameter("account");
        String password = config.getInitParameter("password");
        
        try{
            conn = DriverManager.getConnection(
                            url, account, password);
            System.out.println("Create new Connection!");
            String query = "select * from v$version";
            stmt = conn.createStatement();
            rs = stmt.executeQuery(query);
            PrintWriter out = response.getWriter();
            while(rs.next()){
                out.println(rs.getString(1));
            }
        }catch(SQLException e){
            e.printStackTrace();
        } finally{
            try{
            if(rs != null){ rs.close();}
            if(stmt != null){ stmt.close(); }
            if(conn != null){ conn.close(); }
            }catch(SQLException e){
                e.printStackTrace();
            }
        }
    }
 
}
cs

 

서버 재시작 후 요청해보면 동일한 결과를 보여준다.

 

주의!
    - web.xml에 설정하면 서블릿 재컴파일이 필요없다.
    - 어노테이션을 사용하면 설정이 변경되면 서블릿도 재컴파일이 필요하다.

 

추가실습>

<context-param>서블릿 전체에서 사용할 수 있는 값 지정
위 실습에서 url정보만 <context-param>으로 지정하여 테스트를 진행해본다.

 

1. web.xml파일에서 InitParamEx 초기화 파라미터 설정에서 url값만 삭제


2. <context-param>으로 url에 대한 값 설정(<web-app> 하위에 작성)

 
 
 
 
<context-param>
    <param-name>url</param-name>
    <param-value>jdbc:oracle:thin:@localhost:1521:xe</param-value>
</context-param>
cs

 

3. InitParamEx클래스에서 context-param값을 이용하여 url값을 얻어오도록 수정

41
41
//String url = config.getInitParameter("url"); //초기화 파라미터에서 얻음
String url = this.getServletContext().getInitParameter("url"); //수정 
cs

 

서버 재 시작 후 브라우저에서 /init요청의 결과는 동일하다.

 

URL Pattern 매핑 규칙

 

클라이언트가 요청하는 경로에 대한 매핑 규칙
<servlet-mapping>태그는 <url-pattern>태그로 서블릿과 URL을 매핑

 

서블릿 규약
    ‘/’로 시작하고 ‘/*’로 끝나는 url-pattern은 경로 매핑을 위해 사용된다.
    ‘*’로 시작하는 url-pattern은 확장자에 대한 매핑을 할 때 사용된다.
    오직 ‘/’만 포함하는 경우 어플리케이션의 기본 서블릿으로 매핑한다.
    이 규칙 외의 나머지 다른 문자열은 정확한 매핑을 위해 사용된다.

 

매핑 예

 

 

서블릿의 전반적인 동작을 이해하도록 한다.

 

 

반응형

+ Recent posts