Spring Boot with Spring MVC and JPA: Pre-existing App Get Data

March 2016

This article shows how to run a Spring Boot app with and JPA (Java Persistent APIs) using Spring Data JPA which connects to the PostgreSQL database populated by Heroku Connect AddOn.

../../_images/heroku-connect-spring-boot-jpa-flow.png

Figure 1 : Heroku-Connect Spring Boot, Spring MVC and Spring Data JPA, Data flow

Figure 1 shows the how HerokuConnect Add-On interacts with Heroku PostgreSQL and Force.com behind the scenes. These steps are independent of the application being deployed on Heroku.

Note

Make sure you have Java 1.8, Maven 3.3.3 installed and Heroku Toolbelt.

We will be using a Spring Boot JPA Sample app available at heroku connect spring boot jpa.

This app has three rest endpoints

  • @app.route('/') shows the home page of the App

  • @app.route('/employees') shows the list of Employees stored in the App

  • @app.route('/contacts') which fetches list of contacts from Postgres table salesforce.contact

    This table is propulates from salesforce and not created by JPA

Clone the Source Code

Clone the source code using git clone and change into the cloned project directory heroku-connect-spring-boot

$ git clone https://github.com/rajdeepd/heroku-connect-spring-boot-jpa
$ cd heroku-connect-spring-boot-jpa

Code

This is a basic Spring-boot app which uses Spring Data JPA to connect to the PostgreSQL database and return the list of contacts. It uses Thymeleaf to render the HTML template

Structure of the App is Listed below

|-- README.md
|-- src
|   `-- main
|       |-- java
|       |   `-- com
|       |       `-- example
|       |           |-- dao
|       |           |   |-- ContactRepository.java
|       |           |   `-- EmployeeRepository.java
|       |           |-- HerokuConnectApplication.java
|       |           `-- model
|       |               |-- Contact.java
|       |               `-- Employee.java
|       |-- resources
|       |   |-- applicationContext.xml
|       |   |-- META-INF
|       |   |   `-- persistence.xml
|       |   `-- templates
|       |       |-- contact.html
|       |       |-- employee.html
|       |       `-- home.html
|       `-- webapp
|           `-- assets
|               |-- css
|               |   |-- bootstrap.css
|               |   `-- style.css
|               `-- js
|                   `-- bootstrap.js

About the Application

The Application is based on Spring MVC Architecture.

The Spring Web model-view-controller (MVC) framework uses DispatcherServlet that dispatches requests to handlers. It has configurable handler mappings, view resolution, locale and theme resolution. The default handler is based on the @Controller and @RequestMapping annotations, offering a wide range of handling methods.

Controllers provide access to the application behavior defined through a service interface. Controllers interpret user input and transform it into a model that is represented to the user by the view (Thymeleaf in our case). Spring implements a controller in an abstract way, which enables developers to create a wide variety of controllers.

Since Spring 2.5 annotation-based programming model for MVC controllers that uses annotations @RequestMapping, @RequestParam, @ModelAttribute has been introduced.
Controllers implemented using this style do not have to extend specific base classes or implement specific interfaces

In our example we are using @Controller annotation to define the Controller and @RequestMapping to map rest endpoints to implementation methods.

Spring Boot developers always annotate the main class with @Configuration, @EnableAutoConfiguration and @ComponentScan. These annotations are frequently used together Spring Boot provides a convenient @SpringBootApplication alternative.

The @SpringBootApplication annotation is equivalent to using @Configuration, @EnableAutoConfiguration and @ComponentScan with their default attributes. @SpringBootApplication is the annotation we are using in our controller listed below.

Model

We have two Model classes annotated by JPA annotation @Entity. It has four member variables

  • id
  • sfid
  • firstName
  • lastName
  • email
  • createdDate

Notice how the entity name is mapped to salesforce.contact table.

@Entity
@Table(name = "contact", schema="salesforce")
public class Contact {

    @Id
    @GeneratedValue
    private Integer id;

    ....

}

Crud Repository

We are using @Repository annotation to identify the CrudRepository. The primary interface in Spring Data repository abstraction is Repository. It takes the domain class to manage as well as the id type of the domain class as type arguments. This interface acts as a marker interface to capture the types to work with, to help discover interfaces that extend this interface. The CrudRepository provides CRUD functionality for the entity class being managed.

In our implementation, we are only using Read functionality from CRUD

@Repository
public interface ContactRepository extends CrudRepository<Contact, Long> {
    public List<Contact> findById(Integer id);
    public List<Contact> findAll();
}

Controller

Main Controller of the App is HerokuConnectApplication class which provides an implementation of two rest Endpoints.

@Controller
@SpringBootApplication
public class HerokuConnectApplication {

}

Following two @RequestMappings have been implemented in the Controller HerokuConnectApplication

