13 서블릿(Servlet)

알재·2023년 7월 14일
0

JSP & Servlet

목록 보기
13/16

13.1 서블릿이란?

JSP가 나오기 전, 자바로 웹 애플리케이션을 개발할 수 있도록 만든 기술.

  • 클라이언트의 요청에 대해 동적으로 작동하는 웹 애플리케이션 컴포넌트
  • MVC 모델에서 컨트롤러 역할
  • 모든 메서드는 스레드로 동작
  • javax.sevlet.http 패키지의 HttpServlet 클래스를 상속받음

13.2 서블릿 컨테이너

서블릿을 관리하는 역할을 한다. 대표적으로 톰캣을 사용하여 서블릿의 수명주기 관리, 스레드를 생성하여 요청을 처리하고 응답을 보낼 수 있도록 통신 지원을 해줌.

  • 통신 지원 : 클라이언트와 통신하기 위해 서버가 특정 포트에 소켓을 열고, I/O 스트림을 생성하는 과정을 지원해줌
  • 수명주기 관리 : 서블릿의 인스턴스화, 초기화, 요청에 맞는 메서드 호출, 가비지 컬렉션을 통해 객체 소멸을 함
  • 멀티스레딩 관리 : 서블릿 요청을 스레드를 생성하여 처리
  • 선언적인 보안 관리 및 JSP 지원 : 보안 기능을 지원하여 별도로 구현하지 않아도 된다

13.3 서블릿 동작 방식


13.4 서블릿 작성 규칙

  • javax.servlet, javax.servlet.http, java.io 패키지를 임포트
  • 서블릿 클래스는 public로 선언, HttpServlet을 상속 받아야함
  • doGet() 메서드나 doPost() 메서드를 반드시 오버라이딩 해야함
  • doGet() 또는 doPost() 메서드는 ServletException과 IOException 예외 처리를 해야함
  • doGet() 또는 doPost() 메서드를 호출할 때의 매개변수는 HttpServletRequest와 HttpServletResponse를 사용
package 패키지명;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class 서블릿클래스명 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
            // 실행부
    }
}

13.5 서블릿 작성

  • web.xml에 기술하는 방법
  • @WebServlet 애너테이션을 사용하는 방법

13.5.1 web.xml에서 매핑

  <servlet>  <!-- 서블릿 등록 -->
    <servlet-name>서블릿명</servlet-name>
    <servlet-class>패키지를 포함한 서블릿 클래스명</servlet-class>
  </servlet>
  <servlet-mapping>  <!-- 서블릿과 요청명 매핑 -->
    <servlet-name>서블릿명</servlet-name>
    <url-pattern>클라이언트 요청 URL</url-pattern>
  </servlet-mapping>

HelloServlet.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>HelloServlet.jsp</title>
</head>
<body>
    <h2>web.xml에서 매핑 후 JSP에서 출력하기</h2>
    <p>
        <strong><%= request.getAttribute("message") %></strong>
        <br />
        <a href="./HelloServlet.do">바로가기</a>
    </p>
</body>
</html>
web.xml

  <servlet>  <!-- 서블릿 등록 -->
    <servlet-name>HelloServlet</servlet-name>
    <servlet-class>servlet.HelloServlet</servlet-class>
  </servlet>
  <servlet-mapping>  <!-- 서블릿과 요청명 매핑 -->
    <servlet-name>HelloServlet</servlet-name>
    <url-pattern>/13Servlet/HelloServlet.do</url-pattern>
  </servlet-mapping>

package servlet;

import java.io.IOException;

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

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        req.setAttribute("message", "Hello Servlet..!!");
        req.getRequestDispatcher("/13Servlet/HelloServlet.jsp").forward(req, resp);
    }
}


13.5.2 @WebServlet 애너테이션으로 매핑

AnnoMapping.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>AnnoMapping.jsp</title>
</head>
<body>
    <h2>애너테이션으로 매핑하기</h2>
    <p>
        <strong>${ message }</strong>
        <br />        
        <a href="<%= request.getContextPath() %>/13Servlet/AnnoMapping.do">바로가기</a>
    </p>
