JPA란?
JPA는, SQL을 쓰지 않고 데이터를 생성, 조회, 수정, 삭제할 수 있도록 해주는 번역기입니다.
Repository(클래스)는 JPA를 작동시키는 매개체입니다.repository는 데이터를 접근할 때 사용하는 하나의 도구
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
Domain = Entity : 테이블
Repository = SQL : Repository에 써 있는 코드가 jpa 코드를 사용하는 것과 같다.
//Table
@NoArgsConstructor // 기본생성자를 대신 생성해줍니다. 기본생성자를 자동으로 넣어줄 것
@Entity // db기준으로 테이블 역할을 한다는 것을 알리는 것
public class Course {
//SQL
@Id // ID 값, Primary Key로 사용하겠다는 뜻입니다.
@GeneratedValue(strategy = GenerationType.AUTO) // id 생성 시 자동으로 증가 명령
private Long id;
@Column(nullable = false) // 컬럼 값이고 반드시 값이 존재해야 함을 나타냅니다.
private String title;
@Column(nullable = false)
private String tutor;
public String getTitle() {
return this.title;
}
public String getTutor() {
return this.tutor;
}
public Course(String title, String tutor) {
this.title = title;
this.tutor = tutor;
}
}
Interface
//CourseRepository : SQL 역할을 대신해주는 녀석
//<Course,Long> : "course = 클래스" , "Long : id 상태"
public interface CourseRepository extends JpaRepository<Course, Long> {
}
인터페이스(인터페이스는 jpa를 사용하는 방법)
->Course클래스가 course 테이블이 된다.
//저장
Course course1 = new Course(title, tutor)
repository.save(course1);
//조회
JPA 리턴 타입 : List<Course> 여러개를 보여야 하니까.
List<Course> courseLise = repository.findByAll();
@MappedSuperclass // 상속했을 때, 컬럼으로 인식하게 합니다.
@EntityListeners(AuditingEntityListener.class) // 생성/수정 시간을 자동으로 반영하도록 설정
public class Timestamped {
@CreatedDate // 생성일자임을 나타냅니다.
private LocalDateTime createdAt;
@LastModifiedDate // 마지막 수정일자임을 나타냅니다.
private LocalDateTime modifiedAt;
}
@ 붙은것을 어노테이션이라고 해서 스프링한테 "야! 이런 역할이 있어!" 라고 알려주는 것.
CRUD
정보관리의 기본 기능
-> 생성(CREATE)
-> 조회(READ)
-> 변경(UPDATE)
-> 삭제(DELETE)
데이터 저장하기 & 조회하기
(Repository의 save와 findAll 이용)
// 데이터 저장하기
repository.save(new Course("프론트엔드의 꽃, 리액트", "임민영"));
// 데이터 전부 조회하기
List<Course> courseList = repository.findAll();
for (int i=0; i<courseList.size(); i++) {
Course course = courseList.get(i);
System.out.println(course.getId());
System.out.println(course.getTitle());
System.out.println(course.getTutor());
}
//// 데이터 하나 조회하기
//repository 왜 있지? SQL을 작성해야하니까! JPA에서는 Repository가 sql 임을 잊지마:D
Course course = repository.findById(1L).orElseThrow(
() -> new IllegalArgumentException("해당 아이디가 존재하지 않습니다.")
);
NullPointerException : 가리키는게 없다.
Service
Update 는 Service 부분에 작성
//"자바 코스에 작성"
public void update(Course course) {
this.title = course.title;
this.tutor = course.tutor;
->풀이 : 코스라는 것을 받았을 때 타이틀과 튜터를 업데이트 해줘라.
}
//Update
//"서비스 패키지에 작성"
@Service // 스프링에게 이 클래스는 서비스임을 명시
public class CourseService {
// final: 서비스에게 꼭 필요한 녀석임을 명시
private final CourseRepository courseRepository;
// 생성자를 통해, Service 클래스를 만들 때 꼭 Repository를 넣어주도록
// 스프링에게 알려줌
public CourseService(CourseRepository courseRepository) {
this.courseRepository = courseRepository;
}
@Transactional // SQL 쿼리가 일어나야 함을 스프링에게 알려줌
//업데이트를 하기 위해 재료 두가지 필요. id와 코스. 코스 안에는 아이디와 튜터 정보 있음.
public Long update(Long id, Course course) {
Course course1 = courseRepository.findById(id).orElseThrow(
() -> new IllegalArgumentException("해당 아이디가 존재하지 않습니다.")
);
course1.update(course);
return course1.getId();
}
}
//
Dto
왜 사용하는가? 업데이트 할 때 Course 클래스를 이용해 데이터 받고 있는데, Course 클래스를 전달하는 방식으로 사용하기에 적합할까? 저장, 클라이언트 넘길 때 활용하지만 변경에는 적합하지 않다. 왜? 테이블을 막 건들다보면 코드 작성하다가 다른 사람이 마음대로 변경할 수도 있기 때문에(Course클래스가 변경되는 것은 DB가 바뀌는 것이나 다름 없음)완충재 역할로 DTO 를 사용하는 것이다.
domain에 CourseRequestDto(=코스요청관련 정보 물고 다니는 친구) 자바 파일 생성
@NoArgsConstructor //
@Getter
@Setter // 정보 설정을 위함.
public class CourseRequestDto {
private String title;
private String tutor;
public CourseRequestDto(String title, String tutor) {
this.title = title;
this.tutor = tutor;
}
}
Controller
데이터 조회 API
@RequiredArgsConstructor
@RestController
public class CourseController {
private final CourseRepository courseRepository;
@GetMapping("/api/courses")
public List<Course> getCourses() {
return courseRepository.findAll();
}
}
Post : 생성요청
private final CourseService courseService;
// PostMapping을 통해서, 같은 주소라도 방식이 다름을 구분합니다.
@PostMapping("/api/courses")
public Course createCourse(@RequestBody CourseRequestDto requestDto) {
// requestDto 는, 생성 요청을 의미합니다.
// requestbody 가 없으면 requestDto에 정보가 쏙 들어가질 않는다.
// 저장하는 것은 Dto가 아니라 Course이니, Dto의 정보를 course에 담아야 합니다.
// 잠시 뒤 새로운 생성자를 만듭니다.
Course course = new Course(requestDto);
// JPA를 이용하여 DB에 저장하고, 그 결과를 반환합니다.
return courseRepository.save(course);
}
PUT
@PutMapping("/api/courses/{id}")
public Long updateCourse(@PathVariable Long id, @RequestBody CourseRequestDto requestDto) {
return courseService.update(id, requestDto);
}
Delete
@DeleteMapping("/api/courses/{id}")
public Long deleteCourse(@PathVariable Long id){
courseRepository.deleteByID(id);
return id;
}
@PathVariable 아이디 전달 잘 해줌?
**스프링의 구조는 3가지로 나뉜다.
1. Controller : 가장 바깥 부분으로써, 요청/응답을 처리한다.
Restcontroller : JSON 자동응답기
Service : 중간 부분, 실제 중요한 작동이 많이 일어나는 부분, 업데이트 사용 시 사용
db와 응답하는 부분을 연결해주는 역할이 service
repository(저장소) : 가장 안쪽 부분으로, DB와 맞닿아 있음.(repository, entity)
-> 생성 삭제 조회