다연이네

[days08] MVC 패턴 본문

JSP

[days08] MVC 패턴

 다연  2021. 1. 5. 23:50
반응형

MVC 패턴

 

mvc 패턴을 알려면
모델1 구조와 모델 2구조를 알아야 한다.

모델1 구조는 클라이언트가 요청하면 JSP/Servlet이  응답해주는 구조이다.  클 <->JSP/Servlet
 장점) 직관적으로 연결되어 쉽다.
 단점) 로직코드와 뷰 코드가 혼합되어 JSP 코드가 복잡해지며, 유지보수가 힘들다. 
         코드 중복이 발생하기 쉽다

웹사이트는 유지보수가 빈번히 발생하기 때문에 모델1을 사용하지 않는다.

모델2는 MVC 패턴으로, 로직-모델, 뷰 코드-뷰 로 분리하여 컨트롤러라는 서블릿이 모든 요청에 대한 흐름 제어를 한다.
 로직 코드와 뷰 코드를 분리해 유지보수가 쉬워지며, 컨트롤러 서블릿에서 권한 검사나 인증과 같은 공통 기능 처리가
가능하다. 
 장점) 유지보수가 쉽다, 확장이 용이하다.
 단점) 작업량이 많고 접근이 어렵다.

더 오래걸리고 힘들더라도 mvc 패턴을 사용해야 한다.

 

     1. [MVC 패턴]
        - 모델 1 구조  (유지보수 어려움)
           클라이언트 -(요청)-> JSP/Servlet 
                      <-(응답)-
        - 모델 2 구조 (==MVC 패턴) 
          
          클 -(요청)->       [C]ontroller
             list.do         list.do -> 컨트롤러가 서블릿 객체를 찾아 일 시킴 -> 로직 처리(모델[M]odel) 
             //(실질적으로 로직 처리하는 애는 모델 객체이고 그 모델 객체를 찾는 역할은 컨트롤러가 )
                             list.do(컨트롤러에게 결과물 돌아옴) <- request.setAttribute(ArrayList <> list) 
            <-(응답)- <- 
            
         1) 컨트롤러(Controller) - 모든 요청, 응답에 대한 흐름 제어자(객체)
                 모든 요청을 -> 서블릿
               MVC패턴일 때는 컨트롤러는 서블릿이다.
                 
         2) 모델(Model) - 비지니스 로직 처리하는 객체 (여러개일 수 있음 list.do , write.do ...)
                 자바빈(DTO, VO), 로직처리 서비스 클래스, DAO (서블릿 아님)
                 
         3) 뷰(View) - 사용자에게 결과 화면을 출력하는 객체
               JSP
         
         결과물을 컨트롤러에게 넘기면 보낼땐 jsp로 보내야하는데 보여지는 페이지를 view라고 함
         컨트롤러가 뷰를 찾아 뷰에서 응답하는 것 (뷰에 모델 객체에서 처리된 리스트(결과물)를 넘김)
       뷰(View) list.jsp (list)  EL+JSTL
       
      로직 처리하는 모델이 DAO 같은건가요?
      DAO 기능도 포함되어지고, 서비스에서 DAO 호출했듯이 서비스가 더 넓은 의미로 로직을 처리하는 객체로 보면 된다.
      서비스+DAO 합쳐 모델이라 해도 되고, 서비스를 모델이라 해도 됩니다.
      dao가 완벽한 모델 ? 은 아니다. dao는 db연동만 하는거니까 (로직 처리 중 db연동, 일부분인 것)
      

 

 

ex10.jsp -> 인터페이스 -> 컨트롤러 (+ web.xml, xxx.properties) -> 모델(핸들러) -> 컨트롤러 -> 뷰

 

 

ex10.jsp

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="">
<style>
</style>
<script>
   $(document).ready(function (){     
   });
</script>
</head>
<body>
<!-- 
MVC 패턴의 구현 방법을 설명할 때
컨트롤러(서블릿)가 해야할 두 번째 작업은 사용자가 어떤 것을 요청했는지 분석하는 작업
> 요청 분석하는 방법 (두 가지 사용) *여기서 요청은 : 글쓰기인지, 글보기 인지, ... 등
ㄱ. 특정 이름의 파라미터에 명령어 정보를 전달(?cmd=boardList)
	예) 게시판 글 목록 요청
	http://localhost:80/jspPro/controller(임의대로)?cmd=boardList
	http://localhost:80/jspPro/controller(임의대로)?cmd=boardContent&seq=20
	
