심화 스프링 프레임워크: 문제 해결과 실전 예시 모음

1. 빈 설정 및 DI (Dependency Injection)

 

문제: 의존성 주입을 이용해 서비스 클래스를 작성하고, @Autowired를 사용해 주입된 객체를 이용하는 방법을 구현하세요.

 

해결 방안:

@Service
public class OrderService {
    private final ProductRepository productRepository;

    // 생성자 주입
    @Autowired
    public OrderService(ProductRepository productRepository) {
        this.productRepository = productRepository;
    }

    public Product getProductById(Long id) {
        return productRepository.findById(id);
    }
}

 

@Autowired를 사용해 생성자에서 ProductRepository를 주입합니다. 이는 스프링이 자동으로 빈을 주입하는 방식 중 하나입니다.

 

2. 트랜잭션 관리

 

문제: 데이터베이스의 무결성을 유지하기 위해 트랜잭션을 사용하는 방법을 보여주세요.

 

해결 방안:

@Service
public class BankService {

    @Autowired
    private AccountRepository accountRepository;

    @Transactional
    public void transferMoney(Long fromAccountId, Long toAccountId, Double amount) {
        Account fromAccount = accountRepository.findById(fromAccountId);
        Account toAccount = accountRepository.findById(toAccountId);

        fromAccount.debit(amount);
        toAccount.credit(amount);

        accountRepository.save(fromAccount);
        accountRepository.save(toAccount);
    }
}

 

@Transactional 애노테이션을 사용하여 트랜잭션을 관리합니다. 메서드가 실행되는 동안 예외가 발생하면 트랜잭션이 롤백됩니다.

 

3. AOP(Aspect-Oriented Programming) 사용

 

문제: 메서드 실행 시간을 측정하기 위한 AOP를 작성하세요.

 

해결 방안:

@Aspect
@Component
public class LoggingAspect {

    @Around("execution(* com.example.service.*.*(..))")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();

        Object proceed = joinPoint.proceed();

        long executionTime = System.currentTimeMillis() - startTime;
        System.out.println(joinPoint.getSignature() + " executed in " + executionTime + "ms");

        return proceed;
    }
}

 

@Aspect@Around를 사용하여 특정 서비스 메서드의 실행 시간을 측정하는 AOP를 작성할 수 있습니다.

 

4. 프로파일 기반 설정

 

문제: 개발 환경(dev)과 운영 환경(prod)에 따라 다른 설정을 적용하는 방법을 구현하세요.

 

해결 방안:

@Configuration
@Profile("dev")
public class DevDatabaseConfig {

    @Bean
    public DataSource dataSource() {
        return new H2DataSource(); // H2 데이터베이스 사용
    }
}

@Configuration
@Profile("prod")
public class ProdDatabaseConfig {

    @Bean
    public DataSource dataSource() {
        return new MySQLDataSource(); // MySQL 데이터베이스 사용
    }
}

 

@Profile을 사용해 환경(dev, prod)에 따라 다른 빈을 로드하는 설정을 구현합니다.

 

5. REST API 개발

 

문제: RESTful 웹 서비스를 개발하고, GET 요청으로 특정 데이터를 조회하는 엔드포인트를 작성하세요.

 

해결 방안:

@RestController
@RequestMapping("/api/products")
public class ProductController {

    @Autowired
    private ProductService productService;

    @GetMapping("/{id}")
    public ResponseEntity<Product> getProduct(@PathVariable Long id) {
        Optional<Product> product = productService.getProductById(id);
        return product.map(ResponseEntity::ok)
                      .orElseGet(() -> ResponseEntity.notFound().build());
    }
}

 

@RestController, @GetMapping을 사용해 RESTful API를 구현합니다. 제품 ID에 따라 제품 정보를 조회합니다.

 

6. 테스트 작성

 

문제: 스프링의 의존성 주입을 사용하여 서비스를 테스트하는 방법을 보여주세요.

 

해결 방안:

@SpringBootTest
public class ProductServiceTest {

    @Autowired
    private ProductService productService;

    @Test
    public void testGetProduct() {
        Product product = productService.getProductById(1L);
        assertNotNull(product);
        assertEquals("Product1", product.getName());
    }
}

 

@SpringBootTest를 사용해 스프링 컨텍스트에서 서비스를 테스트합니다.

 

7. 스프링 시큐리티를 사용한 인증

 

문제: 스프링 시큐리티를 사용해 로그인 인증 기능을 구현하세요.

 

해결 방안:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("user").password("{noop}password").roles("USER")
            .and()
            .withUser("admin").password("{noop}admin").roles("ADMIN");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/admin/**").hasRole("ADMIN")
            .antMatchers("/**").permitAll()
            .and()
            .formLogin();
    }
}

 

@EnableWebSecurityHttpSecurity를 사용해 권한에 따라 다른 페이지 접근을 제한합니다.

 

8. 파일 업로드 처리

 

문제: MultipartFile을 사용하여 파일 업로드 기능을 구현하세요.

 

해결 방안:

@RestController
public class FileUploadController {

    @PostMapping("/upload")
    public ResponseEntity<String> handleFileUpload(@RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            return ResponseEntity.badRequest().body("No file selected");
        }

        try {
            byte[] bytes = file.getBytes();
            Path path = Paths.get("uploads/" + file.getOriginalFilename());
            Files.write(path, bytes);

            return ResponseEntity.ok("File uploaded successfully");
        } catch (IOException e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }
}

 

MultipartFile을 사용해 파일 업로드 기능을 구현합니다.

 

9. 스케줄러 사용

 

문제: 주기적으로 특정 작업을 수행하는 스케줄러를 작성하세요.

 

해결 방안:

@Configuration
@EnableScheduling
public class SchedulingConfig {

    @Scheduled(cron = "0 0 * * * *")
    public void performTask() {
        System.out.println("Task performed at " + new Date());
    }
}

 

@Scheduled 애노테이션을 사용해 매 시간마다 작업이 실행되도록 설정합니다.

 

10. RabbitMQ를 사용한 메시지 큐

 

문제: RabbitMQ를 사용해 메시지를 송신하고, 메시지 수신을 처리하는 방법을 구현하세요.

 

해결 방안:

@Configuration
public class RabbitConfig {

    @Bean
    public Queue queue() {
        return new Queue("messageQueue", false);
    }
}

@RestController
public class MessageController {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @PostMapping("/send")
    public String sendMessage(@RequestParam String message) {
        rabbitTemplate.convertAndSend("messageQueue", message);
        return "Message sent";
    }
}

@Component
public class MessageListener {

    @RabbitListener(queues = "messageQueue")
    public void receiveMessage(String message) {
        System.out.println("Received message: " + message);
    }
}

 

RabbitTemplate@RabbitListener를 사용하여 메시지를 송신 및 수신하는 RabbitMQ 설정을 구현합니다.

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유