제대로 강의를 듣기 전에 데이터 접근 기술을 배우기 위한 기본 소스 코드를 살펴본다.
public interface ItemRepository {
Item save(Item item);
void update(Long itemId, ItemUpdateDto updateParam);
Optional<Item> findById(Long id);
List<Item> findAll(ItemSearchCond cond); //검색 조건
}
DTO(data transfer object)
- 데이터 전송 객체
- DTO는 기능은 없고 데이터를 전달만 하는 용도로 사용되는 객체를 의미
- DTO에 기능이 없어야만 하는 것은 아님. 객체의 주 목적이 데이터를 전송하는 것이라면 DTO라고 할 수 있다.
- 객체 이름에 DTO를 꼭 붙여야 하는 것은 아니지만, 붙여두면 용도를 알 수 있다는 장점이 있다.
- 이런 규칙은 정해진 것이 없어서, 해당 프로젝트 안에서 일관성 있게 규칙을 정하면 된다.
- DTO의 위치는 마지막으로 호출되는 위치로 둔다. 마지막으로 끝나는 위치.
검색 기능
@Override
public List<Item> findAll(ItemSearchCond cond) {
String itemName = cond.getItemName();
Integer maxPrice = cond.getMaxPrice();
return store.values().stream()
.filter(item -> {
if (ObjectUtils.isEmpty(itemName)) { //itemName이 없으면
return true; //무조건 가져오기
}
return item.getItemName().contains(itemName); //itemName을 포함하고 있으면 리턴
}).filter(item -> {
if (maxPrice == null) { //maxPrice가 없으면 무조건 리턴
return true;
}
return item.getPrice() <= maxPrice; //maxPrice보다 작으면 리턴
})
.collect(Collectors.toList());
}
//검색 기능 테스트
@Test
void findItems() {
//given
Item item1 = new Item("itemA-1", 10000, 10);
Item item2 = new Item("itemA-2", 20000, 20);
Item item3 = new Item("itemB-1", 30000, 30);
itemRepository.save(item1);
itemRepository.save(item2);
itemRepository.save(item3);
//둘 다 없음 검증
test(null, null, item1, item2, item3);
test("", null, item1, item2, item3); //isEmpty()가 빈 문자열의 경우에도 True로 반환해서
//itemName 검증
test("itemA", null, item1, item2);
test("temA", null, item1, item2);
test("itemB", null, item3);
//maxPrice 검증
test(null, 10000, item1);
//둘 다 있음 검증
test("itemA", 10000, item1);
}
서버를 띄우면 만들어지는 샘플 데이터 - 없으면 서버를 만들 때마다 계속 입력해야함. (지금은 메모리라서 서버를 내리면 데이터가 제거)
@Slf4j
@RequiredArgsConstructor
public class TestDataInit {
private final ItemRepository itemRepository;
/**
* 확인용 초기 데이터 추가
*/
@EventListener(ApplicationReadyEvent.class)
public void initData() { //서버를 띄우면 만들어지는 샘플 데이터
log.info("test data init");
itemRepository.save(new Item("itemA", 10000, 10));
itemRepository.save(new Item("itemB", 20000, 20));
}
}
@EventListener(ApplicationReadyEvent.class)
- 스프링 컨테이너가 완전히 초기화를 다 끝내고 실행 준비가 되었을 때 발생하는 이벤트. 스프링이 이 시점에 이 애노테이션이 붙은 initData()를 호출해준다.
@Import(MemoryConfig.class)
@SpringBootApplication(scanBasePackages = "hello.itemservice.web")
public class ItemServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ItemServiceApplication.class, args);
}
@Bean
@Profile("local")
public TestDataInit testDataInit(ItemRepository itemRepository) {
return new TestDataInit(itemRepository);
}
}
- @Import(MemoryConfig.class)
- MemoryConfig를 설정 파일로 사용
- scanBasePackages = "hello.itemService.web
- 이 프로젝트에서는 컨트롤러만 컴포넌트 스캔을 사용하고, 나머지는 직접 수동으로 빈을 등록해서, 컴포넌트 스캔 경로를 hello.itemService.web의 하위로 지정한 것이다.
- @Profile("local")
- 특정 프로필의 경우에만 해당 스프링 빈을 등록한다. 여기서는 local이라는 이름의 프로필이 사용되는 경우에만 testDatainit이라는 스프링 빈을 등록한다.
프로필
스프링은 로딩 시점에 application.properties의 'spring.profiles.active' 속성을 읽어서 프로필로 사용한다.
이 프로필은 로컬(내 PC), 운영 환경, 테스트 실행 등등 다양한 환경에 따라서 다른 설정을 할 때 사용하는 정보이다.
프로필을 지정하지 않으면 'default'라는 이름 프로필을 사용한다.
application.properties에 아래와 같이 작성하면 local이라는 프로필을 사용다.
spring.profiles.active=local
초기화 데이터 덕분에 편리한 점도 있지만, 테스트 케이스를 실행할 때는 문제가 될 수 있다. 테스트에서 이런 데이터가 들어 있다면 오류가 발생할 수 있다.
그래서 test에 있는 application.properties에 아래와 같이 작성한다.
spring.profiles.active=test
데이터베이스 생성 (H2)
drop table if exists item CASCADE;
create table item
(
id bigint generated by default as identity,
item_name varchar(10),
price integer,
quantity integer,
primary key (id)
);
여기서 id 옆에 'generated by default as identity'는 기본 키 생성을 데이터베이스에 위임하는 방식이다. 주 키로 사용되는 id는 개발자가 직접 직정하는 것이 아니라, 비워두고 저장하면 데이터베이서가 순서대로 증가하는 값을 사용해서 넣어준다.
데이터베이스 기본 키의 3가지 조건
- null값은 허용X
- 유일해야 한다.
- 변해선 안된다.
테이블의 기본 키 선택 전략
- 자연 키 (natural key)
- 비즈니스에 의미가 있는 키
- 예: 주민등록번호, 이메일, 전화번호
- 대리 키 (surrogate key)
- 비즈니스와 관련 없는 임의로 만들어진 키, 대체 키로도 불림
- 예: 오라클 시퀀스, auto_increment, identity, 키 생성 테이블 사용
- 자연 키보다는 대리 키 사용을 권장
- 자연 키는 바뀔 수도 있다. 주민등록번호도 바뀔 수도 있다..
'Spring' 카테고리의 다른 글
[Spring DB2] 데이터 접근 기술 - 스프링 JdbcTemplate-2 (1) | 2024.03.14 |
---|---|
[Spring DB2] 데이터 접근 기술 - 스프링 JdbcTemplate-1 (1) | 2024.03.14 |
[Spring DB 1편 듣고 복습, 토이 프로젝트 수정] 6. 스프링과 문제 해결 - 예외 처리, 반복 (2) | 2024.03.09 |
[Spring DB 1편 듣고 복습, 토이 프로젝트 수정] 5. 자바 예외 이해 (4) | 2024.03.02 |
[Spring DB 1편 듣고 복습, 토이 프로젝트 수정] 4. 스프링과 문제 해결 - 트랜잭션 - 2 (0) | 2024.02.29 |