본문 바로가기

Spring

[Spring]기능 - 검색

이제 지금까지 진행한 커뮤니티에서 글 제목, 내용, 글쓴이, 댓글 내용, 댓글 작성자로 검색할 수 있는 기능을 만들어보자.

 

여기서 가장 중요한건 SQL의 쿼리문이다. 쿼리문으로 우리가 지금까지 작성한 question과 answer의 정보를 불러와 보여줄 수 있다.

첫번째로 쿼리문을 알아보자.

 

1. 제목 검색하기

제목을 검색해보자. 

SELECT *
FROM question
WHERE subject like '%sbb%';

이 쿼리문을 보면 question의 모든 컬럼값을 불러오는데, where절로 제목에서 sbb가 포함된 question을 추출한다.

subject 컬럼에서 sbb가 포함되어 있는 내용을 추출한 것을 볼 수 있다.

 

와일드카드?

where절에서 사용된 '%'가 있다. 이것은 바로 와일드 카드라고 불리는데, where절 내의 like에서 자주 쓰인다.

와일드카드는 '_'와 '%'가 있다.

 

(1) '_' : 문자

이는 하나의 아무 문자 하나를 의미하며 where content like '_가' '뭐가', '내가', '너가' 등.. 아무 한가지 문자가 포함되어 있을 경우만 사용된다.

 

(2) '%' : 문자열

이는 문자열을 의미하며 where content like '%가''누군가', '어떤가', '뭐하는가', '안녕한가' 등.. 아무 문자열이 포함되어 있을 경우 사용된다.

 

결론은 '%sbb%' 는 'sbb' 앞뒤로 아무 문자열이 와도 상관없기 때문에 sbb만 포함되어 있다면 되는 것이다.

 

2. 제목 + 내용 검색

제목과 내용에 포함된 문자열로 검색해보자.

select q.*
from question q
where q.subject like '%sbb%' or q.content like '%sbb%';

question 테이블에 포함된 컬럼인 subject와 content에 와일드 카드를 사용하여 조건으로 주어 맞은 question의 컬럼값들을 추출한다.

쿼리문에 or을 사용했기 때문에 sbb가 포함된 제목 혹은 내용을 검색하는 것을 알 수 있다.(제목 혹은 내용 둘중 하나만 포함되어도 출력)

 

3. 제목 + 내용 + 작성자 검색

제목과 내용, 작성자가 포함된 문자열로 검색해보자.

select q.*
from question q
left join site_user s
on q.author_id = s.id
where (
    q.subject like '%user%'
    or
    q.content like '%user%'
    or
    s.username like '%user%'
);

여기서는 join을 사용했다. 작성자를 가져오기 위해서 join을 사용했으며, 작성자의 정보가 아닌 question의 정보를 얻기 위해 left outer join을 사용했다. 조건에도 제목, 내용, 작성자의 이름을 통해 추출하도록 걸었다.

사용자 이름이 user이고, user의 id값은 1이다. id값이 1인 question의 목록을 추출했다.

 

4. 제목 + 내용 + 작성자 + 답변내용 검색

제목과 내용, 작성자, 답변의 내용이 포함된 문자열로 검색해보자.

select q.*
from question q
left join site_user s
on q.author_id = s.id
left join answer a
on q.id = a.id
where (
    q.subject like '%user%'
    or
    q.content like '%user%'
    or
    s.username like '%user%'
    or
    a.content LIKE '%sbb는 질문답변 게시판 입니다.%'
)
group by q.id;

이는 left outer join을 2번 사용했다. 질문 테이블을 통해 답변 테이블의 값을 가져오기 위함이다. 여기서 group by를 사용한 이유는 question의 id값이 중복되지 않아야 하기 때문에 사용했으며 distinct로 대체하여 사용할 수 있다.

작성자의 id가 1인 질문과 질문의 내용에 해당 내용이 포함된 질문들을 추출한 것을 볼 수 있다.

 

5. 제목 + 내용 + 작성자 + 답변내용 + 답변작성자 검색

제목과 내용, 작성자, 답변의 내용, 답변 작성자가 포함된 문자열로 검색해보자.

