Spring Boot REST + Angular 2/4 + JPA + Hibernate + MySQL CRUD Example

By Arvind Rai, May 24, 2017
This page will walk through Spring Boot REST + Angular + JPA + Hibernate + MySQL CRUD example. We will create a REST web service application using Spring Boot and a client application using Angular. REST web service will expose methods for create, read, update and delete operation. The Angular application will use Angular Http API for CRUD operation. If our client application is running on different domain from web service domain, then the Spring Boot web service controller will configure client domain URL using @CrossOrigin annotation to handle Cross-Origin-Resource-Sharing (CORS). Angular application will be single page application that will perform CRUD operation. On the basis of REST web service response HTTP status code, the Angular application will display messages for success and failure of CRUD operation. In our REST web service application we will expose two methods for read operation, one for fetching data by id and another for fetching all data. In our example we will perform CRUD operation on article. When we create article, the article id will be automatically generated by database. To fetch and delete article by id, we will use request parameter to pass article id from client to REST web service application. In our Spring Boot application, we will configure database using application.properties file. To interact with database we will use JPA EntityManager. Now find the complete client and REST web service application step by step.

HTTP URLs, Methods and Response Status Code for CRUD Operation

We will use following HTTP URLs, methods and response status code for CRUD operation in our example.
1. Create :
HTTP Method: POST, URL: /user/article
Angular API: Http.post()
HTTP Response Status Code: 201 CREATED and 409 CONFLICT

2. Read :
HTTP Method: GET, URL: /user/article?id={id} (Fetches article by id)
HTTP Method: GET, URL: /user/all-articles (Fetches all articles)
Angular API: Http.get()
HTTP Response Status Code: 200 OK

3. Update :
HTTP Method: PUT, URL: /user/article
Angular API: Http.put()
HTTP Response Status Code: 200 OK

4. Delete :
HTTP Method: DELETE, URL: /user/article?id={id}
Angular API: Http.delete()
HTTP Response Status Code: 204 NO CONTENT

The output of our Angular application for CRUD operation will be as follows.
Spring Boot REST + Angular 2/4 + JPA + Hibernate + MySQL CRUD Example

Create Operation using Angular Http.post()

We will perform create operation using Angular Http.post() method. It hits the request URL using HTTP POST method. Http.post() method syntax is as follows.
post(url: string, body: any, options?: RequestOptionsArgs) : Observable<Response> 
The description of parameters is given as below.
url: This is the REST web service URL to create article.
body: This is of any type object that will be passed to REST web service server. In our example we will create an Angular class as Article and pass its instance to body parameter.
options: This is optional. This accepts the instance of Angular RequestOptions that is instantiated using Angular RequestOptionsArgs. Using RequestOptions we pass request parameter, request headers etc.

Http.post() returns instance of Observable. Observable is a representation of any set of values over any amount of time.
Client Code
Find the client code to create the article. Here we will use Angular Http.post() method.
articleUrl = "http://localhost:8080/user/article";
createArticle(article: Article):Observable<number> {
    let cpHeaders = new Headers({ 'Content-Type': 'application/json' });
    let options = new RequestOptions({ headers: cpHeaders });
    return this.http.post(this.articleUrl, article, options)
        .map(success => success.status)
        .catch(this.handleError);
} 
We are passing header Content-Type as application/json. After successful operation we are returning status code as an instance of Observable.
Server Code
Find the web service method for create operation.
@PostMapping("article")
public ResponseEntity<Void> createArticle(@RequestBody Article article, UriComponentsBuilder builder) {
   boolean flag = articleService.createArticle(article);
   if (flag == false) {
       	return new ResponseEntity<Void>(HttpStatus.CONFLICT);
   }
   HttpHeaders headers = new HttpHeaders();
   headers.setLocation(builder.path("/article?id={id}").buildAndExpand(article.getArticleId()).toUri());
   return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
} 
In the above code Article is a java entity that is equivalent to Angular Article class. @PostMapping is request mapping for HTTP POST method. When the process is successful, it returns HTTP status 201 CREATED and URL for new article in location header. If the article already exists then the above server code will return HTTP status 09 CONFLICT

