[Spring Boot] 마크다운 적용하기

DANI·2023년 10월 16일
0
post-thumbnail

💾 build.gradle 파일을 수정

✅ 추가 implementation 'org.commonmark:commonmark:0.21.0'

💾 CommonUtil 컴포넌트 작성

import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;
import org.springframework.stereotype.Component;

@Component
public class CommonUtil {
    public String markdown(String markdown) {
        Parser parser = Parser.builder().build();
        Node document = parser.parse(markdown);
        HtmlRenderer renderer = HtmlRenderer.builder().build();
        return renderer.render(document);
    }
}
  • @Component 애너테이션 : CommonUtil 클래스를 생성
    이렇게 하면 이제 CommonUtil 클래스는 스프링부트에 의해 관리되는 빈(bean, 자바객체)으로 등록된다. 이렇게 빈(bean)으로 등록된 컴포넌트는 템플릿에서 바로 사용할 수 있다.

CommonUtil 클래스에는 markdown 메서드를 생성했다. markdown 메서드는 마크다운 텍스트를 HTML 문서로 변환하여 리턴한다. 즉, 마크다운 문법이 적용된 일반 텍스트를 변환된(소스코드, 기울이기, 굵게, 링크 등) HTML로 리턴한다.



💾 질문 상세 템플릿에 마크다운 적용하기 (question_detail.html 템플릿 수정)

✅ 수정 전

<!-- 질문 -->
<div class="card my-3">
	<h2 class="card-header bg-info text-white border-bottom p-3" th:text="${question.subject}"></h2>
    <div class="card-body bg-light">	
1         <div class="card-text p-2" style="white-space: pre-line;" th:text="${question.content}"></div>       
          <div class="d-flex justify-content-end">
(... 생략 ...)
<!-- 답변 반복 시작 -->
<div class="list-group list-group-flush" th:each="answer, loop : ${question.answerList}">
	<a th:id="|answer_${answer.id}|"></a>
    <div class="list-group-item bg-light">
2          <h8 class="card-text" style="white-space: pre-line;" th:text="${answer.content}"></h8>
           <div class="badge bg-primary text-white" th:text="${loop.count}"></div>
(... 생략 ...)

✅ 수정 후

<!-- 질문 -->
<div class="card my-3">
	<h2 class="card-header bg-info text-white border-bottom p-3" th:text="${question.subject}"></h2>
    <div class="card-body bg-light">	
1         <div class="card-text p-2"  th:utext="${@commonUtil.markdown(question.content)}"></div>       
          <div class="d-flex justify-content-end">
(... 생략 ...)
<!-- 답변 반복 시작 -->
<div class="list-group list-group-flush" th:each="answer, loop : ${question.answerList}">
	<a th:id="|answer_${answer.id}|"></a>
    <div class="list-group-item bg-light">
2          <div class="card-text" style="white-space: pre-line;" th:text="${answer.content}"></div>
           <div class="badge bg-primary text-white" th:text="${loop.count}"></div>
(... 생략 ...)

✅ 수정 전 : 1 <div class="card-text p-2" style="white-space: pre-line;" th:text="${question.content}"></div>
✅ 수정 후 : 1 <div class="card-text p-2" th:utext="${@commonUtil.markdown(question.content)}"></div>


✅ 수정 전 : 2 <div class="card-text" style="white-space: pre-line;" th:text="${answer.content}"></div>
✅ 수정 후 : 2 <div class="card-text" th:utext="${@commonUtil.markdown(answer.content)}"></div>


줄 바꿈을 표시하기 위해 사용했던 기존의 style="white-space: pre-line;" 스타일은 삭제하고 ${@commonUtil.markdown(question.content)}와 같이 마크다운 컴포넌트를 적용했다.

why? th:text -> th:utext 사용한 이유?


th:utext 대신 th:text를 사용할 경우 HTML의 태그들이 이스케이프(escape)처리되어 태그들이 그대로 화면에 보인다. 마크다운으로 변환된 HTML 문서를 제대로 표시하려면 이스케이프 처리를 하지 않고 출력하는 th:utext를 사용해야 한다.




💻 렌더링

마크다운 형식으로 출력된다!






✨ 이번 챕터에서 배운 부분

✅ 컴포넌트에서 마크다운 메소드 추가
✅ 타임리프 th:utext 속성

📝 공부할 부분

✅ 컴포넌트 공부
✅ 타임리프 속성 공부

0개의 댓글