[Spring 가이드 2.0] Backend 효과적인 패키지 구조를 만들기 위한 실전 예시

김현수·2024년 4월 24일
0

spring

목록 보기
4/9


🖋️ Backend 효과적인 패키지 구조를 만들기

  • Domain, Service, Controller, Repository, DAO, DTO, VO 핵심 구성요소 이해



  • 구성

com.example.myapp
├── config
├── controller
├── service
├── repository
├── domain
├── dto
└── exception

  • Domain

@Entity
public class User {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String email;
    // Getters and setters
}

@Entity
public class Post {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;
    private String content;

    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;
    // Getters and setters
}

  • DTO

public class PostDTO {
    private Long id;
    private String title;
    private String content;
    private Long userId;
    // Getters and setters
}

  • Repository Layer

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

public interface PostRepository extends JpaRepository<Post, Long> {
    List<Post> findByUserId(Long userId);
}

  • Service Layer

@Service
public class PostService {
    @Autowired
    private PostRepository postRepository;

    public PostDTO createPost(PostDTO postDTO) {
        Post post = new Post();
        post.setTitle(postDTO.getTitle());
        post.setContent(postDTO.getContent());
        post.setUser(new User(postDTO.getUserId())); // Assume User is validated and exists
        post = postRepository.save(post);
        return new PostDTO(post);
    }

    public List<PostDTO> getPostsByUser(Long userId) {
        return postRepository.findByUserId(userId).stream()
                             .map(PostDTO::new)
                             .collect(Collectors.toList());
    }
}

  • Controller Layer

@RestController
@RequestMapping("/api/posts")
public class PostController {
    @Autowired
    private PostService postService;

    @PostMapping
    public ResponseEntity<PostDTO> createPost(@RequestBody PostDTO postDTO) {
        PostDTO createdPost = postService.createPost(postDTO);
        return new ResponseEntity<>(createdPost, HttpStatus.CREATED);
    }

    @GetMapping("/user/{userId}")
    public ResponseEntity<List<PostDTO>> getPostsByUser(@PathVariable Long userId) {
        List<PostDTO> posts = postService.getPostsByUser(userId);
        return ResponseEntity.ok(posts);
    }
}

  • Exception Handling

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(value = Exception.class)
    public ResponseEntity<Object> handleException(Exception e){
        return new ResponseEntity<>("Error occurred: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
    }
}


  • Config & Security

    • 지연 로딩과 Eager 로딩
      • 지연 로딩을 현명하게 사용
      • 이런 경우 사용자 데이터가 포함된 게시물을 자주 가져오는 경우 Eager Loading을 고려

    • DTO 투영
      • DTO를 사용하여 데이터 초과 가져오기를 방지
      • 쿼리에 필요한 데이터만 투영

    • 캐싱
      • 자주 액세스하는 데이터에는 캐싱을 사용

    • 데이터베이스 인덱싱
      • 자주 쿼리되는 필드에 대해 데이터베이스 측에서 적절한 인덱싱을 보장


  • 역할론과 책임론 잊지 말기
  • DTO 캡슐화를 통해 데이터를 확장하거나
    불필요한 데이터를 제거하거나 최적화 하기
profile
일단 한다

0개의 댓글