# MVC(Model - View - Controller, 모델 뷰 컨트롤러)
소프트웨어 설계에서 세 가지 구성 요소인 모델(Model), 뷰(View), 컨트롤러(Controller)를 이용한 설계 방식
// Tip - Business Logic(비즈니스 로직)
업무에 필요한 데이터 처리를 수행하는 응용 프로그램의 일부
데이터 입력, 수정, 조회 및 보고서 처리 등을 수행하는 루틴
즉, 보이는 것의 그 뒤에서 일어나는 각종 처리 의미
- Model : 소프트웨어 내 데이터
View : 사용자에게 보이는 화면 내용
Controller : 모델과 뷰의 상호 작용을 관리함
- Model 1 vs Model 2
모델 | 장점 | 단점 |
Model 1 | 배우기 쉬움 JAVA 언어를 모르더라도 구현이 가능함 기능과 JSP가 직관적으로 연결되어 있음 하나의 JSP가 하나의 기능과 연결되어 있음 |
로직코드와 View코드가 혼합되어 JSP 코드가 복잡해짐 View 변경 시 논리 코드의 빈번한 복사로 인한 유지보수 작업의 불편함 통합권한 인증코드를 JSP 단위로 적용해야 함 |
Model 2 | 로직코드와 View 코드의 분리에 따른 유지보수의 편리함 Controller Servlet에서 집중적인 작업처리 가능 확장의 용이함 |
JAVA 언어에 익숙하지 않으면 접근하기 어려움 작업량이 많음 디버깅 작업의 어려움 |
① MVC Model 1
② MVC Model 2
# MVC 패턴의 구성
- Controller(서블릿)
View와 Model을 연결시켜주는 핵심요소
// Tip - 서블릿으로 Controller를 구성하는 이유
초기 진입점이자 뷰와 모델을 연동하는 역할을 하기 때문!
(서블릿은 웹에서 요청을 받을 수 있는 자바코드 형태이다)
- View(JSP)
화면 출력 부분에 해당
절대 데이터베이스 연동과 같은 비즈니스 로직을 구현하지 않으며,
Controller를 통하여 Model에서 처리한 결과를 화면에 출력할 때 사용한다.
- Model
실제로 비즈니스 로직을 실행하는 부분
비즈니스 로직을 처리하여 얻은 결과를 Controller를 통해 View 페이지로 전달하게 됨
데이터베이스 작업을 할 경우 Model 부분에서 이루어지게 됨
ex)
- frontControllerEx.jsp
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>Insert title here</title>
</head>
<body>
<a href="insert.do">insert</a>
<hr />
<a href="http://localhost:8080<%=request.getContextPath()%>/update.do">update</a>
<hr />
<a href="http://localhost:8080/FrontController/select.do">select</a>
<hr />
<a href="<%=request.getContextPath()%>/delete.do">delete</a>
</body>
</html>
- frontController.java
package com.tistory.coderbear;
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("*.do") // .do 확장자가 모두 이 파일로 오게 됨
public class FrontController extends HttpServlet {
private static final long serialVersionUID = 1L;
public FrontController() {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("doGet");
actionDo(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("doPost");
actionDo(request, response);
}
private void actionDo(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("actionDo");
String uri = request.getRequestURI(); // 프로젝트 + 파일경로
System.out.println("uri : " + uri);
String conPath = request.getContextPath(); // 프로젝트 path
System.out.println("conPath : " + conPath);
String command = uri.substring(conPath.length());
System.out.println("command : " + command);
if(command.equals("/insert.do")){
System.out.println("insert");
System.out.println("----------------");
}else if(command.equals("/update.do")){
System.out.println("update");
System.out.println("----------------");
}else if(command.equals("/select.do")){
System.out.println("select");
System.out.println("----------------");
}else if(command.equals("/delete.do")){
System.out.println("delete");
System.out.println("----------------");
}
}
}
Q. FrontController패턴과 Command 패턴으로 게시판의 리스트를 구현.
Command 패턴을 활용하는 클래스는 주어진 Command Interface를 활용한다.
- context.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--><!-- The contents of this file will be loaded for each web application --><Context>
<!-- Default set of monitored resources. If one of these changes, the -->
<!-- web application will be reloaded. -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!--
<Manager pathname="" />
-->
<Resource
name="jdbc/testdb" // CONNECTION_POOL_RESOURCE_NAME 부분에 동일하게 적어야 함! testdb = 데이터베이스명
auth="Container"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/testdb?serverTimezone=UTC"
username="root"
password="1234"
type="javax.sql.DataSource"
maxTotal="50"
maxWaitMillis="1000"
removeAbandonedOnBorrow="true"
removeAbandonedTimeout="5"
logAbandoned="true"
/>
<!--
name="jdbc/testdb" 1. name : JNDI로 호출될 이름을 설정한다. (접근 -> java:comp/env/jdbc/testdb)
auth="Container" 2. auth : DBCP를 관리할 관리자 (Container or Application)
driverClassName="com.mysql.cj.jdbc.Driver" 3. driverClassName : JDBC를 이용하기 위한 드라이버 클래스
url="jdbc:mysql://localhost:3306/testdb?serverTimezone=UTC" 4. url : DB의 접속 URL(속성으로 자동 재 접속을 선택했다.)
username="root" 5. username : DB의 계정 명
password="1234" 6. password : 계정에 대한 비밀번호
type="javax.sql.DataSource" 7. type : 해당 resource의 return type(DataSource는 Connection 객체를 반환할 수 있다.)
maxTotal="50" 8. maxActive : 최대 접속 허용 개수
maxWaitMillis="1000" 9. DB 연결이 반환되는 Timebout의 최대 시간(-1은 무한 대기)
removeAbandonedOnBorrow="true" 10. 사용할 수 있는 커넥션이 부족해지면 DBCP(DataBase Connection Pool)은 버려진 커넥션을 찾아 복구한다.
removeAbandonedTimeout="5" 11. 커넥션이 버려졌다고 간주되기 전에 사용되지 않은 시간(초)를 설정합니다.
logAbandoned="true" 12. 만일 커넥션 자원을 낭비한 코드 위치의 로그를 남깁니다.
-->
</Context>
- Command.java
package com.tistory.coderbear.command;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface Command {
void excute(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException;
}
A.
[ view ]
- list.jsp
<%@page import="com.tistory.coderbear.dto.BoardDTO"%>
<%@page import="com.tistory.coderbear.dao.BoardDAO"%>
<%@page import="java.util.ArrayList"%>
<%@page import="com.tistory.coderbear.*"%>
<%@ page import="java.sql.*"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="description" content="HTML Study">
<meta name="keywords" content="HTML,CSS,XML,JavaScript">
<meta name="author" content="coderbear">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>게시판 목록</title>
</head>
<body>
<h3>목록</h3>
<%
ArrayList<BoardDTO> list = (ArrayList<BoardDTO>)request.getAttribute("list");
for(int i=0;list != null && i<list.size();i++)
{
BoardDTO dto = list.get(i);
out.print("번호 " + dto.getNo()+"<br>");
out.print("제목 " + dto.getTitle()+"<br>");
out.print("작성자 " + dto.getName()+"<br>");
out.print("작성일 " + dto.getWtime()+"<br>");
out.print("조회수 " + dto.getRcnt()+"<br><br>");
}
%>
<a href="write.do">글쓰기</a>
</body>
</html>
- write.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="description" content="HTML Study">
<meta name="keywords" content="HTML,CSS,XML,JavaScript">
<meta name="author" content="coderbear">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Insert title here</title>
</head>
<body>
</body>
</html>
[ Controller ]
- FrontController.java
package com.tistory.coderbear.controller;
import java.io.IOException;
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 com.tistory.coderbear.command.Command;
import com.tistory.coderbear.command.ListCommand;
@WebServlet("*.do") // .do 확장자로 끝나는 모든 파일은 이 서블릿에서 처리함
public class FrontController extends HttpServlet {
private static final long serialVersionUID = 1L;
public FrontController() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doAction(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doAction(request, response);
}
public void doAction(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
String commandName = request.getServletPath(); // 마지막 요청을 가지고 옴
String viewPage = null;
Command command = null;
if(commandName.equals("/list.do")) {
command = new ListCommand();
command.excute(request, response);
viewPage = "list.jsp";
}else if(commandName.equals("/write.do")) {
viewPage = "write.jsp";
}
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPage);
dispatcher.forward(request, response);
}
}
[ model ]
- Command.java
package com.tistory.coderbear.command;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface Command {
void excute(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException;
}
- ListCommand.java
package com.tistory.coderbear.command;
import java.io.IOException;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.tistory.coderbear.dao.BoardDAO;
import com.tistory.coderbear.dto.BoardDTO;
public class ListCommand implements Command {
@Override
public void excute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
BoardDAO dao = BoardDAO.getBoardDAO();
ArrayList<BoardDTO> list = dao.listDAO();
request.setAttribute("list", list);
}
}
- BoardDAO.java // 저장이 아닌 데이터베이스와의 엑세스를 위함
package com.tistory.coderbear.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import com.tistory.coderbear.dto.BoardDTO;
public class BoardDAO {
private static BoardDAO boardDAO = new BoardDAO();
private String CONNECTION_POOL_RESOURCE_NAME = "jdbc/testdb";
private final String TABLE_NAME = "board";
private DataSource dataSource;
private final String SELECT_ALL_BOARD_SQL = "SELECT no, title, name, wtime, rcnt FROM " + TABLE_NAME + " ORDER BY no DESC";
public BoardDAO() {
try {
Context context = new InitialContext();
dataSource = (DataSource)context.lookup("java:comp/env/" + CONNECTION_POOL_RESOURCE_NAME);
} catch (NamingException e) {
e.printStackTrace();
}
}
public static BoardDAO getBoardDAO() {
return boardDAO;
}
public Connection getConnection() {
Connection conn = null;
try {
conn = dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public void close(ResultSet rs, PreparedStatement ps, Connection conn){
try {
if(rs != null) rs.close();
if(ps != null) ps.close();
if(conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void close(PreparedStatement ps, Connection conn){
try {
if(ps != null) ps.close();
if(conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public ArrayList<BoardDTO> listDAO()
{
ArrayList<BoardDTO> list = new ArrayList<BoardDTO>();
Connection conn = getConnection();
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
pstmt = conn.prepareStatement(SELECT_ALL_BOARD_SQL);
rs = pstmt.executeQuery();
while(rs.next())
{
BoardDTO dto = new BoardDTO();
dto.setNo(rs.getInt("no"));
dto.setTitle(rs.getString("title"));
dto.setName(rs.getString("name"));
dto.setWtime(rs.getString("wtime"));
dto.setRcnt(rs.getInt("rcnt"));
list.add(dto);
}
} catch(SQLException e) {
e.printStackTrace();
} finally {
close(rs, pstmt, conn);
}
return list;
}
}
[ DTO ]
- BoardDTO.java
package com.tistory.coderbear.dto;
public class BoardDTO {
private int no;
private String title;
private String name;
private String password;
private String email;
private String contents;
private String wtime;
private int rcnt;
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getContents() {
return contents;
}
public void setContents(String contents) {
this.contents = contents;
}
public String getWtime() {
return wtime;
}
public void setWtime(String wtime) {
this.wtime = wtime;
}
public int getRcnt() {
return rcnt;
}
public void setRcnt(int rcnt) {
this.rcnt = rcnt;
}
}
'Web > JSP' 카테고리의 다른 글
[필기정리] Day83 - MIME, Proxy server, http 응답코드 등 (0) | 2020.10.26 |
---|---|
[실습문제] Day81 - MVC Model2 문제 및 해답 (0) | 2020.10.22 |
[필기정리]Day79-1 - Connection Pool, JNDI, Data Source 등 (0) | 2020.10.20 |
[필기정리]Day78 - ActionTag, JavaBeans, DAO, DTO, VO 등 (0) | 2020.10.20 |
[개인실습] JSP로 회원형 게시판 만들기 (0) | 2020.10.19 |