select q.*
from question q
left join site_user s
on q.author_id = s.id
left join answer a
on q.id = a.question_id
left join site_user a_s
on a.author_id = a_s.id
where (
	q.subject like '%admin' 
    or 
    q.content like '%admin' 
    or 
    q.author_id like '%admin%' 
    or 
    a.content like '%admin%'
	or 
    a_s.username like '%user%'
)
group by q.id;

위와 같이 answer에 대한 작성자에 대한 정보를 left join했다. 답변 작성자의 정보를 얻기 위함으로써 answer_site_user.id와 answer의 작성자로 join해주었다.

답변 작성을 user가 한 질문들을 추출한 것을 알 수 있다.

 

이와 같이 쿼리문을 이해하여 Spring JPA로 추출해보자.

 

1. question_list 수정

검색창을 만들어보자. 

<form class="input-group">
    <input type="hidden" name="page" th:value="${param.page}">
    <input class="form-control" type="text" name="kw" placeholder="검색어를 입력해주세요." th:value="${param.kw}">
    <button type="submit" class="btn btn-outline-secondary">검색</button>
</form>

이는 검색창을 새로 만들고, kw라는 변수에 input값을 넣어 보내준다.

 

2. QuestionController 수정

@RequestMapping("/list")

public String list(@RequestParam(defaultValue = "") String kw, Model model, @RequestParam(value="page", defaultValue="0") int page) {
    Page<Question> paging = this.questionService.getList(kw, page);
    model.addAttribute("paging", paging);
    model.addAttribute("kw", kw);

    return "question_list";
}

받아온 kw를 변수로 지정해 service단의 getList 메서드로 넣어준다.

그리고 kw값을 addAttribute로 지정해 검색어를 화면에 유지시킬 수 있도록 했다.

 

3. QuestionService 수정

public Page<Question> getList(String kw, int page) {
    List<Sort.Order> sorts = new ArrayList<>();

    Pageable pageable = PageRequest.of(page, 10, Sort.by(sorts));
    if ( kw == null || kw.trim().length() == 0 ) {
        return questionRepository.findAll(pageable);
    }

    return questionRepository.findDistinctBySubjectContainsOrContentContainsOrAuthor_usernameContainsOrAnswerList_contentContainsOrAnswerList_author_username(kw, kw, kw, kw, kw, pageable);
}

여기서 입력된 kw값을 받아 repository단의 메서드에 넣어준다. 저 메서드는 4. Repository 수정에서 바로 알아보자.

 

4. QuestionRepository 수정

우리가 위에서 확인한 쿼리문을 통해 JPA 쿼리문으로 만들어보자.

JPA는 메서드의 이름을 분석하여 쿼리문을 작성하는데 자세히 알아보자.

findDistinctBySubjectContains(String kw, Pageable pageable);

이는 Distinct를 통해 중복을 제거하고 question 테이블에 subject에 입력한 kw가 포함되어 있는지 확인한다.

 

findDistinctBySubjectContainsOrContentContains(String kw, String kw_, Pageable pageable);

이는 subject 혹은 content에 입력한 kw가 포함되어 있는지 확인한다.

 

findDistinctBySubjectContainsOrContentContainsOrAuthor_usernameContains(String kw, String kw_, String kw__, Pageable pageable);

이는 subject 혹은 content 혹은 question의 작성자에 입력한 kw가 포함되어 있는지 확인한다. 이렇듯 메서드의 이름만으로도 분석할 수 있다.

 

findDistinctBySubjectContains
OrContentContains
OrAuthor_usernameContains
OrAnswerList_contentContains
OrAnswerList_author_username
(String kw, String kw_, String kw__, String kw___, String kw____, Pageable pageable);

이렇게 메서드의 이름으로 질문의 제목 내용 작성자, 답변의 내용 작성자를 통해 검색할 수 있도록 한다.

 

결과화면

 

'Spring' 카테고리의 다른 글

[Spring, QueryDSL]기본 테스트 데이터 생성  (0) 2022.08.29
[Spring]QueryDSL 적용하기  (0) 2022.08.29
[Spring]기능 - 앵커(anchor)  (0) 2022.08.23
[Spring]기능 - 추천 기능  (0) 2022.08.23
[Spring]기능 - 질문 수정 및 삭제  (0) 2022.08.22