Spring Boot backend refactor to use spring data rest

I’ve been on a bit of a journey of discovery within the spring framework. Half my problem is working out why you’d use something, and relating it back to what I already know and have done in the past.

I’ve done a tutorial using spring data rest, and it seems really powerful. However, there’s little opportunity to add an service layers for transactional database updates. There’s also no Controllers, like I’ve had in other tutorials. I’m finding this a bit odd, as working in Enterprise Java environments in the past, there was a lot of business logic before we got anywhere near the database.

However, I’m embracing this simplicity for now so that I can concentrate on an angular app that consumes the data. Then I’ll be happy that I have something working and can apply all the other necessary things to… like security for starters!

Here’s the code so far.

Main application and properties file:

//BTJLApplication.java
package com.backtojavaland;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@SpringBootApplication
public class BTJLApplication {
		
	public static void main(String[] args) {
		SpringApplication.run(BTJLApplication.class, args);
	}

}
#application.properties
spring.datasource.url=jdbc:h2:mem:testdb
spring.h2.console.enabled=true
spring.h2.console.path=/h2
server.servlet.path=/api

The entities and the repositories for them – User and Article:

package com.backtojavaland.user;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import lombok.Getter;
import lombok.Setter;

@Entity
@Setter @Getter
public class User {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long userId;
	private String firstname;
	private String surname;
	
	public User() {}
	public User(String firstname, String surname) {
		this.firstname = firstname;
		this.surname = surname;
	}	
}
package com.backtojavaland.user;

import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;

@RepositoryRestResource(collectionResourceRel = "user", path="user")
public interface UserRepository extends PagingAndSortingRepository<User, Long>{}
package com.backtojavaland.article;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import lombok.Getter;
import lombok.Setter;

@Entity
@Setter @Getter
public class Article {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private int articleId;
	private String title;
	private String summary;

	public Article() {}
	public Article(String title, String summary) {
		this.title = title;
		this.summary = summary;
	}
}
package com.backtojavaland.article;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;

@RepositoryRestResource(collectionResourceRel = "article", path="article")
public interface ArticleRepository extends JpaRepository<Article, Integer> {}

Under src/main/resources I have a data.sql file that gets loaded into a h2 in-memory database. I took the articles from the bbc science and nature rss feed for examples:

