백엔드/웹 개발

14 게시판 만들기

study_yeon 2023. 6. 27. 18:48

2023.06.26 수업

교재 : 자바 웹 개발 워크북


● 복습

 

* 모델1 JSP로 구현
* 모델2 Servlet로 구현

* 서블릿이 시작 (라우팅)
- 컨트롤러를 통해 뷰에 접근
-> web.xml를 편하게 해줌
- 컨트롤러에서 데이터를 서비스로 넘김, 데이터 직접 처리 불가

* 데이터가 변환하는 것 DTO, 데이터가 변환하지 않는 것 VO
-> modelmapper에 의해 변환

* view에서는 요청

* cleanup 
종료를 필요로 하는 경우(자원)에 사용
종료가 필요없는 리소스를 활용하는 경우는 cleanup이 아닌 try-catch 사용

* List -> ListController -> ListService -> DAO
- ListController : 목록조회 기능


▶ 조회기능 구현

2023.06.27 - [백엔드/JSP & Servlet] - 13 게시판 만들기

 

13 게시판 만들기

2023.06.23 수업 ● 복습 ※ 간단정리 비즈니스 로직에 의해 만들어진 것 : 영속적임 영속적인 데이터를 모델이라고함 * DB의 자료는 변하지 않아야하기 때문에 VO를 활용 서비스에서 DTO가 활동 * 비

dustj0824.tistory.com

이어서 

 

▷TodoService 조회기능 구현 
- get() 작성

- TodoDAO의 selectOne()을 통해 TodoVO객체를 가져오고 ModelMapper를 이용하여 TodoDTO로 변환

package org.zerock.jdbcex.service;

import java.util.List;
import java.util.stream.Collectors;

import org.modelmapper.ModelMapper;
import org.zerock.jdbcex.dao.TodoDAO;
import org.zerock.jdbcex.domain.TodoDTO;
import org.zerock.jdbcex.domain.TodoVO;
import org.zerock.jdbcex.util.MapperUtil;

import lombok.extern.log4j.Log4j2;

@Log4j2
public enum TodoService {

	동일
	// 0626 get() 추가
	// 게시물 하나 얻기
	public TodoDTO get(Long tno) throws Exception {
		log.info("tno : " + tno);
		// 모델(DAO)을 통하여 디비로부터 가져오는 데이터는 읽기만 가능
		TodoVO todoVO = dao.selectOne(tno);  // 예외 발생 가능
		// 실제 사용할때는 데이터를 편집할 것이므로 VO -> DTO로 변형
		// modelMapper.map()는 실제 todoVO의 각 멤버필드를 TodoDTO.class를 설정파일에서
		// 설정한대로 분석하여 VO의 값을 DTO의 해당 멤버필드로 복사한다
		TodoDTO todoDTO = modelMapper.map(todoVO, TodoDTO.class);
		
		return todoDTO;
	}
}

▷ TodoReadController 서블릿 만들기
- doGet() 이용
- TodoDTO전달

package org.zerock.jdbcex.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;

import org.zerock.jdbcex.domain.TodoDTO;
import org.zerock.jdbcex.service.TodoService;

import lombok.extern.log4j.Log4j2;

// 게시글의 자세한 내용을 알아볼 것이므로 요청주소에 첨부해서 보내면 됨(GET)
@WebServlet(name = "todoReadController", value = "/todo/read")
@Log4j2
public class TodoReadController extends HttpServlet {
	private static final long serialVersionUID = 1L;
    private TodoService todoService = TodoService.INSTANCE;
	
    @Override
	protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

		try {
			Long tno = Long.parseLong(req.getParameter("tno"));
			
			// 모델로부터 데이터를 받은 데이터를 뷰로 보낸다
			TodoDTO todoDTO = todoService.get(tno);
			
			// 요청객체에 검색한 결과를 속성으로 추가(데이터 담기)
			req.setAttribute("dto", todoDTO);
			
			// 결과 양식 출력, 외부에서 접근 불가
			req.getRequestDispatcher("/WEB-INF/todo/read.jsp").forward(req, res);
			
			
		} catch (Exception e) {
			log.error(e.getMessage());
			throw new ServletException("Read error");
		}
		
	}

}


