하이버네이트 Criteria 검색 쿼리 골치

select this_.id as y0_ from Post this_ where this_.board_id=?

select this_.id as id1_0_, this_.author as author1_0_, this_.board_id as board7_1_0_, this_.contents as contents1_0_, this_.created as created1_0_, this_.title as title1_0_, this_.updated as updated1_0_
from Post this_
where this_.id in (?, ?, ?, ?, ?, ?) and  lcase(this_.title) like ? or lcase(this_.contents) like ?

===============================================

select this_.id as id1_0_, this_.author as author1_0_, this_.board_id as board7_1_0_, this_.contents as contents1_0_, this_.created as created1_0_, this_.title as title1_0_, this_.updated as updated1_0_
from Post this_
where this_.board_id=? and (lcase(this_.title) like ? or lcase(this_.contents) like ?)

================================================

select this_.id as id1_0_, this_.author as author1_0_, this_.board_id as board7_1_0_, this_.contents as contents1_0_, this_.created as created1_0_, this_.title as title1_0_, this_.updated as updated1_0_
from Post this_
where this_.id in
(select this0__.id as y0_ from Post this0__ where this0__.board_id=?)
and (lcase(this_.title) like ? or lcase(this_.contents) like ?)

=================================================

셋 다 똑같네.. 아.. 이런 ㅠ.ㅠ OTL… 뭐야 ㅠ.ㅠ 어떻게 짜야되지. 흠…

(lcase(this_.title) like ? or lcase(this_.contents) like ?)

이 부분이 잘못 됐나? title에 ?가 있거나 contents에 ?가 있는 것들 검색하려는데 분명 테스트 데이터에는 두 개가 나와야 되는데 계속 한 개만 나오네. 흠… 모르겠네… 모르겠어..

=====================
id | title       | contents
1  | keesun | toby
2  | toby      | toby
3  | toby      | keesun
=====================

이 상태에서 서브 쿼리나 in 뒤에 담겨있는 id는 전부 1, 2, 3이라고 치고… titke이 keesun이거나 contents가 keesun이 row를 갖다 달라는 거자나.

그럼 1번 row를 보면 title이 keesun이니까 맞자나. title이 keesun 이자나 contents는 아니고 그럼 일단 하나.
그리고 3번은 contents가 keesun이니까 맞고..

그럼 결과가 2개가 되야 하는데

결과는 1번만 가져오는… 이 상황은 ..;;; 어렵네~

음헤헷 봄싹 게시판 검색 MVC 완성

먼저 뷰는 위 그림과 같이 간단합니다. 기본값을 설정해서 바로 검색 버튼 눌러서 검색할 수 있도록 해뒀습니다.

기본 값은 다음과 같습니다.

현재일 까지 세 달치 검색, 검색어가 없으면 모두 검색. 있으면 해당 키워드가 있는 제목 또는 본문을 가진 글 검색.

작성일 검색 조건 바뀔 때마다 달력으로 검색 범위를 표현해주면 좋겠는데.. 그런 멋진 UI는 나~~~~중에.. 해보기로 하구요. 일단 저렇게 해놨습니다.

<h1>${board.name} 게시판 검색</h1>
<form:form commandName=”param” action=”/post/list.do”>
    검색어 <form:input path=”keyword”/>
    <form:checkboxes items=”${ref.fieldNames}” path=”fieldNames” /><br/>
    작성일: <form:input path=”basicDate”/>
    <form:select path=”dateSearchingType” items=”${ref.dateSearchingTypes}” />
    <form:select path=”dateSearchingTerm” items=”${ref.dateSearchingTerms}” /><br/>
    <input type=”submit” value=”검색”/>
</form:form>

뷰 핵심 코드는 스프링 form 태그를 이용해서 간단하게~ 샤샥…

저 화면을 보여주는 컨트롤러 코드는

    @RequestMapping
    public void search(int boardId, ModelMap model){
        model.addAttribute(“param”, new PostSearchParam());
        model.addAttribute(boardService.getById(boardId));
    }

