Build a Markdown-based Blog with Spring Boot - Part 3
Tags: java, springboot, thymeleaf, markdown
Published: 2021-05-24 07:11:59

<p>This piece is a part of a series of blog posts regarding this topic. If you haven't read the first two, please do so: <a href="https://www.roshanadhikary.com.np/2021/05/build-a-markdown-based-blog-with-spring-boot-part-1.html">Part 1</a> and <a href="https://www.roshanadhikary.com.np/2021/05/build-a-markdown-based-blog-with-spring-boot-part-2.html">Part 2</a>.</p><p>By now, we have defined POJO classes for our entities, repository interfaces for those entities, and controllers for handling various HTTP requests.</p><p>Now, we should try and work with our database. For this, we need to specify various database-specific properties in the <em>application.properties</em> file inside <em>resources</em> directory.</p><h3 style="text-align: left;">Defining application properties</h3><p style="text-align: left;">Inside the <em>application.properties</em> file, we specify our database URL, username, password, and the database initialization method.</p>
<p>
  {% gist https://gist.github.com/roshanadh/60bf81f344fd0943771dda52f6576316.js %}
</p>
<p style="text-align: left;">The first three property names are pretty self-explanatory, and so are their values.</p><p style="text-align: left;">The last property, <em>spring.jpa.hibernate.ddl-auto</em>, specifies the database schema generation method. With a value of <em>create-drop</em>, we instruct Hibernate to drop the database schema and recreate it afterward using the entity model as a reference. More about schema generation strategies <a href="https://vladmihalcea.com/hibernate-hbm2ddl-auto-schema/" target="_blank">here</a>.</p><p style="text-align: left;">Now when we run our <em>@SpringBootApplication</em> class (MdBlogApplication in my case), the database should be created with the name that we specified in the database URL.</p><p style="text-align: left;">After this, we get to read and parse Markdown files for our blog posts. First, lets add&nbsp;<em>CommonMark</em>&nbsp;as one of our dependencies.</p><h3 style="text-align: left;">Adding CommonMark to POM</h3>
<p>
  {% gist https://gist.github.com/roshanadh/5a740dd33f7cdc0a2b18308a9452c59b.js %}
</p>
<p style="text-align: left;">CommonMark will help us to parse Markdown content from our Markdown files and render HTML blog posts from said content.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-P7ejc-YiOm4/YKpfxKiM94I/AAAAAAAAG9o/mbFtKPFe1xUef35uPME6Of9Gd-NNQf05QCLcBGAsYHQ/s1358/add-commonmark.png" style="margin-left: 1em; margin-right: 1em;"><img alt="Loading Maven changes after adding CommonMark" border="0" data-original-height="769" data-original-width="1358" src="https://1.bp.blogspot.com/-P7ejc-YiOm4/YKpfxKiM94I/AAAAAAAAG9o/mbFtKPFe1xUef35uPME6Of9Gd-NNQf05QCLcBGAsYHQ/s16000/add-commonmark.png" title="Loading Maven changes after adding CommonMark" /></a></div><p style="text-align: left;">After adding the CommonMark dependency, IntelliJ IDEA will display a small icon allowing us to load Maven changes. This way, the related files will be downloaded and integrated into our classpath.</p><p style="text-align: left;">Now we are ready to parse some Markdown!</p><h3 style="text-align: left;">Conventions for Markdown files</h3><p style="text-align: left;">From this point on, we will assume that our blog posts will be stored as Markdown files in the <em>resources/posts/</em> directory.</p><p style="text-align: left;">Each Markdown file will be named with the following format in mind: <em>1_Hello_World!.md</em></p><p style="text-align: left;">Let's deconstruct the file name:</p><p style="text-align: left;"><em><b>1</b></em>: This is the ID for the post. It should be unique because our entity <em>Post</em>&nbsp;has a unique, auto-generating ID field.</p><p style="text-align: left;"><em><b>_</b></em>: We will use underscores (<em>_</em>) as the delimiter for separating the ID from the title of the post, and for separating the words in the title.</p><p style="text-align: left;"><em><b>Hello_World!</b></em>: The title of our blog post.</p><p style="text-align: left;"><em><b>.md</b></em>: The extension for the Markdown file.</p><p style="text-align: left;">The reasons for using these conventions will be apparent as soon as we begin reading lines from the Markdown files.</p><h3 style="text-align: left;">Reading lines from Markdown files</h3><p style="text-align: left;">We need to write a utility class with methods that serve to read individual lines from a Markdown file, retrieve ID from a file name, and retrieve title from a file name.</p><p style="text-align: left;">For now, let us implement the&nbsp;method to read individual lines.</p>
<p>
  {% gist https://gist.github.com/roshanadh/ac1992ac713253a6170f857c67de322a.js %}
</p>
<p style="text-align: left;">The <em>readLinesFromMdFile</em> method takes a file name as an argument and creates an <em>InputStream</em> from the <em>ClassPathResource</em> available under that name inside <em>resources/posts/</em> directory.</p><p style="text-align: left;">We create a <em>BufferedReader</em> instance using the InputStream, and then collect individual lines in the file into a <em>List</em> instance, which is returned from the method.</p><p style="text-align: left;">Now onto retrieving the ID and title portions from the file name.</p>
<p>
  {% gist https://gist.github.com/roshanadh/05dde5b90fd8e6f692df3be79d931315.js %}
</p>
<p style="text-align: left;">In the <em>getTitleFromFileName</em> method, we separate the extension (<em>.md</em>) from the rest of the file name, and split the remainder string excluding the ID portion.</p><p style="text-align: left;">In the <em>getIdFromFileName</em> method, again, we separate the extension from the rest of the file name. Then, we parse the ID portion as a <em>long</em> value.</p><p style="text-align: left;">Now we can finally render HTML content from a&nbsp;<em>List</em>&nbsp;of Markdown lines.</p><h3 style="text-align: left;">Rendering HTML</h3><p style="text-align: left;">We need to write another utility class with a method that parses the passed <em>List</em>&nbsp;of Markdown lines and returns a <em>String</em>&nbsp;of rendered HTML content<em>.</em></p>
<p>
  {% gist https://gist.github.com/roshanadh/efd8e107aaefba426077d964dd181b9d.js %}
</p>
<p style="text-align: left;">In the <em>renderHtml</em>&nbsp;method, we use <em>CommonMark</em> types like <em>Parser</em>&nbsp;to parse Markdown content, and&nbsp;<em>HtmlRenderer</em>&nbsp;to render the parsed Markdown content as HTML.</p><p style="text-align: left;">Finally, we return a <em>String</em>&nbsp;that represents our HTML blog post.</p><h3 style="text-align: left;">Code</h3><p style="text-align: left;">&nbsp;This is it for part 3. In the next piece, we will pick up the project from this point on.</p><p style="text-align: left;">The GitHub repository has been updated for this <a href="https://github.com/roshanadh/markdown-blog/tree/part-3" target="_blank">part</a>, as well as other <a href="https://github.com/roshanadh/markdown-blog/branches/all" target="_blank">parts</a>.</p>