회원과 게시판 — 실습
작성자 ID 와 세션 사용자 ID 를 비교해 본인일 때만 허용.
-- MySQL 에서 실행
ALTER TABLE myboard
ADD COLUMN created_at DATETIME DEFAULT CURRENT_TIMESTAMP;
-- 기존 row 도 자동으로 ALTER 시점의 시각으로 채워짐
SELECT num, title, writer, created_at FROM myboard;
// com/smhrd/domain/Board.java — createdAt 필드 합류
@Data @AllArgsConstructor @NoArgsConstructor
public class Board {
private int num;
private String title;
private String writer;
private String content;
private LocalDateTime createdAt; // ← 추가
}
SHOW COLUMNS FROM myboard; — 5번째 컬럼 created_at 보이는가?SELECT created_at FROM myboard; — v5 에서 만든 기존 row 도 시각이 채워져 있는가? (DEFAULT CURRENT_TIMESTAMP 의 위력)<!-- BoardMapper.xml — SELECT 절에 created_at 합류, update/delete 추가 -->
<select id="selectOne" parameterType="int"
resultType="com.smhrd.domain.Board">
SELECT num, title, writer, content, created_at
FROM myboard WHERE num = #{num}
</select>
<update id="update" parameterType="com.smhrd.domain.Board">
UPDATE myboard SET title = #{title}, content = #{content}
WHERE num = #{num}
</update>
<delete id="delete" parameterType="int">
DELETE FROM myboard WHERE num = #{num}
</delete>
// BoardService — 본인 확인
public boolean isOwner(int num, String userId) {
Board b = mapper.selectOne(num);
return b != null && b.getWriter().equals(userId);
}
public void update(Board b, String userId) {
Board o = mapper.selectOne(b.getNum());
if (!o.getWriter().equals(userId))
throw new SecurityException("작성자가 아닙니다");
mapper.update(b);
}
public void delete(int num, String userId) {
Board o = mapper.selectOne(num);
if (!o.getWriter().equals(userId))
throw new SecurityException("작성자가 아닙니다");
mapper.delete(num);
}
num, title, writer, content, created_at 5 컬럼인가?writer.equals(userId) 비교 — 문자열 비교라 == 가 아닌 .equals() 사용했나?@PostMapping("/board/update")
public String update(Board b, HttpSession session, RedirectAttributes ra) {
Member u = (Member) session.getAttribute("loginUser");
if (!service.isOwner(b.getNum(), u.getId())) {
ra.addFlashAttribute("err", "작성자만 수정 가능합니다");
return "redirect:/board/view?num=" + b.getNum();
}
service.update(b, u.getId());
return "redirect:/board/view?num=" + b.getNum();
}
@PostMapping("/board/delete")
public String delete(@RequestParam int num, HttpSession session,
RedirectAttributes ra) {
Member u = (Member) session.getAttribute("loginUser");
if (!service.isOwner(num, u.getId())) {
ra.addFlashAttribute("err", "작성자만 삭제 가능합니다");
return "redirect:/board/view?num=" + num;
}
service.delete(num, u.getId());
return "redirect:/board/list";
}
<!-- view.jsp -->
<p>작성자: ${board.writer} | 작성일: ${board.createdAt}</p>
<c:if test="${board.writer == sessionScope.loginUser.id}">
<a href="/board/edit?num=${board.num}">수정</a>
<form action="/board/delete" method="post" style="display:inline;">
<input type="hidden" name="num" value="${board.num}">
<button>삭제</button>
</form>
</c:if>
실험: user1 로 글을 쓰고 → 로그아웃 → user2 로 로그인 → 같은 글에 들어가본다.
num 값을 변조해도 서버에서 차단되는지 (진짜 보안)${board.createdAt} 시각이 출력되는지