4. Restful webservices using Spring boot

Github Link:  Download

We are using  Spring boot version 1.5.9.RELEASE . We will be creating simple Todo Manager application which provides endpoints to expose todo tasks data without using any database.

Spring boot makes it very easy to develop REST API . We don’t need to worry for JSON conversion using jacksondatabind jar as earlier. Spring boot provides JSON dependency by default for us.

Tools used for below project –

  1. Spring Boot 2.0.2.RELEASE
  2. Spring 5.0.6.RELEASE
  3. Tomcat Embed 8
  4. Maven 3.3
  5. Java 8
  6. Spring Tool Suite IDE (STS)

Step 1: Project Structure

 

 

 

 

 

 

 

 

Step 2: Create a project named SpringBootRestful 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>TodoListManager</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>TodoListManager 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>1.5.9.RELEASE</version>
</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>
<!-- https://mvnrepository.com/artifact/org.threeten/threetenbp -->
<dependency>
<groupId>org.threeten</groupId>
<artifactId>threetenbp</artifactId>
<version>0.7.2</version>
</dependency>

<!-- <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope> </dependency> -->
<!-- H2 Database
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>-->

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

</dependencies>

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

</plugins>

<finalName>TodoListManager</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 hibernate.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.

Model class –

Step 4: Create a “Todo.java” model class in com.anup.springboot.pojo package

package com.anup.springboot.pojo;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
* @author anup
*
*/

@Entity
@Table(name = "TODO")
public class Todo implements Serializable {

public Todo() {
super();
}

public Todo(Long id, String taskName, String taskDesc, String status) {
super();
this.id = id;
this.taskName = taskName;
this.taskDesc = taskDesc;
this.status = status;
}

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

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

}

@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

@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.

Conroller class- 

Step 5: Create “TodoController .java” file under com.myjavablog.controller package –

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

import java.util.ArrayList;
import java.util.List;

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 com.myjavablog.model.Task;

/**
* @author anupb
*
*/
@RestController
public class TodoController {

static List<Task> taskList = new ArrayList<Task>();
static {
Task t1 = new Task(1l, "Walking", "Walking at 6 AM", "PENDING");
Task t2 = new Task(2l, "Breakfast", "Breakfast 7 AM", "COMPLETED");
Task t3 = new Task(3l, "Office", "Office at 9 AM", "COMPLETED");
Task t4 = new Task(4l, "Lunch", "Lunch at 1 PM", "PENDING");
Task t5 = new Task(5l, "Snacks", "Snacks at 6 PM", "PENDING");

taskList.add(t1);
taskList.add(t2);
taskList.add(t3);
taskList.add(t4);
taskList.add(t5);
}

@RequestMapping(value = "/tasks", method = RequestMethod.GET, headers = "Accept=application/json")
public List<Task> getTasks() {

return taskList;
}

@RequestMapping(value = "/addTask", method = RequestMethod.POST, headers = "Accept=application/json")
public String addTask(@RequestBody Task task) {

taskList.add(task);

return "Task added Succesfully!!!";
}

@RequestMapping(value = "/task/{taskId}", method = RequestMethod.GET, headers = "Accept=application/json")
public Task getTask(@PathVariable Long taskId) {

for (Task task : taskList) {

if (task.getId() == taskId)
return task;
}
return null;
}

@RequestMapping(value = "/deleteTask/{taskId}", method = RequestMethod.DELETE, headers = "Accept=application/json")
public String deleteTask(@PathVariable Long taskId) {

boolean flag = false;
Task tempTask = null;
for (Task task : taskList) {

if (task.getId() == taskId) {
tempTask = task;
break;
}
}

flag = taskList.remove(tempTask);
if (flag)
return "Task deleted successfully!!!!!";
else
return "Error in deleting Task!!!!!";
}

@RequestMapping(value = "/updateTask/{id}/{status}", method = RequestMethod.PUT, headers = "Accept=application/json")
public String updateTask(@PathVariable Long id, @PathVariable String status) {

for (Task task : taskList) {

if (task.getId() == id) {
task.setStatus(status);
}
}

return "Task updated Succesfully!!!";
}
}

 Below are the annotations used-

@RestController  –   This is a convenience annotation that does nothing more than adding                          the @Controller and @ResponseBody annotations.  (Note – @Controller is used to mark classes as Spring MVC Controller.)

@PathVariable –  This annotation is used to obtain some placeholder from the URI. Placeholders are generally of primitive datatype.

@RequestBody – This annotation is used to obtain some placeholder from the URI. Placeholders are generally of class objects in JSON format.

@RequestMapping – This anootation is used map requests from URI to java methods.

Spring boot main file

Step 6: Create a  “SpringBootRestfulApplication.java”  file in package com.myjavablog

package com.myjavablog;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootRestfulApplication {

public static void main(String[] args) {
SpringApplication.run(SpringBootRestfulApplication.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 7: Right Click on Project -> Debug As -> Maven Build

 

Step 8: Provide goals as below – 

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

Or

Step 9: Now once the application is up and running, you can access it from POSTMAN tool as below –

Get all tasks –

 

 

 

 

 

 

 

 

 

 

Get single task –

 

 

 

 

 

 

 

 

Add task –

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Delete task –

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Update Task –

Before

 

 

 

 

 

 

 

 

 

After  –

 

 

 

 

 

 

 

Bitnami