Spring Boot-AngularJS-Bootstrap-JPA-CRUD
Hello everyone, Today we will learn how to develop a Spring Boot CRUD application with, Angular JS, embedded Tomcat, and JPA. You can download the source code of this simple application from our GitHub repository.
Following technologies stack being used:
- Spring Boot 2.1.4.RELEASE
- Spring 5.1.6.RELEASE
- Angular JS
- JDK 1.8
- Eclipse Oxygen
- Bootstrap
- Thymeleaf
- H2DB -in-memory database
User Interface
Project Structure
Pom.xml(maven)
A Project Object Model or POM is the fundamental unit of work in Maven. It is an XML file that contains information about the project and configuration details utilized by Maven to build the project. It contains default values for most projects. Some of the configurations that can be designated in the POM is the project dependencies, the plugins or goals that can be executed, the build profiles, and so on. Other information such as the project version, description, developers, mailing lists, and such can withal be designated.
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<artifactId>springboot-jpa-Angular-bootstrap-CRUD</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-jpa-Angular-bootstrap-CRUD</name>
<properties>
<java.version>1.8</java.version>
</properties>
<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-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<groupId>com.knowledgefactory</groupId>
<description>springboot-jpa-Angular-bootstrap-CRUD</description>
</project>
User(Entity Class)
package com.knowledgefactory.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@Column(name = "email", nullable = false, length = 200)
private String email;
public User() {
super();
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public User(String firstName,
String lastName, String email) {
super();
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
@Override
public String toString() {
return "User [id=" + id + ", firstName=" +
firstName + ", lastName="
+ lastName + ", email=" + email + "]";
}
}
The @Entity annotation specifies that the class is an entity and is mapped to a database table. The @Id annotation specifies the primary key of an entity and the @GeneratedValue provides for the specification of generation strategies for the values of primary keys. The @Column annotation is used to specify the mapped column for a persistent property or field. If no Column annotation is specified, the default value will be applied.
User Repository
package com.knowledgefactory.repository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.knowledgefactory.entity.User;
@Repository
public interface UserRepository
extends CrudRepository<User, Long> {
}
@Repository annotation is used to indicate that the class provides the mechanism for storage, retrieval, search, update and delete operation on objects.
User Service
package com.knowledgefactory.service;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.knowledgefactory.entity.User;
import com.knowledgefactory.exception.RecordNotFoundException;
import com.knowledgefactory.repository.UserRepository;
@Service
public class UserService {
@Autowired
UserRepository repository;
public List<User> getAllusers() {
List<User> result = (List<User>) repository.findAll();
if (result.size() > 0) {
return result;
} else {
return new ArrayList<User>();
}
}
public User getUserById(Long id)
throws RecordNotFoundException {
Optional<User> user = repository.findById(id);
if (user.isPresent()) {
return user.get();
} else {
throw new RecordNotFoundException
("No user record exist for given id");
}
}
public User createOrUpdateUser(User entity) {
if (entity.getId() == null) {
entity = repository.save(entity);
return entity;
} else {
Optional<User> user = repository.
findById(entity.getId());
if (user.isPresent()) {
User newEntity = user.get();
newEntity.setEmail(entity.getEmail());
newEntity.setFirstName(entity.getFirstName());
newEntity.setLastName(entity.getLastName());
newEntity = repository.save(newEntity);
return newEntity;
} else {
entity = repository.save(entity);
return entity;
}
}
}
public void deleteUserById(Long id)
throws RecordNotFoundException {
Optional<User> user = repository.findById(id);
if (user.isPresent()) {
repository.deleteById(id);
} else {
throw new RecordNotFoundException
("No user record exist for given id");
}
}
}
@Service annotation is used with classes that provide some business functionalities. Spring context will autodetect these classes when annotation-based configuration and classpath scanning is used.
RestController
package com.knowledgefactory.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.Model;
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.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.knowledgefactory.entity.User;
import com.knowledgefactory.exception.RecordNotFoundException;
import com.knowledgefactory.service.UserService;
@RestController
public class WebController {
@Autowired
UserService service;
@GetMapping({ "/getAllUsers" })
public ResponseEntity<List<User>> getAllUsers() {
List<User> list = service.getAllusers();
return new
ResponseEntity<List<User>>(list, HttpStatus.OK);
}
@DeleteMapping(path = "/delete/{id}")
public void deleteUserById(Model model,
@PathVariable("id") Long id)
throws RecordNotFoundException {
service.deleteUserById(id);
}
@PostMapping(path = "/createUser")
public User createOrUpdateUser(@RequestBody User user) {
return service.createOrUpdateUser(user);
}
}
The @RestController annotation was introduced in Spring 4.0 to simplify the engendering of RESTful web services. It's a convenience annotation that combines @Controller and @ResponseBody. @RequestMapping annotation maps HTTP requests to handler methods of MVC and REST controllers.
Main Controller
package com.knowledgefactory.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class MainController {
@RequestMapping("/")
public String welcome() {
return "index";
}
}
Spring Boot(Main Class)
package com.knowledgefactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.knowledgefactory.entity.User;
import com.knowledgefactory.repository.UserRepository;
@SpringBootApplication
public class KnowledgefactorydemoApplication
implements CommandLineRunner {
@Autowired
private UserRepository repository;
public static void main(String[] args) {
SpringApplication.
run(KnowledgefactorydemoApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
repository.save(new User
("sibin", "knf", "sibinraziya@gmail.com"));
repository.save(new User
("knf", "springboot", "sibinraziya@gmail.com"));
}
}
The @SpringBootApplication annotation is a convenience annotation that combines the @EnableAutoConfiguration, @Configuration and the @ComponentScan annotations.
View Layer
main.js
var app = angular.module("UserManagement", []);
// Controller Part
app.controller("UserController", function ($scope, $http) {
$scope.users = [];
$scope.userForm = {
id: "",
firstName: "",
lastName: "",
email: ""
};
// Now load the data from server
_refreshUserData();
$scope.submitUser = function () {
var method = "";
var url = "";
method = "POST";
url = '/createUser';
$http({
method: method,
url: url,
data: angular.toJson($scope.userForm),
headers: {
'Content-Type': 'application/json'
}
}).then(_success, _error);
};
$scope.createUser = function () {
_clearFormData();
}
$scope.deleteUser = function (user) {
$http({
method: 'DELETE',
url: '/delete/' + user.id
}).then(_success, _error);
};
// In case of edit
$scope.editUser = function (user) {
$scope.userForm.id = user.id;
$scope.userForm.firstName = user.firstName;
$scope.userForm.lastName = user.lastName;
$scope.userForm.email = user.email;
};
function _refreshUserData() {
$http({
method: 'GET',
url: '/getAllUsers'
}).then(function (res) { // success
$scope.users = res.data;
}, function (res) { // error
console.log("Error: " + res.status + " : " + res.data);
});
}
function _success(res) {
_refreshUserData();
_clearFormData();
}
function _error(res) {
var data = res.data;
var status = res.status;
var header = res.header;
var config = res.config;
alert("Error: " + status + ":" + data);
}
// Clear the form
function _clearFormData() {
$scope.userForm.id = -1;
$scope.userForm.firstName = "";
$scope.userForm.lastName = ""
$scope.userForm.email = ""
}
;
});
index.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Spring Boot-Angular</title>
<script th:src="@{/angular.js}"></script>
<script th:src="@{/jquery.min.js}"></script>
<script th:src="@{/bootstrap.min.js}"></script>
<script th:src="@{/main.js}"></script>
<link rel="stylesheet" type="text/css" media="all"
href="../../bootstrap.min.css" th:href="@{/bootstrap.min.css}" />
<head>
<body ng-app="UserManagement" ng-controller="UserController">
<div class="container">
<div class="row">
<div class="col-sm-2"></div>
<div class="col-sm-8">
<h3>CRUD: Spring Boot +AngularJS+Bootstrap</h3>
<form ng-submit="submitUser()">
<table class="table table-striped">
<tr>
<td>First Name</td>
<td>
<input class="form-control input-sm"
type="text"
ng-model="userForm.firstName" />
</td>
</tr>
<tr>
<td>Last Name</td>
<td><input type="text"
class="form-control input-sm"
ng-model="userForm.lastName" />
</td>
</tr>
<tr>
<td>Email</td>
<td>
<input type="text"
class="form-control input-sm"
ng-model="userForm.email" />
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="Submit"
class="btn btn-primary" /></td>
</tr>
</table>
</form>
<br /> <a class="create-button" ng-click="createUser()">
<button type="button" class="btn btn-info">Create
User</button></a><br>
<br>
<table class="table table-striped">
<tr>
<th>Id</th>
<th>FirstName</th>
<th>LastName</th>
<th>Email</th>
<th>Edit</th>
<th>Delete</th>
</tr>
<!-- $scope.users -->
<tr ng-repeat="user in users">
<td>{{ user.id }}</td>
<td>{{ user.firstName }}</td>
<td>{{ user.lastName }}</td>
<td>{{ user.email }}</td>
<td><a ng-click="editUser(user)"
class="btn btn-warning">
Edit</a></td>
<td><a ng-click="deleteUser(user)"
class="btn btn-danger">
Delete</a>
</td>
</tr>
</table>
</div>
<div class="col-sm-2"></div>
</div>
</div>
</body>
</html>
Github repository download link is provided at the end of this tutorial
Github repository download link is provided at the end of this tutorial
Local Setup:
Step 1: Download or clone the source code to a local machine.
Step 2: mvn clean install
Step 3: Run the Spring Boot application
mvn spring-boot:run
More related topics,
More related topics,