Spring Boot REST + Angular 2/4 + JPA + Hibernate + MySQL CRUD Example
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.
Contents
- HTTP URLs, Methods and Response Status Code for CRUD Operation
- Create Operation using Angular Http.post()
- Read Operation using Angular Http.get()
- Update Operation using Angular Http.put()
- Delete Operation using Angular Http.delete()
- Complete Client Application using Angular with TypeScript
- 1. Technologies Used in Client Application
- 2. Client Project Structure
- 3. Create Service for CRUD Operation using Angular Http API
- 4. Create Component and HTML Template for CRUD Operation
- 5. Create Application Component and Module
- Complete REST Web Service Application using Spring Boot with Maven
- 1. Technologies Used in REST Web Service Application
- 2. MySQL Database Schema
- 3. Project Structure in Eclipse
- 4. Maven File
- 5. Configure Properties in application.properties
- 6. Create DAO for CRUD Operation
- 7. Create Service
- 8. REST Web Service Controller
- 9. Create Java Main Class to Run Spring Boot Application
- Run REST Web Service and Angular Application
- 1. Run REST Web Service using Spring Boot
- 2. Run Angular Application using Angular CLI
- References
- Download Source Code
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.

Create Operation using Angular Http.post()
We will perform create operation using AngularHttp.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>
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); }
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); }
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 AngularHttp.get()
method. It hits the URL using HTTP GET method. Find its syntax.
get(url: string, options?: RequestOptionsArgs) : Observable<Response>
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); }
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); }
Update Operation using Angular Http.put()
We will perform update operation using AngularHttp.put()
method. It hits the URL using HTTP PUT method. Find its syntax.
put(url: string, body: any, options?: RequestOptionsArgs) : Observable<Response>
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); }
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); }
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 AngularHttp.delete()
method. Http.delete()
hits the URL using HTTP DELETE method. Find its syntax.
delete(url: string, options?: RequestOptionsArgs) : Observable<Response>
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); }
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); }
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 providesHttp
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); } }
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 usesFormGroup
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; } }
<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>
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.tsimport { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` <app-article></app-article> ` }) export class AppComponent { }
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 asarticles
. 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');
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.
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>
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 inapplication.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 JPAEntityManager
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); }
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); }
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
http://localhost:8080
@CrossOrigin
as follows
@CrossOrigin(origins = {"http://localhost:4200"})
9. Create Java Main Class to Run Spring Boot Application
Create a java class withmain()
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); } }
@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
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
3. Using Executable JAR: Using command prompt, go to the root folder of the project and run the command.
mvn clean package
java -jar target/spring-boot-demo-0.0.1-SNAPSHOT.jar
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.

b. When we click on EDIT button, we load article in form fields to update. Find the print screen.

I am done now. Happy Spring Boot learning with Angular 2+ !
References
Angular HttpSpring Boot REST + JPA + Hibernate + MySQL Example
Angular 2 Http get() Parameters + Headers + URLSearchParams + RequestOptions Example
Angular 2 Http post() Example