728x90
- 사용자에게 기능을 제공하려면 도메인과 사용자를 연결해 줄 표현 영역과 응용 영역이 필요.
- 응용 서비스
- 애플리케이션의 사용 사례(Use Case)를 구현하는 역할
- 주로 사용자의 요청을 처리하고, 도메인 객체 간의 상호 작용을 조정하여 트랜잭션 경계를 설정
- 응용 서비스는 도메인 로직을 직접적으로 구현하지 않고, 도메인 계층의 서비스와 리포지토리를 사용하여 해당 기능을 수행
// 도메인 로직을 직접 구현하지 않는다
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private ProductService productService;
@Transactional // 트랜잭션 경계 설정
public void createOrder(Long productId, int quantity) {
// 상품 조회
Product product = productService.getProduct(productId);
// 재고 확인
if (product.getStock() < quantity) {
throw new InsufficientStockException("재고가 부족합니다.");
}
// 주문 생성
Order order = new Order();
order.setProduct(product);
order.setQuantity(quantity);
order.setStatus(OrderStatus.CREATED);
// 주문 저장
orderRepository.save(order);
// 재고 감소
product.decreaseStock(quantity);
productService.saveProduct(product);
// 트랜잭션 종료
}
// 기타 주문 관련 메서드들...
}
- 표현 영역
- 표현 영역은 사용자 인터페이스(UI)와 애플리케이션 간의 통신을 담당
- 사용자의 요청을 처리하고, 애플리케이션의 상태를 사용자에게 표시
- 주로 HTTP 요청을 받아들이고, 적절한 응답을 생성하여 사용자에게 반환하는 역할을 합니다.
- 컨트롤러는 표현 영역에서 요청을 처리하고, 비즈니스 로직을 실행하기 위해 응용 서비스를 호출
@RestController @RequestMapping("/api/password") public class PasswordController { private final UserService userService; @Autowired public PasswordController(UserService userService) { this.userService = userService; } @PostMapping("/change") public ResponseEntity<String> changePassword(@RequestBody ChangePasswordRequest request) { // 사용자 인증 (현재 암호 확인) Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); String username = authentication.getName(); User user = userService.findByUsername(username); if (user == null || !passwordEncoder.matches(request.getCurrentPassword(), user.getPassword())) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("현재 암호가 일치하지 않습니다."); } // 새로운 암호로 변경 userService.changePassword(user, request.getNewPassword()); return ResponseEntity.ok("암호가 성공적으로 변경되었습니다."); } }
- 값 검증
// 응용 서비스에서 진행
@Transactional
public void registerUser(UserRegistrationRequest request) {
List<String> validationErrors = new ArrayList<>();
// 사용자명 검증
if (StringUtils.isEmpty(request.getUsername())) {
validationErrors.add("사용자명은 필수 입력값입니다.");
} else if (userRepository.existsByUsername(request.getUsername())) {
validationErrors.add("이미 사용 중인 사용자명입니다.");
}
// 비밀번호 검증
if (StringUtils.isEmpty(request.getPassword())) {
validationErrors.add("암호는 필수 입력값입니다.");
} else if (request.getPassword().length() < 6) {
validationErrors.add("암호는 최소 6자 이상이어야 합니다.");
}
// 검증 오류가 있으면 예외를 던집니다.
if (!validationErrors.isEmpty()) {
throw new ValidationException(validationErrors);
}
// 유저 생성 및 저장
User newUser = new User();
newUser.setUsername(request.getUsername());
newUser.setPassword(request.getPassword());
userRepository.save(newUser);
}
}
- 권한 검사 ( Spring Security ) → 따로 학습필요.
- Spring Security + Spring AOP 를 사용한 권한 체크
- Spring AOP를 사용하여 메서드 호출 이전에 보안 검사를 수행
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin();
}
}
@RestController
public class HomeController {
@GetMapping("/")
public String home() {
return "Welcome to the Home Page";
}
@GetMapping("/admin")
@PreAuthorize("hasRole('ADMIN')") // 권한 체크
public String admin() {
return "Welcome to the Admin Page";
}
}
728x90
'Books > 도메인 주도 개발 시작하기' 카테고리의 다른 글
Chapter10. 이벤트 (0) | 2024.04.17 |
---|---|
Chapter7~8. 도메인서비스 ~ 애그리거트 트랜잭션 관리 (0) | 2024.04.10 |
Chapter5. 스프링 데이터 JPA를 이용한 조회 기능 (0) | 2024.04.08 |
Chapter4. 리포지터리와 모델 구현 (0) | 2024.04.08 |
Chapter3. 애그리거트 (0) | 2024.04.07 |
댓글