Back-end/JSP

Servlet 기초

메델 2023. 1. 21. 14:54

6장 Servlet 기초 

WAS(Web Application Server)가 처음 등장했을 때 웹 브라우저의 요청을 스레드 방식으로 처리하는 기술이 Servlet이다. 모든 웹 프로그램은 아래에서 서술한 기능을 바탕으로 동작한다. 

 

(1) Servlet의 세 가지 기본 기능

Client로부터 요청을 받아 비즈니스 로직을 처리하고 결과를 다시 클라이언트에게 돌려주는 과정

 

  1. Client로부터 요청을 받는다.
  2. DB 연동과 같은 비즈니스 로직 처리
  3. 처리된 결과를 Client에게 돌려준다.

Servlet의 세 가지 주요 기능

ex. 로그인 과정

 

1. 사용자가 입력한 ID와 PW가 Server 쪽 Servlet으로 전송

Servlet은 메서드를 이용해 사용자가 전송한 ID와 PW를 받아 온다. 

2. 사용자의 로그인 요청에 따라 DB와 연동해 사용자가 등록된 회원인지 확인

3. 그  결과에 따라서 다음 페이지로 가던지 ID/PW가 틀렸으니 다시 로그인하라는 오류메시지는 전송

 

(2) Servlet 응답과 요청 수행 API 기능 

 

  • 요청과 관련된 API : javax.servlet.http.HttpServletRequest 클래스
  • 응답과 관련된 API: javax.servlet.http.HttpServletResponse 클래스

→ 요청이나 응답과 관련된 API는 모두 javax.servlet.http 패키지에 존재

 

  • Client가 Servlet에 요청하면 먼저 Tomcat 컨테이너가 받음
  • 사용자의 요청이나 응답에 관한 HttpServletRequst객체와 HttpServletResponse 객체를 만들고 Servlet의 doGet()/doPost() 메소드를 호출하면서 객체들을 전달

 

→ Tomcat이 사용자의 요청에 대한 정보를 모든 HttpServletRequest 객체의 속성으로 담아 메서드로 전달하므로 각 HttpServletRequst에서 제공하는 메서드들은 매개변수로 넘어온 객체들을 이용하여 사용자가 전송한 데이터를 받아 오거나 응답할 수 있는 것 

 

HttpServletRequest 의 여러가지 메서드 

 

반환형 메서드 이름 기능
boolean authenticate(HttpServletResponse response)  현재 요청한 사용자가 ServletContext 객체에 대한 인증을 하기 위한 컨테이너 로그인 메커니즘을 사용
String changeSessionId() 현재 요청과 연관된 현재 세션의 id를 변경하여 새 세션 id를 반환
String  getContextPath() 요청한 컨텍스트를 가리키는 URI를 반환
Cookie[] getCookies() 클라이언트가 현재의 요청과 함께 보낸 쿠키 객체들에 대한 배열을 반환 
String getHeader(String name) 특정 요청에 대한 헤더 정보를 문자열로 반환
Enumeration <String> getHeaderNames() 현재의 요청에 포함된 헤더의 name 속성을 enumeration으로 반환
String getMethod() 현재 요청이 GET, POST 또는 PUT 방식 중 어떤 HTTP 요청인지 반환
String getRequestURI() 요청한 URL의 컨텍스트 이름과 파일 경로까지 반환
String getServletPath() 요청한 URL에서 서블릿이나 JSP 이름 반환
HttpSession getSession() 현재의 요청과 연관된 세션을 반환합니다. 만약 세선이 없다면 새로 만들어 반환

 

HttpServletResponse 의 여러가지 메서드 

 

반환형 메서드 이름  기능
void addCookie(Cookie cookie) 응답에 쿠키를 추가
void addHeader(String name, String value) name과 value를 헤더에 추가
String  encodeURL(String url) 클라이언트가 쿠키를 지원하지 않을 때 세션 id를 포함한 특정 URL을 인코딩
Collection <String> getHeaderNames() 현재 응답의 헤더에 포함된 name을 얻어옴
void sendRedirect(String location) 클라이언트에게 redirect 응답을 보낸 후 특정 URL로 다시 요청
String  getPathInfo() 클라이언트가 요청 시 보낸 URL과 관련된 추가 경로 정보를 반환

 

(3) <form> 태그로 Servlet에 요청하는 과정 

 

: Servlet과 JSP은 HTML, CSS, JavaScript 기능에 자신의 기능을 추가하여 서로 연동하여 동작한다. 

사용자의 요청은 HTML의 <form> 태그나 JavaScript로 부터 전송 받아 처리 

 

