본문 바로가기
Books/도메인 주도 개발 시작하기

Chapter6. 응용 서비스와 표현 영역

by YoonJong 2024. 4. 8.
728x90

 

 

https://devfunny.tistory.com/872

  • 사용자에게 기능을 제공하려면 도메인과 사용자를 연결해 줄 표현 영역과 응용 영역이 필요.
  • 응용 서비스
    • 애플리케이션의 사용 사례(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

댓글