<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Roshan Adhikari</title>
    <description>The latest articles on DEV Community by Roshan Adhikari (@roshanadh).</description>
    <link>https://dev.to/roshanadh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F95876%2F0a4679e2-301a-415f-a624-0f5aa70eb861.jpg</url>
      <title>DEV Community: Roshan Adhikari</title>
      <link>https://dev.to/roshanadh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/roshanadh"/>
    <language>en</language>
    <item>
      <title>Spring Boot Integration Testing with MockMvc</title>
      <dc:creator>Roshan Adhikari</dc:creator>
      <pubDate>Sat, 22 Oct 2022 14:29:34 +0000</pubDate>
      <link>https://dev.to/roshanadh/spring-boot-integration-testing-with-mockmvc-2j8b</link>
      <guid>https://dev.to/roshanadh/spring-boot-integration-testing-with-mockmvc-2j8b</guid>
      <description>&lt;p&gt;In this piece, we will build a REST-ful API using Spring Boot and Spring MVC, then perform integration testing by making requests to our endpoints and verifying the responses. For this project, we will need JUnit, MockMvc, H2, and a few other dependencies. Let's get started!&lt;/p&gt;
&lt;h2&gt;Dependencies&lt;/h2&gt;First, go to the &lt;a href="https://start.spring.io"&gt;Spring Initializr&lt;/a&gt; and generate a Spring Web application using the following dependencies:&lt;ol&gt;
&lt;li&gt;Spring Web&lt;/li&gt;
&lt;li&gt;Spring Data JPA&lt;/li&gt;
&lt;li&gt;H2 Database&lt;/li&gt;
&lt;li&gt;Lombok&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OkWpAOQS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0mzx3gdywo4gthaq5otd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OkWpAOQS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0mzx3gdywo4gthaq5otd.png" alt="Configuring Spring Boot dependencies with Spring Initializr" width="880" height="454"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;br&gt;We will create a REST-ful API, expose some endpoints, and test those endpoints using MockMvc.For persistence support, we will use the H2 in-memory database, and for interacting with the database, we will use the repositories provided by Spring Data JPA. I will be using Lombok for reducing the amount of boilerplate code I would be writing otherwise.&lt;h2&gt;Controllers&lt;/h2&gt;For the purposes of brevity, we will be exposing just the following endpoints and HTTP actions:&lt;ol&gt;
&lt;li&gt;
&lt;b&gt;GET /batteries&lt;/b&gt; - Returns a list of all Battery resources in database&lt;/li&gt;
&lt;li&gt;
&lt;b&gt;GET /batteries/:id&lt;/b&gt; - Returns the Battery resource identified by id path variable&lt;/li&gt;
&lt;li&gt;
&lt;b&gt;POST /batteries&lt;/b&gt; - Persists a Battery resource in database and returns the persisted resource&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Resource&lt;/h2&gt;As you can see from the Controllers section, we will be working on a Battery resource for our API. The Battery resource will have the following fields:

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;Also, using the JPA annotations @Entity, @Table, @Column, etc., we map the POJO to our database entity of name &lt;em&gt;batteries&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;Repository&lt;/h2&gt;One of the most useful features of the Spring Data JPA project is the Repository pattern that comes with its implementations out-of-the-box. This way, we can quickly bootstrap a CRUD functionality without having to writing queries by ourselves.&lt;br&gt;Let us define the repository for our Battery entity by extending the &lt;em&gt;JpaRepository &lt;/em&gt;interface.&lt;br&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;Having defined this repository, we can now access a bunch of predefined methods that implement CRUD functionality (e.g.,  &lt;em&gt;save&lt;/em&gt;, &lt;em&gt;saveAll&lt;/em&gt;, &lt;em&gt;deleteById&lt;/em&gt;, &lt;em&gt;delete&lt;/em&gt;, etc.)&lt;/p&gt;
&lt;h2&gt;Bootstrap the database&lt;/h2&gt;To test our application, we will need some preloaded records. Let us create a Bootstrap configuration class that loads records into our database every time the application starts. 

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;When a class is annotated with &lt;em&gt;@Configuration&lt;/em&gt;, it means that the Spring IOC container can expect some bean definition inside the class. And so we give a bean definition using the &lt;em&gt;@Bean&lt;/em&gt; annotation on the &lt;em&gt;initDb &lt;/em&gt;method that returns an object of type &lt;em&gt;CommandLineRunner&lt;/em&gt;.&lt;br&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;br&gt;
&lt;em&gt;CommandLineRunner &lt;/em&gt;is a functional interface with a method named &lt;em&gt;run&lt;/em&gt;. When the Spring context is loaded, Spring Boot invokes the run method of all beans of type &lt;em&gt;CommandLineRunner&lt;/em&gt;.&lt;/blockquote&gt;


&lt;h2&gt;Application properties&lt;/h2&gt;For our application to work, we need to pass some application properties, including those for the database URL, username, password, and driver class name. Additionally, you can pass properties to enable the H2 console through which you can access the database using a GUI.

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;h2&gt;Testing our API&lt;/h2&gt;The &lt;em&gt;spring-boot-starter-test&lt;/em&gt; starter module included in our &lt;em&gt;pom.xml&lt;/em&gt; file includes &lt;em&gt;JUnit&lt;/em&gt;, &lt;em&gt;AssertJ&lt;/em&gt;, &lt;em&gt;Hamcrest&lt;/em&gt;, etc. All of these libraries help us write effective test cases for our projects.&lt;br&gt;For this particular project, start with the main test class:&lt;br&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


The &lt;em&gt;@SpringBootTest&lt;/em&gt; annotation is used on tests classes for Spring Boot, and it loads the complete Spring application context.&lt;br&gt;Using &lt;em&gt;@AutoConfigureMockMvc&lt;/em&gt;, we can enable auto-configuration of the Spring MVC test framework. &lt;em&gt;MockMvc &lt;/em&gt;does request handling but uses mock request and response objects. No actual server is started.&lt;h3&gt;Testing GET /batteries/:id&lt;/h3&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


As you can see, we have imported some static methods from MockMvcRequestBuilders, MockMvcResultHandlers, and MockMvcResultMatchers. These static methods are then used for making HTTP requests (&lt;em&gt;get&lt;/em&gt;, &lt;em&gt;post&lt;/em&gt;, etc.), reading JSON responses (&lt;em&gt;jsonPath&lt;/em&gt;), and printing the responses (&lt;em&gt;print&lt;/em&gt;).&lt;br&gt;With the above test case, we verify that the response for &lt;em&gt;GET /batteries/1&lt;/em&gt; HTTP action contains the same &lt;em&gt;id&lt;/em&gt;, &lt;em&gt;name&lt;/em&gt;, &lt;em&gt;postcode&lt;/em&gt;, and &lt;em&gt;capacity&lt;/em&gt; values as in our database (the one we preloaded).&lt;h3&gt;Testing GET /batteries&lt;/h3&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


Similar to the previous test, we make a GET request to our endpoint and then print the response. Then we continue our tests through &lt;em&gt;andExpect&lt;/em&gt;. First, we verify that the response status is &lt;em&gt;200 OK&lt;/em&gt;. Then, we verify that the response is a list of JSON objects. Finally, we verify that the size of list is equal to the size of records that exist in the database.&lt;h3&gt;Testing POST /batteries&lt;/h3&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


