[Spring Boot] Spring Boot REST + Angular 2/4 + JPA + Hibernate + MySQL CRUD example

Posted by Smifffy on Fri, 22 Oct 2021 06:41:39 +0200

This page will introduce an example of CRUD using Spring Boot REST + Angular + JPA + Hibernate + MySQL.

We will create a REST web service application using Spring Boot and a client application using angular. REST Web Services expose the methods of creating, reading, updating, and deleting operations. Angular applications will use angular's Http API for CRUD operations. If our client application runs on a domain different from the web service domain, the Spring Boot Web service controller will use the @ CrossOrigin annotation to configure the URL of the client domain to handle cross domain resource sharing (CORS).

The Angular application will be a single page application that will perform CRUD operations. Based on the HTTP status code of the REST network service response, the Angular application will display the success and failure information of the crud operation.

In our REST Web service application, we will provide two methods for reading operations, one for getting data by ID and the other for getting all data. In our example, we will CRUD the article table. When we create an article, the article ID will be automatically generated by the database. In order to get and delete articles by ID, we will pass the ID of the article from the client to the REST Web service application using the request parameters.

In our Spring Boot application, we will use the application.properties file to configure the database. To interact with the database, we will use JPA EntityManager. Now find the steps for a complete client and REST web services application.

HTTP URL, method and response status code of CRUD operation

In our example, we will use the following HTTP URL, method and response status code for CRUD operation.
1. Create :

HTTP method: POST, web address: / user/article

Angular API: Http.post()

HTTP response status codes: 201 CREATED and 409 CONFLICT

2. Read :

HTTP method: GET, web address: / user/article?id={id} (Fetches article by id)

HTTP method: GET, web address: / user / all articles (fetches all articles)

Angular API: Http.get()

HTTP response status code: 200 OK

3. Update :

HTTP method: PUT, website: / user/article

Angular API: Http.put()

HTTP response status code: 200 OK

4. Delete :
HTTP method: DELETE, web address: / user/article?id={id}

Angular API: Http.delete()

HTTP response status code: 204 NO CONTENT

The output of the CRUD operation of our Angular application will be as follows.

Use Angular's Http.post() to create

We will use Angular's Http.post() method for the creation operation. It uses the HTTP POST method to access the URL. The syntax of the Http.post() method is as follows.

post(url: string, body: any, options?: RequestOptionsArgs) : Observable<Response> 

The parameters are described below.

URL: This is the URL of the REST web service that created the article.

Body: This is an object of any type that will be passed to the REST web service server. In our example, we will create an Angular class Article and pass its instance to the body parameter.

options: This is optional. It accepts the instance of Angular RequestOptions, which is instantiated with Angular RequestOptionsArgs. Using RequestOptions, we pass request parameters, request header information, etc.

Http.post() returns an instance of observable. Observable is a representation of any set of values at any time.

Client code

Find the client code to create the article. Here we will use Angular's 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 pass the header information content type as application/json. After the operation is successful, we return the status code as an instance of Observable.

Server code
Find the Web service method to create the 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, equivalent to the Article class of Angular@ PostMapping is the request mapping of the HTTP POST method. When the process is successful, it returns the HTTP status 201 CREATED and the URL of the new Article in the location header. If the Article already exists, the above server code will return HTTP status 09 CONFLICT.

Use Http.get() of Angular to read

We will use Angular's Http.get() method for reading. It uses the HTTP GET method to access the URL. Find its syntax.

get(url: string, options?: RequestOptionsArgs) : Observable<Response> 

Find parameter description.

URL: the Web service URL to read the article.

options: This is optional. It is used to pass request parameters, header files, etc.

Http.get() returns an instance of Observable.

Client code

Find the Angular code using Http.get(), which passes the request parameters to filter the results.

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 get the article with the specified id.

Now look for the angular client code, which will get all the 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 network service method that will accept the request parameters to filter the results.

@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 of the HTTP GET method. It accepts the id of the article as the request parameter and is used to get the article by id. After the operation is successful, it will return the article with 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);
} 

After the operation is successful, it will return all articles and HTTP status code 200 OK.

Use Http.put() of Angular to update

We will use Angular's Http.put() method for the update operation. It uses the HTTP PUT method to access the URL. Find its syntax.

put(url: string, body: any, options?: RequestOptionsArgs) : Observable<Response> 

Find parameter description.
URL: This is the REST web service URL used to update the article.

Body: This is an object of any type that will be passed to the REST web service server. In our example, we will create an Angular Article class and pass its instance to the body parameter. The instance of the Article must have the ID of the Article, and other fields of the Article will be updated on this basis.

options: This is optional. This is used to pass request parameters and request header information.

Http.put() returns an Observable instance.

Client code

Find the angular code that uses the 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 an Article class and passed its instance to the Http.put() method. The Article will be updated based on the 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, equivalent to the Article class of Angular@ PutMapping is the request mapping of the HTTP PUT method. After the operation is successful, the HTTP status 200 OK will be returned.

Use Http.delete() of Angular to delete

We will use Angular's Http.delete() method to delete. Http.delete() uses the HTTP DELETE method to access the URL. Find its syntax.

delete(url: string, options?: RequestOptionsArgs) : Observable<Response> 

Find parameter description.

URL: the URL of the Web service used to delete the article.

options: This is optional. It is used to pass request parameters, header files, etc.

Http.get() returns an Observable instance.

Client code

Find the client code using Http.delete() method and delete the 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 pass the article ID to delete the article.

Server code

Find the network service method that will delete the article with the given article ID as the request parameter.

@DeleteMapping("article")
public ResponseEntity<Void> deleteArticle(@RequestParam("id") String id) {
	articleService.deleteArticle(Integer.parseInt(id));
	return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
} 

