Benefits of microservices

You start building microservices because they give you a high degree of flexibility and autonomy with your development teams, but you and your
team quickly find that the small, independent nature of microservices makes them easily deployable to the cloud. Once the services are in the cloud, their small size makes it easy to start up large numbers of instances of the same service, and suddenly your applications become more scalable and with forethought, more resilient.

A microservice architecture has the following characteristics:

  • Application logic is broken down into small-grained components with well defined boundaries of responsibility that coordinate to deliver a solution.
  • Each component has a small domain of responsibility and is deployed completely independently of one another. Microservices should have responsibility for a single part of a business domain. Also, a microservice should be reusable across multiple applications.
  • Microservices communicate based on a few basic principles (notice I said principles, not standards) and employ lightweight communication protocols such as HTTP and JSON (JavaScript Object Notation) for exchanging data between the service consumer and service provider.
  • The underlying technical implementation of the service is irrelevant because the applications always communicate with a technology-neutral protocol (JSON is the most common). This means an application built using a microservice application could be built with multiple languages and technologies.
  • Microservices—by their small, independent, and distributed nature—allow organizations to have small development teams with well-defined areas of responsibility. These teams might work toward a single goal such as delivering an application, but each team is responsible only for the services on which they’re working.

What’s a microservice?

Before the concept of microservices evolved, most web-based applications were built using a monolithic architectural style. In a monolithic rchitecture, an application is delivered as a single deployable software artifact. All the UI (user interface), business and database access logic are packaged together into a single application artifact and deployed to an application server.
While an application might be a deployed as a single unit of work, most of the time there will be multiple development teams working on the application. Each development team will have their own discrete pieces of the application they’re responsible for and oftentimes specific customers they’re serving with their functional piece.

For example, customer relations management (CRM) application that involves the coordination of multiple teams including the UI, the customer master, the data warehouse and the mutual funds teams. Below Figure illustrates the basic architecture of this application.

Monolithic applications force multiple development teams to artificially synchronize their delivery because their code needs to be built, tested, and deployed as an entire unit.

The problem here is that as the size and complexity of the monolithic CRM application grew, the communication and coordination costs of the individual teams working on the application didn’t scale. Every time an individual team needed to make a change, the entire application had to be rebuilt, retested and redeployed.

A microservice is a small, loosely coupled, distributed service.
Microservices allow you to take a large application and decompose it into easy-to manage components with narrowly defined responsibilities. Microservices help combat the traditional problems of complexity in a large code base by decomposing the large code base down into small, well-defined pieces. The key concept you need to embrace as you think about microservices is decomposing and unbundling the functionality of your applications so they’re completely independent of one another. If we take the
CRM application we saw in above figure and decompose it into microservices, it might look like what’s shown in below figure.Looking at below figure, you can see that each functional team completely owns their service code and service infrastructure. They can build, deploy, and test independently of each other because their code, source control repository, and the infrastructure (app server and database) are now completely independent of the other parts of the application.

A microservice architecture of CRM application would be decomposed into a set of microservices completely independent of each other, allowing each development team to move at their own pace.

Microservices Example using Spring Cloud Eureka

In this tutorial, we will create a demo microservice using spring boot framework in java.

Tools Required

  • Java 8
  • IntelliJ IDE

We need to create three different applications as below –

  1. Eureka Service–  This Service will register every microservice and then the client microservice will look up the Eureka server to get a dependent microservice to get the job done.This Eureka Server is owned by Netflix and in this, Spring Cloud offers a declarative way to register and invoke services by using Java annotation.
  2. demo-server – This service will return a simple hello message.
  3. demo-client – It is similar to the standalone client service created in Bootiful Development with Spring Boot. It will consume the APIs provided by demo-server through Eureka Service .

1. Eureka Service

We need to create new project in intelliJ editor by selecting below dependencies –

Project Setup
Maven dependencies

You need to do below configurations to create Eureka service which allows other microservices to register with it .

package com.myjavablog;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer
@SpringBootApplication
public class EurekaServiceApplication {

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

}

