본문 바로가기

Server/Servlet & JSP

JSP 기본 개념 - 1

  • JSP란?
    - JSP(Java Server Page) : Java 코드가 들어있는 HTML 코드
    - Java의 웹 서버 프로그램 스펙(Servlet)으로 변환되어 서비스 됨

  • Servlet과 JSP의 차이점
    - Servlet
    : 웹 서비스 기능을 해주는 자바 클래스를 말하는 것으로,
      자바 소스코드 안에 HTML 코드가 들어가는 형태
      → HTML 문서를 작성하는데 복잡하고 번거로움

    - JSP
    : 복잡한 Servlet을 조금 더 간단히 사용할 수 있음
      Servlet과 반대로 HTML 소스코드 안에
      자바 소스코드(scripting element/스크립팅 원소: <% %> / <%= %>)가 들어가는 형태
      컴파일을 통해 .class 파일로 변환되어 웹 서버(WAS)에서 실행됨

  • Servlet / JSP 동작 순서
    1) 웹 서버가 사용자로부터 Servlet에 대한 요청을 받으면 Servlet Container에 그 요청을 전달함
    2) 요청을 받은 Servlet Container는 HttpRequest와 HttpResponse 객체를 만들어
        이를 Servlet doPost( )나 doGet( ) 메소드 중 하나를 호출
    3) 클라이언트가 요청에 대한 응답 웹 페이지를 보여줄 때
        기존 Servlet에서 출력 객체를 이용하여 HTML 문서를 작성하는 부분(프리젠테이션 로직)을
        JSP로 분리함 → 데이터의 입력, 수정 등에 대한 제어를 JSP로 넘겨 가독성을 높임
    4) JSP가 전달 받은 프리젠테이션 로직을 수행한 후 Servlet Container에게 Response 전달
    5) 전달 받은 JSP 프리젠테이션 로직 수행 결과와 Servlet이 결합되어 .class 파일이 만들어짐

JSP 동작 구조

  • JSP 장점
    - Servlet보다 쉽고 작성하기 빠름
    - 디자인 파트(HTML)와 로직 파트(Java)로 이루어져 있음
      정보, 디자인 파트(HTML)와 로직 파트(Java)를 분리할 수도 있음
    - 프로그래머가 직접 코딩한 Servlet보다 최적화된 Servlet으로 생성시켜주므로 효율적인 코드가 만들어짐
    - 웹 애플리케이션 상에서 변수의 사용 가능한 범위(scope) 설정이 쉬움

  • JSP를 이루는 기본 구성인자(element)
    1. 지시어(directive)
    1) page : 현재 JSP 페이지를 Container에서 처리하는데 필요한 각종 속성을 기술하는 부분
                   보통 소스의 맨 앞에 위치
                   <%@ page 속성1="속성값1" 속성2="속성값2" ... %>
    page 지시어 속성 종류
    - contenttype : MIME 형식 지정 및 캐릭터셋 설정
      ( contentType="text/html; charset=UTF-8" )
    - pageEncoding : JSP 파일(페이지)에 기록된 소스코드 자체의 인코딩 방식
      ( pageEncoding="UTF-8" )

    2. 스크립팅 원소(scripting element)
    : JSP 페이지에서 Java 코드를 직접 기술할 수 있게 하는 기능
    1) 선언문(declaration)
    <%! Java 코드 %>
    2) 스크립틀릿(scriptlet)
    <% Java 코드 %>
    3) 출력식, 표현식(expression)
    <%= Java 코드 %>

  • JSP 페이지에서 사용할 수 있는 내장객체변수의 종류
    - 일반적인 Java 프로그램에서는 변수를 사용하기 전에 반드시 선언을 해야 하지만,
      JSP 페이지에서는 선언을 하지 않고도 사용 가능한 변수가 있음
      → 이러한 변수를 JSP 페이지의 "내장객체변수(implicit variable)"라고 함
    ※ Web-Container(= WAS, TomCat 서버)가 JSP 페이지를 Servlet 클래스로 변환해줄 때,
        변수 선언을 자동으로 해주기 때문에 변수 선언 없이 사용 가능함
    1) request
    : doGet, doPost 메소드의 첫 번째 파라미터와 동일한 역할을 수행
      웹 클라이언트에서 보내온 데이터 값을 받아서 처리하는 변수
      데이터 저장소 역할이 가능함

    2) response
    : doGet, doPost 메소드의 두 번째 파라미터와 동일한 역할을 수행
      웹 클라이언트의 요청에 대한 응답 결과 처리를 위한 변수

  • JSP 기본 예제 - 1 : 로그인 기본 화면 동작 (아이디 비밀번호)