To send a request body along with our POST request, we use the autowired &lt;em&gt;ObjectMapper&lt;/em&gt; instance to map the Battery object onto a String. The string object is then passed as the content of our POST request, and we specify the type of request body as JSON using &lt;em&gt;contentType &lt;/em&gt;method.&lt;br&gt;Then, we use &lt;em&gt;andExpect &lt;/em&gt;to verify our expectations with the JSON response. The response status should should be &lt;em&gt;201 CREATED&lt;/em&gt;. And since our API returns the very object that was persisted, the &lt;em&gt;name&lt;/em&gt;, &lt;em&gt;postcode&lt;/em&gt;, and &lt;em&gt;capacity &lt;/em&gt;parameters should match.&lt;h2&gt;Conclusion&lt;/h2&gt;We have successfully created and tested our REST-ful API using &lt;em&gt;MockMvc &lt;/em&gt;and several other utility testing libraries. The full project code has been pushed to &lt;a href="https://github.com/roshanadh/spring-mockmvc-test"&gt;GitHub&lt;/a&gt;, feel free to check it out.&lt;br&gt;

</description>
      <category>mockmvc</category>
      <category>spring</category>
      <category>java</category>
      <category>junit</category>
    </item>
    <item>
      <title>Build a Markdown-based Blog with Spring Boot - Part 6</title>
      <dc:creator>Roshan Adhikari</dc:creator>
      <pubDate>Fri, 02 Jul 2021 08:04:31 +0000</pubDate>
      <link>https://dev.to/roshanadh/build-a-markdown-based-blog-with-spring-boot-part-6-31o2</link>
      <guid>https://dev.to/roshanadh/build-a-markdown-based-blog-with-spring-boot-part-6-31o2</guid>
      <description>&lt;p&gt;This will be the final part of this series. For previous parts, please check: &lt;a href="https://www.roshanadhikary.com.np/2021/05/build-a-markdown-based-blog-with-spring-boot-part-1.html"&gt;Part 1&lt;/a&gt; | &lt;a href="https://www.roshanadhikary.com.np/2021/05/build-a-markdown-based-blog-with-spring-boot-part-2.html"&gt;Part 2&lt;/a&gt; | &lt;a href="https://www.roshanadhikary.com.np/2021/05/build-a-markdown-based-blog-with-spring-boot-part-3.html"&gt;Part 3&lt;/a&gt; | &lt;a href="https://www.roshanadhikary.com.np/2021/05/build-a-markdown-based-blog-with-spring-boot-part-4.html"&gt;Part 4&lt;/a&gt; | &lt;a href="https://www.roshanadhikary.com.np/2021/07/build-a-markdown-based-blog-with-spring-boot-part-5.html"&gt;Part 5&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Recap&lt;/h3&gt;
&lt;p&gt;By now, we have a complete blogging system set up. We add Markdown files to the &lt;em&gt;resources/posts&lt;/em&gt; directory and our &lt;em&gt;ContextEventListener&lt;/em&gt; class, upon a &lt;em&gt;ContextRefreshedEvent&lt;/em&gt;, populates the database with the content from new Markdown files. Then, on the client side, when we request for a specific blog post by its ID, the &lt;em&gt;PostController.getPostById&lt;/em&gt; method adds the respective post as a model attribute and returns the appropriate view to render.&lt;/p&gt;
&lt;h3&gt;What now?&lt;/h3&gt;
&lt;p&gt;We need to host our database in RemoteMySQL, push our repository to GitHub,and then deploy the repository to Heroku. But before that, let's add some new files to our repository.&lt;/p&gt;
&lt;h3&gt;Specify the Java Runtime&lt;/h3&gt;
&lt;p&gt;We need to specify the Java Runtime version to be used for our application. In the root directory of our project, create a new file &lt;em&gt;system.properties&lt;/em&gt; and specify the Runtime version as 11.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;




&lt;h3&gt;Create a Heroku profile&lt;/h3&gt;
&lt;p&gt;We used the application.properties file for our development environment; but for deployment to Heroku, we will need a new set of properties. Create a &lt;em&gt;application-heroku.properties&lt;/em&gt; file inside the &lt;em&gt;resources&lt;/em&gt; directory.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;We specify the datasource URL, username, and password as environment variables from within our Heroku environment. We also set the automatic database initialization provided by Hibernate to &lt;em&gt;update&lt;/em&gt;; so, Hibernate checks for the tables and if a table doesn't exist, then it creates new tables.&lt;/p&gt;
&lt;p&gt;So basically, we will provide four configuration variables (or Config Vars) to our Heroku deployment.&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;DATASOURCE_URL&lt;/li&gt;&lt;/ul&gt;

&lt;ul&gt;&lt;li&gt;DATASOURCE_USERNAME&lt;/li&gt;&lt;/ul&gt;

&lt;ul&gt;&lt;li&gt;DATASOURCE_PASSWORD&lt;/li&gt;&lt;/ul&gt;

&lt;ul&gt;&lt;li&gt;spring_profiles_active&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;If we set the variable &lt;em&gt;spring_profiles_active&lt;/em&gt; to Heroku, Spring Boot automatically loads the appropriate properties file (i.e., &lt;em&gt;application-heroku.properties&lt;/em&gt;).&lt;/p&gt;
&lt;h3&gt;RemoteMySQL&lt;/h3&gt;
&lt;p&gt;Now onto our production database, register for an account in &lt;a href="https://remotemysql.com/login.php" rel="nofollow"&gt;RemoteMySQL&lt;/a&gt;. After you are a registered user, you can create a new database; after which RemoteMySQL provides you with details about your credentials, including the username, database name, password, port, host, etc. Keep these secure as we need to pass these as Config Vars to our Heroku deployment.&lt;/p&gt;
&lt;p&gt;In the DATABASES section, go to the Action tab of your database (the one you created just now), and click on &lt;em&gt;phpMyAdmin&lt;/em&gt;. RemoteMySQL provided a GUI for interacting with our relations.&lt;/p&gt;
&lt;a href="https://1.bp.blogspot.com/-c_ZNYNQsMWs/YN66jZCA-_I/AAAAAAAAHYk/wQ2lvF8RUT8bnMBpo4Nu1foYnZA_7siIACLcBGAsYHQ/s1919/phpmyadmin.png"&gt;&lt;img alt="Action to open phpMyAdmin" src="https://res.cloudinary.com/practicaldev/image/fetch/s--8byIPyRK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://1.bp.blogspot.com/-c_ZNYNQsMWs/YN66jZCA-_I/AAAAAAAAHYk/wQ2lvF8RUT8bnMBpo4Nu1foYnZA_7siIACLcBGAsYHQ/s16000/phpmyadmin.png" title="Action to open phpMyAdmin"&gt;&lt;/a&gt;&lt;p&gt;In the phpMyAdmin page, login with username and password that you received just now.&lt;/p&gt;
&lt;h3&gt;GitHub&lt;/h3&gt;
&lt;p&gt;Before proceeding any further, make sure you've committed your changes and pushed them to the remote repository.&lt;/p&gt;
&lt;h3&gt;Heroku&lt;/h3&gt;
&lt;p&gt;If you're new to Heroku, first register for an account. Then, from the dashboard, create a new application with &lt;em&gt;New&lt;/em&gt; &lt;em&gt;&amp;gt; Create new app&lt;/em&gt;.&lt;/p&gt;
&lt;a href="https://1.bp.blogspot.com/-dLVAblWN4ac/YN66vrIgXJI/AAAAAAAAHYo/Gz45_fxGvK4vCaYdnAn0sejVVlXIRbq4QCLcBGAsYHQ/s1276/github-heroku.png"&gt;&lt;img alt="Create a new application" src="https://res.cloudinary.com/practicaldev/image/fetch/s--sqGhvDOK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://1.bp.blogspot.com/-dLVAblWN4ac/YN66vrIgXJI/AAAAAAAAHYo/Gz45_fxGvK4vCaYdnAn0sejVVlXIRbq4QCLcBGAsYHQ/s16000/github-heroku.png" title="Create a new application"&gt;&lt;/a&gt;&lt;p&gt;Now we can specify our deployment method. In the following page, select GitHub as the deployment method and select the repository and connect it to Heroku. Then just below, select the branch to trigger automatic deployment and click the &lt;em&gt;Enable Automatic Deploys&lt;/em&gt; button. For me, it is the &lt;em&gt;main&lt;/em&gt; branch.&lt;/p&gt;
&lt;a href="https://1.bp.blogspot.com/-30v9VEQ04kU/YN68GN8DtcI/AAAAAAAAHY0/XxJ_atagXeEL8QWXXfd_VMXhuC42IuiFgCLcBGAsYHQ/s1851/automatic-deploys.png"&gt;&lt;img alt="Enable automatic deploys in Heroku" src="https://res.cloudinary.com/practicaldev/image/fetch/s--X_1_gnfK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://1.bp.blogspot.com/-30v9VEQ04kU/YN68GN8DtcI/AAAAAAAAHY0/XxJ_atagXeEL8QWXXfd_VMXhuC42IuiFgCLcBGAsYHQ/s16000/automatic-deploys.png" title="Enable automatic deploys in Heroku"&gt;&lt;/a&gt;&lt;p&gt;This means that whenever I push something (for instance a new Markdown file inside &lt;em&gt;resources/posts&lt;/em&gt; directory), Heroku reflects those changes in the deployed application. We do not need to redeploy the application.&lt;/p&gt;
&lt;p&gt;Following this, go to the &lt;em&gt;Settings&lt;/em&gt; tab and click the &lt;em&gt;Reveal Config Vars&lt;/em&gt; button. Now we can add all the required configuration variables we discussed above.&lt;/p&gt;
&lt;a href="https://1.bp.blogspot.com/-_m5s_e7A3K4/YN69xt7y33I/AAAAAAAAHY8/pQu-jF7dxXgI9VBFktQn9_n1FfCwWH4aQCLcBGAsYHQ/s1206/configvars.png"&gt;&lt;img alt="Set the config variables in Heroku" src="https://res.cloudinary.com/practicaldev/image/fetch/s--dnEI1qqX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://1.bp.blogspot.com/-_m5s_e7A3K4/YN69xt7y33I/AAAAAAAAHY8/pQu-jF7dxXgI9VBFktQn9_n1FfCwWH4aQCLcBGAsYHQ/s16000/configvars.png" title="Set the config variables in Heroku"&gt;&lt;/a&gt;