▷ read.jsp 수정
- JavaWeb/src/main/webapp/WEB-INF/todo

- EL이용

- tno를 보여주거나 <form> 태그 대신 링크를 통해 수정/삭제하는 기능으로 이동

- 프로젝트를 실행하고 브라우저에 tno(존재하는 번호)를 입력하면 결과 확인 가능

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Todo Read</title>
</head>
<body>

	<div>
		<input type="text" name="tno" value="${dto.tno}" readonly >
	</div>
	<div>
		<input type="text" name="title" value="${dto.title}" readonly >
	</div>
	<div>
		<input type="date" name="dueDate" value="${dto.dueDate}">
	</div>
	<div>
		<input type="checkbox" name="finished" 
		${dto.finished ? "checked" : "" } readonly >
	</div>
	<div>
		<a href="/todo/modify?tno=${ dto.tno }">Modify/Remove</a>
		<a href="/todo/list">List</a>
	</div>

</body>
</html>


▷ list.jsp

- 목록페이지에서 조회링크 추가
- 상세리스트로 보이게 설정

- 번호를 누르면 웹페이지 하단에 경로가 보임

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>   
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>제목은 여기에</title>
</head>
<body>
<h1>List Page</h1>

<%-- 0623(수정 전), 링크가 없음
	<c:forEach var="dto" items="${ dtoList }" >
		<li>${ dto }</li>
	</c:forEach>
--%>	

<%-- 0626 --%>	
	<c:forEach var="dto" items="${ dtoList }" >
		<!-- 상세리스트로 보기 -->
		<li>
			<!-- 게시물 번호 읽기 링크 -->
			<span>
				<a href="/todo/read?tno=${ dto.tno }">${ dto.tno }</a>
			</span>
			<!-- 게시물 제목 -->
			<span>${ dto.title }</span>
			<!-- todo 게시 일자 -->
			<span>${ dto.dueDate }</span>
			<!-- todo 완료 여부 -->
			<span>${ dto.finished ? "DONE" : "NOT YET" }</span>
		</li>
	</c:forEach>

	
</body>
</html>

 


▶ 수정/삭제 기능 구현

▷ TodoService의 수정/삭제 기능 구현

- 외부에서 접근 가능(public)하며 반환값이 없음(void)


* remove()

- 번호(primary key)만 이용 가능
* modify()

- TodoDTO타입을 파라미터로 이용

package org.zerock.jdbcex.service;

import java.util.List;
import java.util.stream.Collectors;

import org.modelmapper.ModelMapper;
import org.zerock.jdbcex.dao.TodoDAO;
import org.zerock.jdbcex.domain.TodoDTO;
import org.zerock.jdbcex.domain.TodoVO;
import org.zerock.jdbcex.util.MapperUtil;

import lombok.extern.log4j.Log4j2;

@Log4j2
public enum TodoService {

	동일
	// 게시물 삭제는 tno 일련번호로 검색 후 삭제
	public void remove(Long tno) throws Exception {
		log.info("TodoService/remove? tno=" + tno);
		// 모델(dao)의 삭제(deleteOne) 메소드 호출
		dao.deleteOne(tno); // 예외발생 가능
	}
	// 게시물 수정은 tno 검색 후 수정
	public void modify(TodoDTO todoDTO) throws Exception {
		log.info("TodoService/modify ?todoDTO = " + todoDTO);
		// todoDTO -> todoVO로 변환, 불변데이터로 바꾸고 
		TodoVO todoVO = modelMapper.map(todoDTO, TodoVO.class);
		// dao(모델)을 사용하여 한 개의 데이터를 업데이트 한다.
		dao.updateOne(todoVO);
	}

}


▷ TodoModifyController 구현

서블릿 만들기
- get 방식으로 tno 파라미터를 이용하여 수정/삭제가 가능한 화면에 내용들을 보여줌(특정 TodoDTO를 보는 기능)

- post 방식으로 수정 작업을 처리할 수 있도록 구성

-> <form>태그에 전송된 정보를 이용하여 TodoDTO를 구성