After the operation is successful, the HTTP status code 204 NO CONTENT will be returned.

Complete client application using Angular and TypeScript

We will use Angular and TypeScript to create a complete client application. For the development environment, we use Angular CLI. Our client project will be a separate project from the REST web service project. Now let's talk about the complete client project.

1. Technologies used in client applications

  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. Customer 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. Use Angular's Http API to create services for CRUD operations

We will create a service where we will handle all HTTP operations to create, read, update, and delete articles. Angular provides HTTP classes in the @ angular/http library. It has get(), post(), put (), delete () and other methods. We will write the creation method using the Http.post() method. To get articles, we will use Http.get() to create two methods, one for getting articles by ID and the other for getting all articles. To update an article, we will use Http.put() to create an update method, and to delete an article, we will use Http.delete() to create a delete method. 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 components and HTML templates for CRUD operations

In our example, we are creating an Angular responsive form to submit articles, which uses FormGroup and FormControl in the @ angular/forms library. We will create different methods to call service methods to handle the CRUD operation of the 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 components and modules

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 Maven's Spring Boot

Here, we will use Spring Boot and Maven to create a complete REST Web service application. We will create a table in the MySQL database. Using JPA and Hibernate, our Spring Boot application will interact with the database. When creating an article, we will not pass the article ID because the article ID will be automatically generated by the database. In our Web service controller, we will expose the methods of creating, reading, updating and deleting articles.

1. Technologies used in rest network service applications

  1. Java 8
  2. Spring Boot 1.5.3.RELEASE
  3. Maven 3.3
  4. MySQL 5.5
  5. Eclipse Mars

2. MySQL database structure

In our database, we created a table called articles. Find the structure of the database.

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 an article, the article ID will be automatically generated by the database. Now find the corresponding 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

4. Maven document

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> 

Locate the description of the spring boot initiator configured in the maven file.

Spring boot starter parent: parent POM for dependency management.

Spring boot starter Web: a launcher for building web and REST applications. It uses the Tomcat server as the default embedded server.

Spring boot starter data JPA: the startup program of spring data JPA with hibernate.

Spring boot devtools: it provides developer tools. These tools are very helpful in application development mode. A feature of developer tools is to automatically restart the server when any code changes.

Spring boot Maven plugin: it is used to create the executable JAR of the application.

5. Configure properties in application.properties

The properties related to the data source, JPA using Hibernate and logs will be configured in the 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

In our example, find the DAO used to perform CRUD operations. We will use JPA EntityManager to query the 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

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. Create Controller

Find the REST network service controller, which exposes the network service methods for CRUD operations.

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

@The cross origin annotation can handle cross resource sharing (CORS). This annotation can be used at the class and method levels of the RESTful Web service controller. In our example, the Angular project will run on the following URL.

http://localhost:4200 

The REST web service project will run on the following URL.

http://localhost:8080 

In order for our Angular project script to access network services, we need to configure @ CrossOrigin as follows

@CrossOrigin(origins = {"http://localhost:4200"}) 

We use it at the class level so that all REST web service methods can be used in our Angular application.

9. Create a Java main class to run the Spring Boot application

Create a java class with a 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 the above classes with @ SpringBootApplication, which is equivalent to @ Configuration, @ EnableAutoConfiguration and @ ComponentScan annotations.

Running REST web services and Angular applications

Find the steps to run the REST Web Services Application and the angular application.

1. Use Spring Boot to run REST network services

To run the REST web service application, first create a table in MySQL, as shown in the example. Now we can run REST web services in the following ways.

1. Using Eclipse: use the download link given in the download section of this page to download the source code of the Web service project. Import the project into eclipse. Using the command prompt, go to the root folder of the project and run.

mvn clean eclipse:eclipse 

Then refresh the project in eclipse. Run the main class MyApplication by clicking run as - > java application. The embedded tomcat server will be started.

2. Use Maven command: download the source code of the Web service project. Use the command prompt to enter the root folder of the project and run the command.

mvn spring-boot:run 

The embedded tomcat server will be started.

3. Use executable jars: use the command prompt to enter the root folder of the project and run the command.

mvn clean package 

We will get the executable JAR package spring-boot-demo-0.0.1-SNAPSHOT.jar in the target folder. Run the JAR as follows

java -jar target/spring-boot-demo-0.0.1-SNAPSHOT.jar 

The embedded tomcat server will be started.

2. Run the Angular application using the Angular CLI

To run the angular application, find the following steps.

1. Visit link Install angular cli quickstar.

2. Use the download link given in the download section of this page to download the source code of Angular project.

3. In your angular CLI application, replace the src folder with the downloaded folder.

4. Run the ng serve command.

5. Our Angular application is ready on the following website.

http://localhost:4200

a. Visit the link. When we click the CREATE button without entering data, we will get the following verification information.


Enter data in the table field and click the CREATE button to CREATE a new article.

b. When we click the "EDIT" button, we load the article in the table field to update, as shown in the figure.

Click the UPDATE button to UPDATE the article with the given article ID. By clicking the "Go Back" button, we can return to the "CREATE" page. Using the DELETE button, we can DELETE the article.

reference

[1]Angular Http
[2]Spring Boot REST + JPA + Hibernate + MySQL Example
[3]Angular 2 Http get() Parameters + Headers + URLSearchParams + RequestOptions Example
[4]Angular 2 Http post() Example
[5]Spring Boot REST + Angular 2/4 + JPA + Hibernate + MySQL CRUD Example

Source download

Extraction code: mao4

[1] Server code
[2] Client code

Topics: Hibernate Spring Boot