우리생애 최고의 순간

사용자 삽입 이미지
이 경기의 원본을 본 기억이 있는데, 자세히 기억이 나지 않습니다. 영화를 보고나니 그때도 ‘승부 던지기’까지가는 접전을 펼친 기억이 났는데 정말 재밌습니다.

스토리야 뻔하지만 여러 가지를 생각하게 하는 영화였습니다.

먼저, 감독님. 국대 감독직을 떠나 산골짜기 학교의 핸드볼 코치로 일하러 가셨습니다. 그렇게 사는 것도 좋다고 하시면서 말이죠. 그 자리를 매꾸는 새로운 감독. 선수들을 팀이 아니라 통제 대상으로 생각합니다. 감독이 팀원을 믿지 못하면 그 경기는 무조건 진다. 라는 말을 듣고 좀 변하기 시작합니다.

그리고 선수들의 팀웤. 노장들과 어린 친구들간의 불화가 해결되는 과정을 보여줍니다. 역시 ‘우리는 하나다.’라는 공동체의식으로 노장들이 어린친구들을 잘 보살펴주니 자연스럽게 해결되더군요. 재밌었습니다. 그리고 노장들이 나이만 믿고 텃새를 부리는 것이 아니라 전부 실력이 상위 5위안에 들었다는 것이 더 멋졌습니다. 나이값하는 노장에다가 든든함으로 어린친구들을 보살펴주다니 이 보다 더 좋은 팀웤이 있을지..

선수는 개발자로..
감독은 관리자로..
경기는 프로젝트로..
맵핑이 됩니다.

저도 저런 팀에서 개발을 해보고 싶습니다. 최고의 순간을 만끽해보기 위해~
그러려면 저는 일단 기초체력부터 열심히 닦아서 엔트리에 들어갈 수 있는 실력부터 닦아야 합니다.

결론은 열공!!!

XML 도메인 모델

특징

  • The XML data model is weak, its type system is complex and underpowered.
  • its data integrity is almost completely procedural.
  • it introduces hierarchical data structures that were outdated decades ago.
  • However, data in XML format is attractive to work with in Java; we have nice tools.

XML로 도메인 모델 뽑아내기

DOM4J로 도메인 모델 뽑아내기
Session dom4jSession = session.getSession(EntityMode.DOM4J);
Element userXML =
(Element) dom4jSession.load(User.class, storedUserId);
  • Element 클래스는 Dom4J API
화면에 출력하기
try {
OutputFormat format = OutputFormat.createPrettyPrint();
XMLWriter writer = new XMLWriter( System.out, format);
writer.write( userXML );
} catch (IOException ex) {
throw new RuntimeException(ex);
}

맵핑할 때 node 속성 사용하기

  • <class> 나 <property> 맵핑에서의 node 속성(node=”name”)은 XML 엘리먼트의 이름을 정의한다.
  • <property> 맵핑에서 node 속성(node=”@name”)은 XML 엘리먼트의 속성을 정의한다.
  • <property> 맵핑에서의 node 속성(node=”name/@attname”)은 name이라는 자식 엘리먼트에 attname이라는 속성을 정의한다.
  • 위의 속성을 사용해서 맵핑하면, 도메인 모델을 표현할 XML을 원하는 형태로 정의할 수 있다.

Map 도메인 모델

특징

  • A dynamic domain model is a model that is dynamically typed.
<hibernate-mapping>
<class entity-name="ItemEntity" table="ITEM_ENTITY">
<id name="id" type="long" column="ITEM_ID">
<generator class="native" />
</id>
<property name="initialPrice" type="big_decimal"
column="INIT_PRICE" />
<property name="description" type="string" column="DESCRIPTION" />
<many-to-one name="seller" entity-name="UserEntity"
column="USER_ID" />
</class>
<class entity-name="UserEntity" table="USER_ENTITY">
<id name="id" type="long" column="USER_ID">
<generator class="native" />
</id>
<property name="username" type="string" column="USERNAME" />
<bag name="itemsForSale" inverse="true" cascade="all">
<key column="USER_ID" />
<one-to-many entity-name="ItemEntity" />
</bag>
</class>
</hibernate-mapping>
  • 다수의 도메인 맵핑을 하나의 파일 안에 두고 있다. 자바 클래스를 맵핑하는 것이 아니기 때문에 메타데이터를 어떻게 구성하던 맘대로 하라.
  • <class name=”…”> 대신에 <class entity-name=”…”> 를 사용했으며, 정적인 도메인 모델과 구분하기 위해 Entity를 접미어로 사용했다.
  • <many-to-one> 와 <one-to-many> 에서 entity-name에 설정한 이름을 사용했다.

