[STS3] Component, Service, Repository, Controller

Shy·2024년 5월 10일

STS

목록 보기
2/8

1. Component

@Component는 스프링 프레임워크에서 제공하는 애노테이션 중 하나로, 주로 컴포넌트를 자동으로 스프링 빈으로 등록하기 위해 사용된다. 이것은 스프링의 어노테이션 기반 구성 메커니즘의 일부이다.

특징과 동작 방식

  1. 빈의 자동 등록
    • 스프링 컨테이너는 패키지를 스캔하여 @Component가 달린 클래스들을 자동으로 스프링 빈으로 등록한다.
    • 빈의 이름은 기본적으로 클래스 이름의 첫 글자를 소문자로 바꾼 값으로 설정된다.
  2. 스테레오타입 애노테이션
    • @Component는 다른 세 가지 스테레오타입 애노테이션(@Service, @Repository, @Controller)의 기본 애노테이션이기도 하다.
    • 이 세 애노테이션은 특정 역할을 가진 컴포넌트들을 식별하고 의미를 부여하는 데 사용된다.

사용 예시

<!-- xml 파일-->
<context:component-scan base-package="com.example.components" />
import org.springframework.stereotype.Component;

@Component
public class MyComponent {
    public void doSomething() {
        System.out.println("MyComponent is doing something.");
    }
}
  • @Component로 마킹된 MyComponent는 스프링 컨테이너에 자동으로 빈으로 등록된다.
  • 스프링 설정 파일에서 <context:component-scan>을 사용하여 특정 패키지 내의 @Component를 스캔하도록 지정한다.

관련 Annotation

  • @Service: 비즈니스 로직이 포함된 서비스 컴포넌트를 나타낸다. @Component의 파생형으로, 비즈니스 로직 클래스에 명시적 의미를 부여하기 위해 사용된다.
  • @Repository: 데이터 접근 계층의 컴포넌트를 나타낸다. 이 애노테이션을 사용하면 예외 변환 등 데이터 관련 기능을 추가로 제공한다.
  • @Controller: 웹 컨트롤러 계층을 나타낸다. 스프링 MVC의 요청 처리 메커니즘과 연동된다.

장점과 단점

  1. 장점
    • 자동화: 스프링 빈을 자동으로 스캔하고 등록해 개발자의 수동 작업을 줄인다.
    • 명확한 의미: 빈의 역할에 맞는 애노테이션을 사용하면 코드 가독성이 향상된다.
  2. 단점
    • 자동 스캔의 오버헤드: 너무 많은 패키지를 스캔하면 애플리케이션 시작 시에 성능 문제가 발생할 수 있다.
    • 설정의 복잡성: 자동화된 구성이 명시적인 XML 구성에 비해 동작 방식을 파악하기 어려울 수 있다.
  3. 결론
    • @Component 애노테이션은 애플리케이션 구조를 개선하고 자동화를 통해 개발자 경험을 향상시키는 도구이다. 빈의 명확한 역할이 필요한 경우 다른 스테레오타입 애노테이션과 함께 사용하여 코드를 더 명확하고 유지 관리하기 쉽게 만들 수 있다.

2. Service

@Service는 스프링 프레임워크에서 제공하는 어노테이션 중 하나로, 주로 서비스 계층의 빈을 표시하기 위해 사용된다. 이 어노테이션은 비즈니스 로직이 포함된 서비스 클래스를 나타내고, 특정 의미를 가진 스테레오타입 어노테이션 중 하나이다.

특징과 동작 방식

  1. 의미 부여
    • 서비스 계층의 컴포넌트로서 비즈니스 로직을 담당하는 클래스를 나타낸다.
    • @Component와 기능적으로 동일하지만, 특정 역할을 나타내는 의미를 부여하기 위해 사용된다.
  2. 스프링 빈 등록
    • 스프링 컨테이너는 @Service로 마킹된 클래스를 찾아 빈으로 등록한다.
    • 이러한 과정은 <context:component-scan> 또는 @SpringBootApplication을 통한 패키지 스캔으로 이루어진다.

사용 예시

<!-- xml 파일-->
<context:component-scan base-package="com.example.services" />
import org.springframework.stereotype.Service;