You need to create application.yml to configure your EurekaService project as register service. Other services will be able to register themselves with EurekaService. So you need to do below configurations –

eureka:
  client:
    registerWithEureka: false
    fetchRegistry: false
    server:
      waitTimeInMsWhenSyncEmpty: 0

Now you can run the application . Once the application is up and running you can go to below URL and see EurekaService is working . You will be able to see below home page of eureka-

As no instances are registered with EurekaService , you can see No instances available message as highlighted above . Now we will create services which will register with our Eureka Server.

2. Demo Server

This is a simple REST based webservice. This will be registering itself with the EurekaService. This service has a simple API which is just returning hello message. Create a project structure as shown below in IntelliJ IDE –

Setup
Maven Dependencies required

Project structure is as shown below –

You need to include Eureka Discovery client dependency in your pom file.

Once the application is up and running , you can see instance of demo-server registered on EurekaService as shown below –

3. Demo Client

Same way as Demo server , we need to create demo client which will consume services provided by demo-server through EurekaService.

demo-client will have autowired RestTemplate to call the services provided by demo-server.

package com.myjavablog.democlient;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("/demo/hello/client")
public class TestController {

    @Autowired
    public RestTemplate restTemplate;

    @GetMapping
    public String test(){
        String url = "http://demo-server/demo/hello/server";
        return restTemplate.getForObject(url, String.class);
    }
}

Also you can see in the above code , we are using String url = “http://demo-server/demo/hello/server”

demo-server is the name specified in the application.yml file of demo-server project . So instead of using http://localhost:8071/demo/hello/server we are using http://demo-server/demo/hello/server .

demo-server is the name registered on Eureka server for demo-server application as shown below –

spring:
  application:
    name: demo-server

server:
  port: 8071

eureka:
  client:
    registerWithEureka: true
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://localhost:8070/eureka/
  instance:
    hostname: localhost

Once the application is up and running , you can see the demo-client is registered on Eureka Server as below –

When you call the APIs from demo client ,it will internally call demo-server APIs through Eureka Service . Eureka server handles all routing and load balancing part. So even if you scale up your services in future by creating multiple instances, you can go on and use the services with the name which is registered on Eureka server.

Github Downlod Link:

Spring Boot profiles

In this article, we will see profiles for spring boot project –

Github Link –

 

What are Profiles?

Every enterprise application has many environments, like:

Dev | Test | Stage | Prod | UAT / Pre-Prod

Each environment requires a setting that is specific to them. For example, in DEV, we do not need to constantly check database consistency. Whereas in TEST and STAGE, we need to. These environments host specific configurations called Profiles.

How do we Maintain Profiles?

In spring boot application, we need different configurations for different environments. We have application.properties file to maintain application specific properties. In order to create profiles for different environments , we need to create various properties files as below –

DEV – application-dev.properties

TEST– application-test.properties

PROD – application-prod.properties

Step 1: Create below project structure in IntelliJ

Step 2: We are creating 3 different property files for below mentioned environments –

DEV – application-dev.properties

TEST– application-test.properties

PROD – application-prod.properties

Of course, the application.properties will remain as a master properties file, but if we override any key in the profile-specific file, the latter will gain precedence.

Step 3: Specify in application.properties file which environment property needs to be loaded

spring.profiles.active=prod

spring.application.name=springbootprofiles

app.message = This is Application property for ${spring.application.name}

Here we are loading PROD properties when application gets booted.

Step 4: Define DB configuration properties for in respective properties file and add code in DBConfiguration.class to pick the appropriate settings.

package com.myjavablog.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@ConfigurationProperties("spring.datasource")
public class DBConfiguration {

    private String driverClassName;
    private String url;
    private String username;
    private String password;

    public String getDriverClassName() {
        return driverClassName;
    }

    public void setDriverClassName(String driverClassName) {
        this.driverClassName = driverClassName;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    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;
    }

    @Profile("dev")
    @Bean
    public String devDatabaseConnection() {
        System.out.println("DB connection for DEV - H2");
        System.out.println(driverClassName);
        System.out.println(url);
        return "DB connection for DEV - H2";
    }

