
출처 : https://wikidocs.net/161220
앞서 우리는 QuestionController에서 QuestionRepository를 직접 사용하여 질문 목록 데이터를 조회했다.
하지만 대부분의 규모있는 스프링부트 프로젝트는 컨트롤러에서 리포지터리를 직접 호출하지 않고
중간에 서비스(Service)를 두어 데이터를 처리한다.
서비스는 스프링에서 데이터 처리를 위해 작성하는 클래스이다.
여러 개의 리포지터리를 사용하여 데이터를 조회한 후 가공하여 리턴한다고 하면, 이러한 기능을 서비스로 만들어두면 컨트롤러에서는 해당 서비스를 호출하여 사용하면 된다.
하지만 서비스로 만들지 않고, 컨트롤러에서 구현하려 한다면 해당 기능을 필요로 하는 모든 컨트롤러가 동일한 기능을 중복으로 구현해야 한다.
서비스는 모듈화를 위해 필요하다.
우리가 작성한 Question, Answer 클래스는 엔티티(Entity) 클래스이다.
엔티티 클래스는 데이터베이스와 직접 맞닿아있는 클래스이기 때문에, 컨트롤러나 타임리프같은 템플릿 엔진에 전달하여 사용하는 것은 좋지 않다.
컨트롤러나 타임리프에서 사용하는 데이터 객체는 속성을 변경하여 비즈니스적인 요구를 처리해야 하는 경우가 많은데,
Question, Answer 같은 엔티티 클래스는 컨트롤러에서 사용할 수 없게끔 설계하는 것이 좋다.
DTO(Data Transfer Object) 클래스가 필요하다. Question, Answer 등의 엔티티 객체를 DTO 객체로 변환하는 작업도 필요하다. 그러면 엔티티 객체를 DTO 객체로 변환하는 일은 어디서 처리해야 할까.
서비스에서 변환을 해준다.
서비스는 컨트롤러와 리포지터리의 중간자적인 입장에서 엔티티 객체와 DTO 객체를 서로 변환하여 양방향에 전달하는 역할을 한다.
//QuestionService.java
package com.mysite.sbb.question;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
@RequiredArgsConstructor
@Service
public class QuestionService {
private final QuestionRepository questionRepository;
public List<Question> getList(){
return this.questionRepository.findAll();
}
}
package com.mysite.sbb.question;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Controller
public class QuestionController {
//private final QuestionRepository questionRepository;
private final QuestionService questionService;
@GetMapping("question/list")
public String list(Model model) {
List<Question> questionList = this.questionService.getList();
model.addAttribute("questionList", questionList);
return "question_list";
}
}
실행시키고 http://localhost:8080/question/list 페이지에 접속하면 이전과 동일한 화면을 볼 수 있다.
앞으로 작성할 컨트롤러도 리포지터리를 직접 사용하지 않고
Controller -> Service -> Repository 구조로 데이터를 처리한다.