&lt;ul&gt;&lt;li&gt;Set the &lt;em&gt;DATASOURCE_URL&lt;/em&gt; variable as &lt;em&gt;jdbc:mysql://remotemysql.com:3306/your-database-name&lt;/em&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;ul&gt;&lt;li&gt;Set the &lt;em&gt;DATASOURCE_USERNAME&lt;/em&gt; variable as the username you received from RemoteMySQL.&lt;/li&gt;&lt;/ul&gt;
&lt;ul&gt;&lt;li&gt;Set the &lt;em&gt;DATASOURCE_PASSWORD&lt;/em&gt; variable as the password you received from RemoteMySQL.&lt;/li&gt;&lt;/ul&gt;
&lt;ul&gt;&lt;li&gt;Set &lt;em&gt;spring_profiles_active&lt;/em&gt; variable as &lt;em&gt;heroku&lt;/em&gt;
&lt;/li&gt;&lt;/ul&gt;


&lt;p&gt;Finally, go back to the &lt;em&gt;Deploy&lt;/em&gt; and click on the &lt;em&gt;Deploy Branch&lt;/em&gt; button to manually deploy the application for the first time.&lt;/p&gt;
&lt;h3&gt;Live deployment&lt;/h3&gt;
&lt;p&gt;If the build process didn't end up in an error, you should be able to open the application and see your blog posts live.&lt;/p&gt;
&lt;a href="https://1.bp.blogspot.com/-3voQgpn1cus/YN7Cghrc9jI/AAAAAAAAHZE/nz4t__DaneY3GVASEc0HZi0YQZ5Z5MRfwCLcBGAsYHQ/s1919/live.png"&gt;&lt;img alt="Deployed application" src="https://res.cloudinary.com/practicaldev/image/fetch/s--uH3i5ech--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://1.bp.blogspot.com/-3voQgpn1cus/YN7Cghrc9jI/AAAAAAAAHZE/nz4t__DaneY3GVASEc0HZi0YQZ5Z5MRfwCLcBGAsYHQ/s16000/live.png" title="Deployed application"&gt;&lt;/a&gt;&lt;h3&gt;Adding new blog posts&lt;/h3&gt;
&lt;p&gt;Too see if the deployment mechanism works, let us create a new Markdown file, &lt;em&gt;6_After_Deployment_Blog.md&lt;/em&gt;, inside the &lt;em&gt;resources/posts&lt;/em&gt; directory in our local repository.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Now, commit the change and push it to the remote repository's &lt;em&gt;main&lt;/em&gt; branch. Note that I am pushing to my &lt;em&gt;main&lt;/em&gt; branch because that's the branch I set to trigger automatic deploys in Heroku. If you had set another branch, then you should push your changes to that branch.&lt;/p&gt;
&lt;p&gt;After you've pushed your changes, you should see a "Build started by ..." message in the logs of your Heroku application. This means that our application's automatic deployment feature is working as intended.&lt;/p&gt;
&lt;p&gt;To check the logs of your application, go to &lt;em&gt;dashboard.heroku.com/apps/&amp;lt;your-app-name&amp;gt;/logs&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;After the build completes, open your deployment to see if the new post is available. In my case, it is.&lt;/p&gt;
&lt;a href="https://1.bp.blogspot.com/-IIkpnQeTnQ0/YN7FvmNlhxI/AAAAAAAAHZM/Yd6RVe4enNgSi3Oh41mph3LL5avI39mKACLcBGAsYHQ/s1919/new%2Bpost.png"&gt;&lt;img alt="New post" src="https://res.cloudinary.com/practicaldev/image/fetch/s--M1mpFtr8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://1.bp.blogspot.com/-IIkpnQeTnQ0/YN7FvmNlhxI/AAAAAAAAHZM/Yd6RVe4enNgSi3Oh41mph3LL5avI39mKACLcBGAsYHQ/s16000/new%252Bpost.png" title="New post"&gt;&lt;/a&gt;&lt;h3&gt;Wrapping up&lt;/h3&gt;
&lt;p&gt;This concludes the series. We have built a blog application that reads Markdown files and populates the database with its content. Whenever we push a new Markdown file to our GitHub repository, Heroku automatically deploys the changes in our application.&lt;/p&gt;
&lt;p&gt;Note that there are several limitations with the free database we use from RemoteMySQL. Read them &lt;a href="https://remotemysql.com/faq.html" rel="nofollow"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All of the code associated with the project have been published in the GitHub &lt;a href="https://github.com/roshanadh/markdown-blog" rel="nofollow"&gt;repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The blog is deployed &lt;a href="https://github-blog-demo.herokuapp.com/" rel="nofollow"&gt;here&lt;/a&gt;, if you want to take a look.&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>thymeleaf</category>
      <category>heroku</category>
    </item>
    <item>
      <title>Build a Markdown-based Blog with Spring Boot - Part 5</title>
      <dc:creator>Roshan Adhikari</dc:creator>
      <pubDate>Thu, 01 Jul 2021 06:36:54 +0000</pubDate>
      <link>https://dev.to/roshanadh/build-a-markdown-based-blog-with-spring-boot-part-5-4jfl</link>
      <guid>https://dev.to/roshanadh/build-a-markdown-based-blog-with-spring-boot-part-5-4jfl</guid>
      <description>&lt;p&gt;Welcome to another instalment of the "Build a Markdown Blog with Spring Boot" series. You can find the previous parts right here: &lt;a href="https://www.roshanadhikary.com.np/2021/05/build-a-markdown-based-blog-with-spring-boot-part-1.html"&gt;Part 1&lt;/a&gt; | &lt;a href="https://www.roshanadhikary.com.np/2021/05/build-a-markdown-based-blog-with-spring-boot-part-2.html"&gt;Part 2&lt;/a&gt; | &lt;a href="https://www.roshanadhikary.com.np/2021/05/build-a-markdown-based-blog-with-spring-boot-part-3.html"&gt;Part 3&lt;/a&gt; | &lt;a href="https://www.roshanadhikary.com.np/2021/05/build-a-markdown-based-blog-with-spring-boot-part-4.html"&gt;Part 4&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Recap&lt;/h3&gt;
