day37 - 0916
- 하루동안 게시판을 구현하는 과제가 있었음 (수업 X)
- 해당 내용은 0919의 게시판 구현 부분임
게시판 구현
테이블 생성
게시판(board) - 회원이 작성하는 글 정보 - 회원 정보가 외래키로 존재해야함 - 회원이 탈퇴하면 작성한 글의 작성자를 제거 구성요소 - 글 번호(board_no) - 유일한 식별키, 시퀀스로 부여 - 작성자(board_writer) - 회원의 아이디 정보, 외래키로 설정 - 제목(board_title) - 글의 제목 (한글 100자 기준으로 설정) - 내용(board_content) - 글의 내용, 가능한 최대로 설정 (4000byte) - 작성일(board_writetime) - 작성된 시점의 데이터베이스 시각 - 수정일(board_updatetime) - 수정된 시점의 데이터베이스 시각, 작성시에는 작성 시각으로 설정 - 조회수(board_read) - 글을 읽으면 자동으로 증가하도록 숫자 항목으로 구현 - 좋아요(board_like) - 회원이 글에 설정한 좋아요 갯수(추가 테이블 필요) - 말머리(board_head) - 다음 항목(정보/유머/공지) 중 하나 혹은 미설정 가능 |
-- board 테이블 생성
create table board (
board_no number primary key,
board_writer references member(member_id) on delete set null,
board_title varchar2(300) not null,
board_content varchar2(4000) not null,
board_writetime date default sysdate not null,
board_updatetime date,
board_read number default 0 not null check(board_read >= 0),
board_like number default 0 not null check(board_like >= 0),
board_head varchar2(6) check(board_head in('정보', '유머', '공지'))
);
-- 시퀀스 생성
create sequence board_seq;
flow chart 구상

BoardDto 생성
- lombok을 이용하면 DTO 생성을 간결하게 할 수 있다
@Getter @Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Builder
public class BoardDto {
// 필드
private int boardNo;
private String boardWriter;
private String boardTitle;
private String boardContent;
private Date boardWritetime;
private Date boardUpdatetime;
private int boardRead;
private int boardLike;
private String boardHead;
}
1. 게시글 작성
- 게시글 작성은 form에서 전송한 DTO를 받아서 BOARD 테이블에 등록(INSERT)을 한다

