SpringBoot와 JPA를 사용하여 게시판을 구현하는 WAS 단 로직을 포스팅하려 합니다. 기본 프로젝트 설정과 데이터베이스 연결 및 View단은 생략할 예정입니다. Gradle 빌드나 프로젝트 구조는 깃허브 Bincolog를 참고하시면 됩니다. 개인적인 공부로 코드의 결함이 있을 수 있으니 참고만 해주세요 :)
Entity 생성📗
처음으로는 Entity를 생성합니다. Entity 클래스는 실제 DB 테이블과 매핑되는 핵심 클래스로, 데이터베이스의 테이블에 존재하는 컬럼들을 필드로 가지는 객체입니다. Entity는 데이터베이스 영속성의 목적으로 사용되기 때문에, 요청이나 응답 값을 전달하는 클래스로 사용하는 것은 좋지 않습니다.
또한, 많은 비즈니스 로직들이 Entity를 기준으로 동작하기 때문에 추후에 Entity를 변경하면 다른 여러 클래스에 영향을 줄 수 있습니다. 따라서 실제 DB와 연관 있는 Entity와 요청 값인 Request, 응답 값인 Response 클래스들은 각각 분리되어야 합니다.
@Getter
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
public String title;
@Lob
public String content;
@Builder
public Post(String title, String content) {
this.title = title;
this.content = content;
}
}
Entity 클래스에서는 Setter 메서드를 지양해야 합니다. 변경되지 않는 인스턴스에 대해서도 setter로 접근이 가능하기 때문에 객체의 일관성, 안전성을 보장하기 힘들어지기 때문입니다.
📌Entity 클래스에는 setter 대신 생성자 또는 Builder를 사용해야 합니다.
🔍각 어노테이션 설명
- @Getter : 말 그대로 각각의 컬럼에 getter를 자동 생성해주는 롬복 라이브러리의 기능입니다.
- @Entity : JPA를 사용해서 DB 테이블과 매핑할 클래스는 @Entity를 꼭 붙여줘야 합니다.
- @NoArgsConstructor : 매개변수가 없는 기본 생성자를 만들어주는 어노테이션입니다. 기본 생성자의 접근 제어를 PROTECTED로 설정해 놓으면 무분별한 객체 생성에 대해 한번 더 체크할 수 있습니다.
- @Id : 테이블 상의 PK(Primary Key)를 지정해 줍니다.
- @GeneratedValue - IDENTITY : 기본키 생성을 데이터베이스에게 위임하는 방식으로 id값을 따로 할당하지 않아도 데이터베이스가 자동으로 AUTO_INCREMENT를 하여 기본키를 생성해줍니다.
- @Lob : Large Object로 이름에 걸맞게 저장할 수 있는 데이터의 양이 4기가로 대용량입니다.
- @Builder : 앞서 말씀드린 것처럼 Setter 대신 사용하는 디자인 패턴입니다. 사용법은 밑에서 자세히 다뤄보겠습니다.
Create - DTO 생성📘
앞서 말씀드린 것처럼 Entity 클래스와 Request 즉 DTO 클래스는 분리되어야 합니다. 게시글 작성 용으로만 사용되는 PostCreate 클래스를 생성합니다.
@ToString
@Setter
@Getter
public class PostCreate {
@NotBlank(message = "제목을 입력해주세요.")
private String title;
@NotBlank(message = "내용을 입력해주세요.")
private String content;
@Builder
public PostCreate(String title, String content) {
this.title = title;
this.content = content;
}
}
🔍각 어노테이션 설명
- @ToString : toString() 메서드를 작성해주는 Lombok의 편리 기능입니다.
- @NotBlank : Null 값과 빈 값, " "을 체크해주는 어노테이션입니다. @NotEmpty와의 차이점은 @NotBlank는 스페이스바까지 체크해줍니다.
여기서 주의할 점은 @NotBlank를 선언만 해준다고 Null 값과 빈 값을 체크해주는 것은 아닙니다. 해당 DTO(PostCreate)를 받는 Request 부분에 @Valid 어노테이션을 추가해줘야 기능이 동작합니다. 사용법은 아래 Controller 부분에 있습니다.
Controller 생성📙
Controller 클래스는 생각보다 간단합니다. 클라이언트 단에서 넘어온 데이터를 이전에 만든 postCreate(DTO)로 받아서 그대로 Service단에 넘겨주면 됩니다. Controller에는 대게 로직을 구현하지 않고, Service 단에서 비즈니스 로직을 구현합니다.
@Slf4j
@RestController
@RequiredArgsConstructor
public class PostController {
private final PostService postService;
@PostMapping("/posts")
public void post(@RequestBody @Valid PostCreate postCreate){
postService.write(postCreate);
}
}
데이터를 저장하는 경우에는 PostMapping을 사용합니다. 외부적으로 데이터를 드러나지 않게 하고 데이터의 길이 제한이 없기 때문입니다. 하지만 암호화 작업이 없다면 body의 데이터도 결국 볼 수 있는 건 똑같습니다. 그래서 유저의 정보 같은 경우에는 암호화 작업을 하지만 지금처럼 게시판 같은 경우에는 암호화의 필요성까지는 없어서 구현하지 않았습니다.
지금 포스팅을 따라서 구현하시는 분들은 postService에서 오류가 발생할 것입니다. 아직 Service 클래스를 구현하지 않았기 때문입니다. 잠시 주석처리를 하고 하단에서 Service 클래스를 구현하고 난 뒤에 주석을 푸시면 될 것 같네요😄
🔍각 어노테이션 설명
- @Slf4j : 로그를 남기는 방식 중 logger 클래스를 사용할 수 있게 해주는 어노테이션입니다.
- @RestController : @Controller에 @ResponseBody가 추가된 것으로, Json 형태로 객체 데이터를 반환할 수 있습니다.
- @RequiredArgsConstructor : DI(의존성 주입) 중 Constructor Injection(생성자 주입)을 임의의 코드 없이 자동으로 설정해주는 어노테이션입니다.
- @PostMapping : post 방식으로 넘어오는 url을 받는 어노테이션입니다.
- @RequestBody : Json 형식으로 본문에 담긴 값들을 받아들이는 어노테이션입니다.
- @Valid : PostCreate(DTO)에서 설정한 @NotBlank와 같은 유효성 검사들을 해주는 어노테이션입니다.
Repository 생성📔
SpringBoot에서는 Entity의 기본적인 CRUD가 가능하도록 JpaRepository 인터페이스를 제공합니다. Spring Data JPA에서 제공하는 JpaRepository 인터페이스를 상속하기만 해도 되며, 따로 인터페이스에 @Repository 등의 어노테이션을 추가할 필요는 없습니다.
JpaRepository를 상속받을 때는 사용될 Entity 클래스와 ID 값이 들어가는 JpaRepository <T, ID> 형태로 작성합니다. 단순 상속하는 것만으로도 아래와 같은 기능을 제공합니다.
Method | 기능 |
save() | 레코드 저장 (insert, update) |
findOne() | primary key로 레코드 한 건 찾기 |
findAll() | 전체 레코드 불러오기, 정렬, 페이징 기능 |
count() | 레코드 갯수 |
delete() | 레코드 삭제 |
public interface PostRepository extends JpaRepository<Post, Long> {
}
T에는 이전에 작성한 Entity 클래스인 Post를 넣어주고, ID는 Long 타입으로 선언하였습니다.
Service 생성📒
앞서 언급한 것처럼 비즈니스 로직은 Service 클래스에서 구현해야 합니다. Service 클래스에서는 위에서 구현한 Repository를 이용하여 로직을 구현합니다.
@Slf4j
@Service
@RequiredArgsConstructor
public class PostService {
private final PostRepository postRepository;
public void write(PostCreate postCreate){
Post post = Post.builder()
.title(postCreate.getTitle())
.content(postCreate.getContent())
.build();
postRepository.save(post);
}
}
write 메서드(게시판 작성)는 Controller 클래스에서 넘겨주는 PostCreate(DTO)를 넘겨받아 Post(Entity) 형식으로 만들어 주기 위해 이전에 언급했던 Builder 패턴을 사용합니다. 사용법은 위 코드와 같이 build 해준 후 save 메서드를 이용하여 데이터를 저장합니다.
🔍각 어노테이션 설명
- @Service : Service 클래스임을 명시하는 어노테이션입니다.
👨👩👦👦 오픈채팅방 운영
취업을 준비하는 예비 개발자분들을 위한 질문&답변할 수 있는 공간을 만들었습니다. 취업과 이직을 하기 위해서 어떤 걸 중점적으로 준비해야 하는지부터 포트폴리오&이력서 작성법 등 다양한 질문들을 받고 답변을 드립니다. 참여하셔서 다양한 정보 얻고 가시면 좋을 것 같네요😁
참여코드 : 456456
https://open.kakao.com/o/gVHZP8dg
👨💻 전자책 출간
아울러 제가 🌟비전공자에서 2년만에 보안 전문 중견기업으로 이직 한 방법들을 정리한 전자책을 출간 하게 되었습니다. 어떤 걸 공부해야 하는지, 이직을 위해서 무엇을 준비해야 하는지, 제가 받았던 기술 면접 리스트 등 다양한 목차로 구성되어 있습니다. 또한, 구매 시 1:1 채팅을 이용하여 포트폴리오 첨삭을 도와드리고 있습니다. 🐕전자책으로 얻은 모든 수익은 유기견 센터 '팅*벨 입양센터'에 후원될 예정입니다. 관심 있으신 분들은 아래 링크를 참고해주세요😁
마치며
지금까지 Entity, DTO, Controller, Repository, Service 클래스를 구현했습니다. 이제는 이 코드들이 문제가 없는지 테스트 케이스를 구현해야 합니다. 사실 테스트 케이스 먼저 구현하고 클래스를 구현하는 게 순서 상 맞지만 포스팅 편의를 위해서 순서를 바꿨습니다.
다음 포스팅은 오늘 구현한 게시판 작성 Controller와 Service 클래스의 테스트 케이스를 작성하는 포스팅을 하려 합니다. 아래 하단에 링크 누르셔서 코드 참고하시면 좋을 것 같네요! 많이 부족하지만 혹여나 궁금한 점은 댓글 남겨주시면 열심히 답변 달아볼게요😄
다음 포스팅
* [ SpringBoot JPA 게시판 CRUD(Create-TDD) ]
* [ SpringBoot JPA 게시판 CRUD(단건 조회 및 TDD) ]
* [ SpringBoot JPA 게시판 CRUD(Read - 다중 조회/페이징 처리/TDD) ]
* [ SpringBoot JPA 게시판 CRUD(Update-TDD) ]
'JPA' 카테고리의 다른 글
SpringBoot JPA 게시판 CRUD 구현(Delete-TDD) (0) | 2022.07.25 |
---|---|
SpringBoot JPA 게시판 CRUD 구현(Update-게시글 수정) (0) | 2022.07.21 |
SpringBoot JPA 게시판 CRUD 구현(다중 조회/ Paging / TDD) (0) | 2022.07.21 |
SpringBoot JPA 게시판 CRUD 구현(Read 단건 조회 및 TDD) (0) | 2022.07.20 |
SpringBoot JPA 게시판 CRUD 구현(Create - TDD) (0) | 2022.07.18 |