🙋‍♀️ Server

[Server] Spring 패키지 구조, 각각의 기능

수댕ʕت̫͡ʔ 2025. 1. 21. 16:41

동기들이랑 AI기반 회의 플랫폼을 개발 중이다. Spring 공부를 하고 싶어서 백엔드 역할을 맡아서 참여하게 되었다. Spring은 처음이다보니 폴더 구조 이해에 어려움이 있어 그 내용을 정리해보려고 한다.

 

Spring 에서 패키지 구조는 어떻게 구성할 수 있을까!

보통 Spring의 폴더 구조는 아래와 같이 구성한다. MVC 설계를 기준으로 다음과 같다.

com.example.projectname
├── controller
├── service
├── repository
├── model 
├── dto
├── config
└── util

 

여기서 사실 안에 코드도 중요하지만 폴더의 구조를 설계하는 것도 대단히 중요하다. 그 이유는 코드의 가독성, 유지보수성 때문이다. Spring은 각각의 코드가 의존성 주입을 통해 객체지향적으로 설계되어있다보니 명확히 역할 분리를 하는 것이 좋다.

 

사실 다양한 포스팅 글을 찾아보니 "가장 최고의 프로젝트 폴더 구조 설계는 존재하지 않는다"고 한다. 스프링 강의를 듣고있는 강사 선생님도 프로젝트 시작 전 항상 폴더의 구조를 고민하신다고 한다. 😅

 

controller

컨트롤러는 사용자 요청을 받고, 해당 요청을 처리할 서비스 계층을 호출한 후, 결과를 반환하는 역할을 한다.

예를 들어 @RestController, @Controller 어노테이션이 포함된 클래스 파일이다. 여기서 각각 기능에 따라서 Usercontroller, ProductController, .. 이렇게 파일을 따로 관리하는 것이 좋다.

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

    @GetMapping("/{id}")
    public ResponseEntity<UserDto> getUser(@PathVariable Long id) {
        return ResponseEntity.ok(userService.getUserById(id));
    }
}

 

여기서 @RestController는 RESTful API 구현에 사용, Json/Xml 데이터를 반환하고 html 반환은 불가한다. 그리고 @Controller, @ResponseBody는 html 뷰를 반환하거나 Json/Xml 데이터를 반환할 수 있다는 차이가 있다.

 

Service

서비스는 비즈니스 로직을 처리하는 역할을 한다. @Service 어노테이션이 포함된 클래스이고, 여기서도 각 기능에 맞게 파일을 따로 나누어 관리한다.

@Service
public class UserService {
    private final UserRepository userRepository;

    public UserDto getUserById(Long id) {
        return userRepository.findById(id)
                .map(user -> new UserDto(user.getId(), user.getName()))
                .orElseThrow(() -> new UserNotFoundException(id));
    }
}

 

Repository

레포지터리는 데이터베이스와의 상호작용을 처리한다.

주로 JPA, MyBatis 와 같은 인터페이스를 담고 있다.

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}

 

 

Entity

여기서는 엔터티 클래스가 담겨있다. 데이터베이스와 매핑되는 엔터티 클래스를 작성하고 @Entity, @Table 어노테이션을 사용하는 클래스이다.

 

여기서 dto랑 차이가 뭔지에 대해 궁금했었는데 entity 은 DB의 설계가 담겨있다고 보면된다. 그래서 여기에는 가능하면 setter을 사용하는것은 지양해야한다. 왜냐하면 객체의 일관성, 안정성을 보장해야하기 때문!

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    // 생성자 및 Getter
}

 

dto

dto는 중요한 역할을 하는데 서버로부터의 요청, 응답 데이터를 캡슐화하는 역할을 한다. 여기서 데이터를 캡슐화하여 뷰와 컨트롤러 간 데이터 전송 시 사용한다.

public class UserDto {
    private Long id;
    private String name;

    // 생성자, Getter, Setter
}

 

config

config에는 애플리케이션 전반의 설정을 정의한다. 여기서 스프링 시큐리티를 사용하거나 Bean 등록 등 그에 대한 설정을 넣을 수도 있다.

 

util

util은 공통 클래스나 헬퍼 메서드를 관리하는 패키지이다.