Software Architecture

기록하는 용도·2022년 10월 1일
0

Software Architecture 소프트웨어 아키텍쳐

소프트웨어 아키텍쳐(설계구조 or 설계양식)는 소프트웨어 구성 요소(component or java bean)들 사이의 관계를 표현하는 것을 말한다.




초기 개발 방식

Servlet 또는 JSP < -- > Database



초기 개발 방식 예제

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="java.sql.*"%>
<%
		//member db에 접근해 회원수를 보여주는 웹페이지
		Connection con = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:xe","scott","tiger");
		String sql = "select count(*) from member";
		PreparedStatement pstmt = con.prepareStatement(sql);
		ResultSet rs = pstmt.executeQuery();
		rs.next();
		int count = rs.getInt(1);
		rs.close();
		pstmt.close();
		con.close();
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>web 초기 개발 방식</title>
 <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.slim.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container pt-3">
<h4>회원수 <%=count %></h4>
</div>
</body>
</html>

초기 개발 방식은 jsp(드물지만 서블릿)와 db와 연동한다.
이런식의 개발은 회원수를 보여주는 로직이 다른페이지에 있으면 또 소스를 복사 붙여넣기 해야한다.






Model 1 Architecture

JSP <--> Java Beans <--> Database


Model1에서 JSP의 역할

client에게 form과 같은 화면을 제공한다.
client가 보낸 요청을 분석하고 요청에 따른 java bean(DAO..)과 연동해 그 결과를 클라이언트에게 응답한다.


Model1에서 Java Beans 역할

bean == component와 동일한 의미로 business logic과 data access logic을 담당한다.


Model1 예제

<%@page import="model.MemberDAO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Model1 설계 방식 적용</title>
 <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.slim.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container pt-3">
회원수 <%=new MemberDAO().findMemberCount() %>
</div>
</body>
</html>
package model;

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

public class MemberDAO {
	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();
	}

	public int findMemberCount() throws SQLException {
		int count = 0;
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			con = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:xe", "scott", "tiger");
			String sql = "select count(*) from member";
			pstmt = con.prepareStatement(sql);
			rs = pstmt.executeQuery();
			rs.next();
			count = rs.getInt(1);
		} finally {
			closeAll(rs, pstmt, con);
		}
		return count;
	}
 }

Model1은 초기에서 분화가 된다. 초기의 jsp가 쪼개져서 java bean dao에서 메소드만 호출할 수 있도록 한다.


Model1 예제2

step1

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>step3-model1-findbyid-form</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet"
	href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
<script
	src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.slim.min.js"></script>
<script
	src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script
	src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
	<div class="container pt-3">
		<h4>Model 1 Architecture 회원검색</h4>
		<form action="step3-model1-findbyid-form-action.jsp">
			<input type="text" name="memberId" placeholder="회원아이디"
				required="required">
			<button type="submit">검색</button>
		</form>
	</div>
</body>
</html>

step2

<%@page import="model.MemberVO"%>
<%@page import="model.MemberDAO"%>
<%@ 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>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet"
	href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
<script
	src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.slim.min.js"></script>
<script
	src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script
	src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>



<%
   MemberDAO dao=new MemberDAO();
   MemberVO memberVO=new MemberVO();
   
   String id=request.getParameter("memberId");
   
   memberVO=dao.findMemberById(id);
   
   if (memberVO!=null) {
%>
		아이디 : <%=id %><br>
        이름 :  <%=memberVO.getName() %><br>
        주소 :  <%=memberVO.getAddress() %>
  <% } else { %>
<script type="text/javascript">
        alert("<%=id%>에 해당하는 회원이 없습니다!");
        location.href = "step3-model1-findbyid-action";
</script>
  <% } %>
</div>
</body>



Model 2 Architecture

Model1 -> Model2 아키텍쳐 변화의 특징

-> java beans 역할은 동일, MVC의 Model 영역
-> Model1에서 jsp가 담당하는 역할이 분화 : Controller와 View로 분업화


Model 2 Architecture : MVC Design Pattern




MVC는 Model2 아키텍처의 근간을 이루는 Design Pattern이다.
자바(or 스프링) 웹 어플리케이션 설계 방식의 근간을 이루는 디자인 패턴이 MVC다.

