[필독][기초] / 서블릿 / servlet [part 4]

2016. 1. 5. 14:53language/jsp

RequestDispatcher 인터페이스
RequestDispathcer는 include()와 forward() 2개의 메소드가 있다.
include()메소드는 요청을 다른 자원으로 보냈다가 다른 자원에서 실행이 끝나면 다시 요청을 가져오는 메소드로 요청을 전달한 자원의 결과를 포함해서 클라이언트에게 보내게 된다.
forward()메소드는 이름 그대로 클라이언트의 요청을 서버상의 다른 자원에게 넘기는 메소드이다.
다음은 RequestDispatcher 의 forward() 메소드의 예로 모델 2 컨트롤러에 대한 이해에 도움이 될 것이다.


ControllerServlet.java
package example;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ControllerServlet extends HttpServlet {

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

          @Override
          public void doPost(HttpServletRequest req, HttpServletResponse resp)
                              throws ServletException, IOException {

                    req.setCharacterEncoding("UTF-8");
                   
                    String uri = req.getRequestURI();
                    String contextPath = req.getContextPath();
                    String command = null;
                    String view = null;
                    boolean isRedirect = false;
                   
                    command = uri.substring(contextPath.length());
                   
                    if (command.equals("/example/join.action")) {
                              view = "/example/join.html";
                    }
                    if (isRedirect == false) {
                              ServletContext sc = this.getServletContext();
                              RequestDispatcher rd = sc.getRequestDispatcher(view);
                              rd.forward(req,resp);
                    } else {
                              resp.sendRedirect(view);
                    }
                   
          }
         
}


명령 프롬프트를 열고 위 소스코드가 있는 /WEB-INF/src/exampe 로 이동하여 컴파일한다.
javac -d C:/www/myapp/WEB-INF/classes ^
-cp "C:/Program Files/Apache Software Foundation/Tomcat 7.0/lib/servlet-api.jar" ^
ControllerServlet.java


다음으로 web.xml 파일을 열고 아래를 추가한다.


web.xml
<servlet>
    <servlet-name>Controller</servlet-name>
    <servlet-class>example.ControllerServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>Controller</servlet-name>
    <url-pattern>*.action</url-pattern>
</servlet-mapping>


톰캣을 재시작한 다음 http://localhost:8989/example/join.action를 방문하여 /example/join.html이 응답하는지 확인한다.
ControllerServlet에서 isRedirect를 true로 변경한 다음 다시 테스트한다.



소스 설명
web.xml에서 모든 action 확장자의 요청을 ControllerServlet 담당하도록 설정했다.
확장자가 action 인 요청이 오면 톰캣은 web.xml 의 매핑정보를 해석해서 ControllerServlet 서블릿의 +service(req:ServletRequest, res:ServletResponse) 메소드를 호출한다.
 +service(req:ServletRequest, res:ServletResponse) 메소드는 #service(req:HttpServletRequest, resp:HttpServletResponse) 메소드를 호출한다.
 #service(req:HttpServletRequest, resp:HttpServletResponse) 메소드에서는 요청의 HTTP METHOD가 무엇인지 판단하고 그에 맞는 메소드를 호출한다.
웹브라우저의 주소창에서 http://localhost:8989/example/join.action를 요청했으므로 GET 방식의 요청이다.
따라서 이 경우는 doGet()메소드를 호출된다.
ControllerServlet서블릿의 doGet()메소드는 단순히 doPost()을 호출한다.
doPost()의 구현부에서 사용된 HttpServletRequest 의 다음 메소드를 다음과 같이 정리한다.


getRequestURI()
   웹브라우저로 http://localhost:8989/example/join.action 요청시 "/example/join.action"을 리턴한다.
getContextPath()
   컨텍스트 파일의 path 속성값을 얻을 수 있다.(이를 Context Path 라 한다.)
   우리는 ROOT 애플리케이션에서 작업하므로 이 메소드를 통해 얻을 수 있는 값은 "" 이다.
req.getRequestURI().substring(req.getContextPath().length())
   결과는 "/example/join.action" 를 리턴한다.
   이 값이 getRequestURI() 의 리턴값이 같은 이유는 ROOT 애플리케이션이기 때문이다.
   ROOT 애플리케이션이 아니라도 이 값은 달라지지 않는다.


 /example/join.html 에 대한 RequestDispatcher 를 얻은 후 forward() 메소드를 이용해서 사용자의 요청을 /example/join.html 로 전달한다.
제어권이 ControllerServlet 에서 /example/join.html 로 이동한 것이다.
결과적으로 /example/join.action 을 요청한 사용자는 /example/join.html 의 응답을 받게 된다.



