프로젝트

Spring mini project 검색 로직 만들기

승현0604 2023. 6. 25. 09:32

앞서 우리프로젝트에서는 2가지의 검색로직이 있었다 하나는 검색단어를 통한 검색방법과 카테고리를 통한 검색 방법이 있었는데 이 로직을 구현한걸 정리할려고 한다

 

1. 단어 검색

<select id="search" parameterType="String" resultType="com.seoul.guide.tour.DTO.TourDTO">
  <![CDATA[
    SELECT t.tourist_id, t.tourist_name, t.tourist_title, t.tourist_subtitle, t.tourist_content, t.tourist_restdate, t.tourist_time, t.tourist_phonenumber, t.tourist_site, t.lati, t.logi, t.local, t.menu_icon1, t.menu_icon2, t.menu_icon3, t.menu_icon4, t.menu_icon5, t.menu_icon6, t.menu_icon7, COALESCE(l.like_count, 0) AS like_count
    FROM tourist t
    LEFT JOIN (
        SELECT tourist_id, COUNT(like_id) AS like_count
        FROM Likemark
        GROUP BY tourist_id
    ) l ON l.tourist_id = t.tourist_id where tourist_name like concat('%', #{word}, '%') or tourist_subtitle like concat('%', #{word}, '%') 
    ]]>
</select>

기존에 전체조회했던 코드에 where을 붙인것뿐이다 

t.tourist_id where tourist_name like concat('%', #{word}, '%') or tourist_subtitle like concat('%', #{word}, '%') 

이부분이 추가된것인데 like concat을 사용했는데 like는 부분적으로 일치를 할때 찾아주는 역할을 해준다  그리고 concat을 활용하여 양쪽에 '%'을 붙여줌으로서 공백 및 빈 공간에 대한문자열을 합쳐주는 역할을 한다. 이러면 사용자가 무의식적으로 띄워쓰기하면서 검색을 해도 뜨게끔하는 말이 되는것이다!!

 

이제 DAO -> Service -> Controller로 이동을 시켜준다. 

@Override
public List<TourDTO> Search(String word) throws Exception {
    return sqlsession.selectList("mapper.tour.search", word);
}
@Override
public List<TourDTO> Search(String word) throws Exception {
    return tourDAO.Search(word);
}
@RequestMapping(value="toursearch", method = RequestMethod.POST)
public ModelAndView searchTour(@RequestParam("word") String word) {
    ModelAndView mav = new ModelAndView();
    try {
        List<TourDTO> tourlist = tourservice.Search(word);
        mav.addObject("tourlist", tourlist);
        mav.setViewName("tour/tour");
    }catch(Exception e) {
        e.printStackTrace();
    }
    return mav;
}

이 방법으로 검색 로직은 성공하였다

 

2. 카테고리 검색 

 

알다시피 검색로직은 이렇게 생겼다 

위에는 checkbox형태로 들어가있는 형태이고 밑에는 select형태로 들어가져있는 검색이다

이 검색로직에 대한 조건은 다음과 같다

1. 둘다 검색이 될 필요는 없다 (교통약자만 검색해도 괜찮고, 지역선택만 검색해도 검색결과가 나와야한다)

2. 둘다 검색을 해도 and조건으로 둘의 조건을 모두 충족시키는 결과값이 나와야한다

3. 검색결과 없으면 없는대로 출력되어야한다(오류 배제)

 

그래서 sql문에 조건을 거는 현상이 발생하게 되는데 정리코드는 다음과 같이 나왔다 

 

<select id="searchdetail" parameterType = "java.util.Map" resultType="com.seoul.guide.tour.DTO.TourDTO">
     SELECT t.tourist_id, t.tourist_name, t.tourist_title, t.tourist_subtitle, t.tourist_content, t.tourist_restdate, t.tourist_time, t.tourist_phonenumber, t.tourist_site, t.lati, t.logi, t.local, t.menu_icon1, t.menu_icon2, t.menu_icon3, t.menu_icon4, t.menu_icon5, t.menu_icon6, t.menu_icon7, COALESCE(l.like_count, 0) AS like_count
    FROM tourist t
    LEFT JOIN (
        SELECT tourist_id, COUNT(like_id) AS like_count
        FROM Likemark
        GROUP BY tourist_id
    ) l ON l.tourist_id = t.tourist_id
        where
      <choose>
        <when test="menu_icon!=null">
            <foreach collection="menu_icon" item="menu" index="index" open="("  separator = " " close =")" >
                <if test="index>0">
                    OR
                </if>
                <choose>
                  <when test="menu == 'type1'">
                    (menu_icon1 = 1 OR menu_icon3 = 1 OR menu_icon4 = 1)
                  </when>
                  <when test="menu == 'type2'">
                    menu_icon6 = 1 
                  </when>
                  <when test="menu == 'type3'">
                    menu_icon5 = 1 
                  </when>
                  <when test="menu == 'type4'">
                    menu_icon2 = 1 
                  </when>
                </choose>
            </foreach> 
            <if test="tourist_subtitle!=null and tourist_subtitle!=''">
                and tourist_subtitle = #{tourist_subtitle}
            </if>
        </when>
        <otherwise>
            <if test="tourist_subtitle!=null and tourist_subtitle!=''">
                tourist_subtitle = #{tourist_subtitle}
            </if>
        </otherwise>
    </choose>
</select>

생각보다 엄청복잡했는데.. 하나씩 설명을 하자면 일단 우리가 사용하고있는 관광지 데이터는 7가지의 교통약자 시설이 존재를 한다. 하지만 우리의 버튼은 4개인데 7가지 교통약자 시설에 대한 정보는 다음과 같다 

 

장애인용 출입문 휠체어 대여 가능 유무 장애인 화장실 유무 장애인 전용 주차장 유무 유아차 대여 여부 점자가이드 유무 오디오가이드 유무

이렇게 7가지의 정보가 존재하는데 이중에서 1번 3번 4번은 지체장애에 해당된다. (물론..제생각이 틀릴수도있다) 그래서 '지체장애'라는 버튼을 클릭했을때 1,3,4번의 시설 중 하나라도 구축이 되어있다면 검색결과에 나와야하는게 첫번째 조건이다. 

 

그래서 

                  <when test="menu == 'type1'">
                    (menu_icon1 = 1 OR menu_icon3 = 1 OR menu_icon4 = 1)
                  </when>

이부분을 보면 버튼 type이 1인경우 3개의 아이콘들이 1인경우가 하나라도 있어야 한다는 조건이 성립이 되는것이다

나머지는 하나씩 있으므로 하나씩 처리를 해주었다. 

 

그러면 나머지 type사이사이에 조건을 어떻게 처리를 해주었냐 이건 foreach로 처리를해주었는데 

xml에서 사용하는 foreach는 다음과 같다

<foreach collection="menu_icon" item="menu" index="index" open="("  separator = " " close =")" >

 

collection은 jsp에서 form태그로 post요청을 할때 선택사항에 태그에 적혀있는 name을 말한다 

이 input태그에 name을 주목!

그리고 우리의 검색로직은 checkbox부분은 다중선택이 가능하다. 그렇기 때문에 foreach로 처리를해주고 menu로 collection에 있던 menu_icon을 하나씩 꺼내주는 역할을 해준다 그래서 밑에 로직까지 이어지게 되는것

 

 <if test="index>0">
            OR
  </if>

처음에 있는 이부분은 버튼과 버튼사이에 들어가있는 부분을 나타내는 것이다 

위에 로직을 다시보면 만약 내가 

type1과 type2의 버튼을 클릭을 했다고 생각하면 choose에 들어가는 로직은 총 2개의 로직이다

근데 이 부분에 대한 index은 0, 1이  차례대로 들아가게되는데 

일단 type1과 2를 누르게 된다면 로직은 이렇게 될 것이다 

 

where  (menu_icon1 = 1 OR menu_icon3 = 1 OR menu_icon4 = 1) menu_icon6 = 1 

 

자 그러면 sql문 상으로 성립을 하지 않음이 보인다 그래서 그 사이에 or조건을 넣으주기위해서 위에 저 코드가 필요한것이다

index가 현재 0, 1이 차례대로 오갔으니 위에 if절문을 다시보면 index가 0이상일때만 or을 붙인다고 되어있으니 완성된 sql문은 

 

where  (menu_icon1 = 1 OR menu_icon3 = 1 OR menu_icon4 = 1)  or menu_icon6 = 1 로 완성이 된다.  

 

그리고 밑에 subtitle부분에 대한 검색 로직이다. 

아 참고로 subtitle은 지역구 선택부분이다. (서울시 구로구.. 이런 느낌이다. )

 

자세히보면 when절에도 사용을 하였고 otherwise절에도 사용을 하였는데 그 이유는 위에 조건때문이다 

 

1. 둘다 검색이 될 필요는 없다 (교통약자만 검색해도 괜찮고, 지역선택만 검색해도 검색결과가 나와야한다)

2. 둘다 검색을 해도 and조건으로 둘의 조건을 모두 충족시키는 결과값이 나와야한다

3. 검색결과 없으면 없는대로 출력되어야한다(오류 배제)

 

이 조건들인데 그래서 위와같이작성한것이다 

 

     <if test="tourist_subtitle!=null and tourist_subtitle!=''">
                and tourist_subtitle = #{tourist_subtitle}
            </if>
        </when>
        <otherwise>
            <if test="tourist_subtitle!=null and tourist_subtitle!=''">
                tourist_subtitle = #{tourist_subtitle}
            </if>
        </otherwise>

완성된 로직이다