    @Profile("test")
    @Bean
    public String testDatabaseConnection() {
        System.out.println("DB Connection to TEST -H2");
        System.out.println(driverClassName);
        System.out.println(url);
        return "DB Connection to TEST -H2";
    }

    @Profile("prod")
    @Bean
    public String prodDatabaseConnection() {
        System.out.println("DB Connection to PROD - H2");
        System.out.println(driverClassName);
        System.out.println(url);
        return "DB Connection to PROD - H2";
    }
}

This will load the properties file as per the spring.profiles.active property we have mentioned in application.properties file.

Step 5: Output

As per the application boot time logs below, you can see PROD database is loaded during application boot up.

2019-12-01 23:29:07.199  INFO 5728 --- [           main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: user_details
2019-12-01 23:29:07.419  INFO 5728 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
DB Connection to PROD - H2
org.h2.Driver
jdbc:h2:mem:proddb;DB_CLOSE_ON_EXIT=FALSE
2019-12-01 23:29:09.147  INFO 5728 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot[email protected]e25951c: startup date [Sun Dec 01 23:28:49 IST 2019]; root of context hierarchy

You can connect to database as shown below –

How to Deploy a Spring Boot application to Azure

Below are the tools required for this tutorial –

  • Maven
  • Git Client
  • Azure CLI
  • JDK
  • Azure Subscription

Create a Spring boot application

  1. Open a git bash terminal window.
  2. Clone the below sample project into the directory you created by typing git clone https://github.com/AnupBhagwat7/azure-demo-service.git
  3. Change to the directory of the completed project by typing cd azure-demo-service
  4. Build the JAR file using Maven by typing mvn clean package
  5. When the web app has been created, start it by typing mvn spring-boot:run
  6. Test it locally by visiting http://localhost:8080/api/hello
    You should see the following message displayed: Hello spring boot on azure!
REST API Response in Browser

Create an Azure service principal

In this section, you will create an Azure service principal that the Maven plugin uses when deploying your web app to Azure.

  1. Open a terminal window.
  2. Sign into your Azure account with the Azure CLI by typing az login
  3. Create an Azure service principal by typing az ad sp create-for-rbac –name “uuuuuuuu” –password “pppppppp” (uuuuuuuu is the user name and pppppppp is the password for the service principal).

Azure should print out a JSON response resembling this:

{
"appId": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
"displayName": "servicename",
"name": "http://servicename",
"password": "pass",
"tenant": "tttttttt-tttt-tttt-tttt-tttttttttttt"
}

Configure Maven to use your Azure service principal

In this section, you will configure Maven to authenticate using your Azure service principal for web app deployment.

Open your Maven settings.xml file in a text editor (usually found at either /etc/maven/settings.xml or $HOME/.m2/settings.xml).

Add your Azure service principal settings from the previous section of this tutorial to the collection in the settings.xml file as shown below:

<servers>
   <server>
     <id>azure-auth</id>
      <configuration>
         <client>aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa</client>
         <tenant>tttttttt-tttt-tttt-tttt-tttttttttttt</tenant>
         <key>pass</key>
         <environment>AZURE</environment>
      </configuration>
   </server>
</servers>


Save and close the settings.xml file.

You need to configure Maven Plugin for Azure Web Apps deployment. Below entry needs to be added in pom.xml –

<plugin>
	<groupId>com.microsoft.azure</groupId>
	<artifactId>azure-webapp-maven-plugin</artifactId>
	<version>1.1.0</version>
	<configuration>
	<!-- Azure configuration -->
	</configuration>
</plugin>

Build and deploy your app to Azure

Once you have configured all of the settings in the previous sections, you are ready to deploy your web app to Azure.

From the git bash terminal window, deploy your web app to Azure with Maven by typing mvn azure-webapp:deploy

Maven will deploy your web app to Azure using a plugin already in the build file of the sample project you cloned earlier. If the web app doesn’t already exist, it will be created.

When your web app has been deployed, visit the Azure portal to manage it. It will be listed in App Services as show below:

Web app will be listed in Azure portal App Services. Click on the application. From there, the publicly-facing URL for your web app will be listed in the Overview section.

Determining the URL for your web app
You can click on this link to visit the Spring Boot application and interact with it.

Spring boot Data JPA+ Angular JS + MySQL Database CRUD

Github Link: 

We are using  Spring boot version 2.0.0.RELEASE . We will be creating simple TodoManager application using which we can manage our daily todo tasks. We will be using angular for front end. It will provide user interface from which you can add, update or delete tasks in todo list.We will use controller, JpaRepository classes to achieve these functionalities.We will connect to MySQL database using SessionFactory class of hibernate.

Tools used for below project –

  1. Spring Boot 2.0.0.RELEASE
  2. Spring 5.0.4.RELEASE
  3. Tomcat Embed 8
  4. Maven 3.3
  5. Java 8
  6. Spring Tool Suite IDE (STS)
  7. Spring Data JPA 2.0.5.RELEASE
  8. MySql 5.1.21

Step 1: Project Structure

Step 2: Create a project named TodoListManagerJPA in STS (Refer Create new project in STS)

Step 3: Change pom.xml as below –

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.anup.springboot</groupId>
<artifactId>TodoListManagerJPA</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>Springboot JPA Maven Webapp</name>
<url>http://maven.apache.org</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
<relativePath />
</parent>

<dependencies>

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

<!-- JSTL for JSP -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>

<!-- For JSP compilation -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>

<!-- mySQL DB -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.21</version>
</dependency>

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

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>

<!-- <plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin> -->
</plugins>

<finalName>TodoListManagerJPA</finalName>
</build>
</project>

The spring-boot-starter-parent provides you all maven defaults required for any spring project. Since we are developing a web application, we also need to add spring-boot-starter-web dependency. Additionally we need to include spring-boot-starter-data-jpa to run this application with MySQL database.You need to also put mysql-connector-java for MySql JDBC driver.If you are using any other database, you need to use different database connector.
Let’s do hibernate configuration first.

Step 4: Create a  “application.properties”  file in package /src/main/resources

spring.mvc.view.prefix: /WEB-INF/views/
spring.mvc.view.suffix: .jsp
server.port=8081

## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url = jdbc:mysql://localhost:3306/test?useSSL=false
spring.datasource.username = root
spring.datasource.password = root

## Hibernate Properties

# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect

# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update

In the above properties file, the last two properties are for hibernate. Spring Boot uses Hibernate as the default JPA implementation.

The property spring.jpa.hibernate.ddl-auto is used for database initialization. I’ve used the value “update”for this property.

It does two things –

  • When you define a domain model, a table will automatically be created in the database and the fields of the domain model will be mapped to the corresponding columns in the table.
  • Any change to the domain model will also trigger an update to the table. For example, If you change the name or type of a field, or add another field to the model, then all these changes will be reflected in the mapped table as well.

Using update for spring.jpa.hibernate.ddl-auto property is fine for development. But, For production, You should keep the value of this property to “validate”, and use a database migration tool like Flyway for managing changes in the database schema.

Step 5: Create a “Task.java” model class in com.myjavablog.springboot.pojo package

package com.myjavablog.springboot.pojo;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

/**
* @author anup
*
*/

@Entity
@Table(name="TASKS")
@EntityListeners(AuditingEntityListener.class)
@JsonIgnoreProperties(value = {"createdAt", "updatedAt"},
allowGetters = true)
public class Task implements Serializable {

/**
*
*/
private static final long serialVersionUID = 1L;

@Id
@Column(name="ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name="TASK_NAME")
private String taskName;

@Column(name="TASK_DESC")
private String taskDesc;

@Column(name="STATUS")
private String status;

@Column(nullable = false, updatable = false , name= "CREATED_AT")
@Temporal(TemporalType.TIMESTAMP)
@CreatedDate
private Date createdAt;

@Column(nullable = false, name= "UPDATED_AT")
@Temporal(TemporalType.TIMESTAMP)
@LastModifiedDate
private Date updatedAt;

public Long getId() {
return id;
}

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

public String getTaskName() {
return taskName;
}

public void setTaskName(String taskName) {
this.taskName = taskName;
}

public String getTaskDesc() {
return taskDesc;
}

public void setTaskDesc(String taskDesc) {
this.taskDesc = taskDesc;
}

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

public Date getCreatedAt() {
return createdAt;
}

public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}

public Date getUpdatedAt() {
return updatedAt;
}

public void setUpdatedAt(Date updatedAt) {
this.updatedAt = updatedAt;
}
}

@Entity – This marks class as Entity

@Table – This maps class to database table

@Id – Marks the class variable as primary key column in table

@Column – Marks it as a column in table , we can also configure name attribute defining its name in database table

@Temporal – annotation is used with java.util.Dateand java.util.Calendar classes. It converts the date and time values from Java Object to compatible database type and vice versa.

@JsonIgnoreProperties – annotation is a Jackson annotation. Spring Boot uses Jackson for Serializing and Deserializing Java objects to and from JSON.This annotation is used because we don’t want the clients of the rest api to supply the createdAt and updatedAt values. If they supply these values then we’ll simply ignore them. However, we’ll include these values in the JSON response.

@EntityListeners(AuditingEntityListener.class)

In our Task model we have annotated createdAt and updatedAt fields with @CreatedDate and @LastModifiedDate annotations respectively.

Now, what we want is that these fields should automatically get populated whenever we create or update an entity.

To achieve this, we need to do two things –

  1. Add Spring Data JPA’s AuditingEntityListener to the domain model. We have already done this in our Task model with the annotation @EntityListeners(AuditingEntityListener.class).
  2. Enable JPA Auditing in the main application. Open TodoManagerApplication.java and add @EnableJpaAuditing annotation.

@GeneratedValue – Marking a field with the @GeneratedValue annotation specifies that a value will be automatically generated for that field. This is primarily intended for primary key fields .There are below types of strategies –

GenerationType.AUTO It is the default generation type and lets the persistence provider choose the generation strategy.

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", updatable = false, nullable = false)
private Long id;

GenerationType.IDENTITY – The GenerationType.IDENTITY is the easiest to use but not the best one from a performance point of view. It relies on an auto-incremented database column and lets the database generate a new value with each insert operation. From a database point of view, this is very efficient because the auto-increment columns are highly optimized, and it doesn’t require any additional statements.

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", updatable = false, nullable = false)
private Long id;

GenerationType.SEQUENCE – The GenerationType.SEQUENCE is my preferred way to generate primary key values and uses a database sequence to generate unique values.

If you don’t provide sequence name hibernate will provide its default sequence

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "id", updatable = false, nullable = false)
private Long id;

