본문 바로가기
05_Server (04. JSP 프로그래밍 구현)

[Servlet + JSP] 서블릿과 JSP 결합

by moca7 2024. 8. 28.

 

 

ㅁ 서블릿과 JSP를 결합시켜서 사용자가 요청할 수 있는 페이지를 제작한다.

- 요청은 서블릿이 처리하고, 처리된 결과를 JSP 페이지를 통해 사용자에게 응답하여 표현한다.

 

 

 

- 아래는 02_jsp 프로젝트의 index.html이다.

 
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

    <h2>JSP</h2>

    <!-- 서블릿 안거치고 바로 페이지 이동 -->
    <a href="/jsp/a_scripting_elements/main.jsp">1. Scripting Elements</a> <br>
    <a href="/jsp/b_page_directive/main.jsp">2. Page Directive</a> <br>
    <a href="/jsp/c_include_directive/main.jsp">3. Include Directive</a> <br>
    <a href=""></a> <br>

    <a href="/jsp/d_pizza/pizzaOrderForm.jsp">피자 주문 페이지</a>

</body>
</html>
 

 

 

 

- 이클립스에서 webapp 폴더 아래에 d_pizza 폴더를 만들고, 그 폴더 안에 pizzaOrderForm.jsp 파일을 만든다.

 

 

 

- 다 저장하고 서버 재시작하고 브라우저에서 확인해본다.

 

 

 

 

 

 

- webapp > d_pizza > pizzaOrderForm.jsp를 아래와 같이 작성한다.

 

 
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

    <h2>피자 주문 페이지</h2>

    <!-- order.do라는 서블릿 클래스가 필요하다. -->
    <form action="/jsp/order.do" method="post">
   
        <fieldset>
            <legend>주문자정보</legend>
           
            <table>
                <tr>
                    <th>이름</th>
                    <td><input type="text" name="userName" required></td>
                </tr>
               
                <tr>
                    <th>전화번호</th>
                    <td><input type="text" name="phone" required></td>
                </tr>
               
                <tr>
                    <th>주소</th>
                    <td><input type="text" name="address" size="30" required></td>
                </tr>
               
                <tr>
                    <th>요청사항</th>
                    <td><textarea name="message" id=""></textarea></td>
                </tr>
            </table>
           
           
        </fieldset>
   
   
        <fieldset>
            <legend>주문정보</legend>

            <table>

                <tr>
                    <th>피자</th>
                    <td>
                        <select name="pizza"> <!-- key값은 select 태그에 한번만 작성하면 된다. -->
                            <option>치즈피자</option> <!-- value 속성을 두지 않으면 텍스트값이 넘어간다. -->
                            <option>페퍼로니피자</option>
                            <option>하와이안피자</option>
                            <option>씨푸드피자</option>
                        </select>
                    </td>
                </tr>

                <tr>
                    <th>토핑</th>
                    <td> <!-- checkbox와 라디오 버튼은 키, 밸류를 다 써줘야 한다.-->
                        <input type="checkbox" name="topping" value="고구마무스"> 고구마무스
                        <input type="checkbox" name="topping" value="콘크림무스"> 콘크림무스
                        <input type="checkbox" name="topping" value="파인애플"> 파인애플
                        <br>
                        <input type="checkbox" name="topping" value="치즈바이트"> 치즈바이트
                        <input type="checkbox" name="topping" value="치즈크러스트"> 치즈크러스트
                        <input type="checkbox" name="topping" value="치즈토핑"> 치즈토핑
                    </td>
                </tr>

                <tr>
                    <th>사이드</th>
                    <td>
                        <input type="checkbox" name="side" value="콜라"> 콜라
                        <input type="checkbox" name="side" value="사이드"> 사이드
                        <input type="checkbox" name="side" value="핫소스"> 핫소스
                        <br>
                        <input type="checkbox" name="side" value="갈릭소스"> 갈릭소스
                        <input type="checkbox" name="side" value="파마산치즈가루"> 파마산치즈가루
                        <input type="checkbox" name="side" value="피클"> 피클
                    </td>
                </tr>

                <tr>
                    <th>결제방식</th>
                    <td> <!-- 라디오 버튼으로 하나만 선택되게끔 한다. -->
                        <input type="radio" name="payment" value="card" checked> 카드결제
                        <input type="radio" name="payment" value="cash"> 현금결제
                    </td>
                </tr>

            </table>

        </fieldset>

        <br>
        <input type="submit" value="주문">
        <input type="reset"> <!-- 기본값이 "초기화" -->
   
    </form>


