//searchList.jsp
// 해당 키워드가 이미 선택되어 있는지 확인
if (index !== -1) {
// 이미 선택되어 있다면 해당 키워드를 제거
selectedKeywords.splice(index, 1);
$(this).removeClass('active');
} else {
// 선택되어 있지 않다면 해당 키워드를 배열에 추가
selectedKeywords.push(keyword);
$(this).addClass('active');
}
키워드를 List에 담아서 처리하기 위해 JSP와 컨트롤러 수정!
//JSP
$(document).ready(function() {
var selectedKeywords = []; // 선택된 키워드를 저장할 배열
// 필터 버튼 클릭 이벤트 핸들러 등록
$(".filterButton").on("click", function(event) {
var keyword = $(this).find(".text-wrapper").text(); // 클릭한 버튼의 텍스트에서 키워드 추출
var index = selectedKeywords.indexOf(keyword); // 선택된 키워드 배열에서 해당 키워드의 인덱스 확인
// 해당 키워드가 이미 선택되어 있는지 확인
if (index !== -1) {
// 이미 선택되어 있다면 해당 키워드를 제거
selectedKeywords.splice(index, 1);
$(this).removeClass('active');
} else {
// 선택되어 있지 않다면 해당 키워드를 배열에 추가
selectedKeywords.push(keyword);
$(this).addClass('active');
}
currentPage = 1; // 페이지를 1로 설정하여 필터가 변경되었음을 나타냄
loadFilteredCafes(selectedKeywords, currentPage); // 필터된 카페들을 불러오는 함수 호출
});
$('.pagination').on('click', 'a', function(event) {
event.preventDefault(); // 기본 동작 방지 (페이지 이동 막기)
currentPage = parseInt($(this).attr('href').split('=')[1]); // 클릭한 페이지 번호 추출
// 필터링된 카페 목록을 요청하는 함수 호출
loadFilteredCafes(selectedKeywords, currentPage);
// 페이지 맨 위로 스크롤
window.scrollTo({
top: 0,
behavior: "smooth"
});
});
//컨트롤러
@RequestMapping("/usr/findcafe/filterCafes")
@ResponseBody
public Map<String, Object> filterCafes(@RequestBody Map<String, Object> filterData) {
Map<String, Object> returnMap = new HashMap<>();
List<String> selectedKeywords = new ArrayList<String>();
//String keyword = filterData.get("keyword"); // 키워드 다중선택 아닌 단일선택 시
//List<String> selectedKeywords = (List<String>) filterData.get("selectedKeywords"); // 키워드 선택하지 않았을 경우 리스트 보이지 않음 (키워드가 빈값 일 때 String)
Object selectedKeywordsObject = filterData.get("selectedKeywords"); // 키워드 선택 안했을 때 String으로 넘어오고, 키워드 선택 했을 땐 List로 넘어와서 변수타입을 Object로 선언.
if (selectedKeywordsObject instanceof String == false) { // 키워드 선택 안했을 시 빈값이 String으로 들어와서 String(빈값) 여부 판단 후 빈값인 경우 전체카페 리스트 보여줌
selectedKeywords = (List<String>) selectedKeywordsObject;
}
int page = Integer.parseInt(filterData.get("page").toString());
List<Cafe> cafesList;
cafeRepository.updateReviewCount();
int cafesCount = 0;
if (selectedKeywords.isEmpty()) {
cafesCount = cafeService.getCafesCount();
} else {
cafesCount = cafeService.getCafesCountKeyword(selectedKeywords);
}
int itemsInAPage = 5;
if (selectedKeywords.isEmpty()) { //키워드가 선택 되지 않았을 경우에 대한 전체카페 리스팅
cafesList = cafeService.getForPrintCafes(itemsInAPage, page);
} else { //키워드가 선택 되었을 경우에 대한 키워드별 카페 리스팅
cafesList = cafeService.getForPrintCafesKeyword(itemsInAPage, page, selectedKeywords);
}
returnMap.put("cafesTotalCount", cafesCount);
returnMap.put("cafesCurrentList", cafesList);
return returnMap;
}
그런데 Repository에서 마이바티스를 foreach문으로 수정하는 과정에서 계속 에러가 뜸!
며칠전에도 같은 문제로 키워드 다중선택 구현중 단일선택으로 원복했던 적이 있었는데..ㅜㅜ
계속 Repository에서 마이바티스 쿼리에서 삽질했던 원인은.. <script>태그로 감싸지 않았기 때문이었음;;; 정말 너무 없이 없고 황당한 실수였었다..
무튼, 배열형태로 넘기고 싶을 땐 마이바티스에서는 foreach 사용하면 된다!
//레파지토리
@Select("""
<script>
SELECT id, name, address, cafeScrapCount, reviewCount, hashtag, cafeImgUrl1
FROM cafe
WHERE
<foreach collection="selectedKeywords" item="keyword" separator="OR" open="(" close=")">
`name` LIKE CONCAT('%', #{keyword}, '%')
OR `address` LIKE CONCAT('%', #{keyword}, '%')
OR `hashtag` LIKE CONCAT('%', #{keyword}, '%')
</foreach>
GROUP BY id
ORDER BY id DESC
<if test="limitFrom >= 0 ">
LIMIT #{limitFrom}, #{limitTake}
</if>
</script>
""")
public List<Cafe> getForPrintCafesKeyword(int limitFrom, int limitTake, List<String> selectedKeywords);
여기 foreach문 안에서 separator="OR"을 사용한 이유는,
selectedKeywords = {'유성구', '모던', '단체'} 라고 가정했을 때:1번째 item인 keyword에
유성구세팅
OR
2번째 item인 keyword에모던세팅
OR
3번째 item인 keyword에단체세팅
이라는 뜻!
(`name` LIKE CONCAT('%', '유성구', '%')
OR `address` LIKE CONCAT('%', '유성구', '%')
OR `hashtag` LIKE CONCAT('%', '유성구', '%')
)
OR
(`name` LIKE CONCAT('%', '모던', '%')
OR `address` LIKE CONCAT('%', '모던', '%')
OR `hashtag` LIKE CONCAT('%', '모던', '%')
)
OR
(`name` LIKE CONCAT('%', '단체', '%')
OR `address` LIKE CONCAT('%', '단체', '%')
OR `hashtag` LIKE CONCAT('%', '단체', '%')
)

//선택된 키워드와 일치하는 텍스트에 스타일 적용하는 함수
function applyStyleToMatchingText(selectedKeywords) {
// 각 카페 아이템에 대해 반복
$(".equal-filter").each(function() {
var cafeItem = $(this);
var text = cafeItem.text(); // 카페 아이템의 텍스트 가져오기
// 선택된 키워드와 일치하는 부분에 스타일 적용
selectedKeywords.forEach(function(keyword) {
// 대소문자 구분 없이 일치하는 모든 부분 찾기 위한 정규표현식(Regular Expression) 생성
var regex = new RegExp(keyword, "gi");
// 일치하는 부분에 스타일 적용
text = text.replace(regex, '<span style="color: red;">$&</span>');
});
cafeItem.html(text); // 스타일이 적용된 텍스트로 카페 아이템 업데이트
});
}
RegExp는 이런거래!

필터에서 전체선택 전체해제 처리만 해결하면 필터기능은 끝이나겠구나 ㅠㅠ
필터구현은... 설계부터 까다로워...