웹 개발 Spring Day5 조건에 따른 검색

김지원·2022년 8월 2일
0

WebDevelop2

목록 보기
24/34

아래에 문의 내용이 뜨도록 하자.
주소에 치고 딱 들어갔을 때도 보여져야하며 문의를 남겼을 때에도 문의 내역이 보여야한다. = 어떤 상황이든 보이게 하자.

index.html 에서 Controller가 GET방식 요청이든 POST방식 요청이든 InquiryService통해서 InquiryEntity타입의 제네릭타입의 list를 html으로 넘겨줘야한다. (select)

modelAndView객체의 addObject를 사용 할 것이다.

modelAndView : addObject

addObject ( name ,value )

: Controller에서 html로 값을 넘겨줄 때 쓰는 것이다. 자바단에서 만들어준 데이터를 html에서 써야될 때 사용한다.

물론 문의를 남겼을 때에도 있어야하기 때문에 POST에도 추가해야한다.
(문의를 남겼을 때보는 페이지는 POST이다.)

GET / POST가 같은 페이지를 보게되는 이유는 setViewName의 값이 같이 때문에 GET이든 POST이든 같은 페이지를 보는 것이다.
inquirues를 똑같이 넘겨줘야만 문의 내역을 똑같이 띄울 수 있다.

modelAndView.addObject("inquirues", this.inquiryService.get());

index.html에 Thymeleaf를 추가하자.

xmlns:th="http://www.thymeleaf.org
  • 얘를 적어주는 것은 thymeleaf 라는 문법을 쓰겠다는 것이다.
  • xmlns : XML Namespace
    태초에 XML이란 파일타입이 있고 이거를 상속 받아서 만든게 HTML이다.
  • 여기에 abc를 쓴다면 abc:if="~" 이런형식으로 문법을 작성한다.

-> index.html / index.css 작성

<body>
<main id="main">
    <h1 class="title">
        <i class="icon fa-solid fa-headset"></i>
        <span class="text">고객문의</span>
    </h1>
    <form class="form" method="post">
        <label class="input-container writer">
            <span class="hint">작성자</span>
            <input class="input" maxlength="10" name="writer" type="text">
            <span class="warning">작성자를 입력해주세요.</span>
        </label>
        <label class="input-container content">
            <span class="hint">문의 내용</span>
            <input class="input" maxlength="100" name="content" type="text">
            <span class="warning">문의 내용을 입력해주세요.</span>
        </label>
        <input class="button" type="submit" value="문의 남기기">
    </form>
    <table class="inquiry-container">
        <thead>
        <tr>
            <th>순번</th>
            <th>작성 일시</th>
            <th>문의 내용</th>
            <th>작성자</th>
        </tr>
        </thead>
        <tbody>
        <tr>
            <td class="no-inquiry" colspan="4">표시할 문의가 없습니다.</td>
        </tr>
        <tr>
            <td>2</td>
            <td>0000-00-00 00:00:00</td>
            <td>문의 내용 자리</td>
            <td>작성자 자리</td>
        </tr>
        <tr>
            <td>1</td>
            <td>0000-00-00 00:00:00</td>
            <td>문의 내용 자리</td>
            <td>작성자 자리</td>
        </tr>
        </tbody>
        <tfoot>
        <tr>
            <td class="page-td" colspan="4">
                <div class="page-container">
                    <a class="page selected" href="#">1</a> <!-- selected 클래스 부여 -->
                    <a class="page" href="#">2</a>
                    <a class="page" href="#">3</a>
                    <a class="page" href="#">4</a>
                    <a class="page" href="#">5</a>
                    <a class="page" href="#">6</a>
                    <a class="page" href="#">7</a>
                    <a class="page" href="#">8</a>
                    <a class="page" href="#">9</a>
                    <a class="page" href="#">10</a>
                </div>
            </td>
        </tr>
        <tr>
            <td class="search-td" colspan="4">
                <form class="search-form" method="get">
                    <label class="input-container criteria"> <!-- 검색기준 -->
                        <span class="hint" hidden>검색 기준</span> <!-- 장애인을 위한 접근성위해서 -->
                        <select class="input criteria" name="criteria">
                            <option selected value="byContent">문의 내용</option>
                            <option value="byWriter">작성자</option>
                        </select>
                    </label>
                    <label class="input-container keyword">
                        <span class="hint" hidden>키워드</span>
                        <input class="input keyword" maxlength="10" name="keyword" placeholder="검색어를 입력해주세요." type="text">
                    </label>
                    <input class="button search" type="submit" value="검색">
                    <input class="button reset" disabled type="button" value="검색 초기화">
                </form>
            </td>
        </tr>
        </tfoot>
    </table>
</main>
</body>


-> 현재 검색을 해보면 주소(경로)에 이렇게 뜬다.

http://localhost:8080/?criteria=byContent&keyword=검색함 
                       <select>           <input>
		 	           name     value     name    value
  • criteria = byContent 인 이유는 html에서 selected로 지정해둔 기본 값이기 때문이다.

insert해서 이 값들을 RequestParam 어노테이션을 이용해서 받아오자.


Controller에서 넘겨받은 inquirues(제네릭)을 html에서 사용하자.

Thymeleaf을 작성해서 정보를 불러오자.

  • 만약 Thymeleaf 작성 시 자동완성이 안된다면 option + enter로 위에 것을 추가해주자.
  • id="inquiries" 의 Type을 고의로 뒤에 것으로 정해주겠다는 의미이다.

th:if="조건"

-> 조건에 따라 표시하도록 해보자.

