{"id":92000,"date":"2019-05-27T08:05:19","date_gmt":"2019-05-27T05:05:19","guid":{"rendered":"http:\/\/www.javacodegeeks.com\/?p=92000"},"modified":"2019-06-03T09:21:09","modified_gmt":"2019-06-03T06:21:09","slug":"angular-spring-boot-build-crud-app-today","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2019\/05\/angular-spring-boot-build-crud-app-today.html","title":{"rendered":"Angular 8 + Spring Boot 2.2: Build a CRUD App Today!"},"content":{"rendered":"<p><span style=\"font-size: 20px;\"><b>\u201cI love writing authentication and authorization code.\u201d ~ No Java Developer Ever.<\/b> Tired of building the same login screens over and over? <a href=\"https:\/\/developer.okta.com\/signup\/?utm_campaign=text_website_all_multiple_dev_ciam_angular-8-spring-boot-2_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Try the Okta API for hosted authentication, authorization, and multi-factor auth.<\/a><\/span><\/p>\n<p>If you\u2019ve been a Java developer for more than 15 years, you probably remember when there were a plethora of Java web frameworks. It started with Struts and WebWork. Then Tapestry, Wicket, and JSF came along and championed the idea of component-based frameworks. Spring MVC was released in 2004 (in the same month as Flex 1.0 and JSF 1.0) and became the de-facto standard in Java web frameworks over the next six years.<\/p>\n<p>Then along came AngularJS and everyone started moving their UI architectures to JavaScript. Angular 2 was announced at the same time that Spring Boot was first revealed in 2014, and it took a couple of years for it to be released, solidify, and become a viable option. These days, we call it Angular, with no version number. The last few releases have been pretty darn stable, with smooth upgrade paths between major releases.<\/p>\n<p>Today, I\u2019d like to show you how to build an app with the latest and greatest versions of Angular and Spring Boot. Angular 8 and Spring Boot 2.2 both come with performance improvements to make your developer life better.<\/p>\n<h2 class=\"wp-block-heading\" id=\"whats-new-in-angular-8\">What\u2019s New in Angular 8?<\/h2>\n<p>Angular 8 adds differential loading, an optional Ivy Renderer, and Bazel as a build option. Differential loading is where the CLI builds two separate bundles as part of your deployed application. The modern bundle is served to evergreen browsers, while the legacy bundle contains all the necessary polyfills for older browsers.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/1.jpg\" alt=\"CRUD App\" class=\"wp-image-92009\" width=\"720\" height=\"405\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/1.jpg 960w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/1-300x169.jpg 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/1-768x432.jpg 768w\" sizes=\"(max-width: 720px) 100vw, 720px\" \/><\/figure>\n<\/div>\n<p>The Ivy Renderer is smaller, faster, simpler to debug, has improved type checking, and \u2013 most importantly \u2013 is backward compatible.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/ivy-renderer-slide.jpg\" alt=\"CRUD App\" class=\"wp-image-92010\" width=\"720\" height=\"405\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/ivy-renderer-slide.jpg 960w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/ivy-renderer-slide-300x169.jpg 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/ivy-renderer-slide-768x432.jpg 768w\" sizes=\"(max-width: 720px) 100vw, 720px\" \/><\/figure>\n<\/div>\n<h2 class=\"wp-block-heading\" id=\"whats-new-in-spring-boot-22\">What\u2019s New in Spring Boot 2.2?<\/h2>\n<p>Spring Boot, feeling some heat from quick-starting frameworks like Micronaut and Quarkus, has made many performance improvements as well. JMX is now disabled by default, Hibernate\u2019s entity scanning is disabled, and lazy initialization of beans is on by default. In addition, startup time and memory usage have been reduced by making use of&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">proxyBeanMethods=false<\/code>&nbsp;in Spring Boot\u2019s&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">@Configuration<\/code>&nbsp;classes. See&nbsp;<a href=\"https:\/\/github.com\/spring-projects\/spring-boot\/wiki\/Spring-Boot-2.2-Release-Notes\">Spring Boot 2.2 Release Notes<\/a>&nbsp;for more information.<\/p>\n<p>If you\u2019re stuck on older versions of these frameworks, you might want to check out a couple of my previous posts:<\/p>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2018\/08\/22\/basic-crud-angular-7-and-spring-boot-2?utm_campaign=text_website_all_multiple_dev_ciam_angular-8-spring-boot-2_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Build a Basic CRUD App with Angular 7.0 and Spring Boot 2.1<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2017\/12\/04\/basic-crud-angular-and-spring-boot?utm_campaign=text_website_all_multiple_dev_ciam_angular-8-spring-boot-2_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Build a Basic CRUD App with Angular 5.0 and Spring Boot 2.0<\/a><\/li>\n<\/ul>\n<p>This post describes how to build a simple CRUD application that displays a list of cool cars. It\u2019ll allow you to edit the cars, and it\u2019ll show an animated gif from&nbsp;<a href=\"http:\/\/giphy.com\/\">GIPHY<\/a>&nbsp;that matches the car\u2019s name. You\u2019ll also learn how to secure your application using Okta\u2019s Spring Boot starter and Angular SDK. Below is a screenshot of the app when it\u2019s completed.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/success-at-last-1024x669.png\" alt=\"CRUD App\" class=\"wp-image-92011\" width=\"768\" height=\"502\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/success-at-last-1024x669.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/success-at-last-300x196.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/success-at-last-768x502.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/success-at-last.png 1600w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure>\n<\/div>\n<p>You will need&nbsp;<a href=\"https:\/\/adoptopenjdk.net\/\">Java 11<\/a>&nbsp;and&nbsp;<a href=\"https:\/\/nodejs.org\/\">Node.js 10+<\/a>&nbsp;installed to complete this tutorial.<\/p>\n<h2 class=\"wp-block-heading\" id=\"build-an-api-with-spring-boot-22\">Build an API with Spring Boot 2.2<\/h2>\n<p>To get started with&nbsp;<a href=\"https:\/\/projects.spring.io\/spring-boot\/\">Spring Boot<\/a>&nbsp;2.2, head on over to&nbsp;<a href=\"https:\/\/start.spring.io\/\">start.spring.io<\/a>&nbsp;and create a new project that uses Java 11 (under more options), Spring Boot version 2.2.0 M2, and dependencies to create a secure API: JPA, H2, Rest Repositories, Lombok, Okta, and Web.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/start.spring.io_-1024x576.gif\" alt=\"CRUD App\" class=\"wp-image-92012\" width=\"768\" height=\"432\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/start.spring.io_-1024x576.gif 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/start.spring.io_-300x169.gif 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/start.spring.io_-768x432.gif 768w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure>\n<\/div>\n<p>Create a directory to hold your server and client applications. I called mine&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">okta-spring-boot-2-angular-8-example<\/code>, but you can call yours whatever you like.<\/p>\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>If you\u2019d rather see the app running than write code, you can&nbsp;<a href=\"https:\/\/github.com\/oktadeveloper\/okta-spring-boot-2-angular-8-example\">see the example on GitHub<\/a>, or clone and run locally using the commands below.<\/p>\n<\/blockquote>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">git clone https:\/\/github.com\/oktadeveloper\/okta-spring-boot-2-angular-8-example.git\ncd okta-spring-boot-2-angular-8-example\/client\nnpm install\nng serve &amp;\ncd ..\/server\n.\/mvnw spring-boot:run\n<\/pre>\n<p>After downloading&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">demo.zip<\/code>&nbsp;from start.spring.io, expand it and copy the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">demo<\/code>&nbsp;directory to your app-holder directory. Rename&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">demo<\/code>&nbsp;to&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">server<\/code>. Open&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">server\/pom.xml<\/code>&nbsp;and comment out the dependency on Okta\u2019s Spring Boot starter.<\/p>\n<pre class=\"gutter: false;brush:xml\">&lt;!--dependency&gt;\n    &lt;groupId&gt;com.okta.spring&lt;\/groupId&gt;\n    &lt;artifactId&gt;okta-spring-boot-starter&lt;\/artifactId&gt;\n    &lt;version&gt;1.1.0&lt;\/version&gt;\n&lt;\/dependency--&gt;\n<\/pre>\n<p>Open the project in your favorite IDE and create a&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Car.java<\/code>&nbsp;class in the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">src\/main\/java\/com\/okta\/developer\/demo<\/code>directory. You can use Lombok\u2019s annotations to reduce boilerplate code.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">package com.okta.developer.demo;\n\nimport lombok.*;\n\nimport javax.persistence.Id;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Entity;\n\n@Entity\n@Data\n@NoArgsConstructor\npublic class Car {\n    @Id @GeneratedValue\n    private Long id;\n    private @NonNull String name;\n}\n<\/pre>\n<p>Create a&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">CarRepository<\/code>&nbsp;class to perform CRUD (create, read, update, and delete) on the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Car<\/code>&nbsp;entity.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">package com.okta.developer.demo;\n\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.rest.core.annotation.RepositoryRestResource;\n\n@RepositoryRestResource\ninterface CarRepository extends JpaRepository&lt;Car, Long&gt; {\n}\n<\/pre>\n<p>Add an&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">ApplicationRunner<\/code>&nbsp;bean to the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">DemoApplication<\/code>&nbsp;class (in&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">src\/main\/java\/com\/okta\/developer\/demo\/DemoApplication.java<\/code>) and use it to add some default data to the database.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">package com.okta.developer.demo;\n\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\nimport java.util.stream.Stream;\n\n@SpringBootApplication\npublic class DemoApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(DemoApplication.class, args);\n    }\n\n    @Bean\n    ApplicationRunner init(CarRepository repository) {\n        return args -&gt; {\n            Stream.of(\"Ferrari\", \"Jaguar\", \"Porsche\", \"Lamborghini\", \"Bugatti\",\n                      \"AMC Gremlin\", \"Triumph Stag\", \"Ford Pinto\", \"Yugo GV\").forEach(name -&gt; {\n                Car car = new Car();\n                car.setName(name);\n                repository.save(car);\n            });\n            repository.findAll().forEach(System.out::println);\n        };\n    }\n}\n<\/pre>\n<p>If you start your app (using&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.\/mvnw spring-boot:run<\/code>) after adding this code, you\u2019ll see the list of cars displayed in your console on startup.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">Car(id=1, name=Ferrari)\nCar(id=2, name=Jaguar)\nCar(id=3, name=Porsche)\nCar(id=4, name=Lamborghini)\nCar(id=5, name=Bugatti)\nCar(id=6, name=AMC Gremlin)\nCar(id=7, name=Triumph Stag)\nCar(id=8, name=Ford Pinto)\nCar(id=9, name=Yugo GV)\n<\/pre>\n<p><strong>NOTE:<\/strong>&nbsp;If you see&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Fatal error compiling: invalid target release: 11<\/code>, it\u2019s because you\u2019re using Java 8. If you change to use Java 11, this error will go away. If you\u2019re using&nbsp;<a href=\"https:\/\/sdkman.io\/\">SDKMAN<\/a>, run&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">sdk install java 11.0.2-open<\/code>&nbsp;followed by&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">sdk default java 11.0.2-open<\/code>.<\/p>\n<p>Add a&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">CoolCarController<\/code>&nbsp;class (in&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">src\/main\/java\/com\/okta\/developer\/demo<\/code>) that returns a list of cool cars to display in the Angular client.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">package com.okta.developer.demo;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport java.util.Collection;\nimport java.util.stream.Collectors;\n\n@RestController\nclass CoolCarController {\n    private CarRepository repository;\n\n    public CoolCarController(CarRepository repository) {\n        this.repository = repository;\n    }\n\n    @GetMapping(\"\/cool-cars\")\n    public Collection&lt;Car&gt; coolCars() {\n        return repository.findAll().stream()\n                .filter(this::isCool)\n                .collect(Collectors.toList());\n    }\n\n    private boolean isCool(Car car) {\n        return !car.getName().equals(\"AMC Gremlin\") &amp;&amp;\n                !car.getName().equals(\"Triumph Stag\") &amp;&amp;\n                !car.getName().equals(\"Ford Pinto\") &amp;&amp;\n                !car.getName().equals(\"Yugo GV\");\n    }\n}\n<\/pre>\n<p>If you restart your server and hit&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http:\/\/localhost:8080\/cool-cars<\/code>&nbsp;with your browser, or a command-line client, you should see the filtered list of cars.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">$ http :8080\/cool-cars\nHTTP\/1.1 200\nContent-Type: application\/json;charset=UTF-8\nDate: Tue, 07 May 2019 18:07:33 GMT\nTransfer-Encoding: chunked\n\n[\n    {\n        \"id\": 1,\n        \"name\": \"Ferrari\"\n    },\n    {\n        \"id\": 2,\n        \"name\": \"Jaguar\"\n    },\n    {\n        \"id\": 3,\n        \"name\": \"Porsche\"\n    },\n    {\n        \"id\": 4,\n        \"name\": \"Lamborghini\"\n    },\n    {\n        \"id\": 5,\n        \"name\": \"Bugatti\"\n    }\n]\n<\/pre>\n<h2 class=\"wp-block-heading\" id=\"create-a-client-with-angular-cli\">Create a Client with Angular CLI<\/h2>\n<p>Angular CLI is a command-line utility that can generate an Angular project for you. Not only can it create new projects, but it can also generate code. It\u2019s a convenient tool because it also offers commands that will build and optimize your project for production. It uses webpack under the covers for building.<\/p>\n<p>Install the latest version of Angular CLI (which is version v8.0.0-rc.3 at the time of this writing).<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">npm i -g @angular\/cli@v8.0.0-rc.3<\/pre>\n<p>Create a new project in the umbrella directory you created.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">ng new client --routing --style css --enable-ivy\n<\/pre>\n<p>After the client is created, navigate into its directory, remove&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.git<\/code>, and install Angular Material.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">cd client\nrm -rf .git # optional: .git won't be created if you don't have Git installed\nng add @angular\/material\n<\/pre>\n<p>When prompted for the theme and other options, select the defaults.<\/p>\n<p>You\u2019ll use Angular Material\u2019s components to make the UI look better, especially on mobile phones. If you\u2019d like to learn more about Angular Material, see&nbsp;<a href=\"https:\/\/material.angular.io\/\">material.angular.io<\/a>. It has extensive documentation on its various components and how to use them. The paint bucket in the top right corner will allow you to preview available theme colors.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/material.angular.io_-1024x704.png\" alt=\"CRUD App\" class=\"wp-image-92013\" width=\"768\" height=\"528\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/material.angular.io_-1024x704.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/material.angular.io_-300x206.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/material.angular.io_-768x528.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/material.angular.io_.png 1600w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure>\n<\/div>\n<h2 class=\"wp-block-heading\" id=\"build-a-car-list-page-with-angular-cli\">Build a Car List Page with Angular CLI<\/h2>\n<p>Use Angular CLI to generate a car service that can talk to the Cool Cars API.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">ng g s shared\/car\/car<\/pre>\n<p>Update the code in&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client\/src\/app\/shared\/car\/car.service.ts<\/code>&nbsp;to fetch the list of cars from the server.<div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">import { Injectable } from '@angular\/core';\nimport { HttpClient } from '@angular\/common\/http';\nimport { Observable } from 'rxjs';\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class CarService {\n\n  constructor(private http: HttpClient) {\n  }\n\n  getAll(): Observable&lt;any&gt; {\n    return this.http.get('\/\/localhost:8080\/cool-cars');\n  }\n}\n<\/pre>\n<p>Open&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">src\/app\/app.module.ts<\/code>, and add&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">HttpClientModule<\/code>&nbsp;as an import.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">import { HttpClientModule } from '@angular\/common\/http';\n\n@NgModule({\n  declarations: [\n    AppComponent\n  ],\n  imports: [\n    BrowserModule,\n    AppRoutingModule,\n    BrowserAnimationsModule,\n    HttpClientModule\n  ],\n  providers: [],\n  bootstrap: [AppComponent]\n})\n<\/pre>\n<p>Generate a&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">car-list<\/code>&nbsp;component to display the list of cars.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">ng g c car-list<\/pre>\n<p>Update&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client\/src\/app\/car-list\/car-list.component.ts<\/code>&nbsp;to use the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">CarService<\/code>&nbsp;to fetch the list and set the values in a local&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">cars<\/code>&nbsp;variable.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">import { Component, OnInit } from '@angular\/core';\nimport { CarService } from '..\/shared\/car\/car.service';\n\n@Component({\n  selector: 'app-car-list',\n  templateUrl: '.\/car-list.component.html',\n  styleUrls: ['.\/car-list.component.css']\n})\nexport class CarListComponent implements OnInit {\n  cars: Array&lt;any&gt;;\n\n  constructor(private carService: CarService) { }\n\n  ngOnInit() {\n    this.carService.getAll().subscribe(data =&gt; {\n      this.cars = data;\n    });\n  }\n}\n<\/pre>\n<p>Update&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client\/src\/app\/car-list\/car-list.component.html<\/code>&nbsp;to show the list of cars.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:xml\">&lt;h2&gt;Car List&lt;\/h2&gt;\n\n&lt;div *ngFor=\"let car of cars\"&gt;\n  {{car.name}}\n&lt;\/div&gt;\n<\/pre>\n<p>Update&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client\/src\/app\/app.component.html<\/code>&nbsp;to have the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">app-car-list<\/code>&nbsp;element.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:xml\">&lt;div style=\"text-align:center\"&gt;\n  &lt;h1&gt;\n    Welcome to {{ title }}!\n  &lt;\/h1&gt;\n&lt;\/div&gt;\n\n&lt;app-car-list&gt;&lt;\/app-car-list&gt;\n&lt;router-outlet&gt;&lt;\/router-outlet&gt;\n<\/pre>\n<p>Start the client application using&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">ng serve -o<\/code>. You won\u2019t see the car list just yet, and if you open your developer console, you\u2019ll see why.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/cors-error-1024x564.png\" alt=\"CRUD App\" class=\"wp-image-92014\" width=\"768\" height=\"423\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/cors-error-1024x564.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/cors-error-300x165.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/cors-error-768x423.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/cors-error.png 1600w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure>\n<\/div>\n<p>This error happens because you haven\u2019t enabled CORS (Cross-Origin Resource Sharing) on the server.<\/p>\n<h3 class=\"wp-block-heading\" id=\"enable-cors-on-the-server\">Enable CORS on the Server<\/h3>\n<p>To enable CORS on the server, add a&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">@CrossOrigin<\/code>&nbsp;annotation to the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">CoolCarController<\/code>&nbsp;(in&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">server\/src\/main\/java\/com\/okta\/developer\/demo\/CoolCarController.java<\/code>).<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">import org.springframework.web.bind.annotation.CrossOrigin;\n...\n@GetMapping(\"\/cool-cars\")\n@CrossOrigin(origins = \"http:\/\/localhost:4200\")\npublic Collection&lt;Car&gt; coolCars() {\n    return repository.findAll().stream()\n            .filter(this::isCool)\n            .collect(Collectors.toList());\n}\n<\/pre>\n<p>In Spring Boot versions 2.1.4 and below, you could also add a&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">@CrossOrigin<\/code>&nbsp;annotation to your&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">CarRepository<\/code>. This would allow you to communicate with its endpoints when adding\/deleting\/editing from Angular.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">import org.springframework.web.bind.annotation.CrossOrigin;\n\n@RepositoryRestResource\n@CrossOrigin(origins = \"http:\/\/localhost:4200\")\ninterface CarRepository extends JpaRepository&lt;Car, Long&gt; {\n}\n<\/pre>\n<p>However, this&nbsp;<a href=\"https:\/\/github.com\/spring-projects\/spring-boot\/issues\/16683\">no longer works in Spring Boot 2.2.0.M2<\/a>. The good news is there is a workaround. You can add a&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">CorsFilter<\/code>bean to your&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">DemoApplication.java<\/code>&nbsp;class. This is necessary when you integrate Spring Security as well; you\u2019re just doing it a bit earlier.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">import org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.core.Ordered;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.cors.UrlBasedCorsConfigurationSource;\nimport org.springframework.web.filter.CorsFilter;\nimport java.util.Collections;\n\n...\n\npublic class DemoApplication {\n    \/\/ main() and init() methods\n    \n    @Bean\n    public FilterRegistrationBean&lt;CorsFilter&gt; simpleCorsFilter() {\n        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();\n        CorsConfiguration config = new CorsConfiguration();\n        config.setAllowCredentials(true);\n        config.setAllowedOrigins(Collections.singletonList(\"http:\/\/localhost:4200\"));\n        config.setAllowedMethods(Collections.singletonList(\"*\"));\n        config.setAllowedHeaders(Collections.singletonList(\"*\"));\n        source.registerCorsConfiguration(\"\/**\", config);\n        FilterRegistrationBean&lt;CorsFilter&gt; bean = new FilterRegistrationBean&lt;&gt;(new CorsFilter(source));\n        bean.setOrder(Ordered.HIGHEST_PRECEDENCE);\n        return bean;\n    }\n}\n<\/pre>\n<p>Restart the server, refresh the client, and you should see the list of cars in your browser.<\/p>\n<h2 class=\"wp-block-heading\" id=\"add-angular-material\">Add Angular Material<\/h2>\n<p>You\u2019ve already installed Angular Material, to use its components, you need to import them. Open&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client\/src\/app\/app.module.ts<\/code>&nbsp;and add imports for animations, and Material\u2019s toolbar, buttons, inputs, lists, and card layout.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">import { MatButtonModule, MatCardModule, MatInputModule, MatListModule, MatToolbarModule } from '@angular\/material';\n\n@NgModule({\n  ...\n  imports: [\n    BrowserModule,\n    AppRoutingModule,\n    BrowserAnimationsModule,\n    HttpClientModule,\n    MatButtonModule,\n    MatCardModule,\n    MatInputModule,\n    MatListModule,\n    MatToolbarModule\n  ],\n  ...\n})\n<\/pre>\n<p>Update&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client\/src\/app\/app.component.html<\/code>&nbsp;to use the toolbar component.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:xml\">&lt;mat-toolbar color=\"primary\"&gt;\n  &lt;span&gt;Welcome to {{title}}!&lt;\/span&gt;\n&lt;\/mat-toolbar&gt;\n\n&lt;app-car-list&gt;&lt;\/app-car-list&gt;\n&lt;router-outlet&gt;&lt;\/router-outlet&gt;\n<\/pre>\n<p>Update&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client\/src\/app\/car-list\/car-list.component.html<\/code>&nbsp;to use the card layout and list component.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:xml\">&lt;mat-card&gt;\n  &lt;mat-card-title&gt;Car List&lt;\/mat-card-title&gt;\n  &lt;mat-card-content&gt;\n    &lt;mat-list&gt;\n      &lt;mat-list-item *ngFor=\"let car of cars\"&gt;\n        &lt;img mat-list-avatar src=\"{{car.giphyUrl}}\" alt=\"{{car.name}}\"&gt;\n        &lt;h3 mat-line&gt;{{car.name}}&lt;\/h3&gt;\n      &lt;\/mat-list-item&gt;\n    &lt;\/mat-list&gt;\n  &lt;\/mat-card-content&gt;\n&lt;\/mat-card&gt;\n<\/pre>\n<p>If you run your client with&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">ng serve<\/code>&nbsp;and navigate to&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http:\/\/localhost:4200<\/code>, you\u2019ll see the list of cars, but no images associated with them.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/car-list-no-images-1024x577.png\" alt=\"CRUD App\" class=\"wp-image-92015\" width=\"768\" height=\"433\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/car-list-no-images-1024x577.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/car-list-no-images-300x169.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/car-list-no-images-768x432.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/car-list-no-images.png 1600w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure>\n<\/div>\n<h2 class=\"wp-block-heading\" id=\"add-animated-gifs-with-giphy\">Add Animated GIFs with Giphy<\/h2>\n<p>To add a&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">giphyUrl<\/code>&nbsp;property to each car, create&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client\/src\/app\/shared\/giphy\/giphy.service.ts<\/code>&nbsp;and populate it with the code below.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">import { Injectable } from '@angular\/core';\nimport { HttpClient } from '@angular\/common\/http';\nimport { map } from 'rxjs\/operators';\n\n@Injectable({providedIn: 'root'})\nexport class GiphyService {\n\n  \/\/ This is a Giphy API Key I created. Create your own at https:\/\/developers.giphy.com\/dashboard\/?create=true.\n  giphyApi = '\/\/api.giphy.com\/v1\/gifs\/search?api_key=nOTRbUNMgD5mj4XowN2ERoPNudAkK6ft&amp;limit=1&amp;q=';\n\n  constructor(public http: HttpClient) {\n  }\n\n  get(searchTerm) {\n    const apiLink = this.giphyApi + searchTerm;\n    return this.http.get(apiLink).pipe(map((response: any) =&gt; {\n      if (response.data.length &gt; 0) {\n        return response.data[0].images.original.url;\n      } else {\n        return 'https:\/\/media.giphy.com\/media\/YaOxRsmrv9IeA\/giphy.gif'; \/\/ dancing cat for 404\n      }\n    }));\n  }\n}\n<\/pre>\n<p>Update the code in&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client\/src\/app\/car-list\/car-list.component.ts<\/code>&nbsp;to set the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">giphyUrl<\/code>&nbsp;property on each car.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">import { GiphyService } from '..\/shared\/giphy\/giphy.service';\n\nexport class CarListComponent implements OnInit {\n  cars: Array&lt;any&gt;;\n\n  constructor(private carService: CarService, private giphyService: GiphyService) { }\n\n  ngOnInit() {\n    this.carService.getAll().subscribe(data =&gt; {\n      this.cars = data;\n      for (const car of this.cars) {\n        this.giphyService.get(car.name).subscribe(url =&gt; car.giphyUrl = url);\n      }\n    });\n  }\n}\n<\/pre>\n<p>Now your browser should show you the list of car names, along with an avatar image beside them.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/car-list-giphy-images-1024x579.png\" alt=\"CRUD App\" class=\"wp-image-92016\" width=\"768\" height=\"434\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/car-list-giphy-images-1024x579.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/car-list-giphy-images-300x170.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/car-list-giphy-images-768x434.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/car-list-giphy-images.png 1600w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure>\n<\/div>\n<h2 class=\"wp-block-heading\" id=\"add-an-edit-feature-to-your-angular-app\">Add an Edit Feature to Your Angular App<\/h2>\n<p>Having a list of car names and images is cool, but it\u2019s a lot more fun when you can interact with it! To add an edit feature, start by generating a&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">car-edit<\/code>&nbsp;component.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">ng g c car-edit<\/pre>\n<p>Update&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client\/src\/app\/shared\/car\/car.service.ts<\/code>&nbsp;to have methods for adding, removing, and updating cars. These methods talk to the endpoints provided by the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">CarRepository<\/code>&nbsp;and its&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">@RepositoryRestResource<\/code>&nbsp;annotation.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">import { Injectable } from '@angular\/core';\nimport { HttpClient } from '@angular\/common\/http';\nimport { Observable } from 'rxjs';\n\n@Injectable({providedIn: 'root'})\nexport class CarService {\n  public API = '\/\/localhost:8080';\n  public CAR_API = this.API + '\/cars';\n\n  constructor(private http: HttpClient) {\n  }\n\n  getAll(): Observable&lt;any&gt; {\n    return this.http.get(this.API + '\/cool-cars');\n  }\n\n  get(id: string) {\n    return this.http.get(this.CAR_API + '\/' + id);\n  }\n\n  save(car: any): Observable&lt;any&gt; {\n    let result: Observable&lt;any&gt;;\n    if (car.href) {\n      result = this.http.put(car.href, car);\n    } else {\n      result = this.http.post(this.CAR_API, car);\n    }\n    return result;\n  }\n\n  remove(href: string) {\n    return this.http.delete(href);\n  }\n}\n<\/pre>\n<p>In&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client\/src\/app\/car-list\/car-list.component.html<\/code>, add a link to the edit component. Also, add a button at the bottom to add a new car.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:xml\">&lt;mat-card&gt;\n  &lt;mat-card-title&gt;Car List&lt;\/mat-card-title&gt;\n  &lt;mat-card-content&gt;\n    &lt;mat-list&gt;\n      &lt;mat-list-item *ngFor=\"let car of cars\"&gt;\n        &lt;img mat-list-avatar src=\"{{car.giphyUrl}}\" alt=\"{{car.name}}\"&gt;\n        &lt;h3 mat-line&gt;\n          &lt;a mat-button [routerLink]=\"['\/car-edit', car.id]\"&gt;{{car.name}}&lt;\/a&gt;\n        &lt;\/h3&gt;\n      &lt;\/mat-list-item&gt;\n    &lt;\/mat-list&gt;\n  &lt;\/mat-card-content&gt;\n\n  &lt;button mat-fab color=\"primary\" [routerLink]=\"['\/car-add']\"&gt;Add&lt;\/button&gt;\n&lt;\/mat-card&gt;\n<\/pre>\n<p>In&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client\/src\/app\/app.module.ts<\/code>, import the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">FormsModule<\/code>.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">import { FormsModule } from '@angular\/forms';\n\n@NgModule({\n  ...\n  imports: [\n    ...\n    FormsModule\n  ],\n  ...\n})\n<\/pre>\n<p>In&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client\/src\/app\/app-routing.module.ts<\/code>, add routes for the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">CarListComponent<\/code>&nbsp;and&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">CarEditComponent<\/code>.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">import { NgModule } from '@angular\/core';\nimport { Routes, RouterModule } from '@angular\/router';\nimport { CarListComponent } from '.\/car-list\/car-list.component';\nimport { CarEditComponent } from '.\/car-edit\/car-edit.component';\n\nconst routes: Routes = [\n  { path: '', redirectTo: '\/car-list', pathMatch: 'full' },\n  {\n    path: 'car-list',\n    component: CarListComponent\n  },\n  {\n    path: 'car-add',\n    component: CarEditComponent\n  },\n  {\n    path: 'car-edit\/:id',\n    component: CarEditComponent\n  }\n];\n\n@NgModule({\n  imports: [RouterModule.forRoot(routes)],\n  exports: [RouterModule]\n})\nexport class AppRoutingModule { }\n<\/pre>\n<p>Modify&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client\/src\/app\/car-edit\/car-edit.component.ts<\/code>&nbsp;to fetch a car\u2019s information from the id passed on the URL, and to add methods for saving and deleting.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">import { Component, OnDestroy, OnInit } from '@angular\/core';\nimport { Subscription } from 'rxjs';\nimport { ActivatedRoute, Router } from '@angular\/router';\nimport { CarService } from '..\/shared\/car\/car.service';\nimport { GiphyService } from '..\/shared\/giphy\/giphy.service';\nimport { NgForm } from '@angular\/forms';\n\n@Component({\n  selector: 'app-car-edit',\n  templateUrl: '.\/car-edit.component.html',\n  styleUrls: ['.\/car-edit.component.css']\n})\nexport class CarEditComponent implements OnInit, OnDestroy {\n  car: any = {};\n\n  sub: Subscription;\n\n  constructor(private route: ActivatedRoute,\n              private router: Router,\n              private carService: CarService,\n              private giphyService: GiphyService) {\n  }\n\n  ngOnInit() {\n    this.sub = this.route.params.subscribe(params =&gt; {\n      const id = params.id;\n      if (id) {\n        this.carService.get(id).subscribe((car: any) =&gt; {\n          if (car) {\n            this.car = car;\n            this.car.href = car._links.self.href;\n            this.giphyService.get(car.name).subscribe(url =&gt; car.giphyUrl = url);\n          } else {\n            console.log(`Car with id '${id}' not found, returning to list`);\n            this.gotoList();\n          }\n        });\n      }\n    });\n  }\n\n  ngOnDestroy() {\n    this.sub.unsubscribe();\n  }\n\n  gotoList() {\n    this.router.navigate(['\/car-list']);\n  }\n\n  save(form: NgForm) {\n    this.carService.save(form).subscribe(result =&gt; {\n      this.gotoList();\n    }, error =&gt; console.error(error));\n  }\n\n  remove(href) {\n    this.carService.remove(href).subscribe(result =&gt; {\n      this.gotoList();\n    }, error =&gt; console.error(error));\n  }\n}\n<\/pre>\n<p>Update the HTML in&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client\/src\/app\/car-edit\/car-edit.component.html<\/code>&nbsp;to have a form with the car\u2019s name, as well as to display the image from Giphy.<\/p>\n<pre class=\"brush:xml\">&lt;mat-card&gt;\n  &lt;form #carForm=\"ngForm\" (ngSubmit)=\"save(carForm.value)\"&gt;\n    &lt;mat-card-header&gt;\n      &lt;mat-card-title&gt;&lt;h2&gt;{{car.name ? 'Edit' : 'Add'}} Car&lt;\/h2&gt;&lt;\/mat-card-title&gt;\n    &lt;\/mat-card-header&gt;\n    &lt;mat-card-content&gt;\n      &lt;input type=\"hidden\" name=\"href\" [(ngModel)]=\"car.href\"&gt;\n      &lt;mat-form-field&gt;\n        &lt;input matInput placeholder=\"Car Name\" [(ngModel)]=\"car.name\"\n               required name=\"name\" #name&gt;\n      &lt;\/mat-form-field&gt;\n    &lt;\/mat-card-content&gt;\n    &lt;mat-card-actions&gt;\n      &lt;button mat-raised-button color=\"primary\" type=\"submit\"\n              [disabled]=\"!carForm.valid\"&gt;Save&lt;\/button&gt;\n      &lt;button mat-raised-button color=\"secondary\" (click)=\"remove(car.href)\"\n              *ngIf=\"car.href\" type=\"button\"&gt;Delete&lt;\/button&gt;\n      &lt;a mat-button routerLink=\"\/car-list\"&gt;Cancel&lt;\/a&gt;\n    &lt;\/mat-card-actions&gt;\n    &lt;mat-card-footer&gt;\n      &lt;div class=\"giphy\"&gt;\n        &lt;img src=\"{{car.giphyUrl}}\" alt=\"{{car.name}}\"&gt;\n      &lt;\/div&gt;\n    &lt;\/mat-card-footer&gt;\n  &lt;\/form&gt;\n&lt;\/mat-card&gt;\n<\/pre>\n<p>Put a little padding around the image by adding the following CSS to&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client\/src\/app\/car-edit\/car-edit.component.css<\/code>.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">.giphy {\n  margin: 10px;\n}\n<\/pre>\n<p>Modify&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client\/src\/app\/app.component.html<\/code>&nbsp;and remove&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">&lt;app-car-list&gt;&lt;\/app-car-list&gt;<\/code>.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:xml\">&lt;mat-toolbar color=\"primary\"&gt;\n  &lt;span&gt;Welcome to {{title}}!&lt;\/span&gt;\n&lt;\/mat-toolbar&gt;\n\n&lt;router-outlet&gt;&lt;\/router-outlet&gt;\n<\/pre>\n<p>After you make all these changes, you should be able to add, edit, or delete any cars. Below is a screenshot that shows the list with the add button.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/car-list-add-btn-1024x645.png\" alt=\"CRUD App\" class=\"wp-image-92017\" width=\"768\" height=\"484\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/car-list-add-btn-1024x645.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/car-list-add-btn-300x189.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/car-list-add-btn-768x484.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/car-list-add-btn.png 1600w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure>\n<\/div>\n<p>The following screenshot shows what it looks like to edit a car that you\u2019ve added.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/car-edit-1024x860.png\" alt=\"CRUD App\" class=\"wp-image-92018\" width=\"768\" height=\"645\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/car-edit-1024x860.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/car-edit-300x252.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/car-edit-768x645.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/car-edit.png 1600w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure>\n<\/div>\n<h2 class=\"wp-block-heading\" id=\"add-oidc-authentication-to-your-spring-boot--angular-app\">Add OIDC Authentication to Your Spring Boot + Angular App<\/h2>\n<p>Add authentication with OIDC is a nifty feature you can add to this application. Knowing who the person is can come in handy if you want to add auditing, or personalize your application (with a rating feature for example).<\/p>\n<h3 class=\"wp-block-heading\" id=\"spring-security--oidc\">Spring Security + OIDC<\/h3>\n<p>On the server side, you can lock things down with Okta\u2019s Spring Boot Starter, which leverages Spring Security and its OIDC support. Open&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">server\/pom.xml<\/code>&nbsp;and uncomment the Okta Spring Boot starter.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:xml\">&lt;dependency&gt;\n    &lt;groupId&gt;com.okta.spring&lt;\/groupId&gt;\n    &lt;artifactId&gt;okta-spring-boot-starter&lt;\/artifactId&gt;\n    &lt;version&gt;1.1.0&lt;\/version&gt;\n&lt;\/dependency&gt;\n<\/pre>\n<p>Now you need to configure the server to use Okta for authentication. You\u2019ll need to create an OIDC app in Okta for that.<\/p>\n<h3 class=\"wp-block-heading\" id=\"create-an-oidc-app-in-okta\">Create an OIDC App in Okta<\/h3>\n<p>Log in to your Okta Developer account (or&nbsp;<a href=\"https:\/\/developer.okta.com\/signup\/?utm_campaign=text_website_all_multiple_dev_ciam_angular-8-spring-boot-2_null&amp;utm_source=jcg&amp;utm_medium=cpc\">sign up<\/a>&nbsp;if you don\u2019t have an account) and navigate to&nbsp;<strong>Applications<\/strong>&nbsp;&gt;&nbsp;<strong>Add Application<\/strong>. Click&nbsp;<strong>Single-Page App<\/strong>, click&nbsp;<strong>Next<\/strong>, and give the app a name you\u2019ll remember. Change all instances of&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http:\/\/localhost:8080<\/code>&nbsp;to&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http:\/\/localhost:4200<\/code>&nbsp;and click&nbsp;<strong>Done<\/strong>.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/oidc-setting-1024x989.png\" alt=\"CRUD App\" class=\"wp-image-92019\" width=\"768\" height=\"742\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/oidc-setting-1024x989.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/oidc-setting-300x290.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/oidc-setting-768x742.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/oidc-setting.png 1480w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure>\n<\/div>\n<p>You\u2019ll see a client ID at the bottom of the page. Add it and an&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">issuer<\/code>&nbsp;property to&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">server\/src\/main\/resources\/application.properties<\/code>.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">okta.oauth2.client-id={yourClientId}\nokta.oauth2.issuer=https:\/\/{yourOktaDomain}\/oauth2\/default\n<\/pre>\n<p>Create&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">server\/src\/main\/java\/com\/okta\/developer\/demo\/SecurityConfiguration.java<\/code>&nbsp;to configure your Spring Boot app as a resource server.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">package com.okta.developer.demo;\n\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;\n\n@EnableWebSecurity\npublic class SecurityConfiguration extends WebSecurityConfigurerAdapter {\n\n    @Override\n    protected void configure(HttpSecurity http) throws Exception {\n        http\n            .authorizeRequests().anyRequest().authenticated()\n            .and()\n            .oauth2ResourceServer().jwt();\n    }\n}\n<\/pre>\n<p>After making these changes, you should be able to restart your app and see an error when you try to navigate to&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http:\/\/localhost:8080<\/code>.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/400-error-1024x712.png\" alt=\"CRUD App\" class=\"wp-image-92020\" width=\"768\" height=\"534\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/400-error-1024x712.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/400-error-300x209.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/400-error-768x534.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/400-error.png 1600w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure>\n<\/div>\n<p><strong>NOTE:<\/strong>&nbsp;You could fix this error by adding&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http:\/\/localhost:8080\/login\/oauth2\/code\/okta<\/code>&nbsp;as a redirect URI to your app, but it won\u2019t solve the problem. If you want to support OIDC Login with Spring Boot, you\u2019ll need to register a&nbsp;<strong>Web<\/strong>&nbsp;app (instead of a SPA) and include a client secret in your&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">application.properties<\/code>. This is not a necessary step in this tutorial.<\/p>\n<p>Now that your server is locked down, you need to configure your client to talk to it with an access token. This is where Okta\u2019s Angular SDK comes in handy.<\/p>\n<h3 class=\"wp-block-heading\" id=\"oktas-angular-support\">Okta\u2019s Angular Support<\/h3>\n<p>The Okta Angular SDK is a wrapper around&nbsp;<a href=\"https:\/\/github.com\/okta\/okta-auth-js\">Okta Auth JS<\/a>, which builds on top of OIDC. More information about Okta\u2019s Angular library can be&nbsp;<a href=\"https:\/\/github.com\/okta\/okta-oidc-js\/tree\/master\/packages\/okta-angular\">found on GitHub<\/a>.<\/p>\n<p>To simplify our Angular SDK\u2019s installation and configuration, we created an @oktadev\/schematics project that does everything for you. You can read more about how @oktadev\/schematics works in&nbsp;<a href=\"https:\/\/developer.okta.com\/blog\/2019\/02\/13\/angular-schematics?utm_campaign=text_website_all_multiple_dev_ciam_angular-8-spring-boot-2_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Use Angular Schematics to Simplify Your Life<\/a>.<\/p>\n<p>Before you install it, it\u2019s a good idea to check your project into source control. If you don\u2019t have Git installed, you can copy your project to another location as a backup. If you do have Git installed, run the following commands from the root directory of your project.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">git init\ngit add .\ngit commit -m \"Initialize project\"\n<\/pre>\n<p>To install and configure Okta\u2019s Angular SDK, run the following command in the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client<\/code>&nbsp;directory:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">ng add @oktadev\/schematics --issuer=https:\/\/{yourOktaDomain}\/oauth2\/default --clientId={yourClientId}\n<\/pre>\n<p>This command will:<\/p>\n<ul class=\"wp-block-list\">\n<li>Install&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">@okta\/okta-angular<\/code><\/li>\n<li>Configure Okta\u2019s Angular SDK for your app in&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">auth-routing.module.ts<\/code><\/li>\n<li>Add&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">isAuthenticated<\/code>&nbsp;logic to&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">app.component.ts<\/code><\/li>\n<li>Add a&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">HomeComponent<\/code>&nbsp;with login and logout buttons<\/li>\n<li>Configure routing with a default route to&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">\/home<\/code>&nbsp;and an&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">\/implicit\/callback<\/code>&nbsp;route<\/li>\n<li>Add an&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">HttpInterceptor<\/code>&nbsp;that adds an&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Authorization<\/code>&nbsp;header with an access token to&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">localhost<\/code>&nbsp;requests<\/li>\n<\/ul>\n<p>Modify&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client\/src\/app\/app.component.html<\/code>&nbsp;to use Material components and to have a logout button.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:xml\">&lt;mat-toolbar color=\"primary\"&gt;\n  &lt;span&gt;Welcome to {{title}}!&lt;\/span&gt;\n  &lt;span class=\"toolbar-spacer\"&gt;&lt;\/span&gt;\n  &lt;button mat-raised-button color=\"accent\" *ngIf=\"isAuthenticated\"\n          (click)=\"oktaAuth.logout()\" [routerLink]=\"['\/home']\"&gt;Logout\n  &lt;\/button&gt;\n&lt;\/mat-toolbar&gt;\n\n&lt;router-outlet&gt;&lt;\/router-outlet&gt;\n<\/pre>\n<p>You might notice there\u2019s a span with a&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">toolbar-spacer<\/code>&nbsp;class. To make that work as expected, add a&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">toolbar-spacer<\/code>&nbsp;rule to&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client\/src\/app\/app.component.css<\/code>.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">.toolbar-spacer {\n  flex: 1 1 auto;\n}\n<\/pre>\n<p>Then update&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client\/src\/app\/home\/home.component.html<\/code>&nbsp;to use Angular Material and link to the Car List.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:xml\">&lt;mat-card&gt;\n  &lt;mat-card-content&gt;\n    &lt;button mat-raised-button color=\"accent\" *ngIf=\"!isAuthenticated\"\n            (click)=\"oktaAuth.loginRedirect()\"&gt;Login\n    &lt;\/button&gt;\n    &lt;button mat-raised-button color=\"accent\" *ngIf=\"isAuthenticated\"\n            [routerLink]=\"['\/car-list']\"&gt;Car List\n    &lt;\/button&gt;\n  &lt;\/mat-card-content&gt;\n&lt;\/mat-card&gt;\n<\/pre>\n<p>Since you\u2019re using Material components in&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">HomeComponent<\/code>, which is managed by the newly-added&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client\/src\/app\/auth-routing.module.ts<\/code>, you\u2019ll need to import&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">MatCardModule<\/code>.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">import { MatCardModule } from '@angular\/material';\n\n@NgModule({\n  ...\n  imports: [\n    ...\n    MatCardModule\n  ],\n  ...\n})\n<\/pre>\n<p>To make it so there\u2019s not a bottom border at the bottom of your content, make the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">&lt;mat-card&gt;<\/code>&nbsp;element fill the screen by adding the following to&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">client\/src\/styles.css<\/code>.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">mat-card {\n  height: 100vh;\n}<\/pre>\n<p>Now if you restart your client, everything&nbsp;<em>should<\/em>&nbsp;work. Unfortunately, it does not because&nbsp;<a href=\"https:\/\/github.com\/angular\/angular\/issues\/29564\">Ivy does not yet implement CommonJS\/UMD support<\/a>. As a workaround, you can modify&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">tsconfig.app.json<\/code>&nbsp;to disable Ivy.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:js\">\"angularCompilerOptions\": {\n  \"enableIvy\": false\n}\n<\/pre>\n<p>Stop and restart the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">ng serve<\/code>&nbsp;process. Open your browser to&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http:\/\/localhost:4200<\/code>.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/login-button-1024x571.png\" alt=\"CRUD App\" class=\"wp-image-92021\" width=\"768\" height=\"428\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/login-button-1024x571.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/login-button-300x167.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/login-button-768x428.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/login-button.png 1600w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure>\n<\/div>\n<p>Click on the&nbsp;<strong>Login<\/strong>&nbsp;button. If you\u2019ve configured everything correctly, you\u2019ll be redirected to Okta to log in.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/okta-login-1024x761.png\" alt=\"CRUD App\" class=\"wp-image-92022\" width=\"768\" height=\"571\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/okta-login-1024x761.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/okta-login-300x223.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/okta-login-768x571.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/okta-login.png 1600w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure>\n<\/div>\n<p>Enter valid credentials, and you should be redirected back to your app. Celebrate when it all works! \ud83c\udf89<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/success-at-last-1-1024x669.png\" alt=\"CRUD App\" class=\"wp-image-92023\" width=\"768\" height=\"502\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/success-at-last-1-1024x669.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/success-at-last-1-300x196.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/success-at-last-1-768x502.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/success-at-last-1.png 1600w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure>\n<\/div>\n<h2 class=\"wp-block-heading\" id=\"learn-more-about-spring-boot-and-angular\">Learn More about Spring Boot and Angular<\/h2>\n<p>It can be tough to keep up with fast-moving frameworks like Spring Boot and Angular. This post is meant to give you a jump start on the latest releases. For specific changes in Angular 8, see the Angular team\u2019s&nbsp;<a href=\"https:\/\/blog.angular.io\/a-plan-for-version-8-0-and-ivy-b3318dfc19f7\">plan for version 8.0 and Ivy<\/a>. For Spring Boot, see its&nbsp;<a href=\"https:\/\/github.com\/spring-projects\/spring-boot\/wiki\/Spring-Boot-2.2-Release-Notes\">2.2 Release Notes<\/a>.<\/p>\n<p>You can see the full source code for the application developed in this tutorial on GitHub at&nbsp;<a href=\"https:\/\/github.com\/oktadeveloper\/okta-spring-boot-2-angular-8-example\">oktadeveloper\/okta-spring-boot-2-angular-8-example<\/a>.<\/p>\n<p>This blog has a plethora of Spring Boot and Angular tutorials. Here are some of my favorites:<\/p>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2019\/03\/20\/build-desktop-app-with-angular-electron?utm_campaign=text_website_all_multiple_dev_ciam_angular-8-spring-boot-2_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Build a Desktop Application with Angular and Electron<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2019\/03\/05\/spring-boot-migration?utm_campaign=text_website_all_multiple_dev_ciam_angular-8-spring-boot-2_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Migrate Your Spring Boot App to the Latest and Greatest Spring Security and OAuth 2.0<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2019\/02\/25\/java-i18n-internationalization-localization?utm_campaign=text_website_all_multiple_dev_ciam_angular-8-spring-boot-2_null&amp;utm_source=jcg&amp;utm_medium=cpc\">i18n in Java 11, Spring Boot, and JavaScript<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2019\/02\/12\/secure-angular-login?utm_campaign=text_website_all_multiple_dev_ciam_angular-8-spring-boot-2_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Build Secure Login for Your Angular App<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2018\/09\/24\/reactive-apis-with-spring-webflux?utm_campaign=text_website_all_multiple_dev_ciam_angular-8-spring-boot-2_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Build Reactive APIs with Spring WebFlux<\/a><\/li>\n<\/ul>\n<p>If you have any questions, please don\u2019t hesitate to leave a comment below, or ask us on our&nbsp;<a href=\"https:\/\/devforum.okta.com\/\">Okta Developer Forums<\/a>. Don\u2019t forget to follow us&nbsp;<a href=\"https:\/\/twitter.com\/oktadev\">on Twitter<\/a>&nbsp;and&nbsp;<a href=\"https:\/\/www.youtube.com\/channel\/UC5AMiWqFVFxF1q9Ya1FuZ_Q\">YouTube<\/a>&nbsp;too!<\/p>\n<p><a href=\"https:\/\/developer.okta.com\/blog\/2019\/05\/13\/angular-8-spring-boot-2?utm_campaign=text_website_all_multiple_dev_ciam_angular-8-spring-boot-2_null&amp;utm_source=jcg&amp;utm_medium=cpc\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\" (opens in a new tab)\">&#8220;Angular 8 + Spring Boot 2.2: Build a CRUD App Today!&#8221;<\/a>&nbsp;was originally published on the Okta developer blog on May 13, 2019.<\/p>\n<p><span style=\"font-size: 20px;\"><b>\u201cI love writing authentication and authorization code.\u201d ~ No Java Developer Ever.<\/b> Tired of building the same login screens over and over? <a href=\"https:\/\/developer.okta.com\/signup\/?utm_campaign=text_website_all_multiple_dev_ciam_angular-8-spring-boot-2_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Try the Okta API for hosted authentication, authorization, and multi-factor auth.<\/a><\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u201cI love writing authentication and authorization code.\u201d ~ No Java Developer Ever. Tired of building the same login screens over and over? Try the Okta API for hosted authentication, authorization, and multi-factor auth. If you\u2019ve been a Java developer for more than 15 years, you probably remember when there were a plethora of Java web &hellip;<\/p>\n","protected":false},"author":13127,"featured_media":240,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[740,30,854],"class_list":["post-92000","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-enterprise-java","tag-angular","tag-spring","tag-spring-boot"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Angular 8 + Spring Boot 2.2: Build a CRUD App Today! - Java Code Geeks<\/title>\n<meta name=\"description\" content=\"Interested to learn about CRUD App? Check our article explaining how to build an app with the latest and greatest versions of Angular and Spring Boot\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/developer.okta.com\/blog\/2019\/05\/13\/angular-8-spring-boot-2\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Angular 8 + Spring Boot 2.2: Build a CRUD App Today! - Java Code Geeks\" \/>\n<meta property=\"og:description\" content=\"Interested to learn about CRUD App? Check our article explaining how to build an app with the latest and greatest versions of Angular and Spring Boot\" \/>\n<meta property=\"og:url\" content=\"https:\/\/developer.okta.com\/blog\/2019\/05\/13\/angular-8-spring-boot-2\" \/>\n<meta property=\"og:site_name\" content=\"Java Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/javacodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2019-05-27T05:05:19+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2019-06-03T06:21:09+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Matt Raible\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@mraible\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Matt Raible\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"23 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/05\\\/13\\\/angular-8-spring-boot-2#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/05\\\/angular-spring-boot-build-crud-app-today.html\"},\"author\":{\"name\":\"Matt Raible\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/54edd49deb980d7706e2af51514c3f7f\"},\"headline\":\"Angular 8 + Spring Boot 2.2: Build a CRUD App Today!\",\"datePublished\":\"2019-05-27T05:05:19+00:00\",\"dateModified\":\"2019-06-03T06:21:09+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/05\\\/angular-spring-boot-build-crud-app-today.html\"},\"wordCount\":2555,\"commentCount\":5,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/05\\\/13\\\/angular-8-spring-boot-2#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"keywords\":[\"Angular\",\"Spring\",\"Spring Boot\"],\"articleSection\":[\"Enterprise Java\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/05\\\/13\\\/angular-8-spring-boot-2#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/05\\\/angular-spring-boot-build-crud-app-today.html\",\"url\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/05\\\/13\\\/angular-8-spring-boot-2\",\"name\":\"Angular 8 + Spring Boot 2.2: Build a CRUD App Today! - Java Code Geeks\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/05\\\/13\\\/angular-8-spring-boot-2#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/05\\\/13\\\/angular-8-spring-boot-2#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"datePublished\":\"2019-05-27T05:05:19+00:00\",\"dateModified\":\"2019-06-03T06:21:09+00:00\",\"description\":\"Interested to learn about CRUD App? Check our article explaining how to build an app with the latest and greatest versions of Angular and Spring Boot\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/05\\\/13\\\/angular-8-spring-boot-2#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/05\\\/13\\\/angular-8-spring-boot-2\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/05\\\/13\\\/angular-8-spring-boot-2#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"width\":150,\"height\":150,\"caption\":\"spring-interview-questions-answers\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/05\\\/13\\\/angular-8-spring-boot-2#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Enterprise Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\\\/enterprise-java\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Angular 8 + Spring Boot 2.2: Build a CRUD App Today!\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"name\":\"Java Code Geeks\",\"description\":\"Java Developers Resource Center\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"alternateName\":\"JCG\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.javacodegeeks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/javacodegeeks\",\"https:\\\/\\\/x.com\\\/javacodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/54edd49deb980d7706e2af51514c3f7f\",\"name\":\"Matt Raible\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g\",\"caption\":\"Matt Raible\"},\"description\":\"Java Champion and Developer Advocate @okta with a passion for skiing, mtn biking, VWs, &amp; good beer.\",\"sameAs\":[\"https:\\\/\\\/developer.okta.com\",\"https:\\\/\\\/x.com\\\/mraible\"],\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/matt-raible\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Angular 8 + Spring Boot 2.2: Build a CRUD App Today! - Java Code Geeks","description":"Interested to learn about CRUD App? Check our article explaining how to build an app with the latest and greatest versions of Angular and Spring Boot","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/developer.okta.com\/blog\/2019\/05\/13\/angular-8-spring-boot-2","og_locale":"en_US","og_type":"article","og_title":"Angular 8 + Spring Boot 2.2: Build a CRUD App Today! - Java Code Geeks","og_description":"Interested to learn about CRUD App? Check our article explaining how to build an app with the latest and greatest versions of Angular and Spring Boot","og_url":"https:\/\/developer.okta.com\/blog\/2019\/05\/13\/angular-8-spring-boot-2","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2019-05-27T05:05:19+00:00","article_modified_time":"2019-06-03T06:21:09+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","type":"image\/jpeg"}],"author":"Matt Raible","twitter_card":"summary_large_image","twitter_creator":"@mraible","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Matt Raible","Est. reading time":"23 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/developer.okta.com\/blog\/2019\/05\/13\/angular-8-spring-boot-2#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2019\/05\/angular-spring-boot-build-crud-app-today.html"},"author":{"name":"Matt Raible","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/54edd49deb980d7706e2af51514c3f7f"},"headline":"Angular 8 + Spring Boot 2.2: Build a CRUD App Today!","datePublished":"2019-05-27T05:05:19+00:00","dateModified":"2019-06-03T06:21:09+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2019\/05\/angular-spring-boot-build-crud-app-today.html"},"wordCount":2555,"commentCount":5,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/developer.okta.com\/blog\/2019\/05\/13\/angular-8-spring-boot-2#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","keywords":["Angular","Spring","Spring Boot"],"articleSection":["Enterprise Java"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/developer.okta.com\/blog\/2019\/05\/13\/angular-8-spring-boot-2#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2019\/05\/angular-spring-boot-build-crud-app-today.html","url":"https:\/\/developer.okta.com\/blog\/2019\/05\/13\/angular-8-spring-boot-2","name":"Angular 8 + Spring Boot 2.2: Build a CRUD App Today! - Java Code Geeks","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/developer.okta.com\/blog\/2019\/05\/13\/angular-8-spring-boot-2#primaryimage"},"image":{"@id":"https:\/\/developer.okta.com\/blog\/2019\/05\/13\/angular-8-spring-boot-2#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","datePublished":"2019-05-27T05:05:19+00:00","dateModified":"2019-06-03T06:21:09+00:00","description":"Interested to learn about CRUD App? Check our article explaining how to build an app with the latest and greatest versions of Angular and Spring Boot","breadcrumb":{"@id":"https:\/\/developer.okta.com\/blog\/2019\/05\/13\/angular-8-spring-boot-2#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/developer.okta.com\/blog\/2019\/05\/13\/angular-8-spring-boot-2"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/developer.okta.com\/blog\/2019\/05\/13\/angular-8-spring-boot-2#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","width":150,"height":150,"caption":"spring-interview-questions-answers"},{"@type":"BreadcrumbList","@id":"https:\/\/developer.okta.com\/blog\/2019\/05\/13\/angular-8-spring-boot-2#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.javacodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Java","item":"https:\/\/www.javacodegeeks.com\/category\/java"},{"@type":"ListItem","position":3,"name":"Enterprise Java","item":"https:\/\/www.javacodegeeks.com\/category\/java\/enterprise-java"},{"@type":"ListItem","position":4,"name":"Angular 8 + Spring Boot 2.2: Build a CRUD App Today!"}]},{"@type":"WebSite","@id":"https:\/\/www.javacodegeeks.com\/#website","url":"https:\/\/www.javacodegeeks.com\/","name":"Java Code Geeks","description":"Java Developers Resource Center","publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"alternateName":"JCG","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.javacodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.javacodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.javacodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/javacodegeeks","https:\/\/x.com\/javacodegeeks"]},{"@type":"Person","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/54edd49deb980d7706e2af51514c3f7f","name":"Matt Raible","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g","caption":"Matt Raible"},"description":"Java Champion and Developer Advocate @okta with a passion for skiing, mtn biking, VWs, &amp; good beer.","sameAs":["https:\/\/developer.okta.com","https:\/\/x.com\/mraible"],"url":"https:\/\/www.javacodegeeks.com\/author\/matt-raible"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/92000","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/users\/13127"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=92000"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/92000\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/240"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=92000"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=92000"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=92000"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}