@Service
public class MyService {
    public void performBusinessLogic() {
        System.out.println("Performing some business logic...");
    }
}
  • 위 코드에서 @Service로 표시된 MyService는 자동으로 스프링 컨테이너에 등록된다.
  • 스프링 설정 파일이나 어플리케이션 클래스에서 컴포넌트 스캔을 통해 이 클래스를 빈으로 등록한다.

장점

  • 명확한 역할 구분(모듈화)
    • 서비스 계층의 클래스임을 명확하게 나타내므로, 코드 가독성이 향상된다.
    • 컨트롤러, 리포지토리, 서비스 등 각 계층의 역할이 명확해진다.
  • 자동화된 빈 등록
    • 자동으로 빈으로 등록되므로, 수동으로 빈을 등록하는 번거로움이 없다.
  • 유지보수 및 테스트 용이성
    • @Service로 명시된 클래스는 의존성 주입을 통해 테스트와 유지보수에 용이하다.
    • (테스트를 위해 Mock 객체로 레포지토리 등을 교체해 비즈니스 로직만 독립적으로 검증할 수 있다.)

Mock 객체는 행위를 검증하기 위해 사용되는 객체를 지칭하며, 수동으로 만들 수도 있고, Mock 프레임워크를 이용할 수도 있다. Mock 객체 라는 단어는 행위기반테스트를 위해 사용되는 객체보다 더 넓은 일반적인 '가상 임시 구현체'의 의미로 사용되는 경우가 더 많다.

사용 사례

  1. 비즈니스 로직 구현
    • 주로 비즈니스 로직을 처리하는 클래스에 적용한다.
    • 데이터의 가공, 연산, 서비스 제공 등을 수행하며, 여러 레포지토리나 다른 서비스 클래스의 조합을 관리한다.
  2. 트랜잭션 관리
    • 데이터베이스와의 작업에 있어 트랜잭션 처리를 중앙 집중적으로 관리해야 할 때 사용된다.
    • @Transactional 어노테이션을 함께 사용하여, 서비스 계층에서 데이터의 일관성 보장을 위한 트랜잭션 경계를 설정할 수 있다.
  3. 중재자 역할
    • 컨트롤러에서 다양한 요청이 들어올 때, 컨트롤러와 데이터 접근 계층(레포지토리) 사이에서 중재자 역할을 한다.
    • 이를 통해 컨트롤러는 간단한 API 논리에 집중하고, 복잡한 비즈니스 로직은 서비스 계층에서 처리한다.
  4. 다른 서비스 호출
    • 하나의 서비스가 다른 서비스로부터 데이터를 가져오거나, 여러 서비스 간의 협업이 필요한 경우, 이를 조정하는 클래스에 @Service를 사용한다.

예시 코드

import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;

@Service
public class UserService {
    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User getUserById(Long id) {
        return userRepository.findById(id).orElse(null);
    }

    public void updateUser(User user) {
        userRepository.save(user);
    }
}
  • @Service: UserService 클래스를 서비스 빈으로 등록한다.
  • 의존성 주입: UserRepository를 서비스 클래스에 주입하여 데이터 접근을 담당한다.

다른 스테레오타입 어노테이션과의 관계

  • @Component: 모든 스테레오타입 애노테이션의 기본이 되는 어노테이션이다.
  • @Repository: 데이터 접근 계층의 컴포넌트를 표시하며, 데이터 예외 변환 기능을 제공한다.
  • @Controller: 웹 컨트롤러 계층을 나타내며, 스프링 MVC와 연동된다.

@Service는 스프링 애플리케이션에서 명확한 역할 구분을 통해 코드 가독성을 높이고, 자동 빈 등록을 통해 개발 생산성을 높이는 데 기여하는 중요한 어노테이션이다.

3. Repository

@Repository는 스프링 프레임워크의 데이터 액세스 계층을 위한 어노테이션이다. 이 어노테이션은 데이터베이스와의 상호작용을 담당하는 클래스(주로 DAO 또는 리포지토리)에 붙여 사용하며, 스프링이 자동으로 빈으로 등록할 수 있도록 도와준다. 또한, 이 어노테이션을 사용하면 데이터 액세스 예외를 처리하는 추가 기능도 함께 제공된다.