동적인 맵 사용하기

동적인 맵 사용 예제
Map user = new HashMap();
user.put("username", "johndoe");

Map item1 = new HashMap();
item1.put("description", "An item for auction");
item1.put("initialPrice", new BigDecimal(99));
item1.put("seller", user);

Map item2 = new HashMap();
item2.put("description", "Another item for auction");
item2.put("initialPrice", new BigDecimal(123));
item2.put("seller", user);

Collection itemsForSale = new ArrayList();
itemsForSale.add(item1);
itemsForSale.add(item2);
user.put("itemsForSale", itemsForSale);

session.save("UserEntity", user);
  • Entity 하나 당 HashMap 객체 하나에 대응한다.
  • ArrayList는 bag을 맵핑하려고 사용했다.
  • Session.save(entity-name, HashMap)를 사용해서 저장했다.
  • cascading에 의해서 user와 user와 연관을 맺고 있는 두 개의 Item 역시 DB에 저장됐다.
  • Set을 사용하면 안 된다. Map은 equals()를 할 때 키값을 가지고 비교하기 때문에, Set을 사용하면 여러 개의 Entity를 넣을 수 없다.

정적인 엔티티 모드와 동적인 엔티티 모드 혼용하기

  • 맵핑할 때, <class name=”model.UserPojo” entity-name=”UserEntity” table=”USER_ENTITY”> 이런식으로 클래스이름과 논리적인 이름을 모두 설정해 준다.
  • Session을 사용할 때는 entity-name을 사용해야 한다.
  • Session의 결과로 받는 값은 기본으로 POJO 객체다.
  • 둘 모두 <property name=”default_entity_mode”>dynamic-map</property> 를 사용해서 Map을 사용하도록 설정할 수 있다.
  • 특정 세션만 Map을 사용하도록 설정할 수 있다. Session dynamicSession = session.getSession(EntityMode.MAP);
  • Note that you can’t link a map with a POJO instance. 당근이지.

하나의 클래스 여러번 맵핑하기

  • 맵핑 할 때 entity-name에 다른 값을 주면, 같은 클래스를 사용해서 서로 다른 테이블로 맵핑할 수 있다.
<hibernate-mapping>
<class name="model.Item" entity-name="ItemAuction"
table="ITEM_AUCTION">
<id name="id" column="ITEM_AUCTION_ID">...</id>
<property name="description" column="DESCRIPTION" />
<property name="initialPrice" column="INIT_PRICE" />
</class>
<class name="model.Item" entity-name="ItemSale" table="ITEM_SALE">
<id name="id" column="ITEM_SALE_ID">...</id>
<property name="description" column="DESCRIPTION" />
<property name="salesPrice" column="SALES_PRICE" />
</class>
</hibernate-mapping>

Many To One 관계를 폼을 통해서 세팅하는 방법 고민 중.

참조 무결성.
– Many 쪽의 객체를 생성할 때 반드시 One 쪽의 객체를 세팅해줘야 함.

1. Many To One 관계가 단방향일 경우.
– Many 쪽 객체가 One 쪽의 객체를 알고 있는 경우. 테이블에서도 실제 Many쪽의 릴레이션에 One쪽의 id를 가지고 있는 컬럼을 가지고 있다.

1-1. Many쪽 객체를 생성하는 페이지에서 해당 객체가 어디에 속할 지 알고 있는 경우.
– 예를 들어, 특정 게시판에서 글하나를 추가하는 경우 해당 글은 이미 자기가 어디에 속해야 할 지 알고 있다.

1-2. Many쪽 객체를 생성하는 페이지에서 해당 객체가 어디에 속할 지 모르고 있는 경우.
– 예를 들어, 티스토리 블로그처럼 글을 작성하는 시점에 해당 글이 포함될 카테고리를 선택할 수 있다.

2. Many To One 관계가 양방향일 경우.
– 위에서 언급한 관계를 설정한 뒤에 추가적으로 One 쪽의 객체에서 자기가 가지고 있는 모든 Many 쪽의 객체들을 알고 있어야 한다.

