Spring Boot 2.7.5
Java 17
MySQL 8.0
프로젝트 구조
-- controller
⌞ PostController.java
-- domain
⌞ Post.java
-- dto
- request
⌞ PostRequestDto.java
- response
⌞ PostResponseDto.java
-- repository
⌞ PostRepository.java
-- service
⌞ PostService.java
post 테이블의 컬럼을 추가합니다.
dto에서 builder를 사용하기 위해 builder 추가하였습니다.
builder 추가 시 @NoArgsConstructor @AllArgsConstructor 필요
@Getter
@Setter
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Post extends BaseTimeEntity {
@Id
@GeneratedValue
@Column(name = "post_id")
private Integer id;
@ManyToOne
@JoinColumn(name="member_id", nullable = false, updatable = false)
private Member member;
@Column(columnDefinition = "TEXT")
private String content;
}
public interface PostRepository extends JpaRepository<Post, Integer> {
}
게시글 쓰기를 위해 PostRequestDto.java를 작성합니다.
@NoArgsConstructor
@Getter
@Setter
@ToString
public class PostRequestDto {
private String content;
private Member member;
@Builder
public PostRequestDto(String content, Member member) {
this.content = content;
this.member = member;
}
public Post toEntity() {
return Post.builder()
.content(content)
.member(member)
.build();
}
}
프론트에서 요청이 왔을 때 처리할 기능을 controller에 작성합니다.
저번 시간에 만든 SecurityUser를 이용하여 게시글을 작성한 Member를 저장합니다.
@RequiredArgsConstructor
@RestController
@RequestMapping("/api/post")
public class PostController {
private final PostService postService;
@PostMapping(value = "/create")
public String create(@RequestBody PostRequestDto requestDto, @AuthenticationPrincipal SecurityUser principal) {
// 프론트에서 받은 토큰으로 Member 구분함
requestDto.setMember(principal.getMember());
Post post = postService.save(requestDto);
return "success";
}
}
@RequiredArgsConstructor
@Service
public class PostService {
private final PostRepository postRepository;
// create
@Transactional
public Post save(PostRequestDto requestDto) {
return postRepository.save(requestDto.toEntity());
}
}
Headers에 access token 을 넣어주고
Body에 데이터를 작성해주면 게시글 쓰기가 완료됩니다.
@Getter
@ToString
public class PostResponseDto {
private Integer id;
private String content;
private String nickname;
private String profilePath;
private String createdAt;
public PostResponseDto(Post entity) {
this.id = entity.getId();
this.nickname = entity.getMember().getNickname();
this.profilePath = entity.getMember().getProfilePath();
this.content = entity.getContent();
this.createdAt = entity.getCreated_at().format(DateTimeFormatter.ofPattern("yyyy.MM.dd"));
}
}
글을 작성한 유저의 모든 정보가 필요하지는 않기 때문에 닉네임만 보여주기 위해서 entity.getMember().getNickname(); 작성하였습니다.
작성일을 yyyy.MM.dd 로 표현하기 위해 format(DateTimeFormatter.ofPattern("yyyy.MM.dd")); 작성하였습니다.
public List<PostResponseDto> list(Member member, String nickname) {
List<Post> posts = postRepository.findAll();
List<PostResponseDto> postList = new ArrayList<>();
for (Post post : posts) {
PostResponseDto postResponseDto = new PostResponseDto(post);
postList.add(postResponseDto);
}
return postList;
}
프론트에 보여줄 내용만 PostResponseDto 에 정리했으므로 PostService 에서 ArrayList를 만들어 담아줍니다. 다음에 postList에 댓글 수, 좋아요 수를 담을 예정입니다.
public class PostController {
private final PostService postService;
@GetMapping()
public List<PostResponseDto> list(@AuthenticationPrincipal SecurityUser principal ,@RequestParam(value = "nickname", required=false) String nickname) {
return postService.list(principal.getMember(), nickname);
}
}
PostController 에서 PostService로 보내줍니다.
게시글 리스트와 게시글 상세 조회를 했을 때 보여지는 데이터가 같다면 위에서 사용했던 PostResponseDto를 사용하고 다르다면 새로 만들어줍니다.
현재는 동일한 데이터를 보여줄 것이므로 PostResponseDto를 사용하겠습니다.
(다음에 댓글 목록을 추가하여 보여줄 때는 분리할 예정)
@RequiredArgsConstructor
@Service
public class PostService {
public PostDetailResponseDto find(Member member, Integer id) {
Post post = postRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("해당 게시글이 없습니다."));
PostDetailResponseDto postDetailResponseDto = new PostDetailResponseDto(post);
}
}
@RequiredArgsConstructor
@RestController
@RequestMapping("/api/post")
public class PostController {
@GetMapping("/{id}")
public PostDetailResponseDto get(@AuthenticationPrincipal SecurityUser principal, @PathVariable Integer id) {
return postService.find(principal.getMember(), id);
}
}
게시글을 수정하기 위해 domain/Post.java에 아래의 코드를 추가합니다.
public class Post extends BaseTimeEntity {
... (생략)
public void update(String content) {
this.content = content;
}
}
수정할 때 content만 수정 가능하도록 할 것이기 때문에 content만 추가하였습니다.
public class PostService {
@Transactional
public String update(Integer id, PostRequestDto requestDto) {
String message = "fail";
Post post = postRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("해당 게시글이 없습니다."));
// 작성자만 수정 가능
if (postRepository.findById(id).get().getMember().getId().equals(requestDto.getMember().getId())) {
post.update(requestDto.getContent());
message = "success";
}
return message;
}
}
public class PostController {
@PutMapping("{id}/update")
public String update(@PathVariable Integer id, @RequestBody PostRequestDto requestDto, @AuthenticationPrincipal SecurityUser principal) {
requestDto.setMember(principal.getMember());
return postService.update(id, requestDto);
}
}
public class PostService {
@Transactional
public String delete(Integer id, Member member) {
String message = "fail";
Post post = postRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("해당 게시글이 없습니다."));
if (post.getMember().getId().equals(member.getId())) { // 작성자만 삭제 가능
postRepository.delete(post);
message = "success";
}
return message;
}
}
public class PostController {
public String delete(@PathVariable Integer id, @AuthenticationPrincipal SecurityUser principal) {
return postService.delete(id, principal.getMember());
}
}