You can change that by referencing the name of a @SequenceGenerator in the generator attribute of the @GeneratedValue annotation. The @SequenceGenerator annotation lets you define the name of the generator, the name, and schema of the database sequence and the allocation size of the sequence.

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "book_generator")
@SequenceGenerator(name="book_generator", sequenceName = "book_seq", allocationSize=50)
@Column(name = "id", updatable = false, nullable = false)
private Long id;

GenerationType.TABLE – The GenerationType.TABLE gets only rarely used nowadays. It simulates a sequence by storing and updating its current value in a database table which requires the use of pessimistic locks which put all transactions into a sequential order. This slows down your application, and you should, therefore, prefer the GenerationType.SEQUENCE, if your database supports sequences, which most popular databases do

If you don’t provide sequence name hibernate will provide its default sequence

@Id
@GeneratedValue(strategy = GenerationType.TABLE)
@Column(name = "id", updatable = false, nullable = false)
private Long id;

Summary:

  1. AUTO: Hibernate selects the generation strategy based on the used dialect,
  2. IDENTITY: Hibernate relies on an auto-incremented database column to generate the primary key,
  3. SEQUENCE: Hibernate requests the primary key value from a database sequence,
  4. TABLE: Hibernate uses a database table to simulate a sequence.

Step 6: Create database tables