주요 특징

  1. 데이터 액세스 계층 식별
    • 데이터베이스와의 상호작용을 관리하는 클래스에 사용된다.
    • @Component의 하위 어노테이션이기 때문에 스프링 컨테이너에서 빈으로 자동 등록된다.
  2. 예외 변환
    • 스프링 프레임워크는 @Repository 어노테이션이 붙은 클래스에서 발생하는 데이터 액세스 관련 예외를 런타임 예외로 변환하여 통일된 방식으로 예외를 처리할 수 있게 해준다.
    • 예를 들어 SQL 예외를 데이터 액세스 예외로 변환한다.
  3. 트랜잭션 지원
    • 데이터베이스 연산에 대한 트랜잭션 관리가 용이하다.

간단한 예시

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    User findByUsername(String username);
}
  • @Repository: UserRepository 인터페이스를 리포지토리 빈으로 등록한다.
  • Spring Data JPA: 위 예제는 JPA를 사용한 경우로, 리포지토리를 통해 CRUD 연산 및 커스텀 쿼리를 구현한다.

일반적인 사용 방법

  • DAO/리포지토리: 직접 SQL 쿼리를 실행하거나 ORM을 통해 데이터를 처리하는 DAO 또는 리포지토리 클래스에 사용한다.
  • 스프링 데이터 사용: JpaRepository, CrudRepository, MongoRepository 등 스프링 데이터 기반의 리포지토리 인터페이스에도 함께 사용된다.

예외 처리

@Repository를 사용하면 스프링은 데이터베이스 연산 중 발생하는 체크드 예외를 스프링의 데이터 액세스 예외로 변환한다. 이러한 변환을 통해 애플리케이션의 다른 계층에서 데이터베이스 관련 예외를 쉽게 처리할 수 있게 한다.

@Repository는 스프링에서 데이터 액세스 계층을 설계할 때 일관된 방식으로 사용되며, 데이터 처리에 대한 유지보수와 예외 처리를 단순화하는 데 도움이 된다.

예시

@Repository는 데이터 액세스 계층에서 활용되며, 데이터베이스나 다른 영구 저장소에 직접 접근하는 역할을 하는 클래스에 적용된다. 이를 통해 스프링 프레임워크는 해당 클래스를 빈으로 자동 등록하고, 데이터 액세스 관련 예외를 스프링의 데이터 액세스 예외로 변환할 수 있다.

예제 구조

  • 도메인 클래스: 데이터베이스 테이블을 표현하는 클래스.
  • 리포지토리 인터페이스: 데이터베이스 연산을 위한 메서드를 정의하는 인터페이스.
  • 서비스 클래스: 리포지토리에서 데이터를 가져와 비즈니스 로직을 처리하는 클래스.
  • 컨트롤러 클래스: 서비스 클래스를 이용해 HTTP 요청을 처리하는 컨트롤러.
// User.java (도메인 클래스)
package com.example.demo.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String username;
    private String email;

    // Getters and Setters
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}
// UserRepository.java (리포지토리 인터페이스)
package com.example.demo.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.example.demo.model.User;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    // 커스텀 메서드 선언 예시
    User findByUsername(String username);
}
// UserService.java (서비스 클래스)
package com.example.demo.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.demo.model.User;
import com.example.demo.repository.UserRepository;

@Service
public class UserService {
    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User getUserByUsername(String username) {
        return userRepository.findByUsername(username);
    }

    public void createUser(User user) {
        userRepository.save(user);
    }
}
// UserController.java (컨트롤러 클래스)
package com.example.demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import com.example.demo.model.User;
import com.example.demo.service.UserService;

@RestController
@RequestMapping("/users")
public class UserController {
    private final UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/{username}")
    public User getUser(@PathVariable String username) {
        return userService.getUserByUsername(username);
    }

    @PostMapping
    public void createUser(@RequestBody User user) {
        userService.createUser(user);
    }
}
  • 도메인 클래스 (User): JPA 엔티티로 정의된 User 클래스는 데이터베이스 테이블과 매핑되며 사용자 정보를 저장한다.
  • 리포지토리 (UserRepository): JpaRepository 인터페이스를 상속하여 데이터베이스 연산을 위한 메서드를 제공한다.
  • 서비스 (UserService): 리포지토리를 사용하여 비즈니스 로직을 구현하고 데이터를 조작한다.
  • 컨트롤러 (UserController): RESTful API를 제공하며 서비스 클래스를 사용하여 HTTP 요청을 처리한다.

