diff --git a/diff.txt b/diff.txt
deleted file mode 100644
index 93122ee..0000000
--- a/diff.txt
+++ /dev/null
@@ -1,129 +0,0 @@
-diff --git a/frontend/todo/src/app/app.module.ts b/frontend/todo/src/app/app.module.ts
-index 6b42f34..d1b7305 100644
---- a/frontend/todo/src/app/app.module.ts
-+++ b/frontend/todo/src/app/app.module.ts
-@@ -11,6 +11,7 @@ import { ListTodosComponent } from './list-todos/list-todos.component';
- import { MenuComponent } from './menu/menu.component';
- import { FooterComponent } from './footer/footer.component';
- import { LogoutComponent } from './logout/logout.component';
-+import { HttpClientModule } from '@angular/common/http';
-
- @NgModule({
- declarations: [
-@@ -26,7 +27,8 @@ import { LogoutComponent } from './logout/logout.component';
- imports: [
- BrowserModule,
- AppRoutingModule,
-- FormsModule
-+ FormsModule,
-+ HttpClientModule
- ],
- providers: [],
- bootstrap: [AppComponent]
-diff --git a/frontend/todo/src/app/welcome/welcome.component.html b/frontend/todo/src/app/welcome/welcome.component.html
-index 76797b7..f2fc1dc 100644
---- a/frontend/todo/src/app/welcome/welcome.component.html
-+++ b/frontend/todo/src/app/welcome/welcome.component.html
-@@ -2,4 +2,14 @@
-
- <div class="container">
- Welcome {{name}}. You can manage your todos <a routerLink="/todos">here</a>
-+</div>
-+
-+<div class="container">
-+ Click this button for a special welcome message
-+ <button (click)="getWelcomeMessageWithName()">Get Welcome Message</button>
-+</div>
-+
-+<div class="container" *ngIf="welcomeMessageFromService">
-+ <H2>Your Customized Welcome Message</H2>
-+ {{welcomeMessageFromService}}
- </div>
-\ No newline at end of file
-diff --git a/frontend/todo/src/app/welcome/welcome.component.ts b/frontend/todo/src/app/welcome/welcome.component.ts
-index 2bf4fac..3df5978 100644
---- a/frontend/todo/src/app/welcome/welcome.component.ts
-+++ b/frontend/todo/src/app/welcome/welcome.component.ts
-@@ -1,3 +1,4 @@
-+import { HelloWorldDataService } from './../service/data/hello-world-data.service';
- import { ActivatedRoute } from '@angular/router';
- //package com.in28minutes.springboot.web;
-
-@@ -17,13 +18,16 @@ import { Component, OnInit } from '@angular/core';//'./app.component';
- export class WelcomeComponent implements OnInit {
-
- message = 'Some Welcome Message'
-+ welcomeMessageFromService:string
- name = ''
- //String message = "Some Welcome Message"
-
- //public SpringBootFirstWebApplication() {
-
- //ActivatedRoute
-- constructor(private route:ActivatedRoute) {
-+ constructor(private route:ActivatedRoute,
-+ private service: HelloWorldDataService
-+ ) {
-
- }
-
-@@ -35,6 +39,26 @@ export class WelcomeComponent implements OnInit {
- this.name = this.route.snapshot.params['name'];
-
- }
-+
-+ getWelcomeMessage() {
-+ console.log(this.service.executeHelloWorldBeanService());
-+ this.service.executeHelloWorldBeanService().subscribe(
-+ response => this.welcomeMessageFromService = response.message,
-+ error => console.log(error)
-+ );
-+ }
-+
-+ getWelcomeMessageWithName() {
-+ console.log(this.service.executeHelloWorldBeanService());
-+ this.service.executeHelloWorldBeanServiceWithName(this.name).subscribe(
-+ response => this.welcomeMessageFromService = response.message,
-+ error => console.log(error)
-+ );
-+ }
-+
-+ printToConsole(response){
-+ console.log(response)
-+ }
- }
-
- export class Class1 {
-diff --git a/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/HelloWorldController.java b/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/HelloWorldController.java
-index 24287e6..d0fe5d7 100644
---- a/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/HelloWorldController.java
-+++ b/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/HelloWorldController.java
-@@ -1,11 +1,13 @@
- package com.in28minutes.rest.webservices.restfulwebservices;
-
-+import org.springframework.web.bind.annotation.CrossOrigin;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.PathVariable;
- import org.springframework.web.bind.annotation.RestController;
-
- //Controller
- @RestController
-+@CrossOrigin(origins = "http://localhost:4200")
- public class HelloWorldController {
-
- @GetMapping(path = "/hello-world")
-@@ -15,6 +17,7 @@ public class HelloWorldController {
-
- @GetMapping(path = "/hello-world-bean")
- public HelloWorldBean helloWorldBean() {
-+ //throw new RuntimeException("Something Went Wrong");
- return new HelloWorldBean("Hello World");
- }
-
-@@ -23,4 +26,4 @@ public class HelloWorldController {
- public HelloWorldBean helloWorldPathVariable(@PathVariable String name) {
- return new HelloWorldBean(String.format("Hello World, %s", name));
- }
--}
-+}
-\ No newline at end of file
diff --git a/frontend/todo/src/app/service/data/todo-data.service.ts b/frontend/todo/src/app/service/data/todo-data.service.ts
index 0a4d66a..171b5c8 100644
--- a/frontend/todo/src/app/service/data/todo-data.service.ts
+++ b/frontend/todo/src/app/service/data/todo-data.service.ts
@@ -1,4 +1,4 @@
-import { HttpClient } from '@angular/common/http';
+import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Todo } from '../../list-todos/list-todos.component';
@@ -12,28 +12,37 @@ export class TodoDataService {
) { }
retrieveAllTodos(username) {
- return this.http.get<Todo[]>(`http://localhost:8080/users/${username}/todos`);
+ return this.http.get<Todo[]>(`http://localhost:8080/users/${username}/todos`, this.createHeaders());
//console.log("Execute Hello World Bean Service")
}
deleteTodo(username, id){
- return this.http.delete(`http://localhost:8080/users/${username}/todos/${id}`);
+ return this.http.delete(`http://localhost:8080/users/${username}/todos/${id}`, this.createHeaders());
}
retrieveTodo(username, id){
- return this.http.get<Todo>(`http://localhost:8080/users/${username}/todos/${id}`);
+ return this.http.get<Todo>(`http://localhost:8080/users/${username}/todos/${id}`, this.createHeaders());
}
updateTodo(username, id, todo){
return this.http.put(
`http://localhost:8080/users/${username}/todos/${id}`
- , todo);
+ , todo, this.createHeaders());
}
createTodo(username, todo){
+
return this.http.post(
`http://localhost:8080/users/${username}/todos`
- , todo);
+ , todo, this.createHeaders());
+ }
+
+ createHeaders() {
+ let username = 'in28minutes'
+ let password = 'dummy'
+ let basicAuthHeaderString = 'Basic ' + window.btoa(`${username}:${password}`);
+ const headers = new HttpHeaders({ Authorization: basicAuthHeaderString });
+ return { headers };
}
}
diff --git a/frontend/todo/src/app/service/data/welcome-data.service.ts b/frontend/todo/src/app/service/data/welcome-data.service.ts
index df020a2..1513c96 100644
--- a/frontend/todo/src/app/service/data/welcome-data.service.ts
+++ b/frontend/todo/src/app/service/data/welcome-data.service.ts
@@ -1,4 +1,5 @@
-import { HttpClient } from '@angular/common/http';
+import { map } from 'rxjs/operators';
+import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
export class HelloWorldBean {
@@ -21,8 +22,28 @@ export class WelcomeDataService {
//http://localhost:8080/hello-world/path-variable/in28minutes
executeHelloWorldServiceWithPathVariable(name) {
- return this.http.get<HelloWorldBean>(`http://localhost:8080/hello-world/path-variable/${name}`);
+ let username = 'in28minutes'
+ let password = 'dummy'
+ let basicAuthHeaderString = 'Basic ' + window.btoa(`${username}:${password}`);
+ const headers = new HttpHeaders({ Authorization: basicAuthHeaderString });
+ console.log(headers);
+
+ return this.http.get<HelloWorldBean>(`http://localhost:8080/hello-world/path-variable/${name}`, {headers});
//console.log("Execute Hello World Bean Service")
}
+ executeBasicAuthenticationService(username, password) {
+ let basicAuthHeaderString = 'Basic ' + window.btoa(`${username}:${password}`);
+ const headers = new HttpHeaders({ Authorization: basicAuthHeaderString });
+ console.log(headers);
+ return this.http.get(`http://localhost:8080/authenticate`, { headers })
+ .pipe(
+ map(user => {
+ console.log(user);
+ return user;
+ }));
+ }
+
+
+
}
diff --git a/frontend/todo/src/app/todo/todo.component.css b/frontend/todo/src/app/todo/todo.component.css
index e69de29..7343c3c 100644
--- a/frontend/todo/src/app/todo/todo.component.css
+++ b/frontend/todo/src/app/todo/todo.component.css
@@ -0,0 +1,3 @@
+.ng-invalid:not(form) {
+ border-left: 5px solid #a94442;
+}
\ No newline at end of file
diff --git a/frontend/todo/src/app/todo/todo.component.html b/frontend/todo/src/app/todo/todo.component.html
index a5967da..93fe464 100644
--- a/frontend/todo/src/app/todo/todo.component.html
+++ b/frontend/todo/src/app/todo/todo.component.html
@@ -1,20 +1,26 @@
<H1>Todo</H1>
<div class="container">
-
- <fieldset class="form-group">
- <label>Description</label>
- <input type="text" [(ngModel)]="todo.description" class="form-control" name="description" required="required">
- </fieldset>
- <fieldset class="form-group">
- <label>Target Date</label>
- <input type="date"
- [ngModel]="todo.targetDate | date:'yyyy-MM-dd' "
- (ngModelChange)="todo.targetDate = $event"
- class="form-control" name="targetDate" required="required">
- </fieldset>
+ <form #todoForm="ngForm" (ngSubmit)="!todoForm.invalid && saveTodo()">
+ <div class="alert alert-warning" *ngIf='todoForm.dirty && todoForm.invalid'>Enter Valid Values</div>
+ <div class="alert alert-warning" *ngIf='todoForm.dirty && targetDate.invalid'>Enter Valid Target Date</div>
+ <div class="alert alert-warning" *ngIf='todoForm.dirty && description.invalid'>Enter atleast 5 characters in Description</div>
- <button class="btn btn-success" (click)="saveTodo()">Save</button>
+ <fieldset class="form-group">
+ <label>Description</label>
+ <input type="text" #description="ngModel" #login="ngModel" [(ngModel)]="todo.description" class="form-control" name="description" required="required" minlength="5" >
+ </fieldset>
+
+ <fieldset class="form-group">
+ <label>Target Date</label>
+ <input type="date" #targetDate="ngModel"
+ [ngModel]="todo.targetDate | date:'yyyy-MM-dd' "
+ (ngModelChange)="todo.targetDate = $event"
+ class="form-control" name="targetDate" required="required">
+ </fieldset>
+
+ <button type="submit" class="btn btn-success">Save</button>
+ </form>
</div>
\ No newline at end of file
diff --git a/frontend/todo/src/app/welcome/welcome.component.ts b/frontend/todo/src/app/welcome/welcome.component.ts
index 857e705..1c7e53f 100644
--- a/frontend/todo/src/app/welcome/welcome.component.ts
+++ b/frontend/todo/src/app/welcome/welcome.component.ts
@@ -55,11 +55,18 @@ export class WelcomeComponent implements OnInit {
getWelcomeMessageWithParameter() {
//console.log(this.service.executeHelloWorldBeanService());
-
- this.service.executeHelloWorldServiceWithPathVariable(this.name).subscribe(
+
+ this.service.executeBasicAuthenticationService('in28minutes','dummy').subscribe(
response => this.handleSuccessfulResponse(response),
error => this.handleErrorResponse(error)
);
+
+
+
+ // this.service.executeHelloWorldServiceWithPathVariable(this.name).subscribe(
+ // response => this.handleSuccessfulResponse(response),
+ // error => this.handleErrorResponse(error)
+ // );
//console.log('last line of getWelcomeMessage')
diff --git a/restful-web-services/pom.xml b/restful-web-services/pom.xml
index f928221..98f8d55 100644
--- a/restful-web-services/pom.xml
+++ b/restful-web-services/pom.xml
@@ -38,6 +38,11 @@
<dependency>
<groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-security</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
diff --git a/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/TodoResource.java b/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/TodoResource.java
index ee390e6..6ad07d8 100644
--- a/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/TodoResource.java
+++ b/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/TodoResource.java
@@ -18,63 +18,59 @@ import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import com.in28minutes.rest.webservices.restfulwebservices.todo.Todo;
-@CrossOrigin(origins="http://localhost:4200")
+@CrossOrigin(origins = "http://localhost:4200")
@RestController
public class TodoResource {
-
+
@Autowired
private TodoHardcodedService todoService;
-
+
@GetMapping("/users/{username}/todos")
- public List<Todo> getAllTodos(@PathVariable String username){
+ public List<Todo> getAllTodos(@PathVariable String username) {
return todoService.findAll();
}
@GetMapping("/users/{username}/todos/{id}")
- public Todo getTodo(@PathVariable String username, @PathVariable long id){
+ public Todo getTodo(@PathVariable String username, @PathVariable long id) {
return todoService.findById(id);
}
- //DELETE /users/{username}/todos/{id}
+ // DELETE /users/{username}/todos/{id}
@DeleteMapping("/users/{username}/todos/{id}")
- public ResponseEntity<Void> deleteTodo(
- @PathVariable String username, @PathVariable long id){
-
+ public ResponseEntity<Void> deleteTodo(@PathVariable String username, @PathVariable long id) {
+
Todo todo = todoService.deleteById(id);
-
- if(todo!=null) {
+
+ if (todo != null) {
return ResponseEntity.noContent().build();
}
-
+
return ResponseEntity.notFound().build();
}
-
- //Edit/Update a Todo
- //PUT /users/{user_name}/todos/{todo_id}
+ // Edit/Update a Todo
+ // PUT /users/{user_name}/todos/{todo_id}
@PutMapping("/users/{username}/todos/{id}")
- public ResponseEntity<Todo> updateTodo(
- @PathVariable String username,
- @PathVariable long id, @RequestBody Todo todo){
-
+ public ResponseEntity<Todo> updateTodo(@PathVariable String username, @PathVariable long id,
+ @RequestBody Todo todo) {
+
Todo todoUpdated = todoService.save(todo);
-
+
return new ResponseEntity<Todo>(todo, HttpStatus.OK);
}
-
+
@PostMapping("/users/{username}/todos")
- public ResponseEntity<Void> updateTodo(
- @PathVariable String username, @RequestBody Todo todo){
-
+ public ResponseEntity<Void> updateTodo(@PathVariable String username, @RequestBody Todo todo) {
+
Todo createdTodo = todoService.save(todo);
-
- //Location
- //Get current resource url
- ///{id}
- URI uri = ServletUriComponentsBuilder.fromCurrentRequest()
- .path("/{id}").buildAndExpand(createdTodo.getId()).toUri();
-
+
+ // Location
+ // Get current resource url
+ /// {id}
+ URI uri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(createdTodo.getId())
+ .toUri();
+
return ResponseEntity.created(uri).build();
}
-
+
}
diff --git a/restful-web-services/src/main/resources/application.properties b/restful-web-services/src/main/resources/application.properties
index 5cbf315..4ec0ded 100644
--- a/restful-web-services/src/main/resources/application.properties
+++ b/restful-web-services/src/main/resources/application.properties
@@ -1 +1,4 @@
-logging.level.org.springframework = info
\ No newline at end of file
+logging.level.org.springframework = info
+
+spring.security.user.name=in28minutes
+spring.security.user.password=dummy
diff --git a/frontend/todo/src/app/app.module.ts b/frontend/todo/src/app/app.module.ts
index 1a02cbf..f707e90 100644
--- a/frontend/todo/src/app/app.module.ts
+++ b/frontend/todo/src/app/app.module.ts
@@ -1,4 +1,5 @@
-import { HttpClientModule } from '@angular/common/http';
+import { BasicHttpInterceptor } from './service/data/welcome-data.service';
+import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
@@ -32,7 +33,9 @@ import { TodoComponent } from './todo/todo.component';
FormsModule,
HttpClientModule
],
- providers: [],
+ providers: [
+ {provide: HTTP_INTERCEPTORS, useClass: BasicHttpInterceptor, multi: true }
+ ],
bootstrap: [AppComponent]
})
export class AppModule { }
diff --git a/frontend/todo/src/app/service/data/welcome-data.service.ts b/frontend/todo/src/app/service/data/welcome-data.service.ts
index df020a2..f22a7e2 100644
--- a/frontend/todo/src/app/service/data/welcome-data.service.ts
+++ b/frontend/todo/src/app/service/data/welcome-data.service.ts
@@ -1,5 +1,7 @@
-import { HttpClient } from '@angular/common/http';
+import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
+import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
+import { Observable } from 'rxjs';
export class HelloWorldBean {
constructor(public message:string){ }
@@ -21,8 +23,40 @@ export class WelcomeDataService {
//http://localhost:8080/hello-world/path-variable/in28minutes
executeHelloWorldServiceWithPathVariable(name) {
+
return this.http.get<HelloWorldBean>(`http://localhost:8080/hello-world/path-variable/${name}`);
//console.log("Execute Hello World Bean Service")
}
+ createHeaders() {
+ let username = 'in28minutes'
+ let password = 'dummy'
+ let basicAuthHeaderString = 'Basic ' + window.btoa(`${username}:${password}`);
+ const headers = new HttpHeaders({ Authorization: basicAuthHeaderString });
+ return { headers };
+ }
}
+
+@Injectable({
+ providedIn: 'root'
+})
+export class BasicHttpInterceptor implements HttpInterceptor {
+ constructor(){
+
+ }
+
+ intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
+ let username = 'in28minutes'
+ let password = 'dummy'
+ let basicAuthHeaderString = 'Basic ' + window.btoa(`${username}:${password}`);
+
+ request = request.clone({
+ setHeaders: {
+ Authorization: basicAuthHeaderString
+
+ }
+ });
+
+ return next.handle(request);
+ }
+}
\ No newline at end of file
diff --git a/restful-web-services/pom.xml b/restful-web-services/pom.xml
index f928221..df700e6 100644
--- a/restful-web-services/pom.xml
+++ b/restful-web-services/pom.xml
@@ -38,6 +38,11 @@
<dependency>
<groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-security</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
diff --git a/restful-web-services/src/main/resources/application.properties b/restful-web-services/src/main/resources/application.properties
index 5cbf315..4ec0ded 100644
--- a/restful-web-services/src/main/resources/application.properties
+++ b/restful-web-services/src/main/resources/application.properties
@@ -1 +1,4 @@
-logging.level.org.springframework = info
\ No newline at end of file
+logging.level.org.springframework = info
+
+spring.security.user.name=in28minutes
+spring.security.user.password=dummy
diff --git a/frontend/todo/src/app/app.module.ts b/frontend/todo/src/app/app.module.ts
index 6b42f34..d1b7305 100644
--- a/frontend/todo/src/app/app.module.ts
+++ b/frontend/todo/src/app/app.module.ts
@@ -11,6 +11,7 @@ import { ListTodosComponent } from './list-todos/list-todos.component';
import { MenuComponent } from './menu/menu.component';
import { FooterComponent } from './footer/footer.component';
import { LogoutComponent } from './logout/logout.component';
+import { HttpClientModule } from '@angular/common/http';
@NgModule({
declarations: [
@@ -26,7 +27,8 @@ import { LogoutComponent } from './logout/logout.component';
imports: [
BrowserModule,
AppRoutingModule,
- FormsModule
+ FormsModule,
+ HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
diff --git a/frontend/todo/src/app/welcome/welcome.component.html b/frontend/todo/src/app/welcome/welcome.component.html
index 76797b7..f2fc1dc 100644
--- a/frontend/todo/src/app/welcome/welcome.component.html
+++ b/frontend/todo/src/app/welcome/welcome.component.html
@@ -2,4 +2,14 @@
<div class="container">
Welcome {{name}}. You can manage your todos <a routerLink="/todos">here</a>
+</div>
+
+<div class="container">
+ Click this button for a special welcome message
+ <button (click)="getWelcomeMessageWithName()">Get Welcome Message</button>
+</div>
+
+<div class="container" *ngIf="welcomeMessageFromService">
+ <H2>Your Customized Welcome Message</H2>
+ {{welcomeMessageFromService}}
</div>
\ No newline at end of file
diff --git a/frontend/todo/src/app/welcome/welcome.component.ts b/frontend/todo/src/app/welcome/welcome.component.ts
index 2bf4fac..3df5978 100644
--- a/frontend/todo/src/app/welcome/welcome.component.ts
+++ b/frontend/todo/src/app/welcome/welcome.component.ts
@@ -1,3 +1,4 @@
+import { HelloWorldDataService } from './../service/data/hello-world-data.service';
import { ActivatedRoute } from '@angular/router';
//package com.in28minutes.springboot.web;
@@ -17,13 +18,16 @@ import { Component, OnInit } from '@angular/core';//'./app.component';
export class WelcomeComponent implements OnInit {
message = 'Some Welcome Message'
+ welcomeMessageFromService:string
name = ''
//String message = "Some Welcome Message"
//public SpringBootFirstWebApplication() {
//ActivatedRoute
- constructor(private route:ActivatedRoute) {
+ constructor(private route:ActivatedRoute,
+ private service: HelloWorldDataService
+ ) {
}
@@ -35,6 +39,26 @@ export class WelcomeComponent implements OnInit {
this.name = this.route.snapshot.params['name'];
}
+
+ getWelcomeMessage() {
+ console.log(this.service.executeHelloWorldBeanService());
+ this.service.executeHelloWorldBeanService().subscribe(
+ response => this.welcomeMessageFromService = response.message,
+ error => console.log(error)
+ );
+ }
+
+ getWelcomeMessageWithName() {
+ console.log(this.service.executeHelloWorldBeanService());
+ this.service.executeHelloWorldBeanServiceWithName(this.name).subscribe(
+ response => this.welcomeMessageFromService = response.message,
+ error => console.log(error)
+ );
+ }
+
+ printToConsole(response){
+ console.log(response)
+ }
}
export class Class1 {
diff --git a/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/HelloWorldController.java b/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/HelloWorldController.java
index 24287e6..d0fe5d7 100644
--- a/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/HelloWorldController.java
+++ b/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/HelloWorldController.java
@@ -1,11 +1,13 @@
package com.in28minutes.rest.webservices.restfulwebservices;
+import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
//Controller
@RestController
+@CrossOrigin(origins = "http://localhost:4200")
public class HelloWorldController {
@GetMapping(path = "/hello-world")
@@ -15,6 +17,7 @@ public class HelloWorldController {
@GetMapping(path = "/hello-world-bean")
public HelloWorldBean helloWorldBean() {
+ //throw new RuntimeException("Something Went Wrong");
return new HelloWorldBean("Hello World");
}
@@ -23,4 +26,4 @@ public class HelloWorldController {
public HelloWorldBean helloWorldPathVariable(@PathVariable String name) {
return new HelloWorldBean(String.format("Hello World, %s", name));
}
-}
+}
\ No newline at end of file
/frontend/todo/src/app/app-routing.module.ts
import { TodoComponent } from './todo/todo.component';
import { RouteGuardService } from './service/route-guard.service';
import { LogoutComponent } from './logout/logout.component';
import { ListTodosComponent } from './list-todos/list-todos.component';
import { WelcomeComponent } from './welcome/welcome.component';
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { LoginComponent } from './login/login.component';
import { ErrorComponent } from './error/error.component';
// welcome
const routes: Routes = [
{ path: '', component: LoginComponent },//canActivate, RouteGuardService
{ path: 'login', component: LoginComponent },
{ path: 'welcome/:name', component: WelcomeComponent, canActivate:[RouteGuardService]},
{ path: 'todos', component: ListTodosComponent, canActivate:[RouteGuardService] },
{ path: 'logout', component: LogoutComponent, canActivate:[RouteGuardService] },
{ path: 'todos/:id', component: TodoComponent, canActivate:[RouteGuardService] },
{ path: '**', component: ErrorComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
/frontend/todo/src/app/app.component.css
/frontend/todo/src/app/app.component.html
<!--<app-welcome></app-welcome>-->
<!-- <app-login></app-login> -->
<!--
<div>Component Content</div>-->
< app-menu > </ app-menu >
< div class ="container ">
< router-outlet > </ router-outlet >
</ div >
< app-footer > </ app-footer >
/frontend/todo/src/app/app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
//template: '<h1>{{title}}<h1>',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'todo';
message = 'Welcome to in28Minutes';
}
/frontend/todo/src/app/app.constants.ts
export const API_URL = "http://localhost:8080"
export const TODO_JPA_API_URL = "http://localhost:8080/jpa"
/frontend/todo/src/app/app.module.ts
import { HttpIntercepterBasicAuthService } from './service/http/http-intercepter-basic-auth.service';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { WelcomeComponent } from './welcome/welcome.component';
import { LoginComponent } from './login/login.component';
import { ErrorComponent } from './error/error.component';
import { ListTodosComponent } from './list-todos/list-todos.component';
import { MenuComponent } from './menu/menu.component';
import { FooterComponent } from './footer/footer.component';
import { LogoutComponent } from './logout/logout.component';
import { TodoComponent } from './todo/todo.component';
@NgModule({
declarations: [
AppComponent,
WelcomeComponent,
LoginComponent,
ErrorComponent,
ListTodosComponent,
MenuComponent,
FooterComponent,
LogoutComponent,
TodoComponent
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
HttpClientModule
],
providers: [
{provide: HTTP_INTERCEPTORS, useClass: HttpIntercepterBasicAuthService, multi: true }
],
bootstrap: [AppComponent]
})
export class AppModule { }
/frontend/todo/src/app/error/error.component.css
/frontend/todo/src/app/error/error.component.html
/frontend/todo/src/app/error/error.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-error',
templateUrl: './error.component.html',
styleUrls: ['./error.component.css']
})
export class ErrorComponent implements OnInit {
errorMessage = 'An Error Occured! Contact Support at *** - ***'
constructor() { }
ngOnInit() {
}
}
/frontend/todo/src/app/footer/footer.component.css
.footer {
position : absolute;
bottom : 0 ;
width : 100% ;
height : 40px ;
background-color : # 222222 ;
}
/frontend/todo/src/app/footer/footer.component.html
< footer class ="footer ">
< div class ="container ">
< span class ="text-muted "> All Rights Reserved 2018 @in28minutes</ span >
</ div >
</ footer >
/frontend/todo/src/app/footer/footer.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-footer',
templateUrl: './footer.component.html',
styleUrls: ['./footer.component.css']
})
export class FooterComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
/frontend/todo/src/app/list-todos/list-todos.component.css
/frontend/todo/src/app/list-todos/list-todos.component.html
< h1 > Todo </ h1 >
< div class ="alert alert-success " *ngIf ='message '> {{message}}</ div >
< div class ="container ">
< table class ="table ">
< thead >
< tr >
< th > Description</ th >
< th > Target Date</ th >
< th > is Completed?</ th >
< th > Update</ th >
< th > Delete</ th >
</ tr >
</ thead >
< tbody >
<!-- for (Todo todo: todos) { -->
< tr *ngFor ="let todo of todos ">
< td > {{todo.description}}</ td >
< td > {{todo.targetDate | date | uppercase}}</ td >
< td > {{todo.done}}</ td >
< td > < button (click) ="updateTodo(todo.id) " class ="btn btn-success "> Update</ button > </ td >
< td > < button (click) ="deleteTodo(todo.id) " class ="btn btn-warning "> Delete</ button > </ td >
</ tr >
<!-- } -->
</ tbody >
</ table >
< div class ="row ">
< button (click) ="addTodo() " class ="btn btn-success "> Add</ button >
</ div >
</ div >
/frontend/todo/src/app/list-todos/list-todos.component.ts
import { TodoDataService } from './../service/data/todo-data.service';
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
export class Todo {
constructor(
public id: number,
public description: string,
public done: boolean,
public targetDate: Date
){
}
}
@Component({
selector: 'app-list-todos',
templateUrl: './list-todos.component.html',
styleUrls: ['./list-todos.component.css']
})
export class ListTodosComponent implements OnInit {
todos: Todo[]
message: string
// = [
// new Todo(1, 'Learn to Dance', false, new Date()),
// new Todo(2, 'Become an Expert at Angular', false, new Date()),
// new Todo(3, 'Visit India', false, new Date())
// // {id : 1, description : },
// // {id : 2, description : ''},
// // {id : 3, description : 'Visit India'}
// ]
// todo = {
// id : 1,
// description: 'Learn to Dance'
// }
constructor(
private todoService:TodoDataService,
private router : Router
) { }
ngOnInit() {
this.refreshTodos();
}
refreshTodos(){
this.todoService.retrieveAllTodos('in28minutes').subscribe(
response => {
console.log(response);
this.todos = response;
}
)
}
deleteTodo(id) {
console.log(`delete todo ${id}` )
this.todoService.deleteTodo('in28minutes', id).subscribe (
response => {
console.log(response);
this.message = `Delete of Todo ${id} Successful!`;
this.refreshTodos();
}
)
}
updateTodo(id) {
console.log(`update ${id}`)
this.router.navigate(['todos',id])
}
addTodo() {
this.router.navigate(['todos',-1])
}
}
/frontend/todo/src/app/login/login.component.css
/frontend/todo/src/app/login/login.component.html
< H1 > Login!</ H1 >
< div class ="container ">
< div class ="alert alert-warning " *ngIf ='invalidLogin '> {{errorMessage}}</ div >
< div >
User Name : < input type ="text " name ="username " [(ngModel)] ="username ">
Password : < input type ="password " name ="password " [(ngModel)] ="password ">
<!-- User Name : {{username}} -->
<!-- <button (click)=handleLogin() class="btn btn-success">Login</button> -->
<!-- <button (click)=handleBasicAuthLogin() class="btn btn-success">Login</button> -->
< button (click) =handleJWTAuthLogin() class ="btn btn-success "> Login</ button >
</ div >
</ div >
/frontend/todo/src/app/login/login.component.ts
import { BasicAuthenticationService } from './../service/basic-authentication.service';
import { HardcodedAuthenticationService } from './../service/hardcoded-authentication.service';
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
username = 'in28minutes'
password = ''
errorMessage = 'Invalid Credentials'
invalidLogin = false
//Router
//Angular.giveMeRouter
//Dependency Injection
constructor(private router: Router,
private hardcodedAuthenticationService: HardcodedAuthenticationService,
private basicAuthenticationService: BasicAuthenticationService) { }
ngOnInit() {
}
handleLogin() {
// console.log(this.username);
//if(this.username==="in28minutes" && this.password === 'dummy') {
if(this.hardcodedAuthenticationService.authenticate(this.username, this.password)) {
//Redirect to Welcome Page
this.router.navigate(['welcome', this.username])
this.invalidLogin = false
} else {
this.invalidLogin = true
}
}
handleBasicAuthLogin() {
// console.log(this.username);
//if(this.username==="in28minutes" && this.password === 'dummy') {
this.basicAuthenticationService.executeAuthenticationService(this.username, this.password)
.subscribe(
data => {
console.log(data)
this.router.navigate(['welcome', this.username])
this.invalidLogin = false
},
error => {
console.log(error)
this.invalidLogin = true
}
)
}
handleJWTAuthLogin() {
this.basicAuthenticationService.executeJWTAuthenticationService(this.username, this.password)
.subscribe(
data => {
console.log(data)
this.router.navigate(['welcome', this.username])
this.invalidLogin = false
},
error => {
console.log(error)
this.invalidLogin = true
}
)
}
}
/frontend/todo/src/app/logout/logout.component.css
/frontend/todo/src/app/logout/logout.component.html
< H1 > You are logged out</ H1 >
< div class ="container ">
Thank You For Using Our Application.
</ div >
/frontend/todo/src/app/logout/logout.component.ts
import { HardcodedAuthenticationService } from './../service/hardcoded-authentication.service';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-logout',
templateUrl: './logout.component.html',
styleUrls: ['./logout.component.css']
})
export class LogoutComponent implements OnInit {
constructor(
private hardcodedAuthenticationService: HardcodedAuthenticationService
) { }
ngOnInit() {
this.hardcodedAuthenticationService.logout();
}
}
/frontend/todo/src/app/menu/menu.component.css
/frontend/todo/src/app/menu/menu.component.html
< header >
< nav class ="navbar navbar-expand-md navbar-dark bg-dark ">
< div > < a href ="https://www.in28minutes.com " class ="navbar-brand ">
in28minutes</ a > </ div >
< ul class ="navbar-nav ">
< li > < a *ngIf ="hardcodedAuthenticationService.isUserLoggedIn() " routerLink ="/welcome/in28minutes " class ="nav-link "> Home</ a > </ li >
< li > < a *ngIf ="hardcodedAuthenticationService.isUserLoggedIn() " routerLink ="/todos " class ="nav-link "> Todos</ a > </ li >
</ ul >
< ul class ="navbar-nav navbar-collapse justify-content-end ">
< li > < a *ngIf ="!hardcodedAuthenticationService.isUserLoggedIn() " routerLink ="/login " class ="nav-link "> Login</ a > </ li >
< li > < a *ngIf ="hardcodedAuthenticationService.isUserLoggedIn() " routerLink ="/logout " class ="nav-link "> Logout</ a > </ li >
</ ul >
</ nav >
</ header >
/frontend/todo/src/app/menu/menu.component.ts
import { HardcodedAuthenticationService } from './../service/hardcoded-authentication.service';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-menu',
templateUrl: './menu.component.html',
styleUrls: ['./menu.component.css']
})
export class MenuComponent implements OnInit {
//isUserLoggedIn: boolean = false;
constructor(private hardcodedAuthenticationService
: HardcodedAuthenticationService) { }
ngOnInit() {
//this.isUserLoggedIn = this.hardcodedAuthenticationService.isUserLoggedIn();
}
}
/frontend/todo/src/app/service/basic-authentication.service.ts
import { API_URL } from './../app.constants';
import { HttpHeaders, HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import {map} from 'rxjs/operators';
export const TOKEN = 'token'
export const AUTHENTICATED_USER = 'authenticaterUser'
@Injectable({
providedIn: 'root'
})
export class BasicAuthenticationService {
constructor(private http: HttpClient) { }
executeJWTAuthenticationService(username, password) {
return this.http.post<any>(
`${API_URL}/authenticate`,{
username,
password
}).pipe(
map(
data => {
sessionStorage.setItem(AUTHENTICATED_USER, username);
sessionStorage.setItem(TOKEN, `Bearer ${data.token}`);
return data;
}
)
);
//console.log("Execute Hello World Bean Service")
}
executeAuthenticationService(username, password) {
let basicAuthHeaderString = 'Basic ' + window.btoa(username + ':' + password);
let headers = new HttpHeaders({
Authorization: basicAuthHeaderString
})
return this.http.get<AuthenticationBean>(
`${API_URL}/basicauth`,
{headers}).pipe(
map(
data => {
sessionStorage.setItem(AUTHENTICATED_USER, username);
sessionStorage.setItem(TOKEN, basicAuthHeaderString);
return data;
}
)
);
//console.log("Execute Hello World Bean Service")
}
getAuthenticatedUser() {
return sessionStorage.getItem(AUTHENTICATED_USER)
}
getAuthenticatedToken() {
if(this.getAuthenticatedUser())
return sessionStorage.getItem(TOKEN)
}
isUserLoggedIn() {
let user = sessionStorage.getItem(AUTHENTICATED_USER)
return !(user === null)
}
logout(){
sessionStorage.removeItem(AUTHENTICATED_USER)
sessionStorage.removeItem(TOKEN)
}
}
export class AuthenticationBean{
constructor(public message:string) { }
}
/frontend/todo/src/app/service/data/todo-data.service.ts
import { TODO_JPA_API_URL } from './../../app.constants';
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Todo } from '../../list-todos/list-todos.component';
@Injectable({
providedIn: 'root'
})
export class TodoDataService {
constructor(
private http:HttpClient
) { }
retrieveAllTodos(username) {
return this.http.get<Todo[]>(`${TODO_JPA_API_URL}/users/${username}/todos`);
//console.log("Execute Hello World Bean Service")
}
deleteTodo(username, id){
return this.http.delete(`${TODO_JPA_API_URL}/users/${username}/todos/${id}`);
}
retrieveTodo(username, id){
return this.http.get<Todo>(`${TODO_JPA_API_URL}/users/${username}/todos/${id}`);
}
updateTodo(username, id, todo){
return this.http.put(
`${TODO_JPA_API_URL}/users/${username}/todos/${id}`
, todo);
}
createTodo(username, todo){
return this.http.post(
`${TODO_JPA_API_URL}/users/${username}/todos`
, todo);
}
}
/frontend/todo/src/app/service/data/welcome-data.service.ts
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
export class HelloWorldBean {
constructor(public message:string){ }
}
@Injectable({
providedIn: 'root'
})
export class WelcomeDataService {
constructor(
private http:HttpClient
) { }
executeHelloWorldBeanService() {
return this.http.get<HelloWorldBean>('http://localhost:8080/hello-world-bean');
//console.log("Execute Hello World Bean Service")
}
//http://localhost:8080/hello-world/path-variable/in28minutes
executeHelloWorldServiceWithPathVariable(name) {
// let basicAuthHeaderString = this.createBasicAuthenticationHttpHeader();
// let headers = new HttpHeaders({
// Authorization: basicAuthHeaderString
// })
return this.http.get<HelloWorldBean>(
`http://localhost:8080/hello-world/path-variable/${name}`,
//{headers}
);
//console.log("Execute Hello World Bean Service")
}
// createBasicAuthenticationHttpHeader() {
// let username = 'in28minutes'
// let password = 'dummy'
// let basicAuthHeaderString = 'Basic ' + window.btoa(username + ':' + password);
// return basicAuthHeaderString;
// }
//Access to XMLHttpRequest at
//'http://localhost:8080/hello-world/path-variable/in28minutes'
//from origin 'http://localhost:4200' has been blocked by CORS policy:
//No 'Access-Control-Allow-Origin' header is present on the requested resource.
//Access to XMLHttpRequest at 'http://localhost:8080/hello-world/path-variable/in28minutes' from origin 'http://localhost:4200'
//has been blocked by CORS policy:
//Response to preflight request doesn't pass
//access control check: It does not have HTTP ok status
}
/frontend/todo/src/app/service/hardcoded-authentication.service.ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class HardcodedAuthenticationService {
constructor() { }
authenticate(username, password) {
//console.log('before ' + this.isUserLoggedIn());
if(username==="in28minutes" && password === 'dummy') {
sessionStorage.setItem('authenticaterUser', username);
//console.log('after ' + this.isUserLoggedIn());
return true;
}
return false;
}
isUserLoggedIn() {
let user = sessionStorage.getItem('authenticaterUser')
return !(user === null)
}
logout(){
sessionStorage.removeItem('authenticaterUser')
}
}
/frontend/todo/src/app/service/http/http-intercepter-basic-auth.service.ts
import { BasicAuthenticationService } from './../basic-authentication.service';
import { HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class HttpIntercepterBasicAuthService implements HttpInterceptor{
constructor(
private basicAuthenticationService : BasicAuthenticationService
) { }
intercept(request: HttpRequest<any>, next: HttpHandler){
// let username = 'in28minutes'
// let password = 'dummy'
//let basicAuthHeaderString = 'Basic ' + window.btoa(username + ':' + password);
let basicAuthHeaderString = this.basicAuthenticationService.getAuthenticatedToken();
let username = this.basicAuthenticationService.getAuthenticatedUser()
if(basicAuthHeaderString && username) {
request = request.clone({
setHeaders : {
Authorization : basicAuthHeaderString
}
})
}
return next.handle(request);
}
}
/frontend/todo/src/app/service/route-guard.service.ts
import { HardcodedAuthenticationService } from './hardcoded-authentication.service';
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class RouteGuardService implements CanActivate {
constructor(
private hardcodedAuthenticationService: HardcodedAuthenticationService,
private router: Router) {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
if (this.hardcodedAuthenticationService.isUserLoggedIn())
return true;
this.router.navigate(['login']);
return false;
}
}
/frontend/todo/src/app/todo/todo.component.css
.ng-invalid : not (form ) {
border-left : 5px solid red;
}
/frontend/todo/src/app/todo/todo.component.html
< H1 > Todo</ H1 >
< div class ="container ">
< div class ="alert alert-warning " *ngIf ="todoForm.dirty && todoForm.invalid "> Enter valid values</ div >
< div class ="alert alert-warning " *ngIf ="todoForm.dirty && targetDate.invalid "> Enter valid Target Date</ div >
< div class ="alert alert-warning " *ngIf ="todoForm.dirty && description.invalid "> Enter atleast 5 characters in Description</ div >
< form (ngSubmit) ="!todoForm.invalid && saveTodo() " #todoForm ="ngForm ">
< fieldset class ="form-group ">
< label > Description</ label >
< input type ="text " #description ="ngModel "
[(ngModel)] ="todo.description " class ="form-control "
name ="description " required ="required " minlength ="5 ">
</ fieldset >
< fieldset class ="form-group ">
< label > Target Date</ label >
< input type ="date " #targetDate ="ngModel "
[ngModel] ="todo.targetDate | date:'yyyy-MM-dd' "
(ngModelChange) ="todo.targetDate = $event "
class ="form-control " name ="targetDate " required ="required " >
</ fieldset >
< button type ="submit " class ="btn btn-success "> Save</ button >
</ form >
</ div >
/frontend/todo/src/app/todo/todo.component.ts
import { ActivatedRoute, Router } from '@angular/router';
import { TodoDataService } from './../service/data/todo-data.service';
import { Component, OnInit } from '@angular/core';
import { Todo } from '../list-todos/list-todos.component';
@Component({
selector: 'app-todo',
templateUrl: './todo.component.html',
styleUrls: ['./todo.component.css']
})
export class TodoComponent implements OnInit {
id:number
todo: Todo
constructor(
private todoService: TodoDataService,
private route: ActivatedRoute,
private router: Router
) { }
ngOnInit() {
this.id = this.route.snapshot.params['id'];
this.todo = new Todo(this.id,'',false,new Date());
if(this.id!=-1) {
this.todoService.retrieveTodo('in28minutes', this.id)
.subscribe (
data => this.todo = data
)
}
}
saveTodo() {
if(this.id == -1) { //=== ==
this.todoService.createTodo('in28minutes', this.todo)
.subscribe (
data => {
console.log(data)
this.router.navigate(['todos'])
}
)
} else {
this.todoService.updateTodo('in28minutes', this.id, this.todo)
.subscribe (
data => {
console.log(data)
this.router.navigate(['todos'])
}
)
}
}
}
/frontend/todo/src/app/welcome/welcome.component.css
/frontend/todo/src/app/welcome/welcome.component.html
< H1 > Welcome!</ H1 >
< div class ="container ">
Welcome {{name}}. You can manage your todos < a routerLink ="/todos "> here</ a >
</ div >
< div class ="container ">
Click here to get a customized welcome message
< button (click) ="getWelcomeMessageWithParameter() " class ="btn btn-success "> Get Welcome Message</ button >
</ div >
< div class ="container " *ngIf ="welcomeMessageFromService ">
< H2 > Your Customized Welcome Message</ H2 >
{{welcomeMessageFromService}}
</ div >
/frontend/todo/src/app/welcome/welcome.component.ts
import { WelcomeDataService } from './../service/data/welcome-data.service';
import { ActivatedRoute } from '@angular/router';
//package com.in28minutes.springboot.web;
//import org.springframework.boot.SpringApplication;
import { Component, OnInit } from '@angular/core';//'./app.component';
//import { AppComponent } from '../app.component';
//@ComponentScan(
// value = "com.in28minutes.springboot.web")
@Component({
selector: 'app-welcome',
templateUrl: './welcome.component.html',
styleUrls: ['./welcome.component.css']
})
//public class SpringBootFirstWebApplication implements SomeInterface{
export class WelcomeComponent implements OnInit {
message = 'Some Welcome Message'
welcomeMessageFromService:string
name = ''
//String message = "Some Welcome Message"
//public SpringBootFirstWebApplication() {
//ActivatedRoute
constructor(
private route:ActivatedRoute,
private service:WelcomeDataService) {
}
// void init() {
ngOnInit(){
//COMPILATION ERROR this.message = 5
//console.log(this.message)
// console.log(this.route.snapshot.params['name'])
this.name = this.route.snapshot.params['name'];
}
getWelcomeMessage() {
//console.log(this.service.executeHelloWorldBeanService());
this.service.executeHelloWorldBeanService().subscribe(
response => this.handleSuccessfulResponse(response),
error => this.handleErrorResponse(error)
);
//console.log('last line of getWelcomeMessage')
//console.log("get welcome message");
}
getWelcomeMessageWithParameter() {
//console.log(this.service.executeHelloWorldBeanService());
this.service.executeHelloWorldServiceWithPathVariable(this.name).subscribe(
response => this.handleSuccessfulResponse(response),
error => this.handleErrorResponse(error)
);
//console.log('last line of getWelcomeMessage')
//console.log("get welcome message");
}
handleSuccessfulResponse(response){
this.welcomeMessageFromService = response.message
//console.log(response);
//console.log(response.message);
}
handleErrorResponse(error) {
//console.log(error);
//console.log(error.error);
//console.log(error.error.message);
this.welcomeMessageFromService = error.error.message
}
}
export class Class1 {
}
export class Class2 {
}
/frontend/todo/src/browserslist
# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
#
# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed
> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11
/frontend/todo/src/environments/environment.prod.ts
export const environment = {
production: true
};
/frontend/todo/src/environments/environment.ts
// This file can be replaced during build by using the `fileReplacements` array.
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.
export const environment = {
production: false
};
/*
* For easier debugging in development mode, you can import the following file
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
*
* This import should be commented out in production mode because it will have a negative impact
* on performance if an error is thrown.
*/
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
/frontend/todo/src/index.html
<!doctype html>
< html lang ="en ">
< head >
< meta charset ="utf-8 ">
< title > My Todos Application</ title >
< base href ="/ ">
< meta name ="viewport " content ="width=device-width, initial-scale=1 ">
< link rel ="icon " type ="image/x-icon " href ="favicon.ico ">
</ head >
< body >
< app-root > </ app-root >
<!-- <div>Index HTML Content</div> -->
</ body >
</ html >
/frontend/todo/src/karma.conf.js
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module . exports = function ( config ) {
config . set ( {
basePath : '' ,
frameworks : [ 'jasmine' , '@angular-devkit/build-angular' ] ,
plugins : [
require ( 'karma-jasmine' ) ,
require ( 'karma-chrome-launcher' ) ,
require ( 'karma-jasmine-html-reporter' ) ,
require ( 'karma-coverage-istanbul-reporter' ) ,
require ( '@angular-devkit/build-angular/plugins/karma' )
] ,
client : {
clearContext : false // leave Jasmine Spec Runner output visible in browser
} ,
coverageIstanbulReporter : {
dir : require ( 'path' ) . join ( __dirname , '../coverage' ) ,
reports : [ 'html' , 'lcovonly' ] ,
fixWebpackSourcePaths : true
} ,
reporters : [ 'progress' , 'kjhtml' ] ,
port : 9876 ,
colors : true ,
logLevel : config . LOG_INFO ,
autoWatch : true ,
browsers : [ 'Chrome' ] ,
singleRun : false
} ) ;
} ;
/frontend/todo/src/main.ts
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
/frontend/todo/src/polyfills.ts
/**
* This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file.
*
* This file is divided into 2 sections:
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
* file.
*
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
*
* Learn more in https://angular.io/guide/browser-support
*/
/***************************************************************************************************
* BROWSER POLYFILLS
*/
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
// import 'core-js/es6/symbol';
// import 'core-js/es6/object';
// import 'core-js/es6/function';
// import 'core-js/es6/parse-int';
// import 'core-js/es6/parse-float';
// import 'core-js/es6/number';
// import 'core-js/es6/math';
// import 'core-js/es6/string';
// import 'core-js/es6/date';
// import 'core-js/es6/array';
// import 'core-js/es6/regexp';
// import 'core-js/es6/map';
// import 'core-js/es6/weak-map';
// import 'core-js/es6/set';
/**
* If the application will be indexed by Google Search, the following is required.
* Googlebot uses a renderer based on Chrome 41.
* https://developers.google.com/search/docs/guides/rendering
**/
// import 'core-js/es6/array';
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js'; // Run `npm install --save classlist.js`.
/** IE10 and IE11 requires the following for the Reflect API. */
// import 'core-js/es6/reflect';
/**
* Web Animations `@angular/platform-browser/animations`
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
**/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
/**
* By default, zone.js will patch all possible macroTask and DomEvents
* user can disable parts of macroTask/DomEvents patch by setting following flags
*/
// (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
// (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
// (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
/*
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
* with the following flag, it will bypass `zone.js` patch for IE/Edge
*/
// (window as any).__Zone_enable_cross_context_check = true;
/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/
import 'zone.js/dist/zone'; // Included with Angular CLI.
/***************************************************************************************************
* APPLICATION IMPORTS
*/
/frontend/todo/src/styles.css
/* You can add global styles to this file, and also import other style files */
@import url (https://unpkg.com/[email protected] /dist/css/bootstrap.min.css)
/frontend/todo/src/test.ts
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
declare const require: any;
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);
/frontend/todo/src/todos.txt
- <script type="text/javascript" src="runtime.js">
</script><script type="text/javascript" src="polyfills.js"></script><script type="text/javascript" src="styles.js">
</script><script type="text/javascript" src="vendor.js"></script><script type="text/javascript" src="main.js"></script>
/frontend/todo/angular.json
{
"$schema" : " ./node_modules/@angular/cli/lib/config/schema.json" ,
"version" : 1 ,
"newProjectRoot" : " projects" ,
"projects" : {
"todo" : {
"root" : " " ,
"sourceRoot" : " src" ,
"projectType" : " application" ,
"prefix" : " app" ,
"schematics" : {},
"architect" : {
"build" : {
"builder" : " @angular-devkit/build-angular:browser" ,
"options" : {
"outputPath" : " dist/todo" ,
"index" : " src/index.html" ,
"main" : " src/main.ts" ,
"polyfills" : " src/polyfills.ts" ,
"tsConfig" : " src/tsconfig.app.json" ,
"assets" : [
" src/favicon.ico" ,
" src/assets"
],
"styles" : [
" src/styles.css"
],
"scripts" : []
},
"configurations" : {
"production" : {
"fileReplacements" : [
{
"replace" : " src/environments/environment.ts" ,
"with" : " src/environments/environment.prod.ts"
}
],
"optimization" : true ,
"outputHashing" : " all" ,
"sourceMap" : false ,
"extractCss" : true ,
"namedChunks" : false ,
"aot" : true ,
"extractLicenses" : true ,
"vendorChunk" : false ,
"buildOptimizer" : true ,
"budgets" : [
{
"type" : " initial" ,
"maximumWarning" : " 2mb" ,
"maximumError" : " 5mb"
}
]
}
}
},
"serve" : {
"builder" : " @angular-devkit/build-angular:dev-server" ,
"options" : {
"browserTarget" : " todo:build"
},
"configurations" : {
"production" : {
"browserTarget" : " todo:build:production"
}
}
},
"extract-i18n" : {
"builder" : " @angular-devkit/build-angular:extract-i18n" ,
"options" : {
"browserTarget" : " todo:build"
}
},
"test" : {
"builder" : " @angular-devkit/build-angular:karma" ,
"options" : {
"main" : " src/test.ts" ,
"polyfills" : " src/polyfills.ts" ,
"tsConfig" : " src/tsconfig.spec.json" ,
"karmaConfig" : " src/karma.conf.js" ,
"styles" : [
" src/styles.css"
],
"scripts" : [],
"assets" : [
" src/favicon.ico" ,
" src/assets"
]
}
},
"lint" : {
"builder" : " @angular-devkit/build-angular:tslint" ,
"options" : {
"tsConfig" : [
" src/tsconfig.app.json" ,
" src/tsconfig.spec.json"
],
"exclude" : [
" **/node_modules/**"
]
}
}
}
},
"todo-e2e" : {
"root" : " e2e/" ,
"projectType" : " application" ,
"prefix" : " " ,
"architect" : {
"e2e" : {
"builder" : " @angular-devkit/build-angular:protractor" ,
"options" : {
"protractorConfig" : " e2e/protractor.conf.js" ,
"devServerTarget" : " todo:serve"
},
"configurations" : {
"production" : {
"devServerTarget" : " todo:serve:production"
}
}
},
"lint" : {
"builder" : " @angular-devkit/build-angular:tslint" ,
"options" : {
"tsConfig" : " e2e/tsconfig.e2e.json" ,
"exclude" : [
" **/node_modules/**"
]
}
}
}
}
},
"defaultProject" : " todo"
}
/frontend/todo/package.json
{
"name" : " todo" ,
"version" : " 0.0.0" ,
"scripts" : {
"ng" : " ng" ,
"start" : " ng serve" ,
"build" : " ng build" ,
"test" : " ng test" ,
"lint" : " ng lint" ,
"e2e" : " ng e2e"
},
"private" : true ,
"dependencies" : {
"@angular/animations" : " ~7.0.0" ,
"@angular/common" : " ~7.0.0" ,
"@angular/compiler" : " ~7.0.0" ,
"@angular/core" : " ~7.0.0" ,
"@angular/forms" : " ~7.0.0" ,
"@angular/http" : " ~7.0.0" ,
"@angular/platform-browser" : " ~7.0.0" ,
"@angular/platform-browser-dynamic" : " ~7.0.0" ,
"@angular/router" : " ~7.0.0" ,
"core-js" : " ^2.5.4" ,
"rxjs" : " ~6.3.3" ,
"zone.js" : " ~0.8.26"
},
"devDependencies" : {
"@angular-devkit/build-angular" : " ~0.10.0" ,
"@angular/cli" : " ~7.0.3" ,
"@angular/compiler-cli" : " ~7.0.0" ,
"@angular/language-service" : " ~7.0.0" ,
"@types/node" : " ~8.9.4" ,
"@types/jasmine" : " ~2.8.8" ,
"@types/jasminewd2" : " ~2.0.3" ,
"codelyzer" : " ~4.5.0" ,
"jasmine-core" : " ~2.99.1" ,
"jasmine-spec-reporter" : " ~4.2.1" ,
"karma" : " ~3.0.0" ,
"karma-chrome-launcher" : " ~2.2.0" ,
"karma-coverage-istanbul-reporter" : " ~2.0.1" ,
"karma-jasmine" : " ~1.1.2" ,
"karma-jasmine-html-reporter" : " ^0.2.2" ,
"protractor" : " ~5.4.0" ,
"ts-node" : " ~7.0.0" ,
"tslint" : " ~5.11.0" ,
"typescript" : " ~3.1.1"
}
}
diff --git a/frontend/todo/src/app/app.constants.ts b/frontend/todo/src/app/app.constants.ts
index b01b800..bfb0231 100644
--- a/frontend/todo/src/app/app.constants.ts
+++ b/frontend/todo/src/app/app.constants.ts
@@ -1 +1,2 @@
-export const API_URL = "http://localhost:8080"
\ No newline at end of file
+export const API_URL = "http://localhost:8080"
+export const TODO_API_URL = "http://localhost:8080/jpa"
\ No newline at end of file
diff --git a/frontend/todo/src/app/service/data/todo-data.service.ts b/frontend/todo/src/app/service/data/todo-data.service.ts
index 3fa923f..9c276e2 100644
--- a/frontend/todo/src/app/service/data/todo-data.service.ts
+++ b/frontend/todo/src/app/service/data/todo-data.service.ts
@@ -1,4 +1,4 @@
-import { API_URL } from './../../app.constants';
+import { TODO_API_URL } from './../../app.constants';
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Todo } from '../../list-todos/list-todos.component';
@@ -13,27 +13,27 @@ export class TodoDataService {
) { }
retrieveAllTodos(username) {
- return this.http.get<Todo[]>(`${API_URL}/users/${username}/todos`);
+ return this.http.get<Todo[]>(`${TODO_API_URL}/users/${username}/todos`);
//console.log("Execute Hello World Bean Service")
}
deleteTodo(username, id){
- return this.http.delete(`${API_URL}/users/${username}/todos/${id}`);
+ return this.http.delete(`${TODO_API_URL}/users/${username}/todos/${id}`);
}
retrieveTodo(username, id){
- return this.http.get<Todo>(`${API_URL}/users/${username}/todos/${id}`);
+ return this.http.get<Todo>(`${TODO_API_URL}/users/${username}/todos/${id}`);
}
updateTodo(username, id, todo){
return this.http.put(
- `${API_URL}/users/${username}/todos/${id}`
+ `${TODO_API_URL}/users/${username}/todos/${id}`
, todo);
}
createTodo(username, todo){
return this.http.post(
- `${API_URL}/users/${username}/todos`
+ `${TODO_API_URL}/users/${username}/todos`
, todo);
}
diff --git a/frontend/todo/src/app/todo/todo.component.ts b/frontend/todo/src/app/todo/todo.component.ts
index 7dc47bc..b0c1994 100644
--- a/frontend/todo/src/app/todo/todo.component.ts
+++ b/frontend/todo/src/app/todo/todo.component.ts
@@ -34,7 +34,9 @@ export class TodoComponent implements OnInit {
}
saveTodo() {
- if(this.id === -1) {
+ console.log(this.id);
+ if(this.id == -1) {
+ console.log('Calling Update')
this.todoService.createTodo('in28minutes', this.todo)
.subscribe (
data => {
diff --git a/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/Todo.java b/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/Todo.java
index e209d05..f83568a 100644
--- a/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/Todo.java
+++ b/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/Todo.java
@@ -2,8 +2,16 @@ package com.in28minutes.rest.webservices.restfulwebservices.todo;
import java.util.Date;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+@Entity
public class Todo {
- private long id;
+
+ @Id
+ @GeneratedValue
+ private Long id;
private String username;
private String description;
private Date targetDate;
@@ -22,11 +30,11 @@ public class Todo {
this.isDone = isDone;
}
- public long getId() {
+ public Long getId() {
return id;
}
- public void setId(long id) {
+ public void setId(Long id) {
this.id = id;
}
diff --git a/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/TodoHardcodedService.java b/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/TodoHardcodedService.java
index 3e89570..f47b31f 100644
--- a/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/TodoHardcodedService.java
+++ b/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/TodoHardcodedService.java
@@ -11,7 +11,7 @@ import org.springframework.stereotype.Service;
public class TodoHardcodedService {
private static List<Todo> todos = new ArrayList<>();
- private static int idCounter = 0;
+ private static long idCounter = 0;
static {
todos.add(new Todo(++idCounter, "in28minutes","Learn to Dance 2", new Date(), false ));
diff --git a/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/TodoResource.java b/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/TodoResource.java
index ee390e6..111038f 100644
--- a/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/TodoResource.java
+++ b/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/TodoResource.java
@@ -16,57 +16,62 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
-import com.in28minutes.rest.webservices.restfulwebservices.todo.Todo;
-
@CrossOrigin(origins="http://localhost:4200")
@RestController
public class TodoResource {
@Autowired
private TodoHardcodedService todoService;
+
+ @Autowired
+ private TodoRepository todoRepository;
+
- @GetMapping("/users/{username}/todos")
+ @GetMapping("/jpa/users/{username}/todos")
public List<Todo> getAllTodos(@PathVariable String username){
- return todoService.findAll();
+ return todoRepository.findByUsername(username);
}
- @GetMapping("/users/{username}/todos/{id}")
+ @GetMapping("/jpa/users/{username}/todos/{id}")
public Todo getTodo(@PathVariable String username, @PathVariable long id){
- return todoService.findById(id);
+ return todoRepository.findById(id).get();
}
//DELETE /users/{username}/todos/{id}
- @DeleteMapping("/users/{username}/todos/{id}")
+ @DeleteMapping("/jpa/users/{username}/todos/{id}")
public ResponseEntity<Void> deleteTodo(
@PathVariable String username, @PathVariable long id){
- Todo todo = todoService.deleteById(id);
-
- if(todo!=null) {
- return ResponseEntity.noContent().build();
- }
+ todoRepository.deleteById(id);
+ return ResponseEntity.noContent().build();
- return ResponseEntity.notFound().build();
+// if(todo!=null) {
+
+// }
+//
+// return ResponseEntity.notFound().build();
}
//Edit/Update a Todo
//PUT /users/{user_name}/todos/{todo_id}
- @PutMapping("/users/{username}/todos/{id}")
+ @PutMapping("/jpa/users/{username}/todos/{id}")
public ResponseEntity<Todo> updateTodo(
@PathVariable String username,
@PathVariable long id, @RequestBody Todo todo){
- Todo todoUpdated = todoService.save(todo);
+ Todo todoUpdated = todoRepository.save(todo);
return new ResponseEntity<Todo>(todo, HttpStatus.OK);
}
- @PostMapping("/users/{username}/todos")
+ @PostMapping("/jpa/users/{username}/todos")
public ResponseEntity<Void> updateTodo(
@PathVariable String username, @RequestBody Todo todo){
+ todo.setId(null);
+ todo.setUsername(username);
- Todo createdTodo = todoService.save(todo);
+ Todo createdTodo = todoRepository.save(todo);
//Location
//Get current resource url
package com.in28minutes.rest.webservices.restfulwebservices.todo;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface TodoRepository extends JpaRepository<Todo, Long>{
List<Todo> findByUsername(String userName);
}
insert into todo(id,username,description,target_date,is_done)
values(10001,'in28minutes','Learn to Dance', sysdate(), false);
insert into todo(id,username,description,target_date,is_done)
values(10002,'in28minutes','Learn about Microservices', sysdate(), false);
/restful-web-services/src/main/java/com/in28minutes/rest/basic/auth/AuthenticationBean.java
package com .in28minutes .rest .basic .auth ;
public class AuthenticationBean {
private String message ;
public AuthenticationBean (String message ) {
this .message = message ;
}
public String getMessage () {
return message ;
}
public void setMessage (String message ) {
this .message = message ;
}
@ Override
public String toString () {
return String .format ("HelloWorldBean [message=%s]" , message );
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/basic/auth/BasicAuthenticationController.java
package com .in28minutes .rest .basic .auth ;
import org .springframework .web .bind .annotation .CrossOrigin ;
import org .springframework .web .bind .annotation .GetMapping ;
import org .springframework .web .bind .annotation .RestController ;
//Controller
@ CrossOrigin (origins ="http://localhost:4200" )
@ RestController
public class BasicAuthenticationController {
@ GetMapping (path = "/basicauth" )
public AuthenticationBean helloWorldBean () {
//throw new RuntimeException("Some Error has Happened! Contact Support at ***-***");
return new AuthenticationBean ("You are authenticated" );
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/basic/auth/SpringSecurityConfigurationBasicAuth.java
package com .in28minutes .rest .basic .auth ;
import org .springframework .context .annotation .Configuration ;
import org .springframework .http .HttpMethod ;
import org .springframework .security .config .annotation .web .builders .HttpSecurity ;
import org .springframework .security .config .annotation .web .configuration .EnableWebSecurity ;
import org .springframework .security .config .annotation .web .configuration .WebSecurityConfigurerAdapter ;
@ Configuration
@ EnableWebSecurity
public class SpringSecurityConfigurationBasicAuth extends WebSecurityConfigurerAdapter {
@ Override
protected void configure (HttpSecurity http ) throws Exception {
http
.csrf ().disable ()
.authorizeRequests ()
.antMatchers (HttpMethod .OPTIONS ,"/**" ).permitAll ()
.anyRequest ().authenticated ()
.and ()
//.formLogin().and()
.httpBasic ();
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/BcryptEncoderTest.java
package com .in28minutes .rest .webservices .restfulwebservices ;
import org .springframework .security .crypto .bcrypt .BCryptPasswordEncoder ;
public class BcryptEncoderTest {
public static void main (String [] args ) {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder ();
for (int i =1 ; i <=10 ; i ++) {
String encodedString = encoder .encode ("password@!23@#!" );
System .out .println (encodedString );
}
// TODO Auto-generated method stub
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/helloworld/HelloWorldBean.java
package com .in28minutes .rest .webservices .restfulwebservices .helloworld ;
public class HelloWorldBean {
private String message ;
public HelloWorldBean (String message ) {
this .message = message ;
}
public String getMessage () {
return message ;
}
public void setMessage (String message ) {
this .message = message ;
}
@ Override
public String toString () {
return String .format ("HelloWorldBean [message=%s]" , message );
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/helloworld/HelloWorldController.java
package com .in28minutes .rest .webservices .restfulwebservices .helloworld ;
import org .springframework .web .bind .annotation .CrossOrigin ;
import org .springframework .web .bind .annotation .GetMapping ;
import org .springframework .web .bind .annotation .PathVariable ;
import org .springframework .web .bind .annotation .RestController ;
//Controller
@ CrossOrigin (origins ="http://localhost:4200" )
@ RestController
public class HelloWorldController {
@ GetMapping (path = "/hello-world" )
public String helloWorld () {
return "Hello World" ;
}
@ GetMapping (path = "/hello-world-bean" )
public HelloWorldBean helloWorldBean () {
//throw new RuntimeException("Some Error has Happened! Contact Support at ***-***");
return new HelloWorldBean ("Hello World - Changed" );
}
///hello-world/path-variable/in28minutes
@ GetMapping (path = "/hello-world/path-variable/{name}" )
public HelloWorldBean helloWorldPathVariable (@ PathVariable String name ) {
return new HelloWorldBean (String .format ("Hello World, %s" , name ));
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/jwt/JwtInMemoryUserDetailsService.java
package com .in28minutes .rest .webservices .restfulwebservices .jwt ;
import java .util .ArrayList ;
import java .util .List ;
import java .util .Optional ;
import org .springframework .security .core .userdetails .UserDetails ;
import org .springframework .security .core .userdetails .UserDetailsService ;
import org .springframework .security .core .userdetails .UsernameNotFoundException ;
import org .springframework .stereotype .Service ;
@ Service
public class JwtInMemoryUserDetailsService implements UserDetailsService {
static List <JwtUserDetails > inMemoryUserList = new ArrayList <>();
static {
inMemoryUserList .add (new JwtUserDetails (1L , "in28minutes" ,
"$2a$10$3zHzb.Npv1hfZbLEU5qsdOju/tk2je6W6PnNnY.c1ujWPcZh4PL6e" , "ROLE_USER_2" ));
inMemoryUserList .add (new JwtUserDetails (2L , "ranga" ,
"$2a$10$IetbreuU5KihCkDB6/r1DOJO0VyU9lSiBcrMDT.biU7FOt2oqZDPm" , "ROLE_USER_2" ));
//$2a$10$IetbreuU5KihCkDB6/r1DOJO0VyU9lSiBcrMDT.biU7FOt2oqZDPm
}
@ Override
public UserDetails loadUserByUsername (String username ) throws UsernameNotFoundException {
Optional <JwtUserDetails > findFirst = inMemoryUserList .stream ()
.filter (user -> user .getUsername ().equals (username )).findFirst ();
if (!findFirst .isPresent ()) {
throw new UsernameNotFoundException (String .format ("USER_NOT_FOUND '%s'." , username ));
}
return findFirst .get ();
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/jwt/JwtTokenAuthorizationOncePerRequestFilter.java
package com .in28minutes .rest .webservices .restfulwebservices .jwt ;
import java .io .IOException ;
import javax .servlet .FilterChain ;
import javax .servlet .ServletException ;
import javax .servlet .http .HttpServletRequest ;
import javax .servlet .http .HttpServletResponse ;
import org .slf4j .Logger ;
import org .slf4j .LoggerFactory ;
import org .springframework .beans .factory .annotation .Autowired ;
import org .springframework .beans .factory .annotation .Value ;
import org .springframework .security .authentication .UsernamePasswordAuthenticationToken ;
import org .springframework .security .core .context .SecurityContextHolder ;
import org .springframework .security .core .userdetails .UserDetails ;
import org .springframework .security .core .userdetails .UserDetailsService ;
import org .springframework .security .web .authentication .WebAuthenticationDetailsSource ;
import org .springframework .stereotype .Component ;
import org .springframework .web .filter .OncePerRequestFilter ;
import io .jsonwebtoken .ExpiredJwtException ;
@ Component
public class JwtTokenAuthorizationOncePerRequestFilter extends OncePerRequestFilter {
private final Logger logger = LoggerFactory .getLogger (this .getClass ());
@ Autowired
private UserDetailsService jwtInMemoryUserDetailsService ;
@ Autowired
private JwtTokenUtil jwtTokenUtil ;
@ Value ("${jwt.http.request.header}" )
private String tokenHeader ;
@ Override
protected void doFilterInternal (HttpServletRequest request , HttpServletResponse response , FilterChain chain )
throws ServletException , IOException {
logger .debug ("Authentication Request For '{}'" , request .getRequestURL ());
final String requestTokenHeader = request .getHeader (this .tokenHeader );
String username = null ;
String jwtToken = null ;
if (requestTokenHeader != null && requestTokenHeader .startsWith ("Bearer " )) {
jwtToken = requestTokenHeader .substring (7 );
try {
username = jwtTokenUtil .getUsernameFromToken (jwtToken );
} catch (IllegalArgumentException e ) {
logger .error ("JWT_TOKEN_UNABLE_TO_GET_USERNAME" , e );
} catch (ExpiredJwtException e ) {
logger .warn ("JWT_TOKEN_EXPIRED" , e );
}
} else {
logger .warn ("JWT_TOKEN_DOES_NOT_START_WITH_BEARER_STRING" );
}
logger .debug ("JWT_TOKEN_USERNAME_VALUE '{}'" , username );
if (username != null && SecurityContextHolder .getContext ().getAuthentication () == null ) {
UserDetails userDetails = this .jwtInMemoryUserDetailsService .loadUserByUsername (username );
if (jwtTokenUtil .validateToken (jwtToken , userDetails )) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken (
userDetails , null , userDetails .getAuthorities ());
usernamePasswordAuthenticationToken
.setDetails (new WebAuthenticationDetailsSource ().buildDetails (request ));
SecurityContextHolder .getContext ().setAuthentication (usernamePasswordAuthenticationToken );
}
}
chain .doFilter (request , response );
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/jwt/JwtTokenUtil.java
package com .in28minutes .rest .webservices .restfulwebservices .jwt ;
import java .io .Serializable ;
import java .util .Date ;
import java .util .HashMap ;
import java .util .Map ;
import java .util .function .Function ;
import org .springframework .beans .factory .annotation .Value ;
import org .springframework .security .core .userdetails .UserDetails ;
import org .springframework .stereotype .Component ;
import io .jsonwebtoken .Claims ;
import io .jsonwebtoken .Clock ;
import io .jsonwebtoken .Jwts ;
import io .jsonwebtoken .SignatureAlgorithm ;
import io .jsonwebtoken .impl .DefaultClock ;
@ Component
public class JwtTokenUtil implements Serializable {
static final String CLAIM_KEY_USERNAME = "sub" ;
static final String CLAIM_KEY_CREATED = "iat" ;
private static final long serialVersionUID = -3301605591108950415L ;
private Clock clock = DefaultClock .INSTANCE ;
@ Value ("${jwt.signing.key.secret}" )
private String secret ;
@ Value ("${jwt.token.expiration.in.seconds}" )
private Long expiration ;
public String getUsernameFromToken (String token ) {
return getClaimFromToken (token , Claims ::getSubject );
}
public Date getIssuedAtDateFromToken (String token ) {
return getClaimFromToken (token , Claims ::getIssuedAt );
}
public Date getExpirationDateFromToken (String token ) {
return getClaimFromToken (token , Claims ::getExpiration );
}
public <T > T getClaimFromToken (String token , Function <Claims , T > claimsResolver ) {
final Claims claims = getAllClaimsFromToken (token );
return claimsResolver .apply (claims );
}
private Claims getAllClaimsFromToken (String token ) {
return Jwts .parser ().setSigningKey (secret ).parseClaimsJws (token ).getBody ();
}
private Boolean isTokenExpired (String token ) {
final Date expiration = getExpirationDateFromToken (token );
return expiration .before (clock .now ());
}
private Boolean ignoreTokenExpiration (String token ) {
// here you specify tokens, for that the expiration is ignored
return false ;
}
public String generateToken (UserDetails userDetails ) {
Map <String , Object > claims = new HashMap <>();
return doGenerateToken (claims , userDetails .getUsername ());
}
private String doGenerateToken (Map <String , Object > claims , String subject ) {
final Date createdDate = clock .now ();
final Date expirationDate = calculateExpirationDate (createdDate );
return Jwts .builder ().setClaims (claims ).setSubject (subject ).setIssuedAt (createdDate )
.setExpiration (expirationDate ).signWith (SignatureAlgorithm .HS512 , secret ).compact ();
}
public Boolean canTokenBeRefreshed (String token ) {
return (!isTokenExpired (token ) || ignoreTokenExpiration (token ));
}
public String refreshToken (String token ) {
final Date createdDate = clock .now ();
final Date expirationDate = calculateExpirationDate (createdDate );
final Claims claims = getAllClaimsFromToken (token );
claims .setIssuedAt (createdDate );
claims .setExpiration (expirationDate );
return Jwts .builder ().setClaims (claims ).signWith (SignatureAlgorithm .HS512 , secret ).compact ();
}
public Boolean validateToken (String token , UserDetails userDetails ) {
JwtUserDetails user = (JwtUserDetails ) userDetails ;
final String username = getUsernameFromToken (token );
return (username .equals (user .getUsername ()) && !isTokenExpired (token ));
}
private Date calculateExpirationDate (Date createdDate ) {
return new Date (createdDate .getTime () + expiration * 1000 );
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/jwt/JwtUnAuthorizedResponseAuthenticationEntryPoint.java
package com .in28minutes .rest .webservices .restfulwebservices .jwt ;
import java .io .IOException ;
import java .io .Serializable ;
import javax .servlet .http .HttpServletRequest ;
import javax .servlet .http .HttpServletResponse ;
import org .springframework .security .core .AuthenticationException ;
import org .springframework .security .web .AuthenticationEntryPoint ;
import org .springframework .stereotype .Component ;
@ Component
public class JwtUnAuthorizedResponseAuthenticationEntryPoint implements AuthenticationEntryPoint , Serializable {
private static final long serialVersionUID = -8970718410437077606L ;
@ Override
public void commence (HttpServletRequest request , HttpServletResponse response ,
AuthenticationException authException ) throws IOException {
response .sendError (HttpServletResponse .SC_UNAUTHORIZED ,
"You would need to provide the Jwt Token to Access This resource" );
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/jwt/JwtUserDetails.java
package com .in28minutes .rest .webservices .restfulwebservices .jwt ;
import java .util .ArrayList ;
import java .util .Collection ;
import java .util .List ;
import org .springframework .security .core .GrantedAuthority ;
import org .springframework .security .core .authority .SimpleGrantedAuthority ;
import org .springframework .security .core .userdetails .UserDetails ;
import com .fasterxml .jackson .annotation .JsonIgnore ;
public class JwtUserDetails implements UserDetails {
private static final long serialVersionUID = 5155720064139820502L ;
private final Long id ;
private final String username ;
private final String password ;
private final Collection <? extends GrantedAuthority > authorities ;
public JwtUserDetails (Long id , String username , String password , String role ) {
this .id = id ;
this .username = username ;
this .password = password ;
List <SimpleGrantedAuthority > authorities = new ArrayList <SimpleGrantedAuthority >();
authorities .add (new SimpleGrantedAuthority (role ));
this .authorities = authorities ;
}
@ JsonIgnore
public Long getId () {
return id ;
}
@ Override
public String getUsername () {
return username ;
}
@ JsonIgnore
@ Override
public boolean isAccountNonExpired () {
return true ;
}
@ JsonIgnore
@ Override
public boolean isAccountNonLocked () {
return true ;
}
@ JsonIgnore
@ Override
public boolean isCredentialsNonExpired () {
return true ;
}
@ JsonIgnore
@ Override
public String getPassword () {
return password ;
}
@ Override
public Collection <? extends GrantedAuthority > getAuthorities () {
return authorities ;
}
@ Override
public boolean isEnabled () {
return true ;
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/jwt/JWTWebSecurityConfig.java
package com .in28minutes .rest .webservices .restfulwebservices .jwt ;
import org .springframework .beans .factory .annotation .Autowired ;
import org .springframework .beans .factory .annotation .Value ;
import org .springframework .context .annotation .Bean ;
import org .springframework .context .annotation .Configuration ;
import org .springframework .http .HttpMethod ;
import org .springframework .security .authentication .AuthenticationManager ;
import org .springframework .security .config .annotation .authentication .builders .AuthenticationManagerBuilder ;
import org .springframework .security .config .annotation .method .configuration .EnableGlobalMethodSecurity ;
import org .springframework .security .config .annotation .web .builders .HttpSecurity ;
import org .springframework .security .config .annotation .web .builders .WebSecurity ;
import org .springframework .security .config .annotation .web .configuration .EnableWebSecurity ;
import org .springframework .security .config .annotation .web .configuration .WebSecurityConfigurerAdapter ;
import org .springframework .security .config .http .SessionCreationPolicy ;
import org .springframework .security .core .userdetails .UserDetailsService ;
import org .springframework .security .crypto .bcrypt .BCryptPasswordEncoder ;
import org .springframework .security .crypto .password .PasswordEncoder ;
import org .springframework .security .web .authentication .UsernamePasswordAuthenticationFilter ;
@ Configuration
@ EnableWebSecurity
@ EnableGlobalMethodSecurity (prePostEnabled = true )
public class JWTWebSecurityConfig extends WebSecurityConfigurerAdapter {
@ Autowired
private JwtUnAuthorizedResponseAuthenticationEntryPoint jwtUnAuthorizedResponseAuthenticationEntryPoint ;
@ Autowired
private UserDetailsService jwtInMemoryUserDetailsService ;
@ Autowired
private JwtTokenAuthorizationOncePerRequestFilter jwtAuthenticationTokenFilter ;
@ Value ("${jwt.get.token.uri}" )
private String authenticationPath ;
@ Autowired
public void configureGlobal (AuthenticationManagerBuilder auth ) throws Exception {
auth .userDetailsService (jwtInMemoryUserDetailsService ).passwordEncoder (passwordEncoderBean ());
}
@ Bean
public PasswordEncoder passwordEncoderBean () {
return new BCryptPasswordEncoder ();
}
@ Bean
@ Override
public AuthenticationManager authenticationManagerBean () throws Exception {
return super .authenticationManagerBean ();
}
@ Override
protected void configure (HttpSecurity httpSecurity ) throws Exception {
httpSecurity .csrf ().disable ().exceptionHandling ()
.authenticationEntryPoint (jwtUnAuthorizedResponseAuthenticationEntryPoint ).and ().sessionManagement ()
.sessionCreationPolicy (SessionCreationPolicy .STATELESS ).and ().authorizeRequests ().anyRequest ()
.authenticated ();
httpSecurity .addFilterBefore (jwtAuthenticationTokenFilter , UsernamePasswordAuthenticationFilter .class );
httpSecurity .headers ().frameOptions ().sameOrigin () // H2 Console Needs this setting
.cacheControl (); // disable caching
}
@ Override
public void configure (WebSecurity webSecurity ) throws Exception {
webSecurity .ignoring ().antMatchers (HttpMethod .POST , authenticationPath )
.antMatchers (HttpMethod .OPTIONS , "/**" )
.and ().ignoring ()
.antMatchers (HttpMethod .GET , "/" // Other Stuff You want to Ignore
).and ().ignoring ()
.antMatchers ("/h2-console/**/**" );// Should not be done in Production!
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/jwt/resource/AuthenticationException.java
package com .in28minutes .rest .webservices .restfulwebservices .jwt .resource ;
public class AuthenticationException extends RuntimeException {
public AuthenticationException (String message , Throwable cause ) {
super (message , cause );
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/jwt/resource/JwtAuthenticationRestController.java
package com .in28minutes .rest .webservices .restfulwebservices .jwt .resource ;
import java .util .Objects ;
import javax .servlet .http .HttpServletRequest ;
import org .springframework .beans .factory .annotation .Autowired ;
import org .springframework .beans .factory .annotation .Value ;
import org .springframework .http .HttpStatus ;
import org .springframework .http .ResponseEntity ;
import org .springframework .security .authentication .AuthenticationManager ;
import org .springframework .security .authentication .BadCredentialsException ;
import org .springframework .security .authentication .DisabledException ;
import org .springframework .security .authentication .UsernamePasswordAuthenticationToken ;
import org .springframework .security .core .userdetails .UserDetails ;
import org .springframework .security .core .userdetails .UserDetailsService ;
import org .springframework .web .bind .annotation .CrossOrigin ;
import org .springframework .web .bind .annotation .ExceptionHandler ;
import org .springframework .web .bind .annotation .RequestBody ;
import org .springframework .web .bind .annotation .RequestMapping ;
import org .springframework .web .bind .annotation .RequestMethod ;
import org .springframework .web .bind .annotation .RestController ;
import com .in28minutes .rest .webservices .restfulwebservices .jwt .JwtTokenUtil ;
import com .in28minutes .rest .webservices .restfulwebservices .jwt .JwtUserDetails ;
@ RestController
@ CrossOrigin (origins = "http://localhost:4200" )
public class JwtAuthenticationRestController {
@ Value ("${jwt.http.request.header}" )
private String tokenHeader ;
@ Autowired
private AuthenticationManager authenticationManager ;
@ Autowired
private JwtTokenUtil jwtTokenUtil ;
@ Autowired
private UserDetailsService jwtInMemoryUserDetailsService ;
@ RequestMapping (value = "${jwt.get.token.uri}" , method = RequestMethod .POST )
public ResponseEntity <?> createAuthenticationToken (@ RequestBody JwtTokenRequest authenticationRequest )
throws AuthenticationException {
authenticate (authenticationRequest .getUsername (), authenticationRequest .getPassword ());
final UserDetails userDetails = jwtInMemoryUserDetailsService
.loadUserByUsername (authenticationRequest .getUsername ());
final String token = jwtTokenUtil .generateToken (userDetails );
return ResponseEntity .ok (new JwtTokenResponse (token ));
}
@ RequestMapping (value = "${jwt.refresh.token.uri}" , method = RequestMethod .GET )
public ResponseEntity <?> refreshAndGetAuthenticationToken (HttpServletRequest request ) {
String authToken = request .getHeader (tokenHeader );
final String token = authToken .substring (7 );
String username = jwtTokenUtil .getUsernameFromToken (token );
JwtUserDetails user = (JwtUserDetails ) jwtInMemoryUserDetailsService .loadUserByUsername (username );
if (jwtTokenUtil .canTokenBeRefreshed (token )) {
String refreshedToken = jwtTokenUtil .refreshToken (token );
return ResponseEntity .ok (new JwtTokenResponse (refreshedToken ));
} else {
return ResponseEntity .badRequest ().body (null );
}
}
@ ExceptionHandler ({ AuthenticationException .class })
public ResponseEntity <String > handleAuthenticationException (AuthenticationException e ) {
return ResponseEntity .status (HttpStatus .UNAUTHORIZED ).body (e .getMessage ());
}
private void authenticate (String username , String password ) {
Objects .requireNonNull (username );
Objects .requireNonNull (password );
try {
authenticationManager .authenticate (new UsernamePasswordAuthenticationToken (username , password ));
} catch (DisabledException e ) {
throw new AuthenticationException ("USER_DISABLED" , e );
} catch (BadCredentialsException e ) {
throw new AuthenticationException ("INVALID_CREDENTIALS" , e );
}
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/jwt/resource/JwtTokenRequest.java
package com .in28minutes .rest .webservices .restfulwebservices .jwt .resource ;
import java .io .Serializable ;
public class JwtTokenRequest implements Serializable {
private static final long serialVersionUID = -5616176897013108345L ;
private String username ;
private String password ;
public JwtTokenRequest () {
super ();
}
public JwtTokenRequest (String username , String password ) {
this .setUsername (username );
this .setPassword (password );
}
public String getUsername () {
return this .username ;
}
public void setUsername (String username ) {
this .username = username ;
}
public String getPassword () {
return this .password ;
}
public void setPassword (String password ) {
this .password = password ;
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/jwt/resource/JwtTokenResponse.java
package com .in28minutes .rest .webservices .restfulwebservices .jwt .resource ;
import java .io .Serializable ;
public class JwtTokenResponse implements Serializable {
private static final long serialVersionUID = 8317676219297719109L ;
private final String token ;
public JwtTokenResponse (String token ) {
this .token = token ;
}
public String getToken () {
return this .token ;
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/RestfulWebServicesApplication.java
package com .in28minutes .rest .webservices .restfulwebservices ;
import org .springframework .boot .SpringApplication ;
import org .springframework .boot .autoconfigure .SpringBootApplication ;
@ SpringBootApplication
public class RestfulWebServicesApplication {
public static void main (String [] args ) {
SpringApplication .run (RestfulWebServicesApplication .class , args );
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/Todo.java
package com .in28minutes .rest .webservices .restfulwebservices .todo ;
import java .util .Date ;
import javax .persistence .Entity ;
import javax .persistence .GeneratedValue ;
import javax .persistence .Id ;
@ Entity
public class Todo {
@ Id
@ GeneratedValue
private Long id ;
private String username ;
private String description ;
private Date targetDate ;
private boolean isDone ;
protected Todo () {
}
public Todo (long id , String username , String description , Date targetDate , boolean isDone ) {
super ();
this .id = id ;
this .username = username ;
this .description = description ;
this .targetDate = targetDate ;
this .isDone = isDone ;
}
public Long getId () {
return id ;
}
public void setId (Long id ) {
this .id = id ;
}
public String getUsername () {
return username ;
}
public void setUsername (String username ) {
this .username = username ;
}
public String getDescription () {
return description ;
}
public void setDescription (String description ) {
this .description = description ;
}
public Date getTargetDate () {
return targetDate ;
}
public void setTargetDate (Date targetDate ) {
this .targetDate = targetDate ;
}
public boolean isDone () {
return isDone ;
}
public void setDone (boolean isDone ) {
this .isDone = isDone ;
}
@ Override
public int hashCode () {
final int prime = 31 ;
int result = 1 ;
result = prime * result + (int ) (id ^ (id >>> 32 ));
return result ;
}
@ Override
public boolean equals (Object obj ) {
if (this == obj )
return true ;
if (obj == null )
return false ;
if (getClass () != obj .getClass ())
return false ;
Todo other = (Todo ) obj ;
if (id != other .id )
return false ;
return true ;
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/TodoHardcodedService.java
package com .in28minutes .rest .webservices .restfulwebservices .todo ;
import java .util .ArrayList ;
import java .util .Date ;
import java .util .List ;
import org .springframework .stereotype .Service ;
@ Service
public class TodoHardcodedService {
private static List <Todo > todos = new ArrayList <>();
private static long idCounter = 0 ;
static {
todos .add (new Todo (++idCounter , "in28minutes" ,"Learn to Dance 2" , new Date (), false ));
todos .add (new Todo (++idCounter , "in28minutes" ,"Learn about Microservices 2" , new Date (), false ));
todos .add (new Todo (++idCounter , "in28minutes" ,"Learn about Angular" , new Date (), false ));
}
public List <Todo > findAll () {
return todos ;
}
public Todo save (Todo todo ) {
if (todo .getId ()==-1 || todo .getId ()==0 ) {
todo .setId (++idCounter );
todos .add (todo );
} else {
deleteById (todo .getId ());
todos .add (todo );
}
return todo ;
}
public Todo deleteById (long id ) {
Todo todo = findById (id );
if (todo ==null ) return null ;
if (todos .remove (todo )) {
return todo ;
}
return null ;
}
public Todo findById (long id ) {
for (Todo todo :todos ) {
if (todo .getId () == id ) {
return todo ;
}
}
return null ;
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/TodoJpaRepository.java
package com .in28minutes .rest .webservices .restfulwebservices .todo ;
import java .util .List ;
import org .springframework .data .jpa .repository .JpaRepository ;
import org .springframework .stereotype .Repository ;
@ Repository
public interface TodoJpaRepository extends JpaRepository <Todo , Long >{
List <Todo > findByUsername (String username );
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/TodoJpaResource.java
package com .in28minutes .rest .webservices .restfulwebservices .todo ;
import java .net .URI ;
import java .util .List ;
import org .springframework .beans .factory .annotation .Autowired ;
import org .springframework .http .HttpStatus ;
import org .springframework .http .ResponseEntity ;
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 .PathVariable ;
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 .RestController ;
import org .springframework .web .servlet .support .ServletUriComponentsBuilder ;
import com .in28minutes .rest .webservices .restfulwebservices .todo .Todo ;
@ CrossOrigin (origins ="http://localhost:4200" )
@ RestController
public class TodoJpaResource {
@ Autowired
private TodoHardcodedService todoService ;
@ Autowired
private TodoJpaRepository todoJpaRepository ;
@ GetMapping ("/jpa/users/{username}/todos" )
public List <Todo > getAllTodos (@ PathVariable String username ){
return todoJpaRepository .findByUsername (username );
//return todoService.findAll();
}
@ GetMapping ("/jpa/users/{username}/todos/{id}" )
public Todo getTodo (@ PathVariable String username , @ PathVariable long id ){
return todoJpaRepository .findById (id ).get ();
//return todoService.findById(id);
}
//DELETE /users/{username}/todos/{id}
@ DeleteMapping ("/jpa/users/{username}/todos/{id}" )
public ResponseEntity <Void > deleteTodo (
@ PathVariable String username , @ PathVariable long id ){
//Todo todo = todoService.deleteById(id);
todoJpaRepository .deleteById (id );
return ResponseEntity .noContent ().build ();
//return ResponseEntity.notFound().build();
}
//Edit/Update a Todo
//PUT /users/{user_name}/todos/{todo_id}
@ PutMapping ("/jpa/users/{username}/todos/{id}" )
public ResponseEntity <Todo > updateTodo (
@ PathVariable String username ,
@ PathVariable long id , @ RequestBody Todo todo ){
//Todo todoUpdated = todoService.save(todo);
Todo todoUpdated = todoJpaRepository .save (todo );
return new ResponseEntity <Todo >(todo , HttpStatus .OK );
}
@ PostMapping ("/jpa/users/{username}/todos" )
public ResponseEntity <Void > createTodo (
@ PathVariable String username , @ RequestBody Todo todo ){
//Todo createdTodo = todoService.save(todo);
todo .setUsername (username );
Todo createdTodo = todoJpaRepository .save (todo );
//Location
//Get current resource url
///{id}
URI uri = ServletUriComponentsBuilder .fromCurrentRequest ()
.path ("/{id}" ).buildAndExpand (createdTodo .getId ()).toUri ();
return ResponseEntity .created (uri ).build ();
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/TodoResource.java
package com .in28minutes .rest .webservices .restfulwebservices .todo ;
import java .net .URI ;
import java .util .List ;
import org .springframework .beans .factory .annotation .Autowired ;
import org .springframework .http .HttpStatus ;
import org .springframework .http .ResponseEntity ;
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 .PathVariable ;
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 .RestController ;
import org .springframework .web .servlet .support .ServletUriComponentsBuilder ;
import com .in28minutes .rest .webservices .restfulwebservices .todo .Todo ;
@ CrossOrigin (origins ="http://localhost:4200" )
@ RestController
public class TodoResource {
@ Autowired
private TodoHardcodedService todoService ;
@ GetMapping ("/users/{username}/todos" )
public List <Todo > getAllTodos (@ PathVariable String username ){
return todoService .findAll ();
}
@ GetMapping ("/users/{username}/todos/{id}" )
public Todo getTodo (@ PathVariable String username , @ PathVariable long id ){
return todoService .findById (id );
}
//DELETE /users/{username}/todos/{id}
@ DeleteMapping ("/users/{username}/todos/{id}" )
public ResponseEntity <Void > deleteTodo (
@ PathVariable String username , @ PathVariable long id ){
Todo todo = todoService .deleteById (id );
if (todo !=null ) {
return ResponseEntity .noContent ().build ();
}
return ResponseEntity .notFound ().build ();
}
//Edit/Update a Todo
//PUT /users/{user_name}/todos/{todo_id}
@ PutMapping ("/users/{username}/todos/{id}" )
public ResponseEntity <Todo > updateTodo (
@ PathVariable String username ,
@ PathVariable long id , @ RequestBody Todo todo ){
Todo todoUpdated = todoService .save (todo );
return new ResponseEntity <Todo >(todo , HttpStatus .OK );
}
@ PostMapping ("/users/{username}/todos" )
public ResponseEntity <Void > updateTodo (
@ PathVariable String username , @ RequestBody Todo todo ){
Todo createdTodo = todoService .save (todo );
//Location
//Get current resource url
///{id}
URI uri = ServletUriComponentsBuilder .fromCurrentRequest ()
.path ("/{id}" ).buildAndExpand (createdTodo .getId ()).toUri ();
return ResponseEntity .created (uri ).build ();
}
}
/restful-web-services/src/main/resources/application.properties
logging.level.org.springframework = info
# spring.security.user.name=in28minutes
# spring.security.user.password=dummy
jwt.signing.key.secret =mySecret
jwt.get.token.uri =/authenticate
jwt.refresh.token.uri =/refresh
jwt.http.request.header =Authorization
jwt.token.expiration.in.seconds =604800
spring.jpa.show-sql =true
spring.h2.console.enabled =true
/restful-web-services/src/main/resources/data.sql
insert into todo(id, username,description,target_date,is_done)
values(10001, 'in28minutes', 'Learn JPA', sysdate(), false);
insert into todo(id, username,description,target_date,is_done)
values(10002, 'in28minutes', 'Learn Data JPA', sysdate(), false);
insert into todo(id, username,description,target_date,is_done)
values(10003, 'in28minutes', 'Learn Microservices', sysdate(), false);
/restful-web-services/src/test/java/com/in28minutes/rest/webservices/restfulwebservices/RestfulWebServicesApplicationTests.java
package com .in28minutes .rest .webservices .restfulwebservices ;
import org .junit .Test ;
import org .junit .runner .RunWith ;
import org .springframework .boot .test .context .SpringBootTest ;
import org .springframework .test .context .junit4 .SpringRunner ;
@ RunWith (SpringRunner .class )
@ SpringBootTest
public class RestfulWebServicesApplicationTests {
@ Test
public void contextLoads () {
}
}