DisplayTag 링크 기능

참조 : http://displaytag.sourceforge.net/11/tut_links.html

<display:column property=”name” title=”이름” href=”detail.do” paramId=”id” paramProperty=”id” sortable=”true” />

이런식으로 지정해 주면 detail.do 로 링크가 생기며 이 링크로 객체의 id를 id라는 이름으로 넘겨 줍니다.

이것을 받아서 member 한명에 대한 정보를 뿌리는 controller를 만듭니다.
[#M_ more.. | less.. | public class MemberDetailController extends AbstractController{

   private MemberRepository memberRepository;

   @Override
   protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {

       Integer id = Integer.parseInt(request.getParameter(“id”));
       Member member = memberRepository.get(id);
       return new ModelAndView(“detail”, “member”, member);
   }

   public void setMemberRepository(MemberRepository memberRepository) {
       this.memberRepository = memberRepository;
   }
}_M#]id로 넘어온 id를 받은 뒤 그것을 가지고 member 객체를 가져오고 다시 member 객체를 detail이라는 view와 함꼐 ModelAndView 객체에 담아서 리턴합니다. 그럼 viewResolver에 의해서 detail.jsp를 찾아가게 될 것입니다.
[#M_ more.. | less.. | <jsp:root version=”1.2″ xmlns:jsp=”http://java.sun.com/JSP/Page”
    xmlns:display=”urn:jsptld:http://displaytag.sf.net”
    xmlns:c=”urn:jsptld:http://java.sun.com/jstl/core“>

    <jsp:directive.page contentType=”text/html; charset=UTF-8″ />
    <jsp:include page=”inc/header.jsp” flush=”true” />

    <h2><c:out value=”${member.name}”/>’s Information</h2>

    <table>
        <tr>
            <th>이름</th>
            <td><c:out value=”${member.name}”/></td>
        </tr>
        <tr>
            <th>Email</th>
            <td><c:out value=”${member.email}”/></td>
        </tr>
        <tr>
            <th>Phone</th>
            <td><c:out value=”${member.phone}”/></td>
        </tr>
        <tr>
            <th>Blog</th>
            <td><c:out value=”${member.blogAddress}”/></td>
        </tr>
        <tr>
            <th>MessengerId</th>
            <td><c:out value=”${member.messengerId}”/></td>
        </tr>
    </table>

    <jsp:include page=”inc/footer.jsp” flush=”true” />
</jsp:root>_M#]
JSTL을 사용하기 위해 taglib을 지정해 주고 이 페이지에 member객체가 넘어 왔을 테니깐 “${member.name}” 이런식으로 사용해주면 됩니다.

사용자 삽입 이미지
결과는..
사용자 삽입 이미지

Validator 사용하기

앞에서 만든 검색창을 사용할 때 빈 값을 넣으면 에러 메시지가 오른쪽에 출력하도록 하고 싶어졌습니다.

사용자 삽입 이미지
저렇게 해주고 싶으면 먼저 Validator가 필요하고…Controller에 Validator를 등록해줘야 하고…View에서 에러 출력할 부분을 표시해 줘야 합니다.

1. Validator 구현하기

public class SearchingValidator implements Validator {

    @SuppressWarnings(“unchecked”)
    public boolean supports(Class clazz) {
        return MemberCommand.class.isAssignableFrom(clazz);
    }

    public void validate(Object obj, Errors errors) {
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, “keyword”, “required”, “Field is required.”);
    }
}

위 코드는 Spring Reference 13.9.12에 있는 error tag 부분에 있는 소스를 거의 그대로 사용했습니다. 여기에 있는 코드를 보기 전에는 Pro Spring을 보고 아래처럼 구현했었습니다. 전 위가 더 간단해 보이고 편했습니다.
[#M_ more.. | less.. | public class SearchingValidator implements Validator {
    public boolean supports(Class clazz) {
        return clazz.isAssignableFrom(MemberCommand.class);
    }

    public void validate(Object obj, Errors errors) {
        MemberCommand command = (MemberCommand) obj;
        if (command.getKeyword() == null || command.getKeyword().length() == 0) {
            errors.rejectValue(“keyword”, “required”, “Field is required.”);
        }
    }
}_M#]2. Controller에 등록하기.

    <bean name=”/search.do”
        class=”member.web.SearchMemberController”>
        <property name=”memberRepository” ref=”memberRepository” />
        <property name=”validator” ref=”searchingValidator” />
    </bean>

    <!– Validator 등록 –>
    <bean name=”searchingValidator” class=”validator.SearchingValidator”/>

3. View에 자리잡기.

        <table>
            <tr>
                <td>SEARCH:</td>
                <td><form:input path=”keyword” /></td>
                <td><form:errors path=”keyword” /></td>
                <td><input type=”submit” value=”GO” /></td>
            </tr>
        </table>

4. 실험해 봤습니다.
사용자 삽입 이미지
수고했삼~

검색창 하나로 모든 필드에서 검색하기.