이 구조에서 @Repository는 데이터베이스와의 상호작용을 위한 리포지토리 인터페이스에 사용되며, 스프링의 데이터 액세스 예외 변환 기능을 제공하여 데이터 액세스 계층의 구현을 간소화하고 안정적으로 만든다.

4. Controller

@Controller는 Spring MVC에서 웹 애플리케이션의 프레젠테이션 계층을 담당하는 컨트롤러 클래스를 정의하기 위해 사용되는 어노테이션이다. 이 어노테이션이 붙은 클래스는 웹 요청을 처리하고, 결과를 모델에 담아 뷰로 반환하는 역할을 한다.

특징

  • 스프링 빈으로 등록
    • @Controller 어노테이션은 @Component의 하위 어노테이션으로, 스프링 컨테이너에서 자동으로 빈으로 등록된다.
  • 요청 맵핑
    • @RequestMapping이나 다른 요청 매핑 어노테이션(@GetMapping, @PostMapping 등)과 함께 사용되어 특정 URL 패턴에 해당하는 메서드로 요청을 라우팅한다.
  • 모델과 뷰
    • 모델 데이터를 준비하여 뷰에 전달하고, 뷰의 이름을 반환한다.
    • 주로 Model 객체나 ModelAndView를 사용하여 모델을 구성한다.
  • RestController와의 차이점
    • @RestController는 기본적으로 JSON이나 XML 형태로 응답을 반환하지만, @Controller는 JSP, Thymeleaf 등의 뷰를 통해 사용자 인터페이스를 제공하는 데 주로 사용된다.

예시코드

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class GreetingController {

    @GetMapping("/greeting")
    public String greeting(@RequestParam(name = "name", required = false, defaultValue = "World") String name, Model model) {
        model.addAttribute("name", name);
        return "greeting";
    }
}
  1. @Controller
    • GreetingController 클래스를 스프링의 컨트롤러로 정의한다.
  2. @GetMapping
    • /greeting URL 패턴으로 들어오는 GET 요청을 이 메서드로 라우팅한다.
  3. @RequestParam
    • 요청의 쿼리 파라미터에서 name 값을 가져오며, 값이 없을 경우 기본값으로 World를 사용한다.
  4. Model
    • Model 객체를 사용하여 뷰에서 참조할 수 있도록 name 값을 전달한다.
  5. return "greeting"
    • greeting 뷰 이름을 반환하며, 이 이름에 매핑된 JSP 또는 Thymeleaf 템플릿을 찾아서 사용자에게 표시한다.

@Controller는 스프링의 웹 애플리케이션에서 사용자 인터페이스를 담당하는 중요한 역할을 한다. 이 어노테이션을 사용하여 프레젠테이션 계층을 구성하고, 뷰 템플릿과 함께 동작하여 웹 페이지를 동적으로 생성하는 데 사용된다.

예시

// HomeController.java
package com.example.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping("/home")
public class HomeController {

    // /home/greet URL로 요청이 오면 이 메서드가 실행됩니다.
    @GetMapping("/greet")
    public String greet(@RequestParam(name = "name", required = false, defaultValue = "Guest") String name, Model model) {
        // 모델에 데이터를 추가
        model.addAttribute("greeting", "Hello, " + name + "!");
        // greeting이라는 뷰로 이동 (예: greeting.html 또는 greeting.jsp)
        return "greeting";
    }

    // /home/welcome URL로 요청이 오면 이 메서드가 실행됩니다.
    @GetMapping("/welcome")
    public String welcome(Model model) {
        // 간단한 메시지를 모델에 추가
        model.addAttribute("message", "Welcome to the Home Page!");
        // welcome이라는 뷰로 이동 (예: welcome.html 또는 welcome.jsp)
        return "welcome";
    }