</body>
</html>
 

 

- 사용자에게 입력값을 받아서 서버로 요청을 전송한다. form 태그를 활용한다. 서블릿 호출함.

- 원래는 사용자에게 받은 입력값을 일일이 유효성 체크 해야 하는데 기본적으로 어느정도 유효성 체크해주는 속성들이 몇가지 있다. required 등.

- 피자 목록은 텍스트 상자로 아무거나 받으면 안 되고, 피자 목록을 불러와서 조회해서 선택되게끔 해야 한다.

 

- /order.do 라는 url mapping값을 가지는 서블릿 클래스가 필요하다.

- selection 태그에 name 태그로 key값을 한번만 주면 된다.

- option에 value 속성을 두지 않으면 텍스트가 value로 넘어간다. 

- checkbox와 radio 버튼은 name 속성(key값), value 속성을 다 써줘야 한다.

 

 



 

 

 

- 이클립스에서 src/main/java에 controller 라는 패키지를 만들고, 그 안에 서블릿으로 PizzaOrder.java를 만든다.

서블릿은 MVC 패턴 중에 컨트롤러 역할이기 때문에 controller 패키지로 만든다.

 

 

 

- 서블릿 주석을 "/order.do"로 변경한다.

 

 

 

 

ㅁ 서블릿 PizzaOrder.java의 doGet() 메소드 작성하기

 

 

package controller;

 

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("/order.do")

public class PizzaOrder extends HttpServlet {

 

  private static final long serialVersionUID = 1L;

 

  public PizzaOrder() { super(); }

 

 

  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

 

  // 1. 요청시 전달값 뽑기

  // 2. 요청처리 (주로 JDBC)

  // 3. 돌려받은 결과를 가지고 응답페이지 제작하기. 이런 순서로 하면 된다.

 

 

  // 1. 요청시 전달값 뽑기

 

  request.setCharacterEncoding("utf-8"); // post방식 요청이기 때문에 데이터를 뽑기 이전에 인코딩 지정해야 한다.

 

  String userName = request.getParameter("userName"); // required라 빈문자열이나 null이 넘어올 일은 없다.

  String phone = request.getParameter("phone"); // required라 빈문자열이나 null이 넘어올 일은 없다.

  String address = request.getParameter("address"); // required라 빈문자열이나 null이 넘어올 일은 없다.

  String message = request.getParameter("message"); // 텍스트상자는 입력하지 않은 경우 빈 문자열이 넘어온다.

  String pizza = request.getParameter("pizza"); // select는 첫번째 값이 선택되어서 빈문자열이나 null이 넘어올 일은 없다.

  String[] topping = request.getParameterValues("topping"); // radio 버튼과 checkbox는 아무것도 체크하지 않으면 topping이라는 파라미터 자체가 없다. null이 온다.

  String[] side = request.getParameterValues("side"); // radio 버튼과 checkbox는 아무것도 체크하지 않으면 side라는 파라미터 자체가 없다. null이 온다.

  String payment = request.getParameter("payment"); // checked라 빈문자열이나 null이 넘어올 일은 없다.

 

  // 요청과 같이 전달된 값을 뽑아서 곧바로 요청처리 하려하지말고, 항상 출력해서 잘 넘어왔는지 확인해봐라.

  System.out.println("유저이름 : " + userName);

  System.out.println("전화번호 : " + phone);

  System.out.println("주소 : " + address);

  System.out.println("요청사항 : " + message);

  System.out.println("피자 : " + pizza);

  System.out.println("토핑 : " + Arrays.toString(topping));

  System.out.println("사이드 : " + Arrays.toString(side));

  System.out.println("결제방법 : " + payment);

  System.out.println();

 

 

  // 2. 요청처리 (주로 JDBC)

 

 

 

  // 3. 돌려받은 결과를 가지고 응답페이지 제작하기

 

 

  }

 

 

  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    doGet(request, response);

  }

 

}

 

- 요청시 다수의 데이터가 넘어온다. 요청시 전달되는 데이터를 파라미터라고 한다.

요청과 관련된 객체인 request에 객체의 데이터가 담긴다. 

- 요청시 전달된 값을 뽑아서 변수 같은 곳에 기록한다.

- 요청시 전달된 값을 뽑아서 넘겨서  db에 jdbc 과정으로 요청처리를 하고, 응답페이지를 만든다.

- 요청과 같이 전달된 값을 뽑아서 곧바로 요청처리 하려하지말고, 항상 출력해서 잘 넘어왔는지 확인해봐라.

