Whiteship's Note

[회사일] MemberService 만들기. GenericService 만들기

프로젝트/SLT : 2010.06.09 16:50


이번엔 바로 GenericService 인터페이스부터 만들죠.

public interface GenericService<E, S> {

    void add(E e);

    List<E> list(PageParam pageParam, S s);

    E getById(int id);

    void update(E e);

    void deleteBy(int id);
    
}

간단합니다. GenericDao랑 비슷하죠. 이 구현체도 간단합니다. 오히려 GenericDaoImpl 보다 훨씬더..

public class GenericServiceImpl<D extends GenericDao<E, S>, E, S> implements GenericService<E, S>{

    @Autowired protected D dao;

    public void add(E e) {
        dao.add(e);
    }

    public List<E> list(PageParam pageParam, S s) {
        pageParam.initCurrentPageInfosWith(dao.totalSize(s));
        return dao.list(pageParam, s);
    }

    public E getById(int id) {
        return dao.getById(id);
    }

    public void update(E e) {
        dao.update(e);
    }

    public void deleteBy(int id) {
        dao.deleteBy(id);
    }
    
}

유일하게 복잡한 부분이 저 위에 Generic 타입 선언한 부분인데.. GenericDao에 있는 메서드를 사용하려면 D라는 타입이 GenericDao를 확장한 녀석이라는걸 알려줘야 합니다. 그리고 GenericDAO에 넘겨주는 타입이 GenericService에서 사용할 타입과 같다는것도 알려줘야 해서 저렇게 복잡해졌습니다. 만야게 GenericDao 뒤에 붙인 <E, S>를 때어내면 dao.getById(id) 부분에서 타입 불일치 때문에 컴파일 에러가 떨어집니다.ㅋ

public interface MemberService extends GenericService<Member, MemberSearchParam>{

}

public class MemberServiceImpl extends GenericServiceImpl<MemberDao, Member, MemberSearchParam> implements MemberService{
    
}

위에서 만든걸 이용해서 만든 MemberService와 MemberServiceImpl 입니다. 캬.. 간단하군요.






