본문 바로가기
Java Web Programming/4. JSP

[JSP/Model2] Model 2 Architecture ( Singleton Pattern 싱글톤 패턴)

by 파프리카_ 2020. 8. 27.
728x90
반응형

[ Singleton Design Pattern ]

: 시스템 상에서 객체를 단 한번 생성해서, 여러 곳에서 공유해서 사용하는 방식

(*참고 : Spring Framework에서는 기본 객체 운용방식이  singleton이다)

 

[ 적용 방안 ]

  1.  private 생성자로 명시해 외부에서 객체 생성하는 것을 방지한다.
  2. Class Loading 시 ( Class 당 한 번 실행) ,
    static 영역이 method area(class area)에 초기화 되는 것을 이용해
    static 변수로 단 한번 객체를 생성한다.
  3. 외부에서 단 한번 만든 객체를 사용하게 하기 위해,
    public static 메서드로 객체의 주소값을 반환하도록 정의한다.

간단 적용 예제

Company class에 Singleton Design Pattern을 적용해본다.

 

/TestSingleton.java

package test;

//Company Class
class Company {
	private String companyInfo = "회사 정보";
	
	// 2. 생성 방법 1 - class loading시 단 한번 실행된다.
	private static Company instance = new Company();
	
	// 1. 생성자에 private을 명시해 외부에서 생성하는 것을 방지한다
	private Company () {
		System.out.println("Company 객체 생성");
	}
	
	// 3. 외부에서 사용할 수 있게 public static method를 instance로 반환한다.
	public static Company getInstance() {
		return instance;
	}
	
	// 사용자가 서비스 받을 메서드
	public String getCompanyInfo() {
		return companyInfo;
	}
}

//Main Class
public class TestSingleton {
	public static void main(String[] args) {
		
		// private 생성자 이므로, error : 외부에서 객체 생성 할 수 없다
		// Company c1 = new Company();
		
		// 생성은 할 수 없지만, 사용할 수는 있다!
		// static method는 [class명].[method명] 으로 접근한다
		Company c1 = Company.getInstance();
		System.out.println(c1); //test.Company@7852e922
		
		Company c2 = Company.getInstance();
		System.out.println(c2); //test.Company@7852e922 -- 동일한 주소값
		
		// Company class의 인스턴스 변수(companyInfo) 가져오기
		String companyInfo = c2.getCompanyInfo();
		System.out.println(companyInfo); //회사 정보
		
		System.out.println(Company.getInstance().getCompanyInfo()); //회사 정보
		
	}
}

[ Model2 MVC 상품관리 예제 ]

DAO에 Singleton을 적용

Singleton Pattern으로 Model계층의 DAO에 적용시켜,

불필요하게 객체를 다수 생성하는 것을 방지하고 & 

클래스 로딩 시, 단 한번의 객체를 생성해서 여러 컨트롤러에서 사용하도록 했다.

 

1. web_product TABLE의 총 상품 수 조회하기

index.jsp -- request -- ProductTotalCountServlet < -- > ProductDAO

                                                                 ㅣ

                                                                  forward 방식으로 이동

                                                                 ㅣ

                                                product-totalcount.jsp

 

2. id 로 상품 검색하기

index.jsp -- request -- FindProductByIdServlet < -- > ProductDAO.findProductById(id) : ProductVO

                                                                 ㅣ

                                                                  forward 방식으로 이동

                                                                 ㅣ

                                                       ㅣ 상품 있으면  ㅣ 상품 없으면

                                             find_ok.jsp              find_falil.jsp

                               (테이블로 상품정보 조회)

 

3. 상품 리스트 전체 조회하기

전체 상품을 검색해서 product-list.jsp에서 상품 목록을 보여준다.

(*단, 아이디와 상품명만 보여준다! + 상품목록은 아이디 내림차순 )


SQL

web_product TABLE 생성 및 INSERT 