BoardDao
public interface BoardDao {
// 추상 메소드 - 게시글 작성 (다음 시퀀스 번호를 미리 생성 후 등록)
void write(BoardDto boardDto)
}
BoardDaoImpl
- 게시글 작성 후 작성한 게시글로 redirect 해야 한다
- 작성한 게시글로 redirect 하기 위해서는 해당 게시글의 번호를 알아야 한다
- 다음 시퀀스 번호를 생성하는 SQL문을 실행하여 작성할 글 번호를 반환받은 후 이 값을 매개변수 배열에 대입한다,
@Repository
public class BoardDaoImpl implements BoardDao {
// 의존성 주입
@Autowired
JdbcTemplate jdbcTemplate;
// 추상 메소드 오버라이딩 - 게시글 작성 (다음 시퀀스 번호를 미리 생성 후 등록)
@Override
public int insert2(BoardDto boardDto) {
// 다음 시퀀스 번호를 미리 생성
String sql = "select board_seq.nextval from dual";
int boardNo = jdbcTemplate.queryForObject(sql, int.class);
sql = "insert into board("
+ "board_no, board_title, board_content,"
+ "board_writer, board_head"
+ ") values(?, ?, ?, ?, ?)";
Object[] param = {
boardNo, boardDto.getBoardTitle(),
boardDto.getBoardContent(), boardDto.getBoardWriter(),
boardDto.getBoardHead()
};
jdbcTemplate.update(sql, param);
return boardNo;
}
}
boardController
@Controller
@RequestMapping("/board")
public class BoardController {
// 의존성 주입
@Autowired
BoardDao boardDao;
// 1. 게시글 작성
// 1) 게시글 작성 Mapping
@GetMapping("/write")
public String write() {
return "board/write";
}
// 2) 게시글 작성 Mapping에 DTO 전달 및 DB 처리
@PostMapping("/write")
public String write(HttpSession session, @ModelAttribute BoardDto boardDto, RedirectAttributes attr) {
// 게시글 작성자(boardWriter)가 로그인중인 아이디가 되도록 session에서 회원 아이디를 반환
String boardWriter = (String) session.getAttribute("loginId");
// setter 메소드로 게시글 작성자(boardWriter)를 session에서 반환한 로그인 아이디로 설정
boardDto.setBoardWriter(boardWriter);
// 게시글 번호(boardNo)를 위한 다음 시퀀스 번호 반환
int boardNo = boardDao.sequence();
// setter 메소드로 게시글 번호(boardNo)가 다음 시퀀스 번호가 되도록 설정
boardDto.setBoardNo(boardNo);
// 설정이 끝난 boardDto로 게시글 작성 실행
boardDao.write(boardDto);
// 게시글 작성 후 해당 게시글의 상세 Mapping으로 강제 이동(redirect)
attr.addAttribute("boardNo", boardNo);
return "redirect:detail";
}
}
write.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<jsp:include page="/WEB-INF/views/template/header.jsp">
<jsp:param value="자유 게시판" name="title"/>
</jsp:include>
<h1>게시글 작성</h1>
<div align = "center">
<form action="write" method="post">
<table border="1" width="500">
<tbody>
<tr>
<th>말머리</th>
<td>
<select name="boardHead">
<option value="">선택</option>
<option>정보</option>
<option>유머</option>
<c:if test="${mg == '관리자'}">
<option>공지</option>
</c:if>
</select>
</td>
</tr>
<tr>
<th>제목</th>
<td>
<input type="text" name="boardTitle" required>
</td>
</tr>
<tr>
<th>내용</th>
<td>
<textarea name="boardContent" rows="10" cols="50" required></textarea>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td align="right" colspan="2">
<a href="list">목록으로</a>
<button type="submit">등록하기</button>
</td>
</tr>
</tfoot>
</table>
</form>
</div>
<jsp:include page="/WEB-INF/views/template/footer.jsp"></jsp:include>
- session에 저장된 mg(회원등급)이 관리자일 때 공지라는 말머리를 사용할 수 있도록 설정한다
- <form></form>과 <table></table>을 함께 쓸 때 <form></form>가 <table></table>을 감싸도록 한다
- <textarea></textarea>는 <input>과는 달리 여러 줄 입력이 가능하도록 하는 태그
<textarea></textarea> | name | <form></form>으로 값 전송시 변수명 |
rows | 가로 줄 수 (행의 수) | |
cols | 세로 줄 수 (열의 수) |
2. 게시글 목록
- 조회 유형(전체 조회 / 검색 조회)에 맞는 조회(SELECT) 명령을 실행한 후 그 결과를 model에 첨부하여 View에 보낸다
- 게시글 목록 페이지에는 전체 조회 / 검색 조회의 결과가 표시되도록 한다