create schema test;

create table TASKS (id bigint NOT NULL AUTO_INCREMENT, TASK_NAME varchar(255), TASK_DESC varchar(255), STATUS varchar(255) , CREATED_AT timestamp, UPDATED_AT timestamp, primary key (id));

INSERT INTO TASKS VALUES(1, 'Bath', 'Have a bath' , 'PENDING', SYSDATE, SYSDATE);

INSERT INTO TASKS VALUES(2, 'Snacks', 'Have snacks' , 'PENDING' , CURTIME() , CURTIME());

INSERT INTO TASKS VALUES(3, 'Office', 'Office' , 'PENDING' , CURTIME() , CURTIME());

INSERT INTO TASKS VALUES(4, 'Lunch', 'Lunch' , 'PENDING' , CURTIME() , CURTIME());

Controller class

Step 7: Create class “TodoController.java” in package com.myjavablog.springboot.controller

/**
*
*/
package com.myjavablog.springboot.controller;

import java.util.List;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.myjavablog.springboot.exception.ResourceNotFoundException;
import com.myjavablog.springboot.pojo.Task;
import com.myjavablog.springboot.repository.TodoRepository;

/**
* @author anup
*
*/

@RestController
public class TodoController {

@Autowired
TodoRepository todoRepository;

@PostMapping(value = "/todos/addTodo")
public Task addTodo(@Valid @RequestBody Task task) {
return todoRepository.save(task);
}

@PutMapping(value = "/todos/updateTodo")
public Task updateTodo(@Valid @RequestBody Task task) {

Task todo = todoRepository.findById(task.getId())
.orElseThrow(() -> new ResourceNotFoundException("Todo", "id", task.getId()));

todo.setStatus(task.getStatus());
todo.setTaskDesc(task.getTaskDesc());
todo.setTaskName(task.getTaskName());

Task updatedTask = todoRepository.save(todo);
return updatedTask;
}
@GetMapping(value = "/todos/getAllTodos")
public List<Task> getAllTodos() {
return todoRepository.findAll();
}

@DeleteMapping(value="/todos/deleteTodo/{id}")
public ResponseEntity<?> deleteCust(@PathVariable Long id) {
todoRepository.deleteById(id);

return ResponseEntity.ok().build();
}

}