ㄴ. 요청URI 자체에 명령어를 사용
	예) 게시판 글 목록 요청
	http://localhost:80/jspPro/board/list/1 (1페이지)
	http://localhost:80/jspPro/board/content/20 (20번 글 내용)
-->

<!-- 1 모델 (Model) implements CommandHandler  -->
<!-- days08.mvc.command.CommandHandler 인터페이스 (우리가 정함)
모든 모델 객체가 구현할 인터페이스 -->

<!-- 2 컨트롤러로 요청이 들어왔는데 요청을 처리할 모델 객체가 없다면 NullHandler 클래스가 처리하도록 -->
<!-- days08.mvc.command.NullHandler -->

<!-- 3 컨트롤러 - 서블릿 클래스 -->
<!-- days08.mvc.command.ControllerUsingFile -->
<!-- 5  -->
<!-- 4 어떤 요청이 들어오면 어떤 모델 객체가 처리해야하는지 설정하는 파일 -->
<!-- WEB-INF > commandHandler.properties -->
<!-- 컨트롤러가 목록을 보고 어떤 요청이 들어오면 어떤 모델로 처리할지 알 수 있도록 -->

<!-- *.do -> 모든 요청은 컨트롤러가 처리 -->
<a href="/jspPro/hello.do">/jspPro/hello.do</a><br>
<a href="/jspPro/board/list.do">/jspPro/board/list.do</a><br>
<a href="/jspPro/board/write.do">/jspPro/board/write.do</a><br>
</body>
</html>

인터페이스

CommandHandler.java

package days08.mvc.command;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

//로직을 처리할 모델(Model)객체가 공통적으로 구현할 인터페이스
public interface CommandHandler {

	// 리턴자료형 String (내맘) - 뷰(View ==JSP) 
	public String process( HttpServletRequest request
			, HttpServletResponse response ) throws Exception ;
	//인터페이스니까 몸체가 있으면 안됨
	
}

NullHandler.java

컨트롤러로 요청이 들어왔는데 요청을 처리할 모델 객체가 없다면 NullHandler 클래스가 처리

package days08.mvc.command;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class NullHandler implements CommandHandler{

	@Override
	public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
		
		response.sendError(HttpServletResponse.SC_NOT_FOUND);
		//요청에 대해 응답을 찾을 수 없다는 에러메시지를 보내겠다
		return null;
	}

}

web.xml

 <servlet>
   <servlet-name>Controller</servlet-name>
   <servlet-class>days08.mvc.command.ControllerUsingFile</servlet-class>
   <init-param><!-- 경로가 바뀌어도 수정하기 쉽게 -->
   <param-name>path</param-name>
   <param-value>/WEB-INF/commandHandler.properties</param-value>
   </init-param> 
   <load-on-startup>1</load-on-startup> <!-- 요청이 아니라 톰캣 스타트될때 서블릿 객체 생성하겠다 -->
  </servlet>
  <servlet-mapping>
   <servlet-name>Controller</servlet-name>
   <url-pattern>*.do</url-pattern> <!--확장자가 do인 모든  -->
  </servlet-mapping>

commandHandler.properties

# Request = Model 
/hello.do=days08.mvc.hello.HelloHandler
/board/list.do=days08.mvc.board.ListHandler
/board/write.do=days08.mvc.board.WriteHandler
/board/content.do=days08.mvc.board.ContentHandler

 

Controller

ControllerUsingFile.java

package days08.mvc.command;

import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

//MV[C] - 컨트롤러(서블릿)
public class ControllerUsingFile  extends HttpServlet{
	
	//오버라이딩 - 제네릭서블릿 (destroy, init)
	@Override
	public void destroy() {
		// 웹 컨테이너 안에서 생성된 서블릿이 제거될때 호출되는 메소드
	}
	
	private Map<String, CommandHandler> commandHandlerMap =
			new HashMap<String, CommandHandler>();

