경매형 중개플랫폼 마취모 프로젝트 9일차(검색 기능)

0

오늘 한 일

오늘은 검색기능을 구현 하였다


                      <ul class="gnb_list nav nav-pills">
                        <li class="nav-item"><a href="#" class="text-dark nav-link fw-semibold fs-4 link-underline link-underline-opacity-0">HOME</a></li>
                        <li class="nav-item"><a href="#" class="text-dark nav-link fw-semibold fs-4 link-underline link-underline-opacity-0">STYLE</a></li>
                        <li class="nav-item"><a href="#" class="text-dark nav-link fw-semibold fs-4 link-underline link-underline-opacity-0">SHOP</a></li>
                        <li class="nav-item">
                            <form action="/search/list" method="get" class="d-flex" role="search">
                                <label>
                                    <select name="searchOption" style="height: 32px">
                                      <option value="1">작성자</option>
                                      <option value="2">상품명</option>
                                      <option value="3">내영</option>
                                      <option value="4">상품명+내용</option>
                                    </select>
                                </label>
                                <input name="keyword" type="search" placeholder="search">
                                <button type="submit" style="border: none" class="bg-body-tertiary" >
                                <svg  xmlns="http://www.w3.org/2000/svg" width="30" height="30" fill="currentColor" class="bi bi-search" viewBox="0 0 16 16">
                                    <path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"/>
                                </svg>
                                  </button>
                            </form>
                        </li>
                    </ul>


위와 같이 해더에 검색을 하기 위한 기능을 만들어두었었다 이걸 이용하여

SearchVO를 만들어주었다

SearchVO

public record SearchVO(
          Long productsId
        , Long userId
        , String uNickName
        , Long iId
        , String iImage
        , String iSubImage
        ,String pName
        ,String pInfo

) {
}

record는 VO에 가깝기 때문에 record로 만들어주었다
롬복에 너무 의존하지 않아서 좋다 값들도 다 불변이고 VO에 가깝다 생각들어
VO들은 record로 만드는 편이다

검색에 결과값으로 뽑아올 DAO를 설계해주자
결과 값에 따른 db연결를 하기 위해 아래와 같이 설계했다

SearchDAO


@Mapper
public interface SearchDAO {
    List<SearchVO> searchUser(String keyword);
    List<SearchVO> searchProductName(String keyword);
    List<SearchVO> searchProductInfo(String keyword);
    List<SearchVO> searchProductNameOrInfo(String keyword);
    <select id="searchUser" resultType="com.example.project_machimo.search.dto.SearchVO">
        SELECT p.PRODUCTS_ID as products_id, u.USER_ID as user_id, u.U_NICKNAME as u_nickname
        ,i.i_ID as i_id, MIN(i.I_IMAGE) AS i_image,MIN(i.i_sub_img) as i_sub_img
        ,p.P_NAME as p_name , p.P_INFO as p_info
        FROM USERS U
        JOIN PRODUCTS P ON U.USER_ID = P.USER_ID
        LEFT JOIN (
        SELECT PRODUCT_ID,I_ID,MIN(I_IMAGE) AS I_IMAGE ,MIN(i_sub_img) as i_sub_img , p.P_NAME as p_name,p.P_INFO as
        p_info
        FROM PRODUCT_IMAGES i join PRODUCTS p on p.PRODUCTS_ID = i.PRODUCT_ID
        GROUP BY PRODUCT_ID,I_ID,P_NAME,P_INFO
        ) i ON P.PRODUCTS_ID = i.PRODUCT_ID
        WHERE u.U_NICKNAME LIKE '%'||#{keyword}||'%'
        GROUP BY p.PRODUCTS_ID, u.USER_ID, u.U_NICKNAME, i.i_ID,p.P_NAME,p.P_INFO
        ORDER BY u.USER_ID
    </select>
    <select id="searchProductName" resultType="com.example.project_machimo.search.dto.SearchVO">

        SELECT p.PRODUCTS_ID as products_id, u.USER_ID as user_id, u.U_NICKNAME as u_nickname
        ,i.i_ID as i_id, MIN(i.I_IMAGE) AS i_image,MIN(i.i_sub_img) as i_sub_img
        ,p.P_NAME as p_name , p.P_INFO as p_info
        FROM USERS U
        JOIN PRODUCTS P ON U.USER_ID = P.USER_ID
        LEFT JOIN (
        SELECT PRODUCT_ID,I_ID,MIN(I_IMAGE) AS I_IMAGE ,MIN(i_sub_img) as i_sub_img , p.P_NAME as p_name,p.P_INFO as
        p_info
        FROM PRODUCT_IMAGES i join PRODUCTS p on p.PRODUCTS_ID = i.PRODUCT_ID
        GROUP BY PRODUCT_ID,I_ID,P_NAME,P_INFO
        ) i ON P.PRODUCTS_ID = i.PRODUCT_ID
        WHERE p.P_NAME LIKE '%'||#{keyword}||'%'
        GROUP BY p.PRODUCTS_ID, u.USER_ID, u.U_NICKNAME, i.i_ID,p.P_NAME,p.P_INFO
        ORDER BY u.USER_ID

