스파르타 코딩클럽_ 내일 배움 캠프 Spring 트랙 6기
[프로젝트] 뉴스 피드 만들기
2023.06.30 ~ 2023.07.07
<프로젝트 정보>
개발도구 : IntelliJ
프로그래밍 언어 : Java
데이터베이스 : MySQL
프레임워크 : Spring
와이어프레임 : Figma
ERD 설계 : ERD Cloud
<프로젝트 내용>
지난 금요일에 정해진 내용을 바탕으로 각자 맡은 기능을 구현하기 시작했고, 내가 오늘 제작한 건 게시글 작성 API와 게시글 삭제 API를 구현했다.
깃허브가 슬슬 익숙해졌기 때문에 프로젝트 할 때는 깃허브를 필수적으로 사용하고 있는데 한 명의 레포지토리를 포크하는 방식이 아닌
팀 대시보드를 만들어 브랜치를 여러개 나누어 작업하는 방식을 오늘 처음 사용해봤다.
팀원 모두 필수 구현사항을 빠르게 완성했기 때문에 내일은 머지하고 새로운 기능을 구현해봐도 좋을 것 같다.
아래는 내가 오늘 완성한 코드다.
[Post]
package com.sparta.newspeed.entity;
import com.sparta.newspeed.dto.PostRequestDto;
import jakarta.persistence.*;
import lombok.*;
import java.time.LocalDateTime;
@Entity
@Getter
@Setter
@Table
@NoArgsConstructor
public class Post extends Timestamped{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
//PK값 자동 생성
@Column(name = "post_id")
private Long postId; // 게시글 고유 id
@Column (nullable = false, length = 500)
private String title; // 제목
@Column (nullable = false, length = 10)
private String author; // 작성자명
@Column (nullable = false, length = 1000)
private String contents; // 작성내용
//setAuthor
@ManyToOne
@JoinColumn(name = "user_id")
private User username;
public Post(String title, String author, String contents) {
this.title = title;
this.author = author;
this.contents = contents;
}
}
[PostController]
package com.sparta.newspeed.controller;
import com.sparta.newspeed.dto.PostRequestDto;
import com.sparta.newspeed.dto.PostResponseDto;
import com.sparta.newspeed.security.UserDetailsImpl;
import com.sparta.newspeed.service.PostService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class PostController {
private final PostService postService;
// 게시글 작성 API
@PostMapping("/posts")
public ResponseEntity<PostResponseDto> createdPost(@RequestBody PostRequestDto requestDto, @AuthenticationPrincipal UserDetailsImpl userDetails) {
PostResponseDto createdPost = postService.createdPost(requestDto, userDetails);
return ResponseEntity.status(HttpStatus.CREATED).body(createdPost);
}
// 선택한 게시글 삭제 API
@DeleteMapping("/posts/{id}")
public ResponseEntity<String> deletePost(@PathVariable Long id,@AuthenticationPrincipal UserDetailsImpl userDetails) {
String message = postService.deletePost(id, userDetails);
return ResponseEntity.ok(message);
}
}
[PostRepository]
package com.sparta.newspeed.repository;
import com.sparta.newspeed.entity.Post;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface PostRepository extends JpaRepository<Post, Long> {
List<Post> findAllByOrderByModifiedAtDesc(); //내림차순 정렬
}
[PostService]
package com.sparta.newspeed.service;
import com.sparta.newspeed.dto.PostRequestDto;
import com.sparta.newspeed.dto.PostResponseDto;
import com.sparta.newspeed.entity.Post;
import com.sparta.newspeed.entity.Timestamped;
import com.sparta.newspeed.entity.User;
import com.sparta.newspeed.jwt.JwtUtil;
import com.sparta.newspeed.repository.PostRepository;
import com.sparta.newspeed.security.UserDetailsImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;
@Service
@RequiredArgsConstructor //생성자 주입으로 데이터베이스에 대한 생성자를 생성하지 않아도 됨
public class PostService {
private final PostRepository postRepository;
private final JwtUtil jwtUtil;
//게시글 작성 API
@Transactional
public PostResponseDto createdPost(PostRequestDto requestDto, UserDetailsImpl userDetails){
// JWT 토큰 검증
if (!jwtUtil.validateToken(requestDto.getToken())) {
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "유효하지 않은 토큰입니다.");
}
// 사용자 인증
User currentUser = userDetails.getUser();
String username = jwtUtil.getUserInfoFromToken(requestDto.getToken()).getSubject();
if (!username.equals(currentUser.getUsername())) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "게시글 작성 권한이 없습니다.");
}
Post post = new Post(requestDto.getTitle(), currentUser.getUsername(), requestDto.getContents());
Post savedPost = postRepository.save(post);
return new PostResponseDto(savedPost.getPostId(), savedPost.getTitle(), savedPost.getAuthor(), savedPost.getContents(), savedPost.getCreatedAt());
}
//게시글 삭제 API
@Transactional
public String deletePost(Long id, UserDetailsImpl userDetails) {
Post post = postRepository.findById(id)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "게시글을 찾을 수 없습니다."));
User currentUser = userDetails.getUser();
if (!post.getAuthor().equals(currentUser.getUsername())) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "작성자만 게시글을 삭제할 수 있습니다.");
}
postRepository.delete(post);
return "게시글이 성공적으로 삭제되었습니다.";
}
}
[PostRequestDto]
package com.sparta.newspeed.dto;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
public class PostRequestDto {
private String token; // JWT 토큰 추가
private String title;
private String username;
private String contents;
public PostRequestDto(String title, String username, String contents) {
this.title = title;
this.username = username;
this.contents = contents;
}
public String getToken() {
return token;
}
}
[PostResponseDto]
package com.sparta.newspeed.dto;
import lombok.Getter;
import java.time.LocalDateTime;
@Getter
public class PostResponseDto { // 게시물 조회 요청에 대한 응답으로 사용
private Long postId;
private String title;
private String author;
private String contents;
private LocalDateTime createdAt;
// private LocalDateTime modifiedAt; 수정시간 - 상인님 코드
public PostResponseDto(Long postId, String title, String author, String contents, LocalDateTime createdAt) {
this.postId = this.postId;
this.title = this.title;
this.author = this.author;
this.contents = this.contents;
this.createdAt = this.createdAt;
// this.modifiedAt = modifiedAt;
}
}
'🏕️내일배움캠프 > 📂뉴스 피드 프로젝트(23.06.30)' 카테고리의 다른 글
뉴스 피드 프로젝트 6일차_코드 발표 및 회고 (0) | 2023.07.07 |
---|---|
뉴스 피드 프로젝트 5일차_ERD, API 수정, 코드 리뷰 및 발표 준비 (0) | 2023.07.07 |
뉴스 피드 프로젝트 4일차_추가 기능 구현 (0) | 2023.07.05 |
뉴스 피드 프로젝트 3일차_필수 구현 기능 코드 테스트 및 추가 기능 구현 시작 (0) | 2023.07.05 |
뉴스 피드 프로젝트 1일차_S.A와 와이어프레임 제작,ERD 설계, API 명세 작성 (0) | 2023.07.03 |