데이터베이스 연동
JDBC 메뉴에서 실습했던 오라클 JDBC 연동 테스트 파일인 GetEmp.java 를 서블릿으로 변환해보자.
이번 예제는 순수 자바 애플리케이션을 서블릿으로 바꾸는 예제인 것이다.
ROOT 애플리케이션의 /WEB-INF/src/example 디렉토리에 GetEmpServlet.java 파일을 생성한다.


GetEmpServlet.java


package example;

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.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class GetEmpServlet extends HttpServlet {
         
          private String DB_URL = "jdbc:oracle:thin:@127.0.0.1:1521:XE";
          private String DB_USER = "scott";
          private String DB_PASSWORD = "tiger";
         
          /*
           * GenericServlet의 init() 메소드
           * init(ServletConfig config) 메소드 구현부에서 이 메소드를 호출하도록 구현되어 있다.
           * 따라서 굳이 init(ServletConfig config) 메소드를 오버라이딩하지 않아도 된다.
           */
          @Override
          public void init() throws ServletException {
                    try {
                              Class.forName( "oracle.jdbc.driver.OracleDriver" );
                    } catch (ClassNotFoundException e) {
                              e.printStackTrace();
                    }
          }
         

          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp)
                              throws ServletException, IOException {
                   
                    resp.setContentType("text/html; charset=UTF-8");
                    PrintWriter out = resp.getWriter();
                   
                    Connection con = null;
                    Statement stmt = null;
                    ResultSet rs = null;
                   
                    String sql = "select * from emp";
                   
                    try {
                              // Connection 레퍼런스를 획득
                              con = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
                              // Statement를 생성
                              stmt = con.createStatement();
                              // SQL문 실행
                              rs = stmt.executeQuery(sql);
                             
                              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 {
                              if (rs != null) {
                                        try {
                                                  rs.close();
                                        } catch (SQLException e) {
                                                  e.printStackTrace();
                                        }
                              }
                              if (stmt != null) {
                                        try {
                                                  stmt.close();
                                        } catch (SQLException e) {

                                                  e.printStackTrace();
                                        }
                              }
                              if (con != null) {
                                        try {
                                                  con.close();
                                        } catch (SQLException e) {
                                                  e.printStackTrace();
                                        }
                              }
                    }
                   
          }

}


명령 프롬프트를 이용해서 ROOT 애플리케이션의 /WEB-INF/src/example 디렉토리로 이동 한 후 컴파일한다.
javac -d C:/www/myapp/WEB-INF/classes ^
-cp "C:/Program Files/Apache Software Foundation/Tomcat 7.0/lib/servlet-api.jar" ^
GetEmpServlet.java


컴파일 후에는 web.xml 파일을 편집한다.
web.xml 열고 아래와 같이 서블릿 선언과 매핑을 추가한다.


web.xml
<servlet>
    <servlet-name>GetEmpServlet</servlet-name>
    <servlet-class>example.GetEmpServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>GetEmpServlet</servlet-name>
    <url-pattern>/empList</url-pattern>
</servlet-mapping>


이미 설명한 대로 톰캣 클래스로더는 환경변수 CLASSPATH 를 참조하지 않는다.
JDBC 드라이버 파일은 특별한 이유로 반드시 {톰캣홈}/lib 두어야 한다.


톰캣을 재시작한 후, http://localhost:8989/empList를 방문하여 확인한다.


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


원하는 결과가 나오지 않을 때에는 아래 리스트를 체크한다.

•web.xml 파일에서 서블릿 선언과 서블릿 매핑정보가 올바른지 확인한다.
•/WEB-INF/classes/example 에 GetEmpServlet 바이트코드 있는지 확인한다.
•{톰캣홈}/lib 에 오라클 JDBC 드라이버 파일(ojdbc6.jar)이 있는지 확인한다.
•웹 애플리케이션이 성공적으로 로드되었는지 확인한다.

 

참고
http://docs.oracle.com/javaee/7/api/index.html?overview-summary.html
http://www.mkyong.com/servlet/a-simple-httpsessionlistener-example-active-sessions-counter/
http://commons.apache.org/proper/commons-fileupload/download_fileupload.cgi
http://commons.apache.org/proper/commons-io/download_io.cgi
http://commons.apache.org/proper/commons-fileupload/using.html
http://www.albumbang.com/board/board_view.jsp?board_name=free&no=292
http://www.docjar.com/docs/api/javax/servlet/GenericServlet.html
http://www.java-school.net/jsp/Servlet


 

 

 

도움이 되셨다면 공감을 부탁드립니다. ^^