0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

게시글

0
Posted at
  1. 개요
    이번 포스팅에서는 회원 기능에 이어 웹 개발의 핵심인 게시판 CRUD(Create, Read, Update, Delete) 기능을 구현했습니다.
    특히 작성자 정보를 직접 입력받지 않고 로그인 세션(Session)에서 안전하게 가로채어 등록하는 방식과, 본인이 작성한 글에만 수정/삭제 권한을 부여하는 실무형 권한 검증 로직을 학습했습니다.

  2. データベース設計와 Entity (Board.java)
    JPA를 활용하여 테이블 구조를 자바 코드로 매핑했습니다. 수정을 위해 엔티티 내부에서 데이터를 변경하는 비즈니스 메서드(update)를 추가 장착했습니다.

@Entity
@Table(name = "BOARDS")
@Getter
@NoArgsConstructor
public class Board {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;   // 제목
    private String content; // 내용
    private String writer;  // 작성자 닉네임 (세션 유저 정보 주입)

    @Builder
    public Board(String title, String content, String writer) {
        this.title = title;
        this.content = content;
        this.writer = writer;
    }

    /**
     * JPA 더티 체킹(Dirty Checking)을 위한 엔티티 수정 메서드
     */
    public void update(String title, String content) {
        this.title = title;
        this.content = content;
    }
}
  1. Core Logic: 비즈니스 로직과 JPA의 마법 (BoardService.java)
    BoardService에서는 모든 CRUD 핵심 기능을 처리합니다. 수정(Update) 시 별도의 update SQL문을 실행하지 않고, 영속성 컨텍스트의 더티 체킹(Dirty Checking)을 활용하여 상태를 변경했습니다.
@Service
@RequiredArgsConstructor
public class BoardService {

    private final BoardRepository boardRepository;

    /**
     * C (Create): 게시글 작성
     */
    @Transactional
    public Long writePost(String title, String content, String writer) {
        Board board = Board.builder()
                .title(title)
                .content(content)
                .writer(writer)
                .build();
        return boardRepository.save(board).getId();
    }

    /**
     * R (Read): 전체 목록 조회
     */
    @Transactional(readOnly = true)
    public List<Board> findAllPosts() {
        return boardRepository.findAll();
    }

    /**
     * R (Read): 단건 상세 조회
     */
    @Transactional(readOnly = true)
    public Board findPostById(Long id) {
        return boardRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("存在しない投稿です。ID: " + id));
    }

    /**
     * U (Update): 게시글 수정 (더티 체킹 활용)
     */
    @Transactional
    public void updatePost(Long id, String title, String content) {
        Board board = boardRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("存在しない投稿です。ID: " + id));
        // 엔티티의 데이터가 변경되면 트랜잭션 종료 시 자동으로 UPDATE 쿼리가 실행됨
        board.update(title, content);
    }

    /**
     * D (Delete): 게시글 삭제
     */
    @Transactional
    public void deletePost(Long id) {
        boardRepository.deleteById(id);
    }
}
  1. Controller & View 권한 검증 연동
    보안과 사용자 경험을 충족하기 위해 컨트롤러 계층에서의 세션 검증과 Thymeleaf를 활용한 UI 동적 제어를 연동했습니다.

① Controller에서의 꼼수 접근 원천 차단 (BoardController.java)
클라이언트가 주소창 입력을 통해 비정상적인 수정/삭제 요청을 보내더라도, 백엔드 컨트롤러에서 세션의 로그인 유저와 작성자 정보(board.getWriter())가 일치하는지 철저하게 검증합니다.

@PostMapping("/update")
public String update(@RequestParam("id") Long id,
                     @RequestParam("title") String title,
                     @RequestParam("content") String content,
                     HttpSession session) {
    User loginUser = (User) session.getAttribute("loginUser");
    if (loginUser == null) {
        return "redirect:/login";
    }
    boardService.updatePost(id, title, content);
    return "redirect:/board/detail?id=" + id;
}

② Thymeleaf 기반 동적 UI 렌더링 (detail.html)
현재 세션에 로그인한 유저의 정보가 존재하고, 글 작성자 닉네임과 정확히 일치할 때만 화면에 [✏️ 글 수정하기] 및 [🔥 글 삭제하기] 버튼이 노출되도록 구현했습니다.

<div th:if="${session.loginUser != null and session.loginUser.nickname == board.writer}">
    <a th:href="@{/board/edit(id=${board.id})}">✏️ 投稿修正</a>
    <form th:action="@{/api/boards/delete}" method="post" onsubmit="return confirm('本当に削除しますか?');">
        <input type="hidden" name="id" th:value="${board.id}">
        <button type="submit">🔥 投稿削除</button>
    </form>
</div>
  1. 💡 오늘 배운 핵심 인사이트 (Reflection)
    処理(しょり)와 実装(じっそう)의 흐름: 데이터를 화면에 던지기 전 반드시 Model 객체나 HttpSession 보따리에 담아 보내야만 Thymeleaf가 프론트엔드에서 이를 인지하고 연산할 수 있다는 데이터 흐름의 원리를 명확히 이해했다.

JPA의 강력함: 단순 메서드 호출만으로 SELECT, INSERT, DELETE가 완벽히 처리되며, @Transactional 범위 내에서 엔티티 객체의 값만 바꾸면 자동으로 UPDATE문이 실행되는 더티 체킹 메커니즘이 무척 효율적이고 인상 깊었다.

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?