@RestController annotation is a combination of Spring’s @Controller and @ResponseBody annotations.

Repository 

Step 8: Create interface “TodoRepository.java” in package “com.myjavablog.springboot.repository” and extend it from JpaRepository.

We have to create a repository to access Tasks from the database.

Well, Spring Data JPA comes to rescue us here. It comes with a JpaRepository interface which defines methods for all the CRUD operations on the entity, and a default implementation of JpaRepository called SimpleJpaRepository. JPA has eliminated lot of boilerplate code which we need to write for CRUD operations otherwise.

package com.myjavablog.springboot.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.myjavablog.springboot.pojo.Task;

/**
* @author anupb
*
*/
@Repository
public interface TodoRepository extends JpaRepository<Task, Long>{

}

we have annotated the interface with @Repository annotation. This tells Spring to bootstrap the repository during component scan.

Cool! That is all you have to do in the repository layer. You will now be able to use JpaRepository’s methods like save()findOne()findAll()count()delete() etc.

Custom Exception

Step 9: Create “ResourceNotFoundException.java” in “com.myjavablog.springboot.exception” package –

We have defined the Rest APIs for creating, retrieving, updating, and deleting a Task .

The APIs will throw a ResourceNotFoundException whenever a Task with a given id is not found in the database.

package com.myjavablog.springboot.exception;

import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.http.HttpStatus;
/**
* @author anupb
*
*/
@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
private String resourceName;
private String fieldName;
private Object fieldValue;

public ResourceNotFoundException(String resourceName, String fieldName, Object fieldValue) {
super(String.format("%s not found with %s : '%s'", resourceName, fieldName, fieldValue));
this.resourceName = resourceName;
this.fieldName = fieldName;
this.fieldValue = fieldValue;
}