&lt;p&gt;Right before this part, we have finished building how the blog works -- we use Markdown files stored in &lt;em&gt;resources/posts&lt;/em&gt; directory to populate our database and then fetch the posts on respective requests using our &lt;em&gt;PostController&lt;/em&gt; class.&lt;/p&gt;
&lt;p&gt;Now, we need to render the posts. For this, we use Thymeleaf and Bootstrap. We already have a Thymeleaf dependency specified in our POM.&lt;/p&gt;
&lt;h3&gt;Bootstrap WebJar&lt;/h3&gt;
&lt;p&gt;For Bootstrap, we just need to add its WebJar in the &lt;em&gt;pom.xml&lt;/em&gt; file.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Again, load the Maven changes in your POM file. Now we're ready to use Bootstrap in our Thymeleaf templates.&lt;/p&gt;
&lt;h3&gt;Header for our templates&lt;/h3&gt;
&lt;p&gt;Inside the &lt;em&gt;resources/templates&lt;/em&gt; directory, create a new template: &lt;em&gt;header.html&lt;/em&gt;. This will be the header portion of our blog that will be present in every page.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Notice how we specify both &lt;em&gt;href&lt;/em&gt; and &lt;em&gt;th:href&lt;/em&gt; attributes when linking Bootstrap. This is the reason why Thymeleaf is a &lt;em&gt;natural&lt;/em&gt; template engine: Templates written in Thymeleaf can be rendered with or without the server running. When we run the server, Thymeleaf reads the &lt;em&gt;th:href&lt;/em&gt; attribute and links Bootstrap using the WebJar resource. When the server isn't running, the browser uses the &lt;em&gt;href&lt;/em&gt; attribute to link Bootstrap.&lt;/p&gt;
&lt;h3&gt;Creating a home page&lt;/h3&gt;
&lt;p&gt;Next, create a template, &lt;em&gt;posts.html&lt;/em&gt;, that will serve as our home page.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Here, for each post retrieved from the database, a card element is created. We also use the &lt;em&gt;#temporals&lt;/em&gt; utility provided by Thymeleaf to format our &lt;em&gt;LocalDateTime&lt;/em&gt; instance so that we can render the month name, day, and year in the format: &lt;em&gt;July 1, 2021&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;You can additionally use a pagination element from Bootstrap to fetch paginated posts. (In this article, we will do it the manual way -- using request queries to specify the size and page.)&lt;/p&gt;
&lt;h3&gt;The one where we render a post&lt;/h3&gt;
&lt;p&gt;Now onto our &lt;em&gt;post.html&lt;/em&gt; template. This will be the page that renders a single blog post in full.&lt;/p&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;In this template, we employ some error-handling mechanism. Go back to the &lt;em&gt;PostController.getPostById&lt;/em&gt; method. Notice how if a post by a given ID doesn't exist, we add an &lt;em&gt;error&lt;/em&gt; attribute with &lt;em&gt;no-post&lt;/em&gt; value in the model.&lt;/p&gt;
&lt;p&gt;In &lt;em&gt;post.html&lt;/em&gt; if the model contains the &lt;em&gt;error&lt;/em&gt; attribute, we change the title as well as the body to indicate an error. Otherwise, we render the respective blog post.&lt;/p&gt;
&lt;p&gt;This is it for the coding portion of this series. To test if the pagination works, add some more Markdown files in the &lt;em&gt;resources/posts&lt;/em&gt; directory, and fetch them from the website.&lt;/p&gt;
&lt;h3&gt;Running the application&lt;/h3&gt;
&lt;p&gt;Run the Spring Boot application and wait until the JVM starts running.&lt;/p&gt;
&lt;p&gt;Visit &lt;em&gt;localhost:8080&lt;/em&gt; to see your most recent blog posts.&lt;/p&gt;
&lt;a href="https://1.bp.blogspot.com/-Ak5wrFMIkEw/YN1az2G2vdI/AAAAAAAAHX8/tHKmjbfdMyUDQZQ0OomA77UUTsfy-rPxgCLcBGAsYHQ/s1715/posts%2Bpage.png"&gt;&lt;img alt="localhost:8080/posts renders a list of the most recent blog posts" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Qu8M3-JT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://1.bp.blogspot.com/-Ak5wrFMIkEw/YN1az2G2vdI/AAAAAAAAHX8/tHKmjbfdMyUDQZQ0OomA77UUTsfy-rPxgCLcBGAsYHQ/s16000/posts%252Bpage.png" title="localhost:8080/posts renders a list of the most recent blog posts"&gt;&lt;/a&gt;&lt;br&gt;&lt;p&gt;To modify the pagination parameters, we can use query strings in our request. For instance, &lt;em&gt;localhost:8080/posts?page=0&amp;amp;size=3&lt;/em&gt; should render the three most recent blog posts.&lt;/p&gt;
&lt;a href="https://1.bp.blogspot.com/-78YGlsyO86Q/YN1bWSiGkBI/AAAAAAAAHYE/xXZFUDz9A7cdNaotrLHf8lC0tpQlfQUlACLcBGAsYHQ/s1919/three-posts.png"&gt;&lt;img alt="Rendering three most recent blog posts using query strings" src="https://res.cloudinary.com/practicaldev/image/fetch/s--00AmmDBC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://1.bp.blogspot.com/-78YGlsyO86Q/YN1bWSiGkBI/AAAAAAAAHYE/xXZFUDz9A7cdNaotrLHf8lC0tpQlfQUlACLcBGAsYHQ/s16000/three-posts.png" title="Rendering three most recent blog posts using query strings"&gt;&lt;/a&gt;&lt;br&gt;&lt;p&gt;To render a blog post in full, we can use the ID of that post, or simply click the &lt;em&gt;Read more&lt;/em&gt; hyperlink.&lt;/p&gt;
&lt;a href="https://1.bp.blogspot.com/-IZzfZPXrV_E/YN1byh8klII/AAAAAAAAHYM/oAyPyr1M6BAIm8nW5ySJG-tdD7tLw5-dwCLcBGAsYHQ/s1713/post%2Bpage.png"&gt;&lt;img alt="Rendering a full blog post" src="https://res.cloudinary.com/practicaldev/image/fetch/s--j48hap8a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://1.bp.blogspot.com/-IZzfZPXrV_E/YN1byh8klII/AAAAAAAAHYM/oAyPyr1M6BAIm8nW5ySJG-tdD7tLw5-dwCLcBGAsYHQ/s16000/post%252Bpage.png" title="Rendering a full blog post"&gt;&lt;/a&gt;&lt;br&gt;&lt;h3&gt;Code&lt;/h3&gt;
&lt;p&gt;We have successfully built the blog application that we set out to build. In the following article, we will see how we can deploy our application to Heroku, host our database on RemoteMySQL, and use Heroku's &lt;em&gt;Automatic Deployment&lt;/em&gt; feature to update our blog whenever we add a new blog post.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/roshanadh/markdown-blog/tree/part-5" rel="nofollow"&gt;This session's code&lt;/a&gt; has been pushed to the GitHub repository; for previous sessions, &lt;a href="https://github.com/roshanadh/markdown-blog/branches" rel="nofollow"&gt;check here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>thymeleaf</category>
      <category>markdown</category>
    </item>
    <item>
      <title>Build a Markdown-based Blog with Spring Boot - Part 4</title>
      <dc:creator>Roshan Adhikari</dc:creator>
      <pubDate>Thu, 27 May 2021 09:51:41 +0000</pubDate>
      <link>https://dev.to/roshanadh/build-a-markdown-based-blog-with-spring-boot-part-4-d58</link>
      <guid>https://dev.to/roshanadh/build-a-markdown-based-blog-with-spring-boot-part-4-d58</guid>
      <description>&lt;p&gt;Before continuing with part 4 of this series, make sure you have checked out the previous three parts as well: &lt;a href="https://www.roshanadhikary.com.np/2021/05/build-a-markdown-based-blog-with-spring-boot-part-1.html"&gt;Part 1&lt;/a&gt; | &lt;a href="https://www.roshanadhikary.com.np/2021/05/build-a-markdown-based-blog-with-spring-boot-part-2.html"&gt;Part 2&lt;/a&gt; | &lt;a href="https://www.roshanadhikary.com.np/2021/05/build-a-markdown-based-blog-with-spring-boot-part-3.html"&gt;Part 3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Up to this point, we have a database ready, and we have established conventions for how and where we store our Markdown files. These Markdown files will be parsed, line by line, and rendered as HTML string before we persist it in the database. For parsing and rendering, we have already defined some utility classes -- &lt;em&gt;MdFileReader&lt;/em&gt; and &lt;em&gt;MdToHtmlRenderer&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;For this session, we will write a class that implements the &lt;em&gt;ApplicationListener&lt;/em&gt; interface such that on every firing of the &lt;em&gt;ContextRefreshedEvent&lt;/em&gt;, our event-listener class' &lt;em&gt;onApplicationEvent&lt;/em&gt; method is invoked. Within the onApplicationEvent method, we look for new Markdown files, and if any such new file exists, we persist it in the database.&lt;/p&gt;