-> TodoDTO는 TodoService 객체로 전달되고 목록화면으로 다시 이동하여 수정된 결과를 볼 수 있음

package org.zerock.jdbcex.controller;

import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
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 org.zerock.jdbcex.domain.TodoDTO;
import org.zerock.jdbcex.service.TodoService;
import lombok.extern.log4j.Log4j2;

@WebServlet(name = "todoModifyController", value = "/todo/modify")
@Log4j2
public class TodoModifyController extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	private TodoService todoService = TodoService.INSTANCE;
	private final DateTimeFormatter DATE_FORMMATTER = 
		DateTimeFormatter.ofPattern("yyyy-MM-dd");
	
	protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

		try {
			Long tno = Long.parseLong(req.getParameter("tno"));
			TodoDTO todoDTO = todoService.get(tno);
			
			// view로 데이터 넘겨주기
			req.setAttribute("dto", todoDTO);
			req.getRequestDispatcher("/WEB-INF/todo/modify.jsp").forward(req, res);
			
		} catch (Exception e) {
			e.printStackTrace();
			log.error(e.getMessage()); // 에러의 원인을 알려줌
			throw new ServletException("modify get ... error");
			
		}
		
	}

	protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		String finishedStr = req.getParameter("finished");
		
		TodoDTO todoDTO = TodoDTO.builder()
			.tno(Long.parseLong(req.getParameter("tno")))
			.title(req.getParameter("title"))
			.dueDate(LocalDate.parse(req.getParameter("dueDate"),DATE_FORMMATTER))
			.finished(finishedStr != null && finishedStr.equals("on"))
			.build();
			
		log.info("/todo/modify ... POST ...");
		log.info(todoDTO);
		
		try {
			todoService.modify(todoDTO);
		} catch (Exception e) {
			e.printStackTrace();
		}
		// 게시물 내용이 저장되었으므로 새주소로 옮긴다
		res.sendRedirect("/todo/list");
	}

}


▷ JavaWeb/src/main/webapp/WEB-INF/todo에 modify.jsp 만들기

- 수정작업

- form태그를 통해 수정 / 삭제 작업 분리

- 삭제의 경우 tno를 보이지 않게 함(type="hidden" 활용)

- type="hidden" 홈페이지에 안보이지만 데이터를 가지고 있음

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>Todo Modify / Remove</title>
</head>
<body>
	<form id="form1" action="/todo/modify" method="post">
		<div>
			<input 
				type="text" name="tno" value="${ dto.tno }" readonly />
		</div>
		<div>
			<input 
				type="text" name="title" value="${ dto.title }" />
		</div>
		<div>
			<input 
				type="date" name="dueDate" value="${ dto.dueDate }" />
		</div>
		<div>
			<input 
				type="checkbox" name="finished" ${ dto.finished ? "checked" : "" } /> 
		</div>
		<div>
			<button type="submit">Modify</button>
		</div>
	</form>
	<!-- 삭제용 form -->
	<form id="form2" action="/todo/remove" method="post" >
		<input type="hidden" name="tno" value="${ dto.tno }" readonly />
		<div>
			<button type="submit">Remove</button>
		</div>
	</form>
	
</body>
</html>

▷ TodoRemoveController 구현
- 삭제작업
- doPost만 필요

- 특정 번호 이용하여 삭제
- 삭제가 완료되면 list 페이지로 넘어가야함

package org.zerock.jdbcex.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;
import org.zerock.jdbcex.service.TodoService;
import lombok.extern.log4j.Log4j2;

@WebServlet(name = "todoRemoveController", value = "/todo/remove")
@Log4j2
public class TodoRemoveController extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
	private TodoService todoService = TodoService.INSTANCE;
	
	
	protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		Long tno = Long.parseLong(
				req.getParameter("tno"));
		log.info("tno: " + tno);
		
		try {
			todoService.remove(tno);
		} catch(Exception e) {
			log.error(e.getMessage());
			throw new ServletException("remove error");
		}
		
		// /todo/list 페이지로 이동
		res.sendRedirect("/todo/list");
	}

}

-> 브라우저에서 특정 번호를 선택하고 Remove를 누르면 해당 데이터가 삭제됨