- index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JSP Project</title>
</head>
<body>
    <h3>Get 방식 요청</h3>
    <form action="/JSPProject/login" method="get">
        <!-- 요청 주소 : /JSPProject/login 
             데이터 전달 방식 : get (주소 뒤에 데이터가 붙어서 전달됨) -->
        ID : <input type="text" name="inputId"><br>
        PW : <input type="password" name="inputPw"><br>
        <button>로그인</button>
    </form>
</body>
</html>

- Servlet Container

package edu.kh.jsp.controller;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
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("요청 주소") 어노테이션
// - 해당 클래스를 Servlet 클래스로 등록하고(== web.xml의 <servlet> 태그)
//   어떤 요청 주소를 처리할지 지정함(== web.xml의 <servlet-mapping> 태그)
@WebServlet("/login")
public class LoginServlet extends HttpServlet {

	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 요청 시 전달된 input 태그의 값(== Parameter) 얻어오기
		// ★ 파라미터는 모두 String 타입
		String inputId = req.getParameter("inputId");
		String inputPw = req.getParameter("inputPw");
		// 파라미터를 잘 얻어왔는지 확인
		System.out.println("ID: " + inputId);
		System.out.println("Pw: " + inputPw);
		
		String result = null;
		if(inputId.equals("user01") && inputPw.equals("pass01!")) {
			result = inputId + "님이 로그인 하셨습니다.";
		} else {
			result = "아이디 또는 비밀번호가 일치하지 않습니다.";
		}
		
		// out.print("<html>"); -> JSP로 교체
		
		// JSP란?(Java Server Page)
		// - Servlet에서 HTML 코드 작성이 불편함
		//   -> 반대로 HTML 코드에 Java 코드를 쓸 수 있게 하는 문서
		
		// ★ JSP 생성 폴더 위치
		// -> webapp/WEB-INF 폴더 내부에 생성
		
		//***************************************************************
		
		// ★★★ JSP로 응답하기 ★★★

		// Dispatcher : 필요한 정보를 제공하는 자 == 발송자
		// 위임 : (맡은 일을) 넘겨주다
		// forward : 전송하다, 보내다
		
		// ★ 응답 화면을 만드는 Servlet의 일을
		//   효율적으로 처리할 수 있는 JSP에게 넘겨줄 예정
		
		// RequestDispatcher
		// : Servlet -> JSP로 "HttpServletRequest 객체 / HttpServletResponse 객체"를
		//   발송(위임)하는 역할의 객체
		
		// req.getRequestDispatcher("JSP 경로");
		// - HttpServletRequest 객체가 생성될 때
		//   내부에 자동으로 요청발송자(RequestDispatcher)가 같이 생성됨(new 연산자로 생성 필요 X)
		
		// ★★★ JSP 경로 작성 규칙 ★★★
		// - ★★★webapp 폴더를 기준★★★으로 JSP 파일까지의 모든 경로 작성!!
		RequestDispatcher dispatcher = req.getRequestDispatcher("/WEB-INF/views/loginResult.jsp");
		
		// JSP에게 전송될 예정인 HttpServletRequest 객체에
		// result 변수 값을 담아서 같이 전달
		