Read Operation using Angular Http.get()

We will perform read operation using Angular Http.get() method. It hits the URL using HTTP GET method. Find its syntax.
get(url: string, options?: RequestOptionsArgs) : Observable<Response> 
Find the description of the parameters.
url: Web service URL to read article.
options: This is optional. It is used to pass request parameter, headers etc.

Http.get() returns the instance of Observable.

Client Code
Find the Angular code using Http.get() that will pass request parameter to filter the result.
articleUrl = "http://localhost:8080/user/article";    
getArticleById(articleId: string): Observable<Article> {
   let cpHeaders = new Headers({ 'Content-Type': 'application/json' });
   let cpParams = new URLSearchParams();
   cpParams.set('id', articleId);			
   let options = new RequestOptions({ headers: cpHeaders, params: cpParams });
   return this.http.get(this.articleUrl, options)
	   .map(this.extractData)
	   .catch(this.handleError);
} 
The above code will fetch an article for the given id.
Now find the client code using angular that will fetch all articles from the server.
allArticlesUrl = "http://localhost:8080/user/all-articles";
getAllArticles(): Observable<Article[]> {
    return this.http.get(this.allArticlesUrl)
	.map(this.extractData)
        .catch(this.handleError);
} 

Server Code
Find the web service method that will accept request parameter to filter the result.
@GetMapping("article")
public ResponseEntity<Article> getArticleById(@RequestParam("id") String id) {
   Article article = articleService.getArticleById(Integer.parseInt(id));
   return new ResponseEntity<Article>(article, HttpStatus.OK);
} 
@GetMapping is the request mapping for the HTTP GET method. It accepts the article id as request parameter that is used to fetch article by id. On successful operation it will return the article for the given id and HTTP status code 200 OK.
Now find the web service method that will return all articles.
@GetMapping("all-articles")
public ResponseEntity<List<Article>> getAllArticles() {
	List<Article> list = articleService.getAllArticles();
	return new ResponseEntity<List<Article>>(list, HttpStatus.OK);
} 
On successful operation it will return all articles and HTTP status code 200 OK.

Update Operation using Angular Http.put()

We will perform update operation using Angular Http.put() method. It hits the URL using HTTP PUT method. Find its syntax.
put(url: string, body: any, options?: RequestOptionsArgs) : Observable<Response> 
Find the description of parameters.
url: This is the REST web service URL to update article.
body: This is of any type object that will be passed to REST web service server. In our example we will create an Angular class as Article and pass its instance to body parameter. The instance of Article will have article id on the basis of which other fields of article will be updated.
options: This is optional. This is used to pass request parameter, request headers etc.

Http.put() returns the instance of Observable.
Client Code
Find the angular code that is using Http.put() method to update the article.
articleUrl = "http://localhost:8080/user/article";
updateArticle(article: Article):Observable<number> {
    let cpHeaders = new Headers({ 'Content-Type': 'application/json' });
    let options = new RequestOptions({ headers: cpHeaders });
    return this.http.put(this.articleUrl, article, options)
          .map(success => success.status)
          .catch(this.handleError);
} 
In our Angular application we have created a class as Article and we are passing its instance to Http.put() method. The article will be updated on the basis of article id which is a field of our Angular Article class.
Server Code
Find the web service method to update the article.
@PutMapping("article")
public ResponseEntity<Article> updateArticle(@RequestBody Article article) {
	articleService.updateArticle(article);
	return new ResponseEntity<Article>(article, HttpStatus.OK);
} 
In the above code Article is a java entity that is equivalent to Angular Article class. @PutMapping is the request mapping with HTTP PUT method. On successful operation, the HTTP status 200 OK is returned.

Delete Operation using Angular Http.delete()

We will perform delete operation using Angular Http.delete() method. Http.delete() hits the URL using HTTP DELETE method. Find its syntax.
delete(url: string, options?: RequestOptionsArgs) : Observable<Response> 
Find the description of the parameters.
url: Web service URL to delete article.
options: This is optional. It is used to pass request parameter, headers etc.