INSERT INTO article (article_id, title, summary) values(1, 'Nasa 2020 robot rover to target Jezero ''lake'' crater', 'America''s next robot rover will be sent to a 50km-wide depression that once had water running through it.');
INSERT INTO article (article_id, title, summary) values(2, 'The physicist called Einstein - but not the one you think', 'There is debate around how much Albert Einstein''s first wife, Mileva, contributed to his discoveries.');
INSERT INTO article (article_id, title, summary) values(3, 'Elon Musk renames his BFR spacecraft Starship', 'The entrepreneur would not reveal why he had renamed the craft, which has still not yet been built.');
INSERT INTO article (article_id, title, summary) values(4,'E. coli outbreak: Romaine lettuce probed in US and Canada', 'At least 50 people in the US and Canada have been infected, health officials say.');
INSERT INTO article (article_id, title, summary) values(5, 'Dead sperm whale found in Indonesia had ingested ''6kg of plastic''', 'The dead sperm whale, which washed ashore in Indonesia, had ingested nearly 6kg of plastic waste.');
INSERT INTO article (article_id, title, summary) values(6, 'Climate change: Report raises new optimism over industry', 'Cutting emissions from heavy industry would generate savings and boost economic growth, commission argues.');
INSERT INTO article (article_id, title, summary) values(7, 'UK industry to make new ''Hotbirds''', 'British industry will build new spacecraft for telecoms operator Eutelsat''s flagship TV distribution network.');
INSERT INTO article (article_id, title, summary) values(8, 'Wombat poop: Scientists reveal mystery behind cube-shaped droppings', 'Scientists discover how the marsupials are the only known species producing cube-shaped faeces.');
INSERT INTO article (article_id, title, summary) values(9, 'Ash dieback: Seed orchards could help species recover sooner', 'A scientist at the John Innes Centre in Norwich says resistant seeds could help beat the fatal disease.');
INSERT INTO article (article_id, title, summary) values(10,'Kilogram gets a new definition', 'Scientists take the massive decision to change the definition of the kilogram.');
INSERT INTO article (article_id, title, summary) values(11,'Greenland ice sheet hides huge ''impact crater''', 'Scientists find evidence that an iron asteroid slammed into the Earth deep inside the Arctic Circle.');
INSERT INTO article (article_id, title, summary) values(12,'Climate change: Worries over CO2 emissions from intensifying wildfires', 'Rising numbers of extreme wildfires could result in a significant increase in CO₂ emissions, scientists have warned.');
INSERT INTO article (article_id, title, summary) values(13,'Exoplanet discovered around neighbouring star', 'Astronomers have discovered a planet around one of the closest stars to our Sun.');
INSERT INTO article (article_id, title, summary) values(14,'Climate change: Report says ''cut lamb and beef''', 'The number of sheep and cattle in the UK should be reduced to help combat climate change, a report says.');
INSERT INTO article (article_id, title, summary) values(15,'''Conservation successes'' bring hope for mountain gorilla', 'Mountain gorilla: Conservation efforts appear to be paying off for large, charismatic animals.');

INSERT INTO user (user_id, firstname, surname) values(1, 'Ada', 'Lovelace');
INSERT INTO user (user_id, firstname, surname) values(2, 'Grace', 'Hopper');
INSERT INTO user (user_id, firstname, surname) values(3, 'Hedy', 'Lamarr');
INSERT INTO user (user_id, firstname, surname) values(4, 'Jean', 'Bartik');
INSERT INTO user (user_id, firstname, surname) values(5, 'Marissa', 'Mayer');
INSERT INTO user (user_id, firstname, surname) values(6, 'Francis', 'Allen');
INSERT INTO user (user_id, firstname, surname) values(7, 'Barbara', 'Liskov');
INSERT INTO user (user_id, firstname, surname) values(8, 'Shafi', 'Goldwasser');
INSERT INTO user (user_id, firstname, surname) values(9, 'Karen', 'Spark Jones');
INSERT INTO user (user_id, firstname, surname) values(10, 'Mirella', 'Lapata');
INSERT INTO user (user_id, firstname, surname) values(11, 'Diane', 'Kelly');
INSERT INTO user (user_id, firstname, surname) values(12, 'Emine', 'Yilmaz');
INSERT INTO user (user_id, firstname, surname) values(13, 'Jaime', 'Teevan');

My Angular app is also set up to send log messages back to the server, so I have a Log class that just displays it on the console:

package com.backtojavaland.log;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class Log {
	@PostMapping("/logs")
	public void getLog(@RequestBody String request) {
		System.out.println(request);
	}
}

My pom.xml file has the following dependencies:

spring-boot-starter-web
spring-boot-starter-test
h2
mysql-connector-java
spring-boot-starter-data-jpa
spring-boot-starter-data-rest
lombok

The mysql connector dependency is used in test. I have a Run Configuration set up with a program argument of –spring.profiles.active=test and an application-test.properties file set up to connect to a mysql database. I haven’t updated the schema of it whilst playing around, so it probably won’t work.

If I run the spring application on http://localhost:8080/api/article I get all the articles, and when I append the id I get the first one. Similarly http://localhost:8080/api/user I get all the users, and I can get a specific user by appending the id: http://localhost:8080/api/user/10.

I haven’t gone into the Angular app changes yet, but here is what it looks like so far with two components, user and article, squished unceremoniously onto the front page 🙂

Angular application accessing the restful web services provided by spring-data-rest.

It’s awesome to think that the front-end app is connecting to my rest service. I’m following the Tour if Heroes example and adding to the app as I go.

The path forward

Great! I’ve found my path forward:

Create my basic news app in Spring Boot, playing with web front-ends (e.g. Angular), and learning the Spring stuff. Using Git on GitHub.

Looking at moving said stuff to AWS in a basic way.

Re-writing my code in Spring Cloud and AWS Lambda in a serverless way.

Moving my stuff to AWS in a basic way.

All the while, using my Safari subscription to read and use as much as I can.

Learning AWS, using a cloud guru, probably stop Safari subscription while doing this.

Maybe take some certifications.

Look at automating, CI/CD usign Jenkins or whatever people use. I must remember that I don’t actually want to be a DevOps person, I’m happy creating things and only need to know enough to get my job done.

I might learn Python to help with this, I already know Perl, so it’s not going to be that different.

Then implementing my code with the knowledge I’ve gained.

Cool… let’s get going!

The decline of the big Application Server

Following on the Spring Boot tutorial, it seems that we have moved away from the large Application Servers that I used to deploy a WAR to. It has Tomcat, Jetty and Undertow. When I worked in the JEE world we used WebLogic, Jetty was just becoming a thing, and I honestly didn’t pay it much attention. But I just read this really interesting article about how things have moved on.

https://blog.fabric8.io/the-decline-of-java-application-servers-when-using-docker-containers-edbe032e1f30

It makes sense, especially in this whole microservices landscape. I’m learning a bit about how to configure aspects of the application server now. I must admit that I didn’t really understand this too much at the time either. I just coded, other people set this up for me to deploy to, but I always felt a bit concerned that I didn’t understand how to properly configure the application servers. In this whole new DevOps world, I guess I’ll have to look at this too.