	@Override
	public void init() throws ServletException {
		// 웹 컨테이너 안에서 처음 서블릿이 생성될때 호출되는 메소드
		// 초기화 작업 
		// ㄱ. /WEB-INF/commandHandler.properties 파일을 읽어와
		//		서블릿(컨트롤러)이 어떤 요청에 어떤 모델이 처리하는지 알 수 있어야 함
		//String path = "/WEB-INF/commandHandler.properties"; 경로 바뀌어도 수정 쉽게 path를 web.xml에 주자
		String path = getInitParameter("path");
		String configFilePath = getServletContext().getRealPath(path); 
		//System.out.println(configFilePath);
		//C:\Class\JSPClass\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps
		//    \jspPro\WEB-INF\commandHandler.properties
		
		Properties prop = new Properties();
		try(FileReader fr = new FileReader(configFilePath)) {
			prop.load(fr); //자동으로 프로퍼티에 로딩
		} catch (Exception e) {
			throw new ServletException(e);
		}
		
		//prop -> commandHandlerMap 맵 채워넣는 작업
		Iterator<Object> ir = prop.keySet().iterator(); //모든 key값에서 바로 iterator 받아오기
		while (ir.hasNext()) {
			String url = (String) ir.next(); //요청한 url :  "/hello.do" key값
			String handlerClassFullName = prop.getProperty(url); // "days08.mvc.hello.HelloHandler"
			
			//풀클래스이름으로부터 객체(인스턴스) 생성 -> 맵 추가
			try {
				Class<?> handlerClass = Class.forName(handlerClassFullName); //물리적인 클래스 파일명을 인자로 넣어주면 해당하는 클래스를 반환
				CommandHandler handlerInstance = (CommandHandler)handlerClass.newInstance();
				
				this.commandHandlerMap.put(url, handlerInstance);
				//요청이 들어오면 맵을 뒤져 어떤 요청인지 확인 가능하게 됐다
			} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
				throw new ServletException(e);
			} 
		}
	}//init

	@Override
	protected void doGet(HttpServletRequest request
			, HttpServletResponse response) throws ServletException, IOException {
		String requestURI = request.getRequestURI();
		//System.out.println(requestURI); //     "/jspPro/hello.do"
		String contextPath = request.getContextPath(); // "/jspPro"
		if( requestURI.indexOf(contextPath)==0) { //요청 url이 그 contextPath로 시작하더라
			int beginIndex = contextPath.length();
			requestURI = requestURI.substring(beginIndex); //앞에 /jspPro 잘림 (endIndex 안주면 끝까지)
		}
		//System.out.println(requestURI); //    "/hello.do"
		
		//Model을 찾고 있는 중
		//핸들러(handler) =모델
		CommandHandler handler = this.commandHandlerMap.get(requestURI);
		
		//일 시켜야 함
		//M[View]C == JSP 페이지를 돌려줌
		String viewPage = null;
		try {
			viewPage = handler.process(request, response);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		//포워딩 or 리다이렉트 
		if(viewPage!=null) {
			
			RequestDispatcher dispatcher = request.getRequestDispatcher(viewPage);
			dispatcher.forward(request, response);
		}
		
	}//doGet

	@Override
	protected void doPost(HttpServletRequest request
			, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}//doPost
	
}//class

 

 

Model 1

-HelloHandler.java

package days08.mvc.hello;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import days08.mvc.command.CommandHandler;

//Model
public class HelloHandler implements CommandHandler {

	@Override
	public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
		//일처리
		//
		//
		request.setAttribute("greeting", "안녕하세요... MVC 이해하죠~");
		return "/days08/ex10_hello.jsp"; //View(JSP 페이지)
	}
	
}

View 1

-ex10_hello.jsp

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="">
<style>
</style>
<script>
   $(document).ready(function (){     
   });
</script>
</head>
<body>
<h3>ex10_hello.jsp</h3>
<!-- MVC 패턴 : 처리 -->
${requestScope.greeting }<br>
${greeting }<br>

</body>
</html>

 

 

Model 2

-ListHandler.java

package days08.mvc.board;

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

import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.util.ConnectionProvider;
import com.util.DBConn;

import days05.board.BoardDTO;
import days05.board.PageBlock;
import days08.mvc.command.CommandHandler;

public class ListHandler implements CommandHandler{

	@Override
	public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
		
		String pCurrentPage = request.getParameter("currentPage");
    	int currentPage = pCurrentPage == null ? 1 : Integer.parseInt(pCurrentPage);
    	
    	String pPumberPerPage = request.getParameter("numberPerPage");
    	int numberPerPage = pPumberPerPage == null ? 10 : Integer.parseInt(pPumberPerPage);
    	    	
    	// 검색 추가 코딩
    	String pSearchCondition = request.getParameter("searchCondition");    			
    	int searchCondition = pSearchCondition == null ? 1 : Integer.parseInt(pSearchCondition);
    	
    	String searchWord = request.getParameter("searchWord");
    	if( searchWord == null || searchWord == "") searchWord = "*";
    	
