Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- 디자인강의
- 디자인챌린지
- 부트캠프
- UXUI기초정복
- 내일배움캠프
- 국비지원
- baekjoon
- UXUIPrimary
- 오블완
- 백준
- OPENPATH
- 내일배움카드
- 객체지향
- 백엔드
- 오픈챌린지
- Spring
- Be
- 오픈패스
- 티스토리챌린지
- 환급챌린지
- Java
- 백엔드개발자
- UXUI챌린지
- 백엔드 부트캠프
- KDT
- 국비지원교육
- 디자인교육
- 국비지원취업
- 패스트캠퍼스
- mysql
Archives
- Today
- Total
군만두의 IT 공부 일지
[3주차] 내일배움캠프 Spring Java - AI 활용 비즈니스 프로젝트 DAY4 - Store CRUD 구현 본문
개발일지/스파르타코딩클럽
[3주차] 내일배움캠프 Spring Java - AI 활용 비즈니스 프로젝트 DAY4 - Store CRUD 구현
mandus 2025. 2. 17. 15:28
주문 관리 플랫폼 프로젝트에서 Store의 CRUD 기능을 담당하여 구현했다. 구현한 코드와 개발 초기에 팀원들과의 의논한 사항들을 정리하려고 한다.
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/stores")
public class StoreController {
private final StoreService storeService;
// 새로운 가게 생성
@PostMapping
public ResponseEntity<Store> createStore(@RequestBody StoreRequestDto storeRequestDto) {
Store store = storeService.createStore(storeRequestDto);
return ResponseEntity.ok(store);
}
// 등록된 모든 가게의 리스트 반환
@GetMapping
public ResponseEntity<List<Store>> getAllStores() {
List<Store> stores = storeService.getAllStores();
return ResponseEntity.ok(stores);
}
// 특정 ID를 가진 가게의 상세 정보 조회
@GetMapping("/{id}")
public ResponseEntity<Store> getStoreById(@PathVariable String id) {
return storeService.getStoreById(id)
.map(ResponseEntity::ok)
.orElseGet(() -> ResponseEntity.notFound().build());
}
// 특정 ID를 가진 가게의 정보 업데이트
@PutMapping("/{id}")
public ResponseEntity<Store> updateStore(@PathVariable String id, @RequestBody StoreRequestDto storeRequestDto) {
Store updatedStore = storeService.updateStore(id, storeRequestDto);
return ResponseEntity.ok(updatedStore);
}
// 특정 ID를 가진 가게 삭제
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteStore(@PathVariable String id) {
storeService.deleteStore(id);
return ResponseEntity.ok().build();
}
}
- StoreController
- POST /api/v1/stores: 새로운 가게를 생성한다.
- GET /api/v1/stores, GET /api/v1/stores/{id}: 전체 가게 리스트와 ID별 가게 정보를 조회한다.
- PUT /api/v1/stores/{id}: 지정된 ID의 가게 정보를 업데이트한다.
- DELETE /api/v1/stores/{id}: 지정된 ID의 가게를 삭제한다.
@Service
@RequiredArgsConstructor
public class StoreService {
private final StoreRepository storeRepository;
// 새로운 가게 생성
@Transactional
public Store createStore(StoreRequestDto dto) {
Store store = new Store();
store.setId(dto.getCategoryId().toString());
store.setName(dto.getName());
store.setCategoryId(dto.getCategoryId().toString());
store.setAddress1(dto.getAddress1());
store.setPhone(dto.getPhone());
store.setOperatingHours(dto.getOperatingHours());
store.setClosedDays(dto.getClosedDays());
store.setPictureUrl(dto.getPictureUrl());
store.setStatus(dto.getStatus());
store.setDeliveryType(dto.getDeliveryType().toString());
store.setDeliveryArea(dto.getDeliveryArea());
store.setMinimumOrderPrice(dto.getMinimumOrderPrice());
store.setDeliveryTip(dto.getDeliveryTip());
storeRepository.save(store);
return store;
}
// 등록된 모든 가게 조회
@Transactional(readOnly = true)
public List<Store> getAllStores() {
return storeRepository.findAll();
}
// 특정 ID를 가진 가게의 상세 정보 조회
@Transactional(readOnly = true)
public Optional<Store> getStoreById(String id) {
return storeRepository.findById(id);
}
// 특정 ID를 가진 가게의 정보 업데이트
@Transactional
public Store updateStore(String id, StoreRequestDto dto) {
Store store = storeRepository.findById(id).orElseThrow(() -> new RuntimeException("가게를 찾을 수 없습니다."));
store.setName(dto.getName());
store.setCategoryId(dto.getCategoryId().toString());
store.setAddress1(dto.getAddress1());
store.setAddress2(dto.getAddress2());
store.setAddress3(dto.getAddress3());
store.setAddress4(dto.getAddress4());
store.setAddress5(dto.getAddress5());
store.setPhone(dto.getPhone());
store.setOperatingHours(dto.getOperatingHours());
store.setClosedDays(dto.getClosedDays());
store.setPictureUrl(dto.getPictureUrl());
store.setDeliveryType(dto.getDeliveryType().toString());
store.setDeliveryArea(dto.getDeliveryArea());
store.setMinimumOrderPrice(dto.getMinimumOrderPrice());
store.setDeliveryTip(dto.getDeliveryTip());
store.setStatus(dto.getStatus());
storeRepository.save(store);
return store;
}
// 특정 ID를 가진 가게 삭제
@Transactional
public void deleteStore(String id) {
storeRepository.deleteById(id);
}
}
- StoreService
- 가게 생성, 조회, 업데이트, 삭제 로직을 구현한다.
- @Transactional 어노테이션을 사용하여 데이터 일관성을 보장한다.
public interface StoreRepository extends JpaRepository<Store, String> {
}
- StoreRepository
- Spring Data JPA를 이용하여 CRUD 기능을 구현한다.
해당 내용을 구현하면서 팀원들과 논의할 사항이 많다는 생각이 들었다. 각자 기능을 구현하기 전에 정했으면 좋았을텐데, 당시에는 생각하지 못했었다.
1. createdAt 같은 필드에 대해서 JPA Auditing으로 자동 처리할 것인지?
데이터를 일관적으로 관리하기 위해서 JPA Auditing을 적용하기로 했다.
2. 디렉토리 구조를 계층별로 할 것인지, 아니면 도메인별로 할 것인지?
구조를 명확하게 파악하기 쉽기 때문에 도메인 구조를 선택했다.
3. 예외 처리 전략을 어떻게 할 것인지, Global Exception Handler로 할 것인지?
튜터님의 조언에 따라 Global Exception Handler을 하나 두고, Custom Exception을 설정하여 예외 처리하기로 했다.
4. Swagger을 적용할 것인지?
기능 구현이 완료되면 고려하기로 했다.
5. 성공 응답, 실패 응답을 통일하는 것이 어떤지?
공통 DTO를 구성하여 응답의 형식을 통일하기로 했다.
그리고 서로 코드 구현 방식이 다르기 때문에 코드 컨벤션도 정했다.
- 생성자를 사용하는 대신 @RequiredArgsConstructor으로 의존성 주입을 통일한다.
- 엔티티에서 @Setter 사용을 지양한다.
- @Transactional은 개인의 스타일에 맞춰 사용하되, 적절하게 사용한다.
또한, CRUD 기능 외에 다음 기능들을 구현할 예정이다.
- 가게 주문 확인 및 알림
- 가게 리뷰 관리
- 카테고리별 가게 조회
- 배달 가능 지역 설정
프로젝트가 금방 끝날 줄 알았는데, 해야 할 일이 많은 것 같다. 그리고 팀원들과 프로젝트하기 전에 정해야 할 것들을 잘 정리해야겠다.
프로젝트 초기에 정하면 좋을 것들
- 역할 분담
- 코드 컨벤션
- 기술 스택 결정
- 의사소통 도구
- 목표와 마일스톤
사용한 어노테이션
- @RestController: 클래스가 RESTful 웹 서비스의 컨트롤러 역할을 수행함을 나타낸다. 클라이언트의 HTTP 요청을 처리하고, JSON이나 XML 형태로 데이터를 응답한다.
- @RequiredArgsConstructor: 초기화되지 않은 final 필드나 @NonNull 어노테이션이 붙은 필드에 대한 생성자를 자동으로 생성한다. 생성자를 통한 의존성 주입(Dependency Injection)을 간단하게 할 수 있다.
- @Transactional: 메소드, 클래스, 인터페이스에 적용되어 선언적 트랜잭션 관리가 가능하다. 메소드를 트랜잭션 범위 내에서 실행하게 하며, 실행 중 예외가 발생하면 자동으로 롤백한다.
- JpaRepository 인터페이스: Spring Data JPA를 사용하여 리포지토리 계층을 구현할 때, 이 인터페이스를 확장함으로써 기본적인 CRUD 연산을 자동으로 제공받는다. 데이터 접근 쿼리 메소드도 쉽게 정의할 수 있다.
참고자료
1) Letsdev, "Spring: 예외 처리 - 쉽게 관심사 나누기 Global Exception Handler(Controller Advice)", 2023.05.14, https://velog.io/@letsdev/Spring-예외-처리-쉽게-관심사-나누기-Global-Exception-HandlerController-Advice
'개발일지 > 스파르타코딩클럽' 카테고리의 다른 글
[3주차] 내일배움캠프 Spring Java - AI 활용 비즈니스 프로젝트 DAY5 - Store 엔티티&서비스 코드 수정하기 (1) | 2025.02.18 |
---|---|
[2주차] 내일배움캠프 Spring Java - AI 활용 비즈니스 프로젝트 DAY3 - Issues & PR Template 설정하기 (0) | 2025.02.14 |
[2주차] 내일배움캠프 Spring Java - AI 활용 비즈니스 프로젝트 DAY2 - postgreSQL 설치하기 (0) | 2025.02.13 |
[2주차] 내일배움캠프 Spring Java - AI 활용 비즈니스 프로젝트 DAY1 - S.A 작성하기 (0) | 2025.02.12 |
[2주차] 내일배움캠프 Spring Java 심화 부트캠프 3기 - MSA (0) | 2025.02.11 |
Comments