null pointer exception이 발생하면 여기서 key값에 오타를 내서 null을 뽑았을 확률이 높다. 

 

 

 

- 아직 응답페이지는 만들지 않았기 때문에 사용자에게는 빈 화면이 보여지고 이클립스 콘솔에 출력된다.

- order.do라는 매핑값을 가지는 서블릿을 구동하고 있는 것이다.

 

 

 

 

ㅁ 이번엔 필수 입력값들만 입력하고 submit을 해본다.

 

 

 

 

 

ㅁ 2(요청처리), 3(응답페이지 제작 후 돌려주기) 

 

 

package controller;

 

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("/order.do")

public class PizzaOrder extends HttpServlet {

 

  private static final long serialVersionUID = 1L;

 

 

  public PizzaOrder() { super(); }

 

 

  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

 

  // 1. 요청시 전달값 뽑기

  // 2. 요청처리 (주로 JDBC)

  // 3. 돌려받은 결과를 가지고 응답페이지 제작하기. 이런 순서로 하면 된다.

 

 

  // 1. 요청시 전달값 뽑기

 

  request.setCharacterEncoding("utf-8"); // post방식 요청이기 때문에 데이터를 뽑기 이전에 인코딩 지정해야 한다.

 

  String userName = request.getParameter("userName"); // required라 빈문자열이나 null이 넘어올 일은 없다.

  String phone = request.getParameter("phone"); // required라 빈문자열이나 null이 넘어올 일은 없다.

  String address = request.getParameter("address"); // required라 빈문자열이나 null이 넘어올 일은 없다.

  String message = request.getParameter("message"); // 텍스트상자는 입력하지 않은 경우 빈 문자열이 넘어온다.

  String pizza = request.getParameter("pizza"); // select는 첫번째 값이 선택되어서 빈문자열이나 null이 넘어올 일은 없다.

  String[] topping = request.getParameterValues("topping"); // radio 버튼과 checkbox는 아무것도 체크하지 않으면 topping이라는 파라미터 자체가 없다. null이 온다.

  String[] side = request.getParameterValues("side"); // radio 버튼과 checkbox는 아무것도 체크하지 않으면 side라는 파라미터 자체가 없다. null이 온다.

  String payment = request.getParameter("payment"); // checked라 빈문자열이나 null이 넘어올 일은 없다.

 

  // 요청과 같이 전달된 값을 뽑아서 곧바로 요청처리 하려하지말고, 항상 출력해서 잘 넘어왔는지 확인해봐라.

  System.out.println("유저이름 : " + userName);

  System.out.println("전화번호 : " + phone);

  System.out.println("주소 : " + address);

  System.out.println("요청사항 : " + message);

  System.out.println("피자 : " + pizza);

  System.out.println("토핑 : " + Arrays.toString(topping));

  System.out.println("사이드 : " + Arrays.toString(side));

  System.out.println("결제방법 : " + payment);

  System.out.println();

 

 

  // 2. 요청처리 (주로 JDBC)

  // => service => dao => 쿼리 실행 => 결과 돌려받기

  // 요청 처리 후 돌려받은 결과가 주문번호라고 가정.

  String orderNo = "20240828-1234567"

 

 

 

  // 3. 돌려받은 결과를 가지고 응답페이지 제작하기

  // 응답페이지 : 주문결과페이지

  // resoponse 객체를 이용해서 한땀한땀 html 구문을 출력해도 되지만,

이제부턴 응답페이지 제작하는 과정을 jsp로 이동(forward)해서 진행한다.

 

  /*

  이동하기 "전"에 forward되는 응답 jsp 상에 필요한 데이터를 request에 담아서 전달해야 한다.

 

  ㅁ HttpServletRequest 객체의 응답데이터 처리 메소드

  - 응답페이지에서 필요한 데이터는 보통 request 객체에 담아서 forward로 넘긴다.

  - setAttribute(String 속성, Object 값) : 이동(forward)되는 jsp에서 사용할 데이터를 담는 메소드

  - getAttribute(String 속성) : 해당 데이터를 Object 타입으로 반환 (형변환이 필요할 수 있음)

  - removeAttribute(String 속성) : 해당 데이터를 제거하는 메소드

  */

  request.setAttribute("userName", userName);

  request.setAttribute("orderNo", orderNo);

  request.setAttribute("pizza", pizza);

  request.setAttribute("topping", topping);

  request.setAttribute("side", side);

  request.setAttribute("payment", payment);

 

 