2-1. Many쪽 객체를 생성하는 페이지에서 해당 객체가 어디에 속할 지 알고 있는 경우.

2-2. Many쪽 객체를 생성하는 페이지에서 해당 객체가 어디에 속할 지 모르고 있는 경우.

폼에서 그럼 어떻게 세팅해야 할까?

1-1-1. Session에서 One 쪽 객체를 가지고 있을 경우
– 예를 들어, 현재 게시판 BoardID를 Session에서 가져와서, Post를 생성할 때, session에서 이 값을 가져와서 실제 Board 객체를 가져온 다음에 Post에 세팅하기.

int boardID = SessionUtil.getIntValue(req, “boardID”); //SessionUtil 이 있다고 치고..
Post.setBoard(boardDao.get(boardID));

1-1-2. 굳이 세션에 boardID를 담고 있어야 할까?
– 생각해보니, Sessino에 들도 다닐 필요가 없다. 게시판에서 “새글 작성하기” URL을 다음과 같이 만들면 되겠다.

addPost.do?boardID=${board.boardID}

물론 이렇게 한 다음 1-1-1. 같은 코드를 사용해서 Board 객체를 Post에 세팅한다.

1-2. Session에 모든 카테고리 목록을 들고 다닌다.
– 새 글을 작성할 때, 화면에서 카테고리 목록을 뿌려줘야 하고, 카테고리 이름 뿐만 아니라 실제 카테고리의 id도 있어야 한다. 사용자가 특정 카테고리를 선택하고 서브밋을 하면 어떻게 될까?

int categoryID = RequestUtil.getIntValue(req, “categoryID”); //RequestUtil이 있다고 치고..
Post.setBoard(categoryDao.get(categoryID);

– Session은 그럼 무거운 콜렉션을 들고 다녀야 하나? Session에서는 Category 객체 콜렉션이 아니라 Category의 ID와 Name만 들고 다니자. 하지만, 이것도 Session한테는 무리가 될 수 있을텐데..

2-1. URL을 통해서(1-1-1. 같은 방식으로) 어디에 속할지 알수 있기 때문에, 첨부터 세팅해서 폼을 채운다.(Spring의 Petclinic 예제가 사용한 방식)
– request의 속성으로 이미 새로 만들 Many 쪽의 객체가 포함 될 One 쪽 객체의 id를 알고 있기 때문에.. 폼을 채우기 전에 다음과 같이 세팅을 해서 채울 수 있음.

    @RequestMapping(method = RequestMethod.GET)
    public String setupForm(@RequestParam(“ownerId”) int ownerId, ModelMap model) {
        Owner owner = this.clinic.loadOwner(ownerId);
        Pet pet = new Pet();
        owner.addPet(pet);
        model.addAttribute(“pet”, pet);
        return “petForm”;
    }

이때 위의 addPet() 메소드는 아래에 있는 Convenient Method 형태.

    public void addPet(Pet pet) {
        getPetsInternal().add(pet);
        pet.setOwner(this);
    }

2-2. 어디에 속하는지 객체인지 입력(Command 객체)을 통해서 알아낸다.
– 새로운 Many 객체를 추가할 입력 폼에서 One 쪽의 객체를 선택해야 한다.

${post.category.categoryID} 여기에 선택한 카테고리의 ID를 세팅해 주겠지. 이렇게 할 수 있으려면 new Post() 객체에 new Category()를 세팅해준 다음에 화면으로 보내줘야 돼. 안 그러면 NullPointerException이 발생할테니까…(getCategory() 호출할때..)

그럼 formBackingObject 사용해서 보내자. 그렇게 한 다음 command 객체를 받아오면 어떻게 코딩할까.

Post post = (Post)command;
CategoryDao.get(post.getCategory().getCategoryID()).addPost(post);

– 여전히 뭔가 어색하다. Post가 가지고 있는 Category는 id만 채워져있는 비어있는 카테고리이고, 이 id를 가져와서 실제 카테고리를 가져온 다음에 Post를 세팅하고 있다.

공부 할 것
– 세션, 쿠키, 컨텍스트
    Session에 무언가를 들고 다니는 것 자체가 위험할 수 있다.
– 스프링 PetClinit 예제코드