일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- swap 메모리
- jar빌드
- MVC
- 저장소 복제
- JPA
- 스프링 이메일 전송
- 프로그래머스
- Servlet
- springboot
- 값 타입
- Chat GPT
- 두수의 합 자바
- api 개발
- git 충돌 해결
- Json 객체
- github 복제
- 자바
- 서버 배포
- JDBC
- 넘파이
- 우분투
- HttpServletResponse
- Git
- 저장소 이전
- 비밀번호 재설정 API
- JPQL
- 스프링부트 OpenAI API
- 파이썬
- MySQL
- 페이징 정렬
- Today
- Total
현의 개발 블로그
JPA로 도서관리 API 개발하기 본문
책 생성 API 개발
API 명세서
HTTP Method | POST |
HTTP Path | /book |
HTTP Body | {"name" : String} |
결과 | 반환 X |
book 테이블 설계하기
create table book
(
id bigint auto_increment,
name varchar(255),
primary key (id)
);
@Column length 기본값이 255라서 varchar(255)로 지정했다.
Book 객체 생성
@Entity
@NoArgsConstructor(access = PROTECTED)
public class Book {
@Id @GeneratedValue
private Long id;
@Column(nullable = false)
private String name;
public Book(String name){
if (name == null || name.isBlank())
throw new IllegalArgumentException();
this.name = name;
}
}
Book Repository 생성
public interface BookRepository extends JpaRepository<Book, Long>{}
Book DTO 생성
@Getter
public class BookCreateRequest {
private String name;
}
Book Controller 생성
@RestController
@RequiredArgsConstructor
public class BookController {
private final BookService bookService;
@PostMapping("/book")
public void saveBook(@RequestBody BookCreateRequest request){
bookService.saveBook(request);
}
}
@RestController는 @ResponseBody + @Controller이다.
@ResponseBody는 자바 객체를 http body 객체로 변환한다.
@RequestBody는 http body에 있던 JSON 객체를 자바 객체로 변환한다.
@RequiredArgsConstructor는 final 변수를 생성자 주입해준다.
Book service 생성
@Service @RequiredArgsConstructor
public class BookService {
private final BookRepository bookRepository;
@Transactional
public void saveBook(BookCreaterequest request){
bookRepository.save(new Book(request.getName());
}
}
대출 API 개발
API 명세서
HTTP method | POST |
HTTP path | /book/loan |
HTTP Body | {"userName" : String, "bookName" : String} |
결과 | 반환x |
유저 대출 기록을 저장하는 새로운 테이블을 생성한다.
create table user_loan_history(
id bigint auto_increment,
user_id bigint,
book_name varchar(255),
is_return tinyint(1),
primary key(id)
);
엔티티 생성
@Entity
@NoArgsConstructor
public class UserLoanHistory{
@Id @GeneratedValue
private Long id;
private Long userId;
private String bookName;
private boolean isReturn;
public UserLoanHistory(Long userId, String bookName){
this.userId = userId;
this.bookname = bookName;
this.isReturn = false;
}
}
DTO 생성
@Getter
public class BookLoanRequest {
private String userName;
private String bookName;
}
Controller 생성
@PostMapping("/book/loan")
public void loanBook(@RequestBody BookLoanRequest request){
bookService.loanBook(request);
}
Service 생성
@Transactional
public void loanBook(BookLoanRequest request){
Book book = bookRepository.findByName(request.getBookName())
.orElseThrow(IllegalArgumentException::new);
if (userLoanHistoryRepository.existByBookNameAndIsReturn(book.getName(), false))
throw new IllegalArgumentException("이미 대출중인 책입니다.");
User user = userRepository.findByName(request.getUserName())
.orElseThrow(IllegalArgumentException::new);
userLoanHistoryRepository.save(new UserLoanHistory(user.getId(),book.getName());
}
책 이름에 맞는 책을 찾는데, 없으면 예외를 던진다.
해당 책이 존재하는데 이미 대출 중이라면 예외를 던진다.
유저 이름과 일치하는 유저를 찾는데 없다면 예외를 던진다.
위의 조건들을 다 만족하면, 유저 이름과 책을 대출 기록에 저장한다.
Repository 인터페이스에 함수 추가
public interface BookRepository extends JpaRepository<Book, Long>{
Optional<Book> findByName(String name);
}
public interface UserLoanHistoryRepository extends JpaRepository<UserLoanHistory,Long>{
boolean existsByBookNameAndIsReturn(String name, boolean isReturn);
}
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByName(String name);
}
도서 반납 API 개발
HTTP Method | PUT |
HTTP path | /book/return |
HTTP Body | {"userName" : String, "bookName": String} |
결과 | 반환 x |
앞의 도서 대출 API와 HTTP Body가 동일하다. 그렇다고 기존 DTO를 재활용하기보다는 새로 DTO를 생성하는 것이 좋다.
두 기능 중 한 기능에 변화가 생겼을 때 유지 및 보수가 용이하기 때문이다.
DTO 코드는 편의상 생략하겠다.
Controller 생성
@PutMapping("/book/return")
public void returnBook(@RequestBody BookReturnRequest request){
bookService.returnBook(request);
}
service 생성
@Transactional
public void returnBook(BookReturnRequest request){
User user = UserRepository.findByName(request.getUserName())
.orElseThrow(IllegalArgumentException::new);
UserLocalHistory history = userLoanHistoryRepository
.findByUserIdAndBookNameAndIsReturn(user.getId(), request.getBookName())
.orElseThrow(IllegalArgumentException::new);
history.doReturn();
}
유저를 조회한다. 해당 유저가 없으면 예외를 던진다.
유저 아이디, 책 이름으로 기록 조회한다. 없으면 예외를 던진다.
UserLocalHistory 엔티티 내의 함수를 호출해 반납여부를 true로 변경한다.
마무리
이번에는 JPA로 도서관리 API를 개발하였다.
그러나 해당 코드는 객체 지향적이기 보다는 절차 지향적에 더 가깝다.
다음 글에서는 객체 지향적으로 개발하기 위해 연관관계 매핑을 살펴볼 것이다.
2023.04.19 - [스프링부트/도서관리 웹 개발] - 객체 지향적 개발 - 연관관계 매핑
참고
자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인
Java와 Spring Boot, JPA, MySQL, AWS를 이용해 서버를 개발하고 배포합니다. 웹 애플리케이션을 개발하며 서버 개발에 필요한 배경지식과 이론, 다양한 기술들을 모두 학습할 뿐 아니라, 다양한 옵션들
www.inflearn.com
'스프링부트 실습 > 도서관리 웹 개발' 카테고리의 다른 글
JPA 연관관계 매핑 보충 (Cascade, OrphanRemoval) (0) | 2023.04.19 |
---|---|
객체 지향적 개발 - 연관관계 매핑 (0) | 2023.04.19 |
JPA 활용한 User CRUD 개발 (0) | 2023.04.17 |
JDBC를 활용해 API 개발하기3 - 역할 분리 (0) | 2023.04.15 |
JDBC 활용해 API 개발하기2 - CRUD 개발 (0) | 2023.04.15 |