검색을 할 때 하나의 창에 입력한 값이 멤버와 관련된 어떠한 필드에 포함되더라도 검색을 하도록 구현했습니다. 입력한 값으로 모든 필드를 뒤져보면 되겠죠. 몇일 전 찬욱이가 모든 필드를 나타내는 키워드는 없는지 궁금해 했었는데 궁금해 하는 이유를 물어보다가 이런 기능을 구현할 때 있으면 편하겠구나 하는 생각이 들었는데 찾아보질 않았네요.

애니웨이… 실험해 봤습니다.
사용자 삽입 이미지결과
사용자 삽입 이미지이번에는 blog 주소로 검색을 해봤습니다.
사용자 삽입 이미지결과
사용자 삽입 이미지
흠… 잘 되는 군요.

Good Job! 이제 검색 메뉴를 없애고 검색을 리스트 화면에 합쳐 놓고 리스트 부분만 갱신 되도록 바꿔봐야겠습니다. 검색할려고 다른 곳으로 이동한다는 것이[footnote]눈으로 메뉴를 찾고 클릭을 해야 하고 입력할 곳을 눈으로 찾고 다시 엔터나 클릭을 해야 한다는 번거로움[/footnote]귀찮기 때문이죠.

SimpleFormController 에피소드2

아래 발생한 문제는 SimpleFormController와는 전혀 관계가 없는 내용일 수도 있다는 것을 미리 알려드리고 시작해야겠습니다. 이유는 결론을 보시면 알게 되실듯.

사용자 삽입 이미지위와 같은 리스트가 있습니다. 오호 분명히 “기선”이라는 사람이 매우 많이 있습니다. 왼쪽에 있는 search로 이동해서 “기선”을 찾아 봅시다.

사용자 삽입 이미지이렇게 기선을 입력하고 enter 또는 search 버튼을 클릭했더니 다음과 같은 화면이 출력 됐습니다.

사용자 삽입 이미지헐…출력할 것이 없다니.. 도대체 어디서 문제가 생긴거야???