public String getResourceName() {
return resourceName;
}

public String getFieldName() {
return fieldName;
}

public Object getFieldValue() {
return fieldValue;
}
}

AngularJS UI Layer

Step 10: Create “index.jsp” under \src\main\webapp\WEB-INF\views\

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>

<html>
<head>
<link href="/css/app.css" rel="stylesheet"/>

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js"></script>
<script type="text/javascript" src="/js/app.js"></script>

<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Todo Manager</title>
</head>
<body ng-app="todoManager" ng-controller="todoController">
</br>
<h4 class="todo">Todo Manager</h4>

<form ng-submit="submitTodo()">
<table>

<tr>
<th colspan="2">Add/Edit todo</th>
</tr>
<tr>
<td>Task Name</td>
<td><input type="text" ng-model="todoForm.taskName" /></td>
</tr>
<tr>
<td>Task Desc</td>
<td><input type="text" ng-model="todoForm.taskDesc" /></td>
</tr>
<tr>
<td>Status</td>
<td><select id="status" ng-model="todoForm.status" ng-options="x for x in status" /></select></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="Submit"
class="blue-button" /></td>
</tr>
</table>
</form>

<table>
<tr>

<th width="120">Task Name</th>
<th width="120">Task Desc</th>
<th width="60">Status</th>
<th width="60">Operations</th>

</tr>

<tr ng-repeat="todo in todos" ng-init="statusCls=getClass(todo)">

<td>{{ todo.taskName }}</td>
<td>{{ todo.taskDesc }}</td>
<td class="statusCls"> {{ todo.status }} </td>

<td><a ng-click="editTodo(todo)" class="blue-button">Edit</a>
| <a ng-click="deleteTodo(todo)" class="red-button">Delete</a></td>
</tr>

</table>

</body>
</html>

Step 11: Create javascript file “app.js” under \src\main\resources\static\js\

var app = angular.module("todoManager" , []);

app.controller("todoController" , function($scope, $http){

$scope.todos = [];
$scope.status = ["PENDING", "COMPLETED"];
$scope.todoForm = {
id : -1,
taskName : "",
taskDesc : ""
};

$scope.getClass = function(todo){

if(todo.status == 'PENDING')
return 'red';
else if(todo.status == 'COMPLETED'){
return 'green';
}
}

_refreshTodoData();

function _refreshTodoData(){

$http({
method : 'GET',
url : 'http://localhost:8082/todos/getAllTodos'
}).then(function successCallback(response) {
$scope.todos = response.data;

//alert($scope.todos);
}, function errorCallback(response) {
console.log(response.statusText);
});
}

$scope.submitTodo = function() {

var method = "";
var url = "";
if ($scope.todoForm.id == -1) {
//Id is absent in form data, it is create new todo operation
method = "POST";
url = '/todos/addTodo';
} else {
//Id is present in form data, it is edit todo operation
method = "PUT";
url = '/todos/updateTodo';
}

$http({
method : method,
url : url,
data : angular.toJson($scope.todoForm),
headers : {
'Content-Type' : 'application/json'
}
}).then( _success, _error );
};

$scope.deleteTodo = function(todo) {
$http({
method : 'DELETE',
url : '/todos/deleteTodo/' + todo.id
}).then(_success, _error);
};

$scope.editTodo = function(todo) {

$scope.todoForm.taskName = todo.taskName;
$scope.todoForm.taskDesc = todo.taskDesc;
$scope.todoForm.status = todo.status;
$scope.todoForm.id = todo.id;
};

function _success(response) {
//alert("success");
_refreshTodoData();
_clearFormData();
}

function _error(response) {
//alert("error");
console.log(response.statusText);
}

//Clear the form
function _clearFormData() {
$scope.todoForm.id = -1;
$scope.todoForm.taskName = "";
$scope.todoForm.taskDesc = "";
$scope.todoForm.status = "";

};
});

Step 12: Create CSS file “app.css” under \src\main\resources\static\css\ for adding style

