[Java+SpringBoot+JPA] 기본 CRUD 구현하기 (1)java

2023. 12. 23. 18:42Pratice/CRUD

반응형

 

🟢 Entity

- BaseEntity

  여러 엔터티 클래스에서 상속받아 재사용할 수 있도록 설계

  BaseEntity 클래스를 상속받는 하위 엔터티 클래스는 생성일(reDate) 및 수정일(moDate)을 자동으로 관리

@Getter
@Setter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity {

  @Column(name = "reDate")
  @CreatedDate
  private LocalDateTime reDate;

  @Column(name = "moDate")
  @LastModifiedDate
  private LocalDateTime moDate;

}
더보기

@MappedSuperclass

JPA에서 매핑 정보를 상속하기 위한 어노테이션

이 클래스의 필드들을 상속받는 하위 엔터티 클래스에서도 동일한 필드 매핑 정보를 사용할 수 있게 함

 

AuditingEntityListener 클래스

엔터티의 생성 및 수정 시간을 자동으로 관리

더보기

Application class에 @EnableJpaAuditing 추가 해줘야 함!

 

- ProuuctEntity

@Entity
@Builder
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "product")
@SequenceGenerator(
    name = "product_SEQ",
    sequenceName = "product_SEQ",
    initialValue = 1,
    allocationSize = 1)
public class ProductEntity extends BaseEntity {

  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "product_SEQ")
  private Integer productId;

  @Column(name = "productName", length = 30, nullable = false)
  private String productName;

  @Column(name = "productPrice", length = 10, nullable = false)
  private Integer productPrice;

}
더보기

@SequenceGenerator

시퀀스 생성기를 정의하는 어노테이션

product_SEQ라는 시퀀스를 사용하며 초기값과 할당 크기를 설정

 

initialValue: 시퀀스가 시작하는 초기 값(첫 번째 생성되는 값)

 

allocationSize: 시퀀스에서 한 번에 할당되는 범위의 크기

 

 

🟢 DTO

- Product DTO

  상품 정보를 전달하기 위한 클래스

  DTO는 주로 데이터 전송을 위해 사용되며, 비즈니스 로직을 포함하지 않고 데이터만을 담는 객체

  서비스 간에 데이터를 전달할 때 비즈니스 로직을 포함하지 않고도 필요한 데이터를 효과적으로 전달

@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ProductDTO {

  private Integer productId;

  @NotEmpty(message = "상품 이름은 필수 입력입니다.")
  private String productName;

  @NotNull(message = "가격은 필수 입력입니다.")
  @Min(value = 0, message = "가격은 최소 0원 이상이어야 합니다.")
  private Integer productPrice;

  private LocalDateTime reDate;

  private LocalDateTime moDate;

}
더보기

@NotEmpty

@NotNull

해당 필드가 비어 있으면 안 된다는 제약 조건

 

@Min

어노테이션은 해당 필드가 특정 최솟값 이상이어야 한다는 제약 조건

 

 

🟢 Repository

- Product Repository

@Repository
public interface ProductRepository extends JpaRepository <ProductEntity, Integer> {

}
더보기

JpaRepository

기본적인 CRUD 작업을 수행하기 위한 메서드들을 제공

 

  • save(T entity): 엔터티를 저장하거나 업데이트
  • findById(ID primaryKey): 주어진 주키에 해당하는 엔터티를 찾음
  • findAll(): 모든 엔터티를 가져옴
  • deleteById(ID primaryKey): 주어진 주키에 해당하는 엔터티를 삭제

 

 

🟢 Repository TEST

- Product Repository TEST

@SpringBootTest
@Log4j2
public class ProductRepositoryTest {

  @Autowired
  private ProductRepository productRepository;

  //삽입테스트
  @Test
  public void insert() throws Exception {

    for(int i=1; i<30; i++) {
      ProductEntity productEntity = ProductEntity.builder()
          .productId(i)
          .productName("상품"+i)
          .productPrice(10000)
          .build();
      ProductEntity result = productRepository.save(productEntity);
      log.info("삽입결과:" + result);
    }
  }

  //전체 삭제 테스트
  @Test
  public void deleteAll() throws Exception {

    productRepository.deleteAll();
  }

}

 

 

 

🟢 Service

- Product Service

상품과 관련된 비즈니스 로직을 처리하기 위한 서비스 클래스

@Service
@Transactional
@RequiredArgsConstructor
public class ProductService {

  private final ProductRepository productRepository;
  private final ModelMapper modelMapper = new ModelMapper();

  //Create 생성
  public ProductEntity insert(ProductDTO productDTO) throws Exception {

    ProductEntity productEntity = modelMapper.map(productDTO, ProductEntity.class);
    productRepository.save(productEntity);

    return productEntity;

  }


  //Read 전체 조회
  public List<ProductDTO> findAll() throws Exception {

    List<ProductEntity> productEntityList = productRepository.findAll();
    List<ProductDTO> productDTOS = Arrays.asList(modelMapper.map(productEntityList, ProductDTO[].class));

    return productDTOS;

  }



