요청 포워딩 처리

요청에 대한 응답을 누가할지 선택할 수 있다.
웹 애플리케이션에 있는 다른 컴포넌트에게 처리를 위임하거나 요청을 완전히 다른 URL로 방향을 바꿀 수 있다.

1. RequestDispatcher 클래스를 이용한 forward 방법

웹 브라우저를 통해 사용자가 서블릿에 최초 요청하면 HttpServletRequest 객체가 자동으로 생성된다.
이 request 객체를 사용해 응답을 처리하는 웹 컴포넌트(서블릿, JSP, HTML)로 재요청하는 방식이다.
최초/재요청 동일한 HttpServletRequest 객체를 사용하기 때문에 URL 변동이 없다.
따라서 웹 브라우저 입장에서는 누가 처리한 것인지 알 수 없다.
또한, 동일한 객체를 사용하기 때문에 최초 요청시 request scope에 attribute를 설정하면 재요청시 설정된 attribute 값을 가져올 수 있다.

1
2
RequestDispatcher dispatcher = request.getRequestDispatcher(target);
dispatcher.forward(request, response);
cs

2. HttpServletResponse 클래스를 이용한 redirect 방법

forward 방식과 동일하게 다른 웹 컴포넌트에게 재요청하는 방식이다.
차이점은 최초 요청에 대한 응답시 HttpServletResponse 객체의 상태코드 헤더에 301 값과 Location 헤더에 새로운 URL 값을 포함시킨다.
웹 브라우저는 응답받은 URL로 재요청하기 때문에 동일한 HttpServletRequest가 아닌 새로운 request 객체가 생성된다.
따라서 URL이 변경되고 attribute에 설정된 값을 가져올 수 없다.

1
response.sendRedirect(target);
cs


JDBC 오라클 데이터베이스 연동하기


먼저 오라클 데이터베이스 설치하여 emp 테이블을 생성한 전제로 진행한다. (다운로드 - www.oracle.com)
오라클 드라이버를 클래스 패스에 설정해야 자바 애플리케이션과 오라클 데이터베이스를 연동할 수 있다.
[Windows]-[Preferences]-[Java]-[Build Path]-[ClassPath Variables]에 있는 JRE_LIB 경로를 파악하여
lib\ext 디렉토리에 오라클 설치경로(C:\oraclexe\app\oracle\product\11.2.0\server\jdbc\lib)에 있는'ojdbc6_g.jar'
파일을 복사하면 자동으로 드라이버가 클래스 패스에 추가된다.

* Select 쿼리 예제

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
@WebServlet("/select")
public class SelectServlet extends HttpServlet {
 
    private static final long serialVersionUID = -2214077158028938610L;
 
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
 
        String driver = "oracle.jdbc.OracleDriver"// 오라클 드라이버 클래스 파일명
        String url = "jdbc:oracle:thin:@localhost:1521:XE"// 오라클 위치,포트번호,DB정보
        String id = "root"// 오라클 접속 계정
        String password = "1234"// 오라클 접속 비밀번호
 
        Connection con = null;
        Statement stmt = null;
        ResultSet rs = null;
        String result = null;
        
