Servlet / JSP #15 JSP MVC Pattern

underlier12·2020년 1월 30일
1

SERVLET&JSP

목록 보기
15/16

15. JSP MVC Pattern

JSP MVC Model 1

이번에는 지난 시간에 이어 스파게티 코드처럼 얽혀있는 파일을 MVC model 1에 따라 깔끔하게 분리해본다.

image.png

image.png

Detail 페이지 MVC Model 1 구현

detail.jsp

<%@page import="java.util.Date"%>
<%@page import="java.sql.PreparedStatement"%>
<%@page import="java.sql.ResultSet"%>
<%@page import="java.sql.Statement"%>
<%@page import="java.sql.DriverManager"%>
<%@page import="java.sql.Connection"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<%

int id = Integer.parseInt(request.getParameter("id"));

String url = "jdbc:oracle:thin:@59.15.156.101:1521/xepdb1";
String sql = "SELECT * FROM NOTICE WHERE ID=?";

Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con = DriverManager.getConnection(url, "NEWLEC", "root");
PreparedStatement st = con.prepareStatement(sql);
st.setInt(1, id);

ResultSet rs = st.executeQuery();
rs.next();


String title = rs.getString("TITLE");
Date regdate = rs.getDate("REGDATE");
String writerId = rs.getString("WRITER_ID");
String hit = rs.getString("HIT");
String files = rs.getString("FILES");
String content = rs.getString("CONTENT");


rs.close();
st.close();
con.close();                  		
%>  

    
<!DOCTYPE html>
<html>

<head>
    <title>코딩 전문가를 만들기 위한 온라인 강의 시스템</title>
    <meta charset="UTF-8">
    <title>공지사항목록</title>
    
    <link href="/css/customer/layout.css" type="text/css" rel="stylesheet" />
    <style>
    
        #visual .content-container{	
            height:inherit;
            display:flex; 
            align-items: center;
            
            background: url("../../images/customer/visual.png") no-repeat center;
        }
    </style>
</head>

<body>
    <!-- header 부분 -->

	<header id="header">
        
        <div class="content-container">
            <!-- ---------------------------<header>--------------------------------------- -->

            ... 중략
            
			<!-- --------------------------- main --------------------------------------- -->

			<main>
				<h2 class="main title">공지사항</h2>
				
				<div class="breadcrumb">
					<h3 class="hidden">breadlet</h3>
					<ul>
						<li>home</li>
						<li>고객센터</li>
						<li>공지사항</li>
					</ul>
				</div>

				<div class="margin-top first">
						<h3 class="hidden">공지사항 내용</h3>
						<table class="table">
							<tbody>
								<tr>
									<th>제목</th>
									<td class="text-align-left text-indent text-strong text-orange" colspan="3"><%= title %></td>
								</tr>
								<tr>
									<th>작성일</th>
									<td class="text-align-left text-indent" colspan="3"><%= regdate %></td>
								</tr>
								<tr>
									<th>작성자</th>
									<td><%= writerId %></td>
									<th>조회수</th>
									<td><%= hit %></td>
								</tr>
								<tr>
									<th>첨부파일</th>
									<td colspan="3"><%= files %></td>
								</tr>
								<tr class="content">
									<td colspan="4"><%= content %></td>
								</tr>
							</tbody>
						</table>
					</div>
					
					<div class="margin-top text-align-center">
						<a class="btn btn-list" href="list.jsp">목록</a>
					</div>
					
					<div class="margin-top">
						<table class="table border-top-default">
							<tbody>
								
								<tr>
									<th>다음글</th>
									<td colspan="3"  class="text-align-left text-indent">다음글이 없습니다.</td>
								</tr>
								
									
								
								
								<tr>
									<th>이전글</th>
									<td colspan="3"  class="text-align-left text-indent"><a class="text-blue text-strong" href="">스프링 DI 예제 코드</a></td>
								</tr>
								
								
							</tbody>
						</table>
					</div>			
					
			</main>		
			
		</div>
	</div>

    <!-- ------------------- <footer> --------------------------------------- -->



        ... 후략
    
    </html>

JSP MVC Model 2

위의 모델 1에서 모델 2로 변경하며 더욱 관리에 용이하도록 한다. 기존 모델 1에서는 Control / Model / View가 모두 혼재되어 있어 컴파일 시에도 시간이 더 걸리기 마련인데 Control 부분을 Servlet, 즉 자바 코드로만 작성하고 View 단만 JSP로 작성한다면 View 단만 컴파일을 진행하기에 컴파일 시간이 더 줄어들 것이다. (jsp file은 컴파일을 통해 servlet file로 변환이 필요)

