3. Spring boot + Angular JS + Hibernate CRUD

Github Link:  Download

We are using  Spring boot version 1.5.9.RELEASE which has hibernate 5.0 version inside it. 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, services and DAO 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.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)
  7. Hibernate 5
  8. MySql 5.1.21

Step 1: Project Structure

Step 2: Create a project named TodoListManager 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.

Configure Hibernate – 

Step 4: Create “HibernateConfiguration.java” file under com.anup.springboot.hibernateconfig package –

package com.anup.springboot.hibernateconfig;

import java.util.Properties;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
* @author anup
*
*/
@Configuration
@EnableTransactionManagement
public class HibernateConfiguration {

@Value("${db.driver}")
private String DRIVER;

@Value("${db.password}")
private String PASSWORD;

@Value("${db.url}")
private String URL;

@Value("${db.username}")
private String USERNAME;

@Value("${hibernate.dialect}")
private String DIALECT;

@Value("${hibernate.show_sql}")
private String SHOW_SQL;

@Value("${hibernate.hbm2ddl.auto}")
private String HBM2DDL_AUTO;

@Value("${entitymanager.packagesToScan}")
private String PACKAGES_TO_SCAN;

@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(DRIVER);
dataSource.setUrl(URL);
dataSource.setUsername(USERNAME);
dataSource.setPassword(PASSWORD);
return dataSource;
}

@Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(PACKAGES_TO_SCAN);
Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.dialect", DIALECT);
hibernateProperties.put("hibernate.show_sql", SHOW_SQL);
hibernateProperties.put("hibernate.hbm2ddl.auto", HBM2DDL_AUTO);
sessionFactory.setHibernateProperties(hibernateProperties);

return sessionFactory;
}

@Bean
public HibernateTransactionManager transactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}

}

 This class is annotated with @Configuration and @Bean annotation. These annotations are used to define bean in Spring.

@Configuration is analogous to <beans> tag in Spring XML configuration and @Bean is analogous to <bean> tag.

@Value annotation is used to inject variables from properties files. In this case, it will read from application.properties which we are going to create in next step.

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

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

logging.level=DEBUG
# Database
db.driver: com.mysql.jdbc.Driver
db.url: jdbc:mysql://localhost:3306/todomanager
db.username: root
db.password:

# Hibernate
hibernate.dialect: org.hibernate.dialect.MySQL5Dialect
hibernate.show_sql: true
hibernate.hbm2ddl.auto: update
entitymanager.packagesToScan: com

spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true

Step 7: 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.

Step 6: Create database tables

create table TODO (id bigint NOT NULL AUTO_INCREMENT, TASK_NAME varchar(255), TASK_DESC varchar(255), STATUS varchar(255) , primary key (id));

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

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

Controller class

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

package com.anup.springboot.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 com.anup.springboot.pojo.Todo;
import com.anup.springboot.service.TodoService;

/**
* @author anup
*
*/

@RestController
public class TodoController {

@Autowired
TodoService service;

@RequestMapping(value = "/", method = RequestMethod.GET)
public String getHomePage() {

return "index";
}

@RequestMapping(value = "/todos/addTodo", method = RequestMethod.POST, headers = "Accept=application/json")
public Todo addTodo(@RequestBody Todo t) {
Todo todo = service.addTodo(t);
return todo;
}

@RequestMapping(value = "/todos/updateTodo", method = RequestMethod.PUT, headers = "Accept=application/json")
public Todo updateTodo(@RequestBody Todo t) {
service.updateTodo(t);
return t;
}

@RequestMapping(value = "/todos/getAllTodos", method = RequestMethod.GET, headers = "Accept=application/json")
public List<Todo> getAllTodos() {
List<Todo> todoList = service.getAllTodos();
return todoList;
}

@RequestMapping(value = "/todos/deleteTodo/{id}", method = RequestMethod.DELETE, headers = "Accept=application/json")
public void deleteCust(@PathVariable long id) {
service.deleteTodo(id);
}

}

Service Layer

Step 8: Create interface named “TodoService.java” in package com.anup.springboot.service

package com.anup.springboot.service;

import java.util.List;

import com.anup.springboot.pojo.Todo;

/**
* @author anup
*
*/

public interface TodoService {

public List<Todo> getAllTodos();
public Todo getTodo(Long id);
public Todo addTodo(Todo t);
public Todo updateTodo(Todo t);
public void deleteTodo(Long id);

}

Step 9: Create class named “TodoServiceImpl.java” in package com.anup.springboot.service

package com.anup.springboot.service;

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

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.anup.springboot.dao.TodoRepository;
import com.anup.springboot.pojo.Todo;

/**
* @author anup
*
*/
@Service("todoService")
public class TodoServiceImpl implements TodoService {

@Autowired
TodoRepository dao;

@Override
@Transactional
public List<Todo> getAllTodos() {
List<Todo> todoList = new ArrayList<>();
dao.findAll().forEach(e -> todoList.add(e));
return todoList;
}

@Override
@Transactional
public Todo getTodo(Long id) {
Todo todo = dao.findOne(id);
return todo;
}

@Override
@Transactional
public synchronized Todo addTodo(Todo t) {

dao.save(t);
return t;
}

@Override
@Transactional
public Todo updateTodo(Todo t) {
dao.save(t);
return t;
}

@Override
@Transactional
public void deleteTodo(Long id) {
dao.delete(id);
}

}

DAO Layer

Step 10: Create interface “TodoDao.java” in package com.anup.springboot.dao

package com.anup.springboot.dao;

import java.util.List;

import com.anup.springboot.pojo.Todo;

/**
* @author anup
*
*/
public interface TodoDao {

public void addTodo(Todo c);
public List<Todo> getTodos();
public void deleteTodo(int id);
public void updateTodo(Todo c);
public Todo getTodo(int id);
}

Step 11: Create class “TodoDaoImpl.java” in package com.anup.springboot.dao

package com.anup.springboot.dao;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.anup.springboot.pojo.Todo;

/**
* @author anup
*
*/

@Repository("todoDao")
public class TodoDaoImpl implements TodoDao {

@Autowired
private SessionFactory sessionFactory;

public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}

@Override
public void addTodo(Todo c) {

Session session = sessionFactory.getCurrentSession();

session.save(c);

}

@Override
public List<Todo> getTodos() {

Session session = sessionFactory.getCurrentSession();

List<Todo> list = session.createQuery("from Todo").list();

return list;
}

@Override
public void deleteTodo(int id) {

Session session = sessionFactory.getCurrentSession();

Todo c = session.load(Todo.class, new Integer(id));

if (c != null)
session.delete(c);

}

@Override
public void updateTodo(Todo c) {
Session session = sessionFactory.getCurrentSession();

session.update(c);

}

@Override
public Todo getTodo(int id) {
Session session = sessionFactory.getCurrentSession();

Todo c = (Todo) session.get(Todo.class, id);

return c;
}

}

AngularJS UI Layer

Step 12: 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 13: 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 14: 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 15: Create “TodoManagerApplication.java” a main spring file under com.anup.springboot

package com.anup.springboot;

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

@SpringBootApplication
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 16: Right Click on Project -> Debug As -> Maven Build

 

Step 17: Provide goals as below – 

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

Or

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

Adding new task –

 

 

 

 

 

 

 

 

 

 

Editing the task –

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Deleting the task –

 

 

 

 

 

 

 

 

 

 

 

 

Bitnami