    // /home/about URL로 요청이 오면 이 메서드가 실행됩니다.
    @GetMapping("/about")
    public String about() {
        // about이라는 뷰로 이동
        return "about";
    }
}
  1. @Controller
    • HomeController 클래스를 스프링 MVC의 컨트롤러로 정의한다.
  2. @RequestMapping
    • /home URL을 기본 경로로 지정하여 해당 경로 내의 모든 요청에 대해 이 컨트롤러의 메서드가 동작하도록 한다.
  3. @GetMapping
    • HTTP GET 요청을 특정 메서드로 라우팅한다. 예를 들어 /home/greet로 들어오는 GET 요청은 greet 메서드로 라우팅된다.
  4. @RequestParam
    • 쿼리 파라미터에서 name 값을 가져와 메서드 매개변수로 사용한다. 해당 파라미터가 없는 경우 기본값을 Guest로 설정한다.
  5. Model 객체
    • Model 객체를 사용하여 뷰에서 참조할 데이터를 전달한다. 예를 들어, greet 메서드에서는 greeting이라는 이름으로 데이터를 전달하며, 뷰 템플릿에서 이 이름을 참조할 수 있다.
  6. 뷰 이름 반환
    • 각 메서드는 문자열로 뷰 이름을 반환한다. 이 이름을 기준으로 해당 뷰 템플릿을 찾아 사용자에게 결과를 보여준다.

번외. @RestController

@RestController는 Spring MVC에서 RESTful 웹 서비스의 컨트롤러를 정의하는 데 사용되는 어노테이션이다. @Controller@ResponseBody를 결합한 것으로, 반환된 값을 뷰로 렌더링하지 않고 직접 HTTP 응답 본문에 JSON, XML 등의 형태로 전송한다.

특징

  1. 스프링 빈 등록
    • @RestController@Controller처럼 스프링 컨테이너에서 빈으로 관리된다.
  2. 데이터 직렬화
    • 메서드의 반환값을 JSON 또는 XML로 변환하여 HTTP 응답으로 보낸다.
    • 일반적으로 JSON 형태로 반환되며, Jackson 라이브러리를 사용하여 자동 직렬화된다.
  3. 요청 맵핑
    • @RequestMapping과 함께 사용되며, HTTP 메서드별로 @GetMapping, @PostMapping, @PutMapping, @DeleteMapping 등의 매핑 어노테이션을 활용하여 라우팅한다.

예시코드

// UserController.java
package com.example.demo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;

@RestController
public class UserController {
    private static Map<Long, String> userStore = new HashMap<>();
    private static long idCounter = 1;

    // 간단한 Get 요청 예제
    @GetMapping("/users/{id}")
    public Map<String, Object> getUser(@PathVariable Long id) {
        Map<String, Object> response = new HashMap<>();
        String username = userStore.get(id);

        if (username != null) {
            response.put("id", id);
            response.put("username", username);
        } else {
            response.put("error", "User not found");
        }

        return response; // 자동으로 JSON으로 변환되어 반환됩니다.
    }

    // 간단한 Post 요청 예제
    @PostMapping("/users")
    public Map<String, Object> createUser(@RequestBody Map<String, String> request) {
        String username = request.get("username");
        Map<String, Object> response = new HashMap<>();

        if (username != null && !username.trim().isEmpty()) {
            long newId = idCounter++;
            userStore.put(newId, username);
            response.put("id", newId);
            response.put("username", username);
        } else {
            response.put("error", "Invalid username");
        }

        return response; // JSON으로 변환
    }
}
  • @RestController
    • UserController 클래스를 RESTful 웹 서비스의 컨트롤러로 정의한다.
  • @GetMapping, @PostMapping
    • 각각 HTTP GET 및 POST 요청을 처리하는 메서드에 사용된다.
  • @PathVariable
    • 경로 변수로 요청의 URL에서 변수 값을 추출한다.
  • @RequestBody
    • 클라이언트의 요청 본문에 있는 JSON 데이터를 메서드의 파라미터로 매핑한다.
  • 자동 JSON 변환
    • 메서드의 반환값은 자동으로 JSON 형식으로 변환되어 응답 본문에 전송된다.

@RestController는 RESTful 웹 서비스 개발에 있어서 데이터 API를 구축할 때 효과적이며, 특히 프론트엔드 애플리케이션과 데이터를 교환하는 백엔드 API에 적합하다.

profile
신입사원...

0개의 댓글