참 쉽죠?

저 화면의 폼 처리를 하는 컨트롤러 코드는

    @RequestMapping
    public void list(@ModelAttribute(“param”)PostSearchParam param, ModelMap model){
        System.out.println(param.getKeyword());
        System.out.println(Arrays.toString(param.getFieldNames()));
        System.out.println(param.getBasicDate());
        System.out.println(param.getDateSearchingTerm().name());
        System.out.println(param.getDateSearchingType().name());
//        model.addAttribute(postService.list(param));
    }

요거.. 전 아직도 sysout 디버깅이 넘 좋아요.ㅋㅋ 일단 잘 받는 것 까지 해야 그 다음으로 DAO에서 검색해서 가져오고. 어쩌구 저쩌구를 구현해야 하는데 여기서 한 번 끊고 가는거죠. DAO쪽에선 검색 조건 테스트 할 께 많을테니까요. 짧은 단위로 개발하기..

자.. 저 정도 코드면 될까요? 안 돼죠. 저 녀석들이 주연이면 조연이 필요합니다.

public enum DateSearchingTerm {

    ONE(1, “한 달”), TWO(2, “두 달”), THREE(3, “세 달”), ALL(0, “모두”);

    private int duration;

    private String description;

    DateSearchingTerm(int duration, String description) {
        this.duration = duration;
        this.description = description;
    }

    public int getDuration() {
        return duration;
    }

    public String getDescription() {
        return description;
    }

    public String toString() {
        return description;
    }
}

이 녀석은 작성일 검색 기간 enum으로 duraion은 나중에 DAO에서 검색 조건 만들 때 사용할 속성입니다. 약간 미리 예상하고 만들어 둔 속성이라 거시기 한데… 뭐 필요없어지면 지워버리죠. 하나를 봤으니 딴 건 안 보겠습니다.

public class DateSearchingTermPropertyEditor extends PropertyEditorSupport {

    @Override
    public String getAsText() {
        Object value = getValue();
        if(value == null)
            return “”;
        else
            return value.toString();
    }

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        if(text.equals(“한 달”))
            setValue(DateSearchingTerm.ONE);
        if(text.equals(“두 달”))
            setValue(DateSearchingTerm.TWO);
        if(text.equals(“세 달”))
            setValue(DateSearchingTerm.THREE);
        if(text.equals(“모두”))
            setValue(DateSearchingTerm.ALL);
    }

}

이 녀석은 프로퍼티 에디터 나중에 폼 처리하는 메소드에서 바인딩 할 때 모르는 타입이라고 에러가 날 겁니다. 그래서 이 녀석을 등록해줘야 하죠,

등록은 컨트롤러에서..

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(“yyyy-MM-dd”);
        dateFormat.setLenient(false);

        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
        binder.registerCustomEditor(DateSearchingTerm.class, new DateSearchingTermPropertyEditor());
        binder.registerCustomEditor(DateSearchingType.class, new DateSearchingTypePropertyEditor());
    }

이렇게 해도 되고 쟤들은 다른 컨트롤러도 사용할 테니까 나중에 글로벌하게 XML에 다음의 코드를 이용해서 등록해도 되겠죠

<bean class=”org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter”>
    <property name=”cacheSeconds” value=”0″ />
    <property name=”webBindingInitializer”>
        <bean class=”org.springframework.samples.petclinic.web.ClinicBindingInitializer” />
    </property>
</bean>

from 스프링 레퍼런스 13장

쪼아.. 이제 DAO 구현하러 ㄱㄱㄱ…

게시판에서 글 검색 기능은 어떻게 만들까?

이번주 봄싹 스터디에서는 검색 기능을 구현해 가려고 합니다. 원랜 페이징까지 구현해 가려고 했는데 요즘 번역이 좀 밀려서 번역에 에너지를 쏟았더니 눈이 아파서 코딩을 못하겠네요.

