반응형
저는 카카오 로그인을 생각하고 User의 속성을 정하고 생성, 삭제, 조회 정도만 해보려고 했습니다.
간단 설명
Entity→ 데이터 모델 정의Repository→ 데이터베이스 접근 계층 정의Service→ 비즈니스 로직 작성Controller→ HTTP 요청 처리DTO→ 필요에 따라 작성
폴더 구조 예시
controller, service, repository, entity, dto는 패키지로 생성
src/main/java/com/example/project/
├── controller/
│ └── UserController.java # 클래스
├── service/
│ ├── UserService.java # 인터페이스
│ └── UserServiceImpl.java # 클래스 (인터페이스 구현체)
├── repository/
│ └── UserRepository.java # 인터페이스
├── entity/
│ └── User.java # 클래스
├── dto/
│ └── UserDto.java # 클래스
Entity
Entity는 데이터 모델을 정의하며, 데이터베이스 테이블과 매핑됩니다.- 데이터를 중심으로 작업하므로 가장 먼저 정의하는 것이 논리적입니다.
- 여기서 User에서 사용할 속성을 추가하고, lombok을 통해 Getter와 Setter를 설정했습니다.
package com.example.backend.entity;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import lombok.Getter;
import lombok.Setter;
@Entity
@Getter
@Setter
public class User {
@Id
@GeneratedValue
private Long id;
private String nickname;
private String profileNickname;
private String profileImage;
}
Repository
- 데이터베이스와 상호작용하는 인터페이스를 정의하며,
Entity를 기반으로 작업합니다.
클래스로 작성하지 않는 이유
- Spring이 자동으로 구현체를 제공하므로 추가적으로 클래스를 작성할 필요가 없습니다.
package com.example.backend.repository;
import com.example.backend.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}
Service
Repository를 기반으로 비즈니스 로직을 구현합니다.- 데이터를 가공하거나 여러 저장소와 상호작용하는 로직을 작성합니다.
Service계층은 비즈니스 로직을 담당하며, 보통 인터페이스와 클래스(구현체)로 나누는 경우가 많습니다. 하지만, 반드시 인터페이스를 사용할 필요는 없습니다.
인터페이스와 구현체를 나누는 이유
- 인터페이스:
- 유연성 확보 (추후 다른 구현체로 교체 가능).
- 테스트에서 Mock 객체로 교체하기 쉬움.
- 구현체(클래스 Impl 붙이는 파일):
- 실제 비즈니스 로직을 작성.
그래도 한번 나눠서 코드를 작성해보고자 나눠보았습니다.
인터페이스 코드 예시
package com.example.backend.service;
import com.example.backend.dto.UserDto;
import java.util.List;
public interface UserService {
UserDto createUser(UserDto userDto); // DTO를 반환
void deleteUser(Long id);
List<UserDto> getAllUsers(); // DTO 리스트 반환
}
구현체 코드 예시
package com.example.backend.service;
import com.example.backend.dto.UserDto;
import com.example.backend.entity.User;
import com.example.backend.repository.UserRepository;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
// 엔티티 → DTO 변환 메서드
private UserDto toDto(User user) {
return new UserDto(
user.getId(),
user.getNickname(),
user.getProfileNickname(),
user.getProfileImage()
);
}
// DTO → 엔티티 변환 메서드
private User toEntity(UserDto userDto) {
User user = new User();
user.setId(userDto.getId());
user.setNickname(userDto.getNickname());
user.setProfileNickname(userDto.getProfileNickname());
user.setProfileImage(userDto.getProfileImage());
return user;
}
@Override
public UserDto createUser(UserDto userDto) {
User user = toEntity(userDto); // DTO → 엔티티 변환
User savedUser = userRepository.save(user); // 엔티티 저장
return toDto(savedUser); // 저장된 엔티티를 DTO로 변환
}
@Override
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
@Override
public List<UserDto> getAllUsers() {
return userRepository.findAll()
.stream()
.map(this::toDto) // 엔티티를 DTO로 변환
.collect(Collectors.toList());
}
}
Controller
Repository를 기반으로 비즈니스 로직을 구현합니다.- 데이터를 가공하거나 여러 저장소와 상호작용하는 로직을 작성합니다.
- RequestMapping으로 주소를 정해줍니다.
- ex) localhost:8080/api/users
package com.example.backend.controller;
import com.example.backend.dto.UserDto;
import com.example.backend.entity.User;
import com.example.backend.service.UserService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserService userService;
public UserController(UserService userService){
this.userService = userService;
}
@PostMapping
public ResponseEntity<UserDto> createUser(@RequestBody UserDto userDto) {
UserDto createdUser = userService.createUser(userDto);
return ResponseEntity.ok(createdUser);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return ResponseEntity.noContent().build();
}
@GetMapping
public ResponseEntity<List<UserDto>> getAllUsers() {
List<UserDto> users = userService.getAllUsers();
return ResponseEntity.ok(users);
}
}
Dto
- 데이터 교환:
- 서버와 클라이언트 사이에서 데이터를 전달하는 객체로 사용됩니다.
- 예를 들어, API 요청을 받을 때 DTO 형태로 데이터를 받고, 응답할 때 DTO 형태로 데이터를 반환합니다.
- 보안 강화:
- 엔티티에는 비밀번호나 민감한 데이터가 포함될 수 있는데, DTO를 사용하면 외부로 노출하지 않아야 하는 데이터를 제외하고 필요한 데이터만 제공할 수 있습니다.
- DTO를 통해 데이터의 가공, 필터링, 또는 변환이 가능하여 데이터 노출을 최소화할 수 있습니다.
- 계층 분리:
- 엔티티와 DTO를 분리함으로써 도메인 계층과 API 계층 간의 의존성을 줄이고, 데이터베이스 스키마의 변경이 클라이언트에 영향을 미치지 않도록 할 수 있습니다.
- 유효성 검사:
- DTO를 통해 클라이언트에서 전달된 데이터에 대해 유효성 검사를 할 수 있습니다.
- Spring에서는 @Valid 어노테이션과 javax.validation을 사용해 유효성 검사를 쉽게 추가할 수 있습니다.
package com.example.backend.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class UserDto {
private Long id;
private String nickname;
private String profileNickname;
private String profileImage;
}
+ 가공시키는 코드 예시
nickname과 profileNickname을 조합한 전체 이름을 클라이언트에 제공해야 한다면:
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class UserDto {
private Long id;
private String nickname;
private String profileNickname;
private String profileImage;
public String getFullName() {
return nickname + " (" + profileNickname + ")";
}
}
Entity와 Dto의 차이와 역할
- Entity:
- 데이터베이스 테이블과 직접 매핑되는 클래스입니다.
- 데이터베이스와의 CRUD 작업을 위해 설계되었습니다.
@Entity와 같은 JPA 어노테이션을 사용하여 데이터베이스의 구조를 정의합니다.- 비즈니스 로직이나 DTO와 분리하여 데이터베이스와 직접적인 상호작용을 담당합니다.
- DTO (Data Transfer Object):
- 클라이언트와 서버 간 데이터를 교환하기 위한 객체입니다.
- 주로 컨트롤러에서 사용되며, API의 요청 및 응답 데이터를 정의합니다.
- 비즈니스 로직이나 데이터베이스와의 직접적인 연관이 없습니다.
- Entity의 필드를 그대로 사용할 수도 있지만, 필요에 따라 일부 필드만 포함하거나 추가적인 정보(예: 상태, 메시지 등)를 가질 수 있습니다.
반응형
'백엔드' 카테고리의 다른 글
| Springboot MySQL 연동하기 (2) | 2025.01.14 |
|---|---|
| SpringBoot 첫 프로젝트 생성 (2) | 2025.01.10 |