220413 (7) : DAO / Service 분리
지금까지...
기본적인 기능을 완성하고, JSP/CSS 작업을 진행하였다. 관련 내용은 별로 중요한것 같지 않아 따로 정리는 생략하였다.
DAO(repository)의 역할
DB에서 데이터가 변경되거나 데이터를 가져올 경우, 다음과 같은 과정을 거친다. DAO는 DB에 접속하여 데이터를 변경/읽기 등을 수행한다. 그리고 해당 데이터를 처리하여 페이지 컨트롤러에게 넘긴다. 페이지 컨트롤러는 DAO에게 받은 데이터를 기반으로 작업을 수행한다.
DAO의 역할은 'DB에 접속하여 데이터를 처리하는것'뿐이다. 그러므로 DAO가 직접 데이터를 받아와 파싱을 한다거나, 어떤 작업을 처리할 경우 단일 책임 원칙(SRP)에 위배된다. DAO는 단순히 DB에 접속하여 CRUD(생성/읽기/쓰기/삭제)기능만을 하는 것이 좋다.
그러므로 페이지 컨트롤러와 DAO사이에 DB에서 가져온 정보를 페이지 컨트롤러가 필요한 형태로 파싱해주고, 반대로 페이지 컨트롤러에 요청을 DAO가 수행 할 수 있게 처리해주는 객체인 Service객체가 필요하다.
DAO 수정
DAO는 DB에 접속하여 CRUD기능만을 수행한다.
예를들어 기존의 코드에서 feedDao 클래스가 수행하던 작업은 다음과 같다.
- 모든 피드 읽기 : selectList
- 특정 피드 읽기 : selectOne
- 피드 생성 : insert
- 피드 수정 : update
- 피드 삭제 : delete
- 좋아요(Likes) 1 증가 : updateLikes
- 조회수(Views) 1 증가 : updateViews
- 조회수 높은 글 읽기 : selectMostViewedFeed()
이 중 추가적인 데이터 처리가 필요한 6,7,8 메서드는 DAO에서 삭제하였다.
Interface: feedDao.java
public interface FeedDao {
public List<Feed> selectList() throws Exception;
public Feed selectOne(int no) throws Exception;
public int insert(Feed feed) throws Exception;
public int delete(int no) throws Exception;
public int update(Feed feed) throws Exception;
public int deleteAll() throws Exception;
}
추가적으로 모든 피드를 삭제해주는 deleteAll 메서드를 추가하였다.
Service 객체 생성
각 DAO 별로 서비스 객체를 만들어주었다.
FeedService.java
public class FeedService {
private FeedDao feedDao;
public FeedService setFeedDao(FeedDao feedDao) {
this.feedDao = feedDao;
return this;
}
public List<Feed> selectList() throws Exception {
return feedDao.selectList();
}
public Feed selectById(int id) throws Exception {
return feedDao.selectOne(id);
}
public int insertFeed(Feed feed) throws Exception {
return feedDao.insert(feed);
}
public int deleteFeedById(int id) throws Exception {
return feedDao.delete(id);
}
public int editFeed(Feed feed) throws Exception {
return feedDao.update(feed);
}
public int updateViews(int id) throws Exception {
Feed feed = feedDao.selectOne(id);
int views = feed.getViews();
feed.setViews(views + 1);
return feedDao.update(feed);
}
public int updateLikes(int id) throws Exception {
Feed feed = feedDao.selectOne(id);
int likes = feed.getLikes();
feed.setLikes(likes + 1);
return feedDao.update(feed);
}
public List<Feed> selectMostViewList() throws Exception {
final int MOST_VIEWS = 10;
List<Feed> feeds = feedDao.selectList();
List<Feed> result = new ArrayList<>();
int cnt = 0;
for (Feed feed : feeds) {
if (feed.getViews() >= MOST_VIEWS) {
result.add(feed);
cnt++;
}
if (cnt == 10) break;
}
return result;
}
}
FeedService는 기본적은 curd외에도 좋아요/조회수 증가, 인기글 리턴등을 수행하는 메서드들도 가지고 있다.
페이지 컨트롤러 수정
이제 페이지 컨트롤러는 직접 DAO에게 데이터 수정을 요청하지 않는다. 서비스 객체에게 데이터베이스 관련 작업을 요청한다. 그러기 위해 Service 객체 의존성을 주입하고, 기존의 DAO에게 요청하던 것들을 전부 Service객체로 변경한다.
FeedAddController.java
public class FeedAddController implements Controller, DataBinding {
private FeedService feedService;
public FeedAddController setFeedService(FeedService feedService) {
this.feedService = feedService;
return this;
}
@Override
public Object[] getDataBinders() {
return new Object[] {
"feed", crud_board.vo.Feed.class,
"password", String.class
};
}
@Override
public String execute(Map<String, Object> model) throws Exception {
Feed feed = (Feed) model.get("feed");
String password = (String) model.get("password");
HttpSession session = (HttpSession) model.get("session");
if (feed.getTitle() == null) {
if (session.getAttribute("loginUser").equals("익명")) {
model.put("authority", "");
} else {
model.put("authority", "disabled");
}
return "/feed/FeedAddForm.jsp";
} else {
if (session.getAttribute("loginUser").equals("익명")) {
feed.setWriter("익명" + password);
} else {
feed.setWriter((String) session.getAttribute("loginUser"));
}
//feedDao.insert(feed, session);
feedService.insertFeed(feed);
return "redirect:main.do";
}
}
}
추가 수정
Service 객체를 생성하고 의존성을 주입하기 위해 프로퍼티 파일에 해당 객체들을 명시해주어야 한다.
feedService=crud_board.service.FeedService
userService=crud_board.service.UserService
commentService=crud_board.service.CommentService
여담
이번 편에서는 DAO객체의 과중 부여된 역할을 줄이기 위해 서비스 객체를 만들어 주었다.
그럼에도 여전히 DAO 객체는 문제가 있는데 바로 코드 안에 쿼리문과 자바코드가 섞여있다는 것이다. 이를 분리하기 위해 myBatis를 사용할 예정이다.