Spring_Week3

Spring_Week3

데이터베이스 사용법(JPA) 예외처리

데이터 영속화하기

ORM(Object Relation Mapping)이란? Database에 있는 Relation과 java에 있는 객체들을 Mapping한다는 의미 Native Query를 작성하지 않고도 영속화가 가능 벤더에 독립적이게 영속화 가능

H2 Database 메모리 데이터베이스로 예제 프로젝트에서 주로 사용 콘솔 설정을 하면 웹 기반 DBMS 화면 볼 수 있음

JPA, H2 의존성 추가 implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'com.h2database:h2'

JPA의 관리를 위해 Article 도메인을 엔티티로 변경 //domain/Article.java

@Getter

@Builder

@NoArgsConstructor //파라미터가 없는 기본 생성자를 만들어달라

@AllArgsConstructor //없으면 Builder에 오류가 남

@Entity

public class Article {

@Id

@GeneratedValue(strategy = GenerationType.IDENTITY)

Long id;

String title;

String content;

}

+ ArticleRepository 생성 + Domain 관리를 위함 => Query 수행 가능 ```java public interface ArticleRepository extends CrudRepository { } // <도메인, 도메인 타입>

ArticleService가 ArticleRepository 객체와 연계될 수 있도록 설정 // service/ArticleService.java

@RequiredArgsConstructor

@Service

public class ArticleService {

private final ArticleRepository articleRepository;

public Long save(Article request) { return articleRepository.save(request).getId(); } public Article findById(Long id) { return articleRepository.findById(id).orElse(null); } @Transactional public Article update(Article request) { Article article = this.findById(request.getId()); article.update(request.getTitle(), request.getContent()); return article; } public void delete(Long id) { Article article = this.findById(id); articleRepository.deleteById(id); // = articleRepository.delete(article); }

}

+ Update 함수 코드는 Repository 클래스를 활용하지 않고 도메인 클래스에 바로 접근하도록 설정함 + JPA는 Persistance Context라는 논리적 공간에서 엔티티를 캐싱하고 관리함 + JPA는 하나의 트랜잭션이 끝나면 수정된 domain의 내용을 자동으로 확인하여 실제 데이터베이스 벤더에 저장 ```java // domain/Article.java public void update(String title, String content) { this.title = title; this.content = content; }

Trasaction

원자성이 보장되어야 하는 업무 단위

update = 조회와 수정의 두 역할을 모두 수행

CRUD API 만들기

ArticleController 객체에 PUT, DELETE API 추가하기 //controller/ArticleController.java

@PutMapping("/{id}")

public Response put(@PathVariable Long id, @RequestBody ArticleDto.ReqPut request) {

Article article = Article.builder()

.id(id)

.title(request.getTitle())

.content(request.getContent())

.build();

Article articleResponse = articleService.update(article); ArticleDto.Res response = ArticleDto.Res.builder() .id(String.valueOf(articleResponse.getId())) .title(articleResponse.getTitle()) .content(articleResponse.getContent()) .build(); return Response.builder().code(ApiCode.SUCESS).data(response).build(); }

@DeleteMapping("/{id}")

public Response delete(@PathVariable Long id) {

articleService.delete(id);

return Response. builder().code(ApiCode.SUCESS).build();

}

+ ArticleDto에 PutDto 생성 ```java @Getter public static class ReqPut{ String title; String content; }

H2 DATABASE

메모리 DB

사용하기 편리해서 예제코드에서 많이 사용

localhost:8080/h2-console에 접근하면 확인 가능 // application.properties

spring.h2.console.enabled=true

spring.h2.console.path=/h2-console

spring.datasource.url=jdbc:h2:mem:testdb

## of Pattern + 정적 팩토리 메서드 패턴 + Controller에서 할 수 있는 일을 대신 해줌(응집도를 낮추기 위함 + 가독성) + 특정 객체를 생성하는 코드들이 Controller에 중복되는 것을 막기 위함 + 객체를 생성하는 일을 그 객체에 위임함으로써 보다 객체지향과 같은 코딩을 할 수 있음 + Article에 of 패턴 생성 ```java //domain/Article.java public static Article of(ArticleDto.ReqPost from) { return Article.builder() .title(from.getTitle()) .content(from.getContent()) .build(); } public static Article of(ArticleDto.ReqPut from, Long id) { return Article.builder() .id(id) .title(from.getTitle()) .content(from.getContent()) .build(); }

ArticleDto에 of 패턴 생성 public static Res of(Article from) { return Res.builder() .id(String.valueOf(from.getId())) .title(String.valueOf(from.getTitle())) .content(String.valueOf(from.getContent())) .build(); }

Response에 of 패턴 생성 // dto/Response.java

public static Response ok() { // 데이터를 무조건 넣게 되어있어서 생기는 오류를 해결하기 위함.

return Response. builder()

.code(ApiCode.SUCESS)

.build();

}

public static Response ok(T data) {

return Response. builder()

.code(ApiCode.SUCESS)

.data(data)

.build();

}

+ of 패턴을 사용하면서 Controller의 코드가 다음과 같이 간단해짐 + BUT, 파라미터가 많아지는 경우에는 지양하는 편이다. (코드가 지저분한건 같기 때문) ```java //controller/ArticleController.java public class ArticleController { private final ArticleService articleService; @PostMapping public Response post(@RequestBody ArticleDto.ReqPost request) { return Response.ok(articleService.save(Article.of(request))); } @GetMapping("/{id}") public Response get(@PathVariable Long id) { return Response.ok(ArticleDto.Res.of(articleService.findById(id))); } @PutMapping("/{id}") public Response put(@PathVariable Long id, @RequestBody ArticleDto.ReqPut request) { return Response.ok(ArticleDto.Res.of(articleService.update(Article.of(request, id)))); } @DeleteMapping("/{id}") public Response delete(@PathVariable Long id) { return Response.ok(); }

예외처리

실무에서는 오류를 잡아내는 예외처리가 매우 중요

NullPointerException이 발생할 수 있는 영역을 찾고, null이 발생했을 때 예외를 발생시킨다면? => 실무에서 매우 위험!!!

여러 오류들 함수가 어떤 타입을 받는지의 가독성의 효과를 얻을 수 있었으나, Object를 받음으로 원래 하려던 것이 깨짐. try-catch문을 넣으면서 코드가 장황해짐. (메인코드 이상의 부수적인 것들이 추가 생성됨) 데이터가 존재하지 않는 경우에만 API 코드를 넣었으나, 동일 함수에 data가 존재하지 않는 것 이외의 다른 오류가 발생되면 코드에 지정되어있는 것은 한정적이므로 유연성이 떨어짐 //service/ArticleService.java

@PutMapping("/{id}")

public Response \

\ \ 공유하기 \ \

\ 글 요소 \

\ \

from http://hyeon99-dev.tistory.com/6 by ccl(A) rewrite - 2021-11-01 22:27:43