&lt;p&gt;But before that, we need to add another dependency -- &lt;em&gt;jsoup&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;Adding jsoup dependency&lt;/h3&gt;
&lt;p&gt;Remember how we have a &lt;em&gt;synopsis&lt;/em&gt; attribute in the &lt;em&gt;Post&lt;/em&gt; entity? We will use that attribute (or field, in the database) and set it to the first 150 characters of the actual post's body. However, after parsing the Markdown and rendering HTML from it, the post's body would look like, say,&lt;/p&gt;

&lt;pre&gt;&amp;lt;h1&amp;gt;Hello World!&amp;lt;/h1&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;p&amp;gt;This is the post's actual body, rendered in HTML!&amp;lt;/p&amp;gt;
&lt;/pre&gt;

&lt;p&gt;As you can imagine, most of the rendered text is actually HTML elements and symbols. Hence, we need to select the first 150 characters from the actual text, excluding the HTML elements and symbols.&lt;/p&gt;
&lt;p&gt;We will need &lt;em&gt;jsoup&lt;/em&gt; for doing exactly that. To add &lt;em&gt;jsoup&lt;/em&gt; as one of our dependencies, make sure to add the following segment to your &lt;em&gt;pom.xml&lt;/em&gt; file.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Like before, load the Maven changes in your POM file.&lt;/p&gt;
&lt;a href="https://1.bp.blogspot.com/-uHbHS_zq4f4/YK9HHKIP2bI/AAAAAAAAG-M/3iJYRh9sVcM2_WufrdrKtBS8zDsT7RNsQCLcBGAsYHQ/s1358/add-jsoup.png"&gt;&lt;img alt="Loading Maven changes after adding jsoup dependency" src="https://res.cloudinary.com/practicaldev/image/fetch/s--CQU7g2c_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://1.bp.blogspot.com/-uHbHS_zq4f4/YK9HHKIP2bI/AAAAAAAAG-M/3iJYRh9sVcM2_WufrdrKtBS8zDsT7RNsQCLcBGAsYHQ/s16000/add-jsoup.png" title="Loading Maven changes after adding jsoup dependency" width="880" height="435"&gt;&lt;/a&gt;&lt;p&gt;Then, we can proceed to our event-listener class.&lt;/p&gt;
&lt;h3&gt;ContextEventListener class&lt;/h3&gt;
&lt;p&gt;Begin by creating the class that implements &lt;em&gt;ApplicationListener&lt;/em&gt; interface that takes in as type parameter the &lt;em&gt;ContextReferencedEvent&lt;/em&gt; type. With this, our class would need to override the &lt;em&gt;onApplicationEvent&lt;/em&gt; method.&lt;/p&gt;
&lt;p&gt;We also need some instance variables for purposes that will be apparent soon.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;With &lt;em&gt;@Value&lt;/em&gt;, we inject into the &lt;em&gt;postFiles&lt;/em&gt;, an array of &lt;em&gt;Resource&lt;/em&gt; type, any files that exist in the classpath inside &lt;em&gt;posts&lt;/em&gt; directory.&lt;/p&gt;
&lt;p&gt;Next, we can implement our &lt;em&gt;onApplicationEvent&lt;/em&gt; method.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;In this method, we start by iterating over each file in the &lt;em&gt;postFiles&lt;/em&gt; array. We check to see if a post with the same ID as the file exists in the database. If it does not, we persist the post in the database. Before saving the post, we set it's attributes.&lt;/p&gt;
&lt;p&gt;Notice how we are using static utility methods from &lt;em&gt;PostUtil&lt;/em&gt; and &lt;em&gt;AuthorUtil&lt;/em&gt; classes for operations concerning posts and authors respectively.&lt;/p&gt;
&lt;h3&gt;PostUtil and AuthorUtil classes&lt;/h3&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;In the &lt;em&gt;PostUtil&lt;/em&gt; class, we define methods: &lt;em&gt;getHtmlContentFromMdLines&lt;/em&gt; and &lt;em&gt;getSynopsisFromHtmlContent&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;getHtmlContentFromMdLines&lt;/em&gt; returns a &lt;em&gt;String&lt;/em&gt; of HTML content rendered using the &lt;em&gt;List&lt;/em&gt; of Markdown lines passed as argument.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;getSynopsisFromHtmlContent&lt;/em&gt; method returns the first 150 characters of the text content parsed from the HTML content passed as argument. If the text content is fewer than 150 characters in length, the entire &lt;em&gt;String&lt;/em&gt; is returned. &lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;In the &lt;em&gt;AuthorUtil&lt;/em&gt; class, we define method: &lt;em&gt;bootstrapAuthor&lt;/em&gt;. If no author exists in the database, it creates a new author, before persisting it in the database, and returns it. Otherwise, it returns the first author that exists in the database.&lt;/p&gt;
&lt;h3&gt;Get it running&lt;/h3&gt;
&lt;p&gt;Now, when we run our Spring Boot application, or whenever we cause the Spring Context to refresh, a &lt;em&gt;ContextRefreshedEvent&lt;/em&gt; is fired. This looks for a new blog post in the &lt;em&gt;resources/posts/&lt;/em&gt; directory and persists it.&lt;/p&gt;
&lt;p&gt;To test this, let us create a &lt;em&gt;posts&lt;/em&gt; directory inside the &lt;em&gt;resources&lt;/em&gt; directory.&lt;/p&gt;
&lt;p&gt;Inside it, I will create a new file, &lt;b&gt;1_Hello_World!.md&lt;/b&gt;, with the following content.&lt;/p&gt;

&lt;pre&gt;# Hello World!
This is my *first* blog post. &amp;lt;br&amp;gt;
Be sure to read future parts of this blog post series, &amp;lt;br&amp;gt;
titled **Build a Markdown-based Blog with Spring Boot**.
&lt;/pre&gt;