1. 소스코드를 점검하기 시작합니다. JSP와 Controller를 점검하기 시작했습니다.
[#M_ more.. | less.. |

 컨트롤러

public class SearchMemberController extends SimpleFormController {

    private MemberRepository memberRepository;

    public SearchMemberController() {
        setCommandName(“memberCommand”);
        setCommandClass(MemberCommand.class);
        setFormView(“search”); // 생략가능.
        setSuccessView(“searchResult”);
    }

    public void setMemberRepository(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    @Override
    protected ModelAndView onSubmit(Object command) throws Exception {
        MemberCommand searchingMember = (MemberCommand) command;
//        System.out.println(“message 출력: ” + search.getName());
        ModelAndView mav = new ModelAndView(getSuccessView())
            .addObject(“resultMember”, memberRepository.findByName(searchingMember.getName()))
            .addObject(“memberCommand”, searchingMember);
        return mav;
    }
}

search.jsp

<jsp:root version=”1.2″ xmlns:jsp=”http://java.sun.com/JSP/Page”
    xmlns:display=”urn:jsptld:http://displaytag.sf.net”
    xmlns:form=”http://www.springframework.org/tags/form”>
    <jsp:directive.page contentType=”text/html; charset=UTF-8″ />
    <jsp:include page=”inc/header.jsp” flush=”true” />

    <html>
    <head>
    <title>Search For Members</title>
    </head>
    <body>
    <h2>Search For Members</h2>
    <form:form commandName=”memberCommand” method=”post”>
        <table>
            <tr>
                <td>Name:</td>
                <td><form:input path=”name” /></td>
            </tr>
            <tr>
                <td colspan=”2″><input type=”submit” value=”Search” /></td>
            </tr>
        </table>
    </form:form>
    </body>
    </html>

    <jsp:include page=”inc/footer.jsp” flush=”true” />

</jsp:root>

searchResult.jsp

<jsp:root version=”1.2″ xmlns:jsp=”http://java.sun.com/JSP/Page”
    xmlns:display=”urn:jsptld:http://displaytag.sf.net”
    xmlns:c=”http://java.sun.com/jstl/core_rt”>
    <jsp:directive.page contentType=”text/html; charset=UTF-8″ />
    <jsp:include page=”inc/header.jsp” flush=”true” />

    <jsp:scriptlet>
        java.util.List members = (java.util.List)request.getAttribute(“resultMember”);
        request.setAttribute(“test”, members);
    </jsp:scriptlet>

    <h2>Search Results</h2>

    <display:table name=”test” export=”true”>
        <display:column property=”name” title=”이름”/>
        <display:column property=”email” autolink=”true”/>
        <display:column property=”phone” title=”연락처”/>
        <display:column property=”blogAddress” title=”Blog” autolink=”true”/>
        <display:column property=”messengerId” title=”MSN”/>
    </display:table>

    <jsp:include page=”inc/footer.jsp” flush=”true” />

</jsp:root>

_M#]
처음에는 command 객체에 값이 들어가지 않는 것 같다는 생각이 들었습니다. 중간에 출력문을 한번 넣어보면 될 것을[footnote]소스코드에 주석처리 된 부분입니다.[/footnote] 아직까지도 SimpleFormController가 어떻게 동작하는 것인지 제대로 모르기 때문에 그 떈 더욱 더 Command 객체에 값이 언제 들어가는 것인지 알 수가 없었습니다.

그리고 두번째는 지난 글에서 의문이 들었던 command 객체를 도메인 객체로 써야 하는건가? 싶어서 Member로 바꿔서도 해봤습니다. 결과는… 여전했습니다.

2. 조금더 공부하다가 Command 객체에 값이 들어갔는지 확인해봤습니다. 세상에 값이 들어가 있었습니다. 값이 들어가 있긴 한데… 한글이 깨져있더군요.

message 출력: ?¸°???

-_-;; 난감했습니다. 이전에 DB 인코딩 문제로 한참을 해맸었는데 또다시 인코딩문제인가.. ㄷㄷㄷ 거리고 있었는데 다행히 한수형이 알려주셔서 web.xml에 다음과 같이 코드를 넣어줬더니 한글이 제대로 보였습니다.
[#M_ more.. | less.. |     <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>
            org.springframework.web.filter.CharacterEncodingFilter
        </filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>_M#]
3. 좋았습니다. 이제 콘솔에 찍어보니 한글도 제대로 보이고 검색을 날렸는데… 여전히!! 못찾는겁니다. 왜?? 도대체 왜!! 못찾는거야.. 하면서 iBATIS에 SQL을 확인하러 갔습니다… 세상에…ㅠ.ㅠ
[#M_ more.. | less.. |     <!– find –>
    <select id=”find” resultMap=”memberMap”>
        SELECT id, name, messengerId, email, blogAddress, phone
        FROM Member
        WHERE
        <isNotNull property=”phone”>phone = #phone#</isNotNull>
        <isNotNull property=”blogAddress”>blogAddress = #blogAddress#</isNotNull>
        <isNotNull property=”email”>email = #email#</isNotNull>
        <isNotNull property=”messengerId”>messengerId = #messengerId#</isNotNull>
        <isNotNull property=”name”>name = #name#</isNotNull>
    </select>_M#]like로 바꿔야 겠어요. 흐흐흐흐흐흐흐

SimpleFormController 에피소드1

이녀석을 공부하는 어제부터 현재까지 여러 가지 에피소드들이 있었습니다. 발생한 의문들에 자문 자답을 해봅니다.

1. SimpleFormController가 어떻게 흘러가는 건지 이해가 되지 않았습니다.

AbstractController는 ModelAndView 객체에 요청을 처리할 view이름과 그 view에서 사용할 객체를 전달해 주었습니다. 그런데 이녀석은 그렇게 처리하기엔 뭔가.. 허전하다고 느껴지거든요. 자신에게 어떤 요청이 들어왔다는 것은 무엇을 입력할 곳을 찾아 왔다는 것이고[footnote]검색을 하기 위한 링크를 클릭 했다든가 회원 가입, 글 쓰기등의 버튼을 클릭했을 것입니다.[/footnote] 그럼 일단 그 화면으로 이동을 해줘야 하고 그 때 사용자가 입력할 데이타를 받아들일 객체가 있어야겠습니다. 아마도 그녀석을 Command 객체라고 부르는 것 같습니다. 일단 여기까지는 AbstractController와 비슷합니다. 하지만 여기서 끝나면 안되겠죠. 사용자가 입력을 마치고 엔터를 쳤을 때 또 다시 요청이 날아오게 됩니다. 이것도 역시 처리를 해줘야겠죠. 이 요청도 처리를 합니다. 생성자에 setSuccessView(“결과를 보여줄 view 이름”) 을 생성자에 추가해주면 그쪽 페이지로 이동하게 됩니다.

1.1. Command 객체는 뭔가?

도메인 객체인가? 아닌것 같다는 생각이 듭니다. 물론 도메인 객체를 써도 되겠지만 Command 객체는 사용자가 입력한 값을 받아 오는 역할을 하는 객체이고 만약 사용자가 입력하는 정보다 여러개의 객체에 걸쳐있는 값들이라면 그 때는 도메인 객체만으로는 처리할 수 없겠죠. 아마 그럴 땐 Command 객체를 하나 만들어서 그 안에서 해당 객체에 정보가 들어가도록 처리를 해야될 것 같습니다.

1.2. ModelAndView 객체에는 여러 객체가 들어갈 수 있는 건가?

add(“이름”, 객체) 형태의 메소드로 여러 객체를 ModelAndView에 붙여 줄 수 있습니다. 그리고 여기서 붙인 객체들은 “첫번째 요청에 의해 보여지는 페이지”와 “두번째 요청에 의해 보여지는 페이지”[footnote]success view에서 요청한 페이지[/footnote]에서 모두 사용이 가능합니다.