image.png

Detail 페이지 MVC Model 2

NoticeDetailController.java

package com.newlecture.web.controller;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;

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("/notice/detail")
public class NoticeDetailController extends HttpServlet{
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		
		// list.jsp에서 연결되는 id가 전달되어 연결 됨
		int id = Integer.parseInt(request.getParameter("id"));

		String url = "jdbc:oracle:thin:@59.15.156.101:1521/xepdb1";
		String sql = "SELECT * FROM NOTICE WHERE ID=?";

		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
		
			Connection con = DriverManager.getConnection(url, "NEWLEC", "root");
			PreparedStatement st = con.prepareStatement(sql);
			st.setInt(1, id);
	
			ResultSet rs = st.executeQuery();
			rs.next();
	
	
			String title = rs.getString("TITLE");
			Date regdate = rs.getDate("REGDATE");
			String writerId = rs.getString("WRITER_ID");
			String hit = rs.getString("HIT");
			String files = rs.getString("FILES");
			String content = rs.getString("CONTENT");
			
			// request 객체에 모델을 담음
			request.setAttribute("title", title);
			request.setAttribute("regdate", regdate);
			request.setAttribute("writerId", writerId);
			request.setAttribute("hit", hit);
			request.setAttribute("files", files);
			request.setAttribute("content", content);
			
			rs.close();
			st.close();
			con.close(); 
			
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// redirect : 하나의 작업이 끝난 뒤 다른 작업으로 넘기는 것 (작업 종료)
		
		// forward  : 하나의 작업이 끝난 뒤 다른 작업으로 인자와 함께 전이하는 것(작업 인계)
		request.getRequestDispatcher("/notice/detail.jsp").forward(request, response);
		
	}
}

Controller(servlet)에서 View(jsp)로 넘어갈 땐 Forwarding 방식 사용

detail.jsp

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

<head>
    <title>코딩 전문가를 만들기 위한 온라인 강의 시스템</title>
    <meta charset="UTF-8">
    <title>공지사항목록</title>
    
    <link href="/css/customer/layout.css" type="text/css" rel="stylesheet" />
    <style>
    
        #visual .content-container{	
            height:inherit;
            display:flex; 
            align-items: center;
            
            background: url("../../images/customer/visual.png") no-repeat center;
        }
    </style>
</head>

<body>
    <!-- header 부분 -->

	<header id="header">
        
        <div class="content-container">
            <!-- ---------------------------<header>--------------------------------------- -->

            ...중략 
            
			<!-- --------------------------- main --------------------------------------- -->

			<main>
				<h2 class="main title">공지사항</h2>
				
				<div class="breadcrumb">
					<h3 class="hidden">breadlet</h3>
					<ul>
						<li>home</li>
						<li>고객센터</li>
						<li>공지사항</li>
					</ul>
				</div>

				<div class="margin-top first">
						<h3 class="hidden">공지사항 내용</h3>
						<table class="table">
							<tbody>
								<tr>
									<th>제목</th>
									<td class="text-align-left text-indent text-strong text-orange" colspan="3"><%= request.getAttribute("title") %></td>
								</tr>
								<tr>
									<th>작성일</th>
									<td class="text-align-left text-indent" colspan="3"><%= request.getAttribute("regdate") %></td>
								</tr>
								<tr>
									<th>작성자</th>
									<td><%= request.getAttribute("writerId") %></td>
									<th>조회수</th>
									<td><%= request.getAttribute("hit") %></td>
								</tr>
								<tr>
									<th>첨부파일</th>
									<td colspan="3"><%= request.getAttribute("files") %></td>
								</tr>
								<tr class="content">
									<td colspan="4"><%= request.getAttribute("content") %></td>
								</tr>
							</tbody>
						</table>
					</div>
					
					<div class="margin-top text-align-center">
						<a class="btn btn-list" href="list.jsp">목록</a>
					</div>
					
					<div class="margin-top">
						<table class="table border-top-default">
							<tbody>
								
								<tr>
									<th>다음글</th>
									<td colspan="3"  class="text-align-left text-indent">다음글이 없습니다.</td>
								</tr>
								
									
								
								
								<tr>
									<th>이전글</th>
									<td colspan="3"  class="text-align-left text-indent"><a class="text-blue text-strong" href="">스프링 DI 예제 코드</a></td>
								</tr>
								
								
							</tbody>
						</table>
					</div>			
					
			</main>		
			
		</div>
	</div>

    <!-- ------------------- <footer> --------------------------------------- -->



       ...후략
    
    </html>

  