&lt;p&gt;Then, let's run our Spring Boot application. After the JVM is up and running, we can check our database to see that our new blog post has been persisted successfully, along with the author.&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;p&gt;We have now created an application that persists new blog posts to our database. Now, we will work towards displaying blog posts using the &lt;em&gt;Thymeleaf&lt;/em&gt; template engine. But that's for the next post.&lt;/p&gt;
&lt;p&gt;The GitHub repository has been updated with &lt;a href="https://github.com/roshanadh/markdown-blog/tree/part-4" rel="nofollow"&gt;this session's code&lt;/a&gt;, do check it out. Or if you need to check &lt;a href="https://github.com/roshanadh/markdown-blog/branches/all" rel="nofollow"&gt;previous sessions' code&lt;/a&gt;, please do so as well. &lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>thymeleaf</category>
      <category>markdown</category>
    </item>
    <item>
      <title>Build a Markdown-based Blog with Spring Boot - Part 3</title>
      <dc:creator>Roshan Adhikari</dc:creator>
      <pubDate>Mon, 24 May 2021 07:11:59 +0000</pubDate>
      <link>https://dev.to/roshanadh/build-a-markdown-based-blog-with-spring-boot-part-3-1a99</link>
      <guid>https://dev.to/roshanadh/build-a-markdown-based-blog-with-spring-boot-part-3-1a99</guid>
      <description>&lt;p&gt;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: &lt;a href="https://www.roshanadhikary.com.np/2021/05/build-a-markdown-based-blog-with-spring-boot-part-1.html"&gt;Part 1&lt;/a&gt; and &lt;a href="https://www.roshanadhikary.com.np/2021/05/build-a-markdown-based-blog-with-spring-boot-part-2.html"&gt;Part 2&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;By now, we have defined POJO classes for our entities, repository interfaces for those entities, and controllers for handling various HTTP requests.&lt;/p&gt;
&lt;p&gt;Now, we should try and work with our database. For this, we need to specify various database-specific properties in the &lt;em&gt;application.properties&lt;/em&gt; file inside &lt;em&gt;resources&lt;/em&gt; directory.&lt;/p&gt;
&lt;h3&gt;Defining application properties&lt;/h3&gt;
&lt;p&gt;Inside the &lt;em&gt;application.properties&lt;/em&gt; file, we specify our database URL, username, password, and the database initialization method.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;The first three property names are pretty self-explanatory, and so are their values.&lt;/p&gt;
&lt;p&gt;The last property, &lt;em&gt;spring.jpa.hibernate.ddl-auto&lt;/em&gt;, specifies the database schema generation method. With a value of &lt;em&gt;create-drop&lt;/em&gt;, we instruct Hibernate to drop the database schema and recreate it afterward using the entity model as a reference. More about schema generation strategies &lt;a href="https://vladmihalcea.com/hibernate-hbm2ddl-auto-schema/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now when we run our &lt;em&gt;@SpringBootApplication&lt;/em&gt; class (MdBlogApplication in my case), the database should be created with the name that we specified in the database URL.&lt;/p&gt;
&lt;p&gt;After this, we get to read and parse Markdown files for our blog posts. First, lets add &lt;em&gt;CommonMark&lt;/em&gt; as one of our dependencies.&lt;/p&gt;
&lt;h3&gt;Adding CommonMark to POM&lt;/h3&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;CommonMark will help us to parse Markdown content from our Markdown files and render HTML blog posts from said content.&lt;/p&gt;
&lt;a href="https://1.bp.blogspot.com/-P7ejc-YiOm4/YKpfxKiM94I/AAAAAAAAG9o/mbFtKPFe1xUef35uPME6Of9Gd-NNQf05QCLcBGAsYHQ/s1358/add-commonmark.png"&gt;&lt;img alt="Loading Maven changes after adding CommonMark" src="https://res.cloudinary.com/practicaldev/image/fetch/s--zjjqR9Rq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://1.bp.blogspot.com/-P7ejc-YiOm4/YKpfxKiM94I/AAAAAAAAG9o/mbFtKPFe1xUef35uPME6Of9Gd-NNQf05QCLcBGAsYHQ/s16000/add-commonmark.png" title="Loading Maven changes after adding CommonMark"&gt;&lt;/a&gt;&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Now we are ready to parse some Markdown!&lt;/p&gt;
&lt;h3&gt;Conventions for Markdown files&lt;/h3&gt;
&lt;p&gt;From this point on, we will assume that our blog posts will be stored as Markdown files in the &lt;em&gt;resources/posts/&lt;/em&gt; directory.&lt;/p&gt;
&lt;p&gt;Each Markdown file will be named with the following format in mind: &lt;em&gt;1_Hello_World!.md&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Let's deconstruct the file name:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;b&gt;1&lt;/b&gt;&lt;/em&gt;: This is the ID for the post. It should be unique because our entity &lt;em&gt;Post&lt;/em&gt; has a unique, auto-generating ID field.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;b&gt;_&lt;/b&gt;&lt;/em&gt;: We will use underscores (&lt;em&gt;_&lt;/em&gt;) as the delimiter for separating the ID from the title of the post, and for separating the words in the title.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;b&gt;Hello_World!&lt;/b&gt;&lt;/em&gt;: The title of our blog post.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;b&gt;.md&lt;/b&gt;&lt;/em&gt;: The extension for the Markdown file.&lt;/p&gt;
&lt;p&gt;The reasons for using these conventions will be apparent as soon as we begin reading lines from the Markdown files.&lt;/p&gt;
&lt;h3&gt;Reading lines from Markdown files&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;For now, let us implement the method to read individual lines.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;The &lt;em&gt;readLinesFromMdFile&lt;/em&gt; method takes a file name as an argument and creates an &lt;em&gt;InputStream&lt;/em&gt; from the &lt;em&gt;ClassPathResource&lt;/em&gt; available under that name inside &lt;em&gt;resources/posts/&lt;/em&gt; directory.&lt;/p&gt;
&lt;p&gt;We create a &lt;em&gt;BufferedReader&lt;/em&gt; instance using the InputStream, and then collect individual lines in the file into a &lt;em&gt;List&lt;/em&gt; instance, which is returned from the method.&lt;/p&gt;
&lt;p&gt;Now onto retrieving the ID and title portions from the file name.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;In the &lt;em&gt;getTitleFromFileName&lt;/em&gt; method, we separate the extension (&lt;em&gt;.md&lt;/em&gt;) from the rest of the file name, and split the remainder string excluding the ID portion.&lt;/p&gt;
&lt;p&gt;In the &lt;em&gt;getIdFromFileName&lt;/em&gt; method, again, we separate the extension from the rest of the file name. Then, we parse the ID portion as a &lt;em&gt;long&lt;/em&gt; value.&lt;/p&gt;
&lt;p&gt;Now we can finally render HTML content from a &lt;em&gt;List&lt;/em&gt; of Markdown lines.&lt;/p&gt;
&lt;h3&gt;Rendering HTML&lt;/h3&gt;
&lt;p&gt;We need to write another utility class with a method that parses the passed &lt;em&gt;List&lt;/em&gt; of Markdown lines and returns a &lt;em&gt;String&lt;/em&gt; of rendered HTML content&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;In the &lt;em&gt;renderHtml&lt;/em&gt; method, we use &lt;em&gt;CommonMark&lt;/em&gt; types like &lt;em&gt;Parser&lt;/em&gt; to parse Markdown content, and &lt;em&gt;HtmlRenderer&lt;/em&gt; to render the parsed Markdown content as HTML.&lt;/p&gt;
&lt;p&gt;Finally, we return a &lt;em&gt;String&lt;/em&gt; that represents our HTML blog post.&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;p&gt; This is it for part 3. In the next piece, we will pick up the project from this point on.&lt;/p&gt;
&lt;p&gt;The GitHub repository has been updated for this &lt;a href="https://github.com/roshanadh/markdown-blog/tree/part-3"&gt;part&lt;/a&gt;, as well as other &lt;a href="https://github.com/roshanadh/markdown-blog/branches/all"&gt;parts&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>thymeleaf</category>
      <category>markdown</category>
    </item>
    <item>
      <title>Build a Markdown-based Blog with Spring Boot - Part 2</title>
      <dc:creator>Roshan Adhikari</dc:creator>
      <pubDate>Sat, 22 May 2021 11:53:07 +0000</pubDate>
      <link>https://dev.to/roshanadh/build-a-markdown-based-blog-with-spring-boot-part-2-5aon</link>
      <guid>https://dev.to/roshanadh/build-a-markdown-based-blog-with-spring-boot-part-2-5aon</guid>
      <description>&lt;p&gt;If you haven't read the &lt;a href="https://www.roshanadhikary.com.np/2021/05/build-a-markdown-based-blog-with-spring-boot-part-1.html"&gt;first part&lt;/a&gt;, please do so.&lt;/p&gt;