Model : Business Logic과 Data Access Logic을 담당 / Java Component(or Bean)가 담당, (DAO, Service, VO, DTO .. )
View : client 에게 response 즉 응답을 담당, 화면 표현 /JSP가 담당
Controller : client의 request를 분석, Model과 연동, 연동 결과를 적절한 View를 선택해(forward or redirect) 응답하게한다. /Servlet이 담당

여기서 ⑤를 제어하는 방식이 나뉜다.
forward방식과 redirect방식으로 필요에 따라 쓰게된다.


1. forward 이동방식

기존 request와 response 유지시킨 채 제어를 이동한다. => 주로 정보 조회시 사용한다.
WAS(Web Container)상에서 이동되므로 클라이언트 측 url은 변동이없다.


장점) request와 response 유지시킨다.
즉 클라이언트 측은 이동된 것을 알지 못한다.이런 특성으로 클라이언트 측에서 새로고침(f5)시에는 기존 동작이 반복된다.
-> 등록, 삭제 , 수정에는 적합하지않다.



Model2 forward 예제

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>index.jsp</title>
 <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.slim.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container pt-3">
<%-- 웹어플리케이션 설계방식, Spring Framework(SpringMVC)에 적용된 디자인 패턴--%>
<h4>Model 2 Architecture MVC Design Pattern</h4>
<%--
		회원수 보기
		index.jsp에서 --- MemberCountServlet으로 갈거고(얘가 컨트롤러) --- MemberDAO를 걸쳐서 --- DB로 간다
														|
														| forward 방식 이동
														|
											member-count.jsp
 --%>
<ul>
	<%-- forward 이동방식 --%>
	<li><a href="MemberCountServlet">회원수보기</a></li>
	<%-- redirect 이동방식
			index.jsp --- RedirectTestServlet
											| (모델안거치고)
											|	redirect 방식 이동
											|
									redirect-result.jsp
	--%>
	<li><a href="RedirectTestServlet">RedirectTest</a></li>
	<%--
		회원수 보기
		index.jsp에서 ---ForwardTestServlet으로 갈거고(얘가 컨트롤러) --- MemberDAO를 걸쳐서 --- DB로 간다
														|
														| forward 방식 이동
														|
											forward-result.jsp
 --%>
	
	<li><a href="ForwardTestServlet?command=search">ForwardTest</a></li>
	<li><a href="findbyaddress-form.jsp">주소로 회원검색</a></li>
</ul>
<img src="model2.png" width="400">
</div>
</body>
</html>

package controller;

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.MemberDAO;

/**
 * Servlet implementation class MemberCountServlet
 */
@WebServlet("/MemberCountServlet")
public class MemberCountServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
    /**
     * Model2 MVC 설계방식에서 컨트롤러 역할을 담당
     * 클라이언트 요청 분석
     * 모델과 연동
     * 연동 결과를 저장후 적절한 View를 선택해 이동시켜
     * 클라이언트에게 응답하게된다.
     */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//System.out.println(getServletConfig().getServletName());//servletconfig객체가있으니까 정보를확인할 수 있다. 반응이오는지살펴보기
		System.out.println(getServletName()+ " doGet() 실행"); //
		MemberDAO memberDAO = new MemberDAO();
		try {
			int count = memberDAO.findMemberCount();
			request.setAttribute("count",count); //뷰가 getAttribute하는것임, View(jsp)에게 Model과 연동한 결과를 공유
			//request라는 객체의 공간에 count를 공유해서 view가 찾도록한다.
			//내가할일 끝났으니까 View로 제어를 이동
			
			//forward 이동 방식은 request와 response를 유지시킨 상태에서 이동함
			//그래서 동일한 request를 view에서도 쓸 수  있다.
			request.getRequestDispatcher("member-count.jsp").forward(request, response); //view path를 주고 
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

}

Model2 MVC 설계방식에서 serlvet은 컨트롤러 역할을 담당한다.

request.setAttribute("count",count);

이 코드의 목적은 응답할 jsp가 쓸 데이터를 request 객체에 공유하는것이다.

request.getRequestDispatcher("member-count.jsp").forward(request, response);

forward라는 메소드가 request와 reponse를 유지시킨 상태로 "member-count.jsp"화면으로 간다.
그 화면에 도달해 servlet에서 공유한 정보를 가지고 응답을 한다.

member-count.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>member-count</title>
 <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.slim.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container pt-3">