    </select>
    <select id="searchProductInfo" resultType="com.example.project_machimo.search.dto.SearchVO">
        SELECT p.PRODUCTS_ID as products_id, u.USER_ID as user_id, u.U_NICKNAME as u_nickname
        ,i.i_ID as i_id, MIN(i.I_IMAGE) AS i_image,MIN(i.i_sub_img) as i_sub_img
        ,p.P_NAME as p_name , p.P_INFO as p_info
        FROM USERS U
        JOIN PRODUCTS P ON U.USER_ID = P.USER_ID
        LEFT JOIN (
        SELECT PRODUCT_ID,I_ID,MIN(I_IMAGE) AS I_IMAGE ,MIN(i_sub_img) as i_sub_img , p.P_NAME as p_name,p.P_INFO as
        p_info
        FROM PRODUCT_IMAGES i join PRODUCTS p on p.PRODUCTS_ID = i.PRODUCT_ID
        GROUP BY PRODUCT_ID,I_ID,P_NAME,P_INFO
        ) i ON P.PRODUCTS_ID = i.PRODUCT_ID
        WHERE p.P_INFO LIKE '%'||#{keyword}||'%'
        GROUP BY p.PRODUCTS_ID, u.USER_ID, u.U_NICKNAME, i.i_ID,p.P_NAME,p.P_INFO
        ORDER BY u.USER_ID
    </select>

제품 정보가 담긴 테이블들이 따로 분리 되어 있기 때문에 join으로 처리
되게 어려웠다 처음엔 결과 값이 순서가 이상하게 나오고
알고 보니 Join을 할때도 순서가 중요했다
where에 위치와 order by 위치에 따라 결과가 바뀐다는 사실도 오늘 처음 알았던거 같다 학원에서 문제풀때랑 실전은 다르다는걸 새삼 느낌

SearchService

public interface SearchService {
    List<SearchVO> search(byte searchOption, String keyword);

    
}
@Service
public class SearchServiceImpl implements SearchService {

    private  final SearchDAO searchDAO;

    @Autowired
    public SearchServiceImpl(SearchDAO searchDAO) {
        this.searchDAO = searchDAO;
    }

    @Override
    public List<SearchVO> search(byte searchOption, String keyword) {

        switch (searchOption){
            case 1 -> {
                return searchDAO.getListWithPaging(keyword);
            }
            case 2 ->{
                return searchDAO.searchProductName(keyword);
            }
            case 3 ->{
                return searchDAO.searchProductInfo(keyword);
            }
            case 4 ->{
                return searchDAO.searchProductNameOrInfo(keyword);
            }
        }
        return Collections.emptyList();

    }

searchOption에 따라 분기처리를 해주었따 혹시라도 결과가 없다면
Collections.emptyList();를 리턴 해주었다

SearchController

@Controller
@RequestMapping("/search")
@Slf4j
public class SearchController {

    private final SearchService searchService;

    @Autowired
    public SearchController(SearchService searchService) {
        this.searchService = searchService;
    }

    @GetMapping("/list")
    public String search(@RequestParam byte searchOption
            , @RequestParam String keyword
            , Model model
    ) {

        List<SearchVO> search = searchService.search(searchOption, keyword;

        int total = searchService.searchTotal(keyword);
        if (search.isEmpty()) {
            keyword = keyword + "에 대한 검색결과가 없습니다.";
            model.addAttribute("message", keyword);
            return "search/errorPage";
        } else {
            model.addAttribute("message", keyword);
            model.addAttribute("search", search);
      
            return "search/searchPage";
        }


    }

Service 값이 없을때 Collections.emptyList(); 해주어서 if (search.isEmpty())가 true가 되진 않는다
dao받아온 값이 없을때 이 if문이 동작하여 사용자에겐 에러 페이지를 보여주고
검색하고 싶은 키워드에 값이 없다고 뜨게 해주었다

그리고 모델에 keyword와 search를 담아서 사용자에게 화면을 보여준다
이제 검색은 가능하게 되었다

근데 한가지 문제가 있다

모든 검색값들이 다 나오니 이걸 페이징 처리해야한다

0개의 댓글