클라이언트 웹 브라우저에서 Servlet에 요청하는 방법

 

  1. 웹 브라우저에서 여러 가지 입력 서식을 이용해 전송을 클릭하면 사용자가 입력한 데이터가 Servlet으로 전송
  2. Servlet은 여러 가지 메서드를 이용해서 전송된 데이터를 받음 

 

클라이언트가 서블릿에 요청하는 방법

 

<form> 태그의 여러 가지 속성

 

속성 기능
name <form> 태그의 이름을 지정
여러 개의 form이 존재할 경우 구분하는 역할
JavaScript에서 <form>태그에 접근할 때 많이 사용 
method <form> 태그 안에서 데이터를 전송할 때 전송 방법 지정
GET/POST로 (아무것도 지정하지 않으면 GET)
action <form> 태그에서 데이터를 전송할 Servlet이나 JSP를 지정
Servlet으로 전송할 떄는 매핑 이름 사용
encType <form> 태그에서 전송할 데이터의 encoding 타입을 지정
파일을 업로드할 때는 multipart/form-data 지정

 

<form> 태그 데이터가 전송되는 과정

 

사용자의 로그인 창의 HTML 태그의 구조는 아래와 같다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
</head>
<body>
  <form name="frmLogin" method="get" action="login" enctype="UTF-8">
    ID:<input type="text" name="user_id"><br>
    PW:<input type="password" name="user_pw"><br>
    <input type="submit" value="로그인"><input type="reset" value="다시 입력">
  </form>
</body>
</html>

 

  • 사용자가 ID,PW를 입력한 후 로그인을 클릭
  • <form> 태그의 action 속성은 데이터를 전송할 Servlet이나 JSP의 이름을 지정
  • 지정된 이름이 login인 Servlet으로 ID와 비밀번호 전송 
  • 실제 데이터틑 <input> 태그의 name 속성 값과 쌍으로 전송 
  • Servlet에서 name 속성 값으로  같이 전송된 입력 데이터를 받아 옴

 

<form> 태그 데이터가 전송되는 과정

 

<form> 태그로 전송된 데이터를 받아 오는 메서드

 

메서드 기능
String getParameter(String name) name의 값을 알고 있을 때 그리고 name에 대한 전송된 값을 받아올 떄 사용 
String[] getParameterValues(String name) 같은 name에 대해 여러 개의 값을 얻을 때 사용
Enumeration getParameterNames() name 값을 모를 때 사용 

 

여러 개의 값을 전송할 때의 요청 처리

:  한 개씩 전송된 값은 getParameter() 이용, 하나의 name으로 여러 값을 전송하는 경우 getParameterValues()를 이용해 배열 형태로 반환

 

input.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>여러 가지 input 타입 표시창</title>
</head>
<body>
    <form name="frmInput" method="get" action="input">
      id: <input type="text" name="user_id"><br>
      pw: <input type="password" name="user_pw"><br>

      <input type="checkbox" name="subject" value="java" checked> 자바
      <input type="checkbox" name="subject" value="C언어"> C언어
      <input type="checkbox" name="subject" value="JSP"> JSP
      <input type="checkbox" name="subject" value="안드로이드"> 안드로이드
      <br><br>
      <input type="submit" value="전송">
      <input type="reset" value="초기화">
    </form>

</body>
</html>

InputSevlet.java

 

package sec01.ex01;

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

@WebServlet("/input")
public class InputServlet extends HttpServlet {
    public void init() throws SecurityException{
        System.out.println("init 메서드 호출");
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");

        String user_id = request.getParameter("user_id");
        String user_pw = request.getParameter("user_pw");

        System.out.println("ID: "+ user_id);
        System.out.println("PW: "+ user_pw);
        String[] subject = request.getParameterValues("subject");
        // 하나의 name 으로 여러 값을 전송하는 경우 getParameterValues()를 이용해 배열 형태 반환
        for(String str : subject){
            System.out.println("선택한 과목:"+ str);
        }
    }
    public void destroy(){
        System.out.println("destroy 메서드 호출");
    }
}

 

 

 

 

 

 

 

getParameterNames() 메서드를 이용한 요청처리

: servlet에서 getParameter() 메서드를 이용해서 많은 정보를 처리하면 각 매개 변수를 모두 알아야한다. 전송할 데이터가 많아 name의 값을 모두 기억하기 어려울 때 getParameterNames() 메서드를 이용하면 편리하다.

 

InputSevlet2.java

package sec01.ex01;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;


@WebServlet("/input2")
public class InputServlet2 extends HttpServlet {