th:if="조건"
  • : 해당 조건이 참이 경우에만 해당 태그를 표시한다. 만약 거짓이라면 안보이는게 아니라 HTML 응답 자체에 포함되지 않음. (페이지 소스 보기 하면 없는 것을 의미한다.)

  • inquiries == null null이거나 inquiries.size() == 0 select 된 게 하나도 없으면 표시할 문의가 없다는 tr이 뜨도록 하자.
  • 문의 내용이 있기 때문에 표시할 문의가 없다는 tr은 보이지 않는다.

-> 순번, 작성 일시, 문의 내용, DB에서 작성자를 불러오자.

  • 실제로 넘어오는 inquiries가지고 있는 것들을 싹 다 돌려서 한줄 한줄 표시해주면 된다. th:each 가 있는 요소 자체 하나가 반복이 되어야한다.
  • inquiry객체가 가진 값을 <td>??</td>에 넣으려면 th:text을 이용한다.

검색 Search

페이지 주소 치고 들어갔을 때 경로 → /
검색을 하고 난 후의 경로 ↓

http://localhost:8080/?criteria=byContent&keyword=검색함 
                       <select>           <input>
		 	           name     value     name    value
  • 페이지 주소를 치고 들어갔을 때와 검색한 주소랑 동일한 주소를 요청한 것은 맞는데 다른 주소 처럼 보인다.
    http://localhost:8080/ ? 전까지는 똑같이 찍힌다.
    왜냐하면 ? 뒤로 부터는 변수자리라서 실제 주소는 아니기 때문이다.
    따라서 메인 페이지와 검색 후의 페이지 주소는 같은 주소이다.

게시글을 던져주든 검색걸과를 던져주든 Controller getIndex메서드가 처리해주는게 맞다.

  • getIndex 매개변수자리에 @RequestParam 추가
검색 기준 : @RequestParam(name = "criteria", required = false) String criteria,
검색어   : @RequestParam(name = "keyword", required = false) String keyword,
  • html의 select태그의 criteria와 input태그의 keyword : name과 짝짝궁이 되어야한다!
System.out.printf("%s : %s\n", criteria, keyword);

localhost:8080/으로 들어가면 null:null 이 뜬다.

  • 검색을 해보게 되면 이렇게 뜬다.

이렇게 해서 검색결과를 만들어서 돌려주면 되는데 this.inquiryService.get() 은 전체 검색 결과이다 검색결과에 맞게 뽑아줘야한다.


언제 모든 내역 언제 검색결과가 나와야하는지 언제 검색을 해야하는가?

criteria == null || keyword == null : 전체 내용
criteria != null || keyword != null : 검색 결과 내용  

-> 둘 다 null 일 때

List<InquiryEntity> inquiries;
	if(criteria == null || keyword == null) {
		inquiries = this.inquiryService.get();
	} 

당연히 DB를 사용해야하는데 사용하지 않는다는 가정하에 짠 코드.

else {
	if (criteria.equals("byWriter")) { 
		inquiries = this.inquiryService.get().stream()
				  .filter(x -> x.getWriter().equals(keyword))
                  .collect(Collectors.toList());
	} else {
		inquiries = this.inquiryService.get().stream()
				  .filter(x -> x.getContent().contains(keyword))
                  .collect(Collectors.toList());
	}
}  
  • criteria.equals("byWriter") : 검색 기준이 작성자일 때
  • byWriter : 작성자 값이 전달 받은 keyword문자열과 일치한 것.
  • byContent : 문의 내용이 키워드가 같은 것이 아니라! 키워드를 포함하고 있을 때.

이렇게 코드를 짰을 때 문제점이 있다.
만약 문의내역이 1만건이 있다고 가정을 했을 때 DB에서 가져온 값들이 this.inquiryService.get() 에 1만건이 다 쌓이게 된다.
검색조건과 키워드에 따라 (if문을 통해) 컷 당하게 되는데 리소스 낭비가 된다.
일반적으로 DB에 저장되는 내용들은 주 저장장치(HDD 하드, SSD)에 저장이 된다.
this.inquiryService.get() 에 저장되는 것은 메모리에 저장이 된다.
가져와놓고 자바에서 필터링을 하면 안되고 선택을 할떄 쿼리에서 필터링을 해야한다.


-> InquiryService

  • List<InquiryEntity> 타입을 돌려주는 searchByWriter 메서드 생성 : 작성자 검색 일 떄

-> 쿼리 추가 InquiryDao

  • selectByWriter 추가
"`WHERE` writer = ?\n"
preparedStatement.setString(1, writer);
  • 1번째 ?에 매개변수로 전달받은 writer라는 문자열을 넣는다.

-> InquiryService

return this.inquiryDao.selectByWriter(writer);
  • selectByWriter에서 매개변수 writer 전달인자로 전달해준다.

inquiries = this.inquiryService.searchByWriter(keyword);
  • 이렇게 줄일 수 있다.
  • keyword를 전달해준다.
[작성자] criteria = byWriter

if (criteria.equals("byWriter"))를 하면 true가 뜬다.
작성자선택 후 검색을 하면 criteria에 byWriter가 들어오고 if문이 실행된다.
그래서 실제 작성자의 값을 받는 것은 keyword이다.
고객이라고 검색하면 keyword = "고객" 이 된다.
검색되는 값자체는 keyword가 된다.

HomeController가 keyword를 서비스에게 writer로써 넘겨주고 Dao의 selectByWriter 메서드를 호출하면 그 writer를 다시 writer로 넘겨주어서 WHERE문으로 들어가게 된다. 결국 ?자리에는 "고객"이란게 들어가게 된다.

이러한 절차로 검색이 된다.

  • 검색결과에 따라 검색이 되는 것을 확인 할 수 있다.
profile
Software Developer : -)

0개의 댓글