Http.get() returns the instance of Observable.
Client Code
Find the client code using Http.delete() method to delete article by id.
articleUrl = "http://localhost:8080/user/article";
deleteArticleById(articleId: string): Observable<number> {
     let cpHeaders = new Headers({ 'Content-Type': 'application/json' });
     let cpParams = new URLSearchParams();
     cpParams.set('id', articleId);			
     let options = new RequestOptions({ headers: cpHeaders, params: cpParams });
     return this.http.delete(this.articleUrl, options)
	   .map(success => success.status)
	   .catch(this.handleError);
} 
In the request parameter we are passing article id to delete the article.
Server Code
Find the web service method that will delete the article for the given article id as request parameter.
@DeleteMapping("article")
public ResponseEntity<Void> deleteArticle(@RequestParam("id") String id) {
	articleService.deleteArticle(Integer.parseInt(id));
	return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
} 
On successful operation the HTTP status code 204 NO CONTENT is returned.

Complete Client Application using Angular with TypeScript

We will create complete client application using Angular with TypeScript. For development environment we are using Angular CLI. Our client project will be a separate project from the REST web service project. Now let us discuss the complete client project.

1. Technologies Used in Client Application

Find the technologies being used in our client application.
1. Angular 4.0.0
2. TypeScript 2.2.0
3. Node.js 6.10.1
4. Angular CLI 1.0.4
5. Angular Compiler CLI 4.0.0

2. Client Project Structure

Find the client project structure.
angular-demo
|
|--src
|   |
|   |--app 
|   |   |
|   |   |--article.component.ts
|   |   |--article.service.ts
|   |   |--article.ts
|   |   |--article.component.html
|   |   |--article.component.css
|   |   |
|   |   |--app.component.ts
|   |   |--app.module.ts 
|   | 
|   |--assets
|   |   |
|   |   |--images
|   |   |    |
|   |   |    |--loading.gif      
|   |   |
|   |   
|   |--main.ts
|   |--index.html
|   |--styles.css
|
|--node_modules
|--package.json 

3. Create Service for CRUD Operation using Angular Http API