어쩃든, 검색 기능을 어떻게 구현할지 생각해 봤습니다. 제가 주로 이용하던 검색은 구글이나 네이버 같이 어떤 글을 검색할 땐 키워드 하나면 충분합니다. 그 키워드가 어떤 글의 내용이 될 수도 있고 작성자나 글 제목이 될 수도 있겠죠. 그래서 좀 더 세분화 하기 위해서 어떤 필드(제목, 내용, 글쓴이)를 검색할 키워드로 사용할 것인지를 선택할 수 있도록 기능을 제공해야겠다는 생각이 들었습니다.

다음은 글을 쓴 날짜가 관건인데 이 부분은 고민이 좀 됐습니다. 날짜를 두 개씩 받아서 Between으로 검색을 하자니 매번 날짜 입력하기도 참 불편하고 그렇다고 날짜가 없으면 가져오는 데이터가 너무 많고 그래서 샤워하다가 생각난 것이 은행 사이트의 거래 내역 조회입니다. 은행 사이트에서 거래 내역 조회할 때 보통 기본값으로 1주일이나 한 달치가 검색이 되고 어떤 사이트는 최대 Between을 세 달로 제한해서 검색 대상이 되는 데이터의 범위를 줄여놨습니다. 이걸 게시판에 응용해볼 생각입니다.

검색 조건 파라미터를 나타내는 클래스의 필드는 총 다섯개 입니다.

String keyword
Stringp[] filedNames
Date baseDate
DateSearchingTerm dateSearchingTerm
DateSearchingType dateSearchingType

필드 이름은 String 타입의 속성 이름 배열이 되고 그 중에서 keyword를 가진 녀석들을 검색할 겁니다. 그리고 날짜는 baseDate를 기준으로 type에 따라 하향(from), 상향(to), 중심(around)으로 term 만큼 검색을 할 겁니다. UI 기술이 좀 받쳐주면 아주 잼난 UI를 만들 수 있겠는데 일단은 단순 입력으로 가야겠죠. 전 UI에 약합니다. ㅠ.ㅠ

여기서 재밌는게 DateSearchingTerm 이랑 DateSearchingType 인데, 이 녀석들은 enum으로 만들 겁니다. enum으로 선택지를 만들어 두고 enum이 제공하는 name()과 values() 메소드를 이용해서 화면에 뿌릴 이름을 toString()을 재정의 해서 보여줄 것이고 선택지 컬렉션을 화면에 전달할 겁니다. 이 녀석들은 기본 타입이 아니라 스프링이 어떻게 바인딩 해야 하는지 당연히 모르겠죠. Date도 마찬가지 입니다. 그래서 커스텀 에디터를 만들어서 등록해주고, 차후에는 Date 검색 부분만 따로 분리해서 다른 도메인의 검색 파라미터에서도 재사용하기 쉽도록 해야겠습니다.

오늘은 맥주를 마셨으니 코딩은 내일로 미루고 오늘은 피아노나 조금 치다가 자야겠습니다. Good Night~

게시판 페이징은 어떤 기능을 갖추고 있어야 할까?

봄싹 스터디에서 게시판을 구현하기로 했습니다. 간단한 CRUD와 페이징처리가 주 목적이며, 저를 포함한 대, 여섯 명의 개발자 분들이 자기 나름대로 구현해온 코드를 서로 보여주고 피드백을 받는 방식으로 진행될 예정입니다. 이를 통해 스프링을 실제 프로젝트에 적용하는 방법은 물론이거니와, 게시판 구현 방법에 대한 고민도 나눌 수 있을 것 같고, 개발 전반에 좋은 코드, 좋은 개발 방법 및 현재 자신에게 필요한 학습은 무엇인가에 대한 고민까지도 해볼 수 있는 좋은 스터디로 생각하고 있습니다.

Anyway, 기존 애플리케이션들의 UI를 보면서 페이지 네비게이션을 어떻게 구현하면 좋을지 고민해봤습니다.

Gmail