BoardDao
public interface BoardDao {
// 추상 메소드 - 게시글 조회
// 1) 전체 조회
List<BoardDto> selectList();
// 2) 검색 조회
List<BoardDto> selectList(String type, String keyword);
}
BoardDaoImpl
@Repository
public class BoardDaoImpl implements BoardDao {
// 의존성 주입
@Autowired
JdbcTemplate jdbcTemplate;
// 게시글 조회를 위한 RowMapper
private RowMapper<BoardDto> mapper = new RowMapper<>() {
@Override
public BoardDto mapRow(ResultSet rs, int rowNum) throws SQLException {
return BoardDto.builder()
.boardNo(rs.getInt("board_no"))
.boardWriter(rs.getString("board_writer"))
.boardTitle(rs.getString("board_title"))
.boardContent(rs.getString("board_content"))
.boardWritetime(rs.getDate("board_writetime"))
.boardUpdatetime(rs.getDate("board_updatetime"))
.boardRead(rs.getInt("board_read"))
.boardLike(rs.getInt("board_like"))
.boardHead(rs.getString("board_head"))
.build();
}
};
// 추상 메소드 오버라이딩 - 게시글 조회
// 1) 전체 조회
@Override
public List<BoardDto> selectList() {
String sql = "select * from board order by board_no desc";
return jdbcTemplate.query(sql, mapper);
}
// 2) 검색 조회
@Override
public List<BoardDto> selectList(String type, String keyword) {
String sql = "select * from board where instr(#1, ?) > 0 order by board_no desc";
sql = sql.replace("#1", type);
Object[] param = new Object[] {keyword};
return jdbcTemplate.query(sql, mapper, param);
}
}
BoardController
@Controller
@RequestMapping("/board")
public class BoardController {
// 의존성 주입
@Autowired
BoardDao boardDao;
// 2. 게시글 목록
// 게시글 목록 Mapping
@GetMapping("/list")
public String selectList(Model model,
@RequestParam(required = false) String type,
@RequestParam(required = false) String keyword
) {
// 조회 유형 판정
boolean isSearch = type != null && keyword != null;
if(isSearch) { // 검색 조회라면
// 게시글 검색 조회 실행 후 그 결과를 List에 BoardDto의 형태로 반환
List<BoardDto> list = boardDao.selectList(type, keyword);
// 조회 결과를 model에 첨부
model.addAttribute("list", list);
}
else { // 검색 조회가 아니라면
// 게시글 전체 조회 실행 후 그 결과를 List에 BoardDto의 형태로 반환
List<BoardDto> list = boardDao.selectList();
// 조회 결과를 model에 첨부
model.addAttribute("list", list);
}
// 게시글 목록(list.jsp)로 연결
return "board/list";
}
}
** VO를 이용하여 여러 @RequestParam을 한 번에 입력받을 수 있다
BoardListSearchVO
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BoardListSearchVO {
// 필드
private String type;
private String keyword;
// 메소드 - 조회 유형이 검색 조회인지 여부 반환
public boolean isSearch() {
return type != null && keyword != null;
}
}
BoardDao
public interface BoardDao {
// 추상 메소드 - 게시글 조회
// 3) BoardListSearchVO를 이용한 통합 조회
List<BoardDto> selectList(BoardListSearchVO vo);
}
BoardDaoImpl
@Repository
public class BoardDaoImpl implements BoardDao {
// 의존성 주입
@Autowired
JdbcTemplate jdbcTemplate;
// 추상 메소드 오버라이딩 - 게시글 조회
// 3) BoardListSearchVO를 이용한 통합 조회
@Override
public List<BoardDto> selectList(BoardListSearchVO vo) {
String sql = "select * from board where instr(#1, ?) > 0 order by board_no desc";
sql = sql.replace("#1", vo.getType());
Object[] param = new Object[] {vo.getKeyword()};
return jdbcTemplate.query(sql, mapper, param);
}
}
BoardController
- @RequestParam인 String type, String keyword를 묶어 VO로 만들 수 있다
- @ModelAttributes의 name을 vo로 하여 View에서 해당 name을 변수명으로 사용할 수 있다
@Controller
@RequestMapping("/board")
public class BoardController {
// 의존성 주입
@Autowired
BoardDao boardDao;
// 게시글 목록
// 게시글 목록 Mapping
@GetMapping("/list")
public String selectList(Model model, @ModelAttribute(name = "vo") BoardListSearchVO vo) {
// 조회 유형 판정 - BoardListSearchVO의 isSearch() 메소드
if(vo.isSearch()) { // 검색 조회일 경우
// model에 검색 조회 selectList(BoardListSearchVO vo)의 결과를 첨부
model.addAttribute("list", boardDao.selectList(vo));
}
else { // 그렇지 않다면
// model에 전체 조회 selectList()의 결과를 첨부
model.addAttribute("list", boardDao.selectList());
}
// 게시글 목록(list.jsp)로 연결
return "board/list";
}
}
list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix = "fmt" uri = "http://java.sun.com/jsp/jstl/fmt" %>
<%-- 오늘 날짜를 구해서 today라는 변수로 만든다 --%>
<jsp:useBean id = "now" class = "java.util.Date"></jsp:useBean>
<c:set var = "today">
<fmt:formatDate value = "${now}" pattern = "yyyy-MM-dd"/>
</c:set>
<jsp:include page = "/WEB-INF/views/template/header.jsp">
<jsp:param value = "게시글 목록" name = "title"/>
</jsp:include>
<div align = "center">
<h1>게시글 목록</h1>
<table border = "1" width = "900">
<thead>
<%-- 로그인 상태에서만 글쓰기 항목이 보이도록 설정 --%>
<c:if test = "${loginId != null}">
<tr>
<td align = "right" colspan = "5">
<a href = "write">글쓰기</a>
</td>
</tr>
</c:if>
<tr>
<th>번호</th>
<th width = "45%">제목</th>
<th>작성자</th>
<th>작성일</th>
<th>조회수</th>
</tr>
</thead>
<tbody align = "center">
<c:forEach var = "boardDto" items = "${list}">
<tr>
<td>${boardDto.boardNo}</td>
<td align = "left">
<%-- 말머리가 있을 경우에만 출력 --%>
<c:if test = "${boardDto.boardHead != null}">
[${boardDto.boardHead}]
</c:if>
<%-- 제목을 누르면 해당 게시글의 상세 페이지로 이동하도록 --%>
<a href = "detail?boardNo=${boardDto.boardNo}">
${boardDto.boardTitle}
</a>
</td>
<td>${boardDto.boardWriter}</td>
<td>
<%-- 작성 날짜를 current라는 변수로 만든다 --%>
<c:set var = "current">
<fmt:formatDate value = "${boardDto.boardWritetime}" pattern = "yyyy-MM-dd"/>
</c:set>
<c:choose>
<%-- today(오늘 날짜)와 current(작성 날짜)가 같다면 시간과 분만 표시--%>
<c:when test = "${today == current}">
<fmt:formatDate value = "${boardDto.boardWritetime}" pattern = "HH:mm"/>
</c:when>
<%-- 그렇지 않다면 년도-월-일로 표시 --%>
<c:otherwise>
<fmt:formatDate value = "${boardDto.boardWritetime}" pattern = "yyyy-MM-dd"/>
</c:otherwise>
</c:choose>
</td>
<td>${boardDto.boardRead}</td>
</tr>
</c:forEach>
</tbody>
<c:if test = "${loginId != null}">
<tfoot>
<tr>
<td align = "right" colspan = "5">
<a href = "write">글쓰기</a>
</td>
</tr>
</tfoot>
</c:if>
</table>
<%-- 페이지 네비게이터 --%>
<h3> « < 1 2 3 4 5 6 7 8 9 10 > » </h3>
<%--검색창 --%>
<form action = "list" method = "get">
<select name = "type" required>
<option value = "board_title" <c:if test = "${vo.type == 'board_title'}">selected</c:if>>제목</option>
<option value = "board_content" <c:if test = "${vo.type == 'board_content'}">selected</c:if>>작성자</option>
<option value = "board_writer" <c:if test = "${vo.type == 'board_writer'}">selected</c:if>>작성자</option>
</select>
<input type = "search" name = "keyword" placeholder = "검색어" required value = "${vo.keyword}">
<button type = "submit">검색</button>
</form>
</div>
<jsp:include page = "/WEB-INF/views/template/footer.jsp"></jsp:include>
3. 게시글 상세
- 게시글 상세 Mapping으로 이동하기 위해서는 게시글 번호(boardNo)가 필요하다
- Controller에서 게시글 번호(boardNo)를 요청 파라미터로 받아야 단일 조회를 실행할 수 있다
- 게시글 목록에서 게시글 상세로 이동할 때 해당하는 열의 게시글 번호(boardNo)와 그 값을 포함하는 하이퍼링크를 통해
게시글 상세 Mapping에 요청 파라미터를 전달할 수 있다
- 게시글 번호(boardNo)를 받아 단일 조회(DETAIL) 명령을 수행한 후 그 결과를 model에 첨부하여 View에 보낸다
- 게시글 상세 페이지에는 단일 조회의 결과가 표시되도록 한다
- 게시글 상세 페이지에 들어올 때 해당 게시글의 게시글 조회수(boardRead)가 1씩 증가하도록 한다
- 만약 이전에 들어와본 게시글이라면 해당 게시글의 조회수가 증가하지 않도록 한다