top

  1. 둥이아빠 2010.06.09 19:58 PERM. MOD/DEL REPLY

    저번에 AspectJ 관련 답변 감사드립니다^^

    저도 이번에 프로젝트를 진행하면서 GenericService, GenericDao 구현해 진행하고 있는데요
    Hibernate가 아닌 iBATIS에 물려서 진행하고 있습니다.

    하나 궁금한게 있는데요...

    Domain 설계 하실때...
    Master 화면들은 거의 Table 하나와 매핑 되다 보니 Domain이 CRUD를 적용하기에 명확한데요.
    조금 복잡한 화면들의 경우 Domain 자체가 복잡해 지다 보니 CRUD를 적용하기에 애매한 부분들이 있는것 같습니다.

    프로젝 하실때 그런 복잡한 화면들은 어떤식으로 처리하시는지 궁금합니다.
    예를 들어, 조금 간단한 구조로 화면에 Header에 해당하는 Form과 하단에 Detail 정보를 담을 Grid가 있을 경우 Header, Detail에 해당하는 Domain 구조를 설계하고 (예를 들어 Header Domain에 Detail Domain을 List로 구성하고..)
    해당 Domain과 동일한 구조의 ResultMap (ibatis)을 작성한뒤 한번에 조회해와서 셋팅하도록 하시는지,
    아니면 Header와 Detail을 별개의 Domain으로 설계한 후에 따로 조회를 하시는지 궁금하네요..^^;;

    그리고, 조금 더 복잡하게 Header에 여러 Master Domain들이 구성될 경우, 그런경우는 어떻게 처리하시는지도 궁금하구요..^^;;

    너무 질문이 장황한 것 같은데...
    이번에도 좋은 답변 부탁드리겠습니다^^

    Favicon of http://whiteship.me BlogIcon 기선 2010.06.09 21:04 PERM MOD/DEL

    봄싹 사이트에서 My Page 같은 경우는 여러 도메인 정보를 가져와서 한 화면에 보여줘야 했었는데요.

    MyPageController를 만들고 거기서 MemberService, StudyService 등을 사용해서 원하는 모델 객체들을 가져온다음 화면으로 전달할 ModelMap에 넣어줬습니다.

    그리고 화면에선 그냥 알아서 참조해서 EL로 뿌렸죠.

    화면당 도메인이 꼭 1:1로 매핑되야 하는건 아니고, Generic으로 빼낼 수 있는 기능들도 제한이 있으니 이럴땐 GenericService, GenericDao를 상속해서 만든 클래스와 인터페이스에 추가적인 기능이 들어갈 수도 있겠습니다.

    GenericXXX 들은 코드 중복을 줄이고 확장을 편하게 하기 위함이지 애플리케이션 아키텍처를 단순화하려는 용도는 아니기 때문에 화면에 보여줄 도메인 객체가 여러개 라고 해서 별로 문제될 것은 없을 것 같습니다. 흠냐..

  2. 둥이아빠 2010.06.09 22:25 PERM. MOD/DEL REPLY

    우선, 친절한 답변 감사드립니다.

    아.. MemberService, StudyService가 Member, Study 라는 도메인을 가지고 Controller에서 해당 도메인들을 받아 Map에 넣어서 전달한 케이스군요...

    음..
    Controller에서의 조합은 알겠는데요...
    Service가 가지는 Domain 자체가 복잡도를 가질 경우 그런 케이스를 CRUD로 구성하시는지가 궁금합니다.

    예를 들어, "구매요청" 이라는 도메인을 설계한다고 할때...
    구매요청은 말 그대로 구매요청이라는 Transaction이 있을 수 있고 등록된 구매요청 정보를 조회하는 프로세스가 있을수 있을 텐데요....
    구매요청 도메인은 예산, 업체, 결재 등의 Master Domain들을 구성하고 구매요청할 자재정보인 자재 Master Domain을 List로 구성하는 형태로 설계한다면...
    이런 복잡도를 가진 Domain을 CRUD로 구성을 하시는지 아니면 다른 방법으로 해결을 하시는지가 궁금합니다^^;;;
    Header, Detail 정보를 하나의 Domain으로 설계하는거죠...

    이번에도 좋은 답변 부탁드리겠습니다^^

    Favicon of http://whiteship.me BlogIcon 기선 2010.06.10 08:27 PERM MOD/DEL

    "구매요청"이 생기고, 수정되고, 삭제되고, 목록을 조회하고, 한건을 조회하는 등의 작업은 하실꺼자나요?

    그리고 그 "구매요청"과 관련이 있는 "예산", "업체" 등도 개별적으로 CRUD가 필요할꺼라고 생각합니다.

    "결제" 같은 경우는 (제가 생각하는것과 다를수도 있지만) '제출'된 상태인지, '반려' 됐는지, '결제' 됐는지 등 상태를 나타내기 때문에 여러 도메인에 공통으로 들어갈 수 있는 정보가 될 것 같습니다. 이런 경우는 별도로 CRUD성 DAO, Service, Controller를 만들지 않고 "결제Dao" "결제Service"같은 인터페이스를 만들고 다른 도메인의 DAO나 Service에서 추가로 구현하게 할 것 같습니다.

    Header와 Detail은 잘 안와 닿는 도메인 이름입니다. Header에 들어갈 정보가 form이라고 하셨는데 그렇다면 header쪽에는 지금 제가 회사에서 만들고 있는 화면 오른쪽에 있는 검색 화면이 될 것 같군요. 그건 하나의 도메인이라기 보단 검색용 보조 데이터입니다. 따라서 CodeSearchParam이라는 클래스를 code.support쪽에 만들어놨고 그걸 화면으로 전달해서 그안에 값을 바인딩 시켜서 가져왔습니다. 그리고 Details이라고 하신 부분은 그리드 같은데 제 회사일에도 그리드가 있죠. 그 부분은 보통 다른 도메인의 List를 뿌리는 것일테니까 그 도메인의 CRUD 중에서 R을 활용해서 스프링 ModelAndView 중에 Model에 넣어주었습니다.

    위에서 Map에 넣었다고 했는데 이게 SI에서 사용한다는(전 그쪽을 잘 모릅니다,) 그런 Map은 아니구요. ModelMap이라고 해서 key에 해당하는 값이 객체의 프로퍼티들이 아니라(그렇게 될 수도 있지만) 보통은 객체 자체 입니다.

    model.addAttribute("studyList", studyService.getList());
    model.addAttribute("wikiList", wikiService.getList());

    이런식으로 담아서 전달하는거죠. 아무리 화면이 복잡하더라도 그 화면에서 보여줄 데이터가 도메인 모델로 잘 나눠져 있다면 저런식으로 화면에서 참조할 객체들을 여러개 전달하면 되는것 뿐이죠.

    CRUD 처리도 필요한 도메인에만 만들어주면 될 뿐.. 어떤 도메인은 다른 도메인에 종속적이어서 DAO만 CRUD를 만들어 놓고 서비스나 컨트롤러는 만들지 않는것도 있습니다. 예를 들어 "연간 계획", "연간 계획 상세" 라는 도메인이 있었는데.. 연간 계획은 1년치를 총 집계해서 보는 도메인이고 연간계획상세는 그걸 달단위로 조금 상세하게 적어둔 것이었습니다. (월 게획은 또 별도로 있었는데 암튼..) 그래서 저런 경우에 "연간 계획"이 삭제되면 "연간 계획 상세"도 필요없었거든요. 그래서 "연간 계획 상세"는 DAO만 들어 놓고 나머진 "연간 계획"의 DAO, Service, Controller에서 "연간 계획 상세"의 CRUD도 같이 처리했었습니다.

    흠. 질문하신거에 대한 대답이 될지 어떨지 몰겠네요. 이게 뭐 어디 설명이 되어 있는 내용도 아니고 그냥 제가 일하는 방식이라; @_@

  3. 둥이아빠 2010.06.10 14:57 PERM. MOD/DEL REPLY

    답변 감사드립니다^^;

    방향 설정하는데 많은 도움이 되었습니다^^

    Favicon of http://whiteship.me BlogIcon 기선 2010.06.10 16:24 PERM MOD/DEL

    넵. 도움이 되셨다니;; 다행이네요.ㅋ

Write a comment.




: 1 : ··· : 10 : 11 : 12 : 13 : 14 : 15 : 16 : 17 : 18 : ··· : 30 :