Configuring Spring boot with JPA, Postgresql and Liquibase

Ok folks, I know that you do not exist… I write this blog so I can keep record of my activities mainly for myself so I want be exhaustive on the topic. I will keep notes mainly for myself but if you feel like needing more elaboration on one of the topics then drop me a comment and I will see what I can do.

So what is Liquibase?

database-independent library for tracking, managing and applying database schema changes

Marvelous! Instead of having to create the DB tables with scripts liquibase is taking care of that and we do nothing apart from creating the db and configuring our app to point to that db.

Maven dependencies:

<dependencies>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
   </dependency>

   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
   </dependency>

   <dependency>
      <groupId>org.liquibase</groupId>
      <artifactId>liquibase-core</artifactId>
   </dependency>

   <dependency>
      <groupId>org.postgresql</groupId>
      <artifactId>postgresql</artifactId>
      <version>42.2.2</version>
   </dependency>

   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
   </dependency>
</dependencies>

Liquibase file configuration

/src/main/resources/db/changelog/db.changelog-master.yaml

databaseChangeLog:
    - includeAll:
        path: db/changelog/changes/

schema

/src/main/resources/db/changelog/changes/v0001.sql

create table admin_user (
  id serial primary key not null,
  username varchar(25) not null,
  password varchar(255) not null,
  authenticationToken varchar(255),
  date timestamp without time zone
);

Be careful with the schema. If you run the application with this schema and you change the v0001.sql enough to change the file hash spring boot fails to fire up the application and then you need to delete the tables of the database. (Or something else I am not aware of at the moment)

In case you want to make a change you create another file ex. v0002.sql with the changes.

The POJO:

package gr.glab.blogpost.entities;

import javax.persistence.*;
import java.util.Date;
import java.util.Objects;

@Entity
public class AdminUser {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    private String username;
    private String password;
    @Temporal(TemporalType.TIMESTAMP)
    private Date latestLoginDate;
    private String authenticationToken;

    public AdminUser(){}

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Date getLatestLogginDate() {
        return latestLoginDate;
    }

    public void setLatestLogginDate(Date latestLogginDate) {
        this.latestLoginDate = latestLogginDate;
    }

    public String getAuthenticationToken() {
        return authenticationToken;
    }

    public void setAuthenticationToken(String authenticationToken) {
        this.authenticationToken = authenticationToken;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        AdminUser user = (AdminUser) o;
        return Objects.equals(id, user.id) &&
                Objects.equals(username, user.username) &&
                Objects.equals(password, user.password) &&
                Objects.equals(latestLoginDate, user.latestLoginDate) &&
                Objects.equals(authenticationToken, user.authenticationToken);
    }

    @Override
    public int hashCode() {

        return Objects.hash(id, username, password, latestLoginDate, authenticationToken);
    }

    @Override
    public String toString() {
        return "User{" +
                "id='" + id + '\'' +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", latestLogginDate='" + latestLoginDate + '\'' +
                ", authenticationToken='" + authenticationToken + '\'' +
                '}';
    }
}

I know… but at the moment I don’t like lombok.

And finally the controller, which will need an AdminUser like json body (or an empty json will do since its not required) and it will always return 200 😛

package gr.glab.almaadmin.controllers;

import gr.glab.almaadmin.entities.AdminUser;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/user")
public class AuthenticatorController {


    @RequestMapping(value = "auth", method = RequestMethod.POST)
    public ResponseEntity<?> authanticateUser(@RequestBody AdminUser user) {
        return new ResponseEntity<>(HttpStatus.OK);
    }
}

The best part is now. Running a psql image on a docker container and make it work with the app…

After we make sure that we have docker installed, we type the following in the command line to run the image:

sudo docker run --name <container-name> \
 -p 5432:5432 \
 -e POSTGRES_DB=<db-name> \
 -e POSTGRES_PASSWORD=<user's password> \
 -d postgres

We can name our container however we want and we need to make sure that the db-name will be the same as the one in the configuration file which is presented bellow.

So in the application properties file we have the following:

/src/main/resources/application.properties

spring.datasource.url=jdbc:postgresql://172.17.0.1:5432/<db_name>
spring.datasource.username=postgres
spring.datasource.password=<type the password here>
spring.datasource.driver-class-name=org.postgresql.Driver

spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL9Dialect
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false

How do we get the ip on the above file? In the console:

$ docker inspect <container-id>

and we are looking for the gateway.

How do we access psql running on the container from the command line?

 $ psql -h localhost -p 5432 -U postgres -d almadb

That was it… Now let’s write some code…

Leave a Reply

Your email address will not be published. Required fields are marked *