        try {
            Class.forName(driver); // 드라이버 로딩
            con = DriverManager.getConnection(url, id, password); // DB 커넥션 맺기
 
            String sql = "select eid, ename, salary from emp";
            stmt = con.createStatement();
            rs = stmt.executeQuery(sql);
 
            while (rs.next()) {
                String eid = rs.getString("eid");
                String ename = rs.getString("ename");
                int salary = rs.getInt("salary");
                result  = eid + " " + ename + " " + salary;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try { // 자원 반납
                if (rs != null)
                    rs.close();
                if (stmt != null)
                    stmt.close();
                if (con != null)
                    con.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
 
        request.setAttribute(result, result);
        response.setCharacterEncoding("UTF-8");
        request.getRequestDispatcher("/select.jsp").forward(request, response);
    }
 
}
cs
Select 쿼리 요청에는 executeQuery 메소드를 사용하여 테이블 형태인 ResultSet 객체를 얻는다.
ResultSet 객체는 포인터를 이용해서 원하는 데이터를 얻을 수 있기 때문에 먼저 포인터를 이용해서 레코드를 선택하고 포인터가 가리키는 레코드의 컬럼을 지정해서 데이터를 얻는다. 레코드를 선택하는 메소드는 next()를 사용하고 컬럼은 데이터형에 맞는 get*(컬럼명)메소드를 사용한다.

파일 및 데이터베이스는 외부 자원이기 때문에 사용한 후에는 반드시 자원을 해제시켜야 된다. 해제시킬 때에는 사용한 역순으로 해제시킨다.
예외 발생 여부에 관계없이 항상 자원을 반납해야하므로 finally 문에 코드를 구현하도록 한다.

* Update 쿼리 예제

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
@WebServlet("/update")
public class UpdateServlet extends HttpServlet {
 
    private static final long serialVersionUID = -2214077158028938610L;
 
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
 
        request.setCharacterEncoding("UTF-8");
        String eid = request.getParameter("eid");
        String ename = request.getParameter("ename");
        int salary = Integer.parseInt(request.getParameter("salary"));
        
        String driver = "oracle.jdbc.OracleDriver";
        String url = "jdbc:oracle:thin:@localhost:1521:XE";
        String id = "root";
        String password = "1234";
        
        Connection con = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        
        try {
            Class.forName(driver);
            con = DriverManager.getConnection(url, id, password);
        
            String sql = "update emp set ename = ?, salary = ? where eid = ?";
            pstmt = con.prepareStatement(sql);
            pstmt.setString(1, ename);
            pstmt.setInt(2, salary);
            pstmt.setString(3, eid);
            
            int count = pstmt.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (rs != null)
                    rs.close();
                if (pstmt != null)
                    pstmt.close();
                if (con != null)
                    con.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        response.setCharacterEncoding("UTF-8");
        response.sendRedirect("/select?eid=" + eid);
    }
    
}
cs
PrepareStatement 객체를 이용하면 SQL 문을 먼저 작성하고 나중에 필요한 데이터를 설정할 수 있다.
set 메소드를 이용해 인덱스에 값을 지정한다. 인덱스는 작성한 SQL 문에 있는 '?' 심벌의 순서를 의미한다. 
'?' 심벌 수와 set 메소드 수는 같아야 한다.

DML(Insert, Update, Delete) 쿼리 요청에는 executeUpdate 메소드를 사용하여 데이터를 처리하고 변경된 레코드의 개수를 얻는다.


어노테이션을 이용한 초기화파라미터/리스너/필터 등록하기


어노테이션을 사용하기 위해 프로젝트의 웹 모듈 버전은 3.0 이상으로 설정해야 한다.

ServletConfig API를 활용한 초기화 파라미터 사용
초기화 파라미터는 여러 서블릿에서 공유해서 사용하지 못하고 등록된 서블릿에서만 사용할 수 있다.
(웹 애플리케이션 범위의 초기화 파라미터를 사용하려면 ServletContext API를 사용해야 한다.)

1
2
3
4
5
6
7
8
9
10
11
@WebServlet(name = "init", urlPatterns = { "/init" }, initParams = {
@WebInitParam(name = "dirPath", value = "D:\\test"), @WebInitParam(name = "id", value = "root") })
public class AnnoInitParam extends HttpServlet {
 
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
throws ServletException, IOException {
        System.out.println(getInitParameter("dirPath")); // d:\\test
        System.out.println(getInitParameter("id"));      // root
    }
 
}
cs

ServletContextListener API
웹 애플리케이션도 서블릿처럼 라이프사이클을 가진다. 톰캣 컨테이너가 시작될 때 웹 애플리케이션도 초기화되고, 톰캣 컨테이너가 종료될 때 웹애플리케이션도 제거된다. ServletContextListener API를 사용하면 언제 초기화되고 제거 되는지를 쉽게 알 수 있다.
ex) JDBC Pooling - 웹 애플리케이션이 초기화될 때 Pooling을 활성화하고, 제거될 때 비활성화 시키면 효율적인 Connection 관리를 할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@WebListener
public class ContextListener implements ServletContextListener {
    