We will create a service in which we will handle all HTTP operations to create, read, update and delete article. Angular provides Http class in @angular/http library that has methods get(), post(), put(), delete() etc. We will write create method using Http.post() method. To fetch the article we will create two methods using Http.get(), one for fetching article by id and another for fetching all articles. To update the article we will create update method using Http.put() and to delete the article we will create delete method using Http.delete(). Now find the service class.
article.service.ts
import { Injectable } from '@angular/core';
import { Http, Response, Headers, URLSearchParams, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';

import { Article } from './article';

@Injectable()
export class ArticleService {
    //URLs for CRUD operations
    allArticlesUrl = "http://localhost:8080/user/all-articles";
    articleUrl = "http://localhost:8080/user/article";
    //Create constructor to get Http instance
    constructor(private http:Http) { 
    }
    //Fetch all articles
    getAllArticles(): Observable<Article[]> {
        return this.http.get(this.allArticlesUrl)
	       .map(this.extractData)
	       .catch(this.handleError);

    }
    //Create article
    createArticle(article: Article):Observable<number> {
	let cpHeaders = new Headers({ 'Content-Type': 'application/json' });
        let options = new RequestOptions({ headers: cpHeaders });
        return this.http.post(this.articleUrl, article, options)
               .map(success => success.status)
               .catch(this.handleError);
    }
    //Fetch article by id
    getArticleById(articleId: string): Observable<Article> {
	let cpHeaders = new Headers({ 'Content-Type': 'application/json' });
	let cpParams = new URLSearchParams();
	cpParams.set('id', articleId);			
	let options = new RequestOptions({ headers: cpHeaders, params: cpParams });
	return this.http.get(this.articleUrl, options)
		.map(this.extractData)
		.catch(this.handleError);
    }	
    //Update article
    updateArticle(article: Article):Observable<number> {
	let cpHeaders = new Headers({ 'Content-Type': 'application/json' });
        let options = new RequestOptions({ headers: cpHeaders });
        return this.http.put(this.articleUrl, article, options)
               .map(success => success.status)
               .catch(this.handleError);
    }
    //Delete article	
    deleteArticleById(articleId: string): Observable<number> {
	let cpHeaders = new Headers({ 'Content-Type': 'application/json' });
	let cpParams = new URLSearchParams();
	cpParams.set('id', articleId);			
	let options = new RequestOptions({ headers: cpHeaders, params: cpParams });
	return this.http.delete(this.articleUrl, options)
	       .map(success => success.status)
	       .catch(this.handleError);
    }		
    private extractData(res: Response) {
	let body = res.json();
        return body;
    }
    private handleError (error: Response | any) {
	console.error(error.message || error);
	return Observable.throw(error.status);
    }
} 
article.ts
export class Article {
   constructor(public articleId: string, public title: string, public category: string) { 
   }
} 


4. Create Component and HTML Template for CRUD Operation

In our example we are creating Angular reactive form to submit the article that uses FormGroup and FormControl etc from @angular/forms library. We will create different methods to call service methods to handle CRUD operation for article. Now find the article component.
article.component.ts
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';

import { ArticleService } from './article.service';
import { Article } from './article';

@Component({
   selector: 'app-article',
   templateUrl: './article.component.html',
   styleUrls: ['./article.component.css']
})
export class ArticleComponent implements OnInit { 
   //Component properties
   allArticles: Article[];
   statusCode: number;
   requestProcessing = false;
   articleIdToUpdate = null;
   processValidation = false;
   //Create form
   articleForm = new FormGroup({
       title: new FormControl('', Validators.required),
       category: new FormControl('', Validators.required)	   
   });
   //Create constructor to get service instance
   constructor(private articleService: ArticleService) {
   }
   //Create ngOnInit() and and load articles
   ngOnInit(): void {
	   this.getAllArticles();
   }   
   //Fetch all articles
   getAllArticles() {
        this.articleService.getAllArticles()
	   .subscribe(
                data => this.allArticles = data,
                errorCode =>  this.statusCode = errorCode);   
   }
   //Handle create and update article
   onArticleFormSubmit() {
	  this.processValidation = true;   
	  if (this.articleForm.invalid) {
	       return; //Validation failed, exit from method.
	  }   
	  //Form is valid, now perform create or update
          this.preProcessConfigurations();
	  let title = this.articleForm.get('title').value.trim();
          let category = this.articleForm.get('category').value.trim();	  
	  if (this.articleIdToUpdate === null) {  
	    //Handle create article
	    let article= new Article(null, title, category);	  
	    this.articleService.createArticle(article)
	      .subscribe(successCode => {
		              this.statusCode = successCode;
			      this.getAllArticles();	
			      this.backToCreateArticle();
			},
		        errorCode => this.statusCode = errorCode);
	  } else {  
   	    //Handle update article
	    let article= new Article(this.articleIdToUpdate, title, category);	  
	    this.articleService.updateArticle(article)
	      .subscribe(successCode => {
		        this.statusCode = successCode;
			      this.getAllArticles();	
			      this.backToCreateArticle();
			},
		        errorCode => this.statusCode = errorCode);	  
	  }
   }
   //Load article by id to edit
   loadArticleToEdit(articleId: string) {
      this.preProcessConfigurations();
      this.articleService.getArticleById(articleId)
	      .subscribe(article => {
		            this.articleIdToUpdate = article.articleId;   
		            this.articleForm.setValue({ title: article.title, category: article.category });
			    this.processValidation = true;
			    this.requestProcessing = false;   
		    },
		    errorCode =>  this.statusCode = errorCode);   
   }
   //Delete article
   deleteArticle(articleId: string) {
      this.preProcessConfigurations();
      this.articleService.deleteArticleById(articleId)
	      .subscribe(successCode => {
		      this.statusCode = successCode;
		      this.getAllArticles();	
		      this.backToCreateArticle();
		   },
		   errorCode => this.statusCode = errorCode);    
   }
   //Perform preliminary processing configurations
   preProcessConfigurations() {
          this.statusCode = null;
	  this.requestProcessing = true;   
   }
   //Go back from update to create
   backToCreateArticle() {
          this.articleIdToUpdate = null;
          this.articleForm.reset();	  
	  this.processValidation = false;
   }
} 
article.component.html
<h1>Angular 2 CRUD Operation</h1>
<h3 *ngIf="articleIdToUpdate; else create"> 
   Update Article for Id: {{articleIdToUpdate}}
</h3>
<ng-template #create>
   <h3> Create New Article </h3>
</ng-template>
<div>
 <form [formGroup]="articleForm" (ngSubmit)="onArticleFormSubmit()">
  <table>
    <tr><td>Enter Title</td><td><input formControlName="title">
	       <label *ngIf="articleForm.get('title').invalid && processValidation" [ngClass] = "'error'"> Title is required. </label>
    </td></tr>
    <tr><td>Enter Category</td><td><input formControlName="category">
	       <label *ngIf="articleForm.get('category').invalid && processValidation" [ngClass] = "'error'"> Category is required. </label>
    </td></tr>	
    <tr><td colspan="2">
	    <button *ngIf="!articleIdToUpdate">CREATE</button>  
	    <button *ngIf="articleIdToUpdate">UPDATE</button>  
	    <button (click)="backToCreateArticle()" *ngIf="articleIdToUpdate">Go Back</button>  
    </td></tr>
  </table>
 </form> 
 <br/>
 <div *ngIf="statusCode; else processing">
   <div *ngIf="statusCode === 201" [ngClass] = "'success'">
	 Article added successfully.
   </div>   
   <div *ngIf="statusCode === 409" [ngClass] = "'success'">
        Article already exists.
   </div>   	
   <div *ngIf="statusCode === 200" [ngClass] = "'success'">
        Article updated successfully.
   </div>   	      
   <div *ngIf="statusCode === 204" [ngClass] = "'success'">
        Article deleted successfully.
   </div>   	   
   <div *ngIf="statusCode === 500" [ngClass] = "'error'">
        Internal Server Error.
   </div>   	
 </div>
 <ng-template #processing>
	<img *ngIf="requestProcessing" src="assets/images/loading.gif">
 </ng-template>
</div>
<h3>Article Details</h3>
<table>
  <tr><th> Id</th> <th>Title</th><th>Category</th><th></th><th></th></tr>
  <tr *ngFor="let article of allArticles" >
        <td>{{article.articleId}}</td> <td>{{article.title}}</td> <td>{{article.category}}</td>
	<td><button type="button" (click)="loadArticleToEdit(article.articleId)">Edit</button> </td> 
	<td><button type="button" (click)="deleteArticle(article.articleId)">Delete</button></td>
  </tr>
</table> 
article.component.css
h1 {
    font-size: 2.0em;
    margin: 20px 0 0 0;
    font-weight: 400;   
}
h3 { 
   color: blue;
}
table {
    border-collapse: collapse;
}
table, th, td {
    border: 1px solid black;
    font-size:17px;
}
input {
    width: 225px;
    margin: 8px 0;
    background-color: #dfdfdf;
    font-size:17px;
}
button {
    background-color: #008CBA;
    color: white;
}
.error{
    color: red;
    font-size: 20px;
}
.success{
    color: green;
    font-size: 20px;
} 

5. Create Application Component and Module

app.component.ts
import { Component } from '@angular/core';

@Component({
   selector: 'app-root',
   template: `
		<app-article></app-article>
             `
})
export class AppComponent { 
} 
app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent }  from './app.component';
import { ArticleComponent }  from './article.component';
import { ArticleService } from './article.service';