CREATE TABLE web_product(
    id    NUMBER        PRIMARY KEY,
    name  VARCHAR2(100) NOT NULL,
    maker VARCHAR2(100) NOT NULL,
    price NUMBER        NOT NULL
)

CREATE SEQUENCE web_product_seq nocache;

INSERT INTO web_product VALUES(web_product_seq.nextval, '카스', '두산', 1500);
INSERT INTO web_product VALUES(web_product_seq.nextval, '테라', '진로', 1700);
INSERT INTO web_product VALUES(web_product_seq.nextval, '참이슬', '진로', 1300);

commit

 


Model

DAO class에 Singleton Design Pattern을 적용해보자!

 

/ProductDAO.java

package model;

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


/*
 * DAO class에 Singleton Design Pattern을 적용해보자!
 * 1. private 생성자
 * 2. private static 변수에 자신의 객체를 생성
 * 3. public static method(getInstance())로 공유
 */
public class ProductDAO {
	
	//2. private static 변수에 자신의 객체를 생성
	// --> 딱 한 번만 실행됨 !
	private static ProductDAO instance = new ProductDAO();
	
	// JDBC (DB 연결)에 필요한 변수
	private String driver = "oracle.jdbc.OracleDriver";
	private String url = "jdbc:oracle:thin:@127.0.0.1:1521:xe";
	private String userName = "scott";
	private String userPassword = "tiger";
	