</body>
</html>


package servlet;

import java.io.IOException;

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("/13Servlet/AnnoMapping.do")
public class AnnoMapping extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        req.setAttribute("message", "@WebServlet으로 매핑");
        req.getRequestDispatcher("/13Servlet/AnnoMapping.jsp").forward(req, resp);
    }
}


13.5.3 JSP 없이 서블릿에서 바로 응답 출력

DirectServletPrint.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>DirectServletPrint.jsp</title>
</head>
<body>
    <h2>web.xml에서 매핑 후 Servlet에서 직접 출력하기</h2>
    <form method="post" action="../13Servlet/DirectServletPrint.do">
        <input type="submit" value="바로가기" />
    </form>
</body>
</html>
web.xml

  <servlet>
    <servlet-name>DirectServletPrint</servlet-name>
    <servlet-class>servlet.DirectServletPrint</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>DirectServletPrint</servlet-name>
    <url-pattern>/13Servlet/DirectServletPrint.do</url-pattern>
  </servlet-mapping>

package servlet;

import java.io.IOException;
import java.io.PrintWriter;

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

public class DirectServletPrint extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter writer = resp.getWriter();
      
        writer.println("<html>");
        writer.println("<head><title>DirectServletPrint</title></head>");
        writer.println("<body>");
        writer.println("<h2>서블릿에서 직접 출력합니다.</h2>");
        writer.println("<p>jsp로 포워드하지 않습니다.</p>");
        writer.println("</body>");
        writer.println("</html>");
        writer.close();
    }
}


13.5.4 한 번의 매핑으로 여러 가지 요청 처리

FrontController.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>FrontController.jsp</title>
</head>
<body>
    <h3>한 번의 매핑으로 여러 가지 요청 처리하기</h3>
    ${ resultValue }
    <ol>
        <li>URI : ${ uri }</li>
        <li>요청명 : ${ commandStr }</li>
    </ol>    
    <ul>
        <li><a href="../13Servlet/regist.one">회원가입</a></li>
        <li><a href="../13Servlet/login.one">로그인</a></li>
        <li><a href="../13Servlet/freeboard.one">자유게시판</a></li>
    </ul>
</body>
</html>
FrontController.java

package servlet;

import java.io.IOException;

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("*.one")
public class FrontController extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        String uri = req.getRequestURI();
        int lastSlash = uri.lastIndexOf("/");
        String commandStr = uri.substring(lastSlash);

        if (commandStr.equals("/regist.one"))
            registFunc(req);
        else if (commandStr.equals("/login.one"))
            loginFunc(req);
        else if (commandStr.equals("/freeboard.one"))
            freeboardFunc(req);

        req.setAttribute("uri", uri);
        req.setAttribute("commandStr", commandStr); 
        req.getRequestDispatcher("/13Servlet/FrontController.jsp").forward(req, resp);
    }

    // 페이지별 처리 메서드
    void registFunc(HttpServletRequest req) {
        req.setAttribute("resultValue", "<h4>회원가입</h4>");
    }

    void loginFunc(HttpServletRequest req) {
        req.setAttribute("resultValue", "<h4>로그인</h4>");
    }

    void freeboardFunc(HttpServletRequest req) {
        req.setAttribute("resultValue", "<h4>자유게시판</h4>");
    }
}


13.5.5 서블릿의 수명주기 메서드

서블릿은 클라이언트의 요청이 들어오면 가장 먼저 서블릿 객체를 생성하고, 초기화 한후, 요청을 처리함. 마지막으로 서버를 종료할 때 서블릿 객체를 소멸함.

LifeCycle.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>LifeCycle.jsp</title>
</head>
<body>
    <script>
    function requestAction(frm, met) {
        if (met == 1) {
            frm.method = 'get';
        }
        else {
            frm.method = 'post';
        }
        frm.submit();
    }
    </script>

    <h2>서블릿 수명주기(Life Cycle) 메서드</h2>
    <form action="./LifeCycle.do">
        <input type="button" value="Get 방식 요청하기" onclick="requestAction(this.form, 1);" />
        <input type="button" value="Post 방식 요청하기" onclick="requestAction(this.form, 2);" />
    </form>