– 처음은 일단 가장 최신 글(메일)을 보여주고, “이전” 과 “처음”이 있군요.
– “이전”을 클릭하면 “이전” 과 “처음”은 그대로 있고, “다음”이 추가됩니다.
– 또 한 번 “이전”을 클릭하면 “이전”과 “처음”, “다음”은 그대로 있고, “최근”이 추가됩니다.

두 번째에서 “다음”만 추가한 건 “다음”이 곧 “최근”이기 때문이죠. 이런 페이징의 단점은 중간으로 이동할 수가 없다는 겁니다. “다음”만 10번 눌렀다가 세 번째 페이지로 이동하고 싶을 땐 어떻게 하죠?? 바로 이동할 수 있는 방법은 없습니다. “최근”으로 갔다가 “이전”을 세 번 클릭하는 수밖에..

한 페이지에 보이는 목록의 갯수 설정은 환경 설정에서 할 수 있습니다. 기본으로 50개씩 보여주는데, 이 설정을 별도의 페이지로 옮겨둔건 좋은 것 같습니다. 자주 바꾸는 설정도 아닐텐데 자꾸 눈에 들어오면 괜히 한 번 해보고싶고, 그럼 괜히 불필요한 요청만 늘어날 뿐이니까요. 이런 경우에는 대신 모델 설계가 좀 달라질 것 같습니다. 게시판에 대한 설정을 담고 있는 별도의 모델이 있고 그 모델의 속성으로 한 페이지당 목록 갯수가 들어있을 것 같습니다. 반대로, 만약 페이지와 한 페이지에 대한 목록 갯수가 같이 따라 다닌다면, 페이징 관련 모델에 한 페이지 목록 갯수가 속성으로 들어있겠죠?

Forum


KSUG 포럼 게시판의 페이징을 봤습니다. 처음 모습 그대로를 유지하고, 버튼의 색으로 현재 페이지를 구분하고 있습니다. 일단 위에서 언급했던 중간 페이지로의 이동이 가능해졌습니다. 대신, 여기서도 한 페이지당 갯수 설정 화면은 보이지 않습니다. 어딘가 게시판 설정 페이지에 있을 것 같습니다. 포럼과 Gmail과의 공통점은 둘 다 거의 한 페이지의 내용이 브라우저 범위를 벗어나서 스크롤리 필요하다는 겁니다. 그래서인지, 페이지 네비게이션이 화면의 가장 상단과 가장 하단 두 곳에 모두 위치하고 있습니다. 이런 UI가 사용자에 편하다는 반증으로 생각됩니다. 따라서 화면을 만들 때 네비게이션 부분을 컴포넌트화 해야겠다는 생각이 듭니다. 그래야 코드 중복도 최소화 하고 관리하기 쉬울테니까요.

게시판


제가 자주가는 어떤 사이트의 게시판에 있는 페이지 네비게이션 부분을 봤습니다. 고정이라는 측면에선 포럼과 동일했습니다만, 게시물 갯수에 대한 정보는 없었습니다. 게시물 목록에서 해당 게시물의 번호를 가지고 있는데 그 번호가 그런 정보를 줄테니 굳이 필요 없었던 것 같습니다. 다만, 게시물 번호가 그다지 사실상 사용자에게 그리 의미가 있는지는 모르겠습니다. 게시물을 어떤 URL로 접근하는 것과, 게시물의 번호로 게시물에 접근하는 것의 차이는 좀 크다고 봅니다. 개인적으로는 URL로 게시물에 접근하는게 더 타당해 보이니, 번호는 사실 필요 없다는 생각입니다. 그리고 이 게시판은 한 페이지 목록 수가 작아서 네비게이션을 자주 해야 합니다. 대신에 네비게이션 바는 화면의 맨 하단에 하나만 위치하고 있습니다. 한 화면에 전부 눈에 들어오기 때문에 위의 두 경우처럼 위, 아래 두 곳에 네비게이션 바를 둘 필요는 없다고 생각했을지도 모르는데.. 뭐 타당해 보입니다. 여기서도 한 페이지당 목록 수를 설정하는 화면은 보이지 않습니다.

하아~~ 페이징 어떻게 구현할까나..