    public void init() throws ServletException{
        System.out.println("init 메서드 호출");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        request.setCharacterEncoding("utf-8");
        Enumeration enu = request.getParameterNames();
        //전송 온 name 속성들만 Enumeration 타입으로 받아온다.

        while (enu.hasMoreElements()){
            // 각 name을 하나씩 가져와 대응해서 전송되어 온 값 출력
            
            String name = (String) enu.nextElement();
            String[] values = request.getParameterValues(name);
            for(String value : values){
                System.out.println("name="+ name+",value="+value);
            }
        }
    }
    public void destroy(){
        System.out.println("destroy 메서드 호출");
    }
}

 

getParameterNames()를 이용해 전송된 name과 값이 모두 출력된 것을 확인 할 수 있다.

 

 

(4) Servlet의 응답 처리 방법

-응답 처리-

doGet()/doPost() 매서드 안에서 처리

javax.servlet.http.HttpServletResponse 객체 이용

setContentType()을 이용해 클라이언트에게 전송할 데이터 종류(MIME-TYPE)를 지정

 

-응답 과정-

Client(웹 브라우저)와 Servlet의 통신은 자바 I/O의 스트림 이용

 

1. MIME-TYPE(마임타입)

 

서버(Servlet)에서 자바 I/O의 스트림 클래스를 이용하여 웹 브라우저로 데이터를 전송할 때는 MIME-TYPE을 설정해서 전송할 데이터의 종류를 지정

 

ex.

HTML로 전송: text/html

일반 텍스트로 전송: text/plain

XML 데이터로 전송: application/xml

 

이외에도  톰캣 컨테이너에서 자주 사용하는 데이터 종류를 MIME-TYPE으로 지정해 놓았으므로 서블릿에서 종류를 지정해서 사용하면 된다. 새로운 종류의  데이터 지정시 web.xml에 추가하면 된다.

 

2. HttpServletResponse를 이용한 Servlet 응답 과정

 

setContentType()을 이용해 MIME-TYPE을 지정 → 데이터를 출력한 PrintWriter 객체를 생성 → 출력 데이터를 HTML 형식으로 만듦 → PrintWriter의 print()나 println()을 이용해 데이터를 출력 

 

package sec01.ex01;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/login2")
public class LoginServlet2 extends HttpServlet {
    public void init() throws ServletException{
        System.out.println("init 메서드 호출");
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8"); // 웹 브라우저에서 전송된 데이터의 인코딩을 설정
        response.setContentType("text/html;charset=utf-8"); //setContentType()을 이용해 응답할 데이터의 종류가 HTML임을 설정
        PrintWriter out = response.getWriter();
        String id = request.getParameter("user_id");
        String pw = request.getParameter("user_pw");


        //브라우저로 출력할 데이터를 문자열로 연결해서 html 태그로 만듦

        String data = "<html>";
        data += "<body>";
        data += "아이디 : " + id;
        data += "<br>";
        data += "패스워드 :" + pw;
        data += "</body>";
        data += "</html>";
        out.println(data); // PrintWriter의 print()를 이용해 HTML 태그 문자열을 웹 브라우저로 출력
    }

    public void destroy(){
        System.out.println("destroy 메서드 호출");
    }
}

 

 

위와 같이 서블릿이 ID와 비밀번호를 전달받아 브라우저로 출력하는 것을 볼 수 있다.

 

(5) 웹 브라우저에서 Servlet으로 데이터 전송

 

GET/POST 전송 방식

GET 방식 POST 방식
servlet에 데이터를 전송할 때는 데이터가 URL 뒤에 name=value 형태로 전송
여러 개의 데이터를 전송할 때는 '&'로 구분해서 전송
보안이 취약
전송할 수 있는 데이터는 최대 255자 
기존 전송 방식이고 사용이 쉽다
웹 브라우저에 직접 입력해서 전송할 수도 있다
servlet에서 doGet() 을 이용해 데이터를 처리
Servlet에서 데이터를 전송할때 TCP/IP 프로토콜 데이터의 body 영역에 숨겨진 채 전송
보안에 유리
전송 데이터 용량 무제한
전송시 Servlet에서는  또 다시 가져오는 작업을 해야 하므로 처리 속도가 GET 방식보다 느림
Servlet에서 doPost()를 이용해 데이터 처리

 

Servlet에서는 웹 브라우저에서 전송되는 방식에 따라 doGet()이나 doPost() 메서드로 대응해서 처리

전송방식과 다른 메서드를 사용하면 브라우저에서 아래와 같은 오류가 발생한다.

 

 

이 두 방식으로 전송된 데이터는 반드시 HttpServlet에서 오버라이딩된 doGet() 메서드나 doPost()를 사용해야한다.

메서드가 서블릿에 존재하지 않거나 사용자가 임의로 만든 메서드를 사용하면 오류 발생

 