<%--
		컨트롤러(서블릿)가 모델과 연동 후 공유한 정보를 화면에 표현, 클라이언트에 응답하는 역할에 집중
 --%>
<h4>총 회원수 명<%=request.getAttribute("count") %></h4>
</div>
</body>
</html> 



Model2 forward 예제2

업로드중..

Model2 forward 예제1과 마찬가지로 첫 화면이다.
ForwardTest를 실행하면 forward 이동 방식의 테스트를 할 수 있다.

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>index.jsp</title>
 <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.slim.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container pt-3">
<%-- 웹어플리케이션 설계방식, Spring Framework(SpringMVC)에 적용된 디자인 패턴--%>
<h4>Model 2 Architecture MVC Design Pattern</h4>
<%--
		회원수 보기
		index.jsp에서 --- MemberCountServlet으로 갈거고(얘가 컨트롤러) --- MemberDAO를 걸쳐서 --- DB로 간다
														|
														| forward 방식 이동
														|
											member-count.jsp
 --%>
<ul>
	<%-- forward 이동방식 --%>
	<li><a href="MemberCountServlet">회원수보기</a></li>
	<%-- redirect 이동방식
			index.jsp --- RedirectTestServlet
											| (모델안거치고)
											|	redirect 방식 이동
											|
									redirect-result.jsp
	--%>
	<li><a href="RedirectTestServlet">RedirectTest</a></li>
	<%--
		회원수 보기
		index.jsp에서 ---ForwardTestServlet으로 갈거고(얘가 컨트롤러) --- MemberDAO를 걸쳐서 --- DB로 간다
														|
														| forward 방식 이동
														|
											forward-result.jsp
 --%>
	
	<li><a href="ForwardTestServlet?command=search">ForwardTest</a></li>
	<li><a href="findbyaddress-form.jsp">주소로 회원검색</a></li>
</ul>
<img src="model2.png" width="400">
</div>
</body>
</html>
<li><a href="ForwardTestServlet?command=search">ForwardTest</a></li>

ForwardTestServlet?command=search로 넘어간다.

ForwardTestServlet.java

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;

/**
 * Servlet implementation class ForwardTestServlet
 */
@WebServlet("/ForwardTestServlet")
public class ForwardTestServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println(getServletName() + "doGet()");
		//view(jsp)에 공유할 정보를 request에 저장
		request.setAttribute("info","Model(DAO) 연동 정보");
		request.getRequestDispatcher("forward-result.jsp").forward(request, response);
	}

}

forward-result.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>forward-result.jsp</title>
 <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.slim.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container pt-3">
<%--
			Controller(Servlet)가 request에 공유한 정보  request.setAttribute("")
			View (jsp)에서는 request.getAttribute("")
			client가 보낸 form data 또는 query string은 view(jsp)에서는
			request.getParameter(""); 로 받는다.
 --%>
forward-result.jsp<br>
 컨트롤러(서블릿)에서 공유한 정보 : <%=request.getAttribute("info") %>
 client가 전송한 data : <%=request.getParameter("command") %>
 <%-- 폼데이터는 겟파람!! 클라이언트가 보내준게 getAttr --%>
</div>
</body>
</html>
ForwardTestServlet?command=search

view에서는 query string 또는 form data를 request.getParameter로 받는다.



2. redirect 이동 방식

브라우저에게 이동 url을 지정, 등록 수정 삭제 작업에 적합하다.
기존 request와 response는 유지되지않고 새로운 request, response가 생성된다.
클라이언트 측으로 이동할 url을 지정해서 브라우저가 이동해 view 정보를 보도록 이동하는 방식이다.
업로드중..



redirect 예제1

RedirectTestServlet

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;

/**
 * Servlet implementation class RedirectTestServlet
 */
@WebServlet("/RedirectTestServlet")
public class RedirectTestServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println(getServletName()+ "doGet()");
		request.setAttribute("info", "Model(DAO) 연동 정보"); 
		response.sendRedirect("redirect-result.jsp");
	}


}

redirect-result.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>redirect-result</title>
 <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.slim.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container pt-3">
<%-- redirect 이동방식은 request와 response가 유지되지않으므로 
		Controller(Servlet)에서 공유한 정보를 반환받을 수 없어서 null이 출력 --%>
	redirect-result.jsp <%=request.getAttribute("info") %>
</div>
</body>
</html>

0개의 댓글