BoardDao
public interface BoardDao {
// 추상 메소드 - 게시글 상세
// 1) 게시글 상세 - 조회수가 올라가지 않는 단일 조회
BoardDto selectOne(int boardNo);
// 2) 게시글 상세 - 조회수가 올라가는 단일 조회
BoardDto read(int boardNo);
// 3) 조회수 증가
boolean updateReadCount(int boardNo);
}
BoardDaoImpl
@Repository
public class BoardDaoImpl implements BoardDao {
// 의존성 주입
@Autowired
JdbcTemplate jdbcTemplate;
// 게시글 상세를 위한 ResultSetExtractor
private ResultSetExtractor<BoardDto> extractor = new ResultSetExtractor<>() {
@Override
public BoardDto extractData(ResultSet rs) throws SQLException, DataAccessException {
if(rs.next()) {
return BoardDto.builder()
.boardNo(rs.getInt("board_no"))
.boardWriter(rs.getString("board_writer"))
.boardTitle(rs.getString("board_title"))
.boardContent(rs.getString("board_content"))
.boardWritetime(rs.getDate("board_writetime"))
.boardUpdatetime(rs.getDate("board_updatetime"))
.boardRead(rs.getInt("board_read"))
.boardLike(rs.getInt("board_like"))
.boardHead(rs.getString("board_head"))
.build();
}
else {
return null;
}
}
};
// 추상 메소드 오버라이딩 - 게시글 상세
// 게시글 상세 - 조회수가 올라가지 않는 단일 조회
@Override
public BoardDto selectOne(int boardNo) {
String sql = "select * from board where board_no = ?";
Object[] param = new Object[] {boardNo};
return jdbcTemplate.query(sql, extractor, param);
}
}
BoardController
@Controller
@RequestMapping("/board")
public class BoardController {
// 의존성 주입
@Autowired
BoardDao boardDao;
// 3. 게시글 상세
// 게시글 상세 Mapping
@GetMapping("/detail")
public String detail(Model model, @RequestParam int boardNo) {
// 게시글 상세의 결과를 model에 첨부
model.addAttribute("boardDto", boardDao.selectOne(boardNo));
// 게시글 상세 페이지(detail.jsp)로 연결
return "board/detail";
}
}
detail.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix = "fmt" uri = "http://java.sun.com/jsp/jstl/fmt" %>
<jsp:include page = "/WEB-INF/views/template/header.jsp">
<jsp:param value = "게시글 상세" name = "title"/>
</jsp:include>
<div align = "center">
<h1>게시글 상세</h1>
<table border = "1" width = "900">
<tbody>
<tr>
<th width = "25%">번호</th>
<td>${boardDto.boardNo}</td>
</tr>
<tr>
<th>말머리</th>
<td>${boardDto.boardHead}</td>
</tr>
<tr>
<th>제목</th>
<td>${boardDto.boardTitle}</td>
</tr>
<tr>
<th>작성자</th>
<td>${boardDto.boardWriter}</td>
</tr>
<tr height = "200" valign = "top">
<th>내용</th>
<td>
<%-- pre 태그는 엔터, 띄어쓰기, 탭키 등을 있는 그대로 표시하는 영역 --%>
<pre>${boardDto.boardContent}</pre>
</td>
</tr>
<tr>
<th>조회수</th>
<td>${boardDto.boardRead}</td>
</tr>
<tr>
<th>작성일</th>
<td>
<fmt:formatDate value = "${boardDto.boardWritetime}" pattern = "y년 M월 d일 E요일 a h시 m분 s초"/>
</td>
</tr>
<%-- 한 번이라도 수정한 적이 있다면(수정 시간이 null이 아니라면) 수정 시간을 표시 --%>
<c:if test = "${boardDto.boardUpdatetime != null}">
<tr>
<th>수정일</th>
<td>
<fmt:formatDate value = "${boardDto.boardUpdatetime}" pattern = "y년 M월 d일 E요일 a h시 m분 s초"/>
</td>
</tr>
</c:if>
</tbody>
<tfoot>
<tr>
<td colspan = "2" align = "right">
<%-- 로그인 상태에서만 게시글 작성이 가능하도록 설정 --%>
<c:if test = "${loginId != null}">
<a href = "write">글쓰기</a>
</c:if>
<%-- 로그인한 회원이 게시글 작성자인지에 대한 변수(boolean) 생성 --%>
<c:set var = "owner" value = "${loginId == boardDto.boardWriter}"></c:set>
<%-- 로그인한 회원의 등급이 관리자인지에 대한 변수(boolean) 생성 --%>
<c:set var = "admin" value = "${mg == '관리자'}"></c:set>
<%-- 만약 로그인한 회원이 게시글 작성자라면 게시글을 수정할 수 있도록 설정--%>
<c:if test = "${owner}">
<a href = "edit?boardNo=${boardDto.boardNo}">수정</a>
</c:if>
<%-- 만약 로그인한 회원이 게시글 작성자이거나 등급이 관리자라면 게시글을 삭제할 수 있도록 설정--%>
<c:if test = "${owner || admin}">
<a href = "delete?boardNo=${boardDto.boardNo}">삭제</a>
</c:if>
<a href = "list">목록으로</a>
</td>
</tr>
</tfoot>
</table>
</div>
<jsp:include page = "/WEB-INF/views/template/footer.jsp"></jsp:include>
4. 게시글 수정
- 게시글 수정 페이지로 이동하기 위해서는 해당 게시글 번호(boardNo)가 필요하다
- Controller에서 게시글 번호(boardNo)를 요청 파라미터로 받아 단일 조회의 결과를 model에 첨부하여 View에 보낸다
- 게시글 목록에서 게시글 상세로 이동할 때 해당하는 열의 게시글 번호(boardNo)와 그 값을 포함하는 하이퍼링크를 통해
게시글 상세 Mapping에 요청 파라미터를 전달할 수 있다
- 게시글 수정 페이지에서 단일 조회의 결과를 <form>에 표시하여 수정 전 값이 표시되도록 한다
- 게시글 수정 페이지에서 수정된 값이 입력되면 ModelAttribute로 받아서 수정(UPDATE) 명령을 실행한다
- 게시글 수정이 끝나면 해당 게시글 번호(boardNo)의 게시글 상세 페이지로 redirect 시킨다