GET과 POST 방식 요청 동시에 처리

 

login4.html 

 

(1) method="get"

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
</head>
<body>
  <form name="frmLogin" method="get" action="login4" enctype="UTF-8">
    ID:<input type="text" name="user_id"><br>
    PW:<input type="password" name="user_pw"><br>
    <input type="submit" value="로그인"><input type="reset" value="다시 입력">
  </form>
</body>
</html>

 

(2) method="post"

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
</head>
<body>
  <form name="frmLogin" method="post" action="login4" enctype="UTF-8">
    ID:<input type="text" name="user_id"><br>
    PW:<input type="password" name="user_pw"><br>
    <input type="submit" value="로그인"><input type="reset" value="다시 입력">
  </form>
</body>
</html>

 

loginServlet4.java

package sec03.ex01;


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

@WebServlet("/login4")
public class LoginServlet4 extends HttpServlet {
    public void init() throws ServletException {
        System.out.println("init 메서드 호출");
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        System.out.println("doGet 메서드 호출");
        doHandle(request, response); // GET 방식으로 요청시 다시 doHandle()를 호출
    }

    protected  void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        System.out.println("doPost 메서드  호출");
        doHandle(request, response); // POST 방식으로 요청시 다시 doHandle()를 호출
    }
    private void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        // 모든 방식으로 처리 가능

        request.setCharacterEncoding("utf-8");
        String user_id = request.getParameter("user_id");
        System.out.println("doHandle 메서드 호출");

        String user_pw = request.getParameter("user_pw");
        System.out.println("ID: "+ user_id);
        System.out.println("PW: "+ user_pw);

    }
    public void destroy(){
        System.out.println("destroy 메서드 호출");
    }

}

 

(6) JavaScript에서 Servlet 요청

전송 데이터에 대한 유효성 검사를 구현하기 위해서 자바스크립로 서블릿 요청

 

login5.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <script type="text/javascript">
      function fn_validate(){
        var frmLogin = document.frmLogin;

        var user_id = frmLogin.user_id.value;
        var user_pw = frmLogin.user_pw.value;

        if((user_id.length == 0 || user_id =="")|| (user_pw.length == 0 || user_pw =="")){
          alert("아이디랑 비밀번호 필수");
        }else{
          frmLogin.method="post"; // <form> 태그의 전송 방식을 post로 설정
          frmLogin.action ="login5"; // action 속성을 서블릿 매핑 이름인 login5로 설정
          frmLogin.submit(); // 자바스크립트에서 서블릿으로 전송
        }
      }
    </script>
    <title>로그인창</title>
</head>
<body>
    <form name="frmLogin" method="post" action="login" enctype="UTF-8">
      ID: <input type="text" name="user_id"><br>
      PW: <input type="text" name="user_pw"><br>
      <input type="button" onClick="fn_validate()" value="로그인">
      <input type="reset" value="다시 입력">
      <input type="hidden" name="user_address" value="서울시 성북구"/>

    </form>

</body>
</html>

 

LoginServlet5.java

package sec03.ex01;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;


@WebServlet("/login5")
public class LoginServlet5 extends HttpServlet {
    public void init() throws ServletException {
        System.out.println("init 메서드 호출");
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8"); // 웹 브라우저에서 전송된 데이터의 인코딩을 설정
        response.setContentType("text/html;charset=utf-8"); //setContentType()을 이용해 응답할 데이터의 종류가 HTML임을 설정
        PrintWriter out = response.getWriter();
        String id = request.getParameter("user_id");
        String pw = request.getParameter("user_pw");
        String address = request.getParameter("user_address");
        System.out.println("id: "+id);
        System.out.println("pw: "+ pw);

        //브라우저로 출력할 데이터를 문자열로 연결해서 html 태그로 만듦

        String data = "<html>";
        data += "<body>";
        data += "아이디 : " + id;
        data += "<br>";
        data += "패스워드 :" + pw;
        data += "<br>";
        data += "주소 :" + address;
        data += "</body>";
        data += "</html>";
        out.println(data); // PrintWriter의 print()를 이용해 HTML 태그 문자열을 웹 브라우저로 출력
    }

    public void destroy(){
        System.out.println("destroy 메서드 호출");
    }
}

 

 

 

 

 

(참고: 자바 웹을 다루는 기술)

'Back-end > JSP' 카테고리의 다른 글

Servlet 비즈니스 로직 처리  (0) 2023.01.24
Servlet 이란?  (0) 2023.01.20
웹 애플리케이션  (0) 2023.01.19
프로그램의 발전 과정, 웹 프로그래밍과 JSP  (0) 2023.01.19