9. Tag만들기

CustomTag를 공부 하다가 느낀 점은.. ‘servlet으로 html 코드 뿌리는 것 같다.’, ‘복잡하네..언제는 뭐 상속 받고 언제는 뭐 상속 받고…어떤거 구현해줘야 하고 뭐를 리턴 해줘야 하고,,,,’

그런데 TagFile을 사용하면 매우 단순하게 태그를 만들 수 있었습니다.

1. Tag로 만들 부분 물색.
2. Tag를 만들었다는 가정하에 Tag를 사용해서 변경.
3. Tag 파일 작성.
4. 확인.

2번 다음에 확인하고 5. 수정하고 싶은 부분 수정하고 다시 확인 요거만 추가 하면 TDD랑 많이 닮은 것 같네요.

1. Tag로 만들 부분 물색.
사용자 삽입 이미지2. 먼저 위에 있는 빨간색 부분을 다음과 같이 Tag가 있다고 생각하고 바꿔줍니다.
사용자 삽입 이미지3. 그리고 WEB-INF/tags/os 안에 새로운 태그를 정의해 줍니다. page라는 태그명을 사용했기 때문에 page.tag라는 파일을 작성합니다.

<%@ attribute name=”title” required=”true” %>
<html>
    <head>
        <title>${title}</title>
        <link rel=”stylesheet” type=”text/css” href=”/css/style.css” />
    </head>
    <body>
        <jsp:doBody />
    </body>
</html>

JSP 페이지 지시자를 사용해서 태그의 속성을 나타내고 EL태그로 원하는 위치에 사용하면 됩니다. 몸체가 있는 태그라면 하늘색 부분 처럼 몸체가 들어갈 부분에 <jsp:doBody /> 태그를 사용해 주면 됩니다. 이밖에도.. JSTL의 <c:set /> <c:if /> 이런 태그들을 이용해서 속성값에 기본 값을 setting하고 조건에 따라 값을 바꿀 수 있습니다.

4. 확인하기.
사용자 삽입 이미지이런 에러가 납니다. title이 필수 속성이라고 했는데 왜 안넣어줬느냐!! 라는 것인데.. 전 넣는다고 넣어는데?? 라고 생각하고 소스를 다시 보니.. titile 라고 오타를 쳤네요. ㅠ.ㅠ

사용자 삽입 이미지OK! 수정하고 새로고침을 해보니깐 제대로 나왔습니다.

8.4. 기능 구현

검색 기능을 구현해 봅니다.

1. Dao 테스트에 다음과 같이 “s”로 검색 했을 때 두명이 나올 것이라고 예상합니다. 이런 예상의 근거는 DBUnit을 사용해서 XML에 있는 Data를 넣어서 사용할 것이기 때문에 XML에 있는 데이타를 근거로 삼았습니다.

    public void testGetMembers() throws Exception{
        insertFlatXmlDataSet(“test/src/keesun/kSampleData.xml”);
        assertEquals(2, kMemberDao.getMembers(“s”).size());
    }

2. 그리고 이클립스를 보고 있으면 컴파일 에러가 발생하는 것을 확인할 수 있습니다. 당연하죠. getMembers(String)이라는 인터페이스가 MemberDao 에 없기 때문입니다. 만들어 주면 되죠.

public interface KMemberDao extends GenericDao<KMember, Integer>{

    public List<KMember> getMembers(String string);

}

3. 인터페이스에 추가해 줬더니 이젠 이걸 구현한 쪽에서 에러가 발생합니다. 이것을 구현해 주고 테스트의 결과 녹색불이 들어오면 구현이 끝납니다.

    @SuppressWarnings(“unchecked”)
    public List<KMember> getMembers(final String name) {
        return getHibernateTemplate().executeFind(new HibernateCallback(){
            public Object doInHibernate(Session s) throws HibernateException, SQLException {
                Query q = s.createQuery(“from k_Member m where m.name like :name order by m.name asc”)
                           .setParameter(“name”, “%” + name +”%”);
                return q.list();
            }
        });
    }