request 객체에 담긴 값만 getAttribute로 꺼내 옴

list.jsp

리스트 화면에서 jsp가 아닌 Controller(servlet)으로 연결되어야 한다.

변경 전

<a href="detail.jsp?id=<%= rs.getInt("ID") %>">

변경 후

<a href="detail?id=<%= rs.getInt("ID") %>">

Model 데이터 구조화

데이터에 해당하는 모델을 주고 받기에 너무 지저분할 수 있어 이를 개체(Entity)로 묶어 주고 받는다면 훨씬 효과적일 것이다. 따라서 아래와 같이 개체의 속성으로 묶어 값을 지정한다.

image.png

그래서 jsp 내에서 아래와 같이 EL로 간략히 표기가 가능하며 해당 개체의 속성값을 전달할 수 있게 된다. (notice로 지정 시 notice.id, notice.code 등, n으로 지정 시 n.id, n.code 등 - 혼재하지 않음)

image.png

모델 데이터 구조화 구현

Notice.java

package com.newlecture.web.entity;

import java.util.Date;

public class Notice {
	private int id;
	private String title;
	private Date regdate;
	private String writerId;
	private String hit;
	private String files;
	private String content;
	
	public Notice() {
		// TODO Auto-generated constructor stub
	}
	
	public Notice(int id, String title, 
			Date regdate, String writerId, String hit, 
			String files, String content) {
		this.id = id;
		this.title = title;
		this.regdate = regdate;
		this.writerId = writerId;
		this.hit = hit;
		this.files = files;
		this.content = content;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public Date getRegdate() {
		return regdate;
	}

	public void setRegdate(Date regdate) {
		this.regdate = regdate;
	}

	public String getWriterId() {
		return writerId;
	}

	public void setWriterId(String writerId) {
		this.writerId = writerId;
	}

	public String getHit() {
		return hit;
	}

	public void setHit(String hit) {
		this.hit = hit;
	}

	public String getFiles() {
		return files;
	}

	public void setFiles(String files) {
		this.files = files;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	@Override
	public String toString() {
		return "Notice [id=" + id + ", title=" + title 
				+ ", regdate=" + regdate + ", writerId=" 
				+ writerId + ", hit=" + hit + ", files=" 
				+ files + ", content=" + content + "]";
	}
	
}

NoticeDetailController.java

package com.newlecture.web.controller;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;

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 com.newlecture.web.entity.Notice;

@WebServlet("/notice/detail")
public class NoticeDetailController extends HttpServlet{
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		
		// list.jsp에서 연결되는 id가 전달되어 연결 됨
		int id = Integer.parseInt(request.getParameter("id"));

		String url = "jdbc:oracle:thin:@59.15.156.101:1521/xepdb1";
		String sql = "SELECT * FROM NOTICE WHERE ID=?";

		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
		
			Connection con = DriverManager.getConnection(url, "NEWLEC", "root");
			PreparedStatement st = con.prepareStatement(sql);
			st.setInt(1, id);
	
			ResultSet rs = st.executeQuery();
			rs.next();
	
			String title = rs.getString("TITLE");
			Date regdate = rs.getDate("REGDATE");
			String writerId = rs.getString("WRITER_ID");
			String hit = rs.getString("HIT");
			String files = rs.getString("FILES");
			String content = rs.getString("CONTENT");
			
			// request 객체에 모델을 담음
			Notice notice = new Notice(
								id, 
								title, 
								regdate, 
								writerId, 
								hit, 
								files, 
								content
							);
			
			request.setAttribute("n", notice);
			
			rs.close();
			st.close();
			con.close(); 
			
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// redirect : 하나의 작업이 끝난 뒤 다른 작업으로 넘기는 것 (작업 종료)
		
		// forward  : 하나의 작업이 끝난 뒤 다른 작업으로 인자와 함께 전이하는 것(작업 인계)
		request.getRequestDispatcher("/notice/detail.jsp").forward(request, response);
		
	}
}

detail.jsp

이전 자바 코드들을 아래와 같이 모두 EL로 변환하여 간략히 표기한다.

<th>작성자</th>
<td>${ n.writerId }</td>
<th>조회수</th>
<td>${ n.hit }</td>

List page MVC

리스트 페이지 MVC 패턴으로 변환

NoticeListController.java

package com.newlecture.web.controller;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

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 com.newlecture.web.entity.Notice;

@WebServlet("/notice/list")
public class NoticeListController extends HttpServlet{
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		
		List<Notice> list = new ArrayList<>();
		
