게시판 CRUD 만들기
JPA
- 반복적인 CRUD SQL을 처리해준다.
- SQL이 아닌 객체중심의 개발이 가능하도록 해준다.
//의존성 등록
dependecies{
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
}
CRUD작성
- 게시물 Entity
- 실제 DB의 테이블과 매칭될 클래스이며 보통 Entity클래스라 부름 , JPA를 사용하면 DB데이터에 작업할 경우 실제 데이터보다는 Entity클래스의 수정을 통해 작업한다.
@Getter //Entity클래스는 DB와 맞닿아있는 중요한 클래스이기때문에 Setter 절대 사용하지 않기
@NoArgsConstructor
@Entity
public class Posts extends BaseTimeEntity {
@Id //해당 테이블의 PK필드
@GeneratedValue(strategy = GenerationType.IDENTITY) //PK의 생성규칙 현재 auto_increment
private Long id;
@Column(length = 500, nullable = false) //굳이 나타내지 않아도 디폴트로 칼럼으로 인식 , 변경이 필요할때 보통 선언
private String title;
@Column(columnDefinition = "TEXT", nullable = false)
private String content;
private String author;
@Builder
public Posts(String title,String content,String author){
this.title = title;
this.content = content;
this.author = author;
}
}
JPA 생성
- Post클래스로 DB에 접근하게해줄 PostsRepository
- JpaRepository<Entity클래스, PK타입>을 상속하면 기본적인 CRUD메서드 자동생성
@Repository
public interface PostsRepository extends JpaRepository<Posts, Long> {}
웹계층
Web Layer
- 흔히 @Controller와 같은 뷰와 관련된 영역
Service Layer
@Service , @Transaction 을 사용
- 트랜잭션을 처리하는 영역
- 비즈니스 로직이 실행되는 영역보다는 도메인에서 각 객체들의 비지니스 로직을 실행시키고, 순서보장하는 , 조합하는 영역
Repository Layer
@Repository 사용
- DB에 접근하는 영역(DAO의 역할이라 생각)
DTOs
- 계층간의 데이터 교환 또는 뷰 템플릿에 데이터를 넘겨줄때 사용하는 객체
- 실제 DB를 갖다 쓰기는 부담이 되기에 사용
Domain Model
- 실제 비즈니스 로직이 실행되는 영역
- @Entity가 사용된 영역 역시 도메인 모델이라고 이해하면 된다
- 택시앱으로 따지면 탑습 , 요금 , 배차 등등 각각이 도메인 객체라 볼수 있다.
코드
Web Layer
IndexController
@RequiredArgsConstructor
@Controller
public class IndexController {
private final PostsService postsService;
@GetMapping("/")
public String index(Model model){
model.addAttribute("posts", postsService.findAllDesc());
return "index";
}
@GetMapping("/posts/save")
public String postsSave(){
return "posts-save";
}
@GetMapping("/posts/update/{id}")
public String postsUpdate(@PathVariable Long id,Model model){
PostsResponseDto dto = postsService.findById(id);
model.addAttribute("post", dto);
return "posts-update";
}
}
PostsApiController
@RequiredArgsConstructor
@RestController
public class PostsApiController {
private final PostsService postsService;
@PostMapping("/api/v1/posts")
public Long save(@RequestBody PostsSaveRequestDto requestDto){
return postsService.save(requestDto);
}
@PutMapping("/api/v1/posts/{id}")
public Long update(@PathVariable Long id,@RequestBody PostsUpdateRequestDto requestDto){
return postsService.update(id, requestDto);
}
@GetMapping("/api/v1/posts/{id}")
public PostsResponseDto findById(@PathVariable Long id){
return postsService.findById(id);
}
@DeleteMapping("/api/v1/posts/{id}")
public Long delete(@PathVariable Long id){
postsService.delete(id);
return id;
}
}
Service Layer
PostsService
@RequiredArgsConstructor
@Service
public class PostsService {
private final PostsRepository postsRepository;
@Transactional
public Long save(PostsSaveRequestDto requestDto) {
return postsRepository.save(requestDto.toEntity()).getId();
}
@Transactional
public Long update(Long id, PostsUpdateRequestDto requestDto) {
Posts posts = postsRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("해당 게시글이 없습니다. id=" + id));
posts.update(requestDto.getTitle(), requestDto.getContent());
return id;
}
@Transactional
public PostsResponseDto findById(Long id){
Posts entity = postsRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("해당 게시글이 없습니다. id = " + id));
return new PostsResponseDto(entity);
}
@Transactional(readOnly = true)
public List<PostsListResponseDto> findAllDesc(){
return postsRepository.findAllDesc().stream()
.map(PostsListResponseDto::new)
.collect(Collectors.toList());
}
@Transactional
public void delete(Long id){
Posts posts = postsRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("해당 게시글이 없습니다. id=" + id));
postsRepository.delete(posts);
}
}
Dtos
PostsListResponseDto
@Getter
public class PostsListResponseDto {
private Long id;
private String title;
private String author;
private LocalDateTime modifiedDate;
public PostsListResponseDto(Posts entity){
this.id = entity.getId();
this.title = entity.getTitle();
this.author = entity.getAuthor();
this.modifiedDate = entity.getModifiedDate();
}
}
PostsResponseDto
@Getter
public class PostsResponseDto {
private Long id;
private String title;
private String content;
private String author;
public PostsResponseDto(Posts entity){
this.id = entity.getId();
this.title= entity.getTitle();
this.content= entity.getContent();
this.author = entity.getAuthor();
}
}
PostsSaveRequestDto
@Getter
@NoArgsConstructor
public class PostsSaveRequestDto {
private String title;
private String content;
private String author;
@Builder
public PostsSaveRequestDto(String title,String content,String author){
this.title = title;
this.content = content;
this.author = author;
}
public Posts toEntity() {
return Posts.builder()
.author(author)
.title(title)
.content(content)
.build();
}
}
PostsUpdateRequestDto
@Getter
public class PostsUpdateRequestDto {
private String title;
private String content;
@Builder
public PostsUpdateRequestDto(String title,String content){
this.content = content;
this.title = title;
}
}
참고 교재
728x90
'Spring' 카테고리의 다른 글
[스프링 MVC 1편] - 서블릿 (0) | 2023.01.02 |
---|---|
[스프링 MVC 1편] - 웹 애플리케이션 이해 (1) | 2022.12.31 |
JPA Auditing기능이란? (0) | 2022.12.29 |
스프링 핵심 원리[기본편] - 의존관계 자동 주입 (0) | 2022.12.28 |
스프링 핵심 원리[기본편] - 컴포넌트 스캔 (0) | 2022.12.27 |