&lt;p&gt;At the end of the first part, we had defined the POJO classes for the two entities (&lt;em&gt;Author&lt;/em&gt; and &lt;em&gt;Post&lt;/em&gt;) in our project.&lt;/p&gt;
&lt;p&gt;We begin the second part by defining the repository interfaces for those entities.&lt;/p&gt;
&lt;h3&gt;Defining repositories&lt;/h3&gt;
&lt;p&gt;Spring Data provides several &lt;em&gt;Repository&lt;/em&gt; abstractions that aim at reducing the amount of human-generated code for data-access layers. Two of such abstractions that we need for our blog are &lt;em&gt;&lt;a href="https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/CrudRepository.html"&gt;CrudRepository&lt;/a&gt;&lt;/em&gt; and &lt;em&gt;&lt;a href="https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/PagingAndSortingRepository.html"&gt;PagingAndSortingRepository&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The CrudRepository interface provides various methods for performing CRUD operations on an entity. On the other hand, the PagingAndSortingRepository is an extension of the CrudRepository that provides additional methods for retrieving entities using the paging and sorting abstraction.&lt;/p&gt;
&lt;p&gt;The repositories for our entities are defined as follows.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;




&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Since we don't need to implement paging or sorting for the Author entity, we can extend CrudRepository for &lt;em&gt;AuthorRepository&lt;/em&gt;. On the other hand, since we will be retrieving posts using the paging and sorting abstraction, we need to extend PagingAndSortingRepository for &lt;em&gt;PostRepository&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Note how both CrudRepository and PagingAndSortingRepository take as type arguments the domain class to manage and the type of ID of the domain class.&lt;/p&gt;
&lt;p&gt;Another thing to note is that we &lt;a href="https://stackoverflow.com/a/51918761/10218970" rel="nofollow"&gt;don't need to annotate&lt;/a&gt; either repository interfaces with &lt;em&gt;@Repository&lt;/em&gt; or &lt;em&gt;@Component&lt;/em&gt;. This is because CrudRepository and PagingAndSorting interfaces are annotated with &lt;em&gt;@NoRepositoryBean&lt;/em&gt;, making them &lt;em&gt;intermediate interfaces&lt;/em&gt;. Intermediate interfaces are not picked up by the Spring container and as such are not instantiated as beans.&lt;/p&gt;
&lt;p&gt;However, any derivatives of such interfaces that are not annotated with @NoRepositoryBean -- in our case, AuthorRepository and PostRepository -- are automatically instantiated by the Spring container.&lt;/p&gt;
&lt;h3&gt;Defining controllers&lt;/h3&gt;
&lt;p&gt;Now onto defining controllers for the blog. These will handle requests to our web application and are responsible for delivering the appropriate view to the client.&lt;/p&gt;
&lt;p&gt;We need to define two classes -- RootController and PostController -- each of which will handle respective requests.&lt;/p&gt;
&lt;h4&gt;RootController&lt;/h4&gt;
&lt;p&gt;RootController will be mapped to handle &lt;em&gt;GET /&lt;/em&gt; requests.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;As we see, all GET requests to the &lt;em&gt;/&lt;/em&gt; route will be redirected to the &lt;em&gt;/posts&lt;/em&gt; route.&lt;/p&gt;
&lt;h4&gt;PostController&lt;/h4&gt;
&lt;p&gt;PostController will be mapped to handle &lt;em&gt;GET /posts/*&lt;/em&gt; requests.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;At this point, there are no handler methods defined in the class. We define an instance variable named PAGINATIONSIZE that indicates the size of pagination -- i.e., the number of posts to render at once.&lt;/p&gt;
&lt;p&gt;Then, we inject an implementation of PostRepository.&lt;/p&gt;
&lt;p&gt;We will define two additional methods that handle requests made to &lt;em&gt;GET /posts&lt;/em&gt; and &lt;em&gt;GET /posts/{id}&lt;/em&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;The &lt;em&gt;getPaginatedPosts&lt;/em&gt; method takes three parameters -- the requested page, size of each page, and the model to add attributes to.&lt;/p&gt;
&lt;p&gt;We obtain an instance of &lt;em&gt;PageRequest&lt;/em&gt; using three arguments -- page, size, and the order of posts.&lt;/p&gt;
&lt;p&gt;The order of posts should be in decreasing order of their ID since larger the ID, more recent the post was authored. This is because when we retrieve our posts, we need them in the order of their decreasing recency.&lt;/p&gt;
&lt;p&gt;Then, since PostRepository extends the PagingAndSortingRepository, its &lt;em&gt;findAll&lt;/em&gt; method can take the said instance of PageRequest, which in turn returns a &lt;em&gt;Page&lt;/em&gt; of posts. This instance of type Page can be converted to a List type, and that is exactly what we did.&lt;/p&gt;
&lt;p&gt;Then, using the total number of posts available, we compute the total number of pages to be made available to the client.&lt;/p&gt;
&lt;p&gt;Finally, we add these values as attributes to our &lt;em&gt;Model&lt;/em&gt; parameter.&lt;/p&gt;
&lt;p&gt;Next, we define a &lt;em&gt;getPostById&lt;/em&gt; method.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;The getPostById method takes two parameters -- ID of the post to retrieve and the model to add attributes to.&lt;/p&gt;
&lt;p&gt;Using the findById method of PostRepository, we retrieve an &lt;em&gt;Optional&lt;/em&gt; instance of type Post. This provides a sense of &lt;em&gt;null-safety&lt;/em&gt; as we reduce our chances of running into &lt;em&gt;Null Pointer Exception&lt;/em&gt;s.&lt;/p&gt;
&lt;p&gt;Only if the Optional instance contains a non-null value (i.e., if a post of that ID exists), do we add the post as a model attribute.&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;p&gt;This is it for part 2. Stay tuned for more parts where we continue building our Markdown blog.&lt;/p&gt;
&lt;p&gt;As always, all of the code up to this point has been pushed to the GitHub &lt;a href="https://github.com/roshanadh/markdown-blog/tree/part-2"&gt;repository&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>thymeleaf</category>
      <category>markdown</category>
    </item>
    <item>
      <title>Build a Markdown-based Blog with Spring Boot - Part 1</title>
      <dc:creator>Roshan Adhikari</dc:creator>
      <pubDate>Wed, 19 May 2021 16:09:47 +0000</pubDate>
      <link>https://dev.to/roshanadh/build-a-markdown-based-blog-with-spring-boot-part-1-c2p</link>
      <guid>https://dev.to/roshanadh/build-a-markdown-based-blog-with-spring-boot-part-1-c2p</guid>
      <description>&lt;p&gt;In this piece, we will be building a personal blog containing articles written in Markdown.&lt;/p&gt;
&lt;p&gt;We will use Spring Boot to develop the project and few other tools and libraries. We will push our project to a GitHub repository and use Heroku's Automatic Deployment feature to publish posts to our blog.&lt;/p&gt;
&lt;p&gt;Additionally, we will use the RemoteMySQL service to host our remote MySQL database. To communicate with the database, we will need MySQL connector for Java and Spring Data JPA.&lt;/p&gt;
&lt;p&gt;For rendering our view, we will use Thymeleaf.&lt;/p&gt;
&lt;p&gt;This article is one part of a series of posts that I intend to publish on this topic. &lt;/p&gt;
&lt;p&gt;For the entirety of this tutorial, I will use IntelliJ IDEA Community Edition as the IDE.&lt;/p&gt;
&lt;p&gt;There may be some IntelliJ-specific shortcuts and hotkeys here and there, but you can follow along using your IDE of choice.&lt;/p&gt;
&lt;p&gt;Now let's get going!&lt;/p&gt;

&lt;h3&gt;Generating Project&lt;/h3&gt;
&lt;p&gt;Just like how every fun Spring Boot adventure begins, go to &lt;a href="http://start.spring.io" rel="noopener noreferrer"&gt;start.spring.io&lt;/a&gt; (Spring Initializr) and configure our project.&lt;/p&gt;
&lt;p&gt;Select the &lt;span&gt;&lt;span&gt;&lt;em&gt;Maven Project&lt;/em&gt;&lt;/span&gt;&lt;/span&gt; option and &lt;em&gt;Java&lt;/em&gt; as the language.&lt;/p&gt;
&lt;p&gt;Choose a non-snapshot version of Spring Boot (I chose 2.4.5). &lt;/p&gt;
&lt;p&gt;Then, fill up your Project Metadata -- including the Group, Artifact, Name, Description, and Package name.&lt;/p&gt;
&lt;p&gt;We will be using Jar packaging, so select &lt;em&gt;Jar&lt;/em&gt;. Then, choose &lt;em&gt;11&lt;/em&gt; as the Java version.&lt;/p&gt;
&lt;p&gt;For dependencies, we will need the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spring Data JPA&lt;/li&gt;
&lt;li&gt;MySQL Driver&lt;/li&gt;
&lt;li&gt;Thymeleaf&lt;/li&gt;
&lt;li&gt;Spring Web&lt;/li&gt;
&lt;li&gt;Lombok&lt;/li&gt;
&lt;/ul&gt;Finally, generate the project structure by clicking the &lt;em&gt;Generate&lt;/em&gt; button.&lt;p&gt;Extract the resulting &lt;em&gt;.zip&lt;/em&gt; file and you're ready to go!&lt;/p&gt;
&lt;br&gt;&lt;a href="https://1.bp.blogspot.com/-rLWfwW3sIU4/YKUVYp4PHII/AAAAAAAAG6U/zICDtMPsDVAH6Wkoj-xRy7TkJKnT9YTggCLcBGAsYHQ/s1725/spring-init.jpg" rel="noopener noreferrer"&gt;&lt;img alt="Configuring project with start.spring.io" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2F1.bp.blogspot.com%2F-rLWfwW3sIU4%2FYKUVYp4PHII%2FAAAAAAAAG6U%2FzICDtMPsDVAH6Wkoj-xRy7TkJKnT9YTggCLcBGAsYHQ%2Fs16000%2Fspring-init.jpg" title="Configuring project with start.spring.io"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;&lt;h3&gt;Opening the project&lt;/h3&gt;
&lt;p&gt;Once the .zip file has been extracted, the project can be imported into the IDE.&lt;/p&gt;
&lt;p&gt;Using IntelliJ IDEA, you can open the project by pointing IntelliJ to the root folder of the project (one that contains the &lt;em&gt;pom.xml&lt;/em&gt; file as an immediate child).&lt;/p&gt;
&lt;a href="https://1.bp.blogspot.com/-TFEtQw9LX0o/YKUalTzeJ_I/AAAAAAAAG6c/ccv21dZfAIY2ppZx_YkEbKArd70aSE3kACLcBGAsYHQ/s616/intellij-open-project.jpg" rel="noopener noreferrer"&gt;&lt;img alt="Open project with IntelliJ IDEA" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2F1.bp.blogspot.com%2F-TFEtQw9LX0o%2FYKUalTzeJ_I%2FAAAAAAAAG6c%2Fccv21dZfAIY2ppZx_YkEbKArd70aSE3kACLcBGAsYHQ%2Fs16000%2Fintellij-open-project.jpg" title="Open project with IntelliJ IDEA"&gt;&lt;/a&gt;&lt;br&gt;&lt;p&gt;After you've opened the project, take a look at the directory and file structure generated by Spring Intializr.&lt;/p&gt;
&lt;a href="https://1.bp.blogspot.com/-INBthZF8SRU/YKUbLeS45pI/AAAAAAAAG6k/554DO-d7M4EEC3Qp4PUqw33M6TmMf88vwCLcBGAsYHQ/s1919/opened-project.png" rel="noopener noreferrer"&gt;&lt;img alt="Project directory structure" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2F1.bp.blogspot.com%2F-INBthZF8SRU%2FYKUbLeS45pI%2FAAAAAAAAG6k%2F554DO-d7M4EEC3Qp4PUqw33M6TmMf88vwCLcBGAsYHQ%2Fs16000%2Fopened-project.png" title="Project directory structure"&gt;&lt;/a&gt;&lt;br&gt;&lt;p&gt;The pom.xml file is crucial for a Maven project.&lt;/p&gt;
&lt;p&gt;It is filled with the dependencies that we selected from our little configuration session with Spring Initialzr.&lt;/p&gt;
&lt;p&gt;Since Spring Boot is an opinionated framework, within its starter dependencies are a collection of other dependencies that have been curated by Spring Boot itself.&lt;/p&gt;

&lt;h3&gt;Defining entities&lt;/h3&gt;
&lt;p&gt;Our blog needs two entities -- posts and authors.&lt;/p&gt;
&lt;p&gt;The author entity describes an author of a post with their name, email, and website.&lt;/p&gt;
&lt;p&gt;The post entity describes a post, with its title, content, timestamp of creation, synopsis (first 150 characters of the post), and the ID of the author.&lt;/p&gt;
&lt;p&gt;Both entities are identified by a unique, auto-generating ID.&lt;/p&gt;

&lt;a href="https://1.bp.blogspot.com/-XAzFVjGF-B8/YKUflQfmhDI/AAAAAAAAG6s/c509lX3vHY4g1BW8qdOc6To32q9XL5guQCLcBGAsYHQ/s964/erd.png" rel="noopener noreferrer"&gt;&lt;img alt="ER diagram of entities" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2F1.bp.blogspot.com%2F-XAzFVjGF-B8%2FYKUflQfmhDI%2FAAAAAAAAG6s%2Fc509lX3vHY4g1BW8qdOc6To32q9XL5guQCLcBGAsYHQ%2Fs16000%2Ferd.png" title="ER diagram of entities"&gt;&lt;/a&gt;&lt;br&gt;&lt;h3&gt;Defining POJOs&lt;/h3&gt;
&lt;p&gt;The Plain Old Java Object (POJO) definitions for the entities are as described below.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We use &lt;em&gt;JPA&lt;/em&gt; annotations to specify a one-to-many relationship between authors and posts.&lt;/p&gt;
&lt;p&gt;Furthermore, to map Java's &lt;em&gt;LocalDateTime&lt;/em&gt; typed attribtue to MySQL's &lt;em&gt;datetime&lt;/em&gt; typed column, we need to convert between the two types (from LocalDateTime to &lt;em&gt;TimeStamp&lt;/em&gt; and vice-versa).&lt;/p&gt;
&lt;p&gt;For that, we define a new &lt;em&gt;LocalDateTimeConverter&lt;/em&gt; class as following.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;h3&gt;&lt;br&gt;&lt;/h3&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;p&gt;I will end things at this much for now. We will continue the project from the next part of this series.&lt;/p&gt;
&lt;p&gt;The project has been pushed to a GitHub repository, and you can find the code &lt;a href="https://github.com/roshanadh/markdown-blog/tree/part-1" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>markdown</category>
      <category>thymeleaf</category>
    </item>
  </channel>
</rss>
