4. 화면 중심 프로젝트
• 화면 중심으로 프로젝트 구조를 구성
• View 단위로 개발자 투입
• Service, Dao, Entity를 각자 만들어 써야함, 공
유하는 것은 허용하지 않음
5. 회원관리 화면 Package
controller (MemberController)
service (MemberService)
dao (MemberDao)
entity (Member)
상품 관리 화면 Package
controller (ProductController)
service (ProductService)
dao (ProductDao)
entity (Product)
55. 도메인 객체
@Getter @Setter
@Entity
public class Member extends BaseEntity<Long>{
private String name;
private int age;
@OneToMany(mappedBy="member")
List<MemberCard> memberCards = new ArrayList<MemberCard>();
public void addMemberCard(MemberCard memberCard) {
memberCards.add(memberCard);
}
}
@Getter @Setter
@Entity
public class Card extends BaseEntity<Long>{
private String name;
private int rate; //적립률
//create
public CardPoint createCardPoint(int money) {
return new CardPoint(name,money,rate);
}
}
56. @Getter @Entity
public class MemberCard extends BaseEntity<Long>{
@OneToMany(cascade=CascadeType.PERSIST) @JoinColumn(name="memberCard_id")
private List<CardPoint> cardPoints = new ArrayList<CardPoint>();
@ManyToOne private Member member;
@ManyToOne private Card card;
//BIZ
public void payMoney(int money) {
CardPoint createCardPoint = card.createCardPoint(money);
addCardPoint(createCardPoint);
}
//VIEW Logic
public int getTotalPoint() {
int totalPoint = 0;
for (CardPoint cardPoint : cardPoints) {
totalPoint += cardPoint.getPoint();
}
return totalPoint;
}
}
57. 회원 조회, QueryDSL
@RequestMapping("member/home")
public String home(MemberCond cond, Model model) {
//QUERY DSL
QMember qMember = QMember.member;
BooleanExpression containsName = qMember.name.contains(cond.getName());
BooleanExpression gtAge = qMember.age.gt(cond.getAge());
model.addAttribute("members",memberRepository.findAll(containsName.and(gtAge)));
return "member/home";
} public interface MemberRepository extends
JpaRepository<Member, Long>, QueryDslPredicateExecutor<Member>{
}
select * from Member member
where (member.name like '%서%') and member.age > 26
58. 회원 등록, SpringDataJPA
@RequestMapping("member/saveMember")
public String saveMenu(Member member) {
memberRepository.save(member);
return "redirect:/member/home";
}
public interface MemberRepository extends
JpaRepository<Member, Long>, QueryDslPredicateExecutor<Member>{
}
`
62. 회원카드 결제하기 = ORM 저장
@RequestMapping("memberCard/payMoney")
public String payMoney(
@RequestParam("memberCardId") MemberCard memberCard,
@RequestParam("money") int money) {
memberCardService.payMoney(memberCard, money);
return "redirect:/memberCard/home";
}
@Service
@Transactional
public class MemberCardService {
public void payMoney(MemberCard memberCard, int money) {
memberCard.payMoney(money);
}
}
public class MemberCard {
@OneToMany(cascade=CascadeType.PERSIST) @JoinColumn(name="memberCard_id")
private List<CardPoint> cardPoints = new ArrayList<CardPoint>();
public void payMoney(int money) {
CardPoint createCardPoint = card.createCardPoint(money);
cardPoints.add(createCardPoint);
}
public class Card{
private String name;
private int rate;
public CardPoint createCardPoint(int money) {
return new CardPoint(name,money,rate);
}
}
Auto SAVE
`
`
63. Spring-Data-JPA 소개
• interface로 Repository 자동 생성
(CRUD, 조회)
• simple queries
ex) findByName(String name)
select * from member where name={name}
• pagination
• Web Binding
• Specifications, QueryDSL지원
69. • Domain Model을 모든 Layer에서 적극 사용
하자.
• OSIV(Open Session InView) 사용
• Getter, Setter 사용
• DTO는 중복 악마다!
Domain Model
Everywhere
70. • 장점
• 개발하기에 빠르고 편리함
• 단점
• 복잡한View 표현 힘듬
• Domain Model의 Getter, Setter를 노출,View로직 추가
• Domain Model의 순수성이 떨어짐
• XML, JSON, 외부와의 통신API 위험 = 도메인 모델은 생각보다
자주 변함
Domain Model
Everywhere
78. Pure Domain Model
잡종
이런 잡종 구조는 새로운 함수는 물론이고 새로
운 자료 구조도 추가하기 어렵다.
양쪽 세상에서 단점만 모아 놓은 구조다. 그러므
로 잡종 구조는 되도록 피하는 편이 좋다.
- Clean Code, Chapter 6 객체와 자료구조 -
95. • Domain Driven Design
• Pure Domain Model 을 유지하며 실용적으로
개발하는 방법
• DTO를 생성하는 방법, 활용법
• ex) http://modelmapper.org/
• ex) Builder Pattern
우리의 과제
96. • 이터너티님의 블로그(http://aeternum.egloos.com)
• 백기선님 블로그 (http://whiteship.me)
• 이미 2005년에 작성된 토비님의 아티클
Domain Model vs. DTO : http://toby.epril.com/?p=99
• 실전 코드가 있는 자바지기님의 DTO에 관한 최근 아
티클 : http://www.slipp.net/wiki/pages/viewpage.action?pageId=2031636
• Javacan님의 DDD 발표자료 : http://javacan.tistory.com/entry/DDD-
%EC%8C%A9%EA%B8%B0%EC%B4%88-%EC%84%B8%EB%AF%B8%EB%82%98-%EB%B0%9C%ED%91%9C-%EC%9E%90%EB%A3%8C
좋은 자료
97. • Clean Code (Chapter 6 객체와 자료 구조)
• http://codebetter.com/gregyoung/
2010/02/16/cqrs-task-based-uis-event-
sourcing-agh/
• http://martinfowler.com/bliki/CQRS.html
참고
115. 뚱뚱한 Service
회원ENTITY
BIZ LOGIC
View A
View B
View C
회원DTO
+ViewA로직
+ViewB로직
+ViewC로직
View D 회원관리DTO
+ViewD로직
회원Service
+회원등록()
+회원수정()
+회원탈퇴()
+getMemberDTO()
+getMemberManageDTO()
...DTO()
그래 나 뚱뚱하다!
118. 뚱뚱한 Service
회원ENTITY
BIZ LOGIC
View A
View B
View C
회원DTO
+ViewA로직
+ViewB로직
+ViewC로직
View D 회원관리DTO
+ViewD로직
회원Service
+회원등록()
+회원수정()
+회원탈퇴()
+getMemberDTO()
+getMemberManageDTO()
...DTO()
그래 나 뚱뚱하다!
119. 뚱뚱한 Service
회원ENTITY
BIZ LOGIC
View A
View B
View C
회원DTO
+ViewA로직
+ViewB로직
+ViewC로직
View D 회원관리DTO
+ViewD로직
회원CommandService
+회원등록()
+회원수정()
+회원탈퇴()
회원
QueryService+getMemberDTO
()
+getMemberManageDTO()
...DTO()