위 코드에서 getHibernateTemplate()으로 HibernateTemplate객체를 받아오고 이 객체의 executeFind() 메소드를 사용해서 자기가 할일을 남(HibernateCallback)을 시켜서 합니다.

구현을 아래 처럼 간단하게 할 수도 있는데요.

        Session s = getSession();
        Query q = s.createQuery(“from k_Member m where m.name like :name order by m.name asc”)
                      .setParameter(“name”, “%” + name +”%”);
        return q.list();

callback을 사용하는 이유가 있겠죠? 궁금하네요~ *_*

8.3. Criteria 공부하기

특정 Member의 검색을 할 때 이름만 입력할 수도 있고 이메일만 입력할 수도 있습니다. 입력 할 수 있는 곳이 여러 곳이면 둘 다 입력하거나 둘 다 입력하지 않을 수도 있습니다. 이럴 때 입력을 하느냐 안하느냐에 따라 쿼리가 달라지는데요. 이런것을 Dynamic Query라고 하는것 같습니다.

HQL을 이용해서 이러한 쿼리를 다음과 같이 작성할 수 있습니다.

    public void testDynamicQueryByHQL(){
        insertDatas();
        String name = “s”;
        String email = null;

        StringBuffer sb = new StringBuffer(“from k_Member m where 1=1”);
        if(!StringUtils.isEmpty(name)) sb.append(” and m.name like :name”);
        if(!StringUtils.isEmpty(email)) sb.append(” and m.email like :email”);
        q = s.createQuery(sb.toString());
        if(!StringUtils.isEmpty(name)) q.setParameter(“name”, “%” + name + “%”);
        if(!StringUtils.isEmpty(email)) q.setParameter(“email”, “%” + email + “%”);

        assertEquals(2, q.list().size());
    }

위와 같은 내용의 쿼리를 Criteria를 사용해서 작성하면 다음과 같이 간결해 집니다. 그리고 @Entity의 name속성에 지정해 준 값을 사용하는 것이 아니라 진짜 클래스 명을 사용해야 합니다.

    public void testDynamicQueryByCriteria(){
        insertDatas();
        String name = “s”;
        String email = “keesun@os.net”;

        Criteria c = s.createCriteria(KMember.class);
        if(!StringUtils.isEmpty(email)) c.add(Restrictions.eq(“email”, email));
        if(!StringUtils.isEmpty(name)) c.add(Restrictions.like(“name”, “%” + name + “%”));

        assertEquals(1, c.list().size());
    }

Criteria의 add 메소드는 인자로 Criterion을 넘겨 주어야 하는데요. Restrictions라는 팩토리를 사용해서 Criterion을 받아 오게 됩니다. Restrictions 클래스에는 쿼리에 덧붙일 수 있는 여러 메소드들이 있습니다.

8.2.4. HQL 공부하기 – inner join

insertDatas() 메소드에서 집어 넣는 데이타에서 Member와 Messenger의 모습을 보면 다음과 같습니다.

사용자 삽입 이미지

seal 멤버만 두개의 Messenger 정보를 가지고 있습니다. 이 때 inner join을 하면 다음과 같이 두개의 레코드가 생기게 됩니다.
사용자 삽입 이미지inner join을 HQL로 하는 방법은 s.create(“from Member m inner join m.messengers”) 이렇게 콜렉션을 가리키면 됩니다.



public void testJoinHQL(){


       insertDatas();


       q = s.createQuery(“from k_Member m inner join m.messengers”);


       List<Object> result = q.list();


       // Member m1 | Messenger msg1(“keesun”, MSN)


       // Member m1 | Messenger msg2(“keesun2”, Skype)


       assertEquals(2, result.size());


       Object[] result1 = (Object[]) result.get(0);


       assertTrue(result1[0] instanceof KMember);


       assertTrue(result1[1] instanceof KMessenger);


       KMessenger msg1 = (KMessenger) result1[1];


       assertEquals(“seal”, msg1.getM_id());


       assertEquals(KMessengerType.MSN, msg1.getM_type());


}