블로그 만들기 21. 게시글 구현 : 상세보기 권한 체크하기

Feb 06, 2024
블로그 만들기 21. 게시글 구현 : 상세보기 권한 체크하기

1. 상세 페이지 확인하기

  • 로그인 인증 후 접속할 수 있게 하기
  • 자기 게시글에 만 수정, 삭제 권한 주기
notion image
notion image
 

2. pageOwner 만들기

  • detail에 {{#pageOwner}} {{/pageOwner}}로 가정법 집어넣기
pageOwner로 활성화 비활성화 조절하기
{{> layout/header}} <div class="container p-5"> {{#pageOwner}} <!-- 수정삭제버튼 --> <div class="d-flex justify-content-end"> <button class="btn btn-warning me-1">수정</button> <button class="btn btn-danger">삭제</button> </div> {{/pageOwner}} <div class="d-flex justify-content-end"> <b>작성자</b> : {{board.username}} </div> <!-- 게시글내용 --> <div> <h2><b>{{board.title}}</b></h2> <hr /> <div class="m-4 p-2"> {{board.content}} </div> </div> <!-- 댓글 --> <div class="card mt-3"> <!-- 댓글등록 --> <div class="card-body"> <form action="/reply/save" method="post"> <textarea class="form-control" rows="2" name="comment"></textarea> <div class="d-flex justify-content-end"> <button type="submit" class="btn btn-outline-primary mt-1">댓글등록</button> </div> </form> </div> <!-- 댓글목록 --> <div class="card-footer"> <b>댓글리스트</b> </div> <div class="list-group"> <!-- 댓글아이템 --> <div class="list-group-item d-flex justify-content-between align-items-center"> <div class="d-flex"> <div class="px-1 me-1 bg-primary text-white rounded">cos</div> <div>댓글 내용입니다</div> </div> <form action="/reply/1/delete" method="post"> <button class="btn">🗑</button> </form> </div> <!-- 댓글아이템 --> <div class="list-group-item d-flex justify-content-between align-items-center"> <div class="d-flex"> <div class="px-1 me-1 bg-primary text-white rounded">ssar</div> <div>댓글 내용입니다</div> </div> <form action="/reply/1/delete" method="post"> <button class="btn">🗑</button> </form> </div> </div> </div> </div> {{> layout/footer}}
  • 상세보기 하기 전에 detail()에서 잡아야 함
  • 페이지 주인 여부 체크하기
board의 userId와 sessionId의 값 비교
같을 경우에는 pageOwner = true → 활성화
다를 경우에는 pageOwner = false → 비활성화
이 값을 mustache에게 줘야함!
package shop.mtcoding.blog.board; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpSession; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.ResponseBody; import shop.mtcoding.blog.user.User; import java.util.List; @RequiredArgsConstructor @Controller public class BoardController { private final HttpSession session; // DI private final BoardRepository boardRepository; // DI @PostMapping("/board/save") public String save(BoardRequest.SaveDTO requestDTO, HttpServletRequest request) { // 1. 인증 체크 User sessionUser = (User) session.getAttribute("sessionUser"); System.out.println("sessionUser:" + sessionUser); if (sessionUser == null) { return "redirect:/loginForm"; } // 2. 바디 데이터 확인 및 유효성 검사 System.out.println(requestDTO); if (requestDTO.getTitle().length() > 30) { request.setAttribute("status", 400); request.setAttribute("msg", "title의 길이가 30자를 초과해서는 안되요"); return "error/40x"; // BadRequest } // 3. 모델 위임 // insert into board_tb(title, content, user_id, created_at) values(?,?,?, now()); boardRepository.save(requestDTO, sessionUser.getId()); return "redirect:/"; } // http://localhost:8080?page=0 @GetMapping({"/", "/board"}) public String index(HttpServletRequest request) { List<Board> boardList = boardRepository.findAll(); request.setAttribute("boardList", boardList); return "index"; } @GetMapping("/board/saveForm") // /board/saveForm Get요청이 옴 public String saveForm() { // session 영역에 접근하기 위한 // 1. session 영역에 sessionUser 키 값에 user 객체가 있는지 체크하기 User sessionUser = (User) session.getAttribute("sessionUser"); // 2. 값이 null이면 로그인 페이지로 리다이렉션 if (sessionUser == null) { return "redirect:/loginForm"; } // 3. null이 아니면 /board/saveForm으로 이동 return "board/saveForm"; } // 상세보기시 호출 @GetMapping("/board/{id}") // 1이 프라이머리키 -> 뭐든 넣어도 실행시키려면 변수화시켜서 {} public String detail(@PathVariable int id, HttpServletRequest request) { System.out.println("id : " + id); // 1. 바로 모델 진입 -> 상세보기 데이터 가져오기 // body 데이터가 없으면 유효성 검사할 필요 없음 BoardResponse.DetailDTO reponseDTO = boardRepository.findById(id); // user 객체를 가져와서 session 값 받기 : object라 다운 캐스팅 해야함 User sessionUser = (User) session.getAttribute("sessionUser"); //System.out.println("sessionUser: " + sessionUser); // 2. 페이지 주인 여부 체크(board의 userId와 sessionId의 값 비교) boolean pageOwner = false; if (reponseDTO.getUserId() == sessionUser.getId()) { //System.out.println("getUserId:" + reponseDTO.getUserId()); pageOwner = true; } request.setAttribute("board", reponseDTO); request.setAttribute("pageOwner", pageOwner); // 이 값을 mustache에게 줘야함! return "board/detail"; } }
notion image
notion image
notion image
notion image
 
package shop.mtcoding.blog.board; import lombok.Data; import shop.mtcoding.blog.user.User; public class BoardResponse { @Data // DB세상의 데이터 -> 릴레이션 매핑 : Java세상 데이터 public static class DetailDTO { private int id; private String title; private String content; private int userId; // 게시글 작성자 아이디 private String username; private Boolean boardOwner; public void isBoardOwner(User sessionUser) { // 로그인한 ID가 필요함 if (sessionUser == null){ boardOwner = false; } else { boardOwner = sessionUser.getId() == userId; // 같은지 확인하기 } } } @Data public static class ReplyDTO { private Integer id; private Integer userId; private String comment; private String username; private Boolean replyOwner; // 댓글의 작성자 확인(session값과 비교) public ReplyDTO(Object[] ob, User sessionUser) { this.id = (Integer) ob[0]; this.userId = (Integer) ob[1]; this.comment = (String) ob[2]; this.username = (String) ob[3]; if(sessionUser == null) { replyOwner = false; } else { replyOwner = sessionUser.getId() == userId; } } } }
package shop.mtcoding.blog.reply; import jakarta.persistence.EntityManager; import jakarta.persistence.Query; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; import shop.mtcoding.blog.board.BoardResponse; import shop.mtcoding.blog.user.User; import java.util.List; @RequiredArgsConstructor @Repository public class ReplyRepository { private final EntityManager em; public List<BoardResponse.ReplyDTO> findByBoardId(int boardId, User sessionUser) { String q = """ select rt.id, rt.user_id, rt.comment, ut.username from reply_tb rt inner join user_tb ut on rt.user_id = ut.id where rt.board_id = ? """; // ReplyDTO는 ENTITY가 아니니까 파싱 안해줌 // Reply.class는 데이터가 다르니까 파싱 안해줌 Query query = em.createNativeQuery(q); // ReplyDTO는 ENTITY가 아니니까 파싱 안해줌 query.setParameter(1, boardId); List<Object[]> rows = query.getResultList(); return rows.stream().map(row -> new BoardResponse.ReplyDTO(row, sessionUser)).toList(); } @Transactional public void save(ReplyRequest.SaveDTO requestDTO, int userId) { Query query = em.createNativeQuery("insert into reply_tb(comment, board_id, user_id, created_at) values(?,?,?, now())"); query.setParameter(1, requestDTO.getComment()); query.setParameter(2, requestDTO.getBoardId()); query.setParameter(3, userId); query.executeUpdate(); } }
package shop.mtcoding.blog.board; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpSession; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import shop.mtcoding.blog.reply.ReplyRepository; import shop.mtcoding.blog.user.User; import java.util.List; @RequiredArgsConstructor @Controller public class BoardController { private final HttpSession session; // DI private final BoardRepository boardRepository; // DI private final ReplyRepository replyRepository; // ?title=제목1&content=내용1 // title=제목1&content=내용1 // 쿼리 스트링과 -x-www-form-urlencoded와 파싱 방법이 동일함 @PostMapping("/board/{id}/update") public String update(@PathVariable int id, BoardRequest.UpdateDTO requestDTO) { // 파싱 전략이 json으로 바뀜 // System.out.println(requestDTO); 정보 받기 확인 // 인증 체크하기 User sessionUser = (User) session.getAttribute("sessionUser"); if (sessionUser == null) { return "redirect:/loginForm"; } // 권한 체크하기 Board board = boardRepository.findById(id); if (board.getUserId() != sessionUser.getId()) { return "error/403"; } // update board_tb set title =?, content =?, where id =? boardRepository.update(requestDTO, id); return "redirect:/board/" + id; // 수정한 게시글로 돌아가기 } @GetMapping("/board/{id}/updateForm") // 보드에 해당 페이지 public String updateFormn(@PathVariable int id, HttpServletRequest request) { // 인증 체크하기 User sessionUser = (User) session.getAttribute("sessionUser"); if (sessionUser == null) { return "redirect:/loginForm"; } // 권한 체크하기 Board board = boardRepository.findById(id); if (board.getUserId() != sessionUser.getId()) { request.setAttribute("status", 403); request.setAttribute("msg", "게시글을 수정할 권한이 없습니다"); return "error/40x"; // 리다이렉트 하면 데이터 사라지니까 하면 안됨 } // 가방에 담기 request.setAttribute("board", board); return "board/updateForm"; } @PostMapping("/board/{id}/delete") // body데이터가 없어서 유효성 검사 안해도 됨 public String delete(@PathVariable int id) { // 1. 인증 검사하기 User sessionUser = (User) session.getAttribute("sessionUser"); if (sessionUser == null) { return "redirect:/loginForm"; } // 2. 권한 검사하기 Board board = boardRepository.findById(id); if (board.getUserId() != sessionUser.getId()) { return "error/403"; } boardRepository.deleteById(id); return "redirect:/"; } @PostMapping("/board/save") public String save(BoardRequest.SaveDTO requestDTO, HttpServletRequest request) { // 1. 인증 체크 User sessionUser = (User) session.getAttribute("sessionUser"); System.out.println("sessionUser:" + sessionUser); if (sessionUser == null) { return "redirect:/loginForm"; } // 2. 바디 데이터 확인 및 유효성 검사 System.out.println(requestDTO); if (requestDTO.getTitle().length() > 30) { request.setAttribute("status", 400); request.setAttribute("msg", "title의 길이가 30자를 초과해서는 안되요"); return "error/40x"; // BadRequest } // 3. 모델 위임 // insert into board_tb(title, content, user_id, created_at) values(?,?,?, now()); boardRepository.save(requestDTO, sessionUser.getId()); return "redirect:/"; } // http://localhost:8080?page=0 @GetMapping({"/", "/board"}) public String index(HttpServletRequest request) { List<Board> boardList = boardRepository.findAll(); request.setAttribute("boardList", boardList); return "index"; } @GetMapping("/board/saveForm") // /board/saveForm Get요청이 옴 public String saveForm() { // session 영역에 접근하기 위한 // 1. session 영역에 sessionUser 키 값에 user 객체가 있는지 체크하기 User sessionUser = (User) session.getAttribute("sessionUser"); // 2. 값이 null이면 로그인 페이지로 리다이렉션 if (sessionUser == null) { return "redirect:/loginForm"; } // 3. null이 아니면 /board/saveForm으로 이동 return "board/saveForm"; } // 상세보기시 호출 @GetMapping("/board/{id}") // 1이 프라이머리키 -> 뭐든 넣어도 실행시키려면 변수화시켜서 {} public String detail(@PathVariable int id, HttpServletRequest request) { User sessionUser = (User) session.getAttribute("sessionUser"); // 페이지 권한 BoardResponse.DetailDTO boardDTO = boardRepository.findByIdWithUser(id); //메서드 이름 변경 boardDTO.isBoardOwner(sessionUser); // null이면 터짐 List<BoardResponse.ReplyDTO> replyDTOList = replyRepository.findByBoardId(id, sessionUser); request.setAttribute("board", boardDTO); request.setAttribute("replyList", replyDTOList); return "board/detail"; } }
notion image
Share article

vosw1