Spring Boot

[Spring Boot] Controller, Service, Mapper, DTO

Tech박조롱 2024. 7. 18. 17:13

Spring Boot 애플리케이션에서는 MVC(Model-View-Controller) 패턴을 사용하여 애플리케이션을 구조화할 수 있으며, Controller, Service, DAO, Mapper는 애플리케이션을 모듈화하고 유지 보수하기 쉽게 만드는 데 중요한 역할을 한다.

 

1. Controller

클라이언트 요청을 처리하고, 요청에 따라 적절한 서비스를 호출하여 결과를 반환한다. 주로 HTTP 요청을 매핑하고, 요청 데이터를 바인딩하며, 서비스 계층을 호출한다.

package com.example.demo.controller;

import com.example.demo.dto.UserDTO;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController // RESTful 웹 서비스의 컨트롤러임을 나타냄
@RequestMapping("/api/users") // 컨트롤러가 처리할 기본 URL 경로를 지정
public class UserController {

    private final UserService userService;

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

    @GetMapping // HTTP GET 요청을 이 메서드에 매핑합니다.
    public ResponseEntity<List<UserDTO>> getAllUsers() {
        List<UserDTO> users = userService.getAllUsers();
        return ResponseEntity.ok(users);
    }

    @GetMapping("/{id}") // 경로 변수 id를 포함한 HTTP GET 요청을 매핑
    public ResponseEntity<UserDTO> getUserById(@PathVariable Long id) {
        UserDTO user = userService.getUserById(id);
        return ResponseEntity.ok(user); 
    }

    @PostMapping // HTTP POST 요청을 매핑
    public ResponseEntity<UserDTO> createUser(@RequestBody UserDTO userDTO) {
        UserDTO createdUser = userService.createUser(userDTO);
        return ResponseEntity.status(201).body(createdUser); 
    }

    @PutMapping("/{id}") // 경로 변수 id를 포함한 HTTP PUT 요청을 매핑
    public ResponseEntity<UserDTO> updateUser(@PathVariable Long id, @RequestBody UserDTO userDTO) {
        UserDTO updatedUser = userService.updateUser(id, userDTO);
        return ResponseEntity.ok(updatedUser); 
    }

    @DeleteMapping("/{id}") // 경로 변수 id를 포함한 HTTP DELETE 요청을 매핑
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
        return ResponseEntity.noContent().build();
    }
}

 

2.  Service

비즈니스 로직을 처리. Service 계층은 Controller와 DAO 간의 중간 계층으로, 비즈니스 요구사항을 구현하고 트랜잭션을 관리한다.

package com.example.demo.service;

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

import java.util.List;
import java.util.stream.Collectors;

@Service // 이 클래스가 서비스 계층의 빈임을 나타냄
public class UserService {

    private final UserRepository userRepository;

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

    public List<UserDTO> getAllUsers() {
        // 모든 사용자를 조회하고 DTO 목록으로 변환
        return userRepository.findAll().stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    public UserDTO getUserById(Long id) {
        // ID로 사용자를 조회하고, 없으면 예외를 발생
        User user = userRepository.findById(id).orElseThrow(() -> new RuntimeException("User not found"));
        return convertToDTO(user);
    }

    public UserDTO createUser(UserDTO userDTO) {
        // DTO를 엔티티로 변환하고 저장한 후, 다시 DTO로 변환
        User user = convertToEntity(userDTO);
        User savedUser = userRepository.save(user);
        return convertToDTO(savedUser);
    }

    public UserDTO updateUser(Long id, UserDTO userDTO) {
        // ID로 기존 사용자를 조회하고 업데이트한 후 저장
        User existingUser = userRepository.findById(id).orElseThrow(() -> new RuntimeException("User not found"));
        existingUser.setName(userDTO.getName());
        existingUser.setEmail(userDTO.getEmail());
        User updatedUser = userRepository.save(existingUser);
        return convertToDTO(updatedUser);
    }

    public void deleteUser(Long id) {
        // ID로 사용자를 삭제
        userRepository.deleteById(id);
    }

    private UserDTO convertToDTO(User user) {
        // 엔티티를 DTO로 변환
        return new UserDTO(user.getId(), user.getName(), user.getEmail());
    }

    private User convertToEntity(UserDTO userDTO) {
        // DTO를 엔티티로 변환
        return new User(userDTO.getId(), userDTO.getName(), userDTO.getEmail());
    }
}

 

3. Mapper

주로 MyBatis와 같은 ORM 도구를 사용할 때 데이터베이스와의 매핑을 담당. 

 

Read-Only Mapper

package com.example.demo.mapper;

import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper // 이 인터페이스가 MyBatis 매퍼 인터페이스임을 나타냄
public interface UserReadOnlyMapper {
    @Select("SELECT * FROM users WHERE id = #{id}")
    User findById(Long id);

    @Select("SELECT * FROM users")
    List<User> findAll();
}

 

Read-Write Mapper

package com.example.demo.mapper;

import com.example.demo.entity.User;
import org.apache.ibatis.annotations.*;

@Mapper // 이 인터페이스가 MyBatis 매퍼 인터페이스임을 나타냄
public interface UserReadWriteMapper {
    @Insert("INSERT INTO users(name, email) VALUES(#{name}, #{email})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    void insert(User user);

    @Update("UPDATE users SET name = #{name}, email = #{email} WHERE id = #{id}")
    void update(User user);

    @Delete("DELETE FROM users WHERE id = #{id}")
    void deleteById(Long id);
}

 

4. DTO (Data Transfer Object)

계층 간 데이터 전송을 위한 객체

package com.example.demo.dto;

@Getter
@Setter
public class UserDTO {

    private Long id;
    private String name;
    private String email;

    public UserDTO() {
    }

    public UserDTO(Long id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }
}