[Spring] core4 - Spring Data JPA

호호빵·2022년 6월 22일
0

Spring

목록 보기
11/24

ORM: Object-Relational Mapping

  • Object: 객체 (자바), Relational: DB (H2, MySQL)

JPA: Java Persistence API

  • ORM 기술에 대한 표준 명세
  • JPA 를 편리하게 사용하기 위해, 스프링에서 JPA 를 Wrapping
  • Repostiory 인터페이스만 작성하면, 필요한 구현은 스프링이 대신 알아서
public interface ProductRepository extends JpaRepository<Product, Long> {

}

// findById 할 때 Id의 형식 필요함

# 기본 제공 기능 
생성 - save
조회 - findAll
전체 개수 조회 - count
삭제 - delete

# ID 외의 필드에 대한 추가 기능은 interface 만 선언해 주면, 구현은 Spring Data JPA 가 대신!!
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);
}

Spring Data JPA 의 Query Methods 추가 구현

페이징 적용

ProdcutController

# ProductController - 페이징 전
@RestController // JSON으로 데이터를 주고받음을 선언합니다.
public class ProductController {
    // 멤버 변수 선언
    private final ProductService productService;

    // 생성자: ProductController() 가 생성될 때 호출됨
    @Autowired
    public ProductController(ProductService productService) {
        // 멤버 변수 생성
        this.productService = productService;
    }

    // 로그인한 회원이 등록한 상품들 조회
    @GetMapping("/api/products")
    public List<Product> getProducts(@AuthenticationPrincipal UserDetailsImpl userDetails) {
        Long userId = userDetails.getUser().getId();
        return productService.getProducts(userId);
    }


    // 신규 상품 등록
    @PostMapping("/api/products")
    public Product createProduct(@RequestBody ProductRequestDto requestDto, @AuthenticationPrincipal UserDetailsImpl userDetails) {
        // 로그인 되어 있는 ID
        Long userId = userDetails.getUser().getId();

        Product product = productService.createProduct(requestDto, userId);
        // 응답 보내기
        return product;
    }

    // 설정 가격 변경
    @PutMapping("/api/products/{id}")
    public Long updateProduct(@PathVariable Long id, @RequestBody ProductMypriceRequestDto requestDto) {
        Product product = productService.updateProduct(id, requestDto);
        return product.getId();
    }
}

# 페이징 후
@RestController // JSON으로 데이터를 주고받음을 선언합니다.
public class ProductController {
    // 멤버 변수 선언
    private final ProductService productService;

    // 생성자: ProductController() 가 생성될 때 호출됨
    @Autowired
    public ProductController(ProductService productService) {
        // 멤버 변수 생성
        this.productService = productService;
    }

    // 로그인한 회원이 등록한 상품들 조회
    @GetMapping("/api/products")
    public Page<Product> getProducts(
            @RequestParam("page") int page,
            @RequestParam("size") int size,
            @RequestParam("sortBy") String sortBy,
            @RequestParam("isAsc") boolean isAsc,
            @AuthenticationPrincipal UserDetailsImpl userDetails
    ) {
        Long userId = userDetails.getUser().getId();
        page = page - 1;
        return productService.getProducts(userId, page , size, sortBy, isAsc);
    }

    // 신규 상품 등록
    @PostMapping("/api/products")
    public Product createProduct(@RequestBody ProductRequestDto requestDto, @AuthenticationPrincipal UserDetailsImpl userDetails) {
        // 로그인 되어 있는 ID
        Long userId = userDetails.getUser().getId();

        Product product = productService.createProduct(requestDto, userId);
        // 응답 보내기
        return product;
    }

    // 설정 가격 변경
    @PutMapping("/api/products/{id}")
    public Long updateProduct(@PathVariable Long id, @RequestBody ProductMypriceRequestDto requestDto) {
        Product product = productService.updateProduct(id, requestDto);
        // 응답 보내기
        return product.getId();
    }

    // (관리자용) 등록된 모든 상품 목록 조회
    @Secured("ROLE_ADMIN")
    @GetMapping("/api/admin/products")
    public Page<Product> getAllProducts(
        @RequestParam("page") int page,
        @RequestParam("size") int size,
        @RequestParam("sortBy") String sortBy,
        @RequestParam("isAsc") boolean isAsc
    ) {
        return productService.getAllProducts(page , size, sortBy, isAsc);
    }
}

ProductService

# 전
@Service
public class ProductService {
    // 멤버 변수 선언
    private final ProductRepository productRepository;

    // 생성자: ProductService() 가 생성될 때 호출됨
    @Autowired
    public ProductService(ProductRepository productRepository) {
        this.productRepository = productRepository;   // 멤버 변수 생성
    }

    // 회원 ID 로 등록된 모든 상품 조회
    public List<Product> getProducts(Long userId) {
        return productRepository.findAllByUserId(userId);
    }