    	//
    	request.setAttribute("searchWord", searchWord);
    	request.setAttribute("searchCondition", searchCondition);
 //DBCP   	 dbconn -> connprovider
		Connection con = ConnectionProvider.getConnection();
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		String sql =" SELECT * " + 
				" FROM ( " + 
				"            SELECT rownum no,  t.* " + 
				"            FROM ( " + 
				"                        SELECT seq, title, writer, writedate, readed  " + 
				"                                  , case   when ( sysdate - writedate)  between 0 and 1/24   then 'true'                   else 'false'          end newmark " +
				"                        FROM TBL_CSTVSBOARD  ";
				
				switch (searchCondition) {
				case 1:  // 제목			
					sql += " WHERE regexp_like( title , ? , 'i' )  ";
					break;
				case  2: // 내용
					sql += " WHERE regexp_like( content , ? , 'i' )  ";
					break;
				case 3: // 작성자
					sql += " WHERE regexp_like( writer , ? , 'i' )  ";
					break;
				case 4: // 제목 + 내용
					sql += " WHERE regexp_like( title , ? , 'i' ) OR  regexp_like( content , ? , 'i' )   ";						
					break;
				} 		 // switch
				
				sql += "                        ORDER BY seq DESC " + 
				"                     )  t " + 
				"            ) b " + 
				" WHERE b.no BETWEEN  ? AND ?  ";
		int start = (currentPage - 1)*numberPerPage+1;
		int end   =  currentPage*numberPerPage;		
		
		ArrayList<BoardDTO> list = null;

		try {
			
			pstmt = con.prepareStatement(sql);
			// BETWEEN  ? AND ?
			pstmt.setInt(1, start);
			pstmt.setInt(2, end);
			
			
			// 검색 조건 1/2/3/4
			if (searchCondition == 4 ) {
				// 검색조건 4  Wherer  ? or ?    Between ? And  ?
				pstmt.setString(1, searchWord);
				pstmt.setString(2, searchWord);
				pstmt.setInt(3, start);
				pstmt.setInt(4, end);
			} else {
				pstmt.setString(1, searchWord);
				pstmt.setInt(2, start);
				pstmt.setInt(3, end);
			} 
			
			rs = pstmt.executeQuery();

			int seq;
			String title;
			String writer;
			Date writedate;  // java.sql.Date 타입.
			int readed;
			boolean newmark ;
			
			BoardDTO dto = null;

			if (rs.next()) {
				list = new ArrayList<BoardDTO>();
				do {
					// 글번호	글제목	   글쓴이	작성일	조회수
					seq = rs.getInt("seq");
					
					title = rs.getString("title");
					if( searchCondition == 1 && !searchWord.equals("*")) {
						title = title.replace(searchWord
								, String.format("<span class=\"searchWord\">%s</span>", searchWord) );
					}
					
					writer = rs.getString("writer");
					writedate = rs.getDate("writedate");
					readed = rs.getInt("readed");
					//newmark =  rs.getBoolean("newmark");  //
					newmark = Boolean.parseBoolean(rs.getString("newmark"));

					dto = new BoardDTO();
					dto.setSeq(seq);
					dto.setTitle(title);
					dto.setWriter(writer);
					dto.setWritedate(writedate);
					dto.setReaded(readed);
					dto.setNewmark(newmark);                   // 

					list.add(dto);
				} while (rs.next());
			} // if 
		} catch (SQLException e1) { 
			e1.printStackTrace();
		}finally {
			try {
				rs.close();
				pstmt.close();
			} catch (SQLException e) { 
				e.printStackTrace();
			}
		} // try  현재 페이지 게시글   ArrayList 채워넣는 코딩
		
		// *** 페이징 처리  시작~ ***
		// 페이징 처리할 때 필요한 것을 필드로 가지는 클래스 선언 : PageBlock
		// (ㄱ). 현재페이지 (ㄴ). 한페이지당 게시글수 ㄷ. 페이지블럭 ㄹ. 페이지블럭 시작, 끝  ㅁ. 이전, 다음
		// 1. 총페이지수 계산
		int totalPages = 0;
		sql =  "SELECT count(*) totalRecords ,  CEIL(count(*)/?) totalPages" 
				+" FROM TBL_CSTVSBOARD ";
		
		switch (searchCondition) {
		case 1:  // 제목			
			sql += " WHERE regexp_like( title , ? , 'i' )  ";
			break;
		case  2: // 내용
			sql += " WHERE regexp_like( content , ? , 'i' )  ";
			break;
		case 3: // 작성자
			sql += " WHERE regexp_like( writer , ? , 'i' )  ";
			break;
		case 4: // 제목 + 내용
			sql += " WHERE regexp_like( title , ? , 'i' ) OR  regexp_like( content , ? , 'i' )   ";						
			break;
		} 		 // switch
		
