[JPA] JPA 사용법 - Spring Data JPA

koline·2024년 1월 8일

JPA

목록 보기
3/11

이전 포스팅에서 Spring Data JPA의 세팅방법을 다뤘는데, 여기서 작성한 내용을 기준으로 사용법에 대해서 작성한다.

// /com/practice/project/test/controller/TestController.java
package com.practice.project.test.controller;

import com.practice.project.test.repository.TestRepository;
import com.practice.project.test.entity.TestEntity;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequiredArgsConstructor
public class TestController {

	// 여기서는 서비스까지 생성하기는 귀찮아서 repository를 그대로 사용했지만
    // 실제로는 이렇게 사용하면 안된다.
    // 3-tier 구조를 지켜야한다!
	private final TestRepository testRepository;

	@PostMapping("/test")
    public ResponseEntity<TestEntity> createTest() {
    	TestEntity testEntity = testRepository.save(
        	TestEntity.builder()
        		.val1("val1")
                .val2("val2")
            .build()
        );
        
		return ResponseEntity.ok(testEntity);
    }
    
    @GetMapping("/tests")
    @ResponseStatus(HttpStatus.OK)
    public List<TestEntity> getTestList() {
    	return testRepository.findAll();
    }
}

// /com/practice/project/test/repository/TestRepository.java
package com.practice.project.test.repository;

import com.practice.project.test.entity.TestEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

// JpaRepository를 상속하여 사용. <객체, ID타입>
@Repository
public interface TestRepository extends JpaRepository<TestEntity, Long> {
}

이게 지난 포스팅에서 작성된 내용인데, 위 내용을 그대로 변경하며 사용하겠다.

위 예시에서는 그냥 포스팅을 목적으로 작성했기 때문에 Controller에서 Repository를 바로 호출하는데 저번 포스팅에서도 언급했듯이 3-tier 구조를 지키는 것은 스프링에서 매우 중요하다. (Spring의 3요소 중 서비스의 추상화 관련)

// 컨트롤러 전체 코드
@RestController
@RequestMapping("/tests")
@RequiredArgsConstructor
public class TestController {

	// 여기서는 서비스까지 생성하기는 귀찮아서 repository를 그대로 사용했지만
    // 실제로는 이렇게 사용하면 안된다.
    // 3-tier 구조를 지켜야한다!
	private final TestRepository testRepository;

	/**
     * Create 메소드
     * save 메소드는 id가 동일한 객체가 DB에 존재하지 않을경우 INSERT 한다.
     */
	@PostMapping
    public ResponseEntity<TestEntity> createTest() {
    	TestEntity testEntity = testRepository.save(
        	TestEntity.builder()
            	.id("id1")
        		.val1("val1")
                .val2("val2")
            .build()
        );
        
		return ResponseEntity.ok(testEntity);
    }
    
    /**
     * List 조회 메소드
     * 파라미터로 받는 Pageable 객체는 
     * sort, limit, offset 등 페이징에 사용되는 요소를 모은 객체로
     * JPA find 메소드에 파라미터로 전달하면 파라미터에 맞게 페이징을 해준다.
     * findAll 메소드는 데이터가 없을 경우 빈 배열을 리턴한다.
     */
    @GetMapping
    @ResponseStatus(HttpStatus.OK)
    public List<TestEntity> getTests(
    	final Pageable pageable
    ) {
    	return testRepository.findAll(pageable);
    }
    
    /**
     * Read 메소드
     * findById 메소드는 Optional 객체를 리턴한다.
     * Optional 객체의 isPresent 메소드를 통해 
     * 실제로 존재하는 객체인지 확인한 후 get() 메소드를 실행하면 실제 객체를 리턴한다.
     */
    @GetMapping("/{id}")
    public ResponseEntity<TestEntity> getTest(
    	@PathVariable(name = "id") Long id
    ) {
    	TestEntity testEntity = testRepository.findById(id);
        
        if (testEntity.isPresent()) {
        	return ResponseEntity.ok(testEntity.get());
        } else {
        	return ResponseEntity.badRequest().body(null);
        }
    }
    
    /**
     * Update 메소드
     * save 메소드는 id가 동일한 객체가 DB에 존재할 경우 UPDATE 한다.
     */
    @PatchMapping("/{id}")
    public ResponseEntity<TestEntity> updateTest(
    	@PathVariable(name = "id") Long id
    ) {
    	if (testRepository.existsById(id)) {
        	TestEntity entityToUpdate = TestEntity.builder()
            		.id(id)
                    .val1("val1_updated")
                    .val2("val2_updated")
                    .build();
            TestEntity updatedEntity = testRepository.save(updatedEntity);
            
            return ResponseEntity.ok(updatedEntity);
        } else {
        	return ResponseEntity.badRequest().body(null);
        }
    }
    
    /**
     * Delete 메소드
     */
    @DeleteMapping("/{id}")
    public ResponseEntity<String> deleteTest(
    	@PathVariable(name = "id") Long id
    ) {
    	if (testRepository.existsById(id)) {
        	testRepository.deleteById(id)
            return ResponseEntity.ok(
            	"{ \"result\" : \"success\" }"
            );
        } else {
        	return ResponseEntity.badRequest().body(
            	"{ \"result\" : \"fail\" }"
            );
        }
    }
}

위 내용은 가장 기본적인 JpaRepository의 사용법이다. 그 외의 요소는 편의성을 위해 최대한 간단하게 작성했으니 무시해도 된다.

기본적인 findAll(), findById(), save(), deleteById() 등 CRUD 메소드나 existsById()와 같이 일반적으로 많이 쓰인느 메소드는 다 제공이 된다. (사용법은 위 코드의 주석 참고)

하지만 개발을 하다보면 기본적인 메소드만 활용해서는 한계가 있다. 직접 쿼리를 작성하고 커스텀 하는 방법에 대해서는 Query 커스텀하기 포스팅 참고

profile
개발공부를해보자

0개의 댓글