Adding a Little More Functionality to our Spring Boot Application (SPEED ROUND)

Alright people, so we’re almost getting ready to begin developing a basic iOS application that will aim to consume the APIs we’ve been working on. Before doing so, I wanted to add a little more functionality to the (Spring Boot) backend that we have developed so far.  This part of the tutorial I’ll go through pretty quickly as we already have a basic idea of how to develop an API.  If you haven’t followed any of the other tutorials, not to worry, I’ve put the updated source code on github which can be found here.

If you’ve completely forgotten some of the steps we’ve taken to setting up our first API, here is the general flow that I like to follow

  1. If I need to create a new table in the database, I’ll start by creating my Java object that will be mapped into my relational database, ex: our Game.java class.
  2. If necessary I’ll create (or add to) my repository which represents the Java object that is mapped to the database, ex: our GameRepository.java interface.  This is where I would start writing my @Query methods.
  3. I will create (or add to) my existing @Service class that is used to add additional logic to the repository interface, ex: our GameService.java class.
  4. If I’m feeling super eager, I’ll write a unit test to check that my service methods are performing as I expect.
  5. And finally, I will create or add to an existing @RestController class so that my new service methods are accessible through an API, ex: our GameController.java class.

With that in mind, these are the steps that I will follow through in this tutorial.  If you’re just here for the source code, I’ll add it to the end of this post.

Step 1: Creating A new Table

I’m going to create a new table that will allow users to create comments on a particular game if they wish.  To do so, I’ve set up the following Java object inside of our entity package…

package tutorial.springsetup.entity;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Table(name = "comment")
@Entity
public class Comment {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    
    @ManyToOne // One game will have many comments
    private Game game;

    // Authors name
    @Column(name = "author")
    private String author;

    // Comment text
    @Column(name = "text")
    private String text;
    
    // Date the comment was created
    @Column(name = "created_date", nullable = false)
    private Date createdDate;

    public Comment(){
        createdDate = new Date(); // set the date to today's date when create
    }

    public Long getId() {
        return id;
    }
    
    public void setId(Long id) {
        this.id = id;
    }

    public Game getGame() {
        return game;
    }
    
    public void setGame(Game game) {
        this.game = game;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public Date getCreatedDate() {
        return createdDate;
    }

    public void setCreatedDate(Date createdDate) {
        this.createdDate = createdDate;
    }  
}

Great, so that is what our basic comment table will look like.  Once you run your application this table will be created and you’ll be able to view it in your local MySQL database.

Step 2: Creating the CommentRepository interface

Now that we have our new table, the next step is to create our repository interface so that we can write some basic queries.  The first query I would like to add will allow for users to be able to find all comments created on a particular game.  I’m going to create a brand new repository called CommentRepository inside of our repository package.  It’s going to look like this…

package tutorial.springsetup.repository;

import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import tutorial.springsetup.entity.Comment;

public interface CommentRepository extends JpaRepository<Comment, Long>{