		// req.setAttribute(String Key, Object value);
		// - key는 String(문자열)
		
		// Attribute : 속성(데이터, 값)
		req.setAttribute("res", result);
		
		// 요청 발송자를 이용하여 req, resp 객체를 전송(forward)
		dispatcher.forward(req, resp);
	}
}

- JSP

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<% // 자바 코드 작성 영역

   // Servlet으로 부터 전송 받은 req, resp가 있는 상태
   // -> req, resp 사용 가능함!
   //    대신 이름이 request, response로 바뀜
   
   // getAttribute("key값");
   // 반환형 Object이기 때문에 원래 타입으로 강제 형변환!
   String r = (String)request.getAttribute("res");

%>    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그인 결과 화면</title>
</head>
<body>
	<!-- 위에서 선언된 변수 r에 저장된 값 출력 -->
	<h1><%= r %></h1>
</body>
</html>

- 결과 화면

로그인 조건 일치하는 경우
Get 방식 : URL로 입력한 값을 서버로 전달
로그인 조건 일치하지 않는 경우


  • JSP 기본 예제 - 2 : 피자 주문

- index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JSP Project</title>
</head>
<body>
    <h3>Servlet/JSP로 페이지 이동</h3>
    <!-- 서버 요청 주소 작성 -->
    <!-- 
    	GET 방식 요청 종류 : a태그, JS(location), 직접 주소 작성, form태그 method="get" 
     -->
	<a href="/JSPProject/pizza/order">피자 주문하기</a>
</body>
</html>

- Servlet Container

package edu.kh.jsp.controller;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
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("/pizza/order")
public class PizzaOrderServlet extends HttpServlet{
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// a태그 요청 == Get 방식
		
		// 별도의 처리 없이 바로 JSP로 요청 위임
		
		// RequestDispatcher : 요청 발송자
		// -> 지정된 JSP로 요청 정보(HttpServletRequest), 응답 정보(HttpServletResponse)를
		//    전송(발송)하는 역할
		
		// JSP 경로는 webapp을 기준으로 작성함!!
		//RequestDispatcher dispatcher = req.getRequestDispatcher("JSP 경로");
		RequestDispatcher dispatcher = req.getRequestDispatcher("/WEB-INF/views/pizza_order.jsp");
		
		// forward : 보내다, 전송하다
		// -> JSP로 요청, 응답을 보내는 기능
		dispatcher.forward(req, resp);
	}
	
	// form태그 POST 방식 제출 시
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		// ★★★ POST 방식의 한글 깨짐 문제 ★★★
		// - 데이터 전달 방식 차이점
		// GET : 주소(URL)를 통해서 데이터 전달
		//       이 때, 문자 인코딩은 제출된 HTML파일의 문자 인코딩(charset)을 따름
		
		// POST : HTTP Body를 통해서 데이터 전달
		//        이 때, 문자 인코딩은 서버의 기본 문자 인코딩을 따름
		//        우리 서버(Tomcat) -> ISO-8859-1이 기본 문자 인코딩
		// ★ 해결 방법 ★
		// - POST 방식으로 전달 받은 데이터의 문자 인코딩을 UTF-8로 변경
		req.setCharacterEncoding("UTF-8");
		
		String pizza = req.getParameter("pizza"); // 치즈 피자-8000
		String size = req.getParameter("size");
		int amount = Integer.parseInt(req.getParameter("amount"));
		
		// 피자 이름, 가격 나누기
		String[] arr = pizza.split("-"); // "-"구분자로 쪼개서 String[]로 반환
		// arr == {"치즈 피자", "8000"};
		
		String pizzaName = arr[0]; // 치즈 피자
		int price = Integer.parseInt(arr[1]); // 8000
		
		// L 사이즈인 경우 4000원 추가
		if(size.equals("L")) {
			price += 4000;
		}
		
		// 피자 수량만큼 price에 곱하기
		price *= amount;
		// price = price * amount;
		
		// JSP로 요청 위임(forward)
		RequestDispatcher dispatcher = req.getRequestDispatcher("/WEB-INF/views/pizza_result.jsp");
		
		// JSP로 전달하는 req에는 파라미터가 담겨 있음
		// 하지만, Servlet에서 만든 변수 pizzaName, price는 없음!
		
		// [해결 방법]
		// req에서 속성(Attribute)으로 추가하면
		// JSP에서 꺼내쓸 수 있음!
		// (주의) forward 하기 전에 추가해줘야 함!
		req.setAttribute("pizzaName", pizzaName);
		req.setAttribute("price", price);
		
		dispatcher.forward(req, resp);
	}
}

