자유 게시판 기능부터 구현해보도록 하겠다.
상대적으로 ,, 간단해보인다,,,
우선 값 검증이나 이런것들은 한번에 하겠다.
참고로 제대로 동작하는지 위해 다음과 같이 임시 데이터를 넣어줬다.
(@PostConstruct 사용)
@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)
}
@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();
}
}
@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();
}
}
@Repository
public interface BoardRepository extends JpaRepository<Board, Long> {
Page<Board> findAll(Pageable pageable);
}
@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);
}
}
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;
}
}
spring:
...
mvc:
hiddenmethod:
filter:
enabled: true
짱구로 로그인한 후 테스트 시연이다. (맥북 영상녹화 시프트 + 커맨드 + 숫자 5)
디테일보단 우선 기능위주로,,, UI는 참참참^^