💡 Spring Boot JPA(Java Persistence API) - 데이터베이스를 쉽게 다루기 위한 ‘데이터 액세스 기술’로 ORM(Object-Relational Mapping) 기법을 사용하여 자바 애플리케이션에서 사용하는 객체와 관계형 데이터베이스 사이의 매핑을 관리하는 ORM 기술에 대한 API 표준 명세서(인터페이스) 의미합니다. - 이 API를 사용하여 개발자가 직접적인 SQL을 작성하지 않고도 데이터베이스에서 데이터를 저장, 업데이트, 삭제, 조회하는 등의 작업을 수행할 수 있게 해 줍니다. - JPA는 표준화된 API를 제공함으로써, 다양한 ORM 프레임워크(예: Hibernate, EclipseLink, OpenJPA 등)와의 호환성을 보장합니다. 이로 인해 개발자는 특정 ORM 프레임워크에 종속되지 않고 필요에 따라 다른 프레임워크로 쉽게 전환할 수 있습니다.
- 데이터베이스 스키마 생성 관련 동작을 제어합니다. 이 속성을 사용하면 Hibernate가 데이터베이스의 DDL(Data Definition Language)을 자동으로 생성하고 실행할 수 있습니다.
- 해당 속성은 개발 중에는 매우 편리하지만, 프로덕션 환경에서는 데이터 손실 위험이 있기에 ‘none’ 속성을 사용해야 합니다. - 또한 ‘create’ 속성을 사용하게 되면 테이블을 우선 DROP 하고 새로 생성하기에 적재한 데이터까지 사라질 수 있으니 주의해야 합니다.
옵션
설명
create
세션 팩토리가 시작될 때, 데이터베이스 드롭을 실행한 후 새로 생성합니다.
update
세션 팩토리가 시작될 때, 데이터베이스를 변경합니다.
create-drop
세션 팩토리가 시작될 때 데이터베이스를 드롭한 후 새로 생성하고, 세션 팩토리가 종료될 때 드롭합니다.
validate
세션 팩토리가 시작될 때 엔티티와 테이블이 매핑되어 있는지 검증합니다.
none
아무 작업도 실행하지 않습니다.
4. DDL-AUTO 속성을 테스트를 위해 Entity 생성
💡 DDL-AUTO 속성을 테스트를 위해 Entity 생성
- DDL-AUTO 속성 값으로 create를 사용했습니다. 그렇기에 객체(Object) 내에 지정한 값을 통해 데이터베이스 테이블이 자동으로 생성될 예정입니다. 추후 해당 내용은 아래에서 설명하겠습니다.
- Spring Data JPA에서 제공하는 기능 중 하나로 개발자가 데이터베이스와의 CRUD(Create, Read, Update, Delete) 연산을 더욱 쉽게 처리할 수 있도록 도와주는 인터페이스입니다.
- JpaRepository 인터페이스를 상속받은 인터페이스를 만들면, Spring Data JPA가 자동으로 해당 인터페이스의 구현체를 만들어서 Bean으로 등록해 줍니다. - 이를 통해 개발자는 SQL 쿼리를 직접 작성하지 않고도 메서드 이름만으로 데이터베이스 연산을 수행할 수 있게 됩니다.
4) JPA 구성 테스트 : JpaRepository 구성하기
💡 JPA 구성 테스트 : JpaRepository 구성하기
- 해당 환경은 4-Tier Architecture 기반의 환경에서 Repository는 JpaRepository를 상속받아서 재 구성합니다.
[ 더 알아보기 ]
💡 JpaRepository랑 CRUDRepository가 있는데 왜 JpaRepository를 사용하는 걸까? - JpaRepository를 사용하면 상속받고 있는 PagingAndSortingRepository, CRUDRepository, Repository 인터페이스를 사용할 수 있습니다.
💡 Entity 구성 이후 서버를 수행하였을 시 구성한 객체를 기반으로 테이블이 생성되었습니다.
2. 디렉터리 구조
디렉터리
설명
controller
사용자의 요청을 처리하는 레이어로, HTTP 요청을 받아 서비스 레이어에 작업을 위임하고 결과를 클라이언트에게 전달합니다.
entity
데이터베이스 테이블에 해당하는 클래스를 담는 레이어로, 이 클래스는 데이터베이스의 테이블과 매핑됩니다.
repository
데이터베이스와 관련된 연산을 처리하는 레이어로, 데이터베이스 CRUD(Create, Read, Update, Delete) 연산이 이 레이어에서 수행됩니다.
service
비즈니스 로직을 담당하는 레이어로, 컨트롤러로부터 요청을 받아 필요한 데이터를 리포지토리에서 가져와 처리하고 결과를 컨트롤러에게 반환합니다.
service.Impl
서비스 인터페이스를 구현하는 클래스를 담는 레이어로, 이 레이어에는 실제 비즈니스 로직이 구현되어 있습니다.
3. UserJpaRepository
💡 UserJpaRepository - Spring Data JPA에서 제공하는 JpaRepository 인터페이스를 상속받는 UserJpaRepository 인터페이스를 정의합니다 - JpaRepository 인터페이스는 JPA를 좀 더 쉽게 사용할 수 있도록 도와주며, CRUD(Create, Read, Update, Delete) 기능을 기본적으로 제공합니다.
package com.adjh.multiflex.jpa.repository;
import com.adjh.multiflex.jpa.entity.UserEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
/**
* JpaRepository를 기본적으로 활용하여 Repository 구성
*
* @author : jonghoon
* @fileName : UserCRUDRepository
* @since : 2/8/24
*/
@Repository
public interface UserJpaRepository extends JpaRepository<UserEntity, Long> {
}
4. UserSerivce
💡 UserSerivce
- 사용자 서비스에 대한 인터페이스를 정의합니다.
1. userList() : 사용자 리스트를 조회하는 메서드입니다. 2. saveUser(UserEntity userEntity) : 입력받은 UserEntity 객체를 이용하여 새로운 사용자를 등록하는 메서드입니다. 3. updateUser(UserEntity userEntity) : 입력받은 UserEntity 객체를 이용하여 기존 사용자의 정보를 업데이트하는 메서드입니다. 4. deleteUserByUserSq(long userSq) : 입력받은 사용자 번호(userSq)를 이용하여 해당 사용자를 삭제하는 메서드입니다.
package com.adjh.multiflex.jpa.service;
import com.adjh.multiflex.jpa.entity.UserEntity;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 사용자 서비스 인터페이스입니다.
*
* @author : jonghoon
* @fileName : UserService
* @since : 2/8/24
*/
@Service
public interface UserService {
List<UserEntity> userList(); // 사용자 리스트 조회
UserEntity saveUser(UserEntity userEntity); // 사용자 등록
UserEntity updateUser(UserEntity userEntity); // 사용자 수정
void deleteUserByUserSq(long userSq); // 사용자 삭제
}
5. UserServiceImpl
💡 UserServiceImpl - 해당 코드는 UserService 인터페이스를 기반으로 구현체를 구현합니다. 1. userList() - 이 메서드는 데이터베이스에서 모든 사용자의 목록을 검색합니다. - findAll()은 UserJpaRepository에서 제공하는 인터페이스입니다.
2. saveUser(UserEntity userEntity) - 이 메서드는 새로운 사용자를 데이터베이스에 저장합니다. - save()는 UserJpaRepository에서 제공하는 인터페이스입니다.
3. updateUser(UserEntity userEntity): - 이 메서드는 데이터베이스에서 기존 사용자의 세부 사항을 업데이트합니다. - findById()를 통해서 사용자 정보를 조회한 뒤 save()를 통해 데이터를 수정합니다.
4. deleteUserByUserSq(long userSq): - 이 메소드는 ID를 기반으로 데이터베이스에서 사용자를 삭제합니다. - deleteById()는 UserJpaRepository에서 제공하는 인터페이스입니다.
💡 UserJpaRepository는 CRUDRepository <T, ID> 인터페이스를 상속받기에 해당 기능을 모두 사용할 수 있습니다.
리턴 타입
메서드
설명
<S extends T>S
save(S entity)
주어진 엔티티를 저장합니다.
Optional<T>
findById(ID id)
id로 엔티티를 검색합니다.
void
deleteById(ID id)
주어진 id의 엔티티를 삭제합니다.
package com.adjh.multiflex.jpa.service.impl;
import com.adjh.multiflex.jpa.entity.UserEntity;
import com.adjh.multiflex.jpa.repository.UserJpaRepository;
import com.adjh.multiflex.jpa.service.UserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Objects;
/**
* 사용자 인터페이스의 구현체입니다.
*
* @author : jonghoon
* @fileName : UserServiceImpl
* @since : 2/8/24
*/
@Service
public class UserServiceImpl implements UserService {
private final UserJpaRepository userJpaRepository;
public UserServiceImpl(UserJpaRepository userJpaRepository) {
this.userJpaRepository = userJpaRepository;
}
/**
* 사용자 리스트 조회
*
* @return
*/
@Override
@Transactional(readOnly = true)
public List<UserEntity> userList() {
return (List<UserEntity>) userJpaRepository.findAll();
}
/**
* 사용자 등록
*
* @param userEntity
* @return
*/
@Override
@Transactional
public UserEntity saveUser(UserEntity userEntity) {
return userJpaRepository.save(userEntity);
}
/**
* 사용자 수정
*
* @param userEntity
* @return
*/
@Override
@Transactional
public UserEntity updateUser(UserEntity userEntity) {
UserEntity user = userJpaRepository.findById(userEntity.getUserSq()).get();
UserEntity resultEntity = UserEntity.builder().build();
if (Objects.nonNull(user.getUserNm()) && !"".equalsIgnoreCase(user.getUserNm())) {
resultEntity = userEntity.toBuilder().userNm(user.getUserNm()).build();
}
if (Objects.nonNull(user.getUserEmail()) && !"".equalsIgnoreCase(user.getUserEmail())) {
resultEntity = userEntity.toBuilder().userEmail(user.getUserEmail()).build();
}
if (Objects.nonNull(user.getUserSt()) && !"".equalsIgnoreCase(user.getUserSt())) {
resultEntity = userEntity.toBuilder().userEmail(user.getUserSt()).build();
}
return userJpaRepository.save(resultEntity);
}
/**
* 사용자 삭제
*
* @param userSq
*/
@Override
@Transactional
public void deleteUserByUserSq(long userSq) {
userJpaRepository.deleteById(userSq);
}
}
6. UserController
💡 UserController
HTTP Method
엔드포인트
메서드
설명
POST
/api/v1/user/users
selectUserList
UserJpaRepository 인터페이스를 활용하여 사용자를 리스트를 조회합니다
POST
/api/v1/user/user
userSave
UserJpaRepository 인터페이스를 활용하여 사용자를 등록합니다
PUT
/api/v1/user/user
updateUser
UserJpaRepository 인터페이스를 활용하여 사용자를 수정합니다
DELETE
/api/v1/user/user
deleteUser
UserJpaRepository 인터페이스를 활용하여 사용자를 삭제합니다.
package com.adjh.multiflex.jpa.controller;
import com.adjh.multiflex.jpa.entity.UserEntity;
import com.adjh.multiflex.jpa.service.UserService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* Please explain the class!!
*
* @author : jonghoon
* @fileName : UserController
* @since : 2/8/24
*/
@RequestMapping("/api/v1/user")
@RestController
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
/**
* @return
*/
@PostMapping("/users")
public ResponseEntity<Object> selectUserList() {
List<UserEntity> userEntityList = userService.userList();
return new ResponseEntity<>(userEntityList, HttpStatus.OK);
}
/**
* 사용자 등록
*
* @param userEntity
* @return
*/
@PostMapping("/user")
public ResponseEntity<Object> userSave(@RequestBody UserEntity userEntity) {
UserEntity result = userService.saveUser(userEntity);
return new ResponseEntity<>(result, HttpStatus.OK);
}
/**
* 사용자 수정
*
* @param userEntity
* @return
*/
@PutMapping("/user")
public ResponseEntity<Object> updateUser(@RequestBody UserEntity userEntity) {
UserEntity result = userService.updateUser(userEntity);
return new ResponseEntity<>(result, HttpStatus.OK);
}
/**
* 사용자 삭제
*
* @param userSq
* @return
*/
@DeleteMapping("/user")
public ResponseEntity<Object> deleteUser(@RequestParam long userSq) {
userService.deleteUserByUserSq(userSq);
return new ResponseEntity<>(HttpStatus.OK);
}
}