게시판 11 - 추가 기능들

JIWOO YUN·2024년 4월 26일
0

게시판만들기

목록 보기
11/21
post-custom-banner

답변 앵커 추가

  • 사용자가 다른 웹 페이지로 이동하거나 동일한 페이지 내에서 특정 위치로 스크롤 하도록
<a th:id="|answer_${answer.id}|"></a>

질문에 마크다운 적용하기

  • 마크다운의 경우 나의 경우에 깃허브에서 주로 많이 사용했었다.
    • 마크다운 도구를 사용시에 간단한 문법을 통해서 텍스트 편집기를 통해 웹상에서 글자를 강조하거나 제목, 목록, 이미지 , 링크 들을 추가할 때도 유용하기 때문에 적용해놓으면 좋다.
  • 적용하려면 먼저 마크다운 라이브러리를 추가해줘야함.

Maven Repository: org.commonmark » commonmark » 0.22.0 (mvnrepository.com)

  • 최신버전 업데이트를 찾아보니 최근 24년 3월에 추가로 업데이트되었길래 가져왔다.

만약 마크다운으로 바꿔주고 나서 th:utext를 통해서 문법을 알아서 변환하게 해주면 XSS에 굉장히 취약해진다.

코드가 그대로 실행되기 때문에.

  • 일단은 마드다운 형식을 html로 변환시켜준 값을 받아서 다시 넣어주는 형식으로 변환했다.
String content = commonUtil.markdown(questionForm.getContent());
questionService.create(questionForm.getSubject(), content, siteUser);
마크다운 Component
@Component
public class CommonUtil {

    public String markdown(String markdown) {
        Parser parser = Parser.builder().build();
        Node doc = parser.parse(markdown);
        HtmlRenderer renderer = HtmlRenderer.builder().build();

        return renderer.render(doc);
    }
}

답변 부분도 같은 방식으로 추가

String covertcontent = commonUtil.markdown(answerForm.getContent());
Answer answer = answerService.create(question,covertcontent, siteUser);
  • 아마 이게 좋은 방식은 아닌 거같고 xss filter를 보고 추가적으로 filter를 거는 방식이 좋은 방식이 아닐까 싶은 생각이 든다.
    • 추가 구현때 한번 바꿔볼 예정

검색 기능을 추가해보자.

  • 게시판을 만들기 전에 Querydsl을 공부했었는데 이걸 활용해서 검색 기능을 만들어보자.
    • Querydsl의 경우 제대로 학습하기만 한다면 활용도가 무궁무진하기 때문에 한번씩 써보는게 좋아보인다.
  • 제목 기준으로 가져오는걸 목표로 해보자.

기본 제목 검색을 진행한다고 가정해보자. 필요한게 뭐가 있을까?

  • 제목을 입력한 경우 제목을 포함한 질문들을 전부 찾아서 페이지 형식으로 보여주기.
    • 제목을 입력하면 검색 쿼리가 돌아서 찾는다.
    • 현재 가져와야하는 것들 제목, 글쓴이 , 작성일시

querydsl 라이브러리 추가

//QueryDsl 추가
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
querydsl이 만드는 generate밑의 파일들은 git에올라갈필요가없기 때문에 .gitignore를 통해서 올라가지 않게 해주기.
  • 개발자가 직접 만드는게 아닌 자동으로 생성되는 파일이기 때문에 버전 관리 시스템인 git에 올릴 필요가없어서

QEntity를 만들어 주고 난 후에 Query문을 처리하는 QuestionQueryRepository를 추가를 하기전에 controller와 repository,contoller를 package로 나눠놓자.

  • 가독성이 좋지 않아서 나눠서 놓기.

Querydsl은 작성 끝 html 에 제대로 안나오는 문제

  • 제한을 걸지 않으니 그냥 전부 다나온거
    • 페이징에 맞춰서 offset 과 limit를 걸어서 페이징에 맞게 데이터를 찍어주기

참고 : https://velog.io/@ieugeneyi/Spring-Spring-Boot-Data-JPA-QueryDsl-%ED%8E%98%EC%9D%B4%EC%A7%95-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0

List<Question> list = queryFactory
        .selectFrom(question)
        .where(question.subject.contains(subject))
        .orderBy(question.createDate.desc())
        .offset(pageable.getOffset())
        .limit(pageable.getPageSize())
        .fetch();
  • subject가 포함되있는지 체크하여 검색쿼리는 일단 만들어놓았다.
    • querydsl 쿼리를 써보는 건 처음이여서 페이징부분에서 좀 많이 삽질을 했다.
      • 어떻게 해도 paging이 제대로 안되길래 찾아보니 offset과 limit를 통해서 제한을 걸어주지 않으면 그냥 전부 다 찍어버리게된다는 걸 알게되었다.
      • 마지막 반환에서 pageable을 넣어주길래 안잘라도 되는줄 알았다.

question_list.html에 검색창 추가하기.

    <div class="col-6">
        <a th:href="@{/question/create}" class="btn btn-primary">질문 등록하기</a>
    </div>
    <div class="col-6">
        <div class="input-group">
            <input type="text" id="search_kw" class="form-control" th:value="${sub}">
            <button class="btn btn-outline-secondary" type="button" id="btn_search">찾기</button>
        </div>
    </div>
</div>
  • 질문 등록하기 버튼도 밑에 있었던걸 위로 올려서 만들기.
  • 자바 스크립트에서 읽을 수 있도록 id 속성 'search_kw'를 추가

찾기 버튼을 누르면 get input값을 통해서 get 방식으로 요청할 수 있게 추가

<form th:action="@{/question/list}" method="get" id="searchForm">
    <input type="hidden" id="sub" name="sub" th:value="${sub}">
    <input type="hidden" id="page" name="page" th:value="${paging.number}">
</form>

검색 스크립트 추가

<script layout:fragment="script" type='text/javascript'>
const page_elements = document.getElementsByClassName("page-link");
Array.from(page_elements).forEach(function(element) {
    element.addEventListener('click', function() {
        document.getElementById('page').value = this.dataset.page;
        document.getElementById('searchForm').submit();
    });
});
const btn_search = document.getElementById("btn_search");
btn_search.addEventListener('click', function() {
    document.getElementById('sub').value = document.getElementById('search_kw').value;
    document.getElementById('page').value = 0;  // 검색버튼을 클릭할 경우 0페이지부터 조회한다.
    document.getElementById('searchForm').submit();
});
</script>
  • page-link 라는 클래스를 가진 모든 요소를 가져오기
    • 각 요소들을 배열로 변환하여 각 요소에 대해 클릭 이벤트 리스너를 추가
    • 페이지네이션 링크를 누를 경우 -> 클릭된 요소에서 'data-page' 속성 을 읽어온다
    • 이 페이지 번호를 ID가 'page' 인 입력 요소에 할당
    • ID가 search_form인 폼을 제출하여 서버에 데이터를 보내 특정 페이지 데이터를 요청
  • btn_search 인 버튼을 클릭시
    • search_kw 입력필드에서 값을 가져와서 sub 라는 다른 입력 필드에 복사
    • 페이지 번호를 0으로 재설정 -> 새검색이 첫 페이지에서 시작되도록
  • searchForm 제출
    • 페이지네이션과 같은 서버 엔드포인트로 제출될 수 있지
profile
열심히하자
post-custom-banner

0개의 댓글