  request.getRequestDispatcher("/d_pizza/result.jsp").forward(request, response); // 아직 result.jsp를 만들진 않았다.

 

  }

 

 

  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    doGet(request, response);

  }

 

}

 

- 요청시 전달된 다수의 값을 service, dao로 넘길 때 vo객체가 있다면 거기에 담아서 한번에 넘겨라.

담는 과정도 여기서 진행한다. 

- resoponse 객체를 이용해서 한땀한땀 html 구문을 출력해도 되지만,

이제부턴 응답페이지 제작하는 과정을 jsp로 이동(forward)해서 진행한다.

- forward로 servlet으로 이동도 가능하고, jsp로 이동도 가능하다.

forward 할 때는 contextPath는 제외하고 쓰면 된다.

- String 속성은 속성명이고, Object 객체가 내가 request 객체에 담고자 하는 값이다.

배열도 담을수 있고 리스트도 담을 수 있다. vo객체도 담을 수 있다.

- 이제 항상 이런 흐름으로 간다. 

요청을 보내면 요청시 전달값을 뽑아서 sql query를 실행하고 결과를 돌려받고,

그에 해당하는 응답페이지를 jsp로 만들어서 이동시킨다.

그때 응답페이지에서 필요한 데이터는 위와 같이 setAttribute라는 메소드로 request 객체에 담아서 전달시킨다.

- 이동 전에 데이터를 담아야 한다. 

 

 

 

 

ㅁ d_pizza 폴더에 아래와 같이 result.jsp를 만든다.

 

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

          pageEncoding="UTF-8"%>

<%

  String userName = (String)request.getAttribute("userName"); // 실제론 String 타입의 데이터지만 반환은 Object로 됨.

  String orderNo = (String)request.getAttribute("orderNo");

  String pizza = (String)request.getAttribute("pizza");

  String[] topping = (String[])request.getAttribute("topping");

  String[] side = (String[])request.getAttribute("side");

  String payment = (String)request.getAttribute("payment");

%>

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>Insert title here</title>

</head>

<body>

 

  <h2>주문 완료</h2>

 

  <h3>주문번호 : <%= orderNo %></h3>

  <h3>주문자명 : <%= userName %></h3>

 

  <h3>주문내역</h3>

  <ul>

    <li>피자 : <%= pizza %></li>

    <%-- 토핑과 사이드는 체크한게 없으면 null일 수 있다. --%>

    <li>토핑 :

      <% if(topping == null) { %>

        <b>선택안함</b>

      <% }else { %>

        <%= String.join(", ", topping) %>

      <% } %>

    </li>

    <li>사이드 :

      <%

      if(side== null) {

        out.println("<b>선택안함</b>");

      }else {

        out.println(String.join(", ", side));

      }

      %>

    </li>

    <li>결제방식 : <%= payment.equals("card") ? "카드" : "현금" %></li>

</ul>

 

</body>

</html>

 

- 이거 맨 마지막 결제방식 1줄 이클립스에서 빨간줄 뜸. 근데 작동은 잘 됨. 왜 떴던거지.

- jsp에서 request객체를 import 없이 바로 쓸 수 있다. 내장객체다. 

- request 객체에서 데이터를 뽑는 구문은 페이지 로드되자마자 바로 실행되게끔 주로 상단에 쓴다. 

- <% %> 에는 자바코드만 있어야 하고 html 구문이 있어서는 안 된다.

out.println문에 html태그를 쓰면 된다.

 

 

 

 

- 저장하고 서버 재시작, 브라우저 새로고침

 

- 응답페이지가 만들어져 있다.

 

 

 

 

 

- 필수 입력부분만 입력하고 submit하면 아래와 같이 뜬다. 

 

 

 

ㅁ 아래는 최종 디렉토리 구조

 

 

- 실제로는 C:\workspaces\05_jspServlet-workspace\02_jsp\src\main에 java 폴더, webapp 폴더가 같이 있다.

 

- webapp 폴더의 WEB-INF 폴더에는 classes폴더가 있다.

 

 

 

- classes 폴더에는 controller 폴더가 있다.

 

 

- controller 폴더에는 PizzaOrder.class 파일이 있다.

 

 

 

ㅁ 화면 구현할 때는 "메인페이지.html"처럼 구분 가능하게끔 만들어라.

- 각각의 세부페이지들(회원가입페이지, 마이페이지, 공지사항 목록페이지, 게시판 목록페이지 등)은 보통 webapp 폴더에 view 폴더를 둬서 따로 관리를 한다.