  //Read 개별 조회
  public ProductDTO findOne(Integer productId) throws Exception {

    //findById 메서드를 사용하여 ProductEntity를 가져오기
    Optional<ProductEntity> data = productRepository.findById(productId);

    //Optional이 가진 ProductEntity가 존재할 때에만 modelMapper.map이 호출되어 ProductDTO로 변환
    ProductDTO productDTO = new ProductDTO();
    data.ifPresent(entity -> modelMapper.map(entity, productDTO));

    return productDTO;

  }



  //Update 수정
  public void update(ProductDTO productDTO) throws Exception {

    //ProductDTO에서 productId를 가져오기
    Integer productId = productDTO.getProductId();

    //해당 ID에 대한 ProductEntity를 findById를 통해 찾기
    //만약 존재한다면 DTO를 Entity로 변환
    //save 메서드를 통해 업데이트를 수행
    productRepository.findById(productId).ifPresent(productEntity -> {
      modelMapper.map(productDTO, productEntity);
      productRepository.save(productEntity);
    });

  }
  


  //Delete 삭제
  public void delete(Integer productId) throws Exception {

    productRepository.deleteById(productId);

  }


}
더보기

@Transactional

각 메서드에 대해 트랜잭션 처리를 자동으로 지원하도록 하는 어노테이션

메서드 실행 중에 예외가 발생하면 롤백되고, 예외가 발생하지 않으면 커밋

 

@RequiredArgsConstructor

클래스에 대한 생성자를 자동으로 생성

주입받은 필드들에 대한 생성자를 생성

더보기

▪ insert 메서드

DTO를 받아와서 Entity로 변환 후, 데이터베이스에 저장. 저장된 Entity를 반환

 

▪ findAll 메서드

RepositoryfindAll 메서드를 사용하여 모든 엔터티를 가져오고, 이를 DTO 리스트로 변환하여 반환

 

▪ findOne 메서드

RepositoryfindById 메서드를 사용하여 특정 엔터티를 가져오고, 이를 DTO로 변환하여 반환

 

▪ update 메서드

DTO를 사용하여 해당 상품을 찾고, 업데이트할 정보를 적용한 후 다시 저장

 

▪ delete 메서드

RepositorydeleteById 메서드를 사용하여 주어진 ID에 해당하는 상품을 삭제

 

 

 

🟢 Controller

- ProductController

  특정 URL에 대한 요청을 처리하고, 비즈니스 로직은 ProductService를 호출하여 수행

@Controller
@RequiredArgsConstructor
public class ProductController {

  private final ProductService productService;

  
  //삽입폼
  @GetMapping("/productinsert")
  public String insertForm (Model model) throws Exception {

    ProductDTO productDTO = new ProductDTO();
    model.addAttribute("productDTO", productDTO);

    return "/product/insert";
  }
  //삽입 처리
  @PostMapping("/productinsert")
  public String insertProc (ProductDTO productDTO) throws Exception {

    productService.insert(productDTO);

    return "redirect:/productlist";
  }
  

  //전체조회
  @GetMapping("/productlist")
  public String productlist (Model model) throws Exception {

    List<ProductDTO> productDTOS = productService.findAll();
    model.addAttribute("productDTOS", productDTOS);

    return "/product/list";
  }


  //개별조회
  @GetMapping("/productdetail")
  public String productDetail (Integer productId, Model model) throws Exception {

    ProductDTO productDTO = productService.findOne(productId);
    model.addAttribute("productDTO", productDTO);

    return "/product/detail";
  }

  
  //수정폼
  @GetMapping("/productupdate")
  public String updateForm (Integer productId, Model model) throws Exception {

    ProductDTO productDTO = productService.findOne(productId);
    model.addAttribute("productDTO", productDTO);

    return "/product/update";
  }
  //수정처리
  @PostMapping("/productupdate")
  public String updateProc (ProductDTO productDTO) throws Exception {

    productService.update(productDTO);

    return "redirect:/productlist";
  }
  
  
  //삭제
  @GetMapping("/productdelete")
  public String deleteProc (Integer productId) throws Exception {

    productService.delete(productId);

    return "redirect:/productlist";
  }

}
더보기

▪ Model 객체

Spring MVC에서 컨트롤러에서 뷰로 데이터를 전달하는 데 사용되는 인터페이스

 

model.addAttribute("key", value) 메서드

뷰로 전달할 데이터를 설정

뷰에서는 전달받은 데이터를 사용하여 동적인 페이지를 생성

더보기

▪ insertForm (상품등록)

ProductDTO 객체를 생성하고, 이를 "productDTO"라는 이름으로 모델에 추가하여 뷰로 전달

 

▪ insertProc (상품등록 처리)

DTO를 받아서 Service를 통해 상품을 데이터베이스에 삽입한 후, 상품 목록을 보여주는 페이지로 리다이렉트

반응형