		try {
			pstmt = con.prepareStatement(sql);
			pstmt.setInt(1, numberPerPage);
			
			pstmt.setString(2, searchWord);
			if (searchCondition == 4 )				pstmt.setString(3, searchWord);
						
			rs = pstmt.executeQuery();

			if( rs.next() )
				totalPages  = rs.getInt("totalPages");	
		} catch (SQLException e) { 
			e.printStackTrace();
		} finally {
			try {
				pstmt.close();
				rs.close();
				//DBConn.close();
				con.close(); // DBCP 반환
			} catch (SQLException e) { 
				e.printStackTrace();
			}
		}  // try  총페이지 수 처리 블럭.
		
		int  numberOfPageBlock = 10;
		int startOfPageBlock = (currentPage-1)/numberOfPageBlock*numberOfPageBlock+1;
		int endOfPageBlock = startOfPageBlock + numberOfPageBlock -1;
		if( endOfPageBlock > totalPages ) endOfPageBlock = totalPages;			 
		
		// 2.  
		PageBlock pageBlock = new PageBlock();
			pageBlock.setCurrentPage(currentPage);
			//pageBlock.setNumberPerPage(numberPerPage);
			//pageBlock.setNumberOfPageBlock(numberOfPageBlock);
			pageBlock.setStart(startOfPageBlock);
			pageBlock.setEnd(endOfPageBlock);
			pageBlock.setPrev( startOfPageBlock != 1 ? true : false   );
			pageBlock.setNext( endOfPageBlock != totalPages ? true : false   );
				
		// 포워딩~
		// ?currentPage=1&numberPerPage=10   list.jsp 파라미터 전달 O
		request.setAttribute("list", list);
		request.setAttribute("pageBlock", pageBlock);
		
		return "/days08/board/ex10_list.jsp";
	}//process

}//class

View 2

-ex10_list.jsp

<%@page import="days05.board.PageBlock"%>
<%@page import="java.util.Iterator"%>
<%@page import="days05.board.BoardDTO"%>
<%@page import="java.util.ArrayList"%>
<%@ page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SS13 - k≡n¡k ( 2020. 12. 29 - t오후 2:25:17 )</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"> 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="">
<style>
table, td, th {
   border: solid 1px gray;
}

table {
   border-spacing: 3px;
   border-collapse: separate;
}

table, tr, td {
   /* border-radius: 3px; */
   /* padding:3px;  */
   
}

tbody tr  td:nth-of-type(2) {
   text-align: left;
}

a {
   text-decoration: none;
   color: black;
}

a:hover {
   color: red;
}
</style>
<!-- 페이징 처리 style -->
<style>
.pagination {
   margin: 0 auto;
   display: flex;
   justify-content: center;
}

.pagination a {
   color: black;
   float: left;
   padding: 4px 8px;
   text-decoration: none;
   transition: background-color .3s;
}

.pagination a.active {
   background-color: dodgerblue;
   color: white;
}

.pagination a:hover:not (.active ) {
   background-color: #ddd;
}
</style>
<style>
.searchWord {
   background-color: yellow;
   color: red;
}
</style>
<style>
.title {
   display: inline-block;
   white-space: nowrap;
   width: 90%;
   overflow: hidden;
   text-overflow: ellipsis;
}
</style>
<script>
   $(document).ready(function (){     
      // list.htm?write=success
      if( '<%= request.getParameter("write") %>' == 'success' ){
         alert("글 쓰기 완료!!!");
      }         
      
      // 상태 유지
      $("#searchCondition").val( '${  requestScope.searchCondition }'); 
      $("#searchWord").val('${ param.searchWord}');

      $(".pagination a").attr("href", function (i, val){ 
          return val 
          +"&searchCondition=${ requestScope.searchCondition}&searchWord=${ param.searchWord}"; 
      });
       
        /* 
       $(".pagination a")
            .eq("${ pageBlock.currentPage / 10 -1 }")
            .addClass("active")
            .attr("href","#");
       */
       
       // ?seq=1
      $("a.title").attr("href", function (i, val){ 
          return val 
          +"&currentPage=${ param.currentPage }&searchCondition=${ requestScope.searchCondition}&searchWord=${ param.searchWord}"; 
      });
   });