- JSP
1) pizza_order

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>피자 주문 페이지</title>

<!-- 절대 경로 기준 == webapp == /JSPProject -->
<link rel="stylesheet" href="/JSPProject/resources/css/pizza.css">
</head>
<body>
	<main>
        <h1>피자 주문 페이지</h1>
        <!-- /JSPProject/pizza/order 라는 같은 주소 요청을
             처리하는 Servlet이 존재하지만
             데이터 전달 방식이 Get / Post로 구분되기 때문에
             doGet(), doPost()로 연결되어 처리되므로
             충돌 문제 없음 
        -->
        <form action="/JSPProject/pizza/order" method="POST">
            <div class="row">
                <label>피자 :</label> 
                <select name="pizza">
                  <option>치즈 피자-8000</option>
                  <option>콤비네이션 피자-9000</option>
                  <option>쉬림프 피자-15000</option>
                  <option>더블 포테이토 피자-14000</option>
                  <option>하와이안 피자-12000</option>
                </select>
              </div>
        
              <div class="row">
                <label>사이즈 : </label>
                R <input type="radio" name="size" value="R" checked>
                L(+4000) <input type="radio" name="size" value="L">
              </div>
        
              <div class="row">
                <label>수량</label>
                <button type="button">-</button>
                <input type="number" name="amount" min="1" max="9" value="1">
                <button type="button">+</button>
              </div>
        
              <button class="order-btn">주문하기</button>
        </form>
    </main>

    <script src="/JSPProject/resources/js/pizza.js"></script>
</body>
</html>

2) pizza_result

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<!--HTML 주석(개발자 도구에 노출 O)-->

<%--JSP 주석(개발자 도구에 노출 X)--%>

<%-- 
	<%@ %> : 지시자 태그(페이지 정의)
	
	"charset=UTF-8"      : 현재 문서가 UTF-8 문자 인코딩 형식으로 작성되어 있음
	"pageEncoding=UTF-8" : 현재 문서를 해석할 때 UTF-8 문자 인코딩을 이용해서 해석
	
	<% %> : 스크립틀릿(scriptlet) : JSP에서 자바 코드를 작성할 수 있는 영역
	
	<%= %> : 표현식(Expression) : 자바 코드의 값을 HTML 형식으로 표현(출력)	 
 --%>    
    
<%  // 자바 코드 작성 영역 (Scriptlet)

	String pizzaName = (String)request.getAttribute("pizzaName");
	int price = (int)request.getAttribute("price");
	
	// JSP에서도 요청 시 전달 받은 값(Parameter)을 얻어올 수 있다.
	String amount = request.getParameter("amount");
	String size = request.getParameter("size");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>피자 주문 결과</title>
</head>
<body>
	<!-- webapp 폴더 내부 html/css/jsp 등은
		 서버를 끄지 않고도 수정 가능 -->
	<h1>주문 결과</h1>
	<ul>
		<li>피자 : <%=pizzaName%></li>
		<li>사이즈 : 
			<%if(size.equals("R")){%>
				레귤러
			<%}else{%>
				라지	
			<%}%>
		</li>
		<li>수량 : <%=amount%></li>
		<li>합계 : <%=price%></li>
	</ul>
	
    <h3>for문 작성 예시</h3>
	<%for(int i=1; i<=6; i++){%>
		<h<%=i%>><%=i%>번째 출력</h<%=i%>>
	<%}%>
