[개발일지] 취미 커뮤니티 개발일지 (3) 자유게시판 글 CRUD + 페이징

zwon·2023년 10월 12일
0

개발일지

목록 보기
15/23

자유 게시판 기능부터 구현해보도록 하겠다.
상대적으로 ,, 간단해보인다,,,

우선 값 검증이나 이런것들은 한번에 하겠다.

참고로 제대로 동작하는지 위해 다음과 같이 임시 데이터를 넣어줬다.
(@PostConstruct 사용)

baseTimeEntity

@MappedSuperclass
@Getter
@EntityListeners(AuditingEntityListener.class)
public class BaseTimeEntity {

  @CreatedDate
  @Column(updatable = false)
  private LocalDateTime createdDate; // 등록일

  @LastModifiedDate
  private LocalDateTime lastModifiedDate; // 수정일

  @PrePersist
  public void prePersist() {
    LocalDateTime now = LocalDateTime.now();
    createdDate = now;
    lastModifiedDate = now;
  }
  @PreUpdate
  public void preUpdate(){
    LocalDateTime now = LocalDateTime.now();
    lastModifiedDate = now;
  }![](https://velog.velcdn.com/images/security-won/post/ffc89259-97f5-4f89-9789-e65f007cfa8f/image.gif)


}

User

@Entity @Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Table(name = "users")
public class User extends BaseTimeEntity {
  @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "user_id")
  private Long id;
  private String name; // 본명
  private String nickname; // 별명
  private String password;
  private String email;

  @Builder
  public User(String name, String nickname, String password, String email) {
    this.name = name;
    this.nickname = nickname;
    this.password = password;
    this.email = email;
  }

  public void update(UserUpdateRequestDto updateDto) {
    // 갑자기 궁금한게 회원정보를 닉네임만 변경하던가 비번만 변경할 수 있는데 이럴경우 업데이트 메서드를 따로 분리해야하나?
    this.nickname = updateDto.getNickname();
    this.password = updateDto.getPassword();
  }
}

board

  • 자유게시판 엔티티
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Board extends BaseTimeEntity {

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

  private String title;
  @Lob
  private String content;

  @ManyToOne(fetch = FetchType.EAGER)
  @JoinColumn(name = "user_id")
  private User user;

  public void setUser(User user){ 
    this.user = user;
  }

  public void update(BoardUpdateRequestDto request) {
    this.title = request.getTitle();
    this.content = request.getContent();
  }
}
  • User와 board는 일대다 관계.

boardRepository

@Repository
public interface BoardRepository extends JpaRepository<Board, Long> {

  Page<Board> findAll(Pageable pageable);
}

boardService

@Service
@RequiredArgsConstructor
public class BoardService {
  private final BoardRepository boardRepository;

  // 게시판 등록
  public Long save(BoardSaveRequestDto request, User user){
    Board board = request.toEntity();
    board.setUser(user);
    boardRepository.save(board);
    return board.getId();
  }
  // 게시판 조회 - 단건
  public BoardResponseDto findById(Long id){
    Board board = boardRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("존재하지 않는 포스트입니다."));
    return new BoardResponseDto(board);
  }
  // 게시판 조회 - 전체
  public List<BoardResponseDto> findAll() {
    List<BoardResponseDto> boards = boardRepository.findAll()
        .stream()
        .map(BoardResponseDto::new)
        .collect(Collectors.toList());
    return boards;
  }
  // 게시판 조회 - 전체, 페이징 적용
  public Page<BoardResponseDto> findAll(Pageable pageable) {
    Page<BoardResponseDto> boards = boardRepository.findAll(pageable).map(BoardResponseDto::new);
    return boards;
  }
  // 회원 삭제
  public void delete(Long id){
    boardRepository.deleteById(id);
  }

  // 게시판 수정
  @Transactional
  public void update(Long id, BoardUpdateRequestDto request){
    Board board = boardRepository.findById(id)
        .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 포스트입니다."));
    board.update(request);
  }
}

boardViewController

package com.jiwon.blog.web.controller.view;

