DEV Community

Roshan Adhikari
Roshan Adhikari

Posted on • Edited on • Originally published at roshanadhikary.com.np

3 2

Build a Markdown-based Blog with Spring Boot - Part 3

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: Part 1 and Part 2.

By now, we have defined POJO classes for our entities, repository interfaces for those entities, and controllers for handling various HTTP requests.

Now, we should try and work with our database. For this, we need to specify various database-specific properties in the application.properties file inside resources directory.

Defining application properties

Inside the application.properties file, we specify our database URL, username, password, and the database initialization method.

spring.datasource.url=jdbc:mysql://localhost:3306/markdownblogdb?createDatabaseIfNotExist=true
spring.datasource.username=root
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create-drop

The first three property names are pretty self-explanatory, and so are their values.

The last property, spring.jpa.hibernate.ddl-auto, specifies the database schema generation method. With a value of create-drop, we instruct Hibernate to drop the database schema and recreate it afterward using the entity model as a reference. More about schema generation strategies here.

Now when we run our @SpringBootApplication class (MdBlogApplication in my case), the database should be created with the name that we specified in the database URL.

After this, we get to read and parse Markdown files for our blog posts. First, lets add CommonMark as one of our dependencies.

Adding CommonMark to POM

<dependencies>
<!-- other dependencies -->
<dependency>
<groupId>org.commonmark</groupId>
<artifactId>commonmark</artifactId>
<version>0.17.1</version>
</dependency>
</dependencies>
view raw POM.xml hosted with ❤ by GitHub

CommonMark will help us to parse Markdown content from our Markdown files and render HTML blog posts from said content.

Loading Maven changes after adding CommonMark

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.

Now we are ready to parse some Markdown!

Conventions for Markdown files

From this point on, we will assume that our blog posts will be stored as Markdown files in the resources/posts/ directory.

Each Markdown file will be named with the following format in mind: 1_Hello_World!.md

Let's deconstruct the file name:

1: This is the ID for the post. It should be unique because our entity Post has a unique, auto-generating ID field.

_: We will use underscores (_) as the delimiter for separating the ID from the title of the post, and for separating the words in the title.

Hello_World!: The title of our blog post.

.md: The extension for the Markdown file.

The reasons for using these conventions will be apparent as soon as we begin reading lines from the Markdown files.

Reading lines from Markdown files

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.

For now, let us implement the method to read individual lines.

package np.com.roshanadhikary.mdblog.util;
import org.springframework.core.io.ClassPathResource;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.stream.Collectors;
public class MdFileReader {
public static List<String> readLinesFromMdFile(String filename) {
try {
InputStream iStream = new ClassPathResource("/posts/" + filename)
.getInputStream();
BufferedReader bReader = new BufferedReader(new InputStreamReader(iStream));
return bReader.lines()
.collect(Collectors.toList());
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public static String getTitleFromFileName(String filename) {
}
public static long getIdFromFileName(String filename) {
}
}

The readLinesFromMdFile method takes a file name as an argument and creates an InputStream from the ClassPathResource available under that name inside resources/posts/ directory.

We create a BufferedReader instance using the InputStream, and then collect individual lines in the file into a List instance, which is returned from the method.

Now onto retrieving the ID and title portions from the file name.

package np.com.roshanadhikary.mdblog.util;
import java.util.Arrays;
public class MdFileReader {
// ... readLinesFromMdFile method
public static String getTitleFromFileName(String filename) {
String fileNameBeforeExtension = filename.split(".md")[0];
String[] tokens = fileNameBeforeExtension.split("_");
String[] titleTokens = Arrays.copyOfRange(tokens, 1, tokens.length);
return String.join(" ", titleTokens);
}
public static long getIdFromFileName(String filename) {
String fileNameBeforeExtension = filename.split(".md")[0];
return Long.parseLong(fileNameBeforeExtension.split("_")[0]);
}
}

In the getTitleFromFileName method, we separate the extension (.md) from the rest of the file name, and split the remainder string excluding the ID portion.

In the getIdFromFileName method, again, we separate the extension from the rest of the file name. Then, we parse the ID portion as a long value.

Now we can finally render HTML content from a List of Markdown lines.

Rendering HTML

We need to write another utility class with a method that parses the passed List of Markdown lines and returns a String of rendered HTML content.

package np.com.roshanadhikary.mdblog.util;
import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;
import java.util.List;
public class MdToHtmlRenderer {
/**
* Parse List of Markdown lines passed as argument, and render
* corresponding HTML
*/
public static String renderHtml(List<String> markdownLines) {
Parser parser = Parser.builder().build();
HtmlRenderer renderer = HtmlRenderer.builder().build();
StringBuilder renderedSB = new StringBuilder();
for (String markdownLine : markdownLines) {
Node document = parser.parse(markdownLine);
renderedSB.append(renderer.render(document));
}
return new String(renderedSB);
}
}

In the renderHtml method, we use CommonMark types like Parser to parse Markdown content, and HtmlRenderer to render the parsed Markdown content as HTML.

Finally, we return a String that represents our HTML blog post.

Code

 This is it for part 3. In the next piece, we will pick up the project from this point on.

The GitHub repository has been updated for this part, as well as other parts.

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read full post →

Top comments (0)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more