		String url = "jdbc:oracle:thin:@59.15.156.101:1521/xepdb1";
		String sql = "SELECT * FROM NOTICE";

		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
		
			Connection con = DriverManager.getConnection(url, "NEWLEC", "root");
			Statement st = con.createStatement();
			ResultSet rs = st.executeQuery(sql);
	
			while(rs.next()){ 
				int id = rs.getInt("id");
				String title = rs.getString("TITLE");
				Date regdate = rs.getDate("REGDATE");
				String writerId = rs.getString("WRITER_ID");
				String hit = rs.getString("HIT");
				String files = rs.getString("FILES");
				String content = rs.getString("CONTENT");
				
				Notice notice = new Notice(
						id, 
						title, 
						regdate, 
						writerId, 
						hit, 
						files, 
						content
					);
				list.add(notice);
			} 
	
			rs.close();
			st.close();
			con.close();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		request.setAttribute("list", list);
		request.getRequestDispatcher("/notice/list.jsp").forward(request, response);
	}
}

list.jsp

<%@page import="java.util.List"%>
<%@page import="com.newlecture.web.entity.Notice"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<!DOCTYPE html>
<html>

<head>
    <title>코딩 전문가를 만들기 위한 온라인 강의 시스템</title>
    <meta charset="UTF-8">
    <title>공지사항목록</title>
    
    <link href="/css/customer/layout.css" type="text/css" rel="stylesheet" />
    <style>
    
        #visual .content-container{	
            height:inherit;
            display:flex; 
            align-items: center;
            
            background: url("../../images/customer/visual.png") no-repeat center;
        }
    </style>
</head>

<body>
    <!-- header 부분 -->

    <header id="header">
        
        <div class="content-container">
            <!-- ---------------------------<header>--------------------------------------- -->

            ... 중략
            
			<!-- --------------------------- main --------------------------------------- -->

		<main class="main">
			<h2 class="main title">공지사항</h2>
			
			<div class="breadcrumb">
				<h3 class="hidden">경로</h3>
				<ul>
					<li>home</li>
					<li>고객센터</li>
					<li>공지사항</li>
				</ul>
			</div>
			
			<div class="search-form margin-top first align-right">
				<h3 class="hidden">공지사항 검색폼</h3>
				<form class="table-form">
					<fieldset>
						<legend class="hidden">공지사항 검색 필드</legend>
						<label class="hidden">검색분류</label>
						<select name="f">
							<option  value="title">제목</option>
							<option  value="writerId">작성자</option>
						</select> 
						<label class="hidden">검색어</label>
						<input type="text" name="q" value=""/>
						<input class="btn btn-search" type="submit" value="검색" />
					</fieldset>
				</form>
			</div>
			
			<div class="notice margin-top">
				<h3 class="hidden">공지사항 목록</h3>
				<table class="table">
					<thead>
						<tr>
							<th class="w60">번호</th>
							<th class="expand">제목</th>
							<th class="w100">작성자</th>
							<th class="w100">작성일</th>
							<th class="w60">조회수</th>
						</tr>
					</thead>
					<tbody>
					
					<% 
					List<Notice> list = (List<Notice>)request.getAttribute("list");
					for(Notice n : list){ 
						pageContext.setAttribute("n", n);
					%>
					
					<tr>
						<td>${n.id }</td>
						<td class="title indent text-align-left"><a href="detail?id=${n.id }"></a>${n.title }</td>
						<td>${n.writerId }</td>
						<td>${n.regdate }</td>
						<td>${n.hit }</td>
					</tr>
					
					<%} %>
					
										
					</tbody>
				</table>
			</div>
			
			<div class="indexer margin-top align-right">
				<h3 class="hidden">현재 페이지</h3>
				<div><span class="text-orange text-strong">1</span> / 1 pages</div>
			</div>

			<div class="margin-top align-center pager">	
		
	<div>
		
		
		<span class="btn btn-prev" onclick="alert('이전 페이지가 없습니다.');">이전</span>
		
	</div>
	<ul class="-list- center">
		<li><a class="-text- orange bold" href="?p=1&t=&q=" >1</a></li>
				
	</ul>
	<div>
			<span class="btn btn-next" onclick="alert('다음 페이지가 없습니다.');">다음</span>
	</div>
	
			</div>
		</main>
		
			
		</div>
	</div>

    <!-- ------------------- <footer> --------------------------------------- -->
              
        ...후략
    
    </html>
    
profile
logos and alogos

0개의 댓글