    @Override
    public void contextDestroyed(ServletContextEvent e) {
        System.out.println("웹 애플리케이션 종료");
    }
 
    @Override
    public void contextInitialized(ServletContextEvent e) {
        System.out.println("웹 애플리케이션 초기화");        
    }
 
}
cs

Filter API
클라이언트인 웹 브라우저와 웹 서버인 서블릿은 요청과 응답을 주고 받는다. Filter API를 사용하면 웹 브라우저에서 서블릿으로의 요청 전에 선처리와
서블릿에서 웹 브라우저로의 응답 전에 후처리가 가능하다. 또한, 다수의 필터를 체인처럼 묶어서 적용할 수 있다.

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
@WebFilter(urlPatterns = "/*")
public class AnnoFilter implements Filter {
 
    @Override
    public void destroy() {
        System.out.println("필터 제거");
    }
 
    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("선처리 요청필터");
        req.setCharacterEncoding("UTF-8");
        
        chain.doFilter(req, resp); // 선.후처리 기준점
        
        System.out.println("후처리 응답필터");
        resp.setCharacterEncoding("UTF-8");
    }
 
    @Override
    public void init(FilterConfig config) throws ServletException {
        System.out.println("필터 초기화");
    }
    
}
cs


서블릿 한글 깨짐 방지


HTML에서 입력한 파라미터 값에 한글이 포함되어 있다면 한글 인코딩 작업을 해야한다.
브라우저에서 문자를 처리하는 방식과 서버에서 문자를 처리하는 방식이 일치해야 한글이 깨지지 않는다.
톰캣서버의 기본문자 처리방식은 ISO-8859-1라서 한글 인식이 제대로 되지 않는다.

요청 방식에 따라 달리 처리해줘야 한다.
POST - 파라미터 값을 얻기전에 doGet 메소드에서 request.setCharacterEncoding("UTF-8"); 메소드로 한글 인코딩을 처리한다.
GET - 톰캣 설정 파일인 server.xml을 수정해야 한다. Connector 태그에 URIEncoding="UTF-8" 값을 추가해야 한다.
        8080포트로 직접 요청한 경우 
       <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8"/>
        아파치에서 톰캣 커넥터를 통해 톰캣을 연결한 경우
        <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/>

어노테이션을 이용한 Servlet Project 시작하기


웹 프로젝트를 하기에 앞서 http://tomcat.apache.org 사이트에서 톰캣을 다운로드해 설치해야 한다. 또한 Java Enterprise Edition을 사용해야 한다.

어노테이션을 사용하기 위해 Dynamic Web Project를 생성할 때 웹 모듈 버전은 3.0 이상으로 설정한다.

'http://localhost:포트번호/컨텍스트명/맵핑명' 형식으로 요청하기 때문에 컨텍스트명은 생략해주는 것이 좋다. (server.xml에서 수정 가능하다.)

프로젝트 라이브러리에 톰캣이 안잡혔다면 다운로드 받은 톰캣의 lib 디렉토리에서 servlet-api.jar, jsp-api.jar 파일을 추가해줘야 한다.

간단한 요청을 구현하기 위해 Java Resources/src 경로에 서블릿 클래스를 생성한다.

1
2
3
4
5
6
7
8
9
10
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setCharacterEncoding("UTF-8");
        request.getRequestDispatcher("hello.jsp").include(request, response);
    }
    
}

cs

@WebServlet에 맵핑명을 지정한다. 배열로 여러개의 맵핑명을 지정할 수도 있다. (web.xml에 매핑하는 것보다 편하고 직관적이다.)
보여줄 페이지의 한글 깨짐을 방지하기 위해 인코딩방식을 UTF-8로 설정한다.
WebContent 하위 경로에 jsp 파일을 생성하고 해당 경로로 매핑해준다.

그리고 톰캣으로 Run하게되면 Servers 탭에 톰캣이 추가되고 더블클릭하면 다음과 같은 화면이 나온다.
8080포트의 충돌을 방지하기 위해 포트번호를 변경해준다.

http://localhost:8090/hello URL을 요청하면 서블릿 요청을 거쳐 다음과 같이 hello.jsp 화면을 출력한다.


+ Recent posts