</script>
</head>
<body>
 <!-- <h3>list.jsp</h3> -->
 <div align="center">
  <h2>목록 보기 -  EL+ JSTL</h2>
  <a href="/jspPro/board/write.do">글쓰기</a>
  <table style="width:600px;">
    <thead>
      <tr>
        <th width="10%">번호</th>
        <th width="45%">제목</th>
        <th width="17%">작성자</th>
        <th width="20%">등록일</th>
        <th width="10%">조회</th>
      </tr>
    </thead>
    <tbody>
    <c:if test="${ empty list }">
       <tr><td colspan="5">등록된 게시글이 없습니다.</td></tr>
    </c:if>
    <c:if test="${ not empty list }">
        <c:forEach items="${ list }" var="dto">
        
           <tr align="center">
           <td>${ dto.seq }</td>           
           <td>
              <a class="title" href="/jspPro/board/content.do?seq=${ dto.seq }">${ dto.title }</a>
              <c:if test="${ dto.newmark }">
                <img src="/jspPro/days08/board/images/ico-new.gif" alt="" />
              </c:if>
           </td>
           
           <td>
              <c:if test="${ dto.writer eq   'kenik' }">
                <img src="/jspPro/days08/board/images/star.gif" alt="" />
              </c:if> 
               <a href="mailto:${ dto.email }">${ dto.writer }</a>
           </td>
           <td>${  dto.writedate }</td>
           <td>${  dto.readed }</td>
         </tr>
        
        </c:forEach>
    </c:if>
   
    </tbody>
    <tfoot>
      <tr>
        <td colspan="5" align="center">
           <div class="pagination">       
             <c:if test="${ pageBlock.prev }">
                <a href="/jspPro/board/list.do?currentPage=${ pageBlock.start-1 }"> &laquo; </a>
             </c:if>         
             <c:forEach begin="${ pageBlock.start }" end="${ pageBlock.end }" var="i" >
              <a class="${ i eq pageBlock.currentPage  ? 'active':'' }" href="/jspPro/board/list.do?currentPage=${ i }">${ i }</a> 
             </c:forEach>
              <c:if test="${ pageBlock.next }">
                <a href="/jspPro/board/list.do?currentPage=${ pageBlock.end+1 }"> &raquo; </a>
              </c:if>  
           </div>
        </td>
      </tr>
      <tr>
        <td colspan="5" align="center">
          <form>
            <select name="searchCondition" id="searchCondition">
              <option value="1">title</option>
              <option value="2">content</option>
              <option value="3">writer</option>
              <option value="4">title+content</option>
            </select>
            <input type="text" name="searchWord" id="searchWord" />
            <input type="submit" value="search" />
          </form>
        </td>
      </tr>
    </tfoot>
  </table>
  <!-- GET 방식 요청  -->
  <a href="/jspPro/board/write.do">글쓰기</a>
 </div>
</body>
</html>

 

 

Model 3

-WriteHandler.java

package days08.mvc.board;

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

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.util.DBConn;

import days08.mvc.command.CommandHandler;

public class WriteHandler implements CommandHandler{

	@Override
	public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
		//글쓰기 작업시 get/ post 달리 해야함 if로 나누자
		//request.getMethod() : GET /POST 돌림(대문자로)
		
		if(request.getMethod().equalsIgnoreCase("GET")) {
			
			return "/days08/board/ex10_write.jsp"; //그 자체로 포워딩이니 경로만 주자
		
		}else if(request.getMethod().equalsIgnoreCase("POST")) {
			
			request.setCharacterEncoding("UTF-8");
			
			String writer = request.getParameter("writer");
			String pwd = request.getParameter("pwd");
			String email = request.getParameter("email");
			String title = request.getParameter("title");
			int tag = Integer.parseInt( request.getParameter("tag") );
			String content = request.getParameter("content");		
			Connection con = DBConn.getConnection();
			PreparedStatement pstmt = null;		
			String sql = "INSERT INTO TBL_CSTVSBOARD "
					+ " ( seq, writer, pwd, email, title, tag, content ) "
					+ " VALUES ( SEQ_TBL_CSTVSBOARD.NEXTVAL, ?, ?, ?, ?, ?, ? )";
			int rowCount = 0;
			try {
				pstmt =  con.prepareStatement(sql); 
					pstmt.setString(1,  writer );
					pstmt.setString(2, pwd );
					pstmt.setString(3, email );
					pstmt.setString(4, title );
					pstmt.setInt(5, tag );
					pstmt.setString(6, content ); 
				rowCount =  pstmt.executeUpdate();
			} catch (SQLException e) { 
				e.printStackTrace();
			} finally {
				try {
					pstmt.close();
				} catch (SQLException e) { 
					e.printStackTrace();
				}
			} // try		
			
			// redirect  list.htm
			String location = "/jspPro/board/list.do";
			if( rowCount == 1 ) location +="?write=success";
			response.sendRedirect(location);
		}
		return null;
	}

}

