56일차 (1) - JSP/Servlet (MVC패턴, db조회, db저장, servlet, jsp)

Yohan·2024년 5월 10일
0

코딩기록

목록 보기
79/156
post-custom-banner

MVC 패턴

자바웹프로그래밍에서 사용되는 대표적인 아키텍처 패턴 중 하나

  • Model: 데이터와 비즈니스 로직을 처리하는 부분
    • 사용자가 요청한 데이터를 처리하고, 데이터를 CRUD
    • 보통 DAO(Data Access Object) 패턴을 사용하여 구현
  • View: 데이터를 시각적으로 출력해주는 부분
    • 클라이언트 측에서 사용자가 요청한 결과를 표시
    • HTML, JSP 등을 사용하여 구현
  • Controller: Model과 View를 연결하여 사용자의 요청을 처리하는 부분
    • 사용자의 요청을 받아서 Model을 호출하여 데이터를 가져오고, 그 결과를 View에 전달하여 응답을 생성
    • 보통 Servlet을 사용하여 구현

MVC 실습

1. 서블릿만으로 구성하는 경우

  • 서블릿만으로 요청과 응답 로직을 구현할 경우 HTML 코드가 굉장히 까다롭다.
  • 여러 역할의 코드(요청데이터 처리, 브라우저 응답처리, 비즈니스 로직 처리)가 뒤죽박죽 섞여 객체지향적인 구조 X

2. JSP만으로 구성하는 경우

  • jsp만으로 요청과 응답 로직을 구현할 경우 HTML 작성에서 피로감은 해소 O
  • 역으로 자바 코드 작성부분이 까탈스럽다.
  • 여전히 여러 역할의 코드(요청데이터 처리, 브라우저 응답처리, 비즈니스 로직 처리)가 뒤죽박죽 섞여 전혀 객체지향적인 구조 X

3. MVC패턴 적용

  • 깔끔한 view를 위해 jstl 라이브러리를 추가
	<!--jstl 문법: 태그 형식으로 코딩하는 방법(디자이너에게 직관적임)-->
	<c:forEach var ="i" begin = "1" end = "10">
		${i}
	</c:forEach>
  1. 댄서 등록 (mvc버전)에 대한 html 코드 생성
<%@ 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>
    <h1>Welcome!</h1>

    <a href="/chap02/dancer/register">댄서 등록(서블릿버전)</a>
    <a href="/chap03/dancer/register.jsp">댄서 등록(jsp버전)</a>
    <a href="/chap04/dancer/form">댄서 등록(mvc버전)</a>
  </body>
</html>
  1. 댄서 등록(mvc버전)을 클릭하면 servlet이 forward를 통해 view에게 html 파일을 열으라고 요청, 실질적으로는 view가 /WEB-INF/chap04/register.jsp html 파일을 열음
// 역할: 댄서 등록 화면을 요청하면 해당 html파일을 열기만해주는 역할
@WebServlet("/chap04/dancer/form")
public class DancerFormRequestServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // forward를 통해 적당한 view에게 화면처리를 위임 (controller -> view 위임)
        // forwarding: 화면 파일을 찾아서 열어주는 개념
        RequestDispatcher rd
                = req.getRequestDispatcher("/WEB-INF/chap04/register.jsp");
        rd.forward(req, resp); // jsp에게 화면처리하라고 던짐

    }
}
  1. 댄서등록 폼에서 댄서를 등록하게되면 댄서 정보를 데이터베이스에 등록하기 위해 repo에 저장
  • servlet
    • 저장된 dancer의 정보를 JSP에게 전달하기위해 수송객체 사용
      -> JSP에서 <h2>${d.name}님(소속: ${d.crewName})이 정상 등록</h2> 처럼 쉽게 끌어다 쓸 수 있음
package com.jsp.chap04;

import com.jsp.entity.Dancer;
import com.jsp.repository.DancerJdbcRepo;
import com.jsp.repository.DancerMemoryRepo;

import javax.servlet.DispatcherType;
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;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

// 역할: 새로운 댄서 정보를 데이터베이스에 등록하기 위해
//       댄서 정보들을 가져와서 처리하는 역할
@WebServlet("/chap04/new-dancer")
public class AddNewDancerServlet extends HttpServlet {

//    private DancerMemoryRepo repo = DancerMemoryRepo.getInstance();
    private DancerJdbcRepo repo = DancerJdbcRepo.getInstance();

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 요청파라미터를 읽어서 댄서 정보 가져오기
        req.setCharacterEncoding("utf-8");

        String name = req.getParameter("name");
        String crewName = req.getParameter("crewName");
        String danceLevel = req.getParameter("danceLevel");
        String[] genres = req.getParameterValues("genres");

        // 댄서 객체 생성
        Dancer dancer = new Dancer();
        dancer.setName(name);
        dancer.setCrewName(crewName);
        dancer.setDanceLevel(Dancer.DanceLevel.valueOf(danceLevel));

        List<Dancer.Genre> genreList = new ArrayList<>();
        for (String genre : genres) {
            genreList.add(Dancer.Genre.valueOf(genre));
        }
        dancer.setGenres(genreList);

        System.out.println("dancer = " + dancer);

        // 생성된 댄서 객체를 데이터베이스에 저장
        // 데이터베이스 처리에 특화된 객체에게 위임
        repo.save(dancer);

        // JSP에게 전달할 동적데이터를 어떻게 전달할 것인가?
        // 수송객체 (page, request, session, application)
        // request: 한 번의 요청과 응답이 끝날동안만 보관
        // session: 브라우저가 꺼질 때 까지 or 세션시간이 만료될 때 까지 보관
        req.setAttribute("d",dancer);