BoardDao
public interface BoardDao {
// 추상 메소드 - 게시글 수정
boolean update(BoardDto boardDto);
}
BoardDaoImpl
@Repository
public class BoardDaoImpl implements BoardDao {
// 의존성 주입
@Autowired
JdbcTemplate jdbcTemplate;
// 추상 메소드 오버라이딩 - 게시글 수정
@Override
public boolean update(BoardDto boardDto) {
String sql = "update board set "
+ "board_title = ?, "
+ "board_content = ?, "
+ "board_head = ?, "
+ "board_updatetime = sysdate "
+ "where board_no = ?";
Object[] param = new Object[] {
boardDto.getBoardTitle(),
boardDto.getBoardContent(),
boardDto.getBoardHead(),
boardDto.getBoardNo()
};
return jdbcTemplate.update(sql, param) > 0;
}
}
BoardController
@Controller
@RequestMapping("/board")
public class BoardController {
// 의존성 주입
@Autowired
BoardDao boardDao;
// 4. 게시글 수정
// 1) 게시글 수정 Mapping
@GetMapping("/edit")
public String edit(Model model, @RequestParam int boardNo) {
// 하이퍼링크를 통해 전달받은 boardNo를 이용하여 단일 조회 실행 후 그 결과를 boardDto에 저장
BoardDto boardDto = boardDao.selectOne(boardNo);
// 단일 조회의 결과가 없다면(null) 설정한 예외 발생
if(boardDto == null) {
throw new TargetNotFoundException();
}
// 단일 조회의 결과(boardDto)를 model에 첨부
model.addAttribute("boardDto", boardDto);
// 게시글 수정 페이지(edit.jsp)로 연결
return "board/edit";
}
// 2) 게시글 수정 Mapping에 DTO 전달 및 DB 처리
@PostMapping("/edit")
public String edit(@ModelAttribute BoardDto boardDto, RedirectAttributes attr) {
// 게시글 수정 성공 여부
boolean result = boardDao.update(boardDto);
// 게시글 수정에 성공했다면 해당 게시글의 상세 Mapping으로 강제 이동(redirect)
if(result) {
attr.addAttribute("boardNo", boardDto.getBoardNo());
return "redirect:detail";
}
// 게시글 수정에 실패했다면 설정한 예외 발생
else {
throw new TargetNotFoundException();
}
}
}
edit.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<jsp:include page = "/WEB-INF/views/template/header.jsp">
<jsp:param name = "title" value = "게시글 수정"/>
</jsp:include>
<div align = "center">
<form action = "edit" method = "post">
<%-- 수정 완료 후 해당 상세 페이지로 이동하기 위해 boardNo는 수정이 불가능하도록 하며 그 값을 다시 되돌려 받는다 --%>
<input type = "hidden" name = "boardNo" value = "${boardDto.getBoardNo()}">
<table border = "1" width = "500">
<tbody>
<tr>
<th>말머리</th>
<td>
<select name = "boardHead">
<option value = "">선택</option>
<%-- option의 selected 속성은 페이지 로드시 미리 선택되어지는 옵션 --%>
<%-- 수정하기 전 boardHead가 '정보'였다면 수정 페이지에서 '정보'가 자동으로 선택되어있다 --%>
<option <c:if test = "${boardDto.boardHead == '정보'}">selected</c:if>>정보</option>
<option <c:if test = "${boardDto.boardHead == '유머'}">selected</c:if>>유머</option>
<%-- 회원 등급이 관리자일 때만 '공지'라는 말머리를 사용할 수 있도록 한다 --%>
<c:if test = "${mg == '관리자'}">
<option <c:if test = "${boardDto.boardHead == '공지'}">selected</c:if>>공지</option>
</c:if>
</select>
</td>
</tr>
<tr>
<th>제목</th>
<td>
<input type = "text" name = "boardTitle" required value = "${boardDto.boardTitle}">
</td>
</tr>
<tr>
<th>내용</th>
<td>
<textarea name = "boardContent" rows = "10" cols = "50" required>${boardDto.boardContent}</textarea>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td align = "right" colspan = "2">
<a href = "list">목록으로</a>
<button type = "submit">수정하기</button>
</td>
</tr>
</tfoot>
</table>
</form>
</div>
<jsp:include page = "/WEB-INF/views/template/footer.jsp"></jsp:include>
5. 게시글 삭제

