*sql
[GD.sql]
DROP TABLE BOARD_T;
CREATE TABLE BOARD_T (
BOARD_NO NUMBER NOT NULL,
TITLE VARCHAR2(1000 BYTE) NOT NULL,
CONTENT CLOB,
MODIFIED_AT DATE,
CREATED_AT DATE,
CONSTRAINT PK_BOARD PRIMARY KEY(BOARD_NO)
);
DROP SEQUENCE BOARD_SEQ;
CREATE SEQUENCE BOARD_SEQ NOCACHE;
*lib
-lombok.jar
-ojdbc8.jar
-taglibs 2종
*META-INF-[context.xml]
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<!-- 오라클 접속 정보 -->
<Resource
auth="Container"
name="jdbc/oraclexe"
type="javax.sql.DataSource"
driverClassName="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:@localhost:1521:xe"
username="GD"
password="1111"
maxTotal="8"
maxIdle="8"
maxWaitMillis="-1" />
</Context>
게시판 목록 링크를 누르면 controller 로 정보가 전달.
[index.jsp]
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<c:set var="contextPath" value="<%=request.getContextPath()%>" />
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
</head>
<body>
<div>
<a href="${contextPath}/board/list.do">게시판목록</a>
</div>
</body>
</html>

[BoardFilter.java]
package filter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet Filter implementation class BoardFilter
*/
@WebFilter("*.do")
public class BoardFilter extends HttpFilter implements Filter {
/**
* @see HttpFilter#HttpFilter()
*/
public BoardFilter() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 컨트롤러가 실행되기 이전에 처리되는 코드
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
// 요청 인코딩
req.setCharacterEncoding("UTF-8");
// 요청 주소 확인
System.out.println(req.getRequestURI());
// 요청 파라미터 확인
Map<String, String[]> map = req.getParameterMap();
for(Entry<String, String[]> entry : map.entrySet()) {
System.out.println(entry.getKey() + ":" + Arrays.toString(entry.getValue()));
}
// pass the request along the filter chain
chain.doFilter(request, response);
}
/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
System.out.println("::::: BoardFilter 시작 :::::");
}
}