</body>
</html>

- 화면
1) 주문하기 화면

a태그로 설정한 상태

2) 클릭하여 이동한 피자 주문 페이지

주문 페이지 기본값

3) 피자 주문 및 결과 화면

피자 주문
피자 주문 결과 출력

※ for문 작성 예시 결과(pizza_result.jsp에서 코드 확인 가능)


  • JSP 기본 예제 - 2 : 회원가입 양식

- index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JSP Project</title>
</head>
<body>
    <h3>회원가입</h3>
    <form action="/JSPProject/signUp" method="post">
        <table>
            <tr>
                <th>아이디 : </th>
                <td>
                    <input type="text" name="memberId">
                </td>
            </tr>
            <tr>
                <th>비밀번호 : </th>
                <td>
                    <input type="text" name="memberPw">
                </td>
            </tr>
            <tr>
                <th>이름 : </th>
                <td>
                    <input type="text" name="memberName">
                </td>
            </tr>
            <tr>
                <th>자기소개 </th>
                <td> 
                    <textarea name="intro" rows="3" cols="30"></textarea>
                </td>
            </tr>
        </table>
        <button>회원가입</button>
        <button type="reset">초기화</button>
    </form>
</body>
</html>

- Servlet Container

package edu.kh.jsp.controller;

import java.io.IOException;

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

// Servlet : 웹 서비스(요청, 응답)를 위한 자바 클래스

// @WebServlet("요청주소") : Servlet 클래스 등록 + 요청 주소 매핑
@WebServlet("/signUp")
public class SignUpServlet extends HttpServlet{
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		// ★ POST 방식으로 데이터를 전달 받을 경우
		//   서버(Tomcat)의 기본 문자 인코딩을 따름
		
		// -> UTF-8로 인코딩 변경해줘야 함!!(한글 깨짐 방지)
		req.setCharacterEncoding("UTF-8");
		
		String memberId = req.getParameter("memberId"); 	// 생략 가능
		String memberPw = req.getParameter("memberPw"); 	// 생략 가능
		String memberName = req.getParameter("memberName"); // 생략 가능
		String intro = req.getParameter("intro"); 			// 생략 가능
		
		String message = memberName + "님의 가입을 환영합니다.";
		
		// 요청 -> Servlet -> RequestDispatcher -> forward(req, resp) -> JSP
		//                      (요청 발송자)             (전송)
		RequestDispatcher dispatcher = req.getRequestDispatcher("/WEB-INF/views/signUp_result.jsp");
		// 														JSP 경로는 webapp 폴더를 기준으로 작성함!!
		
		// HttpServletRequest 객체에 message 변수 추가
		req.setAttribute("message", message);
		
		dispatcher.forward(req, resp);
	}
}

- JSP

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%	// Dispatcher가 forward 할 때 req, resp를 매개변수로 보냄
	// 따라서 JSP에서도 req, resp 사용 가능!
	
	// 전달 받은 파라미터
	String memberId = request.getParameter("memberId");
	String memberPw = request.getParameter("memberPw");
	String memberName = request.getParameter("memberName");
	String intro = request.getParameter("intro");
	
	String message = (String)request.getAttribute("message");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title><%=memberName%>님 가입 결과</title>
</head>
<body>
	<ul>
		<li>아이디 : <%=memberId%></li>
		<li>비밀번호 : <%=memberPw%></li>
		<li>이름 : <%=memberName%></li>
		<li>자기소개 : <%=intro%></li>
	</ul>
	<h1><%=message%></h1>
</body>
</html>

- 화면
1) 회원가입 양식에 데이터 입력

회원가입 양식

2) 회원가입 버튼 누르면 결과 화면으로 이동

회원가입 결과 화면