View 3

-ex10_write.jsp

<%@page import="java.util.Iterator"%>
<%@page import="days05.board.BoardDTO"%>
<%@page import="java.util.ArrayList"%>
<%@ page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>write.jsp</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"> 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="">
<style>
table, td, th {
	border: solid 1px gray;
}

table {
	border-spacing: 3px;
	border-collapse: separate;
}

table, tr, td {
	/* border-radius: 3px; */
	/* padding:3px;  */
	
}
</style>
<script>
   $(document).ready(function (){	  
   });
</script>
</head>
<body>
<!--  <h3>write.jsp</h3> -->
 <div align="center">
  <h2>글 쓰기</h2>
  <!-- [기억] action 속성 설정 되지 않으면  http://localhost/jspPro/cstvsboard/write.htm 요청 -->
  <form method="post">
		<table style="padding: 2px; width: 600px">
			<tr>
				<td colspan="2" align="center"><b>글을 적어주세요</b></td>
			</tr>
			<tr>
				<td align="center">이름</td>
				<td><input type="text" name="writer" size="15"
					autofocus="autofocus" required="required"></td>
			</tr>
			<tr>
				<td align="center">비밀번호</td>
				<td><input type="password" name="pwd" size="15" required="required"></td>
			</tr>
			<tr>
				<td align="center">Email</td>
				<td><input type="email" name="email" size="50" ></td>
			</tr>
			<tr>
				<td align="center">제목</td>
				<td><input type="text" name="title" size="50" required="required"></td>
			</tr>
			<tr>
				<td align="center">내용</td>
				<td><textarea name="content" cols="50" rows="10"></textarea></td>
			</tr>
			<tr>
				<td align="center">HTML</td>
				<td><input type="radio" name="tag" value="1" checked>적용
					<input type="radio" name="tag" value="0">비적용</td>
			</tr>
			<tr>
				<td colspan="2" align="center">
				  <input type="submit" value="작성 완료">
				  &nbsp;&nbsp;&nbsp; 
				  <input type="reset" value="다시 작성">
				  &nbsp;&nbsp;&nbsp; 
				  <a href="/jspPro/board/list.do">Home</a>
				</td>
			</tr>
		</table>
	</form>
 </div>
</body>
</html>

 

Model 4

-ContentHandler.java

package days08.mvc.board;

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

import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.util.ConnectionProvider;
import com.util.DBConn;

import days05.board.BoardDTO;
import days08.mvc.command.CommandHandler;

public class ContentHandler  implements CommandHandler{

	@Override
	public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
		int seq = Integer.parseInt(request.getParameter("seq"));
		
		Connection con = ConnectionProvider.getConnection();
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		// 1. 조회수 증가
		String sql = "UPDATE TBL_CSTVSBOARD "
				+ " SET readed = readed + 1 "
				+ " WHERE seq = ?";
		int rowCount = 0;
		try {
			pstmt = con.prepareStatement(sql);
			pstmt.setInt(1, seq);
			rowCount = pstmt.executeUpdate();
		} catch (SQLException e) { 
			e.printStackTrace();
		} finally {
			try {
				pstmt.close();
			} catch (SQLException e) { 
				e.printStackTrace();
			}
		}
		
		// 2. 게시글 얻어오는 코딩.
		sql    = "SELECT seq, writer, title, content, readed, writedate , email "
				+ " FROM TBL_CSTVSBOARD "
				+ " WHERE seq = ?";
		
		BoardDTO dto = null;
		
		try {
			pstmt = con.prepareStatement(sql);
			pstmt.setInt(1, seq);		
			rs = pstmt.executeQuery();		
			 
			if (rs.next()) {
				// seq, writer, title, content, readed, writedate
				dto = new BoardDTO();
					dto.setSeq( rs.getInt("seq"));
				dto.setWriter(rs.getString("writer"));
				dto.setTitle(rs.getString("title"));
				dto.setContent(rs.getString("content"));
				dto.setReaded( rs.getInt("readed"));
				dto.setWritedate(rs.getDate("writedate"));
				dto.setEmail(rs.getString("email"));
			}		
		} catch (SQLException e) { 
			e.printStackTrace();
		} finally {
			try {
				rs.close();
				pstmt.close();	
				con.close();
			} catch (SQLException e) { 
				e.printStackTrace();
			}
		} // try
			