[BoardController.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;
import common.ActionForward;
import service.BoardService;
import service.BoardServiceImpl;
/**
* Servlet implementation class BoardController
*/
@WebServlet("*.do")
public class BoardController extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public BoardController() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// BoardFilter 실행 후 Controller 실행
// 요청 인코딩(BoardFilter가 수행함) + 응답 타입과 인코딩
// request.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=UTF-8");
// 요청 주소 확인
String requestURI = request.getRequestURI();
String contextPath = request.getContextPath();
String urlMapping = requestURI.substring(contextPath.length());
// 어디로 어떻게 이동할 것인지 알고 있는 ActionForward 객체
ActionForward af = null;
// BoardService 객체 생성
BoardService boardService = new BoardServiceImpl();
// 요청에 따른 처리
switch(urlMapping) {
// 단순 이동 (forward 처리)
case "/board/write.do":
af = new ActionForward("/board/write.jsp", false);
break;
case "/index.do":
af = new ActionForward("/index.jsp", false);
break;
// 서비스 처리
case "/board/register.do":
af = boardService.register(request);
break;
case "/board/list.do":
af = boardService.getBoardList(request);
break;
case "/board/detail.do":
af = boardService.getBoardByNo(request);
break;
case "/board/edit.do":
af = boardService.edit(request);
break;
case "/board/modify.do":
af = boardService.modify(request);
break;
case "/board/delete.do":
af = boardService.delete(request);
break;
}
// 이동
if(af != null) {
if(af.isRedirect()) {
response.sendRedirect(af.getPath());
} else {
request.getRequestDispatcher(af.getPath()).forward(request, response);
}
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
[BoardDto.java]
package domain;
import java.sql.Date;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class BoardDto {
private int board_no;
private String title;
private String content;
private Date modified_at;
private Date created_at;
}
[PageVo.java]
package util;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@Data
public class PageVo {
private int page; // 현재 페이지 번호(요청 파라미터로 받는다.)
private int total; // 전체 항목의 개수(DB에서 구한 뒤 받는다.)
private int display; // 한 페이지에 표시할 항목의 개수(요청 파라미터로 받는다.)
private int begin; // 한 페이지에 표시되는 항목의 시작 번호(계산한다.)
private int end; // 한 페이지에 표시되는 항목의 종료 번호(계산한다.)
private int totalPage; // 전체 페이지의 개수(계산한다.)
private int pagePerBlock = 2; // 한 블록에 표시되는 페이지의 개수(임의로 정한다.)
private int beginPage; // 한 블록에 표시되는 페이지의 시작 번호(계산한다.)
private int endPage; // 한 블록에 표시되는 페이지의 종료 번호(계산한다.)
public void setPaging(int page, int total, int display) {
/* 한 페이지를 나타낼 때 필요한 정보 */
// 받은 정보 저장
this.page = page;
this.total = total;
this.display = display;
// 계산한 정보 저장
begin = (page - 1) * display + 1;
end = begin + display - 1;
if(end > total) {
end = total;
}
/* 전체 페이지를 나타낼 때 필요한 정보 */
// 전체 페이지 계산
totalPage = (int)Math.ceil((double)total / display);
// 각 블록의 시작 페이지와 종료 페이지 계산
beginPage = ((page - 1) / pagePerBlock) * pagePerBlock + 1;
endPage = beginPage + pagePerBlock - 1;
if(endPage > totalPage) {
endPage = totalPage;
}
}
public String getPaging(String url) {
StringBuilder sb = new StringBuilder();
sb.append("<div>");
// 이전 블록
if(beginPage == 1) {
sb.append("<span>이전</span>");
} else {
sb.append("<a href=\"" + url + "?page=" + (beginPage - 1) + "\">이전</a>");
}
// 페이지 번호
for(int p = beginPage; p <= endPage; p++) {
if(p == page) {
sb.append("<span>" + p + "</span>");
} else {
sb.append("<a href=\"" + url + "?page=" + p + "\">" + p + "</a>");
}
}
// 다음 블록
if(endPage == totalPage) {
sb.append("<span>다음</span>");
} else {
sb.append("<a href=\"" + url + "?page=" + (endPage + 1) + "\">다음</a>");
}
sb.append("</div>");
return sb.toString();
}
}


[BoardDao.java]
package repository;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import domain.BoardDto;
public class BoardDao {
// 모든 메소드가 공동으로 사용할 객체 선언
private Connection con;
private PreparedStatement ps;
private ResultSet rs;
// Connection Pool 관리 DataSource 객체 선언
private DataSource dataSource;
// Singleton Pattern으로 BoardDao 객체 생성
private static BoardDao dao = new BoardDao();
private BoardDao() {
// META-INF/context.xml에 있는 <Resource name="jdbc/oraclexe" /> 태그 내용을 읽어서 DataSource 객체 생성하기
try {
Context context = new InitialContext();
Context env = (Context)context.lookup("java:comp/env");
dataSource = (DataSource)env.lookup("jdbc/oraclexe");
} catch(Exception e) {
e.printStackTrace();
}
}
public static BoardDao getDao() {
return dao;
}
// 자원 반납 메소드
public void close() {
try {
if(rs != null) rs.close();
if(ps != null) ps.close();
if(con != null) con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
// 게시글 등록 메소드
public int register(BoardDto dto) {
// 등록 결과 선언 (insert 실행 결과는 삽입된 행의 개수이다.)
int insertResult = 0;
try {
// Connection Pool에서 Connection을 하나 받아온다.
// Connection Pool 관리는 DataSource 객체가 수행한다.
con = dataSource.getConnection();
// 쿼리문 작성
String sql = "INSERT INTO BOARD_T(BOARD_NO, TITLE, CONTENT, MODIFIED_AT, CREATED_AT) VALUES (BOARD_SEQ.NEXTVAL, ?, ?, SYSDATE, SYSDATE)";
// ps 객체 생성 (쿼리문 실행을 담당하는 객체)
ps = con.prepareStatement(sql);
// 쿼리문의 변수(?로 처리된 부분)에 값을 전달
ps.setString(1, dto.getTitle()); // 1번째 물음표(?)에 dto.getTitle() 전달하기
ps.setString(2, dto.getContent()); // 2번째 물음표(?)에 dto.getContent() 전달하기
// 쿼리문의 실행
insertResult = ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
close();
}
// 등록 결과 반환
return insertResult;
}
// 게시글 개수 반환 메소드
public int getBoardCount() {
// 게시글 개수
int count = 0;
try {
con = dataSource.getConnection();
String sql = "SELECT COUNT(*) FROM BOARD_T"; // COUNT(*)
// --------
// 120
ps = con.prepareStatement(sql);
rs = ps.executeQuery();
if(rs.next()) {
count = rs.getInt(1); // count = rs.getInt("COUNT(*)")도 가능함
}
} catch (Exception e) {
e.printStackTrace();
} finally {
close();
}
// 게시글 개수 반환
return count;
}
// 게시글 목록 반환 메소드
public List<BoardDto> getBoardList(Map<String, Object> map){
// 게시글 목록 저장 List
List<BoardDto> list = new ArrayList<BoardDto>();
try {
con = dataSource.getConnection();
String sql = "SELECT A.BOARD_NO, A.TITLE, A.CONTENT, A.MODIFIED_AT, A.CREATED_AT"
+ " FROM (SELECT ROW_NUMBER() OVER (ORDER BY BOARD_NO DESC) AS RN, BOARD_NO, TITLE, CONTENT, MODIFIED_AT, CREATED_AT"
+ " FROM BOARD_T) A"
+ " WHERE A.RN BETWEEN ? AND ?";
ps = con.prepareStatement(sql);
ps.setInt(1, (int)map.get("begin"));
ps.setInt(2, (int)map.get("end"));
rs = ps.executeQuery();
while(rs.next()) {
// rs -> BoardDto
BoardDto dto = BoardDto.builder()
.board_no(rs.getInt(1))
.title(rs.getString(2))
.content(rs.getString(3))
.modified_at(rs.getDate(4))
.created_at(rs.getDate(5))
.build();
// BoardDto -> list 추가
list.add(dto);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
close();
}
// 게시글 목록 반환
return list;
}
// 게시글 반환 메소드
public BoardDto getBoardByNo(int board_no) {
// 게시글
BoardDto dto = null;
try {
con = dataSource.getConnection();
String sql = "SELECT BOARD_NO, TITLE, CONTENT, MODIFIED_AT, CREATED_AT"
+ " FROM BOARD_T"
+ " WHERE BOARD_NO = ?";
ps = con.prepareStatement(sql);
ps.setInt(1, board_no);
rs = ps.executeQuery();
if(rs.next()) {
dto = BoardDto.builder()
.board_no(rs.getInt(1))
.title(rs.getString(2))
.content(rs.getString(3))
.modified_at(rs.getDate(4))
.created_at(rs.getDate(5))
.build();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
close();
}
// 게시글 반환
return dto;
}
// 게시글 수정 메소드
public int modify(BoardDto dto) {
// 수정 결과
int modifyResult = 0;
try {
con = dataSource.getConnection();
String sql = "UPDATE BOARD_T"
+ " SET TITLE = ?, CONTENT = ?, MODIFIED_AT = SYSDATE"
+ " WHERE BOARD_NO = ?";
ps = con.prepareStatement(sql);
ps.setString(1, dto.getTitle());
ps.setString(2, dto.getContent());
ps.setInt(3, dto.getBoard_no());
modifyResult = ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
close();
}
// 수정 결과 반환
return modifyResult;
}
// 게시글 삭제 메소드
public int delete(int board_no) {
// 삭제 결과
int deleteResult = 0;
try {
con = dataSource.getConnection();
String sql = "DELETE FROM BOARD_T WHERE BOARD_NO = ?";
ps = con.prepareStatement(sql);
ps.setInt(1, board_no);
deleteResult = ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
close();
}
// 삭제 결과 반환
return deleteResult;
}
}
[BaordService.java]
package service;
import javax.servlet.http.HttpServletRequest;
import common.ActionForward;
public interface BoardService {
public ActionForward register(HttpServletRequest request);
public ActionForward getBoardList(HttpServletRequest request);
public ActionForward getBoardByNo(HttpServletRequest request);
public ActionForward edit(HttpServletRequest request);
public ActionForward modify(HttpServletRequest request);
public ActionForward delete(HttpServletRequest request);
}
[BoardServiceImpl]
package service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.servlet.http.HttpServletRequest;
import common.ActionForward;
import domain.BoardDto;
import repository.BoardDao;
import util.PageVo;
public class BoardServiceImpl implements BoardService {
// 모든 서비스가 공동으로 사용하는 BoardDao, PageVo 객체 가져오기
private BoardDao dao = BoardDao.getDao();
private PageVo pageVo = new PageVo();
@Override
public ActionForward register(HttpServletRequest request) {
// 등록할 제목과 내용
String title = request.getParameter("title");
String content = request.getParameter("content");
// 제목 + 내용 -> BoardDto 객체
BoardDto dto = BoardDto.builder()
.title(title)
.content(content)
.build();
// BoardDao의 register 메소드 호출
int registerResult = dao.register(dto);
// 등록 성공(registerResult == 1), 등록 실패(registerResult == 0)
String path = null;
if(registerResult == 1) {
path = request.getContextPath() + "/board/list.do";
} else if(registerResult == 0) {
path = request.getContextPath() + "/index.do";
}
// 어디로 어떻게 이동하는지 반환 (insert 수행 후에는 반드시 redirect 이동한다.)
return new ActionForward(path, true);
}
@Override
public ActionForward getBoardList(HttpServletRequest request) {
/* page, total, display 정보가 있어야 목록을 가져올 수 있다. */
// 전달된 페이지 번호 (페이지 번호의 전달이 없으면 1 페이지를 연다.)
Optional<String> opt = Optional.ofNullable(request.getParameter("page"));
int page = Integer.parseInt(opt.orElse("1"));
int total = dao.getBoardCount();
int display = 5; // 고정 값 사용(원하면 파라미터로 받아 오는 것으로 변경도 가능함)
// PageVo의 모든 정보 계산하기
pageVo.setPaging(page, total, display);
// 게시글 목록을 가져올 때 사용할 변수들을 Map으로 만듬
Map<String, Object> map = new HashMap<String, Object>();
map.put("begin", pageVo.getBegin());
map.put("end", pageVo.getEnd());
// DB로부터 게시글 목록 가져오기
List<BoardDto> boardList = dao.getBoardList(map);
// 게시글 목록과 paging을 /board/list.jsp로 전달하기 위하여 request에 저장한 뒤 forward한다.
request.setAttribute("boardList", boardList);
request.setAttribute("paging", pageVo.getPaging(request.getContextPath() + "/board/list.do"));
return new ActionForward("/board/list.jsp", false);
}
@Override
public ActionForward getBoardByNo(HttpServletRequest request) {
// 상세조회할 게시글 번호
Optional<String> opt = Optional.ofNullable(request.getParameter("board_no"));
int board_no = Integer.parseInt(opt.orElse("0"));
// DB로부터 게시글 가져오기
BoardDto board = dao.getBoardByNo(board_no);
// 게시글을 /board/detail.jsp에 전달하기 위해서 forward 처리
request.setAttribute("board", board);
return new ActionForward("/board/detail.jsp", false);
}
@Override
public ActionForward edit(HttpServletRequest request) {
// 편집할 게시글 번호
Optional<String> opt = Optional.ofNullable(request.getParameter("board_no"));
int board_no = Integer.parseInt(opt.orElse("0"));
// DB로부터 게시글 가져오기
BoardDto board = dao.getBoardByNo(board_no);
// 게시글을 /board/edit.jsp에 전달하기 위해서 forward 처리
request.setAttribute("board", board);
return new ActionForward("/board/edit.jsp", false);
}
@Override
public ActionForward modify(HttpServletRequest request) {
// 수정할 게시글 정보
String title = request.getParameter("title");
String content = request.getParameter("content");
int board_no = Integer.parseInt(request.getParameter("board_no"));
// 수정할 게시글 정보를 BoardDto 객체로 생성
BoardDto dto = BoardDto.builder()
.title(title)
.content(content)
.board_no(board_no)
.build();
// 수정하기
int modifyResult = dao.modify(dto);
// 수정 성공(modifyResult == 1), 수정 실패(modifyResult == 0)
String path = null;
if(modifyResult == 1) {
path = request.getContextPath() + "/board/detail.do?board_no=" + board_no;
} else {
path = request.getContextPath() + "/index.do";
}
// update 이후에는 redirect 한다.
return new ActionForward(path, true);
}
@Override
public ActionForward delete(HttpServletRequest request) {
// 삭제할 게시글 번호
Optional<String> opt = Optional.ofNullable(request.getParameter("board_no"));
int board_no = Integer.parseInt(opt.orElse("0"));
// 삭제하기
int deleteResult = dao.delete(board_no);
// 삭제 성공(deleteResult == 1), 삭제 실패(deleteResult == 0)
String path = null;
if(deleteResult == 1) {
path = request.getContextPath() + "/board/list.do";
} else if(deleteResult == 0) {
path = request.getContextPath() + "/index.do";
}
// delete 이후에는 redirect 한다.
return new ActionForward(path, true);
}
}
[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" %>
<c:set var="contextPath" value="<%=request.getContextPath()%>" />
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
<style>
.board span {
margin-right: 20px;
}
</style>
<script>
$(function(){
fnDetail();
})
function fnDetail(){
$('.board').click(function(){
location.href = '${contextPath}/board/detail.do?board_no=' + $(this).find('.board_no').text();
})
}
</script>
</head>
<body>
<div>
<a href="${contextPath}/board/write.do">작성하러가기</a>
</div>
<hr>
<div>
<c:forEach items="${boardList}" var="board">
<div class="board">
<span class="board_no">${board.board_no}</span>
<span>${board.title}</span>
<span>${board.created_at}</span>
</div>
</c:forEach>
</div>
<div>${paging}</div>
</body>
</html>

[write.jsp]
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<c:set var="contextPath" value="<%=request.getContextPath()%>" />
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
<script>
$(function(){
// 함수 호출
fnBoardList();
fnBoardRegister();
})
// 함수 정의
function fnBoardList(){
$('#btn_list').click(function(){
location.href = '${contextPath}/board/list.do';
})
}
// 함수 정의
function fnBoardRegister(){
$('#frm_register').submit(function(event){
if($('#title').val() === ''){
alert('제목은 필수입니다.');
$('#title').focus();
event.preventDefault();
return;
}
})
}
</script>
</head>
<body>
<div>
<form id="frm_register" method="post" action="${contextPath}/board/register.do">
<div>
<label for="title">제목</label>
<input type="text" id="title" name="title">
</div>
<div>
<textarea rows="5" cols="50" name="content"></textarea>
</div>
<div>
<button type="submit">작성완료</button>
<button type="reset">작성초기화</button>
<button type="button" id="btn_list">목록으로이동</button>
</div>
</form>
</div>
</body>
</html>

[detail.jsp]
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<c:set var="contextPath" value="<%=request.getContextPath()%>" />
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
<style>
.link a {
margin-right: 20px;
}
</style>
<script>
$(function(){
fnDelete();
})
function fnDelete(){
$('#delete_link').click(function(event){
if(!confirm('게시글을 삭제할까요?')){
event.preventDefault();
return;
}
})
}
</script>
</head>
<body>
<div class="link">
<a href="${contextPath}/board/write.do">작성하러가기</a>
<a href="${contextPath}/board/list.do">목록으로이동</a>
<a href="${contextPath}/board/edit.do?board_no=${board.board_no}">수정하러가기</a>
<a id="delete_link" href="${contextPath}/board/delete.do?board_no=${board.board_no}">삭제하기</a>
</div>
<hr>
<div>
<div>게시글번호: ${board.board_no}</div>
<div>제목: ${board.title}</div>
<div><pre>${board.content}</pre></div>
<div>최종수정일: ${board.modified_at}</div>
<div>최초작성일: ${board.created_at}</div>
</div>
</body>
</html>

[edit.jsp]
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<c:set var="contextPath" value="<%=request.getContextPath()%>" />
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
<script>
$(function(){
// 함수 호출
fnBoardList();
fnBoardModify();
})
// 함수 정의
function fnBoardList(){
$('#btn_list').click(function(){
location.href = '${contextPath}/board/list.do';
})
}
// 함수 정의
function fnBoardModify(){
$('#frm_edit').submit(function(event){
if($('#title').val() === ''){
alert('제목은 필수입니다.');
$('#title').focus();
event.preventDefault();
return;
}
})
}
</script>
</head>
<body>
<div>
<form id="frm_edit" method="post" action="${contextPath}/board/modify.do">
<div>
<label for="title">제목</label>
<input type="text" id="title" name="title" value="${board.title}">
</div>
<div>
<textarea rows="5" cols="50" name="content">${board.content}</textarea>
</div>
<div>
<input type="hidden" name="board_no" value="${board.board_no}">
<button type="submit">수정완료</button>
<button type="reset">작성초기화</button>
<button type="button" id="btn_list">목록으로이동</button>
</div>
</form>
</div>
</body>
</html>


실제 저장된 db

삭제


