[TIL] 3주차 주특기 입문ㅣCRUD API 만들기 1편
Spring 입문 주차 개인 과제
이번 주차는 처음으로 개인 과제를 받았다.
스프링 부트를 이용하여 CRUD API를 만드는 것인데
자세한 요구사항은 다음과 같다.
🚩 Goal: "스프링 부트로 로그인 기능이 없는 나만의 항해 블로그 백엔드 서버 만들기"
처음 과제를 마주했을 때는 '이게 되나..?' 싶은 마음이 컸는데
어느새 강의를 다 듣고.. 유스케이스를 그리고.. 프로젝트를 만들고 있는 나를 발견😂
하나하나 알려주는 방식이 아니다 보니 오늘의 궁금했던 부분과 찾아낸 해답들을 정리해보려 한다.
오늘의 궁금증
1. @RequestBody vs @ModelAttribute
둘 다 클라이언트 측에서 보낸 데이터를 객체로 바꿔주는 건 맞는데.. 둘이 어떻게 다르지?
- RequestBody
- @RequestBody는 MessageConverter를 통해 Json 형태의 HTTP Body를 Java 객체로 변환시킨다.
- ModelAttribute
- @ModelAttribute는 폼(form) 형태의 HTTP Body와 요청 파라미터들을 객체에 바인딩시킨다.
📚 참고자료
@RequestBody vs @ModelAttribute
1. @RequestBody와 @ModelAttribute Controller.java @RequestBody와 @ModelAttribute는 클라이언트 측에서 보낸 데이터를 Java…
tecoble.techcourse.co.kr
[Spring] @RequestBody, @ModelAttribute, @RequestParam의 차이
이번에는 Spring에서 Client로 받은 요청을 객체로 바인딩하기 위해 사용하는 방법들에 대해서 알아보도록 하겠습니다. 1. RequestBody, ModelAttribute, RequestParam이란? [ @RequestParam ] @RequestParam은 1개의 HTTP
mangkyu.tistory.com
2. Entity vs VO vs DTO
VO와 DTO를 함께 사용한 적은 있는데 Entity는 초면이다.
이참에 3가지의 차이점이 무엇인지 정리해보았다.
- DTO(Data Transfer Object)
- 데이터를 전달하기 위한 객체. 주로 View와 Controller 사이에서 데이터를 주고받을 때 활용.
- getter, setter 메소드 포함. 이 외의 비즈니스 로직은 포함하지 않음.
- VO(Value Object)
- 값 자체를 표현하는 객체. 객체들의 주소가 달라도 값이 같으면 동일한 것으로 판단.
- getter 메소드 포함. setter 메소드는 포함하지 않음.
- 값 비교를 위해 equals()와 hashCode() 메소드를 오버라이딩 해줘야 함.
- Entity
- 실제 DB 테이블과 매핑되는 핵심 클래스. 절대로 Entity를 요청이나 응답 값을 전달하는 클래스로 사용해서는 안된다. 이를 기준으로 테이블이 생성되고 스키마가 변경되기 때문.
- DTO처럼 setter 메소드를 가지는 경우 가변 객체로 활용 가능. 비즈니스 로직 포함.
📚 참고자료
DTO vs VO vs Entity
DTO와 VO는 분명히 다른 개념이다. 그런데, 같은 개념으로 생각해서 사용하는 경우가 많다. 왜일까? ⌜Core J2EE Patterns: Best Practices and Design Strategies⌟ 책의 초판에서는 데이터 전송용 객체를 로 정의
tecoble.techcourse.co.kr
3. Spring Data JPA Query Methods
memoRepository.findAllByOrderByModifiedAtDesc()
Mybatis를 이용해서 쿼리문을 매핑해준 적은 있는데 아예 DB 자체를 매핑해주는 JPA는 처음이라 좀 당황스러웠다.
하나씩 풀어서 설명해보자면,
findAll(전체를 가져와라)By(대신 조건이 있음)OrderBy(정렬을 할건데)ModifiedAt(수정 날짜 기준)Desc(내림차순으로)
이런 의미이다. 그럼 이 메소는 뭔가 정해진 약속이 있는 건가?
Spring Data JPA - Reference Documentation
Example 119. Using @Transactional at query methods @Transactional(readOnly = true) interface UserRepository extends JpaRepository { List findByLastname(String lastname); @Modifying @Transactional @Query("delete from User u where u.active = false") void del
docs.spring.io
맞다. 이것들은 Spring Data JPA에 쿼리메소드로 정의되어있다.
Repository 인터페이스에서 JpaRepository 클래스를 상속받고,
해당하는 메소드를 사용하면 자동으로 쿼리가 생성되면서 DB와 연결되어 저장된다..!(미쳤다)
다음처럼 사용할 수 있다.
public interface ProductRepository extends JpaRepository<Product, Long> {
// (1) 회원 ID 로 등록된 상품들 조회
List<Product> findAllByUserId(Long userId);
// (2) 상품명이 title 인 관심상품 1개 조회
Product findByTitle(String title);
// (3) 상품명에 word 가 포함된 모든 상품들 조회
List<Product> findAllByTitleContaining(String word);
// (4) 최저가가 fromPrice ~ toPrice 인 모든 상품들을 조회
List<Product> findAllByLpriceBetween(int fromPrice, int toPrice);
}
4. 왜 update 할 때는 Repository를 거치지 않는 거지?
@Transactional
public BoardResponseDto update(Long id, BoardRequestDto requestDto) {
Board board = boardRepository.findById(id).orElseThrow(
() -> new IllegalArgumentException("아이디가 존재하지 않습니다.")
);
board.update(requestDto); // 엥 이게 끝?
return new BoardResponseDto(board);
}
제공된 강의를 참고하며 과제를 진행하던 중 흥미로운 부분을 발견했다.
Create와 Delete 모두 Repository내에 미리 정의된 메소드를 불러와 DB를 변경시켰는데
Update에는 왜 없는 것인가? Entity에서 바로 해결이 되는 건가?
오늘 팀 과제를 하며 JPA에 대한 내용을 찾아보던 중 해답을 발견했다!
참고로, JPA는 수정 메소드를 제공하지 않는다. 하지만 당연히 수정은 필요하기 때문에 JPA는 데이터 수정 시, 매핑된 객체(테이블 데이터)를 조회해서 값을 변경 후 커밋하면 DB 서버에 UPDATE 문을 전송하여 UPDATE를 실행한다.
[Spring JPA] JPA 란?
이번 글에서는 JPA(Java Persistence API)가 무엇인지 알아보려고한다. JPA는 자바 진영에서 ORM(Object-Relational Mapping) 기술 표준으로 사용되는 인터페이스의 모음이다. 그 말은 즉, 실제적으로 구현된것이
dbjh.tistory.com
5. 왜 long이 아닌 Long일까?
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
Entity인 Board 클래스의 id 부분이다.
처음엔 몰랐는데 여러 번 보다 보니 id의 타입이 long이 아닌 Long이라는 걸 알 수 있었다.
왜? 굳이?
이유는 바로 null을 사용할 수 있기 때문!
프리미티브 타입은 기본값이 0인데 그럼 실제로 id 값이 0인 건지, 값이 없는 건지 사실 구분하기 어렵습니다. id가 0일 수도 있는 거니까요. 그런데 Wrapper 타입인 Long이나 Integer를 쓰면 id가 없는 경우엔 확실히 null이고, 그 자체로 id가 없다는 걸 보장할 수 있죠.
Long 타입에 대한 질문입니다. - 인프런 | 질문 & 답변
강의에서 엔티티 클래스를 정의할 때, Long 타입을 id로 사용하는 이유가 궁금합니다. primitive 타입인 long 타입도 있는데, Long타입과의 차이점? 사용시의 차이점..?을 알고 싶습니다. 항상 친절한 답
www.inflearn.com
오늘의 에러
java.lang.NoClassDefFoundError
- 상황 - 분명 class 파일이 있는데 자꾸 못 찾는다.
- 원인 - 괜히 폴더 정리하겠다고 이름 바꾸고 여기저기 옮겼다가 IDE의 리팩토링 기능을 화나게 한 것 같다..^^
- 해결 - 깔끔하게 out 폴더 싹 다 지우고 다시 빌드 → 성공!
오늘의 나는
정말 모르는 거 투성이다.
'이게 도대체 뭐야..?' 싶은 부분이 나올 때마다 흥미로움 반 한숨 반으로 대차게 부딪히는 중이다.
열심히 구글링 한 덕에 CRUD의 큰 틀은 완성되었고,
아직 해결 못한 Timestamped 에러와 비밀번호 일치 로직을 구현하고 나면
기술 매니저님이 던져주신 키워드로 Spring boot와 JPA에 대해 더 공부해 봐야겠다!
기술 매니저님의 핵심 키워드 💡
- @Transactional 어노테이션이 없더라도 update는 되어야 함
- 영속성 컨텍스트
- 커밋 롤백
- controller에서 repository 사용하고 있지 않은지
- controller에 entity가 있진 않은지
- setter에 대해 찾아 볼 것