Spring Boot Webservice (AutoRecovered)
Spring Boot Webservice (AutoRecovered)
is called as Poducer(Server).
Type Code
---------------------------------------
Information 1xx
Redirect 3xx
Ref:-
https://developer.mozilla.org/en-US/docs/Web/HTTP
A) Get Will not support request Body. It is used to fetch data from server.
Just used to call a task at server (do not know its message,
A)
Get Will not support request Body. It is used to fetch data from server.
Post is used to send data using its request body (Data is hidden here),
Post is used to send data using its request body (Data is hidden here),
Put is used to send data using its request body (Data is hidden here),
Date : 12-11-2022
Mr. Raghu
(ASHOK IT)
---------------------------------------------------------------------
Webservices
========================================================================
-------------------------------------------------------------------
"key" : value,
"key" : value,
...
=> Every key must be quoted, value is quoted for String type.
-------------------------------------------------------------------
Java JavaScript
------------------------------------------------------------------
int id = 10 var id = 10
e.setName("ABC");
--------------------------------------------------------------------
1. Primitives Data
2. Array/List/Set
3. Map/child class(HAS-A)
"project" : {
"pid" : "101",
"pcode": "AA"
A)
JSON YAML
============================================================
ex:
<employee>
<eid>10</eid>
<ename>AJ</ename>
</employee>
======================================================================
Webservices 2 Types:
Re = Representation
S = State
T = Trasfer
=>** Send/receive data in global format.
(pre-defined classes/interfaces/enums/annotation)
-------------------------------------------------------------------
(Java) (.net)
Angular/ReactJS
Mr. Raghu
(ASHOK IT)
---------------------------------------------------------------------
ReST(Architecture/Client-Server) [XML/JSON/Text]
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- case#1
Restful Webservices
+----------------------------+----------------------------------------+
| Controller | RestController |
+----------------------------+----------------------------------------+
(UI/Java based-JSP/Thymeleaf)
(Model/ModelAttribute..etc)
It is a full web-app developing It is like a service Provider
(Any Language)
+----------------------------+----------------------------------------+
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- case#2
Frontend Applications are called as Client Apps which are fully dependent
only.
==================================================================== case#3
Compile
Build
Deploy
Instance
Scale(Horizontal/Vertical)
DownTime
Load balace
IP Address (private/public/elastic)
Network/firewall/routing.
Date : 14-11-2022
Spring Boot and Microservices
Mr. Raghu
(ASHOK IT)
---------------------------------------------------------------------
Servlet (DispatcherServlet).
RestController#Method details
(ex: PaymentRestController#doPay)
*) Note:
4. For both Spring boot WEB MVC and Spring boot ReST we have to use same dependency "Spring
Boot WEB" that comes with default server "Tomcat" with default port:8080
Download Link:
https://www.postman.com/downloads/
+----------------------------+----------------------------------------+
| Controller | RestController |
+----------------------------+----------------------------------------+
(UI/Java based-JSP/Thymeleaf)
(Model/ModelAttribute..etc)
(Any Language)
+----------------------------+----------------------------------------+
3. @GetMapping
4. @PostMapping
5. @PutMapping
6. @PatchMapping
7. @DeleteMapping
========================================================================
405 - Method Not Allowed (URL is valid, but not Http Method type)
App/Coding Steps:-
Name: SpringBootRestProducerFirstEx
org.springframework.http.ResponseEntity; import
org.springframework.web.bind.annotation.DeleteMapping; import
org.springframework.web.bind.annotation.GetMapping; import
org.springframework.web.bind.annotation.PatchMapping; import
org.springframework.web.bind.annotation.PostMapping; import
org.springframework.web.bind.annotation.PutMapping; import
org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/product")
@GetMapping("/fetch")
return response;
@PostMapping("/save")
HttpStatus.OK
);
return response;
@PutMapping("/update") public
ResponseEntity<String> updateProduct() {
HttpStatus.OK
);
return response;
@DeleteMapping("/remove")
);
return response;
@PatchMapping("/updatecost")
HttpStatus.OK
);
return response;
[PATCH] http://localhost:8080/product/updatecost[SEND]
--Task----------------------------------------------------
Write one simple REST API For Student that will display simple messages for
===================================================================== Q)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
(or)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
====================================================================
Date : 15-11-2022
Mr. Raghu
(ASHOK IT)
---------------------------------------------------------------------
MediaType annotations.
1. @RequestBody : It will read Http Request Body Section, checks
*)Note:
@ResponseBody.
===============================================================
JSON Syntax:
element1, element2,...
"key":val, "key":val
}
===========Working with output (@ResponseBody) ==================
Name : SpringBootRestJSONOutput
1. Entity classes
package com.app.raghu.entity;
java.util.Set;
com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
lombok.NoArgsConstructor;
@Data
@NoArgsConstructor @AllArgsConstructor
@JsonProperty("user-unq-id")
@JsonProperty("user-first-name")
@JsonIgnore
-------Role Entity-----------
package com.app.raghu.entity;
import lombok.AllArgsConstructor;
lombok.NoArgsConstructor;
@Data
@NoArgsConstructor @AllArgsConstructor
com.app.raghu.rest;
import java.util.Arrays;
java.util.Map; import
java.util.Set;
org.springframework.http.ResponseEntity; import
org.springframework.web.bind.annotation.GetMapp
ing; import
org.springframework.web.bind.annotation.Request
Mapping; import
org.springframework.web.bind.annotation.RestCont
roller;
com.app.raghu.entity.User;
@RestController
@RequestMapping("/user") public
class UserRestController {
@GetMapping("/one")
//@ResponseBody
Set.of("P1","P2"),
Map.of("M1","AA","M2","AB")
);
return response;
@GetMapping("/list")
);
@GetMapping("/map")
);
return response;
URLS:
http://localhost:9090/user/one http://localhost:9090/user/list
http://localhost:9090/user/map
=======================================================================
Note:
(used in project)
======================================================================= Q)
A) @JsonIgnore
A) null is printed.
A) @JsonProperty
=================================================================
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
Accept = application/xml
Mr. Raghu
(ASHOK IT)
---------------------------------------------------------------------
@RequestBody: It takes data (XML/JSON) from Http Request Body Section and
+--------------------------------------+
+--------------------------------------+
| |
| Content-Type: application/json |
+--------------------------------------+
| |
+--------------------------------------+
Syntax:
3. If any field/variable is missing data from JSON, then it holds default value based on datatype (ex:
ex:
"empId": 10,
"empName": "A",
"empSal": 300.0,
"empDept" : "DEV"
Ex:
"empId": 10,
"empSal": 300.0,
"empName": "A"
MediaType.
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
=============Code=======================================
Name : SpringBootRestMediaTypeOutputEx
1. Entity package
com.app.raghu.entity;
import lombok.Data;
@Data
2. RestController
package com.app.raghu.rest;
org.springframework.http.ResponseEntity; import
org.springframework.web.bind.annotation.PostMapping; import
org.springframework.web.bind.annotation.RequestBody; import
org.springframework.web.bind.annotation.RequestMapping; import
org.springframework.web.bind.annotation.RestController;
import com.app.raghu.entity.Employee;
@RestController
@RequestMapping("/employee")
@PostMapping("/create") public
ResponseEntity<String> createEmployee(
String s = employee.toString();
return response;
==========Complex Inputs========================================
1. Entity classes
package com.app.raghu.entity;
import lombok.AllArgsConstructor;
lombok.NoArgsConstructor;
@Data
@NoArgsConstructor @AllArgsConstructor
-----------------
package com.app.raghu.entity;
java.util.Map;
import lombok.AllArgsConstructor;
lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor public
class Employee {
com.app.raghu.rest;
java.util.Map;
org.springframework.web.bind.annotation.PostMapping; import
org.springframework.web.bind.annotation.RequestBody; import
org.springframework.web.bind.annotation.RequestMapping; import
org.springframework.web.bind.annotation.RestController;
com.app.raghu.entity.Employee;
@RestController
@RequestMapping("/employee")
@GetMapping("/find")
Map.of("A1",10,"A2",20));
@PostMapping("/create") public
ResponseEntity<String> createEmployee(
@RequestBody Employee employee
String s = employee.toString();
return response;
3. POSTMAN Request
URL: http://localhost:9090/employee/create
Method: POST
Body (raw/JSON)
"empId": 10,
"empSal": 300.0,
"empName": "A",
"addr" : {
"hno": "7-A/77-B",
},
"projects" : ["P1","P2","P3"],
Body (raw/XML)
<Employee>
<empId>101</empId>
<empName>AAAA</empName>
<empSal>500.0</empSal>
<addr>
<hno>AB/44</hno>
<loc>HYD</loc>
</addr>
<projects>
<projects>M1</projects>
<projects>M2</projects>
</projects>
<codes>
<A2>20</A2>
<A1>10</A1>
</codes>
</Employee>
=================================================================
Task:
(ASHOK IT)
---------------------------------------------------------------------
Request Parameter:-
ex: http://localhost:9090/employee/find?id=10&name=A
id = Integer.parseInt(val);
--------------------------------
@RequestParam("key")DataType variableName
(or)
===========================================================
.../employee/find/10/A
.../employee/find?name=A&id=10
*) Note:
1. Path Creation
@GetMapping("/employee/find/{id}/{name}")
@PathVariable("key")DataType variable
====================code============================================
Name : SpringBootRestPathVariableEx
com.app.raghu.rest;
org.springframework.http.ResponseEntity; import
org.springframework.web.bind.annotation.GetMapping; import
org.springframework.web.bind.annotation.PathVariable; import
org.springframework.web.bind.annotation.RequestMapping; import
org.springframework.web.bind.annotation.RequestParam; import
org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/product") public
class ProductRestController { //
Using RequestParam
// .../dataa?pid=10&pname=A
@GetMapping("/dataa") public
ResponseEntity<String> showDataA(
{
System.out.println("PID " + id +" PNAME "+ name); return new
// Using Pathvariable
//.../datab/10/A
@GetMapping("/datab/{pid}/{pname}")
Request URL:
1.
http://localhost:9090/product/datab/101/MNO
2.
http://localhost:9090/product/datab/222/111
3.
http://localhost:9090/product/datab/MNO/888
Output
4.
http://localhost:9090/product/dataa?pid=10&pname=A
Output
5.
http://localhost:9090/product/dataa?pname=AB&pid=101
Output
===============================================================
Still lot of apps are using RequestParam. So, Spring boot even supports
? q= sachin+tendulkar
& sxsrf=ALiCzsZBVp76CI2yhnmxjbUGyPbMNMyotQ%3A1668650417775
& source=hp
& ei=sZV1Y6bJLMe3z7sPvtWYqAM
& iflsig=AJiK0e8AAAAAY3Wjwf8qaKKi4GIF9p
===============================================================
@RequestHeader("key")DataType variableName
=======================================================================
Example: package
com.app.raghu.rest;
//ctrl+shift+O
@RestController
@RequestMapping("/product")
@PostMapping("/details") public
ResponseEntity<String> showHeaders(
@RequestHeader("Content-Type")String type,
@RequestHeader("Content-Length")String len,
@RequestHeader("Authorization")String auth,
HttpServletRequest req
System.out.println(auth);
(headerNames.hasMoreElements()) {
==============================================================
new ResponseEntity<String>("OK",HttpStatus.OK);
} else {
}
Date : 18-11-2022
Mr. Raghu
(ASHOK IT)
---------------------------------------------------------------------
In this case we can not provide our Status code and Headers,
======================================================================== Q)
*) Http Headers are MultiValueMaps. ie one key can have multiple values
Ex:
Accept = application/xml,application/json,*/*
A)
only body.
======================Sample code==========================================
Name : SpringBootRestReturnTypeEx
1. Entity package
com.app.raghu.entity;
import lombok.AllArgsConstructor;
lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor public
class Book {
2. RestController package
com.app.raghu.rest;
import org.springframework.http.HttpHeaders; import
org.springframework.http.HttpStatus; import
org.springframework.http.ResponseEntity; import
org.springframework.web.bind.annotation.GetMapping; import
org.springframework.web.bind.annotation.RequestMapping; import
org.springframework.web.bind.annotation.RestController;
import com.app.raghu.entity.Book;
@RestController
@RequestMapping("/book")
@GetMapping("/a")
@GetMapping("/b")
@GetMapping("/data")
CLIENT");
return response;
==================================================================
*) Entity class
package com.app.raghu.entity;
import lombok.AllArgsConstructor;
lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor public
class Book {
}
*) REstController package
com.app.raghu.rest;
org.springframework.http.HttpStatus; import
org.springframework.http.ResponseEntity; import
org.springframework.web.bind.annotation.GetMapping; import
org.springframework.web.bind.annotation.PathVariable; import
org.springframework.web.bind.annotation.RequestMapping; import
org.springframework.web.bind.annotation.RestController;
import com.app.raghu.entity.Book;
@RestController
@RequestMapping("/book")
if(id == 501) {
headers.add("found", "yes");
headers, //headers
} else {
headers.add("found", "no");
headers, //headers
return response;
Date : 21-11-2022
7AM
Mr. Raghu
(ASHOK IT)
---------------------------------------------------------------------
Ex:
"timestamp": "2022-11-21T01:42:22.666+00:00",
"status": 500,
"path": "/product/one/5586"
com.app.raghu.rest;
org.springframework.http.ResponseEntity; import
org.springframework.web.bind.annotation.GetMapping; import
org.springframework.web.bind.annotation.PathVariable; import
org.springframework.web.bind.annotation.RequestMapping; import
org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/product") public
class ProductRestController {
@GetMapping("/one/{id}") public
ResponseEntity<String> getProductById(
@PathVariable("id") Integer id
if(id==150)
else
2. application.properties server.port=9090
3. POSTMAN URL
GET http://localhost:9090/product/one/158
GET http://localhost:9090/product/one/150
====================================================================
*******************************************************************
*******************************************************************
====================================================================
We can define our own Response Format incase of Any exception occured in
@ExceptionHandler.
"BasicErrorController".
=> For one exception type, we need to define one Handler method.
return Custom Error Response class type for JSON/XML output. ie @RestControllerAdvice internally
-------------case#1-----------------------------------------
1. RestController package
com.app.raghu.rest;
import org.springframework.beans.factory.annotation.Autowired;
org.springframework.http.ResponseEntity; import
org.springframework.web.bind.annotation.GetMapping; import
org.springframework.web.bind.annotation.PathVariable; import
org.springframework.web.bind.annotation.RequestMapping; import
org.springframework.web.bind.annotation.RestController;
com.app.raghu.exception.ProductNotFoundException; import
com.app.raghu.service.ProductService;
@RestController
@RequestMapping("/product")
@PathVariable("id") Integer id
if(id==150)
else
com.app.raghu.handler;
import java.util.Date;
org.springframework.http.ResponseEntity; import
org.springframework.web.bind.annotation.ExceptionHandler; import
org.springframework.web.bind.annotation.RestControllerAdvice;
com.app.raghu.exception.ProductNotFoundException;
MyCustomExceptionHandler {
@ExceptionHandler(ProductNotFoundException.class)
public ResponseEntity<String> showCustomErrorMsg(
ProductNotFoundException pnfe
pnfe.getMessage(),
HttpStatus.INTERNAL_SERVER_ERROR);
----------case#2------------------------------------------
2. Custom ErrorResponse
1. Entity/Beans package
com.app.raghu.entity;
import lombok.AllArgsConstructor;
lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor public
class Product {
--------------
package com.app.raghu.bean;
import lombok.AllArgsConstructor;
lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor public
class MyErrorResponse {
message;
package
com.app.raghu.exception;
extends RuntimeException
/**
*/
public ProductNotFoundException() {
super();
super(message);
}
com.app.raghu.service;
import org.springframework.stereotype.Service;
com.app.raghu.exception.ProductNotFoundException;
ProductService {
if(id==150) return
else
4. RestController package
com.app.raghu.rest;
import org.springframework.beans.factory.annotation.Autowired;
org.springframework.http.ResponseEntity;
org.springframework.web.bind.annotation.PathVariable; import
org.springframework.web.bind.annotation.RequestMapping; import
org.springframework.web.bind.annotation.RestController;
import com.app.raghu.entity.Product; import
com.app.raghu.exception.ProductNotFoundException; import
com.app.raghu.service.ProductService;
@RestController
@RequestMapping("/product") public
class ProductRestController {
@Autowired
/*
@GetMapping("/one/{id}") public
ResponseEntity<String> getProductById(
@PathVariable("id") Integer id
if(id==150)
else
}*/
@GetMapping("/one/{id}")
@PathVariable("id") Integer id
try {
Product pob = service.getOneProductById(id);
pnfe.printStackTrace();
return response;
com.app.raghu.handler;
import java.util.Date;
org.springframework.http.ResponseEntity; import
org.springframework.web.bind.annotation.ExceptionHandler; import
org.springframework.web.bind.annotation.RestControllerAdvice;
com.app.raghu.exception.ProductNotFoundException;
MyCustomExceptionHandler { /*
@ExceptionHandler(ProductNotFoundException.class)
ProductNotFoundException pnfe
pnfe.getMessage(),
HttpStatus.INTERNAL_SERVER_ERROR);
}
*/
@ExceptionHandler(ProductNotFoundException.class) public
ResponseEntity<MyErrorResponse> showCustomErrorMsg(
ProductNotFoundException pnfe
new MyErrorResponse(
new Date().toString(),
"EXCEPTION IN PROCESS",
500,
pnfe.getMessage()),
HttpStatus.INTERNAL_SERVER_ERROR);
================================================================== Q)
-> throw exception obj -> Exception Handler -> compare type
---------------------------------------------------------------------
=> RestTemplate:
1. it is a class
-> Arrays can be any number and any order as parameter for a method
1. Producer Code
Name : 07SpringBootRestProducerEx
com.app.raghu.entity;
import lombok.AllArgsConstructor;
lombok.NoArgsConstructor;
@Data
@NoArgsConstructor @AllArgsConstructor
bcost;
*) RestController package
com.app.raghu.rest; import
org.springframework.http.Re
sponseEntity; import
org.springframework.web.bi
nd.annotation.GetMapping;
import
org.springframework.web.bi
nd.annotation.PathVariable;
import
org.springframework.web.bi
nd.annotation.RequestMapp
ing; import
org.springframework.web.bi
nd.annotation.RestControlle
r;
import com.app.raghu.entity.Book;
@RestController
@RequestMapping("/v1/api/book")
@GetMapping("/showA")
@GetMapping("/showB/{id}/{name}")
return ResponseEntity.ok("WELCOME TO FIRST CALL TYPE - GET ==> " +id +""+name);
500.0)); }
----------------------------------
2. Consumer Code
Name : 07SpringBootRestConsumerEx
==application.properties== server.port=9696
com.app.raghu.runner;
import org.springframework.boot.CommandLineRunner;
org.springframework.stereotype.Component; import
org.springframework.web.client.RestTemplate;
@Component
// 2+3
System.out.println(response.getBody());
System.out.println(response.getHeaders());
System.out.println(response.getStatusCode().name());
System.out.println(response.getStatusCode().value());
-----------------------------------------
package com.app.raghu.runner;
import org.springframework.boot.CommandLineRunner;
org.springframework.web.client.RestTemplate;
Exception {
// 2+3
ResponseEntity<String> response =
template.getForEntity(
url,
String.class,
);
System.out.println(response.getBody());
System.out.println(response.getHeaders());
System.out.println(response.getStatusCode().name());
System.out.println(response.getStatusCode().value());
========================================================================
--API--
postForEntity(
url : String,
requestEntity:HttpEntity,
responseType:K.class
) ResponseEntity<K>
--Sample code---
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
===============================CODE=============================
com.app.raghu.rest;
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.RequestBody; import
org.springframework.web.bind.annotation.RequestMapping; import
org.springframework.web.bind.annotation.RestController;
import com.app.raghu.entity.Book;
@RestController
@RequestMapping("/v1/api/book") public
class BookRestController {
@PostMapping("/showD") public
ResponseEntity<String> showMgs4(
}
2. Consumer code (Runner class) package
com.app.raghu.runner;
import org.springframework.boot.CommandLineRunner;
org.springframework.http.HttpHeaders; import
org.springframework.http.MediaType; import
org.springframework.http.ResponseEntity; import
org.springframework.stereotype.Component; import
org.springframework.web.client.RestTemplate;
@Component
headers.setContentType(MediaType.APPLICATION_JSON);
ResponseEntity<String> response =
System.out.println(response.getBody());
System.out.println(response.getHeaders());
System.out.println(response.getStatusCode().name());
System.out.println(response.getStatusCode().value());
}
Date : 23-11-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
RestTemplate (Http Client)
exchange(
url,
HttpMethod,
HttpEntity(request),
ResponseType.class,
pathVariables...
): ResponseEntity<T>
Old Line:
ResponseEntity<String> response = template.getForEntity(url,String.class,101, "ABC" );
New Line:
ResponseEntity<String> response = template.exchange(url, HttpMethod.GET, null, String.class,
101,"ABC");
*) There are no direct methods for put() and delete() that returns
ResponseEntity<>. In that case we use exchange() method.
*) RestController code
package com.app.raghu.rest;
import org.springframework.http.ResponseEntity;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.app.raghu.entity.Book;
@RestController
@RequestMapping("/v1/api/book")
public class BookRestController {
//-------PUT/DELETE EXAMPLES
@PutMapping("/showE")
public ResponseEntity<String> showMgs5(
@RequestBody Book book
)
{
return ResponseEntity.ok("Data FROM PUT is " + book);
}
@DeleteMapping("/showF/{id}")
public ResponseEntity<String> showMsg6(
@PathVariable("id") Integer id
)
{
return ResponseEntity.ok("DELETE MAPPING " + id);
}
}
=====================================================================
2. Consumer Application
import org.springframework.boot.CommandLineRunner;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
//@Component
public class PutTestARunner implements CommandLineRunner {
System.out.println(response.getBody());
System.out.println(response.getHeaders());
System.out.println(response.getStatusCode().name());
System.out.println(response.getStatusCode().value());
}
---------------------------------------------------------------
package com.app.raghu.runner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
@Component
public class DeleteTestARunner implements CommandLineRunner {
// Print Response
System.out.println(response.getBody());
System.out.println(response.getHeaders());
System.out.println(response.getStatusCode().name());
System.out.println(response.getStatusCode().value());
}
}
=======================================================================
*) Implicite Type Conversion:-
By Default any type of Response Content can be stored in String
(Text/JSON/XML/HTML/..etc). But we can even store JSON/XML into a
Specific type (like Employee.class, in place of String.class)
In that case RestTemplate compares key names and if matched then
type conversion is done internally (Response Body --> JSON/XML--> Objeect)
(Entity class)
package com.app.raghu.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book {
*) Consumer code:
--Runner class-------
package com.app.raghu.runner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import com.app.raghu.entity.BookAtConsumer;
@Component
public class GetTestBRunner implements CommandLineRunner {
System.out.println(response.getBody());
System.out.println(response.getHeaders());
System.out.println(response.getStatusCode().name());
System.out.println(response.getStatusCode().value());
--------Entity class---------
package com.app.raghu.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BookAtConsumer {
Module : Student
Layers: DAL, SL and IL
Class File:
Entity
Repository
CustomException
Service
RestController
RestControllerAdvice
------------------------------------------------------------------------
Name : SpringBootRestCrudMySQLEx
Dep : Spring web, Lombok, Devtools, Data JPA, MySQL
1. application.properties
#Port number
server.port=9690
#Database config
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/boot7am
spring.datasource.username=root
spring.datasource.password=root
#JPA Configuration
spring.jpa.show-sql=true
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.hibernate.ddl-auto=update
2. Entity class
package com.app.raghu.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Data;
@Data
@Entity
@Table(name="stdtab")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="sid")
private Integer stdId;
@Column(name="sname")
private String stdName;
@Column(name="sgen")
private String stdGen;
@Column(name="scourse")
private String stdCourse;
@Column(name="saddr")
private String stdAddr;
}
3. Repository interface
package com.app.raghu.repo;
import org.springframework.data.jpa.repository.JpaRepository;
import com.app.raghu.entity.Student;
4. Service interface
package com.app.raghu.service;
import java.util.List;
import com.app.raghu.entity.Student;
5. Service Impl
package com.app.raghu.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.app.raghu.entity.Student;
import com.app.raghu.exception.StudentNotFoundException;
import com.app.raghu.repo.StudentRepository;
import com.app.raghu.service.IStudentService;
@Service
public class StudentServiceImpl implements IStudentService {
@Autowired
private StudentRepository repo;
@Override
public List<Student> getAllStudents() {
List<Student> list = repo.findAll();
return list;
}
public StudentNotFoundException() {
super();
}
public StudentNotFoundException(String message) {
super(message);
}
}
7. RestController
package com.app.raghu.rest;
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.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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.app.raghu.entity.Student;
import com.app.raghu.exception.StudentNotFoundException;
import com.app.raghu.service.IStudentService;
@RestController
@RequestMapping("/v1/api/student")
public class StudentRestController {
@Autowired
private IStudentService service;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import com.app.raghu.exception.StudentNotFoundException;
@RestControllerAdvice
public class MyCustomExceptionHandler {
@ExceptionHandler(StudentNotFoundException.class)
public ResponseEntity<String> showStudentNotFoundError(
StudentNotFoundException snfe
)
{
return new ResponseEntity<>(
snfe.getMessage(),
HttpStatus.INTERNAL_SERVER_ERROR);
}
}
=======================================================================
*) Note:
1.
200-OK Request is processed without any exception (no failure/success)
2.
201-CREATED -- new resource is created at producer side (Used for POST operations)
Date : 25-11-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Spring Boot ReST -- Backend Application
=======================================================================
1. At Entity class
package com.app.raghu.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import lombok.Data;
@Data
@Entity
@Table(name="stdtab")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="sid")
private Integer stdId;
@Column(name="sname")
//@NotNull(message = "Name can not be null")
//@NotEmpty(message="STUDENT NAME CAN NOT BE EMPTY")
@NotBlank(message="STUDENT NAME CAN NOT BE EMPTY")
@Size(min = 2,max = 6,message = "NAME MUST BE 2-6 CHARS ONLY")
@Pattern(regexp = "[A-Za-z]{2,6}",message = "Only A-Z/a-z are allowed")
private String stdName;
@Column(name="sgen")
@NotBlank(message="STUDENT GENDER CAN NOT BE EMPTY")
private String stdGen;
@Column(name="scourse")
@NotBlank(message="STUDENT COURSE MUST BE SELECTED")
private String stdCourse;
@Column(name="saddr")
@Pattern(regexp = "[A-Za-z0-9\\.\\-\\?]{10,250}",message = "INVALID ADDRESS DETAILS")
private String stdAddr;
}
2. At RestController
Old Code:
@RequestBody Student student
New Code:
@RequestBody @Valid Student student
*) Patterns in Java:
https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html
Date : 28-11-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Frontend Application (Angular/ReactJS)
*) Node
Goto : https://nodejs.org/en/download/
Click on Download Link (OS BASED LINK)
--check using these-------
C:\Users\user> node -v
C:\Users\user> npm -v
C:\Users\user> npx -v
*) VS Code Editor
Link: https://code.visualstudio.com/download
Download and Install (Next > Next > Finish)
> File > open Folder .. > new folder ex: FrontEndApps > Open
===============================================================
*) Angular Setup
Ref This: https://angular.io/guide/setup-local
http://localhost:4200/
Ref:
https://reactjs.org/docs/create-a-new-react-app.html#create-react-app
npx create-react-app@latest student-rjs-app
cd student-rjs-app
npm start
http://localhost:3000/
function App() {
return (
<div className="App">
<h3>WELCOME TO APP</h3>
</div>
);
}
========================Stage#1 START=========================
Step#1 Generate All code files in project
> cd <projectName>
ex:
> cd student-ang-app
---Angular commands to Generage files------
ng g class entities/student --skip-tests
ng g s services/student --skip-tests
ng g c components/student-list --skip-tests
ng g c components/student-add --skip-tests
------------------------------------------------------
Step#2 Activate Forms and HTTP Client concepts
---------------------------------------------------------
Step#3 Configure Routing (For which URL where to GO)
==========================================================
Step#4 Configure Menubar and check Routing working
> index.html
Inside head tag, add below links
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
/>
<script
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.slim.min.js"
></script>
<script
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"
></script>
-------------app.component.html-----------------------
<nav class="navbar navbar-expand-lg navbar-light bg-primary">
<a class="navbar-brand text-white">R-APP</a>
<button
class="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon"></span>
</button>
<router-outlet></router-outlet>
========================Stage#1 END=========================
> ng serve --open
*****************************************************************
========================Stage#2 START=========================
> At backend application, on top of RestController add annotation
@CrossOrigin("http://localhost:4200/")
@Injectable({
providedIn: 'root',
})
export class StudentService {
baseUrl = 'http://localhost:9690/v1/api/student';
getAllStudents(): Observable<Student[]> {
return this.http.get<Student[]>(`${this.baseUrl}/all`);
}
@Component({
selector: 'app-student-list',
templateUrl: './student-list.component.html',
styleUrls: ['./student-list.component.css'],
})
export class StudentListComponent implements OnInit {
students: Student[] = [];
message: any = '';
ngOnInit() {
this.getAllStudents();
}
getAllStudents() {
this.service.getAllStudents().subscribe({
next: (data) => (this.students = data),
error: (err) => console.log(err),
complete: () => console.info('complete'),
});
}
deleteStudent(id: number) {
this.service.deleteStudent(id).subscribe({
next: (data) => {
console.log(data);
this.message = data;
this.getAllStudents();
},
error: (err) => console.log(err),
complete: () => console.info('complete'),
});
}
}
=======================Satage#3 START=========================
> Student Register Process
---student-add.component.html----------
import { Component } from '@angular/core';
import { Student } from 'src/app/entities/student';
import { StudentService } from 'src/app/services/student.service';
@Component({
selector: 'app-student-add',
templateUrl: './student-add.component.html',
styleUrls: ['./student-add.component.css'],
})
export class StudentAddComponent {
student: Student = new Student(0, '', '', '', '');
message: string = '';
createStudent() {
this.service.createStudent(this.student).subscribe({
next: (data) => {
this.message = data;
this.student = new Student(0, '', '', '', '');
},
error: (err) => {
console.log(err);
},
complete: () => {
console.log('complete');
},
});
}
}
--------------------student-add.component.html-----------
<h3 class="text-center">STUDENTS REGISTER PAGE</h3>
<form (ngSubmit)="createStudent()">
NAME :
<input
type="text"
name="stdName"
id="stdName"
[(ngModel)]="student.stdName"
class="form-control"
/>
GENDER :
<input
type="radio"
name="stdGen"
id="stdGen"
[(ngModel)]="student.stdGen"
value="Male"
/>
Male
<input
type="radio"
name="stdGen"
id="stdGen"
[(ngModel)]="student.stdGen"
value="Female"
/>
Female
<br />
COURSE :
<select
name="stdCourse"
id="stdCourse"
[(ngModel)]="student.stdCourse"
class="form-control"
>
<option value="JAVA">JAVA</option>
<option value="DOT NET">DOT NET</option>
<option value="DEVOPS">DEVOPS</option>
<option value="SALESFORCE">SALESFORCE</option>
</select>
ADDRESS:
<textarea
name="stdAddr"
id="stdAddr"
[(ngModel)]="student.stdAddr"
class="form-control"
></textarea>
<br />
<button type="submit" class="btn btn-success">ADD STUDENT</button>
</form>
<div class="text-center">
<strong>{{ message }}</strong>
</div>
Date : 01-12-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Full Code Links:
https://github.com/javabyraghu/SpringBootRestCrudMySQLEx
editStudent(id: number) {
this.router.navigate(['/edit', id]);
}
======================================================================
Student Edit Page HTML Code:-
@Component({
selector: 'app-student-edit',
templateUrl: './student-edit.component.html',
styleUrls: ['./student-edit.component.css'],
})
export class StudentEditComponent implements OnInit {
student: Student = new Student(0, '', '', '', '');
message: string = '';
constructor(
private service: StudentService,
private activatedRoute: ActivatedRoute,
private router: Router
) {}
ngOnInit() {
let id = this.activatedRoute.snapshot.params['id'];
this.loadStudent(id);
}
loadStudent(id: number) {
this.service.getOneStudent(id).subscribe({
next: (data) => {
this.student = data;
},
error: (err) => console.log(err),
complete: () => console.info('Student received successfully'),
});
}
updateStudent() {
this.service.updateStudent(this.student).subscribe({
next: (data) => {
this.message = data;
alert(this.message);
this.router.navigate(['/all']);
},
error: (err) => console.log(err),
complete: () => console.info('Student updated successfully'),
});
}
}
------------------in service TS code--------------------
updateStudent(student: Student): Observable<any> {
return this.http.put(`${this.baseUrl}/modify`, student, {
responseType: 'text',
});
}
===================================================================
*******************************************************************
ReactJS APP
1. Create new ReactJS Project
npx create-react-app student-rjs-app
2. Enter into Application
cd student-rjs-app
3. Start Project
npm start
=================================
ReactJS Clean Setup: (ECMA)
npm uninstall -g create-react-app
npx clear-npx-cache
npm i create-react-app
================================
*) Install Bootstrap
npm install bootstrap@4 --save
=============code files==============================
1. HOC
import React from "react";
import { useNavigate } from "react-router-dom";
2. List Component
import React, { Component } from "react";
import StudentService from "../services/StudentService";
import withNavigateHook from "./withNavigateHook";
deleteStudent(id) {
StudentService.deleteStudent(id).then((response) => {
this.setState({
students: this.state.students.filter((student) => student.stdId !== id),
message: response.data,
});
});
}
editStudent(id) {
this.props.navigation("/edit/" + id);
}
componentDidMount() {
StudentService.getAllStudents().then((response) => {
this.setState({ students: response.data });
});
}
render() {
return (
<>
<h3 className="text-center">STUDENTS DATA PAGE</h3>
<table className="table table-hover">
<thead>
<tr className="bg-info text-white">
<th>ID</th>
<th>NAME</th>
<th>GENDER</th>
<th>COURSE</th>
<th>ADDRESS</th>
<th>OPERATION</th>
</tr>
</thead>
<tbody>
{this.state.students.map((student) => (
<tr key={student.stdId}>
<td>{student.stdId}</td>
<td>{student.stdName}</td>
<td>{student.stdGen}</td>
<td>{student.stdCourse}</td>
<td>{student.stdAddr}</td>
<td>
<button
className="btn btn-danger"
onClick={() => this.deleteStudent(student.stdId)}
>
DELETE
</button>
<button
className="btn btn-warning"
onClick={() => this.editStudent(student.stdId)}
>
EDIT
</button>
</td>
</tr>
))}
</tbody>
</table>
{this.state.message && (
<div className="text-center">
<strong>{this.state.message}</strong>
</div>
)}
</>
);
}
}
3. Create Component
import React, { Component } from "react";
import StudentService from "../services/StudentService";
import withNavigateHook from "./withNavigateHook";
handleChange(event) {
this.setState({ [event.target.name]: event.target.value });
}
4. NavBar Component
import { BrowserRouter as Router, Route, Routes, Link } from "react-router-dom";
import StudentListComponent from "./StudentListComponent";
import StudentCreateComponent from "./StudentCreateComponent";
function NavBarComponent() {
return (
<Router>
<nav className="navbar navbar-expand-lg navbar-light bg-primary">
<a className="navbar-brand text-white" href="#">
R-APP
</a>
<button
className="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span className="navbar-toggler-icon"></span>
</button>
5. Service class
import axios from "axios";
class StudentService {
getAllStudents() {
return axios.get(`${baseUrl}/all`);
}
createStudent(student) {
return axios.post(`${baseUrl}/create`, student);
}
deleteStudent(id) {
return axios.delete(`${baseUrl}/remove/${id}`, id);
}
getOneStudent(id) {
return axios.get(`${baseUrl}/find/${id}`, id);
}
updateStudent(student) {
return axios.put(`${baseUrl}/modify`, student);
}
}
6. App Component
import "./App.css";
import NavBarComponent from "./components/NavBarComponent";
function App() {
return (
<div className="container">
<NavBarComponent />
</div>
);
}
====================================================================
At backend application: @CrossOrigin("http://localhost:3000/")
HOC
Hooks
LifeCycleMethods
Redux
Testing
------------------------------------------------------------------------
Backend Application Code:
https://github.com/javabyraghu/SpringBootRestCrudMySQLEx
Frontend (Angular)
https://github.com/javabyraghu/student-ang-app
Frontend (ReactJS)
https://github.com/javabyraghu/student-rjs-app
===================================================================
*) Web page is a collection of Components (ex: header, NavBar,
Body, Side Panel, Footer..etc)
Syntax:
const { paramname1, paramname2,... } = useParams();
Ex:
const { id } = useParams();
=====================================================================
useEffect(callBackFun,dependencies) :
This one is used to execute function based on dependencies modified.
useEffect(() => {
StudentService.getOneStudent(id).then((response) =>
setStudent(response.data)
);
}, [id, setStudent]);
-------------------------------------------------------------------------
Swagger : (Programmer one time configuration)
springfox-swagger2
springfox-swagger-ui
http://localhost:9690/swagger-ui.html
.
-> Full Document(webpage) displayed at UI
Docket(DocumentationType.SWAGGER_2)
.paths(PathSelectors.regex("/v1/api.*"))
--------Coding steps--------------------------------
1. pom.xml
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
import java.util.Collections;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket createDocket() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.app.raghu.rest"))
//.paths(PathSelectors.any())
.paths(PathSelectors.regex("/v1/api.*"))
.build()
.pathMapping("/")
.apiInfo(apiInfo());
}
3. Properties file
spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER
Step#2
Annotation at Starter class:
@OpenAPIDefinition
=> In this case CP, reduces wait time by processing statements in parallel.
=> When ever we add Spring Boot Data JPA/Spring Boot JDBC dependency
then it internally provides HikariCP dependency with Configuration too.
Like:
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
=> We can provide our custom values for properties using keys with prefix
spring.datasource.hikari.<keyName>=<value>
#Database config
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/boot7am
spring.datasource.username=root
spring.datasource.password=root
#CP Config
spring.datasource.hikari.pool-name=HikariCP-Test
spring.datasource.hikari.connection-timeout=10000
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.minimum-idle=15
spring.datasource.hikari.connection-init-sql=select * from stdtab
spring.datasource.hikari.auto-commit=false
spring.datasource.hikari.idle-timeout=5000
#spring.datasource.hikari.driver-class-name= default copied from spring.datasource
#JPA Configuration
spring.jpa.show-sql=true
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.hibernate.ddl-auto=create
#Swagger Config
spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER
======================================================================
Unit Test: Testing A part of Application/ Module which is implemented
by a Programmer.
Jenkins(CI/CD) --> Read Source Code from Github --> Download Jars -> Compile
-> Unit Test --> Build(.jar/.war) --> Deploy(server)
** JUnit will compare Expected Result with actual output and says
TEST PASS or FAIL.
====================Basic JUnit Example===========================================
1) pom.xml
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.5.1</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>4.5.1</version>
</dependency>
</dependencies>
MathService ms = null;
int expected ;
@BeforeEach
public void setup() {
ms = new MathService();
expected = 30;
}
@Test
public void testAdd() {
int actual = ms.add(10, 20);
assertEquals(expected, actual);
boolean result = ms.isEven(51);
assertTrue(result);
}
@AfterEach
public void clean() {
ms = null;
}
}
=====================================================================
*) Mocking will not do Test, it creates Environment.
Dummy objects, Dummy Logic, Dummy Request..etc
*) @Mock : Create Dummy object for given classes.
@InjectMocks: Will find all required objects for current clas object
and inject.
when(methodCall()).thenReturn(output)
when(methodCall()).thenThrow(exceptionObj)
----------SAMPLE CODE---------------------------------
*) src/main/java
package com.app.raghu;
import java.sql.SQLException;
import java.util.List;
public class Repository {
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
}
}
===src/test/java======================
package com.app.raghu;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@Test
public void testSuccess() {
try {
// dummy implement given using Mocking
when(repository.getData()).thenReturn(Arrays.asList("A", "B", "RAGHU",
"12345", "1234"));
} catch (SQLException e) {
e.printStackTrace();
}
@Test
public void testException() {
try {
// dummy implement given using Mocking
when(repository.getData()).thenThrow(new SQLException("CONNECTION
ISSUE"));
} catch (SQLException e) {
e.printStackTrace();
}
// Test using JUnit
List<String> actual = service.getDataByLen();
assertNotNull(actual);
assertEquals(0, actual.size());
}
}
Date : 07-12-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
JUnit 5.x: Testing API / assert our results / PASS/FAIL
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
*) This starter provides all required jars for JUnit and Mockito setup
with Spring Boot Rest testing Environment.
*) Spring Boot test F/w is used to create a Mock Request and execute with
application by creating Mocked Container setup, check finally
respose with assertAPI.
(This request is not coming from actual client/browser)
=======================2 steps====================================
1. Create Test Environment using Mocking.
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
=> Activates Server/Container setup to start application (Like Main class work)
@AutoConfigureMockMvc
=> Activates MVC/HTTP protocol and annotations @RequestBody, @RestController
@TestPropertySource("classpath:application.properties")
=> Load External Properties file (with any name)
*) Even if we do not provide, default application.properties is loaded.
=> here we need to provide HttpMethod (POST), URL, Headers and Body.
Ex#1
MockHttpServletRequestBuilder request =
MockMvcRequestBuilders.post("/product/create")
.contentType("application/json")
.content("{\"pname\":\"A\",\"cost\":200}");
Ex#2
MockHttpServletRequestBuilder request =
MockMvcRequestBuilders.get("/product/all")
.accept("application/xml");
======================================================================
*) under src/test/java , one default class is given , just modify that as
package com.app.raghu;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
@AutoConfigureMockMvc
@TestPropertySource("classpath:application.properties")
public class SpringBootRestCrudMySqlExApplicationTests {
@Autowired
private MockMvc mockMvc;
/**
* Test save Operation
*/
@Test
@Disabled
@DisplayName("TESTING STUDENT SAVE OPERATIONS")
@Order(1)
public void testCreateStudent()
throws Exception
{
//1. CREATE MOCKED REQUEST
MockHttpServletRequestBuilder request =
MockMvcRequestBuilders.post("http://localhost:9690/v1/api/student/create")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"stdName\":\"AJAY\",\"stdGen\":\"Male\",\"stdC
ourse\":\"JAVA\",\"stdAddr\":\"HYD IND\"}");
mockMvc.perform(
post("http://localhost:9690/v1/api/student/create")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"stdName\":\"AJAY\",\"stdGen\":\"Male\",\"stdCourse\":
\"JAVA\",\"stdAddr\":\"HYD IND\"}"))
.andExpect(
status().isCreated()
);
}}
Date : 09-12-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Spring Boot Unit Testing
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
@AutoConfigureMockMvc
@TestPropertySource("classpath:application.properties")
public class SpringBootRestCrudMySqlExApplicationTests {
@Autowired
private MockMvc mockMvc;
/**
* Test save Operation
*/
@Test
// @Disabled -- Skip the test method
@DisplayName("TESTING STUDENT SAVE OPERATIONS")
@Order(1)
public void testCreateStudent() throws Exception {
// 1. CREATE MOCKED REQUEST
MockHttpServletRequestBuilder request = MockMvcRequestBuilders
.post("http://localhost:9690/v1/api/student/create").contentType(MediaType.APPLICATION_JSON)
.content("{\"stdName\":\"AJAY\",\"stdGen\":\"Male\",\"stdCourse\":
\"JAVA\",\"stdAddr\":\"HYD IND\"}");
* .content("{\"stdName\":\"AJAY\",\"stdGen\":\"Male\",\"stdCourse\":\"JAVA\",\"stdAddr\":\"HYD
IND\"}"
* )) .andExpect( status().isCreated() );
*
*
*}
*/
@Test
@Order(2)
@DisplayName("GET ALL STUDENTS")
public void testGetAllStudents() throws Exception {
// 1. create request
MockHttpServletRequestBuilder request =
MockMvcRequestBuilders.get("http://localhost:9690/v1/api/student/all");
// 2. execute it
MvcResult result = mockMvc.perform(request).andReturn();
// 3. read response
MockHttpServletResponse response = result.getResponse();
// 4. assert result
assertEquals(HttpStatus.OK.value(), response.getStatus());
assertNotNull(response.getContentAsString());
@Test
@Order(3)
@DisplayName("GET ONE STUDENT BY ID")
public void testGetOneStudent() throws Exception {
// 1. create request
MockHttpServletRequestBuilder request = MockMvcRequestBuilders.get(
"http://localhost:9690/v1/api/student/find/{id}",1);
// 2. execute it
MvcResult result = mockMvc.perform(request).andReturn();
// 3. read response
MockHttpServletResponse response = result.getResponse();
// 4. assert result
assertEquals(HttpStatus.OK.value(), response.getStatus());
assertNotNull(response.getContentAsString());
assertEquals(MediaType.APPLICATION_JSON_VALUE, response.getContentType());
}
@Test
@DisplayName("TESTING STUDENT UPDATE OPERATIONS")
@Order(4)
public void testupdateStudent() throws Exception {
// 1. CREATE MOCKED REQUEST
MockHttpServletRequestBuilder request = MockMvcRequestBuilders
.put("http://localhost:9690/v1/api/student/modify")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"stdId\":1,\"stdName\":\"AA\",\"stdGen\":\"Male\",\"std
Course\":\"JAVA\",\"stdAddr\":\"HYD IND\"}");
@Test
@Order(5)
@DisplayName("TEST DELETE STUDENT BY ID")
public void testDeleteStudent() throws Exception {
// 1. create request
MockHttpServletRequestBuilder request = MockMvcRequestBuilders.delete(
"http://localhost:9690/v1/api/student/remove/{id}",1);
// 2. execute it
MvcResult result = mockMvc.perform(request).andReturn();
// 3. read response
MockHttpServletResponse response = result.getResponse();
// 4. assert result
assertEquals(HttpStatus.OK.value(), response.getStatus());
assertNotNull(response.getContentAsString());
}
}
=======================================================================
Embedded Database: NO DOWNLOAD AND NO INSTALL REQUIRED
These are In-Memory databases, used for Dev/Testing purpose only.
Not recomanded to use in Production.
---application.properties--------
server.port=9090
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
spring.datasource.url=jdbc:h2:mem:testdb
-------------------------------------
==============code=============================================
Name : SpringBootRestH2Ex
Dep : Web, Lombok, Devtools, Data JPA, H2
*) properties file
server.port=9090
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
spring.datasource.url=jdbc:h2:mem:testdb
*) Entity class
package com.app.raghu.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import lombok.Data;
@Data
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer bid;
private String bname;
private String bauth;
}
*) repo
package com.app.raghu.repo;
import org.springframework.data.jpa.repository.JpaRepository;
import com.app.raghu.entity.Book;
*) RestController
package com.app.raghu.rest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.app.raghu.entity.Book;
import com.app.raghu.repo.BookRepository;
@RestController
@RequestMapping("/book")
public class BookRestController {
@Autowired
private BookRepository repo;
@PostMapping("/create")
public String createBook(@RequestBody Book book) {
repo.save(book);
return "BOOK CREATED";
}
}
*) POSTMAN REQUEST
POST http://localhost:9090/book/create
BODY
(*) raw [JSON]
{
"bname" : "JAVA",
"bauth" : "TEST"
}
Monolithic Application:-
If an application is developed as a single unit (multiple service together)
and finally made as single deployable component (1 WAR FILE/ 1 JAR FILE).
Life Cycle:-
Plan -> Code -> Build -> Deploy -> Moniter
Ref:
https://www.atlassian.com/microservices/microservices-architecture/microservices-vs-monolith
Microservices
*) Microservices : it is a Design.
Small Independent services as Application.
Creating Independent Deployable components.
One Module/Service = as 1 Project/Application
===========================================================
Compile : .java --> .class
Build : .class --> .jar/.war
Deploy : Place WAR under server and starter server
Instance : A Running server with project (successfully)
Load : No.of Request (Incoming Request ) to server
Load Factor : No.of Request / Total Capacity
0 < LF < 1
Test : Executing JUnit test cases
Docker Image : OS Independent S/w can be run at VM/Server
Jenkins : (CI) Pull Code from Git --> Compile --> Build --> Store at Nexus/JFrog
(CD) Create Docker Images --> Run at Server --> Code Quality--> Release to production
--> Moniter
==============================================================
Advantages of a monolithic architecture:
1. Development When an application is built with one code base,
it is easier to develop.
5. Easy debugging With all code located in one place, it s easier to follow a request and find an issue.
(Checking the code for issues)
------------------------------------------------------------
Disadvantages of a monolithic architecture:-
1. Slower development speed A large, monolithic application makes development more complex and
slower.
Exception in one module may effect other modules to stop/in valid output
..etc
5. Lack of flexibility A monolith is constrained by the technologies already used in the monolith.
[Using different new techbologies/ enhancements are not easy]
Microservices:-
One Big Application is implemented as small projects and connected finally
using Webservices.
---Advantages of microservices-------
[FAST development/deployment]
Agility – Promote agile ways of working with small teams that deploy frequently.
[As we can maintain multiple Instances, if one/some goes down other instances exist]
High reliability – You can deploy changes for a specific service, without the threat of bringing down
the entire application.
===========================================================================
Disadvantages of microservices:-
Development issues
--Comonponents---
1. Microservice : One Module/ One service in Project (Spring ReST is used)
2. Register and Discovery : (Netflix Eureka Server)
Here, all Microservices Instance details are stored
(serviceId, instanceId, HOST, IP, PORT, Load Factor..etc)
5. Admin Dashboard : Visual dashboard for all MS# which are registered
with eureka (Health, Beans, Info, cache details, ..etc)
It internall uses Actuator.
9. Circuite Breaker:
Avoid executing application for a period of time if app is throwing
exceptions in Continioues manner.
*) Our Small Apps are implemented using Spring Boot REST only.
*) We need even other concepts like:
Register and Discovery, Log Aggregator, Moniter/Dashboard,
Gateway, LoadBalancer, Continioues data Flow, Security,
Distributed Tracing, Dynamic Routing..etc
=======================================================================
*) Register and Discovery Server:-
Register is a Storage Area for Audit details of all services.
----------------------MS# app---------------------
Name : SpringCloudCartService
Dep : Spring Web, Eureka Discovery Client
*) Execution Order:
1. Run Eureka Server
2. Run MS# application
3. Enter URL : http://localhost:8761
4. Check Instance Running and click on Link (then modify)
http://localhost:8081/v1/api/cart/show
=================================================================
*) Spring Boot : Data JPA, Web, Email, Cache, Connection Pooling, REST..etc
*) Spring Cloud : Eureka Server, Config Server, gateway, Feign Client..etc
*)Note:
1. Every MS# need to be register with Eureka Server.
2. For That every MS# should contain Eureka Client Dependency,
annotation: @EnableEurekaClient and key
eureka.client.register-with-eureka=true
3. ** Spring Cloud is a Parent for all MS# even for Eureka Server.
it has given key: eureka.client.register-with-eureka=true (as default)
that reduces in every MS#.
4. But, Eureka Server even gets same true value. Which means
"Register Eureka Server with Eureka Server"
So, to remove this: eureka.client.register-with-eureka=false
at Eureka Server.
Spring Boot mainly used for Webapps(Web MVC, REST), DATA JPA, Email,
Security, Configurations...etc
Q) How our app is connected with both Spring Cloud and Spring boot
(using Maven)?
A) To link with Spring Boot, in our project inside pom.xml there is
<parent> tag exist.
======================================================================
Q) What is Instance ? and Why?
A) An Application running under server.
More instance gives services to multiple users in parallel.
ServiceId = application-name
InstanceId = (Some Number/code/application-name:randome value)
IP/PORT = IP Address/ Port Number
LF = Load Factor
==================================================================
Q) How can we expose our MS# or Register ? How can we enable to get
other MS# data from Register?
1. Add Spring Cloud Eureka Discovery Client Dependency (along with WEB)
2. At main class add: @EnableEurekaClient
A) No. By default Spring Cloud parent has given JARS and config props
for Eureka. There it has given default value 'true' for
register-with-eureka and fetch-registry.
A) Even for Eureka Server, spring cloud has provided default values as true
So, self register is done by eureka, that creates one UNKNOW instance
which takes some memory at Eureka server (no meaning) [No error, No Exception]
============================================================================
Q) What is the defaultZone value if we did not provide in MS#?
A) EurekaClientConfigBean is given by Spring Cloud.
That is storing config details for location of Eureka as a Map.
The default URL is given as:
http://localhost:8761/eureka
==========================================================================
Q) K8s. What is Deployment and Replicasets?
A)
MS# --> Container Image --> Pod --> ReplicaSets --> Deployments
ReplicaSets : No.of Instances of a Pod
Date : 21-12-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Microservices Communication
*) MS# Communication: If one MS# wants to send request and get response
from another MS# then it is called as MS# communication.
*) All MS# are internall Spring Boot REST apps. So, we can use RestTemplate.
But hardcoding URL of MS# is not a good approch.
Why?
-> MS# instances may run at different systems (IP May be diff in realtime)
-> MS# multiple instances may be created for LoadBalancing.
========================================================================
Spring Cloud has provided Client APIs (or) Communication APIs
They are:
1. DiscoveryClient (Legacy)
2. **LoadBalancerClient
3. *** Feign Client (open Feign)
*** Above clients helps to link two MS# apps.(for Communication only)
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
***********************[DiscoveryClient]*************************
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
This is given by Spring Cloud to fetch details from Register of a
given MS# based on ServiceId(application name) of client MS#
Q) Why DiscoveryClient?
A) TO get MS# details from Eureka Server at runtime.
Based on MS# serviceId
Q) Can DiscoveryClient make request to MS# application?
A) NO. It always connectes to Eureka Server.
it is never used to make Http Request/Response to MS# apps.
Q) What is ServiceInstance?
A) ServiceInstance means details of One MS# instance.
ServiceInstance = serviceId+ InstanceId + URI(IP/PORT) + ...
Protocol = http
IP = 192.168.10.11
Port = 8086
contextpath (project name) = /myapp (default is / in boot)
Resource Path = /employee/find/101 (dynamic path)
URI = IP + PORT
===Code=================================================================
3 projects
1. Eureka Server
Name : SpringCloudEurekaServer
Dep : Eureka Server
Main : @EnableEurekaServer
application.properties
# RECOMANDED PORT NUMBER
server.port=8761
*******************************************************************
2. CartService
Name : SpringCloudCartService
Dep : Spring Web, Eureka Discovery Client
Main: @EnableEurekaClient
--application.properties--
#PORT
server.port=8081
--RestController-------
package com.app.raghu.rest;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/cart")
public class CartRestController {
@GetMapping("/info")
public ResponseEntity<String> showMessage() {
return ResponseEntity.ok("WELCOME TO CART SERVICE");
}
}
*******************************************************************
3. OrderService
Main: @EnableEurekaClient
--application.properties--
#PORT
server.port=8094
--Consumer code--------
package com.app.raghu.consumer;
import java.net.URI;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
@Component
public class CartConsumer {
// read URI
URI uri = si.getUri();
--RestController-------
package com.app.raghu.rest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.app.raghu.consumer.CartConsumer;
@RestController
@RequestMapping("/order")
public class OrderRestController {
@Autowired
private CartConsumer consumer;
@GetMapping("/place")
public ResponseEntity<String> placeOrder() {
String cartResp = consumer.getCartResponse();
return ResponseEntity.ok("ORDER PLACED WITH => " + cartResp);
}
}
========================================================================
--Execution Order--
1. Run Eureka Server
2. Run Cart Service
3. Run Order Service
4. Goto Eureka (http://localhost:8761)
5. Click on Order Service link
May look like : http://localhost:8094/actuator/info
6. Modify Full URL of Cart service
ex:
http://localhost:8094/order/place
Output: Order service output ( Order Service Response + Cart Service Response)
ORDER PLACED WITH => WELCOME TO CART SERVICE
Date : 22-12-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Microservices Communication
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*********************[LoadBalancerClient]*************************
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Name : SpringCloudEurekaServer
Dep : Eureka Server
Main : @EnableEurekaServer
application.properties
# RECOMANDED PORT NUMBER
server.port=8761
*******************************************************************
2. CartService
Name : SpringCloudCartService
Dep : Spring Web, Eureka Discovery Client
Main: @EnableEurekaClient
--application.properties--
#PORT
server.port=8081
# Generating Instance ID
eureka.instance.instance-id=${spring.application.name}:${random.value}
--RestController-------
package com.app.raghu.rest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/cart")
public class CartRestController {
@Value("${server.port}")
private String port;
@GetMapping("/info")
public ResponseEntity<String> showMessage() {
return ResponseEntity.ok("WELCOME TO CART SERVICE =>" + port);
}
}
*******************************************************************
3. OrderService
Name : SpringCloudOrderService
Dep : Spring web, Eureka Discovery Client, Cloud LoadBalacer
Main: @EnableEurekaClient
--application.properties--
#PORT
server.port=9091
--Consumer code--------
package com.app.raghu.consumer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
@Component
public class CartConsumer {
@Autowired
private LoadBalancerClient client;
--RestController-------
package com.app.raghu.rest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.app.raghu.consumer.CartConsumer;
@RestController
@RequestMapping("/order")
public class OrderRestController {
@Autowired
private CartConsumer consumer;
@GetMapping("/place")
public ResponseEntity<String> placeOrder() {
String cartResp = consumer.getCartResponse();
return ResponseEntity.ok("ORDER PLACED WITH => " + cartResp);
}
}
========================================================================
--Execution Order--
1. Run Eureka Server
2. Run Cart Service (3 times with different port number)
3. Run Order Service (1 time)
4. Goto Eureka (http://localhost:8761)
5. Click on Order Service link
May look like : http://localhost:9091/actuator/info
6. Modify Full URL of Cart service
ex:
http://localhost:9091/order/place
Output: Order service output ( Order Service Response + Cart Service Response)
ORDER PLACED WITH => WELCOME TO CART SERVICE =>8083
*) Note:
1. ${random.value} Generates one Random value using class
RandomValuePropertySource(C)
Q) How many Instances does it return for a single request from eureka?
A) Alway one ServiceInstance which has Less Load Factor
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*********************[FeignClient]*************************
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
1. Feign Client is also called as Open Feign.
2. It is 3rd party API, integrated with Spring Cloud.
3. It generates code at runtime (Dynamic Proxy class)
which internally uses LoadBalancerClient code.
4. Programmer has to provide,
a. one interface with abstract methods
b. Endpoint details : Path, HttpMethods, serviceId(Provider App)
c. Request/Response Entities/Beans need to be re-defined
(type of duplicate code / bolier plate code)
Name : SpringCloudEurekaServer
Dep : Eureka Server
Main : @EnableEurekaServer
application.properties
# RECOMANDED PORT NUMBER
server.port=8761
*******************************************************************
2. CartService
Name : SpringCloudCartService
Dep : Spring Web, Eureka Discovery Client, Lombok
Main: @EnableEurekaClient
--application.properties--
#PORT
server.port=8081
# Generating Instance ID
eureka.instance.instance-id=${spring.application.name}:${random.value}
----Spring Bean---
package com.app.raghu.entity;
import lombok.Data;
@Data
public class Cart {
--RestController-------
package com.app.raghu.rest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
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.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.app.raghu.entity.Cart;
@RestController
@RequestMapping("/cart")
public class CartRestController {
@Value("${server.port}")
private String port;
@GetMapping("/info")
public ResponseEntity<String> showMessage() {
return ResponseEntity.ok("WELCOME TO CART SERVICE =>" + port);
}
@GetMapping("/find/{id}")
public ResponseEntity<Cart> getCartById(@PathVariable("id")Integer id) {
Cart cart = new Cart();
cart.setCartId(id);
cart.setCartCost(2300.0);
cart.setCartCode("TEST");
return ResponseEntity.ok(cart);
}
@PostMapping("/create")
public ResponseEntity<String> addToCart(@RequestBody Cart cart) {
return ResponseEntity.ok("ADDED TO CART => " + cart);
}
}
*******************************************************************
3. OrderService
Name : SpringCloudOrderService
Dep : Spring web, Eureka Discovery Client, Open Feign, Lombok
--application.properties--
#PORT
server.port=9091
--Spring Bean--------
package com.app.raghu.entity;
import lombok.Data;
@Data
public class Cart {
--Consumer code--------
package com.app.raghu.consumer;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.ResponseEntity;
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.RequestBody;
import com.app.raghu.entity.Cart;
@FeignClient("CART-SERVICE")
public interface CatConsumerFeign {
@GetMapping("/cart/info")
public ResponseEntity<String> showMessage();
@GetMapping("/cart/find/{id}")
public ResponseEntity<Cart> getCartById(
@PathVariable("id")Integer id);
@PostMapping("/cart/create")
public ResponseEntity<String> addToCart(
@RequestBody Cart cart);
}
--RestController-------
package com.app.raghu.rest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
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.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.app.raghu.consumer.CatConsumerFeign;
import com.app.raghu.entity.Cart;
@RestController
@RequestMapping("/order")
public class OrderRestController {
@Autowired
private CatConsumerFeign consumer;
@GetMapping("/place")
public ResponseEntity<String> placeOrder() {
String cartResp = consumer.showMessage().getBody();
return ResponseEntity.ok("ORDER PLACED WITH => " + cartResp);
}
@GetMapping("/fetch/{id}")
public ResponseEntity<String> fetchOrderWithCart(
@PathVariable("id") Integer id
)
{
Cart cob = consumer.getCartById(id).getBody();
return ResponseEntity.ok("ORDER WITH CART DATA => " + cob);
}
@PostMapping("/addToCart")
public ResponseEntity<String> addToCart(
@RequestBody Cart cart
)
{
String cartResp = consumer.addToCart(cart).getBody();
return ResponseEntity.ok("ORDER WITH => " + cartResp);
}
}
========================================================================
--Execution Order--
1. Run Eureka Server
2. Run Cart Service (3 times with different port number)
3. Run Order Service (1 time)
4. Goto Eureka (http://localhost:8761)
5. Click on Order Service link
May look like : http://localhost:9091/actuator/info
6. Modify Full URL of Cart service
ex:
http://localhost:9091/order/place
Output: Order service output ( Order Service Response + Cart Service Response)
ORDER PLACED WITH => WELCOME TO CART SERVICE =>8083
======================================================================
Ex#2
GET http://localhost:9091/order/fetch/1190
Ex#3
POST http://localhost:9091/order/addToCart
Body
raw(*) [JSON]
{
"cartId" : 1019,
"cartCode" : "AA",
"cartCost" : 9900.0
}
Date : 26-12-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Spring Cloud Config Server
1. One Application can have multiple MS# implemented using Spring REST
and Spring Cloud components.
2. Every MS# application contains application.properties file
3. These files contains key=val few are same as other MS#(Duplicate Key=Val pairs)
4. Such Duplicate Pairs can be placed outside of All MS# and link
ie called as Config Server
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*********************[Config Server]*************************
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
To externalize all duplicate key=val pairs from each MS#
into one common location (Ex: Github) and connect with every MS#
at runtime using a medium server ie runs at port:8888
*) Every MS# should have Config Client Dependency and URL of Config Server
*) Config Server recomanded port number is 8888
*) Config Server will load all KEY=VALs into Environment(I)
[email protected]
Model@12034
> Click on Plus Symbol > Create Repository > Enter name
Ex: SpringCloudConfigServerEx
> Finish
GitLink: https://github.com/raghu2023sample/SpringCloudConfigServerEx.git
=====================================================================
--Stage@2---------Create Config Server Application--------------
Name : SpringCloudConfigServerEx
Dep : Config Server
===================================================================
--Stage@3---------Integrate Every MS# with Config server--------
spring.config.import=optional:configserver:http://localhost:8888
=================================================================
Execution order:
1. Run Config Server | Eureka Server
2. Run MS# Apps
3. Enter URL:
http://localhost:8084/cart/info
--------------------------------------------------------------
Check at console: At Cart Service / Order Service
ConfigServerConfigDataLoader : Fetching config from server at : http://localhost:8888
Date : 27-12-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Spring Cloud Config Server : Refresh Scope
Problem Statement:
Once we start MS# apps with Eureka and Config server, then we modify/
update any key=vals at Config Server (+Git properties File)
those will not get effected at MS# until we restart MS# apps.
Solution Statement:
We have to implement "Refresh Scope" at MS# app. So, that if any
key=val is updated at Config server that will be updated at MS# app
also, without restarting MS# apps.
--Coding Steps---
*) Code changes at MS# app only
check: http://localhost:8082/cart/info
==Ex========================================
Name: SpringCloudSchedulerService
Dep : Web
application.properties
server.port=9601
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
@Component
public class FetchLatestDataFromProps {
======================================================================
Date : 28-12-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Plan -> Document -> Development -> Build -> Test -> Release -> Moniter
These are tools used to know the current status of applications/MS# running
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Ex:
http://localhost:8082/actuator
Note:
1. If we did not specify any include services then default only
one service 'health' is activated.
(old versions : Upto 2.4.x -- 2 were activated - health, info)
======================================================================
Spring Cloud Adminserver
===Coding Steps=============================
1. Admin Server
Name : SpringCloudAdminServer
Dep : Admin Server
2. At MS#
*) Add Two Dependencies : Actuator, Admin Client
--Execution order-------
1. Eureka Server | Config Server | Admin Server
2. MS# Apps (create multiple instances)
http://localhost:8761/
http://localhost:8888/actuator/refresh
http://localhost:9999/applications
Date : 30-12-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Workspace Link:
https://github.com/javabyraghu/Workspace7AM_082022
========================================================================
Date : 02-01-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Ref:
https://kafka.apache.org/intro
Quick Start:***
https://kafka.apache.org/quickstart
Kafka Tut:
https://data-flair.training/blogs/kafka-terminologies/
*) The continoues data flow between two systems. Producer will send data
and consumer will read by using a connector/mediator ie 'Message Broker'
*)MQs usecases:
1. Swiggy Delivery
2. Ola/Uber cab status
3. Live Train status
4. Live Stock Market data
5. Live Currency Updates
6. Live Cricket Score (BCCI server-> ESPN, CricBuzz,XYZ Server)
..etc
*)Note:
1. There can be multiple topics, queues are created with unique names.
2. Both P2P and Pub/Sub are used in realtime.
Click on : apache-activemq-5.17.3-bin.zip
and Extract to a Folder
2. Run ActiveMQ
> Goto Folder : D:\apache-activemq-5.17.3\bin\win64
> Click on : activemq.bat
> Enter URL : http://localhost:8161/admin/
un: admin , pwd: admin
Date : 03-01-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
ActiveMQ 5 Download Link:
https://activemq.apache.org/activemq-5016005-release
Click on : apache-activemq-5.16.5-bin.zip
and Extract to a Folder
2. Run ActiveMQ
> Goto Folder : D:\apache-activemq-5.17.3\bin\win64
> Click on : activemq.bat
> Enter URL : http://localhost:8161/admin/
un: admin , pwd: admin
*) For HTTP protocol, to see web console (Moniter Tool) Port number is : 8161
*) For communication between systems, we use TCP protocol, runs at port: 61616
===========================Producer===============================
Name : SpringCloudMqProducerEx
Dep : ActiveMQ5
*) application.properties
#Connect with MOM
spring.activemq.broker-url=tcp://localhost:61616
spring.activemq.user=admin
spring.activemq.password=admin
#Destination name
my.app.desti-name=my-q-abc1
------------------------------------
*) ProducerService
package com.app.raghu.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;
@Component
public class ProducerService {
@Autowired
private JmsTemplate jt;
@Value("${my.app.desti-name}")
private String destination;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import com.app.raghu.service.ProducerService;
@Component
public class TestSenderRunner {
//implements CommandLineRunner {
@Autowired
private ProducerService service;
===================Consumer Application=========================
Name : SpringCloudMqConsumerEx
Dep : ActiveMQ5
*) application.properties
#Connect with MOM
spring.activemq.broker-url=tcp://localhost:61616
spring.activemq.user=admin
spring.activemq.password=admin
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
@Component
public class ConsumerService {
@JmsListener(destination = "${my.app.desti-name}")
public void readMsg(String message) {
System.out.println(message);
}
}
======Execution Order==========================================
1. Start ActiveMQ
2. Run Consumer and Producer apps
Date : 04-01-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
1st Party Sun / Oracle - JMS API [javax.jms package]
MessageCreator(I)
createMessage(Session) : Message
*) So, we can just call above session and pass data using createMessage()
with method createTextMessage().
=======Note===========================================
1. JmsTemplate(C) is given by Spring JMS which is pre-configured
2. It has method send(destination,messageCreator)
3. Destination is a name must be matched with Producer and consumer
4. MessageCreator is a Functional Interface
5. It takes Session as input and Returns Message as output
6. Session and Message are interfaces given by Sun/Oracle
7. Impl classes are given by Apache ActiveMQ
ActiveMQSession, ActiveMQTextMessage
new interfaceName() {
//override methods
}
==Note=============================================================
1. Both Producer and Consumer must be connected to same destination.
2. Both internally uses JMS API that is Session support
3. They are connected using TCP protocol and PORT number 61616
4. To view Web UI output use HTTP porotocol and PORT 8161.
5. JmsTemplate (C) is pre-configured by Spring Boot.
6. Incase of Consumer application we need to apply @EnableJms
and also use @JmsListener.
Date : 07-01-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Apache Kafka:
https://www.youtube.com/watch?v=0V9SK6jmDPk
https://www.youtube.com/watch?v=gg-
VwXSRnmg&list=PLkz1SCf5iB4enAR00Z46JwY9GGkaS2NON&index=1
A)
P2P : There will be only one consumer. So , all Producer mesages single
copy is persisted at MOM Destination. Once consumer is up
then all Messages are delivered.
Pub/Sub : Based on No.of Consumers, Cloned Copies are created and sent to
consumer applications. [not persisted]
Ex: 3 consumers are connected first.
1 Message in = 3 Message out.
If One Consumer is stopped in middle
1 Message in = 2 Message out
=====Execution order===================
1. Start ActiveMQ
2. Start Consumer Application#1 and #2
3. Start Producer application
Date : 10-01-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
https://kafka.apache.org/quickstart
Apache Kafka
*) Kafka supports Pub/Sub Model only. No P2P. To send data to one consumer
use only Pub/Sub.
==========================================================================
Download : https://kafka.apache.org/downloads
Link: Scala 2.12 - kafka_2.12-2.8.1.tgz (asc, sha512)
Commands:
1. Start ZooKeeper
[Windows]
.\bin\windows\zookeeper-server-start.bat .\config\zookeeper.properties
[Linux/MacOS]
.\bin\zookeeper-server-start.sh .\config\zookeeper.properties
==============================================================
2. Start Kafka Server
[Windows]
.\bin\windows\kafka-server-start.bat .\config\server.properties
[Linux/MacOS]
.\bin\kafka-server-start.sh .\config\server.properties
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
@Bean
public NewTopic topic() {
return TopicBuilder.name("myabc")
.partitions(10)
.replicas(1)
.build();
}
--cmd--
.\bin\windows\kafka-topics.bat
--create
--topic myabc
--partitions 10
--replicas 1
--bootstrap-server localhost:9092
Date : 17-01-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Spring Boot + Apache Kafka Integration Example
======code=========================
Name : SpringBootKafkaServiceEx
Dep : Lombok, Data JPA, MySQL, Web, Devtools, Spring For apache kafka
1. application.properties
# server port
server.port=8686
# Producer properties
spring.kafka.producer.bootstrap-servers=localhost:9092
spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer
# Consumer properties
spring.kafka.consumer.bootstrap-servers=localhost:9092
spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer
spring.kafka.consumer.value-deserializer=org.apache.kafka.common.serialization.StringDeserializer
spring.kafka.consumer.group-id=abcd
# TopicName
my.topic.name=TEST-SAMPLE
# Database Properties
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/boot7am
spring.datasource.username=root
spring.datasource.password=root
# JPA Properties
spring.jpa.show-sql=true
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.hibernate.ddl-auto=create
2. Entity
package com.app.raghu.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Data;
@Data
@Entity
@Table(name="stocktab")
public class StockInfo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="sid")
private Integer stkId;
@Column(name="scode")
private String stkCode;
@Column(name="scost")
private Double stkCost;
3. Repository
package com.app.raghu.repo;
import org.springframework.data.jpa.repository.JpaRepository;
import com.app.raghu.entity.StockInfo;
}
4. JSONUTIL
package com.app.raghu.util;
import com.app.raghu.entity.StockInfo;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
5. MessageStore
package com.app.raghu.db;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.app.raghu.entity.StockInfo;
import com.app.raghu.repo.StockInfoRepository;
import com.app.raghu.util.JsonUtil;
@Component
public class MessageStore {
@Autowired
private StockInfoRepository repo;
6. Consumer Service
package com.app.raghu.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;
import com.app.raghu.db.MessageStore;
import lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
public class ConsumerService {
@Autowired
private MessageStore store;
7. Producer service
package com.app.raghu.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
public class ProducerService {
@Autowired
private KafkaTemplate<String, String> template;
@Value("${my.topic.name}")
private String topicName;
public void sendMessage(String message) {
log.info("MESSAGE IS AT PRODUCER SERVICE");
template.send(topicName, message);
}
}
8. RestController
package com.app.raghu.rest;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.app.raghu.db.MessageStore;
import com.app.raghu.entity.StockInfo;
import com.app.raghu.service.ProducerService;
import com.app.raghu.util.JsonUtil;
@RestController
@RequestMapping("/api/v1/kafka")
public class StockRestController {
@Autowired
private ProducerService service;
@Autowired
private MessageStore store;
//send?code=__&cost=__
@GetMapping("/send")
public String readMessage(
@RequestParam String code,
@RequestParam Double cost
)
{
//create Entity class object
StockInfo si = new StockInfo();
si.setStkCode(code);
si.setStkCost(cost);
//convert to JSON
String message = JsonUtil.convertToString(si);
@GetMapping("/all")
public List<StockInfo> fetchAll() {
return store.getAll();
}
=======execution order==========================
1. run zookeeper
.\bin\windows\zookeeper-server-start.bat .\config\zookeeper.properties
4. enter urls
http://localhost:8686/api/v1/kafka/send?code=A&cost=50.0
http://localhost:8686/api/v1/kafka/all
Date : 18-01-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
*) JACKSON API (open source Java API)
This API is used to convert
1. Java Object to JSON
2. JSON to Java Object
(C) ObjectMapper
(M) write__ Obj->JSON
(M) read__ JSON->OBJ
==Example code==========
*) if we create any Spring boot application with Web Dependeny
then by default JACKSON API is also added.
1. Model / Entity
package com.app.raghu.entity;
import lombok.Data;
@Data
public class StockInfo {
private Integer stkId;
private String stkCode;
private Double stkCost;
2. Test class
package com.app.raghu;
import com.app.raghu.entity.StockInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
//JSON to Object
public static void main(String[] args) {
String json ="{\"stkId\":101,\"stkCode\":\"A\",\"stkCost\":200.0}";
try {
ObjectMapper om = new ObjectMapper();
StockInfo si = om.readValue(json, StockInfo.class);
System.out.println(si);
} catch (Exception e) {
e.printStackTrace();
}
}
//Object to JSON
public static void main1(String[] args) {
StockInfo si = new StockInfo();
si.setStkCode("A");
si.setStkCost(200.0);
si.setStkId(101);
try {
ObjectMapper om = new ObjectMapper();
String s = om.writeValueAsString(si);
System.out.println(s);
} catch (Exception e) {
e.printStackTrace();
}
}
}
======================================================================
Topic: Apache Kafka supports only Topics to send data even for 1 to 1 also.
No P2P -- Queue concept in kafka. Everything is Pub/Sub -- Topic
@Bean
public NewTopic topic() {
return TopicBuilder.name("topic1")
.partitions(10) //based on message sizes
.replicas(1) // no.of consumers
.build();
}
//default values are : partitions=1 , replicas =1
(or) KafkaTemplate creates given topic name on the fly (at runtime)
*)Group : Logical unit of a multiple consumers which are using same topicName
In this case MessageBroker informs MessageReplica to create Cloned Copies
======================================================================
*) When ever KafkaTemplate calls send method then Kafka API creates one object
ProducerRecord (C)
*) Internally data format is binary (byte[]) easy for trasfer and partitions
=> One consumer can read data from multiple topics too.
Ex:
@KafkaListener(topics = {
"${my.topic.name2}",
"${my.topic.name1}",
"${my.topic.name3}"
},
groupId = "abcd")
*) Our application is connected with Kafka Server that runs on port : 9092
Zookeeper runs on port: 2181
=====================================================================
Gateway: Single entry and exit point for entire MS# apps.
http://sampleapp.com/user/find/101
http://sampleapp.com/cart/modify/106
Date : 19-01-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Spring Cloud : API Gateway
API Gateway : It is a single entry and exit point for our MS# application.
Why Gateway?
1. Routing : Dispatching a client request to MS# application
2. LoadBalancing : Choose one Instance from Eureka based on LoadFactor
for every request
3. Filters : Modify Request/ Response details (Encryption, Authentication..etc)
/cart/** lb://CART-SERVICE
--------------------------------------------
If request URL contains /order in Path
ex: http://localhost:80/order/find/10
then select ORDER-SERVICE goto Eureka, fetch one ORDER-SERVICE instance
and execute request for path "/order/find/10"
package com.app.raghu.config;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyRouteConfig {
return builder.routes()
//.route("cartRoutingId",
r->r.path("/cart/**").uri("http://172.10.12.36:9696")) //one cart instance only
.route("cartRoutingId", r->r.path("/cart/**").uri("lb://CART-
SERVICE"))
.route("orderRoutingId", r->r.path("/order/**").uri("lb://ORDER-
SERVICE"))
.build();
}
}
2. properties file
#server.port=80
server.port=9600
---------------------------------------------------------
ID PATH URI
---------------------------------------------------------
CID /cart/** lb://CART-SERVICE
OID /order/** lb://ORDER-SERVICE
---------------------------------------------------------
--application.properties---
server.port=80
#server.port=9600
spring.application.name=API-GATEWAY
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyRouteConfig {
@Bean
public RouteLocator configureRoutes(RouteLocatorBuilder builder) {
return builder.routes()
.route("cartId", r -> r.path("/cart/**").uri("lb://CART-SERVICE"))
.route("orderId", r -> r.path("/order/**").uri("lb://ORDER-SERVICE"))
.build();
}
}
==Execution order=========
1. Config Server | Eureka Server | Admin Server
http://localhost:8888/actuator/refresh
http://localhost:8761
http://localhost:9999/applications
cmd> ipconfig
sh> ifconfig (or) ip addr show
ifconf
=================================================
Date : 23-01-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Ref Workspace:
https://github.com/javabyraghu/Workspace7AM_082022
DSA: https://github.com/javabyraghu/DataStructuresAndAlgorithms
Filters:-
To Modify existed request/response data at API Gateway level
we use filters.
==code changes====================================
1. API Gateway
package com.app.raghu.config;
import java.util.UUID;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyRouteConfig {
@Bean
public RouteLocator configureRoutes(RouteLocatorBuilder builder) {
return builder.routes()
.uri("lb://CART-SERVICE"))
.route("orderId", r -> r.path("/order/**").uri("lb://ORDER-
SERVICE")).build();
}
2. Cart RestController
@RestController
@RequestMapping("/cart")
@RefreshScope
public class CartRestController {
@Value("${my.app.title}")
private String title;
@GetMapping("/info")
public ResponseEntity<String> showMessage(
@RequestHeader("MyToken") String token
)
{
return ResponseEntity.ok("WELCOME TO CART SERVICE =>" + token);
}
....
}
==Execution order=========
1. Config Server | Eureka Server | Admin Server
http://localhost:8888/actuator/refresh
http://localhost:8761
http://localhost:9999/applications
cmd> ipconfig
sh> ifconfig (or) ip addr show
ifconf
=================================================
Equal YAML Configuration for API Gateway:
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
server:
port: 80
spring:
application:
name: API-GATEWAY
cloud:
gateway:
routes:
- id: cartId
uri: lb://CART-SERVICE
predicates:
- Path=/cart/**
filters:
- AddRequestHeader=MyToken,BasicTEST
- AddResponseHeader=Service-Mode, Active
- id: orderId
uri: lb://ORDER-SERVICE
predicates:
- Path=/order/**
Date : 24-01-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Distributed Tracing
[Sleuth and Zipkin]
*) Zipkin Server:
How many Request processed?
Execution Path?
How Many MS# called?
How much time taken?
Click on :
zipkin-server-2.12.9-exec.jar
Execute Command:
java -jar zipkin-server-2.12.9-exec.jar
Enter URL:
http://127.0.0.1:9411/zipkin/
===================================================================
*) We have to define two MS# wich are connected using any one client.
-> DiscoveryClient / LoadBalancerClient [manual code]
-> Open Feign (Abstract client)
-> RestTemplate : Supports all Apps (non-Java)
-> WebClient : Webflux (Reactive coding)
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-zipkin-client</artifactId>
</dependency>
Date : 25-01-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
TASK:
https://www.youtube.com/results?search_query=ELK
We can even add : Admin Client, Eureka Discovery Client, Config Client..etc
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class AppConfig {
@Bean
public RestTemplate rt() {
return new RestTemplate();
}
*)Define RestController
package com.app.raghu.rest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class ProcessARestController {
@Autowired
private RestTemplate rt;
@GetMapping("/showA")
public String showMsg() {
log.info("WE ARE AT A SERVICE...");
*) Sleuth and Zipkin stores data using Logs and format looks like
[ServiceName, TraceId, spanId, ExportFlag]
=> Spring Boot WebFlux (Spring 5.x), comes with Netty Server.
=> We need to use NoSQL DB like MongoDB, Redis..etc
stores: JSON Format/Documents Data
=> We have to use Spring boot reavtie API which is implemented using
Spring Webflux. Here DB are used NoSQL Reactive suported.
==MongoDB setup====================================
1. Goto : https://www.mongodb.com/try/download/community
2. Fill details and download
3. Run Executable
4. Create folder system C:/data/db
5. To start Mongodb server
cmd: mongod (starts on port: 27017)
Ref:
#1
https://www.mongodb.com/docs/v4.2/crud/
#2
https://data-flair.training/blogs/mongodb-relationships/
#3
https://www.mongodb.com/docs/manual/reference/sql-comparison/
Date : 28-01-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
1. Producer: [Spring Webflux and Reactive MongoDB API]
1. Entity
package com.app.raghu.entity;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document //optional annotation
public class Student {
@Id
private String id;
private String name;
private Double fee;
}
2. Repository
package com.app.raghu.repo;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import com.app.raghu.entity.Student;
3. Service
package com.app.raghu.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.app.raghu.entity.Student;
import com.app.raghu.repo.StudentRepository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Service
public class StudentService {
@Autowired
private StudentRepository repo;
4. RestController
package com.app.raghu.rest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.app.raghu.entity.Student;
import com.app.raghu.service.StudentService;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/student")
public class StudentRestController {
@Autowired
private StudentService service;
@PostMapping("/create")
public Mono<Student> save(@RequestBody Student student) {
return service.save(student);
}
}
5. Properties file
#Server Port
server.port=9090
****************************************************
> first run cmd "mongod" then start application
> Test using POSTMAN
****************************************************
3. Consumer : WebClient
*) execution order:
-> Run cmd: mongod
-> Run Application(Producer)
=====================================================================
Q) Does MongoDB Generates PK values?
A) YES. But type must be String only (UUID value)
We can check in DB like
"_id" : ObjectId("_________"),
===code=============
Create a Spring Boot Application
Name : SpringBootReactiveProducerEx
Dep : Reactive Web, Reactive MongoDB, Lombok, Devtools
1. application.properties
#Server Port
server.port=9090
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document //optional annotation
public class Student {
@Id
private String id;
private String name;
private Double fee;
}
3. Repository interface
package com.app.raghu.repo;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import com.app.raghu.entity.Student;
4. Service class
package com.app.raghu.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.app.raghu.entity.Student;
import com.app.raghu.repo.StudentRepository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Service
public class StudentService {
@Autowired
private StudentRepository repo;
5. RestController
package com.app.raghu.rest;
import org.springframework.beans.factory.annotation.Autowired;
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.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.app.raghu.entity.Student;
import com.app.raghu.service.StudentService;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/student")
public class StudentRestController {
@Autowired
private StudentService service;
@PostMapping("/create")
public Mono<Student> save(@RequestBody Student student) {
return service.save(student);
}
@GetMapping("/fetch/{id}")
public Mono<Student> getOne(@PathVariable String id) {
return service.getOne(id);
}
@GetMapping("/all")
public Flux<Student> fetchAll() {
return service.findAll();
}
@DeleteMapping("/remove/{id}")
public Mono<Void> deleteOne(@PathVariable String id) {
return service.delete(id);
/* service.delete(id);
return Mono.just("Removed Id "+id); */
}
6. Execution order
cmd> mongod
Run application
Date : 31-01-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Reactive Programming
[consumer application]
WebClient:-
=> It is a Reactive Client.
=> RestTemplate will not support reactive calls(request)
=> It is internally Asynchronous communication.
--coding steps---
1. Define WebClient object using base URL
2. Provide call details in order
HttpMethod
PATH + PathVariables
Body With Type
Execute
Convert Response to Type(Mono/Flux)
Subscribe data
Name: SpringBootReactiveConsumerEx
Dep : Spring Boot Reactive Web, Lombok
1. Runner class
package com.app.raghu.runner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import com.app.raghu.entity.Student;
import reactor.core.publisher.Mono;
@Component
public class TestProducerCallRunner implements CommandLineRunner {
//call
/*
Mono<Student> result =
client
.post() //Http Method
.uri("/create") //PATH
.body(Mono.just(new Student("AA256", "SAM", 300.0)), Student.class)
//Body
.retrieve() // execute
.bodyToMono(Student.class); //convert response
/*
Flux<Student> flux = client.get().uri("/all").retrieve().bodyToFlux(Student.class);
flux.doOnNext(System.out::println).blockLast();
*/
Mono<Student> result =
client.get().uri("/fetch/AA256").retrieve()
.bodyToMono(Student.class);
result.subscribe(System.out::println);
}
2. Entity class
package com.app.raghu.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
Ex: BankApplication
URLs: /home, /login, /checkBal, /logout, /approveLoan, /openFD ..etc
Authorization Levels(3):
1. permitAll : A URL/Path can be accessed by every one
[no login/ no role is required]
Ex: /home, /login, /contactUs, /aboutUs
2. JDBCAuthentication
=> We use Database to Store user data and roles (1/2 tables)
=> But check details (login details and role details)
using SQL queries (manually we need to define)
====================================================================
*) PasswordEncoder:- It is not recomanded to store plain text password
inside database, better convert into unreadable format ie encoding.
===coding================================================================
1. We need to define only one class (additionally) for security.
ie SecurityConfig (any equal name) called as One Configuration class.
Old Configuration:
https://github.com/javabyraghu/SpringBoot2SecurityOrmEx/blob/master/src/main/java/in/
nareshit/raghu/config/SecurityConfig.java
New Configuration:
https://github.com/javabyraghu/SpringBootSecurityInMemoryEx/blob/main/src/main/java/com/
app/raghu/config/WebSecurityConfig.java
Ref Doc:-
https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter
Date : 02-02-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Ref Link:
https://www.mediafire.com/file/w5x9w5vcmkwkkdv/RaghuSirNareshITJavaPdfs.zip/file
.antMatchers("/welcome").permitAll()
.antMatchers("/profile").authenticated()
.antMatchers("/mydata").hasAuthority("ADMIN")
.antMatchers("/checkBal").hasAnyAuthority("MANAGER", "CUSTOMER")
.anyRequest().permitAll()
[or]
.anyRequest().authenticated()
[or]
.anyRequest().hasAuthority("ADMIN")
======================================================================
Spring Boot Security # InMemoryAuthentication
======================================================================
.antMatchers("/home","/login").permitAll()
.antMatchers("/hello").authenticated()
(UserDetails)
username : sam
password : sam (No password encoder)
roles : ADMIN
1. Controller
package com.app.raghu.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class HomeController {
@GetMapping({"/home","/"})
public String showHome() {
return "home";
}
@GetMapping("/hello")
public String showHello() {
return "hello";
}
@GetMapping("/login")
public String showLogin() {
return "login";
}
}
2. SecurityConfig
package com.app.raghu.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
// 2. Authorization
@Bean
public SecurityFilterChain configurePaths(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(
request -> request.antMatchers("/","/home").permitAll()
.anyRequest().authenticated()
)
.formLogin( form -> form.loginPage("/login").permitAll() )
.logout( logout -> logout.permitAll() );
return http.build();
}
//old style
/*
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/","/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/hello")
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login?logout");
}
*/
// 1. Authentication (InMemory)
@Bean
public UserDetailsService userDetailsService() {
}
3. UI/ View Pages
a) home.html
<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org">
<head>
<title>Spring Security Example</title>
</head>
<body>
<h1>Welcome!</h1>
b) hello.html
<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org">
<head>
<title>Hello World!</title>
</head>
<body>
<h1>Hello world!</h1>
<form th:action="@{/logout}" method="post">
<input type="submit" value="Sign Out"/>
</form>
</body>
</html>
c) login.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
<head>
<title>Spring Security Example </title>
</head>
<body>
<div th:if="${param.error}">
Invalid username and password.
</div>
<div th:if="${param.logout}">
You have been logged out.
</div>
<br/>
<form th:action="@{/login}" method="post">
<div><label> User Name : <input type="text" name="username"/> </label></div>
<div><label> Password: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Sign In"/></div>
</form>
</body>
</html>
*) Run application and Enter URL:
http://localhost:8080/home
Date : 03-02-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Docs:
https://www.mediafire.com/file/w5x9w5vcmkwkkdv/RaghuSirNareshITJavaPdfs.zip/file
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
Database Setup:
create table users(
username varchar(50) not null primary key,
password varchar(500) not null,
enabled boolean not null);
mysql>
mysql> create table authorities (
-> username varchar(50) not null,
-> authority varchar(50) not null,
-> constraint fk_authorities_users foreign key(username)
-> references users(username));
Query OK, 0 rows affected (0.15 sec)
mysql>
mysql> create unique index ix_auth_username on authorities (username,authority);
Query OK, 0 rows affected (0.09 sec)
Records: 0 Duplicates: 0 Warnings: 0
================================================================
Name : 02SpringBootSecurityJdbcAuthEx
Dep : Spring web, Spring Security, Devtools, JDBC, MySQL, Thymeleaf
1. Controller class
package com.app.raghu.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class HomeController {
@GetMapping("/login")
public String showLogin() {
return "login";
}
}
2. Security Config
package com.app.raghu.config;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
//authorization
@Bean
public SecurityFilterChain configureAuth(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(
request->request.antMatchers("/home","/").permitAll()
.antMatchers("/admin").hasAuthority("ADMIN")
.antMatchers("/customer").hasAuthority("CUSTOMER")
.anyRequest().authenticated()
)
.formLogin(
form->form.loginPage("/login").permitAll()
.defaultSuccessUrl("/hello", true)
)
.logout(logout->logout.permitAll()) ;
return http.build();
}
//authentication
@Bean
public UserDetailsService userDetailsService(DataSource datasource) {
UserDetails user1 = User.withUsername("sam")
.password("$2a$10$TD7ldmKUQw3EHFxVivyA8OUrzy7butY9QDRnltnBS/b9aI0j6reYq")
.authorities("ADMIN").build();
.password("$2a$10$dEm8gdOC0R2S7IgXSnBKFOSeeKbCNuVeMC/hP24eY7zdADlUif4n.")
.authorities("CUSTOMER").build();
return users;
}
3. View pages
a) admin.html
<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org">
<head>
<title>Hello World!</title>
</head>
<body>
<h1>HELLO ADMIN PAGE!!</h1>
<form th:action="@{/logout}" method="post">
<input type="submit" value="Sign Out"/>
</form>
</body>
</html>
b) customer.html
<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org">
<head>
<title>Hello World!</title>
</head>
<body>
<h1>HELLO CUSTOMER PAGE!!</h1>
<form th:action="@{/logout}" method="post">
<input type="submit" value="Sign Out"/>
</form>
</body>
</html>
c) hello.html
<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org">
<head>
<title>Hello World!</title>
</head>
<body>
<h1>Hello world!</h1>
<form th:action="@{/logout}" method="post">
<input type="submit" value="Sign Out"/>
</form>
</body>
</html>
d) home.html
<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org">
<head>
<title>Spring Security Example</title>
</head>
<body>
<h1>Welcome!</h1>
e) login.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
<head>
<title>Spring Security Example </title>
</head>
<body>
<div th:if="${param.error}">
Invalid username and password.
</div>
<div th:if="${param.logout}">
You have been logged out.
</div>
<br/>
<form th:action="@{/login}" method="post">
<div><label> User Name : <input type="text" name="username"/> </label></div>
<div><label> Password: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Sign In"/></div>
</form>
</body>
</html>
4) application.properties
#DB Connection
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/boot6am
spring.datasource.username=root
spring.datasource.password=root
==Run below SQLs while starting application if you get any issue===
mysql> delete from authorities;
mysql> delete from users;
Date : 04-02-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Spring Boot Security using ORM
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Stage#1 Application setup and User Register
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
In this stage we define Spring boot web mvc application like CRUD process
that reads Register Form data and stores in two tables.
ie User table and Roles table.
For this we need to define User Entity with Repository, service and Controller
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/boot7am
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.show-sql=true
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.hibernate.ddl-auto=create
------------------------------------------
S#4 Entity class
package com.app.raghu.entity;
import java.util.Set;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name="usertab")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="uid")
private Integer userId;
@Column(name="uname")
private String userName;
@Column(name="umail")
private String userEmail;
@Column(name="upwd")
private String userPwd;
@ElementCollection
@CollectionTable(name="roles_tab",
joinColumns = @JoinColumn(name="uid")
)
@Column(name="urole")
private Set<String> userRoles;
}
-----------------------------------
S#5 Repository interface
package com.app.raghu.repo;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import com.app.raghu.entity.User;
import java.util.Optional;
import com.app.raghu.entity.User;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.app.raghu.entity.User;
import com.app.raghu.repo.UserRepository;
import com.app.raghu.service.IUserService;
@Service
public class UserServiceImpl implements IUserService {
@Autowired
private UserRepository repo;
7. Controller
package com.app.raghu.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.app.raghu.entity.User;
import com.app.raghu.service.IUserService;
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private IUserService service;
8. UI View Page
-- UserRegister.html --
<html xmlns:th="https://www.thymeleaf.org/">
<head>
<title>SECURITY USING ORM</title>
</head>
<body>
<h3> WELCOME TO REGISTER PAGE</h3>
<form th:action="@{/user/save}" method="POST">
<pre>
NAME : <input type="text" name="userName"/>
EMAIL : <input type="text" name="userEmail"/>
PASSWD : <input type="password" name="userPwd"/>
ROLES :
<input type="checkbox" name="userRoles" value="ADMIN"/> ADMIN
<input type="checkbox" name="userRoles" value="CUSTOMER"/>
CUSTOMER
<input type="submit" value="Create User"/>
</form>
</pre>
<div>[[${message}]]</div>
</body>
</html>
Date : 06-02-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Link:
https://github.com/javabyraghu/Workspace7AM_082022
===================================================================
2.*** User Login and Password Encoder
===================================================================
Custom UserDetailsService (ORM)
Coding Steps:
1. Add Security Dependencies in pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration
public class AppConfig {
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
--------------------------------------
3. Encode Password Before save operation
--UserServiceImpl--
@Autowired
private BCryptPasswordEncoder passwordEncoder;
@Autowired
private UserRepository repo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import
org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfigur
ation;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private BCryptPasswordEncoder passwordEncoder;
@Autowired
private UserDetailsService userDetailsService;
//old
/*
void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}*/
//new code--starts
@Bean
public AuthenticationManager authenticationManager(
AuthenticationConfiguration authConfig)
throws Exception {
return authConfig.getAuthenticationManager();
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(passwordEncoder);
provider.setUserDetailsService(userDetailsService);
return provider;
}
//new code ends
@Bean
public SecurityFilterChain configureAuth(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(
request->request.antMatchers("/home","/","/user/**").permitAll()
.antMatchers("/admin").hasAuthority("ADMIN")
.antMatchers("/customer").hasAuthority("CUSTOMER")
.anyRequest().authenticated()
)
.formLogin(
form->form.loginPage("/login").permitAll()
.defaultSuccessUrl("/hello", true)
)
.logout(logout->logout.permitAll()) ;
return http.build();
}
}
===============================================================
mysql> select * from usertab;
+-----+-------------+-------+--------------------------------------------------------------+
| uid | umail | uname | upwd |
+-----+-------------+-------+--------------------------------------------------------------+
| 1 | [email protected] | AJAY |
$2a$10$qZoopSxnSw1H.ZvnahqNiOqfnQFzNpSfzI2Y.BeGqioCUWhIcHwDW |
+-----+-------------+-------+--------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
Date : 09-02-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Spring Boot Security using ORM
1. HttpSession :
Once a User login is successful then server creates one Session per
client/user. That stores user data.
This is an object stores user data fora period of time (Login to Logout)
Ex: userId, roles ..etc
Note: Below line read old session, if not present creates new Session
HttpSession session = request.getSession();
session.invalidate();
====================================================================
Date : 10-02-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Spring Boot Security
=> Server will never store any user data, no session, no token even.
=> When client wants to make a request then it has to send token
along with request.
=> Server validates token using Secret key if valid provide response
Else redirect to login page (or any other).
=======================================================================
JWT - JSON Web Token is used to implement Token based Authentication.
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
Maven Project:
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
</dependencies>
*) Test class:
package com.app.raghu;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
String token =
Jwts.builder()
.setId("8562455") //user UnqId
.setSubject("sample") //username
.setIssuedAt(new Date(System.currentTimeMillis())) //created time
.setExpiration(new Date(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(2))) //exp
time
.setIssuer("ASHOKIT") //token provider name
.signWith(SignatureAlgorithm.HS256, secret.getBytes()) //sec algo, secret
.compact();
System.out.println(token);
Claims c =
Jwts.parser()
.setSigningKey(secret.getBytes())
.parseClaimsJws(token).getBody();
System.out.println(c.getSubject());
System.out.println(c.getIssuer());
System.out.println(c.getExpiration());
}
}
================================================================
task:
1. What are Filters in Servlet API?
2. Why they need ?
3. How can we define them ?
Date : 11-02-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Spring Boot Security
1) User Register
=> Read data as JSON From POSTMAN and Store in DB
2. Security Config
=> Define Authentication, Authorization
=> Make Configuration for security as Stateless(No HTTPSession)
=> Add/Register Filter that gets executed before FC.
================================================================
1. Create user
2. Login user
Key Value
Authorization Paste your token here
===============================================
*) Sun/Oracle has given one Security Contract ie : Principal(I)
ie If any F/w, Tech is implementing Security Concept then
store current user details inside Principal Object.
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
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 com.app.raghu.util.JwtUtil;
@Component
public class SecurityFilter extends OncePerRequestFilter {
@Autowired
private JwtUtil jwtUtil;
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
// check userdetails
if (username != null && SecurityContextHolder.getContext().getAuthentication() ==
null) {
// load user from DB
UserDetails user = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authenitcation = new
UsernamePasswordAuthenticationToken(username,
user.getPassword(), user.getAuthorities());
authenitcation.setDetails(new
WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenitcation);
}
}
filterChain.doFilter(request, response);
}
}
-------------------------------------
2. Security Config
package com.app.raghu.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import
org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfigur
ation;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
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.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import com.app.raghu.filter.SecurityFilter;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private BCryptPasswordEncoder passwordEncoder;
@Autowired
private AuthenticationEntryPoint authenticationEntryPoint;
@Autowired
private SecurityFilter securityFilter;
@Bean
public AuthenticationManager authenticationManager(
AuthenticationConfiguration configuration
) throws Exception
{
return configuration.getAuthenticationManager();
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(passwordEncoder);
provider.setUserDetailsService(userDetailsService);
return provider;
}
@Bean
public SecurityFilterChain configureAuth(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests().antMatchers("/user/save","/user/login").permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(securityFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}}
Date : 14-02-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Spring Boot Security
OAuth 2.x
=> OAuth 2.x Means Open Authorization using "Auth and Resource Server"
(3rd Party services) to access enduser data by a client application.
=> OAuth is a standard Protocol for User Identity and verify concept
using client application service.
--3 devices---
1. Auth & Resource Server
2. Client Application (server)
3. End Customer Device (Browser)
================Stages======================================
1. Register Client application with Auth&Resource Server
*) Goto : https://developers.facebook.com/
> Click on MyApps
> Choose Consumer > Next
> Enter app name > Next
> Click on App name (Top left corner)
> Create test app > Finish
> Click on Settings > Basics
> copy client-id: 1651876458565698
secret: 0b407987f0c3fea6bd82fb155819e2db
===================================================
--application.yml---
spring:
security:
oauth2:
client:
registration:
facebook:
client-id: 1651876458565698
client-secret: 0b407987f0c3fea6bd82fb155819e2db
==========================================================
SecurityConfig.java
package com.app.raghu.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfig {
//authentication ...
//authorization
@Bean
public SecurityFilterChain configure(HttpSecurity http) throws Exception {
http.antMatcher("/**")
.authorizeRequests()
.antMatchers("/","/login**").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login();
return http.build();
}
}
========UserController========
package com.app.raghu.rest;
import java.security.Principal;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class UserController {
@GetMapping("/secure")
public String showHome(Principal p)
{
System.out.println(p);
return "Secure";
}
@GetMapping("/")
public String showLogin()
{
return "Index";
}
}
==========Index.html===========
<html xmlns:th="https://www.thymeleaf.org/">
<head>
<title>WELCOME TO LOGIN</title>
</head>
<body>
<h2>Spring Security using OAuth2.x</h2>
<a href="secure">Login </a>
</body>
</html>
==============Secure.html====================
<html xmlns:th="https://www.thymeleaf.org/">
<head>
<title>WELCOME TO LOGIN</title>
</head>
<body>
<h2>WELCOME</h2>
<span th:text="${#authentication.name}"></span>
</body>
</html>
Date : 16-02-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
SOLID
SRP: "A class should have one, and only one, reason to change"
(We need to follow this)
OCP: "You should be able to extend a class’s behavior, without modifying it"
(Supported by Java) Inheritance and Override
--------------
Solution:
--------------
Stop executing MS# if it is failed continiousely, and give some dummy
response/Error message to client. Admin/Support Team can fix issue
meanwhile. ie called as Circut Breaker.
States:
1. CLOSED : Connection exist between Two MS# (MS#1 ----MS#2)
2. OPEN : Connection is broken b/w MS# (MS#1 --/ -MS#2)
3. HALF_OPEN : Try after some 'x' time to make another request to test
Exceptions/issues status.
No Issues --> Move to CLOSED, else OPEN.
resilience4j:
circuitbreaker:
instances:
orderService:
registerHealthIndicator: true
eventConsumerBufferSize: 10
automaticTransitionFromOpenToHalfOpenEnabled: true
failureRateThreshold: 50
minimumNumberOfCalls: 5
permittedNumberOfCallsInHalfOpenState: 3
slidingWindowSize: 10
waitDurationInOpenState: 5s
slidingWindowType: COUNT_BASED
management:
health:
circuitbreakers:
enabled: true
endpoints:
web:
exposure:
include: health
endpoint:
health:
show-details: always
=MS#1 Controller======
package com.app.raghu.controller;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
@RestController
public class OrderController {
@GetMapping("/order")
@CircuitBreaker(name = ORDER_SERVICE, fallbackMethod = "orderFallback")
public ResponseEntity<String> createOrder() {
String response = new RestTemplate().getForObject("http://localhost:8081/item",
String.class);
return new ResponseEntity<String>(response, HttpStatus.OK);
}
===MS#2 Controller===============
package com.app.raghu;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class OrderController {
@GetMapping("/item")
public ResponseEntity<String> createOrder() {
return new ResponseEntity<String>("HELLO USERS!!", HttpStatus.OK);
}
*) Development : ___.java
*) Compile : ___.class
*) Build : ___.jar / __.war / ___.ear
===============================================================
Project Management Tool : Maven
==============================================================
~/.m2 : It is called as Local Repository that holds all download
jars from Maven Central Repository
Ex:
C:\Users\raghu\.m2
--example--
pom.xml
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.32</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.1</version>
<scope>test</scope>
</dependency>
</dependencies>
--code--
package com.app;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Connection;
import org.junit.jupiter.api.Test;
@Test
public void testGetConnection() {
DatabaseConnection dbc = new DatabaseConnection();
Connection con = dbc.getConnection();
assertNotNull(con);
}
}
> Right click on project > Run As > Maven Build ...
> clean package > apply and run
Date : 21-02-2023
Tools Session
7 AM
-----------------------------------------------------
Apache Maven
*) Dependency Exclusion:-
> Avoid / exclude one child dependency (jar) from parent dependency
chain is called as Dependency Exclusion.
Example:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.25</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</exclusion>
</exclusions>
</dependency>
Q) How can we move from Tomcat Server to any other server in Spring boot?
A) By using Maven Dependency Exclusion concept.
First we need to exclude tomcat dependency from spring web dependency
then add Jetty/Undertow Dependency manually.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
========================================================================
Dependency Scope in Maven:- When and Which jar is used?
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
<scope>provided</scope>
</dependency>
5. system : Jar is not present in .m1/.m2 then load from system drives
If a JAR exist inside our System Drives
<dependency>
<groupId>com.app</groupId>
<artifactId>sample-abcd</artifactId>
<version>3.32</version>
<scope>system</scope>
<systemPath>D:/abcd/sample</systemPath>
</dependency>
=====================================================================
Web Application:
> File > new > Maven > Maven project > Next [no checkbox]
> Next > DropDown [internal] > Search for web
> maven-archtype-webapp > Next > Enter details
groupId: com.app
artifactId: FirstwebApp
Version : 1.0
Apache Tomcat:-
> Download and Configure : apache-tomcat-9.0.72
> Make sure set Path and JAVA_HOME
> Goto tomcat folder / bin / click on startup.bat file
> Enter URL: http://localhost:8080/
================================================
Web Application:
> File > new > Maven > Maven project > Next [no checkbox]
> Next > DropDown [internal] > Search for web
> maven-archtype-webapp > Next > Enter details
groupId: com.app
artifactId: FirstwebApp
Version : 1.0
*) WAR Plugin
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.1</version>
</plugin>
</plugins>
***) open web.xml and remove dtd lines code (top 3 lines)
===============================================================
Parent Maven Project (Parent Project) type: pom
*) We can create one Maven Project with type pom and specify
all codes and dependencies for child application connected using
<parent> tag.
<parent>
<groupId>___</groupId>
<artifactId>___</artifactId>
<version>__</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
</dependencies>
================================================================
Date : 25-02-2023
Tools Session
7 AM
-----------------------------------------------------
Logging:- Finding/Reading Messages from application like
Success, Info, warning, Errors and Exceptions..etc
where is running in dev/production/stage servers.
3 Components:-
Types:
ConsoleAppender : Write Log messages to Console
FileAppender/RollingFileAppender/DailyRollingFileAppender
: Write Log messages to File
=> SimpleLayout : Print Log message to Appender and goto next line
=> HTMLLayout : Print Log message in HTML Format
=> XMLLayout : Print Log message in XML Format
=> PatternLayout*** : Print Log message in Custom Pattern
in pom.xml
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.20.0</version>
</dependency>
Date : 01-03-2023
Tools Session
7 AM
-----------------------------------------------------
Log4j 2.x
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.31</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.14.0</version>
</dependency>
</dependencies>
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.31</version>
</dependency>
*) Create table:
create table EVENT_LOGS (
ID varchar(50) primary key,
DATE_TIME timestamp,
CLASS varchar(100),
LEVEL varchar(10),
MESSAGE TEXT
);
==MySQL Console================
mysql> drop database boot7am;
Query OK, 1 row affected (0.07 sec)
====================================================================
JUnit 5.x:-
It is open Source java F/w to test java applications (PASS/FAIL)
=> Actual Result after operation and expected result are same or not?
1. JUnit Annotations
2. JUnit Assert API
}
}
===Ex#1==================================================
pom.xml
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.5.1</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>4.5.1</version>
</dependency>
</dependencies>
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class ProcessTest {
@BeforeAll
public static void firstSetup() {
System.out.println("ONLY ONCE AT BEGINNING");
}
@BeforeEach
public void setup() {
System.out.println("FROM BEFORE");
}
@Order(30)
@Test
@DisplayName("FROM A TEST")
public void testA() {
System.out.println("FROM TEST#A METHOD");
}
@Test
@Disabled
public void testB() {
System.out.println("FROM TEST#B METHOD");
}
@Order(20)
@Test
@DisplayName("FROM C TEST")
public void testC() {
System.out.println("FROM TEST#C METHOD");
}
@AfterEach
public void clean() {
System.out.println("FROM AFTER");
}
@AfterAll
public static void lastCleanup() {
System.out.println("ONLY ONCE AT END");
}
}
===============Ex#2=====================================
service code:
package com.app.raghu;
Test code:
package com.app.raghu;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class CalculatorTest {
Calculator c;
int a, b, actual, expected;
@BeforeEach
public void setup() {
c = new Calculator();
a = 10;
b = 20;
expected = 200;
}
@Test
@Order(10)
@DisplayName("TESTING NULL CHECK")
public void testObjCreated() {
assertNotNull(c);
}
@Order(20)
@Test
@DisplayName("TESTING MULTIPLY OPERATION")
public void testMultiply() {
actual = c.multiply(a, b);
assertEquals(expected, actual);
}
@AfterEach
public void clean() {
c = null;
}
Q) How can we confirm that two references are pointed to same Object?
A) we can use assertSame(ob1,ob2) to check are they pointed to same
object or not?
*) Service class:
package com.app.raghu;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
static {
try {
con = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/boot7am", "root", "root");
} catch (SQLException e) {
e.printStackTrace();
}
}
*) TEST CLASS:
package com.app.raghu;
import java.sql.Connection;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class ConnectionUtilTest {
@BeforeEach
public void setup() {
con1 = ConnectionUtil.getConnection();
con2 = ConnectionUtil.getConnection();
}
@Test
@Disabled
@DisplayName("CHECKING NOT NULL")
@Order(1)
public void testNotNull() {
assertAll(
()->assertNotNull(con1),
()->assertNotNull(con2)
);
}
@Test
@DisplayName("CHECKING SAME REF")
@Order(2)
public void testSameRef() {
assertSame(con1, con2);
}
@AfterEach
public void clean() {
con1 = con2 = null;
}
}
===================================================================
Mockito
//depends on
interface ProductService {
Integer saveProduct();
}
ProductService ps = mock(ProductService.class);
*) Test class:
package com.app.raghu;
import org.junit.jupiter.api.Test;
assertEquals(ps.getCode("ABC"), 100);
}
}
=======Basic Example#2=======================================================
*) Application code:
package com.app.raghu;
import java.sql.SQLException;
import java.util.List;
-------------
package com.app.raghu;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class ServiceTest {
@InjectMocks //creates actual object of service with dummy Repo object injected
private Service sob;
@Test
public void testGetDataLen() throws SQLException {
//provide dummy impl for method getData(), that returns Array of 5 elements
when(repo.getData())
.thenReturn(Arrays.asList("A","B","TEST","WELCOME","FORMAT"));
}
======================================================================
*) Recomanded to use Embedded Databases: H2 for Testing Spring Boot
Applications