    @Transactional // 메소드 동작이 SQL 쿼리문임을 선언
    public Product createProduct(ProductRequestDto requestDto, Long userId){
        Product product = new Product(requestDto, userId);    // 요청받은 DTO 로 DB에 저장할 객체 만들기
        productRepository.save(product);
        return product;
    }

    @Transactional
    public Product updateProduct(Long id, ProductMypriceRequestDto requestDto) {
        Product product = productRepository.findById(id)
                .orElseThrow(() -> new NullPointerException("해당 아이디가 존재하지 않습니다."));
        int myPrice = requestDto.getMyprice();
        product.updateMyPrice(myPrice);
        return product;
    }
} 

# 후
@Service
public class ProductService {
    // 멤버 변수 선언
    private final ProductRepository productRepository;
    private static final int MIN_PRICE = 100;

    // 생성자: ProductService() 가 생성될 때 호출됨
    @Autowired
    public ProductService(ProductRepository productRepository) {
        // 멤버 변수 생성
        this.productRepository = productRepository;
    }

    public Page<Product> getProducts(Long userId, int page, int size, String sortBy, boolean isAsc) {
        Sort.Direction direction = isAsc ? Sort.Direction.ASC : Sort.Direction.DESC;
        Sort sort = Sort.by(direction, sortBy);
        Pageable pageable = PageRequest.of(page, size, sort);

        return productRepository.findAllByUserId(userId, pageable);
    }

    @Transactional // 메소드 동작이 SQL 쿼리문임을 선언합니다.
    public Product createProduct(ProductRequestDto requestDto, Long userId) {
        // 요청받은 DTO 로 DB에 저장할 객체 만들기
        Product product = new Product(requestDto, userId);
        productRepository.save(product);
        return product;
    }

    @Transactional // 메소드 동작이 SQL 쿼리문임을 선언합니다.
    public Product updateProduct(Long id, ProductMypriceRequestDto requestDto) {
        Product product = productRepository.findById(id).orElseThrow(
                () -> new NullPointerException("해당 아이디가 존재하지 않습니다.")
        );

        // 변경될 관심 가격이 유효한지 확인합니다.
        int myPrice = requestDto.getMyprice();
        if (myPrice < MIN_PRICE) {
            throw new IllegalArgumentException("유효하지 않은 관심 가격입니다. 최소 " + MIN_PRICE + " 원 이상으로 설정해 주세요.");
        }

        product.updateMyPrice(myPrice);
        return product;
    }

    // 모든 상품 조회 (관리자용)
    public Page<Product> getAllProducts(int page, int size, String sortBy, boolean isAsc) {
        Sort.Direction direction = isAsc ? Sort.Direction.ASC : Sort.Direction.DESC;
        Sort sort = Sort.by(direction, sortBy);
        Pageable pageable = PageRequest.of(page, size, sort);

        return productRepository.findAll(pageable);
    }
}

ProductRepository

# 전
public interface ProductRepository extends JpaRepository<Product, Long> {
    List<Product> findAllByUserId(Long userId);
}

# 후
public interface ProductRepository extends JpaRepository<Product, Long> {
    Page<Product> findAllByUserId(Long userId, Pageable pageable);
}

테스트

폴더 추가

# FolderCreateRequestDto
  @Getter
  public class FolderCreateRequestDto {
      List<String> folderNames;
  }

# FolderController
  // 회원이 폴더 추가
  @PostMapping("/api/folders")
  public List<Folder> addFolders(@RequestBody FolderCreateRequestDto folderCreateRequestDto, 
    							 @AuthenticationPrincipal UserDetailsImpl userDetails) {
      List<String> folderNames = folderCreateRequestDto.getFolderNames();
      return folderService.createFolders(folderNames, userDetails.getUser());
      // 예전 Long userId = userDetails.getUser().getId();  ->  return 값에 userId 넘겨줌
      // 현재 User user = userDetails.getUser();
  }
    
# ProductService
  public List<Folder> createFolders(List<String> folderNameList, User user) {
  	List<Folder> folderList = new ArrayList<>();
    for (String folderName : folderNameList) {
        Folder folder = new Folder(folderName, user);
        folderList.add(folder);
    }
    folderList = folderRepository.saveAll(folderList);
    return folderList;
  }
    
# FolderRepository
  public interface FolderRepository extends JpaRepository<Folder, Long> {
      List<Folder> findAllByUser(User user);
  }

    
# HomeController
  @GetMapping("/")
  public String home(Model model, @AuthenticationPrincipal UserDetailsImpl userDetails) {
    List<Folder> folders = folderService.getFolders(userDetails.getUser());
    model.addAttribute("folders", folders);
    model.addAttribute("username", userDetails.getUsername());
    return "index";
  }

관심상품에 폴더 추가 구현

폴더 별 관심상품 조회

4주차 강의노션

profile
하루에 한 개념씩

0개의 댓글