        // 적당한 HTML(JSP) 응답
        RequestDispatcher rd
                = req.getRequestDispatcher("/WEB-INF/chap04/result.jsp");
        rd.forward(req,resp);
    }
}
  • repo
    • 댄서를 데이터베이스에 저장하고 조회하기 위해서 INSERT, SELECT 구현
    • SELECT는 INSERT, UPDATE, DELETE 와는 다르게 executeUpdate 대신에 executeQuery 사용
      -> SELECT는 조회해야 하므로 ResultSet을 반환
    • rs.next()을 한 번 입력할 때 마다 한 행씩 넘어감 (2번 입력하면 2번째 행 출력)
package com.jsp.repository;

import com.jsp.chap05.Person;
import com.jsp.entity.Dancer;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

// 역할: 실제 데이터베이스에 댄서들을 CRUD
// Model
public class DancerJdbcRepo {

    private static DancerJdbcRepo repo = new DancerJdbcRepo();

    // 싱글톤 구현
    private DancerJdbcRepo() {
    }

    // 싱글객체를 리턴하는 메서드
    public static DancerJdbcRepo getInstance() {
        return repo;
    }

    private String username = "root"; // db계정명
    private String password = "mariadb"; // db 패스워드
    private String url = "jdbc:mariadb://localhost:3307/spring5"; // db url : 데이터베이스 설치 위치
    private String driverClassName = "org.mariadb.jdbc.Driver"; // db벤더별 전용 커넥터 클래스

    // 댄서를 데이터베이스에 저장하는 기능
    public boolean save(Dancer dancer) {
        try (Connection conn
                     = DriverManager.getConnection(url, username, password)) {
            Class.forName(driverClassName);

            String sql = "INSERT INTO tbl_dancer " +
                    "(name, crew_name, dance_level) " +
                    "VALUES (?, ?, ?)";

            // 4. SQL 실행 객체 생성
            PreparedStatement pstmt = conn.prepareStatement(sql);

            // 5. ? 값 채우기
            pstmt.setString(1, dancer.getName());
            pstmt.setString(2, dancer.getCrewName());
            pstmt.setString(3, dancer.getDanceLevel().toString());

            // 6. 실행 명령
            // INSERT, UPDATE, DELETE 같은 명령을 사용
            pstmt.executeUpdate();
            return true;

            // 7. 데이터베이스 연결 해제

        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    // 댄서리스트를 반환하는 기능
    public List<Dancer> retrieve() {
        try (Connection conn  // 테이블이 정보를 가지고있음
                     = DriverManager.getConnection(url, username, password)) {

            Class.forName(driverClassName);

            String sql = "SELECT * FROM tbl_dancer " +
                    "ORDER BY id DESC";

            // SQL 실행 객체 생성
            PreparedStatement pstmt = conn.prepareStatement(sql);

            // ? 채우기

            // 실행 명령 - SELECT는 다른 메서드를 사용
            // ResultSet : SELECT의 결과집합 표를 가져옴
            ResultSet rs = pstmt.executeQuery();

            // ResultSet 데이터 가져오기
            List<Dancer> dancerList = new ArrayList<>();
            while (rs.next()) { // rs.next(): 표의 행을 지목하는 커서

                // 커서가 가리키는 행의 데이터를 하나씩 추출
                int id = rs.getInt("id");
                String name = rs.getString("name");
                String crewName = rs.getString("crew_name");
                String danceLevel = rs.getString("dance_level");

                Dancer dancer = new Dancer();
                dancer.setName(name);
                dancer.setCrewName(crewName);
                dancer.setDanceLevel(Dancer.DanceLevel.valueOf(danceLevel));

                dancerList.add(dancer);
            }
            return dancerList;


        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
  • result.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>

    <!-- <%
        String name = (String) request.getAttribute("name");
        String crew = (String) request.getAttribute("crew");
    %> -->

  <h1>댄서 등록 결과페이지 입니다.</h1>
  <h2>${d.name}님(소속: ${d.crewName})이 정상 등록되었습니다~~</h2>
  <h3>댄스 수준: ${d.danceLevel}</h3>

  <a href="/chap04/dancer/form">새로운 댄서 등록하러 가기</a> <br>
  <a href="/chap04/show-list">댄서 목록 조회하기</a> <br>
</body>
</html>
  1. 데이터베이스에 저장된 댄서 정보를 수송객체를 통해 JSP에게 전달하여 디자인해서 보여주기
package com.jsp.chap04;


import com.jsp.entity.Dancer;
import com.jsp.repository.DancerJdbcRepo;
import com.jsp.repository.DancerMemoryRepo;

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;
import java.io.IOException;
import java.util.List;

// 역할: 댄서 목록 조회 요청을 받아서 데이터베이스에 있는 댄서 정보를
//      가져온 후 적당한 HTML을 찾아서 forwarding
@WebServlet("/chap04/show-list")
public class ShowDancerListServlet extends HttpServlet {

    private DancerJdbcRepo repo = DancerJdbcRepo.getInstance();

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 데이터베이스에 접근하여 댄서 목록을 가져옴
        List<Dancer> dancerList = repo.retrieve();

        // 가져온 댄서 목록을 JSP를 통해 디자인
        // JSP파일에게 보낼 데이터 수송객체에 담기
        req.setAttribute("dancers", dancerList);

        // JSP 파일 열기
        RequestDispatcher rd
                = req.getRequestDispatcher("/WEB-INF/chap04/dancer-list.jsp");
        rd.forward(req, resp);
    }
}
profile
백엔드 개발자
post-custom-banner

0개의 댓글