2022.11.24 - [Java/spring 게시판] - spring boot 게시판 - 7 <회원 정보 수정 및 탈퇴>
이전에 회원 관련 로직을 대부분 구현 한 뒤 이번에는 게시물에 관련된 로직을 구현해봤는데
회원 로직과 비슷한 부분이 많아 상대적으로 수월했던 것 같다.
✅게시물 작성
게시물을 작성하기 앞서 우선 domain을 생성해 주었는데 이번에는 게시물의 작성 시간을 확인하기 위해서
BaseEntity를 만들어 상속시켜주었다.
🟧Domain
⏹️ BaseEntity.java
package com.practice.board.domain;
import lombok.Getter;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.Column;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
@Getter
public class BaseEntity {
@CreationTimestamp
@Column(updatable = false)
private LocalDateTime createdAt;
@UpdateTimestamp
@Column(insertable = false)
private LocalDateTime updatedAt;
}
BaseEntity에서는 생성 시간과 수정시간을 알 수 있도록 딱 두 가지만 만들었다.
⏹️ Board.java
package com.practice.board.domain;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Entity
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "board")
public class Board extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String title;
@Column(nullable = false)
private String content;
@ManyToOne
@JoinColumn(name = "MEMBER_ID")
private Member member;
}
위와 같이 BaseEntity를 상속받으면 자동으로 날짜가 기입된다.
또한 해당 게시물을 누가 작성했는지 알아야 하기 때문에 Member 테이블을 조인시켰다.
🟧Controller
⏹️ BoardController.java
package com.practice.board.controller;
import com.practice.board.dto.board.BoardResponseDTO;
import com.practice.board.dto.board.BoardWriteRequestDTO;
import com.practice.board.service.board.BoardService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
@Controller
@RequiredArgsConstructor
@RequestMapping("/board")
public class BoardController {
private final BoardService boardService;
/**
* 게시글 작성
* @return 게시글 작성 페이지
*/
@GetMapping("/write")
public String writeForm() {
return "board/write";
}
/**
* 게시글 작성 post
* @param boardWriteRequestDTO 게시글 정보
* @param authentication 유저 정보
* @return 게시글 디테일 페이지
*/
@PostMapping("/write")
public String write(BoardWriteRequestDTO boardWriteRequestDTO, Authentication authentication) {
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
boardService.saveBoard(boardWriteRequestDTO, userDetails.getUsername());
return "redirect:/";
}
}
회원가입과 마찬가지로 Entity를 직접 건드리지 않기 위해서 DTO를 작성하여 정보를 받아오고
authentication을 통해 유저를 인증한다.
🟧DTO
⏹️ BoardWriteRequestDTO
package com.practice.board.dto.board;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BoardWriteRequestDTO {
private String title;
private String content;
}
DTO를 통해서 게시물의 제목, 내용만 간단히 받아온다.
🟧Service
⏹️ BoardServiceImpl.java
package com.practice.board.service.board;
import com.practice.board.domain.Board;
import com.practice.board.domain.Member;
import com.practice.board.dto.board.BoardResponseDTO;
import com.practice.board.dto.board.BoardWriteRequestDTO;
import com.practice.board.repository.BoardRepository;
import com.practice.board.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
@RequiredArgsConstructor
public class BoardServiceImpl implements BoardService{
private final MemberRepository memberRepository;
private final BoardRepository boardRepository;
@Override
public Long saveBoard(BoardWriteRequestDTO boardWriteRequestDTO, String email) {
Member member = memberRepository.findByEmail(email).orElseThrow(() -> new UsernameNotFoundException("이메일이 존재하지 않습니다."));
Board result = Board.builder()
.title(boardWriteRequestDTO.getTitle())
.content(boardWriteRequestDTO.getContent())
.member(member)
.build();
boardRepository.save(result);
return result.getId();
}
}
Controller에서 넘어온 유저 정보로 Member 테이블을 가져오고
DTO를 통해 Board 테이블을 생성한다. 여기서 BaseEntity를 상속했기 때문에 별 다른 내용을
넣지 않더라도 테이블에 자동적으로 생성이 된다.
🟧Repository
⏹️ BoardRepository.java
package com.practice.board.repository;
import com.practice.board.domain.Board;
import org.springframework.data.jpa.repository.JpaRepository;
public interface BoardRepository extends JpaRepository<Board, Long> {
}
boardRepository 또한 Member와 마찬가지로 JpaRepository를 상속받는다.
Member는 Id 값을 email로 잡았기 때문에 findByEmail 메서드를 추가했지만 Board는 필요하지 않기 때문에 생략.
🟧테스트
게시글을 작성하여 등록하면
DB에 정상적으로 등록되었다.
✅게시물 상세 조회
게시물을 등록 후 View에서 바로 확인하고 싶어서 수정보다 상세 조회를 먼저 진행하였다.
🟧Controller
⏹️ BoardController.java
/**
* 게시글 상세 조회
* @param id 게시글 ID
* @param model
* @return
*/
@GetMapping("/{id}")
public String boardDetail(@PathVariable Long id, Model model) {
BoardResponseDTO result = boardService.boardDetail(id);
model.addAttribute("dto", result);
model.addAttribute("id", id);
return "board/detail";
}
URL을 통해 게시물의 ID를 받아서 Service 단으로 넘겨준 뒤 전달받은 데이터를
model을 통해 View로 넘겨준다.
Controller에서 Param을 받는 방법에는 여러 종류가 있다.
https://atoz-developer.tistory.com/111
🟧Service & DTO
⏹️ BoardServiceImpl.java
@Override
public BoardResponseDTO boardDetail(Long id) {
Board board = boardRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("존재하지 않는 게시글입니다."));
BoardResponseDTO result = BoardResponseDTO.builder()
.board(board)
.build();
return result;
}
Service에서는 넘겨받은 id로 게시물을 찾은 뒤 Entity를 바로 넘겨주지 않기 위해 DTO에서 한번 빌드한 뒤
DTO 값을 넘겨준다.
⏹️ BoardResponseDTO.java
package com.practice.board.dto.board;
import com.practice.board.domain.Board;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Getter
@NoArgsConstructor
public class BoardResponseDTO {
private Long id;
private String title;
private String content;
private LocalDateTime createdAt;
private String username;
private String email;
@Builder
public BoardResponseDTO(Board board) {
this.id = board.getId();
this.title = board.getTitle();
this.content = board.getContent();
this.createdAt = board.getCreatedAt();
this.username = board.getMember().getUsername();
this.email = board.getMember().getEmail();
}
}
🟧수정, 삭제 권한 처리
게시물 상세 조회에서 중요한 점이 바로 게시물을 작성한 작성자만 수정 및 삭제를 할 수 있다는 점이다.
게시물 수정 쪽에서 한번 더 인증하겠지만 게시물의 작성자가 아니라면 수정과 삭제 버튼이 없어야
할 것이다.
⏹️ detail.html
<th:block th:if="${dto.getEmail() == #authentication.principal.username}">
<a th:href="@{/board/{id}/update(id=${id})}" class="btn btn-outline-warning">modify</a>
<a th:href="@{/board/{id}/remove(id=${id})}" class="btn btn-outline-danger" onclick="return confirm('삭제하시겠습니까?')">remove</a>
</th:block>
컨트롤러에서 넘겨 받은 이메일 정보와 authentication의 정보와 일치하는지를 확인 후
일치하는 유저에게만 수정과 삭제 버튼이 보이도록 처리했다.
🟧테스트
..../board/{id} 로 접속하였을 때
✅게시물 전체 조회
게시판 항목을 따로 만들고 홈 화면을 게시물 화면으로 만들었다.
🟧Controller
⏹️ GlobalController.java
/**
* Home 화면
* @return 홈 페이지
*/
@GetMapping("/")
public String Home(Model model) {
List<BoardResponseDTO> dto = boardService.boardList();
model.addAttribute("boardList", dto);
return "home";
}
원래 홈 컨트롤러는 페이지만 리턴해줬는데 boardList 정보를 넘겨주게 되었다.
🟧Service
⏹️ BoardServiceImpl.java
@Override
public List<BoardResponseDTO> boardList() {
List<Board> boards = boardRepository.findAll();
List<BoardResponseDTO> boardDTOs = new ArrayList<>();
for (Board board : boards) {
BoardResponseDTO result = BoardResponseDTO.builder()
.board(board)
.build();
boardDTOs.add(result);
}
return boardDTOs;
}
회원 목록을 조회하는 것과 마찬가지로 로직을 작성하였다.
🟧테스트
작성한 게시물이 정상적으로 홈 화면에 출력된다.
지난 포스팅에 Thymeleaf 공식 문서를 링크했었는데 그곳에서 List를 반복해서 가져오는
내용을 활용하면 된다.
✅끝
원래 수정, 삭제도 같이 포스팅하려고 했는데 글이 너무 길어질 것 같아서 2편으로 잘라서 올리면
좋을 것 같다.
https://github.com/Kimmingki/board
'Java > Spring Boot 게시판' 카테고리의 다른 글
spring boot 게시판 - 10 <JPA Pageable, thymeleaf> (0) | 2023.02.21 |
---|---|
spring boot 게시판 - 9 <게시물 수정, 삭제> (2) | 2022.11.30 |
spring boot 게시판 - 7 <회원 정보 수정 및 탈퇴> (2) | 2022.11.24 |
spring boot 게시판 - 6 <bootstrap 적용하기> (0) | 2022.11.22 |
spring boot 게시판 - 5 <thymeleaf layout 적용> (0) | 2022.11.21 |