[portfolio] 블로그 프로젝트 - (1) - CRUD
1. 주특기 주차 복습 하며 포트 폴리오 준비
1주차의 crud 구현부터 해서 보강해가며 더 많은 기능을 구현할 생각입니다.
원래 항해 일정이 있기 때문에 천천히 포스팅할 예정이며 한 번 열심히 만들어보겠습니다.
아쉽게도 프론트는.... 항해에서 제공해준 프론트에 제가 추가할 수 있는 부분은 추가할 예정입니다.
제가 만들 프로젝트는 블로그 프로젝트 입니다. 이 주제를 선택한 이유는 다른 주제 블로그 포스팅을 1년 정도 해왔고 그만큼 접한 기능과 필요하다 생각한 기능이 많았기 때문입니다. 먼저 제가 구현할 패턴에 대해 소개하면
이는 MVC패턴이라고 하며 밑에 링크로 볼 수 있습니다.
2023.06.28 - [항해99] - [항해99 TIL] MVC, DTO, IOC
말그대로 M(model), V(view), C(controller)입니다.
1) CRUD구현
먼저 CRUD가 무엇인지 정리하면
여기서 확인 하시면 됩니다.
2023.07.20 - [Java/SpringBoot] - [Java SpringBoot] CRUD
2) entity 생성 (Post)
CRUD를 구현하기 위해서 먼저 엔티티 클래스를 만들겠습니다.
엔티티를 이해하기 위해서는 영속성 컨텍스트를 알면 좋지만 일단 데이터 베이스 테이블에 대응하는 클래스라고 생각하시면 됩니다. 먼저 저희는 포스팅만 구현하기 때문에 Post
클래스를 만들겠습니다.
@Entity //JPA를 사용해서 엔티티를 정의
@Getter //Lombok의 에너테이션 getter메서드를 자동 생성
@Setter //setter 메서드 자동 생성
@Table(name = "postprac") //JPA @로서 엔티티 클래스가 매핑할 데이터 베이스 이름이 "postprac"
@NoArgsConstructor //Lombok 기본생성자 자동 생성
public class Post {
@Id //Primary Key
//Primary Key 생성 전략 :
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name="title", nullable = false) //칼럼이 title, null허용X
private String title;
@Column(name = "content", nullable = false) //칼럼이 content, null허용X
private String content;
// PostRequestDto를 인자로 받는 생성자. 이를 통해 DTO의 데이터 엔티티 객체에 채움
// 사실 추후에 추가해야 하는데 나중에 설명하겠습니다.
public Post(PostRequestDto requestDto) {
this.content=requestDto.getContent();
this.title=requestDto.getTitle();
}
}
import는 먼저 제거했습니다. 추후 Lombok이나 gradle에 관련해서도 설명하겠습니다.
이렇게 Post
클래스를 만듦으로서 데이터베이스와 상응할 수 있도록 하겠습니다. 설명은 주석으로 달겠습니다.
저희 항해 기술 매니저님이 @GeneratedValue(strategy = GenerationType.IDENTITY)
에 대해 한 번 다시 보라고 하셔서 설명 해보겠습니다.
<@GeneratedValue(strategy = GenerationType.IDENTITY)
>
GenerationType.IDENTITY
는 데이터베이스의 자동 증가(auto-increment) 기능을 사용하여 기본 키를 생성하는 방식입니다.
자세한 내용은 밑에 링크를 보시면 됩니다.
2023.07.20 - [Java/SpringBoot] - [Java Spring] @GeneratedValue(strategy = )
3) Contorller
@Slf4j //로그 남기기 위한 주석 (아직 추가x)
@RestController //RESTful 웹 서비스 컨트롤러라고 명시 @ResponseBody와 @Controller 합체본
@RequestMapping("/api") //공통적으로 적용될 url로 매핑
public class PostController {
private final PostService postService; //final인 이유는 변경하지 않아야 하고 스레드의 안정성을 위해.
public PostController(PostService postService) { //기본 생성자
this.postService = postService;
}
@PostMapping("/post")
//PostResponseDto의 객체를 요청 본문으로 받아 게시물 생성
public PostResponseDto createPost(@RequestBody PostRequestDto requestDto) {
return postService.createPost(requestDto);
}
}
여기서 controller를 만들어 클라이언트와의 응답을 관리합니다.
여기서 @RestController는 메서드의 반환값이 자동으로 JSON이나 XML 형식으로 변환되어 HTTP 응답 본문에 담기게 됩니다.
RUD도 마찬가지입니다. 나중에 추가하겠습니다.
4) repository 추가
public interface PostRepository extends JpaRepository<Post, Long> {
}
// extends 키워드를 사용하여 JpaRepository 인터페이스를 상속합니다.
// JpaRepository는 JPA를 쉽게 사용하기 위한 스프링 데이터 인터페이스로,
// <엔티티 타입, 엔티티의 ID 타입>을 제네릭으로 받습니다.
// 이를 통해 CRUD 연산과 같은 기본적인 데이터베이스 작업을 수행하는 메소드를 사용할 수 있습니다.
인터페이스로 생성하며 인스턴스를 생성 불가능합니다. 대신 인터페이스를 사용할 service에서 인스턴스를 생성합니다.
5) Mysql 연결
이렇게 데이터 베이스를 mysql로 연결하시면 됩니다.
이는 밑에 링크로 보시면 될 것 같습니다.
2023.07.20 - [mysql] - [mysql] 데이터 베이스 생성 방법 - 콘솔
6) Service
@Service
public class PostService {
private final PostRepository postRepository;
// 생성자 생성
public PostService(PostRepository postRepository) {
this.postRepository = postRepository;
}
//생성 service 메서드
public PostResponseDto createPost(@RequestBody PostRequestDto requestDto) {
//PostRequestDto 객체를 이용하여 Post 객체를 생성
// Post 클래스가 PostRequestDto 객체를 받아서 필요한 정보를 추출합니다.
Post post = new Post(requestDto);
//데이터 베이스에 저장
Post savePost= postRepository.save(post);
//저장된 Post 객체를 이용하여 PostResponseDto 객체 생성
PostResponseDto postResponseDto = new PostResponseDto(savePost);
return postResponseDto;
}
}
여기서
@RequestBody
는 클라이언트의 HTTP 요청의 본문(body) 부분을 자바 객체로 변환해주는 역할을 하는 Spring MVC 어노테이션입니다.
이렇게 MVC 패턴으로 CRUD의 C까지 만들었습니다. CRUD도 마찬가지이기 때문에 전 코드 올려보겠습니다.
2. controller과 service 코드
1) controller
@Slf4j
@RestController
@RequestMapping("/api")
public class PostController {
private final PostService postService;
public PostController(PostService postService) {
this.postService = postService;
}
@PostMapping("/post")
public PostResponseDto createPost(@RequestBody PostRequestDto requestDto) {
return postService.createPost(requestDto);
}
@GetMapping("/post")
public PostListResponseDto getPosts() {
return postService.getPosts();
}
@GetMapping("/post/{id}")
public PostResponseDto getPosts(@PathVariable Long id){
return postService.getPostById(id);
}
@PutMapping("/post/{id}")
public PostResponseDto updatePost(@PathVariable Long id, @RequestBody PostRequestDto requestDto){
return postService.updatePost(id, requestDto);
}
@DeleteMapping("/post/{id}")
public PostResponseDto deletePost(@PathVariable Long id){
return postService.deltetPost(id);
}
}
2) service
@Service
public class PostService {
private final PostRepository postRepository;
private final UserRepository userRepository;
public PostService(PostRepository postRepository, UserRepository userRepository) {
this.postRepository = postRepository;
this.userRepository = userRepository;
}
//게시글 작성
public PostResponseDto createPost(@RequestBody PostRequestDto requestDto) {
Post post = new Post(requestDto);
Post savePost= postRepository.save(post);
PostResponseDto postResponseDto = new PostResponseDto(savePost);
return postResponseDto;
}
//게시글 전체 조회
public PostListResponseDto getPosts() {
List<PostResponseDto> postResponseDtoList = postRepository.findAllByOrderByIdDesc()
.stream().map((PostResponseDto::new)).toList();
return new PostListResponseDto(postResponseDtoList);
}
//특정 게시글 조회
public PostResponseDto getPostById(Long id){
Post post = postRepository.findById(id).orElseThrow(()->new IllegalArgumentException("게시글이 존재하지 않습니다."));
return new PostResponseDto(post);
}
//수정
@Transactional
public PostResponseDto updatePost(Long id, PostRequestDto requestDto) {
Post post = postRepository.findById(id).orElseThrow(()->
new IllegalArgumentException("게시글이 존재하지 않습니다."));
post.update(requestDto);
return new PostResponseDto(post);
}
public PostResponseDto deltetPost(Long id) {
Post post = postRepository.findById(id).orElseThrow(()->new IllegalArgumentException("게시글이 존재하지 않습니다."));
postRepository.delete(post);
return new PostResponseDto(post);
}
}
3) repository
public interface PostRepository extends JpaRepository<Post, Long> {
List<Post> findAllByOrderByIdDesc();
}
4) entity
@Entity
@Getter
@Setter
@Table(name = "postprac")
@NoArgsConstructor
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name="title", nullable = false)
private String title;
@Column(name = "content", nullable = false)
private String content;
public Post(PostRequestDto requestDto) {
this.content=requestDto.getContent();
this.title=requestDto.getTitle();
}
public void update(PostRequestDto requestDto){
this.title=requestDto.getTitle();
this.content=requestDto.getContent();
}
}