	//1. private 생성자 
	// 이 단계에서 Driver Loading 해줌 
	private ProductDAO() {
		try {
			Class.forName(driver);
			System.out.println("ProductDAO 객체 생성");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	//3. public static method(getInstance())로 공유
	/* public static [return type] [method 명] () { 
	 * 		return [DAO object-instance];
	 * }
	 */
	public static ProductDAO getInstance() {
		return instance;
	}
	
	/* getAllMemberCount() method
	 * 서비스에 제공할 메서드 : 전체 상품 수 반환
	 */
	public int getAllMemberCount() throws SQLException {
		int count = 0;
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		con = DriverManager.getConnection(url,userName , userPassword);
		String sql = "SELECT COUNT(*) FROM web_product";
		pstmt = con.prepareStatement(sql);
		rs = pstmt.executeQuery();
		if (rs.next()) {
			count = rs.getInt(1);
		}
		
		closeAll(rs, pstmt, con);
		
		return count;
	}
	
	/* findProductById() method
	 * 아이디에 맞는 상품 정보(ProductVO) 제공하는 메서드
	 */
	public ProductVO findProductById(String id) throws SQLException {
		ProductVO vo = null;
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try {
			con = DriverManager.getConnection(url, userName, userPassword);
			String sql = "SELECT id, name, maker, price "
					+ "FROM web_product "
					+ "WHERE id = ?";
			pstmt = con.prepareStatement(sql);
			pstmt.setString(1, id);
			rs = pstmt.executeQuery();
			if (rs.next()) {
				vo = new ProductVO(rs.getString("id"), rs.getString("name"),
						rs.getString("maker"), rs.getInt("price"));
			}
		} finally {
			closeAll(rs, pstmt, con);
		}
		return vo;
		
	}
	
	
	/* findAllProductList() method
	 * table에 있는 모든 상품 정보 list로 가져오기
	 */
	public ArrayList<ProductVO> findAllProductList() throws SQLException{
		ArrayList<ProductVO> list = new ArrayList<ProductVO>();
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try {
			con = DriverManager.getConnection(url, userName, userPassword);
			String sql = "SELECT id, name, maker, price FROM web_product ";
			pstmt = con.prepareStatement(sql);
			rs = pstmt.executeQuery();
			
			while(rs.next()) {
				ProductVO vo = new ProductVO();
				vo.setId(rs.getString("id"));
				vo.setName(rs.getString("name"));
				list.add(vo);
			}
			
		} finally {
			closeAll(rs, pstmt, con);
		}	
		
		return list;
	}
	
	/* closeAll() method
	 * JDBD용 closeAll 메서드
	 */
	public void closeAll(ResultSet rs, PreparedStatement pstmt,
			Connection con) throws SQLException {
		if (rs!=null)
			rs.close();
		if (pstmt!=null)
			pstmt.close();
		if (con!=null)
			con.close();
	}
}

 

/ProductVO.java

package model;

public class ProductVO {
	private String id;
	private String name;
	private String maker;
	private int price;
	
	
	public ProductVO() {
		super();
	}

	public ProductVO(String id, String name, String maker, int price) {
		super();
		this.id = id;
		this.name = name;
		this.maker = maker;
		this.price = price;
	}

	public String getId() {
		return id;
	}

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

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getMaker() {
		return maker;
	}

	public void setMaker(String maker) {
		this.maker = maker;
	}

	public int getPrice() {
		return price;
	}

	public void setPrice(int price) {
		this.price = price;
	}

}

View

 

/index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Model2 MVC 상품관리</title>
</head>
<body>
<%--
		index.jsp -- request -- ProductTotalCountServlet < -- > ProductDAO
                                         ㅣ
                                    forward 방식으로 이동
                                         ㅣ
                                  product-totalcount.jsp
 --%> 
<ul>
	<li><a href = "ProductTotalCountServlet">전체 상품 수 조회</a></li>
</ul>
</body>
</html>

 

1. 총 상품 수 조회 jsp (View)

/product-totalcount.jsp

<%@page import="model.ProductDAO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>전체 상품 수 조회</title>
</head>
<body bgcolor="yellow">
<a href = "index.jsp">Home</a>
<hr>
<%-- 
	Controller(ProductTotalCountServlet)에서 
	totalcount를 받아옴 
--%>
전체 상품 수 : <%=request.getAttribute("totalcount") %>

</body>
</html>

 

2. 아이디로 상품 검색 jsp (View)

/find-product.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>상품 검색</title>
</head>
<body>
<form action="FindProductByIdServlet">
	상품 아이디 <input type="number" name="productId" required="required">
	<input type="submit" value="검색">
</form>
</body>
</html>

 

/find-ok.jsp

<%@page import="model.ProductVO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<link type="text/css" rel="stylesheet" href="css/mystyle.css">
<head>
<meta charset="UTF-8">
<title>상품 상세 정보</title>
</head>
<body>
	<table>
		<thead>
			<tr>
				<th>아이디</th>
				<th>이름</th>
				<th>상표</th>
				<th>가격</th>
			</tr>
		</thead>

		<tbody>
			<tr>
				<% ProductVO vo = (ProductVO) request.getAttribute("vo"); %>
				<td><%=vo.getId() %></td>
				<td><%=vo.getName() %></td>
				<td><%=vo.getMaker() %></td>
				<td><%=vo.getPrice() %></td>	
			</tr>
		</tbody>
	
	</table>
</body>
</html>

 

/find-fail.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>오류 페이지</title>
</head>
<body>
	<script type="text/javascript">
		alert("상품 정보가 없습니다.");
		location.href = "find-product.jsp";
	</script>
</body>
</html>

 

3. 전체 상품 리스트 조회하기 jsp (View)

/product-list.jsp

<%@page import="model.ProductVO"%>
<%@page import="java.util.ArrayList"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<link type="text/css" rel="stylesheet" href="css/mystyle.css">
<head>
<meta charset="UTF-8">
<title>상품 목록</title>
</head>
<body>
<%
	@SuppressWarnings("unchecked")
	ArrayList<ProductVO> list 
		= (ArrayList<ProductVO>) request.getAttribute("list");
%>
	<table>
		<thead>
			<tr>
				<th>ID</th>
				<th>NAME</th>
			<tr>
		</thead>	

		<tbody>
		<%-- 아래에 있는 상품명을 클릭하면 상품 상세정보가 조회된다. --%>
			<%  for (ProductVO vo:list) { %>
				<tr>
					<td><%=vo.getId() %></td>
					<td><a href = "FindProductByIdServlet?productId=<%=vo.getId()%>">
						<%=vo.getName()%></a></td>
				</tr>
			<%  }  %>
		</tbody>
	</table>
</body>
</html>

Controller

 

1. 총 상품 수 조회 Serlvet (Controller)

/ProductTotalCountServlet.java - Serlvet

package model;

import java.io.IOException;
import java.sql.SQLException;

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("/ProductTotalCountServlet")
public class ProductTotalCountServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    
	protected void doGet(HttpServletRequest request, 
			HttpServletResponse response) 
					throws ServletException, IOException {
		
		// Model과 연동 (dao에서 service가 실행)
		ProductDAO dao = ProductDAO.getInstance();
		
		// count : 전체 상품 수
		int count;
		try {
			count = dao.getAllMemberCount();
			
			// 연동 결과 View에 공유 (-> product-totalcount.jsp)
			// request.serAttrubute(name, value)
			request.setAttribute("totalcount", count);
			
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		//forward 방식으로 view로 이동
		// (product-totalcount.jsp)
		request.getRequestDispatcher("product-totalcount.jsp").forward(request, response);
	}

}

 

2. id로 상품 정보 검색하기 Serlvet (Controller)

/FindProductByIdServlet.java - Serlvet

package step2;

import java.io.IOException;
import java.sql.SQLException;

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 model.ProductDAO;
import model.ProductVO;

@WebServlet("/FindProductByIdServlet")
public class FindProductByIdServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
           
	protected void doGet(HttpServletRequest request, 
			HttpServletResponse response) 
					throws ServletException, IOException {
		// find-product.jsp에서 id를 받아서
		String id = request.getParameter("productId");
		
		// ProductDAO에 접근해서 ProductVO 받아오기
		// Model과 연동 (dao에서 service가 실행)		
		try {
			ProductVO vo = ProductDAO.getInstance().findProductById(id);
			String viewName = null;
			
			// 연동 결과 View에 공유 & View로 이동
			if (vo == null) { // id가 없으면(-> find_fail.jsp)
				viewName = "find_fail.jsp";
			} else { // id가  있으면 정보 공유(-> find_ok.jsp)
				viewName = "find_ok.jsp";
				request.setAttribute("vo", vo);
			}
			
			request.getRequestDispatcher(viewName).forward(request, response);
			
		} catch (SQLException e) {
			e.printStackTrace();
		}
	
	}

}

 

3. 전체 상품 리스트 조회하기 Serlvet (Controller)

/ProductListServlet.java - Serlvet

package step3;

import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;

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 model.ProductDAO;
import model.ProductVO;


@WebServlet("/ProductListServlet")
public class ProductListServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    
	protected void doGet(HttpServletRequest request, 
			HttpServletResponse response)
					throws ServletException, IOException {
		
		// ProductDAO에 접근해서 ProductVO 받아오기
		// Model과 연동 (dao에서 service가 실행)		
		ArrayList<ProductVO> list = null;
		try {
			list = ProductDAO.getInstance().findAllProductList();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		// 연동 결과 View에 공유
		request.setAttribute("list", list);
		
		//View로 이동
		request.getRequestDispatcher("product-list.jsp").forward(request, response);
	}

	
}

index.jsp 브라우저 화면 (초기화면)


1. 총 상품 수 조회 결과 화면


2. id로 상품 정보 검색 화면 ( find-product.jsp )


2_1. 있는 id를 검색했을 때( find_ok.jsp)  결과 화면

 

2_1. 없는 id를 검색했을 때 (find_fail.jsp)  결과 화면 -> 다시 find-product.jsp 화면으로 감

 


3. 전체 상품 리스트 테이블 조회 결과 화면

3_1. 이름 클릭하면 상세정보 나온다

 

728x90
반응형