🖋️ Backend 효과적인 패키지 구조를 만들기
Domain, Service, Controller, Repository, DAO, DTO, VO 핵심 구성요소 이해
com.example.myapp
├── config
├── controller
├── service
├── repository
├── domain
├── dto
└── exception
@Entity
public class User {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String email;
}
@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;
}
public class PostDTO {
private Long id;
private String title;
private String content;
private Long userId;
}
public interface UserRepository extends JpaRepository<User, Long> {}
public interface PostRepository extends JpaRepository<Post, Long> {
List<Post> findByUserId(Long userId);
}
@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()));
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());
}
}
@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);
}
}
@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 캡슐화를 통해 데이터를 확장하거나
불필요한 데이터를 제거하거나 최적화 하기