@RequestMapping("/")
public String home(Model model) {
    ...
}

@RequestMapping("/contacts")
public String contacts(Model model) {
    ....
}

In the Controller, we need to Autowire the ContactRepository and use it to query the JPA Objects

@Controller
@SpringBootApplication
public class HerokuConnectApplication {
        @Autowired
        ContactRepository contactRepository;

        @RequestMapping("/")
    public String home(Model model) {
        ...
    }

    @RequestMapping("/contacts")
    public String contacts(Model model) {
        ....
    }
}

Get Contacts Implementation

  1. Get the ContactRepository

    ContactRepository repo = getContactRepository();
    
  2. If Contact Repository is not null call findAll() on it to get List of contacts.

  3. Add the list of contacts to model as attribute with key "contacts"

    if(repo != null) {
             contacts = (List<Contact>) repo.findAll();
             model.addAttribute("contacts", contacts);
        }
    
  4. Return from the method by specifying the Thymeleaf template “contact”

    model.addAttribute("contacts", contacts);
    return "contact";
    

Complete code for public String contacts(Model model) method

@RequestMapping("/contacts")
public String contacts(Model model) {
    try {
        ContactRepository repo = getContactRepository();
        List<Contact> contacts = null;

        if(repo != null) {
            contacts = (List<Contact>) repo.findAll();
            model.addAttribute("contacts", contacts);
        }
        return "contact";
    } catch (Exception e) {
        model.addAttribute("contacts", new LinkedList());
        e.printStackTrace();
    }
    return "contact";
}

Complete code Listing for HerokuConnectApplication class

Employees

Similar to Contacts we also have Employees being stored and retrieved the database. The only difference being Employee is a table only in PostgreSQL and not linked a Salesforce SObject.

View implementation with Thymeleaf Templates

Thymeleaf is a template engine capable of processing and generating HTML, XML, etc. It can work both in web and non-web environments. It is better suited for serving the view layer of web applications. It provides an optional integration with Spring MVC so that it can be used as a complete substitute of JSP.

We are using Thymeleaf templates for rendering the Contacts sent by the controller.

Thymeleaf template contact.html below uses variable set in Model to retrieve and display list of contacts.

<table>
    <th><td>Id</td><td>SFID</td><td>First</td><td>Last</td><td>Email</td></th>
    <tr th:each="contact : ${contacts}">
        <td></td>
        <td th:text="${contact.id}" ></td>
        <td th:text="${contact.sfid}" ></td>
        <td th:text="${contact.first}" ></td>
        <td th:text="${contact.last}" ></td>
        <td th:text="${contact.email}" ></td>
    </tr>
    </table>

Compile the App Locally

  1. Execure the following commands to compile and build the jar file

    $ mvn compile
    $ mvn package
    
  2. Run the app using the following command locally

    $ mvn spring-boot:run
    

    Your app should now be running on localhost:8080

Procfile

There is already a Procfile, which tells the Heroku what kind of Dyno is required and the source for the application.

web: java -Dserver.port=$PORT -jar  target/heroku-connect-spring-boot-0.0.1-SNAPSHOT.jar

Deploying to Heroku

$ heroku create
$ git push heroku master

The App is deployed but still needs PostgreSQL to be configured along with Heroku Connect.

Add PostgreSQL Add-On

Add Postgress Add-On as shown below. This step is optional and is required if heroku-postgresql addon is not already configured by heroku for your app.

$ heroku addons:create heroku-postgresql:hobby-dev

Add Heroku Connect Add-On

Configure Heroku Connect Add-On. Command below configures Herok-Connect Add-On to the application.

$ heroku addons:create herokuconnect

Configure Heroku Connect Add-On

  1. Setup Connection
../../_images/setup-connection3.png
  1. Enter Schema Name: This is the schema name underwhich database will be created.
../../_images/enter-schemaname3.png
  1. Trigger OAuth
../../_images/trigger-oauth3.png
  1. Enter Salesforce.com developer account credentials
../../_images/oauth3.png
  1. Create Mappings
../../_images/create-mappings3.png
  1. Create Mappings Contacts : Choose the fields in Salesforce Schema which need to be mapped to Postgres Database in the application.
../../_images/create-mapping-contacts3.png
  1. Explore Contacts in the Dashboard

Open the Remote App in Heroku

$ heroku open

The App opens up in the default route / with the following view

../../_images/heroku-connect-spring-boot-remote-home1.png

Show Contacts

Browse to URL http://{your-app-name}.herokuapp.com/contacts to see the list of contact names.

../../_images/heroku-connect-spring-boot-remote-contacts1.png

Summary

In this tutorial, we learned how to configure a Pre-existing Spring Boot Application to work with Heroku Connect. We used Spring Data JPA to talk to the PostgreSQL database deployed on Heroku.