import com.jiwon.blog.domain.user.User;
import com.jiwon.blog.repository.UserRepository;
import com.jiwon.blog.service.BoardService;
import com.jiwon.blog.web.dto.board.BoardResponseDto;
import com.jiwon.blog.web.dto.board.BoardSaveRequestDto;
import com.jiwon.blog.web.dto.board.BoardUpdateRequestDto;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpSession;
import java.util.List;

@Controller
@RequiredArgsConstructor
public class BoardViewController {

  private final BoardService boardService;

  // 글 등록 폼 보여주기
  @GetMapping("/board/form")
  public String boardWrite(Model model){
    model.addAttribute("boardSaveRequestDto", new BoardSaveRequestDto());
    return "board/form";
  }

  // 글 등록
  @PostMapping("/board/form")
  public String boardSave(@ModelAttribute BoardSaveRequestDto boardSaveRequestDto, HttpSession session){
    User loginUser = (User) session.getAttribute("loginUser");
    boardService.save(boardSaveRequestDto, loginUser);
    return  "redirect:/boards";
  }

  // 글 조회 - 단건 = 상세 조회
  @GetMapping("/boards/{id}")
  public String boards(@PathVariable Long id, Model model) {
    BoardResponseDto board = boardService.findById(id);
    model.addAttribute("board", board);
    return "board/detailBoard";

  }
  // 글 조회 - 전체 - 페이징
  @GetMapping("/boards")
  public String boards(Model model,
                       @PageableDefault(size = 5, sort = "createdDate",
                           direction = Sort.Direction.DESC) Pageable pageable) {
    Page<BoardResponseDto> boards = boardService.findAll(pageable);
    model.addAttribute("boards", boards);
    return "board/main";

  }
  // 글 삭제
  @DeleteMapping("/boards/{id}")
  public String delete(@PathVariable Long id){
    boardService.delete(id);
    return "redirect:/boards";
  }

  // 글 수정 폼
  @GetMapping("/boards/{id}/edit")
  public String updateForm(@PathVariable Long id, Model model){
    BoardResponseDto board = boardService.findById(id);
    BoardUpdateRequestDto boardUpdateRequestDto = new BoardUpdateRequestDto();
    boardUpdateRequestDto.setTitle(board.getTitle());
    boardUpdateRequestDto.setContent(board.getContent());

    model.addAttribute("boardUpdateRequestDto", new BoardUpdateRequestDto());
    return "board/modifyForm";
  }
  // 글 수정
  @PutMapping("/boards/{id}/edit")
  public String update(@PathVariable Long id,
                       @ModelAttribute BoardUpdateRequestDto boardUpdateRequestDto,
                       @RequestParam(defaultValue = "/") String redirectURL){
    boardService.update(id, boardUpdateRequestDto);
    return "redirect:/boards/"+id;
  }
}


  • CRUD 기능 구현, 임시지만 로그인 한 사용자가 글 작성시 글과 작성자가 제댈 매핑되는지 확인하기 위해 아주 간단한 로그인 로직을 구성했다.
  • 그리고 delete와 put 메서드르 사용하기 위해 application.yml에 다음과 같이 설정해줌으로써 put, delete 메서드를 form태그에서 사용할 수 있게되었다.
  • 참고로 th:method="delete", th:method="put"이라고 작성해야한다. th를 써주지 않으면 제대로 동작이 안한다.
spring:
 ... 
  mvc:
    hiddenmethod:
      filter:
        enabled: true
  • 아직은 단순히 CRUD 위주로 구현해서 디테일이 부족하다. 내가 쓴 글에만 삭제와 수정 버튼이 보이게하는지 등 이러한 디테일은 계속 개발을 하면서 수정해나갈 것이다.
  • 그리고 page 구현했따^^ sw 직무 역량 부트캠프를 수강하면서 페이징 구현을 하지 못했는데 공부하고 직접 구현해보니까 너무 뿌듯하다.
  • UI는 나중에....

짱구로 로그인한 후 테스트 시연이다. (맥북 영상녹화 시프트 + 커맨드 + 숫자 5)

디테일보단 우선 기능위주로,,, UI는 참참참^^

profile
Backend 관련 지식을 정리하는 Back과사전

0개의 댓글