    @Query("SELECT c FROM Comment c WHERE c.game.id = ?1")
    public List<Comment> findCommentsByGameId(Long gameId);

}

As you can see, I’ve extended the JpaRepository interface so that we can take advantage of some of the provided operations.  This is similar to what we have done in our GameRepository interface.

Step 3: Creating our GameService class

Now that we have our CommentRepository setup, we can begin setting up our CommentService.  Not only do I want to provide some additional logic to the findCommentsByGameId(Long gameIdwe had just created, but I also want to add in a new method that will allow for users to CREATE new comments (this is where we’ll take advantage of JpaRepository).  I’ve made a new class within our service package and named it CommentService which looks as follows…

package tutorial.springsetup.service;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tutorial.springsetup.entity.Comment;
import tutorial.springsetup.repository.CommentRepository;

@Service
public class CommentService {

    @Autowired
    private CommentRepository commentRepo;

    @Autowired
    private GameRepository gameRepo;

    public List<Comment> findCommentsByGameId(Long gameId) throws Exception{
        if(gameId == null){
            throw new Exception("Invalid game id.");
        }

        List<Comment> results = commentRepo.findCommentsByGameId(gameId);
        return results;
    }

    public Comment createGameComment(Comment comment, Long gameId) throws Exception{
        if(comment == null || gameId == null){
            throw new Exception("Invalid parameters.");
        }

        Game game = gameRepo.findOne(gameId);
        if(game == null){
            throw new Exception("Cannot find game with id=" + gameId);
        }
     
        comment.setGame(game); // Find game by provided gameId and set it
   
        Comment created = commentRepo.save(comment); // "save" is provided by the extended JpaRepository interface
        return created;
    }
}

Step 4: Writing Unit Tests

To avoid boring you to death, I’ll skip over going through the unit testing portion.  If you’re really interested they’ll be available to look at in the source code inside of the CommentServiceTests.java class.

Step 5: Creating The CommentController class

Now that we have added some additional functionality to our CommentService class, we can finally start creating a couple of new API’s. We will want to develop a GET request that will allow for client side users to read the comments that were made on a particular game, and we also want to develop a POST request that will allow for users to create new comments.  I’ve created a new class within our controller package and named it CommentController which looks as follows…

package tutorial.springsetup.controller;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import tutorial.springsetup.entity.Comment;
import tutorial.springsetup.service.CommentService;

@RestController
public class CommentController {
   
    @Autowired
    private CommentService commentService;

    @RequestMapping(value = "/api/games/{gameId}/comments", method = RequestMethod.GET)
    public List<Comment> findCommentsByGameId(@PathVariable("gameId") Long gameId) throws Exception{
        List<Comment> gameComments = commentService.findCommentsByGameId(gameId);
        return gameComments;
    }

    @RequestMapping(value = "/api/games/{gameId}/comments", method = RequestMethod.POST)
        public Comment createNewGameComment(@PathVariable("gameId") Long gameId, @RequestBody final Comment comment) throws Exception{
        Comment created = commentService.createGameComment(comment, gameId);
        return created;
    }
}

Great, so now that we’ve added in our two new APIs we can run our application and test them.  Once again, I’ll be using Restlet Client and after calling each API I am able to retrieve the following responses…

createNewGameComment called with http://localhost:8080/api/games/1/comments (we’ll be creating a comment on a game with id = 1)

Screen Shot 2017-10-14 at 10.59.00 AM

Screen Shot 2017-10-14 at 10.59.19 AM

findCommentsByGameId called with http://localhost:8080/api/games/1/comments

Screen Shot 2017-10-14 at 11.00.08 AM

Super!  We’ve sped through adding in some brand new functionality to our app.  If you’re feeling a bit lost, check out some of the previous tutorials or create a comment below.  I’ve also added the updated source code from this tutorial to github and it can be found here.

Have any questions, comments, suggestions?  Having issues getting your project to this stage?  Leave a comment and I’ll be happy to get back to you. 

Querying a Database From Your Spring Boot Application

Prefer to watch a video? 

Otherwise keep on scrolling!


Last tutorial we managed to configure our Hibernate and database properties within our application to allow for us to create tables using Java objects annotated with @Entity and @Table.  In this tutorial we will be learning how to create simple queries within our application that we can run against our database.

Setting up the Game Repository

In our last tutorial we created a table using the Game.java class.  In order to run queries against our game table, we need to create a repository class.  For every entity class in Java, you will need to create a repository class which will allow for you to perform simple queries.

Remember in the last tutorial how we created a package and named it entity?  We’re going to do something similar here, but instead we’re going to call it repository.  This package will be responsible for holding all of your repository classes.

  • Right click the tutorial.springsetup package
  • Select New > Other and type “package” to filter
  • Name your package “repository” and hit Finish

Your project directory will now look something like this…

Screen Shot 2017-10-08 at 10.09.56 AM.png

With your new package selected, once again right click it and create a new interface called GameRepository.  Once this interface has been created (and it is inside of your repository package), add in the following code…

import org.springframework.data.jpa.repository.JpaRepository;
import tutorial.springsetup.entity.Game;

public interface GameRepository extends JpaRepository<Game, Long>{

}

We’re going to extend JpaRepository so that we can make use of the generic CRUD operations that are provided through this interface.  Might as well take advantage of existing operations and if you’re interested, all of them can be found here.

So we have our repository class set up, now we can start writing some queries.  The first query that I want to write will perform a search for game by it’s title.  To do so, I will use the following code…

@Query("SELECT g FROM Game g WHERE lower(g.title) LIKE lower(?1)")
public List<Game> findGamesByTitle(String title);

What is going on here?  The first line which is annotated with @Query is responsible for the query that is going to be executed when this method is called.  This might look a little different from your typical SQL as we are using our Java Game object within the statement.  Basically, we are going to select every game where the lowercase title of the game is LIKE the String title parameter we are passing through in the second line of code.

I guess if we break it down we can kind of think of it like this

  • findGamesByTitle(“mario”);
  • @Query(“SELECT g FROM Game g WHERE lower(g.title) LIKE lower(“mario”))
  • return a List of Game objects that were found when performing the query above

Testing our First Query

Awesome, so we have written our first query that will attempt to find games by their title.  How do we know this is working?  Let’s write a quick unit test to check that we have it set up correctly and so that you can get a better idea of how to call these methods.

  • Right click on the src/test/java package
  • Select New > Other and create a new class.  I’ve named mine GameServiceTests

This class will be used to test all of your Game related functionality (sure it will).

Now your project directory might look as follows…

Screen Shot 2017-10-08 at 10.47.40 AM.png

Open the GameServiceTests class you have just created and type in the following…

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import tutorial.springsetup.App;
import tutorial.springsetup.entity.Game;
import tutorial.springsetup.repository.GameRepository;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class) // App.class is the name of my main application class, if yours is different you might have to change this.
public class GameServiceTests {