@NgModule({
  imports: [     
        BrowserModule,
	HttpModule,
	ReactiveFormsModule
  ],
  declarations: [
        AppComponent,
	ArticleComponent
  ],
  providers: [
        ArticleService
  ],
  bootstrap: [
        AppComponent
  ]
})
export class AppModule { } 

Complete REST Web Service Application using Spring Boot with Maven

Here we will create a complete REST web service application using Spring Boot with Maven. We will create a table in MySQL database and using JPA with Hibernate, our Spring Boot application will interact with database. While creating article we will not pass article id because article id will be automatically generated by database. In our web service controller we will expose methods for create, read, update and delete operation for the article.

1. Technologies Used in REST Web Service Application

Find the technologies being used in our REST web service application.
1. Java 8
2. Spring Boot 1.5.3.RELEASE
3. Maven 3.3
4. MySQL 5.5
5. Eclipse Mars

2. MySQL Database Schema

In our database we have created a table named as articles. Find the database schema.
Database Schema
-- Dumping database structure for concretepage
CREATE DATABASE IF NOT EXISTS `concretepage`;
USE `concretepage`;
-- Dumping structure for table concretepage.articles
CREATE TABLE IF NOT EXISTS `articles` (
  `article_id` int(5) NOT NULL AUTO_INCREMENT,
  `title` varchar(200) NOT NULL,
  `category` varchar(100) NOT NULL,
  PRIMARY KEY (`article_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;
-- Dumping data for table concretepage.articles: ~4 rows (approximately)
/*!40000 ALTER TABLE `articles` DISABLE KEYS */;
INSERT INTO `articles` (`article_id`, `title`, `category`) VALUES
	(1, 'Angular 2 Tutorial using CLI', 'Angular'),
	(2, 'Spring Boot Getting Started', 'Spring Boot'),
	(3, 'Lambda Expressions Java 8 Example', 'Java 8'),
	(4, 'Android AsyncTask Example', 'Android'); 
When we create article, the article id will be automatically generated by database. Now find the java entity for the above table.
Article.java
package com.concretepage.entity;
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;
@Entity
@Table(name="articles")
public class Article implements Serializable { 
	private static final long serialVersionUID = 1L;
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	@Column(name="article_id")
        private int articleId;  
	@Column(name="title")
        private String title;
	@Column(name="category")	
	private String category;
	public int getArticleId() {
		return articleId;
	}
	public void setArticleId(int articleId) {
		this.articleId = articleId;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getCategory() {
		return category;
	}
	public void setCategory(String category) {
		this.category = category;
	}
} 

3. Project Structure in Eclipse

Find the project structure in eclipse.
Spring Boot REST + Angular 2/4 + JPA + Hibernate + MySQL CRUD Example

4. Maven File

Find the Maven file used in our example.
pom.xml
<?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>
	<groupId>com.concretepage</groupId>
	<artifactId>spring-boot-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
	<name>spring-demo</name>
	<description>Spring Boot Demo Project</description>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.3.RELEASE</version>
	</parent>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<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>	
	    <dependency>
		    <groupId>mysql</groupId>
		    <artifactId>mysql-connector-java</artifactId>
	    </dependency>	 
    	<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency> 
	</dependencies> 
	<build>
	   <plugins>
		  <plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
		  </plugin>
	   </plugins>
	</build>
</project> 
Find the description of spring boot starter configured in maven file.
spring-boot-starter-parent: Parent POM for dependency management.
spring-boot-starter-web: Starter for building web, REST applications. It uses tomcat server as default embedded server.
spring-boot-starter-data-jpa: Starter for spring data JPA with hibernate.
spring-boot-devtools: It provides developer tools. These tools are helpful in application development mode. One of the features of developer tool is automatic restart of the server for any change in code.
spring-boot-maven-plugin: It is used to create executable JAR of the application.

5. Configure Properties in application.properties

The properties related to datasource, JPA using Hibernate and logging will be configured in application.properties file.
application.properties
#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/concretepage
spring.datasource.username=root
spring.datasource.password=
spring.datasource.tomcat.max-wait=20000
spring.datasource.tomcat.max-active=50
spring.datasource.tomcat.max-idle=20
spring.datasource.tomcat.min-idle=15

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect
spring.jpa.properties.hibernate.id.new_generator_mappings = false
spring.jpa.properties.hibernate.format_sql = true

logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE 

6. Create DAO for CRUD Operation

Find the DAO used in our example to perform CRUD operation. We will use JPA EntityManager to query database.
IArticleDAO.java
package com.concretepage.dao;
import java.util.List;
import com.concretepage.entity.Article;
public interface IArticleDAO {
    List<Article> getAllArticles();
    Article getArticleById(int articleId);
    void createArticle(Article article);
    void updateArticle(Article article);
    void deleteArticle(int articleId);
    boolean articleExists(String title, String category);
} 
ArticleDAO.java
package com.concretepage.dao;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.concretepage.entity.Article;
@Transactional
@Repository
public class ArticleDAO implements IArticleDAO {
	@PersistenceContext	
	private EntityManager entityManager;	
	@Override
	public Article getArticleById(int articleId) {
		return entityManager.find(Article.class, articleId);
	}
	@SuppressWarnings("unchecked")
	@Override
	public List<Article> getAllArticles() {
		String hql = "FROM Article as atcl ORDER BY atcl.articleId DESC";
		return (List<Article>) entityManager.createQuery(hql).getResultList();
	}	
	@Override
	public void createArticle(Article article) {
		entityManager.persist(article);
	}
	@Override
	public void updateArticle(Article article) {
		Article artcl = getArticleById(article.getArticleId());
		artcl.setTitle(article.getTitle());
		artcl.setCategory(article.getCategory());
		entityManager.flush();
	}
	@Override
	public void deleteArticle(int articleId) {
		entityManager.remove(getArticleById(articleId));
	}
	@Override
	public boolean articleExists(String title, String category) {
		String hql = "FROM Article as atcl WHERE atcl.title = ? and atcl.category = ?";
		int count = entityManager.createQuery(hql).setParameter(1, title)
		              .setParameter(2, category).getResultList().size();
		return count > 0 ? true : false;
	}
} 

7. Create Service

Find the service used in our example for CRUD operation.
IArticleService.java
package com.concretepage.service;
import java.util.List;
import com.concretepage.entity.Article;
public interface IArticleService {
     List<Article> getAllArticles();
     Article getArticleById(int articleId);
     boolean createArticle(Article article);
     void updateArticle(Article article);
     void deleteArticle(int articleId);
} 
ArticleService.java
package com.concretepage.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.concretepage.dao.IArticleDAO;
import com.concretepage.entity.Article;
@Service
public class ArticleService implements IArticleService {
	@Autowired
	private IArticleDAO articleDAO;
	@Override
	public Article getArticleById(int articleId) {
		Article obj = articleDAO.getArticleById(articleId);
		return obj;
	}	
	@Override
	public List<Article> getAllArticles(){
		return articleDAO.getAllArticles();
	}
	@Override
	public synchronized boolean createArticle(Article article){
               if (articleDAO.articleExists(article.getTitle(), article.getCategory())) {
    	           return false;
               } else {
    	           articleDAO.createArticle(article);
    	           return true;
               }
	}
	@Override
	public void updateArticle(Article article) {
		articleDAO.updateArticle(article);
	}
	@Override
	public void deleteArticle(int articleId) {
		articleDAO.deleteArticle(articleId);
	}
} 

8. REST Web Service Controller

Find the REST web service controller that will expose web service method for CRUD operation.
ArticleController.java
package com.concretepage.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.util.UriComponentsBuilder;
import com.concretepage.entity.Article;
import com.concretepage.service.IArticleService;
@Controller
@RequestMapping("user")
@CrossOrigin(origins = {"http://localhost:4200"})
public class ArticleController {
	@Autowired
	private IArticleService articleService;
	@GetMapping("article")
	public ResponseEntity<Article> getArticleById(@RequestParam("id") String id) {
		Article article = articleService.getArticleById(Integer.parseInt(id));
		return new ResponseEntity<Article>(article, HttpStatus.OK);
	}
	@GetMapping("all-articles")
	public ResponseEntity<List<Article>> getAllArticles() {
		List<Article> list = articleService.getAllArticles();
		return new ResponseEntity<List<Article>>(list, HttpStatus.OK);
	}
	@PostMapping("article")
	public ResponseEntity<Void> createArticle(@RequestBody Article article, UriComponentsBuilder builder) {
		boolean flag = articleService.createArticle(article);
		if (flag == false) {
		     return new ResponseEntity<Void>(HttpStatus.CONFLICT);
		}
		HttpHeaders headers = new HttpHeaders();
		headers.setLocation(builder.path("/article?id={id}").buildAndExpand(article.getArticleId()).toUri());
		return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
	}
	@PutMapping("article")
	public ResponseEntity<Article> updateArticle(@RequestBody Article article) {
		articleService.updateArticle(article);
		return new ResponseEntity<Article>(article, HttpStatus.OK);
	}
	@DeleteMapping("article")
	public ResponseEntity<Void> deleteArticle(@RequestParam("id") String id) {
		articleService.deleteArticle(Integer.parseInt(id));
		return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
	}	
} 
@CrossOrigin annotation handles Cross-Origin-Resource-Sharing (CORS). This annotation can be used at class level as well as method level in RESTful Web service controller. In our example Angular project will run on following URL.
http://localhost:4200 
And REST webs service project will run on following URL.
http://localhost:8080 
To allow our Angular project script to hit the web service we need to configure @CrossOrigin as follows
@CrossOrigin(origins = {"http://localhost:4200"}) 
We are using it at class level so that all the REST web service method will be available to our Angular application.

9. Create Java Main Class to Run Spring Boot Application

Create a java class with main() method that will call SpringApplication.run() to run the application.
MyApplication.java
package com.concretepage;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {  
    public static void main(String[] args) {
	SpringApplication.run(MyApplication.class, args);
    }       
} 
We need to annotate above class with @SpringBootApplication that is equivalent to @Configuration, @EnableAutoConfiguration and @ComponentScan annotations.

Run REST Web Service and Angular Application

Find the steps to run REST web service application and angular application.

1. Run REST Web Service using Spring Boot

To run the REST web service application, first create table in MySQL as given in the example. Now we can run REST web service in following ways.
1. Using Eclipse: Download the web service project source code using download link given on this page in download section. Import the project into eclipse. Using command prompt, go to the root folder of the project and run.
mvn clean eclipse:eclipse 
and then refresh the project in eclipse. Run Main class MyApplication by clicking Run as -> Java Application. Embedded tomcat server will be started.

2. Using Maven Command: Download the web service project source code. Go to the root folder of the project using command prompt and run the command.
mvn spring-boot:run 
Embedded tomcat server will be started.

3. Using Executable JAR: Using command prompt, go to the root folder of the project and run the command.
mvn clean package 
We will get executable JAR spring-boot-demo-0.0.1-SNAPSHOT.jar in target folder. Run this JAR as
java -jar target/spring-boot-demo-0.0.1-SNAPSHOT.jar 
Embedded tomcat server will be started.

2. Run Angular Application using Angular CLI

To run the angular application, find the following steps.
1. Install Angular CLI QUICKSTART using the link.
2. Download Angular project source code using download link given on this page in download section.
3. In your angular CLI application, replace src folder by the downloaded one.
4. Run ng serve command.
5. Our Angular application is ready on the following URL.
http://localhost:4200
a. Find the print screen when creating article. We will get validation messages when we click on CREATE button without entering data.
Spring Boot REST + Angular 2/4 + JPA + Hibernate + MySQL CRUD Example
Enter the data in the form fields and click on CREATE button to create the new article.

b. When we click on EDIT button, we load article in form fields to update. Find the print screen.
Spring Boot REST + Angular 2/4 + JPA + Hibernate + MySQL CRUD Example
Click on UPDATE button to update the article for the given article id. By clicking on Go Back button we can return back to CREATE screen. Using DELETE button we can delete the article.

I am done now. Happy Spring Boot learning with Angular 2+ !

References

Angular Http
Spring Boot REST + JPA + Hibernate + MySQL Example
Angular 2 Http get() Parameters + Headers + URLSearchParams + RequestOptions Example
Angular 2 Http post() Example

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI









©2023 concretepage.com | Privacy Policy | Contact Us