.blue-button {
background: #25A6E1;
filter: progid: DXImageTransform.Microsoft.gradient( startColorstr='#25A6E1',
endColorstr='#188BC0', GradientType=0);
padding: 3px 5px;
color: #fff;
font-family: 'Helvetica Neue', sans-serif;
font-size: 12px;
border-radius: 2px;
-moz-border-radius: 2px;
-webkit-border-radius: 4px;
border: 1px solid #1A87B9;
cursor: pointer;
}

.red-button {
background: #CD5C5C;
padding: 3px 5px;
color: #fff;
font-family: 'Helvetica Neue', sans-serif;
font-size: 12px;
border-radius: 2px;
-moz-border-radius: 2px;
-webkit-border-radius: 4px;
border: 1px solid #CD5C5C;
cursor: pointer;
}

table {
font-family: "Helvetica Neue", Helvetica, sans-serif;
width: 50%;
}

caption {
text-align: left;
color: silver;
font-weight: bold;
text-transform: uppercase;
padding: 5px;
}

th {
background: SteelBlue;
color: white;
}

tbody tr:nth-child(even) {
background: WhiteSmoke;
}

tbody tr td:nth-child(2) {
text-align: center;
}

tbody tr td:nth-child(3), tbody tr td:nth-child(4) {
text-align: center;
font-family: monospace;
}

tfoot {
background: SeaGreen;
color: white;
text-align: right;
}

tfoot tr th:last-child {
font-family: monospace;
}

td, th {
border: 1px solid gray;
width: 25%;
text-align: left;
padding: 5px 10px;
}

#status{
width: 53%;
padding: 1px 0;
}

.todo {
font-size: 24px;
color: #CD5C5C;
text-transform: uppercase;
font-family: arial;
width: 50%;
background: #ccc;
text-align: center;
border-radius: 4px;
margin: 2% 0%;
padding: 3px 0;
box-shadow: 0px 1px 7px 1px grey;
}

.pending{
color: red;
}

.completed{
color: green;
}

  • $http – It’s used to make AJAX calls to server in order to submitTodo(), deleteTodo() , editTodo() task.
  • When you click on submit button on form, it actually calls POST or PUT depending on operation. If you click on edit and submit data then it will be PUT operation as it will update existing resource. If you directly submit data, then it will be POST operation to create new resource.
  • Every time you submit data, it calls _refreshTodoData() to refresh Todo table below.
  • When you call $http, you need to pass method type and URL, it will call it according, You can either put absolute URL or relative URL with respect to context root of web application.

Spring boot main file

Step 13: Create “TodoManagerApplication.java” a main spring file under com.anup.springboot

package com.myjavablog.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication
@EnableJpaAuditing
@EnableJpaRepositories(basePackages="com.myjavablog.springboot.repository")
public class TodoManagerApplication {

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

This is the mail file which bootstraps spring application.

We have just added @SpringBootApplication and it does all the work.
Let’s understand more about this annotation.
@SpringBootApplication is an annotation that adds all of the following:

@Configuration – It makes the class as a source of bean definitions for the application context.
@EnableAutoConfiguration – It enables Spring boot to add beans presents in classpath setting and various property setting.
Normally you would add @EnableWebMvc for a Spring MVC application, but Spring Boot adds it automatically when it sees spring-webmvc on the classpath.
This flags the application as a web application and activates key behaviors such as setting up a DispatcherServlet.
@ComponentScan – It tells Spring to look for other components, configurations, and services in the default package, allowing it to find the controllers.
If specific packages are not defined, scanning will occur from the package of the class that declares this annotation.

Run the application

Step 14: Right Click on Project -> Debug As -> Maven Build

Step 15: Provide goals as below – 

mvn clean install spring-boot:run (Cmd prompt)

Or

Step 16: Now once the application is up and running, you can access it from below link –

Adding new task –

Editing the task –

Deleting the task –

Now we will try to update Task which is not present in database. It should throw a custom exception and we will get response as shown below –

Bitnami