		request.setAttribute("dto", dto);
		String path = "/days08/board/ex10_content.jsp";
		RequestDispatcher dispatcher = request.getRequestDispatcher(path);
		dispatcher.forward(request, response);
		return null;
	}
	
}

View 4

-ex10_content.jsp

<%@page import="days05.board.BoardDTO"%>
<%@ page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
    BoardDTO dto = (BoardDTO) request.getAttribute("dto");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>content.jsp</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"> 

 <!-- jquery.ui  -->
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<link rel="stylesheet" href="/resources/demos/style.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script> 
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
 
<!-- bootstrap4 -->
 <!--  
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
  -->
  
<style>
  table{
     border-spacing: 3px;
     border-collapse: separate; 
   }
   table,  tr, td {
      border:solid 1px gray;
      /* border-radius: 3px;  
      padding:3px;   */ 
   }
   
 #tblContent{
   width:600px;
 }
 
</style>

<script>
   $(document).ready(function (){	  
	   
	   $("#homeLink")
	     .attr("href"
	   , "/jspPro/cstvsboard/list.htm?currentPage=${ param.currentPage }&searchCondition=${ param.searchCondition}&searchWord=${ param.searchWord}");
	   
	   $("#btnModalDelete").on("click", function(event) {
		   // 객체.메서드("open")
	   	  dialog.dialog("open");
	   });
	   
	   $("#cancel").on("click", function(event) {
		   // 객체.메서드("open")
		   	  dialog.dialog("close");
		   });
	   
	   dialog = $( "#dialog-form" ).dialog({
		      autoOpen: false,
		      height: 400,
		      width: 350,
		      modal: true,
		      buttons: {
		        /* "Create an account": addUser,
		        Cancel: function() {
		          dialog.dialog( "close" );
		        } */
		      },
		      close: function() {
		         form[ 0 ].reset();
		         //allFields.removeClass( "ui-state-error" );
		      }
		    });
		 
		 form = dialog.find( "form" );
   });
</script>
</head>
<body>
 
 <div align="center">
  <h2>내용보기</h2>
  <!-- <table id="tblContent" class="table"> -->
  <table id="tblContent">
   <tr>
       <td>이름</td>
       <td>${dto.writer }</td>
       <td>등록일</td>
       <td>${dto.writedate }</td>
   </tr>
   <tr>
       <td>Email</td>
       <td><a href="mailto:${dto.email}">${dto.email}</a></td>
       <td>조회</td>
       <td> ${dto.readed }</td>
   </tr>
   <tr>
        <td>제목</td>
        <td colspan="3">${dto.title}</td>
   </tr>
   <tr>
       <td colspan="4" style="padding:15px;height: 200px;text-align: left;vertical-align: top">
        ${dto.content }
       </td>
   </tr>
   <tr>
       <td colspan="4" align="center">
           <a class="btn btn-secondary"  href="/jspPro/cstvsboard/edit.htm?seq=${dto.seq}" id="editLink">수정하기</a>
           <a class="btn btn-secondary"  href="/jspPro/cstvsboard/delete.htm?seq=${dto.seq}" id="deleteLink">삭제하기</a>
           <a class="btn btn-secondary"  href="#" id="homeLink">Home</a>
           
           <input class="btn btn-secondary"  type="button" id="btnModalDelete" value="모달창으로 글 삭제"> 
           
       </td>
   </tr>
</table>
</div>

<!--  삭제 모달창 -->
<div id="dialog-form" align="center" title="삭제">
  <h2>삭제하기</h2>
  <form action="/jspPro/cstvsboard/delete.htm" method="post">
       
    <table>
	  <tr>
	    <td colspan="2" align="center"><b>글을 삭제합니다</b></td>
	  </tr>
	  <tr>
	    <td align="center">비밀번호</td>
	    <td>
	      <input type="password" name="pwd" size="15" autofocus="autofocus">
	    </td>
	  </tr>
	  <tr>
	    <td colspan="2" align="center">
	      <input type="submit" value="삭제">&nbsp;&nbsp;
	      <!-- <input type="button" onClick="javascript:history.back();" value="취소"> -->
	      <input type="button" id="cancel" value="취소">
	    </td>
	  </tr>
	</table> 
	<input type="hidden" name="seq" value="${ param.seq }" />
	        
</form>
</div>
 
</body>
</html>

게시글 제목 클릭시 

내용 보기로 이동

반응형
Comments