React integration with Java Spring Boot Using Thymeleaf

Yash Agrawal
4 min readMar 3, 2020

--

Photo by Filiberto Santillán on Unsplash

We all know the first thing comes up in mind on hearing UI is ReactJs. And for server side Java Spring framework is one of the top choices in the pool of options like Django, Nodejs etc.

Given the 2 said above, Next important thing to decide is whether to do

  • Server side rendering
  • Client side rendering

To know more about the difference and what to use please read here, or any other result which pops up on simple search on google.

Of course we have followed server side rendering here otherwise writing this blog was not helpful.

Initial requirements

  • You have simple Java spring project running.
  • You have a simple view controller written
  • You have already created a react app using this.

Once you have these things working separately, now most of your work is already done.

Before going deep in coding or technical terms few things i want to convey here is that there are many blogs available from different sources which i will mention in the references below. But the thing they lacked is either they override webpack config due to which hot reloading of react didn’t happen, or they were completely giving code away without explanation which didn’t help noob developer in spring (like me). So along with code i will explain the meaning of everything we will do down there.

STEP 1

Some names we will be following ->

  • My spring project name is blurred in below image, lets assume sampleProject
  • Go inside sampleProject/src/main and create-react-app.
  • My frontend root folder(where package.json exists) is named as frontend

We can see i have put my frontend within java src folder itself, but you can differ also by created separate pom(maven) for frontend specifically. I will publish part 2 following that approach.

Step 2

With this react can be run separately on 3000. Now we need to connect our spring to react. For that create a ViewController.java file in src/main/<project-directory>/ViewController.java

Doing this what is happening is invoking https:<server:ip>/ will try to find and return index.html

Step 3

From the above index.html doesn’t exist in pre-configured directory of thymleaf so it will throw error. To enable thymleaf to find our index.html which actually exists in frontend/public/index.html

We need to write spring.thymeleaf.prefix=classpath:/static/ in application.properties file.(veryyy important)

Step 4

Awesome ! now react works perfectly independently and java also finds index to return. But very important step is building both together. Which means putting build files from frontend/build into sampleProject/target/public/ so that spring is able to see everything under it at one place.

Add below build configuration in between the <project></project> of your pom.xml

<build>  <directory>${project.basedir}/target</directory>  <plugins>    <plugin>       <groupId>org.springframework.boot</groupId>       <artifactId>spring-boot-maven-plugin</artifactId>       <configuration>         <addResources>true</addResources>       </configuration>       <executions>         <execution>            <goals>              <goal>repackage</goal>            </goals>         </execution>       </executions>    </plugin>    <plugin>      <artifactId>maven-war-plugin</artifactId>      <configuration>      <packagingExcludes>WEB-INF/lib/*gson*.jar</packagingExcludes>      </configuration>    </plugin>    <plugin>       <groupId>com.github.eirslett</groupId>       <artifactId>frontend-maven-plugin</artifactId>       <version>1.6</version>       <configuration>         <workingDirectory>src/main/frontend</workingDirectory>         <installDirectory>target</installDirectory>       </configuration>       <executions>         <execution>           <id>install node and npm</id>           <goals>             <goal>install-node-and-npm</goal>           </goals>           <configuration>             <nodeVersion>v12.14.1</nodeVersion>             <npmVersion>6.4.1</npmVersion>           </configuration>        </execution>        <execution>           <id>npm install</id>           <goals>             <goal>npm</goal>           </goals>           <configuration>              <arguments>install</arguments>           </configuration>        </execution>        <execution>           <id>npm run build</id>           <goals>              <goal>npm</goal>           </goals>           <configuration>             <arguments>run build</arguments>           </configuration>        </execution>     </executions>    </plugin>    <plugin>       <artifactId>maven-antrun-plugin</artifactId>       <executions>          <execution>             <phase>generate-resources</phase>             <configuration>               <target>           <copy todir="${project.build.directory}/classes/static"> <fileset dir="${project.basedir}/src/main/frontend/build/static" />          </copy>          <copy todir="${project.build.directory}/classes/static">        <fileset dir="${project.basedir}/src/main/frontend/build" />          </copy>             </target>           </configuration>          <goals>             <goal>run</goal>          </goals>        </execution>     </executions>   </plugin> </plugins></build>

Out of so manyy lines in above code very important code is :

<directory>${project.basedir}/target</directory>

where ${project.basedir} resolves to sampleProject

<configuration><workingDirectory>src/main/frontend</workingDirectory><installDirectory>target</installDirectory></configuration>

and where the magic happens. The purpose of copying is once npm run build command is executed all the build chunks needs to placed somewhere spring will look.

<copy todir="${project.build.directory}/classes/static"><fileset dir="${project.basedir}/src/main/frontend/build/static" /></copy><copy todir="${project.build.directory}/classes/static"><fileset dir="${project.basedir}/src/main/frontend/build" />

THATS ALL !!!!

--

--