</body>
</html>
LifeCycle.java

package servlet;

import java.io.IOException;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
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("/13Servlet/LifeCycle.do")
public class LifeCycle extends HttpServlet {

    @PostConstruct
    public void myPostConstruct() {
        System.out.println("myPostConstruct() 호출");
    }

    @Override
    public void init() throws ServletException {
        System.out.println("init() 호출");
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        System.out.println("service() 호출");
        super.service(req, resp);
    }        

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
        System.out.println("doGet() 호출");
        req.getRequestDispatcher("/13Servlet/LifeCycle.jsp").forward(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
        System.out.println("doPost() 호출");
        req.getRequestDispatcher("/13Servlet/LifeCycle.jsp").forward(req, resp);
    }

    @Override
    public void destroy() {
        System.out.println("destroy() 호출");
    }

    @PreDestroy
    public void myPreDestroy() {
        System.out.println("myPreDestroy() 호출");
    }
}


13.6 MVC 패턴을 적용한 회원인증 구현

13.6.1 뷰(JSP)

MemberAuth.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>MemberAuth.jsp</title>
</head>
<body>
    <h2>MVC 패턴으로 회원인증하기</h2>
    <p>
        <strong>${ authMessage }</strong>
        <br />        
        <a href="./MemberAuth.mvc?id=nakja&pass=1234">회원인증(관리자)</a>
        &nbsp;&nbsp;
        <a href="./MemberAuth.mvc?id=musthave&pass=1234">회원인증(회원)</a>
        &nbsp;&nbsp;
        <a href="./MemberAuth.mvc?id=stranger&pass=1234">회원인증(비회원)</a>
    </p>
</body>
</html>

13.6.2 컨트롤러(서블릿)

web.xml

  <servlet>
    <servlet-name>MemberAuth</servlet-name>
    <servlet-class>servlet.MemberAuth</servlet-class>
    <init-param>
      <param-name>admin_id</param-name>
      <param-value>nakja</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>MemberAuth</servlet-name>
    <url-pattern>/13Servlet/MemberAuth.mvc</url-pattern>
  </servlet-mapping>
MemberAuth.java

package servlet;

import java.io.IOException;

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

import membership.MemberDAO;
import membership.MemberDTO;

public class MemberAuth extends HttpServlet {
    MemberDAO dao;

    @Override
    public void init() throws ServletException {
        // application 내장 객체 얻기
        ServletContext application = this.getServletContext();

        // web.xml에서 DB 연결 정보 얻기
        String driver = application.getInitParameter("OracleDriver");
        String connectUrl = application.getInitParameter("OracleURL");
        String oId = application.getInitParameter("OracleId");
        String oPass = application.getInitParameter("OraclePwd");

        // DAO 생성
        dao = new MemberDAO(driver, connectUrl, oId, oPass);
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        // 서블릿 초기화 매개변수에서 관리자 ID 받기
        String admin_id = this.getInitParameter("admin_id");
        
        // 인증을 요청한 ID/패스워드
        String id = req.getParameter("id");
        String pass = req.getParameter("pass");

        // 회원 테이블에서 인증 요청한 ID/패스워드에 해당하는 회원 찾기
        MemberDTO memberDTO = dao.getMemberDTO(id, pass);

        // 찾은 회원의 이름에 따른 처리
        String memberName = memberDTO.getName();
        if (memberName != null) {  // 일치하는 회원 찾음
            req.setAttribute("authMessage", memberName + " 회원님 방가방가^^*");
        }
        else {  // 일치하는 회원 없음
            if (admin_id.equals(id))  // 관리자
                req.setAttribute("authMessage", admin_id + "는 최고 관리자입니다.");
            else  // 비회원
                req.setAttribute("authMessage", "귀하는 회원이 아닙니다.");
        }
        req.getRequestDispatcher("/13Servlet/MemberAuth.jsp").forward(req, resp);
    }

    @Override
    public void destroy() {
        dao.close();
    }
}

profile
저장소

0개의 댓글

관련 채용 정보