    @Autowired
    private GameRepository gameRepo; // By autowiring in our game repository, we will have access to all of it's public methods

    @Test
    public void testFindGameByTitle(){
        List<Game> results = gameRepo.findGamesByTitle("%mario%"); // We want to find all games with a title like "mario"
        Assert.assertEquals(2, results.size());
    }
}

This is our first unit test which aims to test the query we had created in the previous step.  We want to see if we can find all games with a title like “mario” and check that we are getting the expected results (in this case, we are expecting to find two games).  If we run this test now, it’s going to fail because we have not yet put any data into our database.  Because we have yet to create any methods that will INSERT rows into our game table, for demonstration purposes we’re going to quickly add a few rows into our table from our Terminal window.

  • Open up a Terminal window
  • mysql -u root -p and enter your password.  This should allow you to use the MySQL command line tool
  • USE nintendo; so that all of our SQL statements will run against the nintendo database

Now we can start inserting a few rows for testing purposes.  Copy and paste the following statements below into your terminal window so that we have some data to test with.

INSERT INTO game(id, title, description) VALUES(1, 'Super Mario Bros', 'Platform Video Game');
INSERT INTO game(id, title, description) VALUES(2, 'Super Mario Bros 2', 'Platform Video Game');
INSERT INTO game(id, title, description) VALUES(3, 'Donkey Kong Country', 'Platform Video Game');

Your window might look something like…

Screen Shot 2017-10-08 at 11.06.11 AM.png

So now we have three rows of data in our game table, let’s run our unit test we wrote earlier to see if our query is working as expected.

  • Right click on GameServiceTests.java
  • Select Run As > JUnit Test

This will run your application and execute the unit test which will appear in the left panel.  If it works as expected, you should see the following

Screen Shot 2017-10-08 at 11.09.54 AM.png

Green is good.  This tell us that we have found two games in our table that have titles LIKE “mario” which is exactly the output we expect.

What we have covered so far

Cool, so if you have followed from the beginning we have managed to set up our database, create our Spring Boot and Hibernate environment, configure our project to communicate with our database, write queries within our project that will run against our database and test that they are working as expected.  I hope you’ve been able to follow along without too many issues but let me know in the comments below if you’re totally lost.

In the next tutorial I will show you how to create our Service layer where we will be able to create new game entries (INSERT into) from our application as well as update/modify existing data.  This is where we can take advantage of the JpaRepository we had extended in our GameRepository class.

Oh yeah, and if you’d prefer to just import the source code you can find the updated files here.

Have any questions, comments, suggestions?  Having issues getting your project to this stage?  Leave a comment and I’ll be happy to get back to you.