- 게시글 삭제 페이지로 이동하기 위해서는 해당 게시글 번호(boardNo)가 필요하다
- Controller에서 게시글 번호(boardNo)를 요청 파라미터로 받아 단일 조회의 결과를 model에 첨부하여 View에 보낸다
- 게시글 목록에서 게시글 상세로 이동할 때 해당하는 열의 게시글 번호(boardNo)와 그 값을 포함하는 하이퍼링크를 통해
게시글 삭제 Mapping에 요청 파라미터를 전달할 수 있다
- 게시글 삭제가 끝나면 게시글 목록 Mapping으로 redirect 시킨다
BoardDao
public interface BoardDao {
// 추상 메소드 - 게시글 삭제
boolean delete(int boardNo);
}
BoardDaoImpl
@Repository
public class BoardDaoImpl implements BoardDao {
// 의존성 주입
@Autowired
JdbcTemplate jdbcTemplate;
// 추상 메소드 오버라이딩 - 게시글 삭제
@Override
public boolean delete(int boardNo) {
String sql = "delete board where board_no = ?";
Object[] param = new Object[] {boardNo};
return jdbcTemplate.update(sql, param) > 0;
}
}
BoardDaoController
@Controller
@RequestMapping("/board")
public class BoardController {
// 의존성 주입
@Autowired
BoardDao boardDao;
// 5. 게시글 삭제
// - 게시글 삭제 Mapping
@GetMapping("/delete")
public String delete(@RequestParam int boardNo) {
// 게시글 삭제 성공 여부
boolean result = boardDao.delete(boardNo);
// 게시글 삭제에 성공했다면 해당 게시글 목록 Mapping으로 강제 이동(redirect)
if(result) {
return "reidrect:list";
}
// 게시글 수정에 실패했다면 설정한 예외 발생
else {
throw new TargetNotFoundException();
}
}
}