[Java+SpringBoot+JPA] 기본 CRUD 구현하기 (1)java
🟢 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 메서드
Repository의 findAll 메서드를 사용하여 모든 엔터티를 가져오고, 이를 DTO 리스트로 변환하여 반환
▪ findOne 메서드
Repository의 findById 메서드를 사용하여 특정 엔터티를 가져오고, 이를 DTO로 변환하여 반환
▪ update 메서드
DTO를 사용하여 해당 상품을 찾고, 업데이트할 정보를 적용한 후 다시 저장
▪ delete 메서드
Repository의 deleteById 메서드를 사용하여 주어진 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를 통해 상품을 데이터베이스에 삽입한 후, 상품 목록을 보여주는 페이지로 리다이렉트