0% found this document useful (0 votes)
10 views

Spring Boot Webservice (AutoRecovered)

The document provides an overview of web services, focusing on the integration of applications using HTTP and global data formats like XML and JSON. It explains the roles of consumer and producer applications, HTTP methods, response status codes, and the differences between various request methods. Additionally, it covers the implementation of RESTful web services using Spring Boot, including annotations, application structure, and examples of CRUD operations.

Uploaded by

Harshal More
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
10 views

Spring Boot Webservice (AutoRecovered)

The document provides an overview of web services, focusing on the integration of applications using HTTP and global data formats like XML and JSON. It explains the roles of consumer and producer applications, HTTP methods, response status codes, and the differences between various request methods. Additionally, it covers the implementation of RESTful web services using Spring Boot, including annotations, application structure, and examples of CRUD operations.

Uploaded by

Harshal More
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 277

Webservices

*) To link two or more applications running at different web-servers

using HTTP protocol and data as Global Format (XML/JSON).

*) Webservices is also called as Integration.

ex: BookMyShow App Linked with PayTM.

*) One Application is called as Consumer (Client) and another one

is called as Poducer(Server).

*) Client always makes request to Server application, using

Http Method and URL.

Http Method says "What todo for a Server"

---- Http Request Methods-------------------

GET : Fetch Resource from Server

POST : Create a New Resource at Server

PUT : Modify existed Resource at Server

DELETE : Remove existed Resource at Server

PATCH : Partially Update existed Resource at Server

Other: TRACE, CONNECT, OPTIONS, HEAD

Resource: (File/Image/Doc/DB Data)

Q) Can we use POST Method to Get Data from Server?

A) Actually it supports getting data. But it is not a Http Standard.

Q) What is the difference between PUT and PATCH?

A) PUT : it is recomanded to use when full resource is getting modified.

PATCH: used only for partial data update.


========================================================================

Producer application gives Response Back using Codes/Numbers called as

Http Response Status Codes


---------------------------------------

Type Code

---------------------------------------

Information 1xx

Success 2xx (200-OK)

Redirect 3xx

Client Side Error 4xx (404-Not found)

Server side Error 5xx (500-Internal Server Error)

Ref:-

https://developer.mozilla.org/en-US/docs/Web/HTTP

Http Message Types:

1. Request : Init Line + Header + Body

2. Response : Init Line + Header + Body

Init Line will be in different format

For Request: Http Method URL Version

For Response: Version Status Phrase

Q) What is the difference between GET and HEAD?

A) Get Will not support request Body. It is used to fetch data from server.

Head will not support both request and response body.

Just used to call a task at server (do not know its message,

we get only response code)

Q) What is the difference between GET and POST?

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),

that creates a new resource at server.

Q) What is the difference between POST and PUT?


A)

Post is used to send data using its request body (Data is hidden here),

that creates a new resource at server.

Put is used to send data using its request body (Data is hidden here),

that modifies existed resource at server.

Date : 12-11-2022

Spring Boot and Microservices

Mr. Raghu

(ASHOK IT)

---------------------------------------------------------------------

Webservices

*) 3 Layers (PL,SL and DAL) are used to develop application

(ie consumer or producer).

*) Now we are using 4th Layer Integration (IL) Layer.


This is used to link applications.

*) Both Producer and Consumer should contain this layer.

Skeleton/API -- Producer (IL) Code

Stub/Caller -- Consumer (IL) Code

========================================================================

Global Data Format:- (XML/JSON)

This format of data can be read/processed by any language.

(ie Java, .Net, PHP, Python, Node..etc)

Serialization: Converting Java Object to other formats

Object ---> binary/file/stream/..etc

-------------------------------------------------------------------

JSON : JavaScript Object Notation.

It follow data format like:

"key" : value,

"key" : value,

...

=> Every key must be quoted, value is quoted for String type.

-------------------------------------------------------------------

Java JavaScript

------------------------------------------------------------------

int id = 10 var id = 10

String s = "ABC"; var s = "ABC";

Emp e = new Emp(); var e = { "id": 10, "name":"ABC" };

e.setId(10); //Object Notation

e.setName("ABC");

--------------------------------------------------------------------

JACKSON API | GSON | JAX-B :-


These are opensource 3rd party APIs which are used to convert

Java Object <---> JSON

1. Primitives Data

"eid" : 10, "ename" : "A", "enabled" : false

2. Array/List/Set

"eid" : 10, "ename" : "A",

"depts" : [ "DEV", "QA", "HR" ]

3. Map/child class(HAS-A)

"eid": 10, "ename" : "A",

"project" : {

"pid" : "101",

"pcode": "AA"

Q) When should we use YAML and JSON?

A)

JSON YAML

EndUser data Programmer Data

Trasfer b/w Apps Input to service

Ex: use YAML - Use Email Service (host,port,un,pwd)

use JSON - 200 Products data send it to Order Module.

1 Employee = 1 DB Row = 1 JSON object


DevOps - YAML --> input Ansible / Kubernetes(Runtime Env)

============================================================

XML : eXtensible Markup Language

It is used to represent data in Global Format used for both

Configuration and Data Trasfer.

*) web.xml in Servlets (data given to server)

*) employees.xml file is used to trasfer to another app.

ex:

<employee>

<eid>10</eid>

<ename>AJ</ename>

</employee>

*) JAXB : Java Architecture for XML Binding https://en.wikipedia.org/wiki/Jakarta_EE

This API is used to convert Java Object <--> XML

*) Spring Boot will not support XML as Configuration/Data

by default. We have to enable this to use.

======================================================================

Webservices 2 Types:

1. SOAP : Fully dependent XML/XSD/DTD.

=> SOAP is Protocol (like HTTP) with XML Standards.

=> Slow in processing/ Heavy Code and Configuration.

=> Maintain / Testing is not easy.

2. ReST : It is a design of Client-Server using HTTP + Global Data.

Re = Representation

S = State

T = Trasfer
=>** Send/receive data in global format.

*) ReST API / Restful / ReST ... are same.

*) API : [Application Programming Interface]

Code defined to provide service.

(pre-defined classes/interfaces/enums/annotation)

-------------------------------------------------------------------

Spring Boot ReST/ Restful Webservices using Spring boot

case#1 (Both apps) [BookMyShow --- Paytm]

Consumer Application ------- Producer Application

(Java) (.net)

case#2 Fullstack design [Frontend -- Backend]

UIApplication ----- Java Application (IL,SL,DAL)

Angular/ReactJS

case#3 Microservices Design [1 Application --> n Modules --> n Small Apps]

1 Module App ---- 1 Module App ---- 1 Module App.


Date : 13-11-2022

Spring Boot and Microservices

Mr. Raghu

(ASHOK IT)

---------------------------------------------------------------------

Spring Boot Restful Webservices

=> Webservices is used to link two apps (runs in different server).

=> Webservices - SOAP (XML Based / Protocol),

ReST(Architecture/Client-Server) [XML/JSON/Text]

=> ReST - Representation State Transfer

=> Two apps: Producer and Consumer.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- case#1

Restful Webservices

Link/Integrate two different applications running in two different servers

by using HTTP Protocol and Global Data Format.

Producer should contain -- Service Provider code / Skelton / API

Consumer should contain -- Service Consumer code / Stub / Caller

*) In This case at Producer Application side, we use @RestController,

and at Consumer application side we use RestTemplate(C).

+----------------------------+----------------------------------------+

| Controller | RestController |

+----------------------------+----------------------------------------+

This is for WEB MVC Apps This is for RestBased Apps

It is connected with View Here, we have no View(UI Concept)

(UI/Java based-JSP/Thymeleaf)

Data is Exchanged using Objects Data is Exchanged using XML/JSON

between UI and Controller with Consumer Apps.

(Model/ModelAttribute..etc)
It is a full web-app developing It is like a service Provider

concept. must be used by a client.

(Any Language)

+----------------------------+----------------------------------------+

Ex of Webservices: Payment Service, OTP service, Card Payments ..etc

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- case#2

Fullstack Application design.

Fullstack Application = Frontend Apps + Backend Apps

Frontend Applications are called as Client Apps which are fully dependent

on Backend Application. ie Business Logic / Tx and database exist at backend

only.

Backend Apps are called as Provider which is connected using HTTP

Protocol and data in Global Format(XML/JSON).

Ex Frontend Tech are : Angular/ReactJS, Andriod, iOS,... etc

==================================================================== case#3

Microservices Design (Backend in new way)

[Large Scale Application]

*) Independent deployable components that supports Auto-

Scale, Load Balance, Service Communication,

Less DownTime/Zero DownTime.

Implementing every Module as 1 Project (which are independent) and

connect with using Webservices.

Q) Explain these terms?

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)

---------------------------------------------------------------------

Spring Boot Restful Webservices

*) By Using Spring Boot Restful webservices we can develop both

Producer and Consumer applications.

*) Producer application work flow:

1. Every request is taken by FC(FrontController) which is a

Servlet (DispatcherServlet).

2. FC provides Request details (PATH/Http Method) to HandlerMapper that returns

RestController#Method details

(ex: PaymentRestController#doPay)

3. Once it gets executed output will be ResponseEntity<T>

(Other ReturnType: String, ClassType, Collection).

4. This ResponseEntity is given back to FC and same sent to clientapp.

*) Note:

1. There is NO UI at Producer App for webservices concept.

2. Data Formats are (request/response): Text, JSON, XML

3. No ViewResolver is required to configure.

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

5. Browser supports making GET and POST request only.

So, for Testing purpose we use a Tool "POSTMAN".

Download Link:

https://www.postman.com/downloads/
+----------------------------+----------------------------------------+

| Controller | RestController |

+----------------------------+----------------------------------------+

This is for WEB MVC Apps This is for RestBased Apps

It is connected with View Here, we have no View(UI Concept)

(UI/Java based-JSP/Thymeleaf)

Data is Exchanged using Objects Data is Exchanged using XML/JSON

between UI and Controller with Consumer Apps.

(Model/ModelAttribute..etc)

It is a full web-app developing It is like a service Provider

concept. must be used by a client.

(Any Language)

+----------------------------+----------------------------------------+

Spring Boot Rest Annotations:

1. @RestController : We need to apply this at class level

2. @RequestMapping : At class/ method level too.

3. @GetMapping

4. @PostMapping

5. @PutMapping

6. @PatchMapping

7. @DeleteMapping

8. @PathVariable : URL Input (Similer to Request Param)

9. @HeaderParam : to read Request Header parameters

10. @RequestBody : Request(JSON/XML) ---> Object (Method Input)

11. @ResponseBody : Object (Method Return) ---> Response(JSON/XML)

========================================================================

First Application : Spring Boot Rest Producer Application

*) HttpStatus is a enum that gives all Http Response Status codes to

be returned with Response Object.


200 - OK (success)

400 - Bad Request (Client data is missing/not valid)

404 - Not Found (Invalid URL)

405 - Method Not Allowed (URL is valid, but not Http Method type)

500 - Internal Server Error (Exception at Server side)

App/Coding Steps:-

1. Create one Spring Boot Application

Name: SpringBootRestProducerFirstEx

Dep : Spring Web, Devtools

2. RestController package com.app.raghu.controller;

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.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")

public class ProductRestController {

//1. Fetch Resource

//@RequestMapping(value = "/fetch",method = RequestMethod.GET)

@GetMapping("/fetch")

public ResponseEntity<String> getProduct() {

ResponseEntity<String> response = new ResponseEntity<>(


"FROM GET OPERATION", //body

HttpStatus.OK); //status (OK/200)

return response;

//2. Create Resource

@PostMapping("/save")

public ResponseEntity<String> createProduct() {

ResponseEntity<String> response = new ResponseEntity<>(

"FROM POST OPERATION",

HttpStatus.OK

);

return response;

//3. Modify Resource

@PutMapping("/update") public

ResponseEntity<String> updateProduct() {

ResponseEntity<String> response = new ResponseEntity<>(

"FROM PUT OPERATION",

HttpStatus.OK

);

return response;

//4. Remove Resource

@DeleteMapping("/remove")

public ResponseEntity<String> deleteProduct() {

ResponseEntity<String> response = new ResponseEntity<>(

"FROM DELETE OPERATION",


HttpStatus.OK

);

return response;

//5. Partial Update of Resource

@PatchMapping("/updatecost")

public ResponseEntity<String> modifyProductCost() {

ResponseEntity<String> response = new ResponseEntity<>(

"FROM PATCH OPERATION",

HttpStatus.OK

);

return response;

3. Run Main class and Test from POSTMAN

[GET] http://localhost:8080/product/fetch [SEND]

[POST] http://localhost:8080/product/save [SEND]

[PUT] http://localhost:8080/product/update [SEND]

[DELETE] http://localhost:8080/product/remove [SEND]

[PATCH] http://localhost:8080/product/updatecost[SEND]

--Task----------------------------------------------------

Write one simple REST API For Student that will display simple messages for

GET, POST, PUT, DELETE, PATCH.

===================================================================== Q)

how can we switch to some other servers from tomcat?

How can we remove embeeded tomcat from Spring Boot application?


Step#1 Remove embedded tomcat

<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>

Step#2 Add other server

<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

Spring Boot and Microservices

Mr. Raghu

(ASHOK IT)

---------------------------------------------------------------------

Global Data Formats (XML/JSON)

*) Incase of complex data inputs/outputs like JSON/XML, we use

MediaType annotations.
1. @RequestBody : It will read Http Request Body Section, checks

Content-type -> read data from Body -> Convert to

one Object -> Give it as method param.

2. @ResponseBody: It will write Http Response Body Section, If return type is

non-String type(ClassType, CollectionType) then object -> Gloabl Data ->

given to Response Body and also updates Content-type.

*)Note:

1. These annotations are applicable only if we work on non-String types

(ex: Employee, List<Product> ..etc)

2. Validation of data (request) is done by annotations.

3. Only by default JSON (JACKSON) Conversions are supported.

No XML by default in Spring boot.

4.**** When we add @RestController by default it internally adds

@ResponseBody.

===============================================================

JSON Syntax:

a) For one Object: { "key":val, "key":val }

b) For one List/Array/Set :

element1, element2,...

c) For one Map/Properties :

"key":val, "key":val

}
===========Working with output (@ResponseBody) ==================

Name : SpringBootRestJSONOutput

Dep : Spring web, Lombok, Devtools

1. Entity classes

package com.app.raghu.entity;

import java.util.Map; import

java.util.Set;

import com.fasterxml.jackson.annotation.JsonIgnore; import

com.fasterxml.jackson.annotation.JsonProperty;

import lombok.AllArgsConstructor;

import lombok.Data; import

lombok.NoArgsConstructor;

@Data

@NoArgsConstructor @AllArgsConstructor

public class User {

@JsonProperty("user-unq-id")

private Integer userId;

@JsonProperty("user-first-name")

private String userName;

private String userRole;

@JsonIgnore

private String password;

private Set<String> permissions;

//private List<String> permissions;


//private String[] permissions;

private Map<String,String> models;

//private Properties models;

-------Role Entity-----------

package com.app.raghu.entity;

import lombok.AllArgsConstructor;

import lombok.Data; import

lombok.NoArgsConstructor;

@Data

@NoArgsConstructor @AllArgsConstructor

public class Role {

private Integer roleId;

private String roleCode;

2. RestController class package

com.app.raghu.rest;

import java.util.Arrays;

import java.util.List; import

java.util.Map; import

java.util.Set;

import org.springframework.http.HttpStatus; import

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;

import com.app.raghu.entity.Role; import

com.app.raghu.entity.User;

@RestController

@RequestMapping("/user") public

class UserRestController {

@GetMapping("/one")

//@ResponseBody

public ResponseEntity<User> getOneObj() {

User ob = new User(101, "ABC", "Dev", "PASSWD1234",

Set.of("P1","P2"),

Map.of("M1","AA","M2","AB")

);

ResponseEntity<User> response = new ResponseEntity<>(ob, HttpStatus.OK);

return response;

@GetMapping("/list")

public ResponseEntity<List<Role>> getAllRoles() {

List<Role> roles = Arrays.asList(

new Role(1100, "ADMIN"),

new Role(1102, "BA"),

new Role(1103, "QA")

);

ResponseEntity<List<Role>> response = new ResponseEntity<>(roles, HttpStatus.OK);


return response;

@GetMapping("/map")

public ResponseEntity<Map<String,Role>> getMappedRoles() {

Map<String,Role> rolesMap = Map.of(

"R1", new Role(1100, "ADMIN"),

"R2", new Role(1102, "BA"),

"R3", new Role(1103, "QA")

);

ResponseEntity<Map<String,Role>> response = new ResponseEntity<>(rolesMap, HttpStatus.OK);

return response;

URLS:

http://localhost:9090/user/one http://localhost:9090/user/list

http://localhost:9090/user/map

=======================================================================

Note:

1. Use @JsonIgnore to avoid a variable/field in JSON operations

(used in project)

2. @JsonProperty to give alias names to variables.

======================================================================= Q)

Write one Example using Maven for JSON/JACKSON?

Q) Do we need to apply @ResponseBody in Spring boot rest ?


A) Not required. By default @RestController gives it.

Q) How can we avoid one field/variable in JSON operations?

A) @JsonIgnore

Q) What will happen if variable holds null and in JSON Operations?

A) null is printed.

Q) how can we provide alias names to variables in JSON?

A) @JsonProperty

=================================================================

Working with XML

Step#1 Add Dependency

<dependency>

<groupId>com.fasterxml.jackson.dataformat</groupId>

<artifactId>jackson-dataformat-xml</artifactId>

</dependency>

Step#2 While Making Request, send one Header Param

Accept = application/xml

*) Note: If Dependency is not added, then Accept Request may get

Response code as : 406 Not Acceptable


Date : 16-11-2022

Spring Boot and Microservices

Mr. Raghu

(ASHOK IT)
---------------------------------------------------------------------

Global Data Formats (XML/JSON)

@RequestBody: It takes data (XML/JSON) from Http Request Body Section and

converts into one Object Format.

+--------------------------------------+

| POST | /employee/create | HTTP 1.1|

+--------------------------------------+

| |

| Content-Type: application/json |

+--------------------------------------+

| |

| { "empId" : 101, .... } |

+--------------------------------------+

1. We have to use NON-GET types request to send data using Body.

2. @RequestBody must be used inside Method Parameter.

Syntax:

@RequestBody ClassName objName

3. If any field/variable is missing data from JSON, then it holds default value based on datatype (ex:

null for String).

4. Sending additional keys in JSON (Request) which are not present

in Entity, then those are ignored.

ex:

"empId": 10,

"empName": "A",

"empSal": 300.0,

"empDept" : "DEV"

Here empDept is ignored , it is not exist in Employee.


5. JSON Keys can be sent/receive in any order.

6. Invalid JSON Request, leads to 400-Bad Request.

Ex:

"empId": 10,

"empSal": 300.0,

"empName": "A"

7. If XML Dependency (jackson-dataformat-xml) is not added, and trying to send XML as

Input/Request Body with Content-type: application/xml then FC returns 415 Unsupported

MediaType.

8. To work with XML conversions, add below dependency <dependency>

<groupId>com.fasterxml.jackson.dataformat</groupId>

<artifactId>jackson-dataformat-xml</artifactId>

</dependency>

=============Code=======================================

Name : SpringBootRestMediaTypeOutputEx

Dep : Web, Lombok, Devtools

1. Entity package

com.app.raghu.entity;

import lombok.Data;

@Data

public class Employee {

private Integer empId;

private String empName;

private Double empSal;


}

2. RestController

package com.app.raghu.rest;

import org.springframework.http.HttpStatus; import

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")

public class EmployeeRestController {

@PostMapping("/create") public

ResponseEntity<String> createEmployee(

@RequestBody Employee employee

String s = employee.toString();

ResponseEntity<String> response = new ResponseEntity<>(s,HttpStatus.OK);

return response;

3. Run Application and Make Request using POSTMAN.

==========Complex Inputs========================================

1. Entity classes

package com.app.raghu.entity;
import lombok.AllArgsConstructor;

import lombok.Data; import

lombok.NoArgsConstructor;

@Data

@NoArgsConstructor @AllArgsConstructor

public class Address {

private String hno;

private String loc;

-----------------

package com.app.raghu.entity;

import java.util.List; import

java.util.Map;

import lombok.AllArgsConstructor;

import lombok.Data; import

lombok.NoArgsConstructor;

@Data

@NoArgsConstructor

@AllArgsConstructor public

class Employee {

private Integer empId;

private String empName;

private Double empSal;

private Address addr;//HAS-A

private List<String> projects;

private Map<String,Integer> codes;


}

2. Controller code package

com.app.raghu.rest;

import java.util.List; import

java.util.Map;

import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity;

import org.springframework.web.bind.annotation.GetMapping; 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.Address; import

com.app.raghu.entity.Employee;

@RestController

@RequestMapping("/employee")

public class EmployeeRestController {

@GetMapping("/find")

public ResponseEntity<Employee> getOneEmployee() {

Employee employee = new Employee(101, "AAAA", 500.0,

new Address("A/44","HYD"), List.of("M1","M2"),

Map.of("A1",10,"A2",20));

return new ResponseEntity<>(employee,HttpStatus.OK);

@PostMapping("/create") public

ResponseEntity<String> createEmployee(
@RequestBody Employee employee

String s = employee.toString();

ResponseEntity<String> response = new ResponseEntity<>(s,HttpStatus.OK);

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",

"loc" : "AMPT, HYD"

},

"projects" : ["P1","P2","P3"],

"codes" : { "C1": 10, "C2": 20, "C3": 30 }

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:

Student (sid,sname,sgen,course, langs:List, qualif:Map<String,Double>)

Course (cid,cname,cfee) send Input JSON/XML

Get output JSON/XML


Date : 17-11-2022

Spring Boot and Microservices


Mr. Raghu

(ASHOK IT)

---------------------------------------------------------------------

Request Parameter:-

URL ? key = val & key = val & key = val

ex: http://localhost:9090/employee/find?id=10&name=A

---Adv Java / Servlets--------------------

String val = request.getParameter("key"); int

id = Integer.parseInt(val);

--------------------------------

@RequestParam("key")DataType variableName

(or)

@RequestParam DataType key

===========================================================

PathVariable: Sending data along with URL as Path

.../employee/find/10/A

.../employee/find?id=10&name=A ( Query String)

.../employee/find?name=A&id=10

1. Clean URLs (NO SYMBOLS LIKE ? and &)

2. URL LENGTH AND SIZE is reduced

3. No Overloaded Symbols (NO BURDEN ON SERVER WHILE PARSING URL)

4. Follows Data/Path sending order.

*) Note:

1. Path Creation

@GetMapping("/employee/find/{id}/{name}")

Here /employee/find is called as static path and

/{id}/{name} dynamic path (Data comes at runtime)


2. Data Reading

@PathVariable("key")DataType variable

====================code============================================

Name : SpringBootRestPathVariableEx

Dep : Web, Lombok, Devtools

*) Controller code package

com.app.raghu.rest;

import 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.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(

@RequestParam("pid") Integer id,

@RequestParam("pname") String name

{
System.out.println("PID " + id +" PNAME "+ name); return new

ResponseEntity<>("PID " + id +" PNAME "+ name,HttpStatus.OK);

// Using Pathvariable

//.../datab/10/A

@GetMapping("/datab/{pid}/{pname}")

public ResponseEntity<String> showDataB(

@PathVariable("pid") Integer id,

@PathVariable("pname") String name

System.out.println("PID " + id +" PNAME "+ name); return new

ResponseEntity<>("PID " + id +" PNAME "+ name,HttpStatus.OK);

Request URL:

1.

http://localhost:9090/product/datab/101/MNO

Output Id=__ name=___

2.

http://localhost:9090/product/datab/222/111

Output Id=__ name=___

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

Q) Which one is better to use PathVariable or RequestParam?

A) PathVariable is better over RequestParam.

PathVariables are called as clean URL with less size/length.

No Processing time required for Query String reading.

*) JAVA EE : Supoprts only RequestParam, No PathVariable.

It exist in Spring Boot apps.

*) In fullstack/Rest based apps PathVariable is used.

===============================================================

Still lot of apps are using RequestParam. So, Spring boot even supports

Request Param also. https://www.google.com/search

? q= sachin+tendulkar

& sxsrf=ALiCzsZBVp76CI2yhnmxjbUGyPbMNMyotQ%3A1668650417775

& source=hp

& ei=sZV1Y6bJLMe3z7sPvtWYqAM

& iflsig=AJiK0e8AAAAAY3Wjwf8qaKKi4GIF9p
===============================================================

HeaderParams : These are instructions/Additional Data

(Security, Token data, Certificates, Date and Time, Cookies..etc ) exchanged

by both Browser and Server.

*) it is a Key-value pair. Data is sent in String format

*) There are pre-defined headers: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers

*) We can even pass our key-val as header params.

*) To read data use

@RequestHeader("key")DataType variableName

=> Authorization Header | Accept Header | Content-Type | Cookies Header

=======================================================================

Example: package

com.app.raghu.rest;
//ctrl+shift+O

@RestController

@RequestMapping("/product")

public class ProductRestController {

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

Enumeration<String> headerNames = req.getHeaderNames(); while

(headerNames.hasMoreElements()) {

String hdr = headerNames.nextElement();

System.out.println(hdr + " " + req.getHeader(hdr));

System.out.println("Data " + type +" - "+ len);

return new ResponseEntity<>("CHECK",HttpStatus.OK);

==============================================================

Dynamic ReturnType Selection based on workflow (condition)

Generics (Java 1.5) - wild card character (?)

public ResponseEntity<?> showInfo() {


if(new Random().nextInt() > 0) { return

new ResponseEntity<String>("OK",HttpStatus.OK);

} else {

return new ResponseEntity<Integer>(101,HttpStatus.OK);

}
Date : 18-11-2022

Spring Boot and Microservices

Mr. Raghu

(ASHOK IT)

---------------------------------------------------------------------

*) ReturnType in RestController # Methods

=> Here standard ReturnType is ResponseEntity.

=> It is a combination of Status Code + Header Params + Response Body.

=> ResponseEntity<T> , Here T = DataType of Body.

=> Allowed or possible T types are:

String, ClassType, Collection, Object (Not recomanded)

even ? (wild card char) if type is decided at runtime.

=> We can even return direct type without ResponseEntity<>.

In this case we can not provide our Status code and Headers,

that is considered only as body.

======================================================================== Q)

What is MultiValueMap and how it is different from Map?

A) MultiValueMap is a Map internally.

But Key is SimpleType (Primitive) and Value is List(ColelctionType)

*) Http Headers are MultiValueMaps. ie one key can have multiple values

Ex:

Accept = application/xml,application/json,*/*

*) In Spring REST HttpHeaders(C) is a MultiValueMap internally.

Q) When should we use ResponseEntity<> and Direct Return Type?

A)

If we want to return our own headers/Http status along with Body,

then use ResponseEntity.


Else Just return Direct class/String/Collection type that indicates

only body.

Q) Can we create ResponseEntity object without HttpStatus?

A) Status is must in case of ResponseEntity object.

it can never be null/empty.

Q) Can we create ResponseEntity object without Body?

A) Body can be null / empty

Q) Can we create ResponseEntity object without Headers?

A) Custom headers can be null / empty

======================Sample code==========================================

Name : SpringBootRestReturnTypeEx

Dep : Web, Lombok, Devtools

1. Entity package

com.app.raghu.entity;

import lombok.AllArgsConstructor;

import lombok.Data; import

lombok.NoArgsConstructor;

@Data

@NoArgsConstructor

@AllArgsConstructor public

class Book {

private Integer bookId;

private String bookName;

private Double bookCost;

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")

public class BookRestController {

@GetMapping("/a")

public String justBody() {

return "Hello Book Data!";

@GetMapping("/b")

public Book justBook() {

return new Book(10,"AA",200.0);

@GetMapping("/data")

public ResponseEntity<String> showInfo() {

//1. passing Http Status

//ResponseEntity<String> response = new ResponseEntity<>(HttpStatus.OK);

//2. passing Body + Http Status

//String body = "WELCOME TO APP";

//ResponseEntity<String> response = new ResponseEntity<>(body, HttpStatus.OK);


//3. Passing headers + status

HttpHeaders headers = new HttpHeaders(); headers.add("MyAppOne", "ACTIVATED-

CLIENT");

//ResponseEntity<String> response = new ResponseEntity<>(headers,


HttpStatus.OK);

//4. Passing body + headers + status

String body = "WELCOME TO APP";

ResponseEntity<String> response = new

ResponseEntity<>(body, headers, HttpStatus.OK);

return response;

==================================================================

Usecase# ResponseEntity with custom Headers HttpStatus and Body.

*) Entity class

package com.app.raghu.entity;

import lombok.AllArgsConstructor;

import lombok.Data; import

lombok.NoArgsConstructor;

@Data

@NoArgsConstructor

@AllArgsConstructor public

class Book {

private Integer bookId;

private String bookName;

private Double bookCost;

}
*) 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.PathVariable; import

org.springframework.web.bind.annotation.RequestMapping; import

org.springframework.web.bind.annotation.RestController;

import com.app.raghu.entity.Book;

@RestController

@RequestMapping("/book")

public class BookRestController {

//Path variable id --> Book (200,book,found=yes), String(400,Sorry No Book found, found=no)

@GetMapping("/obj/{id}") public ResponseEntity<?>

findBookById(@PathVariable Integer id)

ResponseEntity<?> response = null;

HttpHeaders headers = new HttpHeaders();

if(id == 501) {

headers.add("found", "yes");

response = new ResponseEntity<Book>(

new Book(id, "DUMMY", 500.0), //body

headers, //headers

HttpStatus.OK); //http status

} else {
headers.add("found", "no");

response = new ResponseEntity<String>(

"Sorry! No Book Found", //body

headers, //headers

HttpStatus.BAD_REQUEST); //http status

return response;

Date : 21-11-2022

Spring Boot and Microservices

7AM

Mr. Raghu

(ASHOK IT)

---------------------------------------------------------------------

Spring Boot - Exception Handling Process

*) Spring Boot has given one Pre-defined class "BasicErrorController"

which takes care of Error and Exception Handling.

=> if any exception is occured in RestController/Controller and not handled

(using try/catch block) then it is taken care by


BasicErrorController(C) and method error().

=> This error() method returns some pre-defined response format.

Ex:

"timestamp": "2022-11-21T01:42:22.666+00:00",

"status": 500,

"error": "Internal Server Error",

"trace": "java.lang.RuntimeException: Product Not Found 5586\r\n\tat


com.app.raghu.rest.ProductRestController.getProductById(ProductRestController.java:24)\r\n\tat
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n\tat
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77
)\r\n\tat
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImp
l.java:43)\r\n\tat java.base/java.lang.reflect.Method.invoke(Method.java:568)\r\n\tat
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMe
thod.java:205)\r\n\tat
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHa
ndlerMethod.java:150)\r\n\tat
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeA
ndHandle(ServletInvocableHandlerMethod.java:117)\r\n\tat
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeH
andlerMethod(RequestMappingHandlerAdapter.java:895)\r\n\tat
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleI
nternal(RequestMappingHandlerAdapter.java:808)\r\n\tat
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHan
dlerMethodAdapter.java:87)\r\n\tat
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1071)\r\n\tat
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:964)\r\n\tat
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\r
\n\tat
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)\r\n\tat
javax.servlet.http.HttpServlet.service(HttpServlet.java:670)\r\n\tat
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\r\n\tat
javax.servlet.http.HttpServlet.service(HttpServlet.java:779)\r\n\tat
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)\r\
n \tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\
tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\r\n\tat
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\
n \tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\
tat
org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100
)\r\n\tat
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\r\n\t
at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\
n \tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\
tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\r\n\
t at
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\r\n\t
at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\
n \tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\
tat
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.jav
a:201)\r\n\tat
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\r\n\t
at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\
n \tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\
tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)\r\n\tat
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\r\n\tat
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)\r\n\tat
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)\r\n\tat
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\r\n\tat
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\r\n\tat
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360)\r\n\tat
org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)\r\n\tat
org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\r\n\tat
org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893)\r\n\tat
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789)\r\n\tat
org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\r\n\tat
org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)\r\n\
tat
org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)\r\n\
tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat
java.base/java.lang.Thread.run(Thread.java:833)\r\n",

"message": "Product Not Found 5586",

"path": "/product/one/5586"

===Sample code ======================================

1. RestController code package

com.app.raghu.rest;

import 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;
@RestController

@RequestMapping("/product") public

class ProductRestController {

@GetMapping("/one/{id}") public

ResponseEntity<String> getProductById(

@PathVariable("id") Integer id

if(id==150)

return new ResponseEntity<>("Product Exist", HttpStatus.OK);

else

throw new RuntimeException("Product Not Found " + id);

2. application.properties server.port=9090

3. POSTMAN URL

GET http://localhost:9090/product/one/158

GET http://localhost:9090/product/one/150

====================================================================

*******************************************************************

Custom Exception Handling

*******************************************************************

====================================================================

We can define our own Response Format incase of Any exception occured in

application by using Annotations : @RestControllerAdvice and

@ExceptionHandler.

@RestControllerAdvice: Addes in Spring 4.3 version


=> It says this is a global class for exception handling.

=> It is executed by FC in the place of BasicErrorController.

@ExceptionHandler: Every Exception type is compared with this annotation on

given methods, if matched execute, else redirect back to

"BasicErrorController".

=> For one exception type, we need to define one Handler method.

==================================================================== *) We can even

return Custom Error Response class type for JSON/XML output. ie @RestControllerAdvice internally

uses @ResponseBody annotation.

-------------case#1-----------------------------------------

1. RestController package

com.app.raghu.rest;

import org.springframework.beans.factory.annotation.Autowired;

import 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.Product; import

com.app.raghu.exception.ProductNotFoundException; import

com.app.raghu.service.ProductService;

@RestController

@RequestMapping("/product")

public class ProductRestController {


@GetMapping("/one/{id}")

public ResponseEntity<String> getProductById(

@PathVariable("id") Integer id

if(id==150)

return new ResponseEntity<>("Product Exist", HttpStatus.OK);

else

throw new ProductNotFoundException("Product Not Found " + id);

2. Handler class package

com.app.raghu.handler;

import java.util.Date;

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.bean.MyErrorResponse; import

com.app.raghu.exception.ProductNotFoundException;

@RestControllerAdvice public class

MyCustomExceptionHandler {

@ExceptionHandler(ProductNotFoundException.class)
public ResponseEntity<String> showCustomErrorMsg(

ProductNotFoundException pnfe

return new ResponseEntity<String>(

pnfe.getMessage(),

HttpStatus.INTERNAL_SERVER_ERROR);

----------case#2------------------------------------------

2. Custom ErrorResponse

1. Entity/Beans package

com.app.raghu.entity;

import lombok.AllArgsConstructor;

import lombok.Data; import

lombok.NoArgsConstructor;

@Data

@NoArgsConstructor

@AllArgsConstructor public

class Product {

private Integer pid;

private String pcode;

--------------

package com.app.raghu.bean;
import lombok.AllArgsConstructor;

import lombok.Data; import

lombok.NoArgsConstructor;

@Data

@NoArgsConstructor

@AllArgsConstructor public

class MyErrorResponse {

private String date;

private String status; private

int code; private String

message;

2. Custom exception class

package

com.app.raghu.exception;

public class ProductNotFoundException

extends RuntimeException

/**

*/

private static final long serialVersionUID = 1L;

public ProductNotFoundException() {

super();

public ProductNotFoundException(String message) {

super(message);
}

3. Service class package

com.app.raghu.service;

import org.springframework.stereotype.Service;

import com.app.raghu.entity.Product; import

com.app.raghu.exception.ProductNotFoundException;

@Service public class

ProductService {

public Product getOneProductById(Integer id) {

if(id==150) return

new Product(id, "DUMMY");

else

throw new ProductNotFoundException("PRODUCT '"+id+"' NOT EXIST");

4. RestController package

com.app.raghu.rest;

import org.springframework.beans.factory.annotation.Autowired;

import 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.Product; import

com.app.raghu.exception.ProductNotFoundException; import

com.app.raghu.service.ProductService;

@RestController

@RequestMapping("/product") public

class ProductRestController {

@Autowired

private ProductService service;

/*

@GetMapping("/one/{id}") public

ResponseEntity<String> getProductById(

@PathVariable("id") Integer id

if(id==150)

return new ResponseEntity<>("Product Exist", HttpStatus.OK);

else

throw new ProductNotFoundException("Product Not Found " + id);

}*/

@GetMapping("/one/{id}")

public ResponseEntity<Product> getProductById(

@PathVariable("id") Integer id

ResponseEntity<Product> response = null;

try {
Product pob = service.getOneProductById(id);

response = new ResponseEntity<Product>(pob,HttpStatus.OK);

} catch (ProductNotFoundException pnfe) {

pnfe.printStackTrace();

throw pnfe;//call handler

return response;

5. RestController advice package

com.app.raghu.handler;

import java.util.Date;

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.bean.MyErrorResponse; import

com.app.raghu.exception.ProductNotFoundException;

@RestControllerAdvice public class

MyCustomExceptionHandler { /*

@ExceptionHandler(ProductNotFoundException.class)

public ResponseEntity<String> showCustomErrorMsg(

ProductNotFoundException pnfe

return new ResponseEntity<String>(

pnfe.getMessage(),

HttpStatus.INTERNAL_SERVER_ERROR);
}

*/

@ExceptionHandler(ProductNotFoundException.class) public

ResponseEntity<MyErrorResponse> showCustomErrorMsg(

ProductNotFoundException pnfe

return new ResponseEntity<MyErrorResponse>(

new MyErrorResponse(

new Date().toString(),

"EXCEPTION IN PROCESS",

500,

pnfe.getMessage()),

HttpStatus.INTERNAL_SERVER_ERROR);

================================================================== Q)

How do you handle exceptions in your RestApplications?

A) Here Service Layer thro exception based on some conditions.

Catched by RestController and re-thrown to GlobalHandler.

Global Exception Handler compares exception type and returns

Custome Error Message with status code.

Request->FC->HM->RestController->call service -> call Repo

-> No Data -> Service throw exception -> catch in RestController

-> throw exception obj -> Exception Handler -> compare type

-> Return custom message.


Date : 22-11-2022

Spring Boot and Microservices

7AM | Mr. Raghu | (ASHOK IT)

---------------------------------------------------------------------

Spring Boot ReST : Client Application

*) Sometimes, our application (implemented using Spring Boot) wants to

connect with other applications (implemented using Java/.net/Python..etc). ie

our application is Consumer.

*) In this case use Http Client : "RestTemplate"(C).

[It is a class, that supports HTTP Protocol]

=> RestTemplate:

1. it is a class

2. Suports all HTTP Methods (GET/POST/PUT/DELETE)

3. Supports Request Body and Headers creation

4. Reads Response into ResponseEntity or DirectType(String, Employee).

5. Auto-type conversion of global Data (JSON/XML-->Object)

Q) What is var-args and how they are different arrays?

A) ... (3 dots) indicates var-args (Varing Length Arguments) we can pass

data of same type multiple values without creating as an array

Just comma separated values.

Array once created fiexd in size, var-args size not fixed.

-> var-args must be the last parameter in method

-> only 1 var-args type is allowed for 1 method

-> JDK 1.5 version (Java 5)

-> Arrays can be any number and any order as parameter for a method

Q) What is mean by : java.net.ConnectException: Connection refused: connect?

A) If Producer application is down/ not started then we see this.


=======================GET OPERATIONS =============================

1. Producer Code

Name : 07SpringBootRestProducerEx

Dep : Spring web, Lombok, Devtools

*) Bean class package

com.app.raghu.entity;

import lombok.AllArgsConstructor;

import lombok.Data; import

lombok.NoArgsConstructor;

@Data

@NoArgsConstructor @AllArgsConstructor

public class Book {

private Integer bid;

private String bname; private

String bauth; private Double

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")

public class BookRestController {

@GetMapping("/showA")

public ResponseEntity<String> showMsg1() {

//return new ResponseEntity<String>("WELCOME",HttpStatus.OK);

return ResponseEntity.ok("WELCOME TO FIRST CALL TYPE - GET");

@GetMapping("/showB/{id}/{name}")

public ResponseEntity<String> showMsg2(

@PathVariable("id") Integer id,

@PathVariable("name") String name

return ResponseEntity.ok("WELCOME TO FIRST CALL TYPE - GET ==> " +id +""+name);

@GetMapping("/showC") public ResponseEntity<Book>

showMsg3() { return ResponseEntity.ok(new Book(101, "ABC", "RAJ",

500.0)); }

//try return type List<Book>


}

----------------------------------

2. Consumer Code

Name : 07SpringBootRestConsumerEx

Dep : Spring web, lombok

==application.properties== server.port=9696

==Runner classes====== package

com.app.raghu.runner;

import org.springframework.boot.CommandLineRunner;

import org.springframework.http.ResponseEntity; import

org.springframework.stereotype.Component; import

org.springframework.web.client.RestTemplate;

@Component

public class GetTestARunner implements CommandLineRunner {

public void run(String... args) throws Exception {

//1. Create URL

//String url = "http://localhost:8080/v1/api/book/showA";

String url = "http://localhost:8080/v1/api/book/showC"; //2. Create Request


Headers

//3. Create Request Body

// 2+3

//4. Create RestTemplate object

RestTemplate template = new RestTemplate();


//5. Make HTTP call and Get Response back

ResponseEntity<String> response = template.getForEntity(url, String.class); //URL,


ResponseFormat.class

//6. print details

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.ResponseEntity; import

org.springframework.web.client.RestTemplate;

//@Component public class GetTestARunner2 implements

CommandLineRunner { public void run(String... args) throws

Exception {

//1. Create URL

String url = "http://localhost:8080/v1/api/book/showB/{id}/{name}";

//2. Create Request Headers

//3. Create Request Body

// 2+3

//4. Create RestTemplate object

RestTemplate template = new RestTemplate();


//5. Make HTTP call and Get Response back

ResponseEntity<String> response =

template.getForEntity(

url,

String.class,

101, "ABC" //path variables

);

//6. print details

System.out.println(response.getBody());

System.out.println(response.getHeaders());

System.out.println(response.getStatusCode().name());

System.out.println(response.getStatusCode().value());

========================================================================

POST METHOD CALL:

To make POST Request we need to pass URL, RequestEntity(Body+Headers) along

with ResponseType to a method postForEntity().

--API--

postForEntity(

url : String,

requestEntity:HttpEntity,

responseType:K.class

) ResponseEntity<K>

HttpEntity = HttpHeaders + Body

--Sample code---
HttpHeaders headers = new HttpHeaders();

headers.setContentType(MediaType.APPLICATION_JSON);

===============================CODE=============================

1. Producer code package

com.app.raghu.rest;

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.Book;

@RestController

@RequestMapping("/v1/api/book") public

class BookRestController {

@PostMapping("/showD") public

ResponseEntity<String> showMgs4(

@RequestBody Book book

return ResponseEntity.ok("Data given is " + book);

}
2. Consumer code (Runner class) package

com.app.raghu.runner;

import org.springframework.boot.CommandLineRunner;

import org.springframework.http.HttpEntity; import

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

public class PostTestARunner implements CommandLineRunner {

public void run(String... args) throws Exception {

//1. Create URL

String url = "http://localhost:8080/v1/api/book/showD";

//2. Create Request Headers

HttpHeaders headers = new HttpHeaders();

headers.setContentType(MediaType.APPLICATION_JSON);

//3. Create Request Body

String body = "{\"bid\" : 101,\"bname\" : \"ABC\", \"bauth\":\"AJ\", \"bcost\":500.0}";

// 2+3 Combine Both Body and Headers

HttpEntity<String> requestEntity = new HttpEntity<>(body,headers);

//4. Create RestTemplate object

RestTemplate template = new RestTemplate();


//5. Make HTTP call and Get Response back

ResponseEntity<String> response =

template.postForEntity(url, requestEntity, String.class);

//6. print details

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)

*) RestTemplate has given one generic method : exchange()


that supports all Http Method call : GET, POST, PUT..etc

exchange(
url,
HttpMethod,
HttpEntity(request),
ResponseType.class,
pathVariables...
): ResponseEntity<T>

*) Just Replace below lines of code in consumer application


Old Line:
ResponseEntity<String> response = template.postForEntity(url, requestEntity, String.class);
New Line:
ResponseEntity<String> response = template.exchange(url, HttpMethod.POST, requestEntity,
String.class);

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.

====================exchange() method code============================


1. Producer Application

*) 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

*) Runner class code


package com.app.raghu.runner;

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 {

public void run(String... args) throws Exception {


String url = "http://localhost:8080/v1/api/book/showE";

String body = "{\"bid\" :


101,\"bname\" : \"ABC\", \"bauth\":\"AJ\", \"bcost\":500.0}";

HttpHeaders headers = new HttpHeaders();


headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> requestEntity = new HttpEntity<String>(body, headers);

RestTemplate rt = new RestTemplate();


//This method makes request , but returns no body (void)
//rt.put(url, requestEntity);
ResponseEntity<String> response = rt.exchange(url, HttpMethod.PUT, requestEntity,
String.class);

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 {

public void run(String... args) throws Exception {


// URL
String url = "http://localhost:8080/v1/api/book/showF/{id}";

// Body, Headers => RequestEntity


// RestTemplate
RestTemplate rt = new RestTemplate();
// make call
//rt.delete(url, 101);
ResponseEntity<String> response = rt.exchange(url, HttpMethod.DELETE, null,
String.class, 101);

// 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)

*) Producer Code (Method only)


@GetMapping("/showC")
public ResponseEntity<Book> showMsg3() {
return ResponseEntity.ok(new Book(101, "ABC", "RAJ", 500.0));
}

(Entity class)
package com.app.raghu.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book {

private Integer bid;


private String bname;
private String bauth;
private Double bcost;
}

*) 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 {

public void run(String... args) throws Exception {


String url = "http://localhost:8080/v1/api/book/showC";
RestTemplate template = new RestTemplate();
//ResponseEntity<BookAtConsumer> response = template.getForEntity(url,
BookAtConsumer.class);
ResponseEntity<BookAtConsumer> response = template.exchange(url,
HttpMethod.GET, null, BookAtConsumer.class);

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 {

private Integer bid;


private String bname;
private String bauth;
private Double bcost;
}

*) Note: class name at consumer need not to be same as producer.


But variable names must match (should have set/get methods)
Date : 24-11-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Spring Boot ReST -- Backend Application

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;

public interface StudentRepository extends JpaRepository<Student, Integer> {

4. Service interface
package com.app.raghu.service;

import java.util.List;

import com.app.raghu.entity.Student;

public interface IStudentService {

Integer saveStudent(Student s);


void updateStudent(Student s);
void deleteStudent(Integer id);
Student getOneStudent(Integer id);
List<Student> getAllStudents();
}

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;

public Integer saveStudent(Student s) {


s = repo.save(s);
return s.getStdId();
}

public void updateStudent(Student s) {


if(s.getStdId() == null || !repo.existsById(s.getStdId()))
throw new StudentNotFoundException("STUDENT '"+s.getStdId()+"' NOT
EXIST");
else
repo.save(s);
}

public void deleteStudent(Integer id) {


repo.delete(getOneStudent(id));
}

public Student getOneStudent(Integer id) {


return repo.findById(id)
.orElseThrow(
()->new StudentNotFoundException("STUDENT
'"+id+"' NOT EXIST")
);
}

@Override
public List<Student> getAllStudents() {
List<Student> list = repo.findAll();
return list;
}

6. Custom Exception class


package com.app.raghu.exception;

public class StudentNotFoundException extends RuntimeException {


/**
*
*/
private static final long serialVersionUID = 1L;

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;

//1. create one student


@PostMapping("/create")
public ResponseEntity<String> createStudent(
@RequestBody Student student
)
{
Integer id = service.saveStudent(student);
String message = "STUDENT '"+id+"' CREATED";

//return new ResponseEntity<String>(message, HttpStatus.OK);


return new ResponseEntity<String>(message, HttpStatus.CREATED);//201
}

//2. fetch all students


@GetMapping("/all")
public ResponseEntity<List<Student>> getAllStudents() {
List<Student> list = service.getAllStudents();
//return new ResponseEntity<List<Student>>(list, HttpStatus.OK);
return ResponseEntity.ok(list);
}

//3. fetch one by id


@GetMapping("/find/{id}")
public ResponseEntity<Student> getOneStudent(
@PathVariable("id") Integer id
)
{
ResponseEntity<Student> response = null;
try {
Student s = service.getOneStudent(id);
response = ResponseEntity.ok(s);
} catch (StudentNotFoundException e) {
e.printStackTrace();
throw e;
}
return response;
}

//4. remove one by id


@DeleteMapping("/remove/{id}")
public ResponseEntity<String> deleteStudent(
@PathVariable("id") Integer id
)
{
ResponseEntity<String> response = null;
try {
service.deleteStudent(id);
response = ResponseEntity.ok("STUDENT '"+id+"' REMOVED");
} catch (StudentNotFoundException e) {
e.printStackTrace();
throw e;
}
return response;
}

//5. update student


@PutMapping("/modify")
public ResponseEntity<String> updateStudent(
@RequestBody Student student
)
{
ResponseEntity<String> response = null;
try {
service.updateStudent(student);
response = ResponseEntity.ok("STUDENT '"+student.getStdId()+"' UPDATED");
} catch (StudentNotFoundException e) {
e.printStackTrace();
throw e;
}
return response;
}
}

8. Global Exception Handler


package com.app.raghu.handler;

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

*) Spring Bean Validator API


=> Validating input at backend application using annotations.
=> To use this option we must add Spring Bean Validator (Hibernate Validator API)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

=> These annotation are given in as : Validation API (javax.validation)

@NotNull : Do not allow null values

sname = null //rejected


sname ="" //accepted
sname=" " //accepted

@NotEmpty : Do not allow null or empty values


sname = null //rejected
sname ="" //rejected
sname=" " //accepted

@NotBlank : Do not allow null/empty string/white space chars


sname = null //rejected
sname ="" //rejected
sname=" " //rejected

@Size : To specify min/max size for input (For String type)

@Min : For numbers (int/double)


@Max : For numbers (int/double)

@Pattern : We can given String Pattern Inputformat (RegExp)

@Past : Date type only


@Future : Date type only
ex:
@Past(message="DOB is invalid")
Date dob;
@Future(message="Product is invalid")
Date exp;

@AssertTrue : used for boolean types (expecting true only)


ex:
@AssertTrue
boolean readTermsAndConditions;

@AssertFalse: Expected input value is false only.

@Email : To validate Email Pattern


----------------
@Valid : This annotation activates validation-api and executes above
annotations in order.

If validation is failed then FC returns error code 400 (Bad Request).


Here,

=======================================================================
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

Only one time:


> npm install -g @angular/cli
> ng version
================================================================
*) Application Creation
> Open VS Code Editor
> Terminal > new Terminal > Switch to Cmd Prompt

> type cmd:


ng new student-ang-app
(Add Routing) y
(Choose CSS) y

> Start Application


cd student-ang-app
ng serve --open

> open app.component.html


> remove all lines of code and paste below code

<h3>WELCOME TO ANGULAR APPLICATION</h3>


<router-outlet></router-outlet>

http://localhost:4200/

> Come back to terminal and press cltr+C to stop app.


=================================================================
ReactJS Setup:
npm uninstall -g create-react-app
npx clear-npx-cache
npm i create-react-app

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/

> open App.js and Modify code as:


import "./App.css";

function App() {
return (
<div className="App">
<h3>WELCOME TO APP</h3>
</div>
);
}

export default App;


======================================================================
Date : 29-11-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Types of Files in Angular to be implemented:
1. Entity
2. Service
3. Component

========================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

> open app.module.ts file


> under import array add:
FormsModule, HttpClientModule

> Import Statements


import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';

---------------------------------------------------------
Step#3 Configure Routing (For which URL where to GO)

> open app-routing.module.ts


> You can check empty Routes array
const routes: Routes = []
> Modify code as
const routes: Routes = [
{ path: 'all', component: StudentListComponent },
{ path: 'create', component: StudentAddComponent },
{ path: '', redirectTo: 'all', pathMatch: 'full' },
{ path: '**', component: StudentListComponent },
];

> incase of import issues:


import { StudentAddComponent } from './components/student-add/student-add.component';
import { StudentListComponent } from './components/student-list/student-list.component';

==========================================================
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>

> change body as


<body>
<div class="container">
<app-root></app-root>
</div>
</body>

-------------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>

<div class="collapse navbar-collapse" id="navbarSupportedContent">


<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link text-white" routerLink="/all">VIEW ALL </a>
</li>
<li class="nav-item">
<a class="nav-link text-white" routerLink="/create">REGISTER</a>
</li>
<li class="nav-item dropdown">
<a
class="nav-link dropdown-toggle text-white"
href="#"
role="button"
data-toggle="dropdown"
aria-expanded="false"
>
OPERATIONS
</a>
<div class="dropdown-menu">
<a class="dropdown-item" routerLink="/all">VIEW ALL</a>
<a class="dropdown-item" routerLink="/create">REGISTER</a>
</div>
</li>
</ul>
</div>
</nav>

<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/")

-> Entity/Model class


export class Student {
constructor(
public stdId: number,
public stdName: string,
public stdGen: string,
public stdCourse: string,
public stdAddr: string
) {}
}
---------------------------------------
-> student service (student.service.ts)
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { Student } from '../entities/student';

@Injectable({
providedIn: 'root',
})
export class StudentService {
baseUrl = 'http://localhost:9690/v1/api/student';

constructor(private http: HttpClient) {}

getAllStudents(): Observable<Student[]> {
return this.http.get<Student[]>(`${this.baseUrl}/all`);
}

createStudent(student: Student): Observable<any> {


return this.http.post(`${this.baseUrl}/create`, student, {
responseType: 'text',
});
}

deleteStudent(id: number): Observable<any> {


return this.http.delete(`${this.baseUrl}/remove/${id}`, {
responseType: 'text',
});
}

getOneStudent(id: number): Observable<Student> {


return this.http.get<Student>(`${this.baseUrl}/find/${id}`);
}

updateStudent(student: Student): Observable<any> {


return this.http.put(`${this.baseUrl}/modify`, student);
}
}

------------------------(View and Delete)--------------------------------


> student-list.component.ts

import { Component, OnInit } from '@angular/core';


import { Student } from 'src/app/entities/student';
import { StudentService } from 'src/app/services/student.service';

@Component({
selector: 'app-student-list',
templateUrl: './student-list.component.html',
styleUrls: ['./student-list.component.css'],
})
export class StudentListComponent implements OnInit {
students: Student[] = [];
message: any = '';

constructor(private service: StudentService) {}

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

===> student-list.component.html (View page)--------------


<h3 class="text-center">STUDENTS LIST PAGE</h3>
<table class="table table-hover">
<tr class="bg-info text-white">
<th>ID</th>
<th>NAME</th>
<th>GENDER</th>
<th>COURSE</th>
<th>ADDRESS</th>
<th>OPERATIONS</th>
</tr>
<tr *ngFor="let sob of students">
<td>{{ sob.stdId }}</td>
<td>{{ sob.stdName }}</td>
<td>{{ sob.stdGen }}</td>
<td>{{ sob.stdCourse }}</td>
<td>{{ sob.stdAddr }}</td>
<td>
<button
type="button"
class="btn btn-danger"
(click)="deleteStudent(sob.stdId)"
>
DELETE
</button>
&nbsp;&nbsp;
<button type="button" class="btn btn-warning">EDIT</button>
</td>
</tr>
</table>
<div class="text-center">
<strong>{{ message }}</strong>
</div>
========================Stage#2 END=========================
************************************************************

=======================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 = '';

constructor(private service: StudentService) {}

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

Angular Edit Operation

=> Generate a new component to show edit page


ng g c components/student-edit --skip-tests

=> In List Component TS File use Router to navigate to EditComponent


-------------------StudentListComponent.ts-----------
constructor(private service: StudentService, private router: Router) {}

editStudent(id: number) {
this.router.navigate(['/edit', id]);
}

=> At List HTML File , configure edit button(similer to delete)


<button
type="button"
class="btn btn-warning"
(click)="editStudent(sob.stdId)"
>

=> Configure in Router Array : app-routing.module.ts


{ path: 'edit/:id', component: StudentEditComponent },

======================================================================
Student Edit Page HTML Code:-

<h3 class="text-center">STUDENTS EDIT PAGE</h3>


<form (ngSubmit)="updateStudent()">
ID :
<input
type="text"
name="stdId"
id="stdId"
[(ngModel)]="student.stdId"
class="form-control"
readonly
/>
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">UPDATE STUDENT</button>
</form>
-------------------------------------------------------

Student Edit TS Code


import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Student } from 'src/app/entities/student';
import { StudentService } from 'src/app/services/student.service';

@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

*) open index.js file and add import


import 'bootstrap/dist/css/bootstrap.min.css';
import 'bootstrap/dist/js/bootstrap.min.js';
import 'bootstrap/dist/js/bootstrap.bundle.min.js';
=================================
---------- Install AXIOS-----------
npm add axios
---------- Install React Router-----------
npm install react-router-dom

=============code files==============================
1. HOC
import React from "react";
import { useNavigate } from "react-router-dom";

const withNavigateHook = (Component) => {


return (props) => {
const navigation = useNavigate();

return <Component navigation={navigation} {...props} />;


};
};

export default withNavigateHook;

2. List Component
import React, { Component } from "react";
import StudentService from "../services/StudentService";
import withNavigateHook from "./withNavigateHook";

class StudentListComponent extends Component {


constructor(props) {
super(props);
this.state = {
students: [],
message: "",
};
}

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>
&nbsp;
<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>
)}
</>
);
}
}

export default withNavigateHook(StudentListComponent);

3. Create Component
import React, { Component } from "react";
import StudentService from "../services/StudentService";
import withNavigateHook from "./withNavigateHook";

class StudentCreateComponent extends Component {


constructor(props) {
super(props);
this.state = {
stdName: "",
stdGen: "",
stdCourse: "",
stdAddr: "",
message: "",
};
}

handleChange(event) {
this.setState({ [event.target.name]: event.target.value });
}

saveStudent = (event) => {


event.preventDefault();
let student = {
stdName: this.state.stdName,
stdGen: this.state.stdGen,
stdCourse: this.state.stdCourse,
stdAddr: this.state.stdAddr,
};
StudentService.createStudent(student).then((response) => {
alert(response.data);
});
this.props.navigation("/all");
};
render() {
return (
<div>
<h3 className="text-center">STUDENTS REGISTER PAGE</h3>
<form>
NAME :
<input
type="text"
name="stdName"
id="stdName"
value={this.state.stdName}
className="form-control"
onChange={(event) => this.handleChange(event)}
/>
GENDER :
<input
type="radio"
name="stdGen"
id="stdGen"
value="Male"
onChange={(event) => this.handleChange(event)}
/>
Male
<input
type="radio"
name="stdGen"
id="stdGen"
value="Female"
onChange={(event) => this.handleChange(event)}
/>
Female
<br />
COURSE :
<select
name="stdCourse"
id="stdCourse"
onChange={(event) => this.handleChange(event)}
className="form-control"
>
<option value="">SELECT</option>
<option value="JAVA">JAVA</option>
<option value="DOT NET">DOT NET</option>
<option value="SALESFORCE">SALESFORCE</option>
<option value="DEVOPS">DEVOPS</option>
</select>
ADDRESS :
<textarea
name="stdAddr"
id="stdAddr"
onChange={(event) => this.handleChange(event)}
className="form-control"
></textarea>
<br />
<button
className="btn btn-success"
onClick={(event) => this.saveStudent(event)}
>
CREATE
</button>
</form>
{this.state.message && (
<div className="text-center">
<strong>{this.state.message}</strong>
</div>
)}
</div>
);
}
}

export default withNavigateHook(StudentCreateComponent);

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>

<div className="collapse navbar-collapse" id="navbarSupportedContent">


<ul className="navbar-nav mr-auto">
<li className="nav-item ">
<Link to="/all" className="nav-link text-white">
VIEW ALL
</Link>
</li>
<li className="nav-item">
<Link to="/add" className="nav-link text-white">
REGISRTER
</Link>
</li>
<li className="nav-item dropdown">
<a
className="nav-link dropdown-toggle text-white"
href="#"
role="button"
data-toggle="dropdown"
aria-expanded="false"
>
OPERATIONS
</a>
<div className="dropdown-menu">
<Link to="/all" className="nav-link">
VIEW ALL
</Link>
<Link to="/add" className="nav-link">
REGISRTER
</Link>
</div>
</li>
</ul>
</div>
</nav>
<Routes>
<Route path="/all" element={<StudentListComponent />}></Route>
<Route path="/add" element={<StudentCreateComponent />}></Route>
<Route path="/" element={<StudentListComponent />}></Route>
<Route path="*" element={<StudentListComponent />}></Route>
</Routes>
</Router>
);
}

export default NavBarComponent;

5. Service class
import axios from "axios";

const baseUrl = "http://localhost:9690/v1/api/student";

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

export default new StudentService();

6. App Component
import "./App.css";
import NavBarComponent from "./components/NavBarComponent";

function App() {
return (
<div className="container">
<NavBarComponent />
</div>
);
}

export default App;

====================================================================
At backend application: @CrossOrigin("http://localhost:3000/")

*) We can even provide multiple URLs for @CrossOrigin.


Ex:
@CrossOrigin({
"http://localhost:3000/",
"http://localhost:4200/"
})
Date : 02-12-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
*) AT Rest Controller class level:
@CrossOrigin({
"http://localhost:3000/",
"http://localhost:4200/"
})
-------------------------------------------------------------------
ReactJS using TypeScript:
https://www.typescriptlang.org/docs/handbook/react.html

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)

*) A Component is a logical part (or) one part of web page.

*) ReactJS : Two types components.


A. class component : Stateful components (Data/Dynamic data)
B. Functional component : Statless components (no Dynamic Data or no State)

*) React Hooks are a new addition in React 16.8.


They let you use state and other React features without writing a class.

*) in Functional component we do not use this keyword.


======================================================================
1. useState() : This is used to store State object (JSON/String..etc)
const [variable, setVariable] = useState(__);
Ex:
const [student, setStudent] = useState(initialFormState);
2. useNavigate(): This is part of routing. To move from one component to
another component use this.

const navigate = useNavigate();


Ex:
navigate("path")

3. useParams(): To read path parameters (Dynamic values from URL)


If URL contains n-path params we can read all of them even.

Name of param must be same as <Route> Config

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

//when id is modified allow setStudent to execute.

*) Try to use one/single component for both EDIT and REGISTER.

Q) What is the difference between Route path / and * in ReactJS?


A)
Default Home Page is indicated using /
<Route path="/" element={<StudentListComponent />}></Route>
If No Path is matched (for request URL)
<Route path="*" element={<NotFoundComponent />}></Route>
Date : 03-12-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
POSTMAN :
>> It is tool used to Test our application, by making HTTP Request.
>> Here, we need to enter detail manually
Method Type, URL, Headers, Body, Type..etc

-------------------------------------------------------------------------
Swagger : (Programmer one time configuration)

>> Open Source API used to document all Endpoint details.


ie Need not to enter details manually. Just enter data.
>> For this we need to code one time configuration
----------------------------------------------------------------------
Open API: (NO Configuration)
>> Open Source API used to document all Endpoint details.
ie Need not to enter details manually. Just enter data.
>> we need not to code any configuration

===Swagger Configuration Steps===================================


1. Add Two Dependencies, they are Swagger-configuration and Swagger-ui

springfox-swagger2
springfox-swagger-ui

Spring Boot 2.7.x


NullPointerException: Cannot invoke
"org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.toString()" because the
return value of
"springfox.documentation.spi.service.contexts.Orderings.patternsCondition(springfox.documentation
.RequestHandler)" is null

Add in properties file


spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER

Spring Boot 2.6.x (or before)


No Exception

http://localhost:9690/swagger-ui.html

.
-> Full Document(webpage) displayed at UI
Docket(DocumentationType.SWAGGER_2)

-> Find RestControllers from given basePackage


.select()
.apis(RequestHandlerSelectors.basePackage("com.app.raghu.rest"))

--> Starts with common path /v1/api/_________

.paths(PathSelectors.regex("/v1/api.*"))

-> URLs starts with / (must or not?)


.pathMapping("/")

-> Metadata to display at Document.


.apiInfo(apiInfo());

--------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>

2. Swagger Config class


package com.app.raghu.config;

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

private ApiInfo apiInfo() {


return new ApiInfo("STUDENT APP",
"SAMPLE APP",
"3.2GA",
"http://sample.com",
new Contact("RAGHU", "http://github.com/javabyraghu",
"[email protected]"),
"APACHE",
"http://apache.com",
Collections.emptyList());
}
}

3. Properties file
spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER

4. Run App and Enter URL:


http://localhost:9690/swagger-ui.html
===============================================================
OPEN API:
Step#1 Add Below Dependency
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.13</version>
</dependency>

Step#2
Annotation at Starter class:
@OpenAPIDefinition

Step#3 Enter URL:


http://localhost:9690/swagger-ui/index.html
Date : 06-12-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Connection Pooling

Pool : Group of Objects of sametype (one class type)


Ex: Student Pool (Student class Objects)
Connection Pool (Database Connections class objects)

*) SCP : String Constant Pool : All String Objects are stored.

Cache : Group of Objects of different types


(employeeobjs, productsobjs..etc)

*) Connection Pool : It is a group of Database Connection objects


created while starting application.

=> One Connection reads a Statement(Query) from Server, send to DB


executes it and finally returns response/output back to server.

=> If more no.of Statements(Query) comes from server to DB.


Then it will process one by one, which is time consuming.

=> In this case CP, reduces wait time by processing statements in parallel.

=> Spring Boot supports Vendors like ***HikariCP, TomcatCP, Apache-DBCP2.x


.etc...

=> 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>

=> Spring Boot has given all configurations to connection pool


using class: HikariConfig

=> We can provide our custom values for properties using keys with prefix
spring.datasource.hikari.<keyName>=<value>

# To provide custom connection pool name


spring.datasource.hikari.pool-name=HikariCP-Test
# Provide timeout for a connection request
spring.datasource.hikari.connection-timeout=10000
# Max Pool size
spring.datasource.hikari.maximum-pool-size=20
# Min No work/idle connections
spring.datasource.hikari.minimum-idle=15
# Check Connection by executing a query at startup
spring.datasource.hikari.connection-init-sql=select * from stdtab
# ENable Autocommit
spring.datasource.hikari.auto-commit=false
# How long idle connection need be kept..
spring.datasource.hikari.idle-timeout=5000
-----------------------------------------------------------------------
Full application.properties file:-
-----------------------------------
#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

#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)

*) Test applciation using code.


*) JUnit [Test F/w] and Mockito [Mocking F/w]
JUnit-5 is used to check our actual code working or not?
But it may have some dependencies which are un-implemented
those can be mocked using Mocking F/w Mockito-4.

Mocking can be done over - DB Connection, Server Setup, Request, Response,


Container Runtime, collection, class/object..etc
==============================================================
JUnit contains Test Methods, which are implemented using:
JUnit Annotations : @Test, @BeforeEach, @AfterEach, @Ignore,..etc
JUnit Assert API : assetEquals, assertTrue, assertNotNull
(assert -- expected)

** 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>

2. src/main/java (Application code)


package com.app.raghu;

public class MathService {

public int add(int a, int b) {


return a + b;
}

public boolean isEven(int a) {


return a % 2 == 0;
}
}

3. src/test/java (JUnit test case)


package com.app.raghu;

import static org.junit.jupiter.api.Assertions.assertEquals;


import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public class MathServiceTest {

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.

*) By using Mocking we can define dummy implementation to a method.


Sample code

when(methodCall()).thenReturn(output)
when(methodCall()).thenThrow(exceptionObj)

*) Mocking Environment is activated using


@ExtendWith(MockitoExtension.class)

----------SAMPLE CODE---------------------------------
*) src/main/java
package com.app.raghu;

import java.sql.SQLException;
import java.util.List;
public class Repository {

public List<String> getData() throws SQLException {


return null;
}
}
------------------
package com.app.raghu;

import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Service {

private Repository repo;

public Service(Repository repo) {


this.repo = repo;
}

public List<String> getDataByLen() {


try {
return repo.getData().stream()
.filter(d -> d.length() < 5)
.collect(Collectors.toList());
} catch (SQLException e) {
return Arrays.asList();
}

}
}

===src/test/java======================
package com.app.raghu;

import static org.junit.jupiter.api.Assertions.assertEquals;


import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.Mockito.when;

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;

//Activate JUnit with Mock


@ExtendWith(MockitoExtension.class)
public class ServiceTest {

// One dummy object is created by Mockito


@Mock
private Repository repository;

// it will find all dependencies and inject them (like Autowired)


@InjectMocks
private Service service;

@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 using JUnit


List<String> actual = service.getDataByLen();
assertNotNull(actual);
assertEquals(3, actual.size());
}

@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

Mockito 4.x: Mocking API / Create Supported Environment /


Dummy Objs, container, server, request..etc
==========================================================================
Spring Boot Rest - Unit Testing

*) Spring Boot provides by default all required dependencies(JARs)


for Unit testing using starter:

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

2. Test each Rest Method using Mock Request.


=> Here A Request is created of Type HttpServletRequest
by using Builder pattern with Mocking type.

=> 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");

*) To execute request we need container (ApplicationContext) for that


we use MockMvc Which is internally Mocked "webAppContextSetup"

======================================================================
*) under src/test/java , one default class is given , just modify that as

package com.app.raghu;

import static org.junit.jupiter.api.Assertions.assertEquals;


import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.fail;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

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

//2. EXECUTE IT AND READ RESULT(REQUEST + RESPONSE + EXCEPTION)


MvcResult result = mockMvc.perform(request).andReturn();

//3. READ RESPONSE FROM RESULT


MockHttpServletResponse response = result.getResponse();

//4. ASSERT RESULT USING JUNIT


assertEquals(HttpStatus.CREATED.value(), response.getStatus());
assertNotNull(response.getContentAsString());
if(! response.getContentAsString().contains("CREATED")) {
fail("STUDENT NOT CREATED!!");
}

//This is short format


@Test
@DisplayName("TESTING STUDENT SAVE OPERATIONS IN SHORT")
@Order(1)
public void testCreateStudentShort()
throws Exception
{

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

MvcResult: It is a Wrapper Type class object that holds details of


" Request + Response + Exception (if raised) "

*) Here, Request --> MockHttpServletRequestBuilder.


Response --> MockHttpServletResponseBuilder
Exception -> Throwable type.

*) Once we get Response after executing request, always result


-> http status
-> content-type
-> content-size
-> other ouput(messages, list empty or not?)

==================test class full code=========================


package com.app.raghu;

import static org.junit.jupiter.api.Assertions.assertEquals;


import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.fail;

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

// 2. EXECUTE IT AND READ RESULT(REQUEST + RESPONSE + EXCEPTION)


MvcResult result = mockMvc.perform(request).andReturn();

// 3. READ RESPONSE FROM RESULT


MockHttpServletResponse response = result.getResponse();

// 4. ASSERT RESULT USING JUNIT


assertEquals(HttpStatus.CREATED.value(), response.getStatus());
assertNotNull(response.getContentAsString());
if (!response.getContentAsString().contains("CREATED")) {
fail("STUDENT NOT CREATED!!");
}

// This is short format


/*
* @Test
*
* @DisplayName("TESTING STUDENT SAVE OPERATIONS IN SHORT")
*
* @Order(1) public void testCreateStudentShort() throws Exception {
*
* 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() );
*
*
*}
*/

@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\"}");

// 2. EXECUTE IT AND READ RESULT(REQUEST + RESPONSE + EXCEPTION)


MvcResult result = mockMvc.perform(request).andReturn();

// 3. READ RESPONSE FROM RESULT


MockHttpServletResponse response = result.getResponse();
// 4. ASSERT RESULT USING JUNIT
assertEquals(HttpStatus.OK.value(), response.getStatus());
assertNotNull(response.getContentAsString());
if (!response.getContentAsString().contains("UPDATED")) {
fail("STUDENT NOT UPDATED!!");
}

@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.

3 DBs are given by Spring Boot


1) H2
2) Apache Derby
3) HSQL(Hyper SQL)

*) These DBs are created when application started and destoryed


once application are stopped.

*) We need to choose H2 Dependency (Do not choose any other Mysql/Oracle..etc)


<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
*) NO Connection or Pooling configuration required.
(driver class, url, username..etc not required).
Those are all present in class : H2ConsoleProperties
and H2ConsoleAutoConfiguration
*) We can modify default by adding our custom properties.
Defaults are:
H2 console available at '/h2-console'.
Database available at 'jdbc:h2:mem:ccec3847-fe26-4651-bea5-d31209382c9d'

---application.properties--------
server.port=9090

spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
spring.datasource.url=jdbc:h2:mem:testdb
-------------------------------------

>> After starting app : URL http://localhost:9090/h2-console


>> Default ddl-auto is : create-drop (Create all tables when we start app
and destory them when we stop server)

==============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;

public interface BookRepository extends JpaRepository<Book, Integer>{

*) 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"
}

*) Enter URL: http://localhost:9090/h2-console


Modify JDBC URL as : jdbc:h2:mem:testdb
Date : 12-12-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Monolithic Application

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).

Application = Set of Services


Project = Set of Modules

ex: Amazon Application


Services = Search, Cart, Payment, Feedback..etc

Life Cycle:-
Plan -> Code -> Build -> Deploy -> Moniter

Q) is JDK Software is platform dependent or independent?


A) Dependent, for every OS JDK s/w is diff.
JDK for Linux, JDK for Windows, JDK for Mac are different.
Date : 13-12-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Q) What is down time of a Server/Project?
A)

Q) What is Blue Green deployment? k8s


A)

Ref:
https://www.atlassian.com/microservices/microservices-architecture/microservices-vs-monolith
Microservices

*) Monolithic Application: Creating Application as a single unit


[one deployable component]

1 Project = all modules together.

*) 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

Scalability : Done for Increasing performance of app.


1. Horizontal Scaling : Creating multiple server instances of same type
application (Run our project multiple times)
2. Vertical Scaling : Increasing the configuration of System
N/w , Storage, Processor, RAM...etc

Load Balancer :- Incase of Multiple instances exist (ie Horizontal Scaling )


for application then we need one Application Load Balancer
for our Cluster to handle/distribute request.

==============================================================
Advantages of a monolithic architecture:
1. Development When an application is built with one code base,
it is easier to develop.

2. Easy deployment One executable file makes deployment easier.

3. Performance In a centralized code base and repository,


one API can often perform the same function.

4. Simplified testing Since a monolithic application is a single,


centralized unit, end-to-end testing can be performed

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.

2. Scalability You can t scale individual components.

3. Reliability If there s an error in any module,


it could affect the entire application s availability.

Exception in one module may effect other modules to stop/in valid output
..etc

4. Barrier to technology adoption Any changes in the framework or


language affects the entire application, making changes often
expensive and time-consuming.
(It is not easy to add new modules as size of application grows slowly
and time consuming for development and deployment)

5. Lack of flexibility A monolith is constrained by the technologies already used in the monolith.
[Using different new techbologies/ enhancements are not easy]

6. Deployment A small change to a monolithic application


requires the redeployment of the entire monolith.
Date : 14-12-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Ref:
https://www.atlassian.com/microservices/microservices-architecture/microservices-vs-monolith

Microservices:-
One Big Application is implemented as small projects and connected finally
using Webservices.

Service: A Part/ Business Unit / Component of a Project that provides


set of operations as a one project.

Ex: OrderService, AuthenticationService, ProductService, PaymentService..etc

*) An independent Deployable component is called as Microservices.


> Parallel Development of independent services
> Parallel Deployment of independent services
> Parallel Scaling of independent services

---Advantages of microservices-------
[FAST development/deployment]
Agility – Promote agile ways of working with small teams that deploy frequently.

[Scale Easily without touching other Services]


Flexible scaling – If a microservice reaches its load capacity, new instances of that service can rapidly
be deployed to the accompanying cluster to help relieve pressure. We are now multi-tenanant and
stateless with customers spread across multiple instances. Now we can support much larger instance
sizes.

[Deploy in servers as independent]


Continuous deployment – We now have frequent and faster release cycles. Before we would push out
updates once a week and now we can do so about two to three times a day.

[Easy to add new features and test them easily]


Highly maintainable and testable – Teams can experiment with new features and roll back if
something doesn’t work. This makes it easier to update code and accelerates time-to-market for new
features. Plus, it is easy to isolate and fix faults and bugs in individual services.

[Deploy without stopping other services]


Independently deployable – Since microservices are individual units they allow for fast and easy
independent deployment of individual features.

[We can develop few services in other languages/technologies]


Technology flexibility – Microservice architectures allow teams the freedom to select the tools they
desire.

[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

Ansible-> deployment playbooks,


Terraform / AWS -> hosting infrastructure,
Docker/Kubernetes -- 1000 Instance- Docker
ELK -> monitoring tools, and more.

updates and interfaces.


Date : 17-12-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Spring Cloud (Microservices)

*) Microservices is a design/Theory, for this coding is "Spring Cloud".

*) Cloud Computing v/s Spring Cloud


Cloud Computing: Run Applications by taking services for rental
(PaaS, IaaS, SaaS) --Ex: AWS, MS-Azure, GCP..etc

Spring Cloud : Develop application using Microservices concept.

*) Netflix is Vendor who gave APIs (JARs) to implement Microservices design.

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

3. Config Server : To store all Microservices common properties


at a external place (Github) and connect with all MS# apps.

4. Communication Client : (RestTemplate)


Open Feign or Feign Client is used to make request from one MS# to
another MS# (It is also called as Client Side Load Balancer).

5. Admin Dashboard : Visual dashboard for all MS# which are registered
with eureka (Health, Beans, Info, cache details, ..etc)
It internall uses Actuator.

6. ELK : Elasticsearch Logstash Kibana :


To read .log file data and display at UI. So, that we can
search all Log details in easy way.

7. Distributed Tracking: (MS2-->MS4-->MS7-->MS4-->MS2)


Finding execution path of a request that has multiple MS# involved
(Which class/methods are executed, how much time taken?)

Tool: Zipkin Server, Sleuth

8. Continioues Data Flow (Message Queue): [Apache Kafka]


Producer sending data and consumer is reading data in continioues manner.

Ex: Swiggy Tracking, Ola/Uber cab status..etc

9. Circuite Breaker:
Avoid executing application for a period of time if app is throwing
exceptions in Continioues manner.

10. API Gateway : Entry-Exit point to MS# apps.


-> Dynamic Routing : Choose MS# based on Load Details
-> Load Balancer : Maintain Load Details based on serviceIds
-> Security : JWT(JSON Web Token), OAuth2.x
Date : 19-12-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Microservices : It is a Design, De-Coupled Architecture.
Independent Deployable Components.
One Big Application --> Small Apps and developed/Linked.

Spring Cloud : API given by Pivotal Team + Vendor(Netflix)


This is Next level app to Spring Boot.
It is used to develop apps using Microservices.

*) 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.

Here Register stores all MS# details, like:


ServiceName, InstanceId, IP, PORT, Load Details (no.of Instances..etc)

+----------------- EXAMPLE REGISTER -------------------------+


| serviceId InstanceId IP PORT LF |
+------------------------------------------------------------+
| CART-SER CART-SER-5410 192.168.0.1 8061 0/200 |
| CART-SER CART-SER-5411 192.168.0.2 8061 0/200 |
| CART-SER CART-SER-5412 192.168.0.3 8061 0/200 |
| PYMT-SER PYMT-SER-5412 192.168.1.4 8161 0/200 |
| PYMT-SER PYMT-SER-5412 192.168.1.5 8161 0/200 |
+------------------------------------------------------------+

LF = Load Factor = Current No.of Request / Max No.of Request

*) Above Register is a List<ServiceInstance>. Here one ServiceInstance


means one Line.

*) Spring Cloud + netflix, provided one Register Server "Eureka Server".


*) Every MS# application is implemented using Spring REST and also
with Eureka Client + Register=true/fetch=true
=========================================================================
TASK:#1
> Create one Eureka Server
> Define one MS# application
> Register with Eureka Server
=========================STEPS + CODE==================================
Name: SpringCloudEurekaServer
Dep : Eureka Server

> At main class: @EnableEurekaServer


> application.properties
# RECOMANDED PORT NUMBER
server.port=8761

# DISABLE SELF REGISTER


eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

----------------------MS# app---------------------
Name : SpringCloudCartService
Dep : Spring Web, Eureka Discovery Client

*) At main class: @EnableEurekaClient


*) application.properties
#PORT
server.port=8081

# ServiceId (app Name)


spring.application.name=CART-SERVICE

#Provide eureka location


eureka.client.service-url.defaultZone=http://localhost:8761/eureka

# Register with Eureka


eureka.client.register-with-eureka=true
# Enable Fetching other MS# Details
eureka.client.fetch-registry=true
==========================================================

*) 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.

5.*** If we do not provide eureka.client.register-with-eureka=false


at Eureka, It will do Self Register which is Memory waste.
Date : 20-12-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Microservices : Spring Cloud

Q) Why Spring Cloud is used?


A) To implement one application in java using Microservices design.

Q) How Spring Cloud is different from Spring Boot?


A) Spring Cloud is built on-top of Spring Boot.

Spring Boot mainly used for Webapps(Web MVC, REST), DATA JPA, Email,
Security, Configurations...etc

Spring Cloud : Register & Discovery Server, Config Server, Gateway..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.

Maven will allow only one <parent> tag.


To link with 2nd parent use BOM (Bill Of Materials) concepts.
ie using <dependencyManagement> tag to link next parent (like HAS-A
relation in java)

dependencyManagement = Using a Parent (another pom.xml) as a Link


[set of JARS possible] to our project.

======================================================================
Q) What is Instance ? and Why?
A) An Application running under server.
More instance gives services to multiple users in parallel.

Q) What is a Register and Discovery Server? Give Example?


How it is different from webserver(tomcat)?

A) Register : It will store all MS# instance details in ServiceInstance format

1 ServiceInstance = 1 ServiceId + 1 InstanceId + 1 IP + 1 PORT + 1 LF (data)

ServiceId = application-name
InstanceId = (Some Number/code/application-name:randome value)
IP/PORT = IP Address/ Port Number
LF = Load Factor

Discovery : It will support to get another MS# details from Register


to communicate with that MS#.

*) Register and Discovery Server example: Netflix Eureka Server,


Apache ZooKeeper.

*) Webservers are used to run .war files. (webapps)


Register and Discovery Server for MS# apps.

==================================================================
Q) How can we expose our MS# or Register ? How can we enable to get
other MS# data from Register?

A) In every MS# application , follow below steps

1. Add Spring Cloud Eureka Discovery Client Dependency (along with WEB)
2. At main class add: @EnableEurekaClient

3. At properties file provide below keys


eureka.client.service-url.defaultZone=http://localhost:8761/eureka
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true

*) Note: if we provide register-with-eureka=false, then we can not


communicate with that MS# (from ourside, or from another MS#)
============================================================
Q) In MS# apps, register-with-eureka=true key and fetch-registry=true
must be given?

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.

Q) Why do we need to provide


register-with-eureka=false and fetch-registry=false
at Eureka Server?

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#

The result of DiscoveryClient#getInstances(serviceId) is


List<ServiceInstance>

One ServiceInstance means one MS# Instance details (one line)


ServiceInstance = serviceId + instanceId + URI(HOST+PORT) + LF..etc

*) Here, if Client MS# is running only once, then result is List<SI>


with only one object(index#0)

From Index#0 we read SI(ServiceInstanec) and read URI (IP+PORT)


finally create URL by adding path (fixed always in code)

*) Pass the URL to restTemplate to make call to Consumer MS# app


and get response ResponseEntity<T>.

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) Can Eureka Server makes HTTP request to MS# application?


A) Never. Eureka Just stores details and provide if you want of MS#.

Q) What is ServiceInstance?
A) ServiceInstance means details of One MS# instance.
ServiceInstance = serviceId+ InstanceId + URI(IP/PORT) + ...

Q) What is the Diff b/w URI, URL, Protocol, ResourcePath?


A)
http://192.168.10.11:8086/myapp/employee/find/101

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

URL = Protocol + URI + ContextPath + ResourcePath

===Code=================================================================
3 projects
1. Eureka Server

Name : SpringCloudEurekaServer
Dep : Eureka Server

Main : @EnableEurekaServer

application.properties
# RECOMANDED PORT NUMBER
server.port=8761

# DISABLE SELF REGISTER


eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

*******************************************************************
2. CartService
Name : SpringCloudCartService
Dep : Spring Web, Eureka Discovery Client

Main: @EnableEurekaClient

--application.properties--
#PORT
server.port=8081

# ServiceId (app Name)


spring.application.name=CART-SERVICE

#Provide eureka location


eureka.client.service-url.defaultZone=http://localhost:8761/eureka

# Register with Eureka


eureka.client.register-with-eureka=true
# Enable Fetching other MS# Details
eureka.client.fetch-registry=true

--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

# ServiceId (app Name)


spring.application.name=ORDER-SERVICE

#Provide eureka location


eureka.client.service-url.defaultZone=http://localhost:8761/eureka

--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 {

//Impl class is : EurekaDiscoveryClient -- given by Netflix Eureka


@Autowired
private DiscoveryClient client;

public String getCartResponse() {


// Goto Eureka server with serviceId
List<ServiceInstance> list = client.getInstances("CART-SERVICE");

// read at index#0 ==> returns SI


ServiceInstance si = list.get(0);

// read URI
URI uri = si.getUri();

// add path ==> return URL


String url = uri + "/cart/info";

// use RestTemplate and call


RestTemplate rt = new RestTemplate();

//make HTTP Request and get response


ResponseEntity<String> response = rt.getForEntity(url, String.class);

//return response body


return response.getBody();
}
}

--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]*************************
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

1. If run same MS# application multiple times (at different servers)


then multiple instances are created.

2. To provider better/faster service to end-customers, multiple instances


are required.

3. In above case, if Consumer wants to read one instance using DiscoveryClient


(which has less load factor) that is not possible, Bcoz it returns
List<ServiceInstance> (all instances)

4. LoadBalancerClient(I) will get only one Instance from Eureka Server


that has less Load Factor (it internall follows round robin concept)

5.** If you want run your MS# application as multiple instances


then must provide : eureka.instance.instance-id=_________
(Any String type data)
-----------------------------------------------------------------------
===Code=================================================================
3 projects
1. Eureka Server

Name : SpringCloudEurekaServer
Dep : Eureka Server

Main : @EnableEurekaServer

application.properties
# RECOMANDED PORT NUMBER
server.port=8761

# DISABLE SELF REGISTER


eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

*******************************************************************
2. CartService
Name : SpringCloudCartService
Dep : Spring Web, Eureka Discovery Client
Main: @EnableEurekaClient

--application.properties--
#PORT
server.port=8081

# ServiceId (app Name)


spring.application.name=CART-SERVICE

#Provide eureka location


eureka.client.service-url.defaultZone=http://localhost:8761/eureka

# 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

# ServiceId (app Name)


spring.application.name=ORDER-SERVICE

#Provide eureka location


eureka.client.service-url.defaultZone=http://localhost:8761/eureka

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

public String getCartResponse() {


ServiceInstance si = client.choose("CART-SERVICE");
String url = si.getUri() + "/cart/info";
System.out.println("*********************** " + url +"
**********************");

RestTemplate rt = new RestTemplate();


ResponseEntity<String> response = rt.getForEntity(url, String.class);
return response.getBody();
}
}

--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) Why LoadBalancerClient is used?


A) To work with multiple instances of Producer MS# app
it is also called as Client Side Load Balancer.

Q) What it the old LoadBalancer Vendor name?


A) Ribbon. it is removed now.
New one is : Cloud Load Balancer

Q) How many Instances does it return for a single request from eureka?
A) Alway one ServiceInstance which has Less Load Factor

Q) Do we need RestTemplate also if we use LoadBalancerClient?


A) Yes RestTemplate is Required.
Bcoz LoadBalancerClient interacts with Eureka.
LoadBalancerClient will not make any HTTP Request to REST/MS# apps.
Date : 24-12-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Microservices Communication

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*********************[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)

5. Here, we need not to use any RestTemplate. No manual code for


LoadBalancer and Http calls.
************************************************************************
===Code=================================================================
3 projects
1. Eureka Server

Name : SpringCloudEurekaServer
Dep : Eureka Server

Main : @EnableEurekaServer

application.properties
# RECOMANDED PORT NUMBER
server.port=8761

# DISABLE SELF REGISTER


eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

*******************************************************************
2. CartService
Name : SpringCloudCartService
Dep : Spring Web, Eureka Discovery Client, Lombok

Main: @EnableEurekaClient

--application.properties--
#PORT
server.port=8081

# ServiceId (app Name)


spring.application.name=CART-SERVICE

#Provide eureka location


eureka.client.service-url.defaultZone=http://localhost:8761/eureka

# 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 {

private Integer cartId;


private String cartCode;
private Double cartCost;
}

--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

Main: @EnableEurekaClient, @EnableFeignClients

--application.properties--
#PORT
server.port=9091

# ServiceId (app Name)


spring.application.name=ORDER-SERVICE

#Provide eureka location


eureka.client.service-url.defaultZone=http://localhost:8761/eureka

--Spring Bean--------
package com.app.raghu.entity;

import lombok.Data;

@Data
public class Cart {

private Integer cartId;


private String cartCode;
private Double cartCost;
}

--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

--Stage@1-------Create Github Properties file-------------------


> Goto https://github.com/signup?source=login
> Fill Form and get Registered
[email protected]
Model@12034

> Click on Plus Symbol > Create Repository > Enter name
Ex: SpringCloudConfigServerEx
> Finish

> Creating new file > Enter name : application.properties


> with some key=vals
> Commit

GitLink: https://github.com/raghu2023sample/SpringCloudConfigServerEx.git
=====================================================================
--Stage@2---------Create Config Server Application--------------
Name : SpringCloudConfigServerEx
Dep : Config Server

> At main class: @EnableConfigServer


> application.properties
------------------
server.port=8888
spring.cloud.config.server.git.uri=https://github.com/raghu2023sample/
SpringCloudConfigServerEx.git
spring.cloud.config.server.git.username=raghu2023sample
spring.cloud.config.server.git.password=Model@12034
spring.cloud.config.server.git.default-label=main
--------------------------

> Run main class and Enter URL:


http://localhost:8888/actuator/refresh

===================================================================
--Stage@3---------Integrate Every MS# with Config server--------

1 Add Config Client Dependency


> Right click on Project (MS# app)
> Spring > add Starter > Config Client
> Next > select pom.xml checkbox > next > finish

2 Add Location of Server at MS# properties file

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

1. Add Actuator Dependency at MS#


> Right click on MS# Project > Spring > Add Starters > Choose Actuator
> Next > pom.xml checkbox > finish

2. Activate Actuator by adding one key=val in properties


management.endpoints.web.exposure.include=*

3. At RestController (or at main class)


@RefreshScope

4. Start all apps in order (Eureka, Config Server, MS# apps)


check: http://localhost:8082/cart/info

5. Modify value at Github and make POSTMAN Request


POST http://localhost:8082/actuator/refresh [SEND]

check: http://localhost:8082/cart/info

*) Above POST call should be implemented using RestTemplate with one


Scheduler Service that gets latest data always.

==Ex========================================
Name: SpringCloudSchedulerService
Dep : Web

application.properties
server.port=9601

> at main class: @EnableScheduling


--Scheduler code--
package com.app.raghu.scheduler;

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 {

@Scheduled(cron = "10 * * * * *")


public void fetch() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>("{}", headers);

RestTemplate rt = new RestTemplate();


String output = rt.postForEntity(
"http://localhost:8082/actuator/refresh", entity, String.class)
.getBody();
System.out.println(output);
}
}
===============================================================
*) ConfigServerConfigDataLoader is given by Spring Cloud Config Client
that gets latest key=val from Config Server. It internally fetch
the data from Environment(I) using PropertySource process.

*) If a key is present at MS# app and Github(Config Server)


then priority is given to Config server properties file key=val only.
ie our MS# Properties are overriden.

======================================================================
Date : 28-12-2022
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Plan -> Document -> Development -> Build -> Test -> Release -> Moniter

We are having different monitering tools like:


1. Admin Server (+Actuator)
2. Zipkin and Slueth

These are tools used to know the current status of applications/MS# running

*) Actuator : Set of Production Ready Endpoints.


It gives some pre-defined services which are commonly used in Production
Environment for every MS# apps. Like: Health Checking, Beans detaiks,
mapping inforation(URL,HttpMethods), cache, heap, thread dumps..etc

=> If we use only 'Actuator' that is manual process of using/checking


services. We should also Integrate Admin Server to have GUI based
checking.

=======Steps to activate Actuator services=========================


S#1 Add Actuator Dependency in MS#
> Right click > Add Starter > Actuator > Next > pom.xml checkbox
> next > finish

pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

S#2 Enable Services


management.endpoints.web.exposure.include=*
#management.endpoints.web.exposure.include=health,beans,env

S#3 Enter URL : http://IP:PORT/actuator

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)

2. Enter service URL to check their details


http://localhost:8082/actuator/beans
http://localhost:8082/actuator/env

======================================================================
Spring Cloud Adminserver

It is a central server that is used to Moniter Actuator Results of


Every MS# which is connected using Admin Client and ADMIN URL.

*) MS# will connect to Admin Server using Admin Client.


*) Actuator must be enabled at every MS# then only Admin Client
can read its information.

===Coding Steps=============================
1. Admin Server
Name : SpringCloudAdminServer
Dep : Admin Server

> At main class: @EnableAdminServer


> application.properties
server.port=9999

2. At MS#
*) Add Two Dependencies : Actuator, Admin Client

*) At MS# Properties file


#Activate Actuator
management.endpoints.web.exposure.include=*

#Connect with Admin Server


spring.boot.admin.client.url=http://localhost:9999

--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

Microservices (Design) - Spring Cloud (Programming)

1. Register and Discovery Server -- Eureka server


-> Supports Storing MS# instance details and communication
using clients(DiscoveryClient, LoadBalancerClient, FeignClient)

2. Config Server -- Github + Config


-> Common key=val of multiple MS# kept at External Location.
-> Each MS# reading this using Config Client Dependency.

3. Admin Server + Actuator


-> Moniter service to find details of MS# like
health, instances , cache, beans, environment..etc

4. MS# implemented using Spring REST.

========================================================================
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/

Message Queues (MQs)

*) The continoues data flow between two systems. Producer will send data
and consumer will read by using a connector/mediator ie 'Message Broker'

*) Client-Server applications works using HTTP protocl.


There client has to make request then server will process it and
gives response back to client.

*) But here, one time connection between producer-consumer is made using


Message broker, then continioues data flow is done. Consumer need not
to make request again and again. one time connection is fine.

*)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

*) MQs concept uses TCP protocol to exchange data.


========================================================================
1. Basic MQs (single broker - No LoadBalancer)
JMS : Java Message Service / Apache ActiveMQ

2. Advanced MQs (Multi Broker - LoadBalancer)


Apache Kafka***

*) One MOM (Message Oriented Middleware) is used to connect two systems


[Producer and Consumer]

*) MOM s/w contains destination, it is a memory that holds messages


given by Producer and sent to Consumer.
*) Here, Both Producer and Consumer systems are connected using
one common destination only. ie Destination name given at consumer
must match with destination name given at producer.

*) There is no direct connection is created between producer and consumer


ie NO IP/PORT details shared.

*) There are two types of communications. Given as:


1. Peer-To-Peer Communication [P2P]
If one message is given to one Consumer, then it is called as P2P.
In this case Destination type is known as : Queue.

2. Publish-Subscribe Communication [Pub/Sub]


If one message is given to Multiple Consumers (cloned copied)
then it is called as Pub/Sub.

In this case Destination type is known as : Topic.

*)Note:
1. There can be multiple topics, queues are created with unique names.
2. Both P2P and Pub/Sub are used in realtime.

==========Apache ActiveMQ setup====================================


1. Download
https://activemq.apache.org/components/classic/download/

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

#Communication Type [P2P]


spring.jms.pub-sub-domain=false

#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;

public void sendMessage(String message) {


jt.send(destination, session -> session.createTextMessage(message));
System.out.println("MESSAGE SENT FROM PRODUCER " + message);
}
}
-----------------------------
*) Runner class
package com.app.raghu.runner;

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;

//public void run(String... args) throws Exception {

@Scheduled(cron = "*/10 * * * * *")


public void sendMsgTest() throws Exception {
service.sendMessage("HELLO "+ new Date());
}

*) At main class: @EnableScheduling

===================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

#Communication Type [P2P]


spring.jms.pub-sub-domain=false
#Destination name
my.app.desti-name=my-q-abc1
---------------------------
*) Consumer Service
package com.app.raghu.service;

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]

3rd Party Apache - ActiveMQ 5.x API [org.apache.activemq package]

2nd Party Programmer - Application

*) Set of interfaces (and few classes) are given by Sun/Oracle for


Message Queues using JMS API [Java Message Service]

Ex Interface names: Session, Message

*) For these interfaces Implementation is given by Apache vendor


with API name : ActiveMQ 5.x

Ex Impl class names: ActiveMQSession, ActiveMQTextMessage

*) Spring boot JMS has given one functional interface

MessageCreator(I)
createMessage(Session) : Message

Above interface contains one method createMessage() that takes


session as input and return Message as output.

*) 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

8. We have to Just call interface methods and pass our message.


either using Lambda Expression or using Anonymous Inner class.
session -> session.createTextMessage(message)

=========core java style code================


interface C{}
interface A{
C m1(String s);
}
------
class D implements C{
D(String s) {}
}
class B implements A{
C m1(String s) {
return new D(s);
}
}
--------
A oa = new B();
------------
C oc = oa.m1("Our Message");
Date : 06-01-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Kafka:
https://kafka.apache.org/quickstart

MQs - Message Queues

*) Session(I) is given by Sun/Oracle, this is used to make connection


and create Message to send data to Consumer.

-> interface is given,


1. Write Subclass (or Impl class) and create object
2. Anonymous Inner class [MAM]

new interfaceName() {
//override methods
}

3. If it is FI(Functional interface), [SAM]


Define Lambda Expression

==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

P2P Communication : If one Message is sent to one Consumer


Destination type is : Queue.

Publish-Subscribe [Pub/Sub] Communication:


if one Message is sent to multiple consumers. Destination type : Topic.

*) In Producer and Consumer applications we need to set one Property


spring.jms.pub-sub-domain as true. Default is false.

=> false means P2P communication, true means Pub/sub.


=> Just define multiple consumers and set spring.jms.pub-sub-domain=true.
=> Cloned Copies of Actual Message is sent to multiple consumers.
=> Make Sure, all destination names (Producer and Consumer apps)
must be matching.

Q) What if we delete topic from MQ Broker?


A) A new topic with same name is created. But old data will be removed.
It is not a recomanded approch.

Q) What if we stop one consumer and start from some time?


In case of P2P and Pub/Sub?

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

Input x Consumers = Output


5 x0 = 0 (data lost)
2 x2 = 4 (delivered)

Q) Does ActiveMQ supports LoadBalancing?


What if MOM S/w ActiveMQ is down?

A) ActiveMQ comes with single instance (No LoadBalance)


if it is down data lose may occure.

=====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

*) It is a Open Source API used to connect multiple applications to


send data (Message Queue)

*) Multi-Broker concept : it contains multiple brokers (Cluster)


to send data to multiple consumers.

[ActiveMQ - Single broker].

*) Scaling/Load Balancing can be done in Cluster.


*) Protocol independent (uses app protocol).

*) Kafka supports Pub/Sub Model only. No P2P. To send data to one consumer
use only Pub/Sub.

*) Full Kafka S/w is called as EcoSystem. This system contains mainly


3 parts. They are:

1. Zoo Keeper : Controls entire system.


2. Kafka Cluster : Group of Message Brokers(old version: min 3, new version: min 1)
3. Topics : Memory that stores data in partitions

*) Data is exchanged in Serilized format (String/JSON/XML Data)


*) Producer and Consumer both are connected using TopicName.
*) By using KafkaTemplate<K,V> producer app will send data to Kafka.
K = TopicName and V = Data
and @KafkaListener(K) is used to read data at consumer app.

*) Topics is a memory that holds data in packets formats [data blocks].


Those are identified using index numbers starts from zero [offset]

*) MR : Messsage Replica creates cloned copies of actual data to send


it to consumer.

*) ZooKeeper controls Eco-System like, create/manage topic,


allocate a broker to consumer, increase cluster size..etc

==========================================================================
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

*) Starts on Port : 2181

==============================================================
2. Start Kafka Server
[Windows]
.\bin\windows\kafka-server-start.bat .\config\server.properties

[Linux/MacOS]
.\bin\kafka-server-start.sh .\config\server.properties

*) Starts on port : 9092


================================================================
3. Create one topic

.\bin\windows\kafka-topics.bat --create --topic myabc --bootstrap-server localhost:9092

4. Start Producer Console

.\bin\windows\kafka-console-producer.bat --topic myabc --bootstrap-server localhost:9092

5. Start Consumer Console

.\bin\windows\kafka-console-consumer.bat --topic myabc --bootstrap-server localhost:9092


.\bin\windows\kafka-console-consumer.bat --topic myabc --from-beginning --bootstrap-server
localhost:9092

*) Press ctrl+C to stop (execute in below order)


Consumer > Producer > Kafka server > ZooKeeper
Date : 11-01-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
*) Kafka is Open Source and MQ S/w
*) Implemented by Apache
*) Uses LoadBalancer for Cluster (Multiple Message Broker)
*) Uses our application protocol
*) Kafka Supports only Pub/Sub Model (Topics).
Even if we want to send message to one consumer use Topic only.
*) Kafka accepts only Serialized data for partitions.
*) Partitions contains index number [offset]

*) KafkaTemplate<K,V> is used at Producer application to send data


to Kafka S/w

*) In case of non-Spring Boot application(Java app)


Ref this:
https://docs.spring.io/spring-kafka/reference/html/#with-java-configuration-no-spring-boot

*) Spring boot supports integration with kafka, we need to use JARs

<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>

*) It gives auto-configuration for KafkaTemplate<K,V> and @KafkaListener


*) Both Producer and Consumer are connected using TopicName.

@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

*) We need to add Kafka API using Spring Boot in pom.xml


<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>

*) EcoSystem creates a connection with Producer application


(by taking some properties) and supports sending data from producer
to EcoSystem using KafkaTemplate<K,V> class.

*) If consumer also connected with EcoSystem, then one Message Broker


is allocated to read data from TopicName using Message Replica(creates
one copy of actual message)

4 Consumers --> 1 Group --> Message Broker --> MR(4 copies)


@KafkaListener takes topicName and groupId to read data from EcoSystem.

*) Im using RestController and MessageStore additionally to send data


and view output.

======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;

public interface StockInfoRepository extends JpaRepository<StockInfo, Integer> {

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

public class JsonUtil {

public static StockInfo convertToObj(String message) {


try {
return new ObjectMapper().readValue(message, StockInfo.class);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}

public static String convertToString(StockInfo si) {


try {
return new ObjectMapper().writeValueAsString(si);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}

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;

public void add(String message) {


//JSON TO Object
StockInfo si = JsonUtil.convertToObj(message);
repo.save(si);
}
public List<StockInfo> getAll() {
return repo.findAll();
}

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;

@KafkaListener(topics = "${my.topic.name}",groupId = "abcd")


public void readMessage(String message) {
log.info("MESSAGE AT CONSUMER : {}", message);
store.add(message);
}
}

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

//call producer service


service.sendMessage(message);
return "SENT";
}

@GetMapping("/all")
public List<StockInfo> fetchAll() {
return store.getAll();
}

=======execution order==========================
1. run zookeeper
.\bin\windows\zookeeper-server-start.bat .\config\zookeeper.properties

2. run kafka server


.\bin\windows\kafka-server-start.bat .\config\server.properties

3. run your app

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;

public class Test {

//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

ex: group=abc, consumers=5 , topicName=TEST-A


MessageBroker-5 is allocated, MR-5 copies of actual message from TEST-A

======================================================================
*) When ever KafkaTemplate calls send method then Kafka API creates one object
ProducerRecord (C)

Internal code: Data --> Serialized


ProducerRecord<K, V> producerRecord = new ProducerRecord<>(topic, data);

*) @KafkListener that reads data from given topicName into ConsumerRecord(C)

//Data -> Deserialized


ConsumerRecord<K,V> consumerRecord = new ConsumerRecord<>(topic,data);

*) 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")

*) Spring with Kafka uses MessagingMessageListenerAdapter(C)


which is a Listener class that reads data from Kafka broker and
converts data.

*) 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.

=> Expose One IP/PORT


=> Single Entry and exit
=> Load Balancer
=> Connected with consumer apps (Angular/ReactJS/3rd Party)
=> Routing Table (Which request --> Where to Go)

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.

=> There may be multiple MS# apps running as multiple Instances


=> All these details are stored at Eureka Server
=> Eureka Server is a Register (Store data).
It never makes any HTTP call to any MS#
=> We can not expose all MS# IP and PORTs to client machine/app.
We should give only one IP and PORT ie Gateway IP and PORT.

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)

Dynamic Routing | Dynamic Dispatching : Routing + Load Balancing.

*) Router needs Input as Routing table which is configured by Developers


*) Predicate compares Request Path with Routertable path if matching
returns true means select MS# serviceId and goto eureka.

*) Pre-Filter(optional), if exist Modify the request before sending to MS# app.


Post-Filter(optional), if exist Modify the Response before sending to Client.

*) Gateway also one type of MS#, It needs to be register with Eureka.


It uses Porxy client (Feign) generated at Gateway, to make call to MS#.
===========================================================================
*) Spring Cloud API Gateway Routing(or Config) can be defined in two ways
1. YAML/Properties file
2. ***Java based Config

---EXAMPLE ROUTING TABLE ------------------


PATH URI
/order/** lb://ORDER-SERVICE

/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"

===Example Java Config=========================================


Dep : Gateway, Eureka Discovery Client

1. Config class for Routing table

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 {

//use lb://ServiceId for multiple instance of MS#


//use http://IP:PORT for single instance of MS#
@Bean
public RouteLocator configRoutes(RouteLocatorBuilder builder) {

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

# Register with eureka


eureka.client.service-url.defaultZone=http://localhost:8761/eureka
Date : 20-01-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Spring Cloud : API Gateway

1. Routing : Request --> MS# using Eureka


2. Loadbalancing : Choose one Instance has less LF (Round Robin)
3. Filters : Modify Request/Response

*) Router is a pre-defined component that taking Routing table data.


Routing table must be configured by Programmer.

Routing table = PATH + URI(serviceId/IP:PORT/HOSTNAME)

---------------------------------------------------------
ID PATH URI
---------------------------------------------------------
CID /cart/** lb://CART-SERVICE
OID /order/** lb://ORDER-SERVICE
---------------------------------------------------------

=> Every Routing table contains List<Route>


=> 1 route contains = 1 id + 1 path + 1 uri + multiple filters
1 MS = 1 route

=> Eureka gives ServiceInstance(serviceId,InstanceId, IP, PORT, LF)

=> If a MS# which is not configured at ApiGateway can never be


accessed from outside world.

Step#1 Define one Application for ApiGateway with 2 dependencies


a. Spring Cloud Gateway
b. Eureka Discovery Client

Step#2 Must be Registed with Eureka Server

--application.properties---
server.port=80
#server.port=9600

spring.application.name=API-GATEWAY

# Register with eureka


eureka.client.service-url.defaultZone=http://localhost:8761/eureka

Step#3 Define Java Configuration for Routing Table configuration


RouteLocator stores List<Route> / Flux<Route>
(Reactive Programming: Mono-1, Flux-n objects)
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 {

@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

2. MS# apps (Cart, Order) run multiple times


Cart MS# - port - 8081, 8082, 8084 (3 times started)
Order MS#- 9091,9092,9094 (3 times)

3. Api Gateway - start once


Enter URL:
http://192.168.0.3:80/cart/find/101
http://192.168.0.3:80/order/fetch/33

Here IP and PORT of API GATEWAY: 192.168.0.3:80

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

Spring Cloud : API Gateway

DSA: https://github.com/javabyraghu/DataStructuresAndAlgorithms

Filters:-
To Modify existed request/response data at API Gateway level
we use filters.

*) Here we have two types:


1. Pre-Filter : That adds/modify data at Request
2. Post-Filter: That adds/modify data at Response

Inside routing config we can provide headers to request like:


.filters(f->
f.addRequestHeader("MyToken", "Basic "+UUID.randomUUID().toString())
.addResponseHeader("Service Mode", "Active")
)

==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()

.route("cartId", r -> r.path("/cart/**")


.filters(f->
f.addRequestHeader("MyToken", "Basic
"+UUID.randomUUID().toString())
.addResponseHeader("Service-Mode", "Active")
)

.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

2. MS# apps (Cart, Order) run multiple times


Cart MS# - port - 8081, 8082, 8084 (3 times started)
Order MS#- 9091,9092,9094 (3 times)

3. Api Gateway - start once


Enter URL:
http://192.168.0.2/cart/info

Here IP and PORT of API GATEWAY: 192.168.0.2:80

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]

=> For one request, there can be multiple MS# executed.


Example Flow:
Req#1 --> API Gateway --> Eureka -> Gateway --> MS#1 --> MS#2 -->MS#3
->MS#2-->MS#1-> Gateway --> Resp#1

=> Distributed Tracing concept is used to find out,


1. No of MS# called
2. Execution Path (method->Method)
3. Time taken for exact service and all services

=> It is type of debugging (Flow Debug).


=> Spring Cloud API has given : Sleuth and Zipkin to handle
"Distributed Tracing"

=> Sleuth : Generates details like Tracing Info/Execution Path/


Execution Time.
=> Zipkin server will store and display Sleuth Result.

*) Eureka Server : Will store Instance details (Not request details)


How Many MS#? Instance count? LF ? IP / PORT ?

*) Zipkin Server:
How many Request processed?
Execution Path?
How Many MS# called?
How much time taken?

==========Download and test Zipkin Server=========================


Goto :
https://repo1.maven.org/maven2/io/zipkin/java/zipkin-server/2.12.9/

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)

*) We need to add 2 dependencies in MS# application

<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

*) Define Multiple MS# applications using


+ Web, Zipkin and Sleuth Dependencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>

We can even add : Admin Client, Eureka Discovery Client, Config Client..etc

*) Define one config file


package com.app.raghu.config;

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 {

private static final Logger log = LoggerFactory.getLogger(ProcessARestController.class);

@Autowired
private RestTemplate rt;
@GetMapping("/showA")
public String showMsg() {
log.info("WE ARE AT A SERVICE...");

String resp = rt.getForEntity("http://localhost:8082/showB", String.class).getBody();

return "FROM A.."+resp;


}
}

*) Repeate same for multiple MS# applications


ServiceB, ServiceC examples.

*) Sleuth and Zipkin stores data using Logs and format looks like
[ServiceName, TraceId, spanId, ExportFlag]

TraceId: Id generated for one entire request flow


spanId : Id generated for one MS# request flow.
parentId: Previous MS# spanId is current MS# parentId

*) Run apps in order and enter URL


http://localhost:8081/showA

*) Check at Zipkin Server , click on Trace.


Date : 27-01-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Spring Boot Reactive Programming

*) Spring Boot WEB (MVC and REST)


starter: spring-boot-starter-web
@Controller, @RestController, @RequestMapping, @GetMapping...
@ModelAttribute, Model ..etc

*) Server: *Tomcat, Undertow, Jetty..etc


*) Tomcat is the default server, that allocates one Thread for one Request
which will process request and returns response.

*) By default every Thread allocated to process is "BLOCKING MODEL".


ie Thread if is making NIO call, then it will be idel, it will not
process any other request meanwhile.

*) NON BLOCKING MODE says do not keep any thread idel.


Use it for another request processing if is waiting for NIO call output.
once we get NIO output allocate same thread or different one for
processing response.

=> 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

Ouptput: Mono<T> (0/1), Flux<T> (0..n) output.

=> 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)

6. To start mongodb client


cmd: mongo

7. Enter commands like:


> show dbs;
> use bootdb;
> show collections;
> db.student.insert({"sid":10,"sname":"AJAY","sfee":300.0});
> db.student.find();
> db.student.find().pretty();

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]

Step#1 Downloaded and Installed MongoDB


cmd> mongod
cmd> mongo

Step#2 Create a Spring Boot Application


Name : SpringBootReactiveProducerEx
Dep : Reactive Web, Reactive MongoDB, Lombok, Devtools

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;

public interface StudentRepository


extends ReactiveMongoRepository<Student, String>{

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;

public Mono<Student> save(Student student) {


return repo.save(student);
}

public Mono<Student> getOne(String id) {


return repo.findById(id).switchIfEmpty(Mono.empty());
}

public Flux<Student> findAll() {


return repo.findAll().switchIfEmpty(Flux.empty());
}

public Mono<Void> delete(String id) {


return repo.deleteById(id);
}
}

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

#Database connection details


spring.data.mongodb.host=localhost
spring.data.mongodb.database=bootdb
spring.data.mongodb.port=27017
#spring.data.mongodb.username=
#spring.data.mongodb.password=

****************************************************
> first run cmd "mongod" then start application
> Test using POSTMAN

****************************************************

Note: Here PK type is String by default (we can change it)


It generates PK as HexaDecimal value (UUID internally)
ex:
"id": "63d48120435d697460977319"

*) PK Field name is taken as _id in Database


*) If we find _class property then it indicates data came from
external sources (like Java, .Net ..etc)
*) If we use any other DataType for PK in coding then value will never
be generated. We need to pass manual value.

3. Consumer: [ Spring Webflux - WebClient ]


Date : 30-01-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Reactive Programming

1. NoSQL DB : MongoDB (Reactive API)


2. Application: Spring Webflux (Reactive API)
Annotations are similer to REST API
Output: Mono (0/1) , Flux(0..n)

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("_________"),

Q) Can we pass our own PK value to MongoDB?


A) YES. Then it is not a generated value then it will show direct value
without ObjectId.
ex: "_id" : "AA1100"

===code=============
Create a Spring Boot Application
Name : SpringBootReactiveProducerEx
Dep : Reactive Web, Reactive MongoDB, Lombok, Devtools

1. application.properties
#Server Port
server.port=9090

#Database connection details


spring.data.mongodb.host=localhost
spring.data.mongodb.database=bootdb
spring.data.mongodb.port=27017
#spring.data.mongodb.username=
#spring.data.mongodb.password=

2. Entity class / Collection class


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

3. Repository interface
package com.app.raghu.repo;

import org.springframework.data.mongodb.repository.ReactiveMongoRepository;

import com.app.raghu.entity.Student;

public interface StudentRepository


extends ReactiveMongoRepository<Student, String>{

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;

public Mono<Student> save(Student student) {


return repo.save(student);
}
public Mono<Student> getOne(String id) {
return repo.findById(id).switchIfEmpty(Mono.empty());
}

public Flux<Student> findAll() {


return repo.findAll().switchIfEmpty(Flux.empty());
}

public Mono<Void> delete(String id) {


return repo.deleteById(id);
}
}

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]

1. RestTemplate : It is a class, supports HTTP Protocol


connects with any language Producer application
Supported only Synchronous Communication
2. LoadBalancerClient/ Open Feign : Supported for MS# application communication

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

=> Here we need to use Spring Boot Reactive API (Webflux)


=> Make sure port numbers are not same compared to Producer application

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 {

public void run(String... args) throws Exception {


//1. Create WebClient object using base URL
WebClient client = WebClient.create("http://localhost:9090/student");

//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

System.out.println("FROM CONSUMER ---->");


//access result
result.subscribe(System.out::println);
*/

/*
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 {

private String id;


private String name;
private Double fee;
}
Date : 01-02-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
JAAS : Java Authentication and Authorization
[Security]

*) Authentication : Validating User Login details : username, password


*) Authorization : Validating User Role to access a service/resources

Ex: BankApplication
URLs: /home, /login, /checkBal, /logout, /approveLoan, /openFD ..etc

User: AJAY/AJAY Role: Customer


User: SAM/SAM Role: Manager
User: SYED/SYED Role: Clerk
..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. Authenticated: A URL/Path can be accessed only after login


[any role is valid]

ex: Show Logout Link, First Login , /chagePwd, /logout ..etc

3. hasAuthority: Login must and Valid Role is required

ex: /approveLoan => Login and Role : Manager


/checkBal => Login and Role : Customer, Manager

=> Role - String, Authority(I) - SimpleGrantedAuthority(C)


--------------------------------------------------------------
Authentication Type(3):-
1. InMemoryAuthentication
=> Storing user details inside RAM / Temp Memory.
=> This is only for Testing purpose. (NO database is used)
=> Not Recomanded in production.

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)

3.*** ORM Authentication/UserDetailsService


=> ORM means uses Data JPA, No SQL Query
=> It stores data in Database Table and converts into Object format
when it is required.

====================================================================
*) PasswordEncoder:- It is not recomanded to store plain text password
inside database, better convert into unreadable format ie encoding.

There is no decode method is given by Spring boot.


If we enter Pwd from Login page then that is encoded and compared
with DB encoded password, if matched then goto Home Page...etc

===coding================================================================
1. We need to define only one class (additionally) for security.
ie SecurityConfig (any equal name) called as One Configuration class.

2. This class contains two methods mainly.


a. Authentication : InMemory/JDBC/UserDetailsService
b. Authorization : permitAll/autnehticated... Login Form + Logout Link

3. ** In Spring Boot 2.6 or before version SecurityConfig class must


extends one class "WebSecurityConfigurerAdapter".
but in new Version ie Spring Boot 2.7 or later it is not required.

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

*) In our application we need to add one Dependency: Spring Security


in pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

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

Example code sampels For Authorization:-


1. Accessed by every one : /welcome

.antMatchers("/welcome").permitAll()

2. Access URL only after Login : /profile

.antMatchers("/profile").authenticated()

3. Access URL after login having role ADMIN : /mydata

.antMatchers("/mydata").hasAuthority("ADMIN")

4. Access URL after login having role MANAGER or CUSTOMER: /checkBal

.antMatchers("/checkBal").hasAnyAuthority("MANAGER", "CUSTOMER")

5. To indicates remaining URLs (which are not configured like above)

.anyRequest().permitAll()
[or]
.anyRequest().authenticated()
[or]
.anyRequest().hasAuthority("ADMIN")

======================================================================
Spring Boot Security # InMemoryAuthentication
======================================================================

.antMatchers("/home","/login").permitAll()
.antMatchers("/hello").authenticated()

*) Create one user in RAM/Temp Memory (not in DB)

(UserDetails)
username : sam
password : sam (No password encoder)
roles : ADMIN

UserDetailsService => InMemoryUserDetailsManager(userDetails)


*) Spring Security has given code for
1. User Validation on Login
2. Session Management
3. Session Invation and Logout logic

==============Simple Security Application====================


Name : SpringSecurityInMemoryEx
Dep : Spring Web, Spring Security, Devtools, Thymeleaf

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() {

UserDetails user = User.withDefaultPasswordEncoder()


.username("sam").password("sam").roles("ADMIN")
.build();

UserDetails user2 = User.withDefaultPasswordEncoder()


.username("ram").password("ram").roles("CUSTOMER")
.build();

return new InMemoryUserDetailsManager(user,user2);


}

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

<p>Click <a th:href="@{/hello}">here</a> to see a greeting.</p>


</body>
</html>

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

Spring Boot Security - using JDBC

*) InMemoryAuthentication : Recomanded to use in Dev Environment only.


It is for testing purpose. Do not use in Production.

*) To store/fetch user details using Database, we use JDBC API.


*) Here we are going to use PasswordEncoder to add user data.

Two tables are created to store user data


users (username, password, enabled)
authorities(username, authority)

*) Password encoder is recomanded to use to encode and store passwords


in database tables.
=================sample -- Test class===================
package com.app.raghu;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

public class Test {

public static void main(String[] args) {


BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String pwd = encoder.encode("ram");
System.out.println(pwd);
}
}
======================================================================

Database Setup:
create table users(
username varchar(50) not null primary key,
password varchar(500) not null,
enabled boolean not null);

create table authorities (


username varchar(50) not null,
authority varchar(50) not null,
constraint fk_authorities_users foreign key(username)
references users(username));

create unique index ix_auth_username on authorities (username,authority);


==MySQL Console=================================
mysql> drop database boot6am;
Query OK, 5 rows affected (0.12 sec)

mysql> create database boot6am;


Query OK, 1 row affected (0.01 sec)

mysql> use boot6am;


Database changed
mysql> create table users(
-> username varchar(50) not null primary key,
-> password varchar(500) not null,
-> enabled boolean not null);
Query OK, 0 rows affected (0.04 sec)

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 {

//EVERY ONCE CAN ACCESS


// .antMatchers("/home").permitAll
@GetMapping({"/home","/"})
public String showHome() {
return "home";
}

//ONLY AFTER LOGIN


// .antMatchers("/hello").authenticated()
@GetMapping("/hello")
public String showHello() {
return "hello";
}

//ONLY ADMIN After login


// .antMatchers("/admin").hasAuthority("ADMIN")
@GetMapping("/admin")
public String showAdmin() {
return "admin";
}

//ONLY CUSTOMER After login


// .antMatchers("/customer").hasAuthority("CUSTOMER")
@GetMapping("/customer")
public String showCustomer() {
return "customer";
}

@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();

UserDetails user2 = User.withUsername("ram")

.password("$2a$10$dEm8gdOC0R2S7IgXSnBKFOSeeKbCNuVeMC/hP24eY7zdADlUif4n.")
.authorities("CUSTOMER").build();

JdbcUserDetailsManager users = new JdbcUserDetailsManager(datasource);


users.createUser(user1);
users.createUser(user2);

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>

<p>Click <a th:href="@{/hello}">here</a> to see a greeting.</p>


</body>
</html>

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

5) Run app and enter URL


http://localhost:8080

*) If we enter details user : sam he is a ADMIN, and


trying to access CUSTOMER PAGE, which is not allowed then FC throws
403 Error Forbidden

==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

1. Application setup and User Register


2.*** User Login and Password Encoder
3. Session Management and Internal Process.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
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

S#1 Define One Spring boot application


Name : 03SpringBootSecurityOrmEx
Dep : web, lombok, data jpa, mysql, devtools, thymeleaf.

S#2 Comment Spring Security Dependencies in pom.xml


---------------------------------------
S#3 application.properties
server.port=9090

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;

public interface UserRepository extends JpaRepository<User, Integer>{

Optional<User> findByUserEmail(String userEmail);


}
-------------------------
S#6 Service interface/class
package com.app.raghu.service;

import java.util.Optional;

import com.app.raghu.entity.User;

public interface IUserService {

Integer saveUser(User user);


Optional<User> getOneUser(Integer id);
}
--------------
package com.app.raghu.service.impl;

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;

public Integer saveUser(User user) {


return repo.save(user).getUserId();
}

public Optional<User> getOneUser(Integer id) {


return repo.findById(id);
}

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;

//1. show Register page


@GetMapping("/register")
public String showReg() {
return "UserRegister";
}

//2. save user data


@PostMapping("/save")
public String saveUser(
@ModelAttribute User user, Model model)
{
Integer id = service.saveUser(user);
String message = "User '"+id+"' created!";
model.addAttribute("message", message);
return "UserRegister";
}

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

Spring Boot Security using ORM

1. Application setup and User Register (DONE)


2.*** User Login and Password Encoder
3. Session Management and Internal Process.

===================================================================
2.*** User Login and Password Encoder
===================================================================
Custom UserDetailsService (ORM)

*) User data is stored inside database tables : usertab and rolestab


*) This data can be loaded into User#Entity class object using DataJPA
*) But Spring Security needs User#Security class object, using
Custom UserDetailsService (ie Impl class).

*) UserDetailsService(I) having one method loadUserbyUsername(String un)


that converts Entity class User object to Spring Security User object.

=> We do call roles in application, but Spring security storing them as


Authority type internally String only.
Ex: ADMIN, CUSTOMER, CLERK ..etc

Roles allocated to one user is called as GrantedAuthority as List.


Ex: User : SAM, GrantedAuthority: ADMIN, CUSTOMER

*) GrantedAuthority(I) -Impl class- SimpleGrantedAuthority(C)

*) We need to configure some beans


1. PasswordEncoder
2. UserDetailsservice Impl class object
3. AuthenticationManager
4. Configure DaoAuthManager using (PasswordEncoder and UserDetailsservice)

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>

2. Configure Bean Password Encoder


package com.app.raghu.config;

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;

public Integer saveUser(User user) {


String encPwd = passwordEncoder.encode(user.getUserPwd());
user.setUserPwd(encPwd);
return repo.save(user).getUserId();
}
...//other methods...
-------------------------------------------
4. Security Config and login pages

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> select * from roles_tab;


+-----+----------+
| uid | urole |
+-----+----------+
| 1 | ADMIN |
| 1 | CUSTOMER |
+-----+----------+
2 rows in set (0.00 sec)

mysql> select * from roles_tab where urole='CUSTOMER';


+-----+----------+
| uid | urole |
+-----+----------+
| 1 | CUSTOMER |
+-----+----------+
1 row in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> delete from roles_tab where urole='CUSTOMER';


Query OK, 1 row affected (0.02 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

--internal Servlets code -------------


#a Creating a new session

HttpSession session = request.getSession(true);

#2 Read Existed Session

HttpSession session = request.getSession(false);

Note: Below line read old session, if not present creates new Session
HttpSession session = request.getSession();

#3 Add/Modify/Remove/Read existed data in session (key String:val Object)

session.setAttribute("userId",102345); //adds data to Session

session.setAttribute("userId",11111); //modify data to Session

int id = (Integer) session.getAttribute("userId"); //Returns Object

session.removeAttribute("userId"); //delete data from session

#4 Delete Session on logout

session.invalidate();

====================================================================
Date : 10-02-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Spring Boot Security

*) Token based Authentication:-


=> Server Generates one Token after validating user login details
by using one Security Hasing Algorithm and Secret key.

=> Once a token is generated then it will be sent to client using


response. Client App has to store the token data.

=> 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.

=> JJWT is open Source API used by java applications to generate,


validate, read/parse Tokens.

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>

=> JWT Token Contains 3 Parts:


1. Head : JWT Related Information
2. Payload: Username and other details(expDate, provider, ....etc)
3. Signature : SignUsingSecret(Encoded[Header]+ Encoded[Payload])

=> Token Format looks like:


xxxxxxxxxx.yyyyyyyyyyyyyyyy.zzzzzzzzzzz

=> Always Signature is validated at server using Secret.


=====================================================================

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;

public class Test {

public static void main(String[] args) {


String secret = "TestAppOneSample";

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) User Login and Token Generation


Define JWT Token service to generate token afte login success

3) Token validation and Service


Check Auth Header using Filter and validate using JwtUtil
if valid then continue to service/controller code

--Check code in github---


Date : 12-02-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Spring Boot Security
1. Filter :
=> In general Filters are used to execute PRE/POST processing logic
for a servlet.
=> We need to define one Filter that is used execute for every request only
OncePerRequestFilter(C) # doFilterInternal()
=> In this Filter, define below coding steps
*) Read Authorization Header (Read Token)
*) Validate Token by using JwtUtil
*) Read Subject/username
*) Validate Username by loading userdata from db
*) Create UsernamePasswordAuthenticationToken
*) Link to current request and SecurityContext
(which is valid upto Response)

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

POST http://localhost:9090/user/save [SEND]


Body
(*) raw [JSON]
{
"name" : "AJAY",
"username" : "[email protected]",
"password" : "ajay",
"roles" : ["ADMIN","CUSTOMER"]
}

2. Login user

POST http://localhost:9090/user/login [SEND]


Body
(*) raw [JSON]
{
"username" : "[email protected]",
"password" : "ajay"
}

3. Check Secured Resources

POST http://localhost:9090/user/welcome [SEND]


Headers

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.

Principal(I) --- Stores only name


IS-A
Authentication(I) -- Given by Spring Security that holds
username and roles
IS-A
UsernamePasswordAuthenticationToken(C) Impl class

*) To hold current user details object inside container to access


globally, Spring Security provided SecurityContextHolder(C)
which creates SecurityContext(I).
=======================================================
1. Filter class
package com.app.raghu.filter;

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 {

// read Token from Request Header


String token = request.getHeader("Authorization");
if (token != null) {

// validate and read subject from token


String username = jwtUtil.getUsername(token);

// 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.

=> OAuth 2.x is recomanded for Day-to-Day business application.


(Internal network application).

Ex: MMT, Carwale, Zomato, BookMyShow ...etc

=> It is not recomanded for finance/banking applications.


Ex: ICIC Bank, CreditCard service..

--3 devices---
1. Auth & Resource Server
2. Client Application (server)
3. End Customer Device (Browser)

*) AuthService Providers: Google , Facebook, Github, LinkedIn, Twiiter..etc


Example:
https://developers.facebook.com/
https://console.cloud.google.com/

================Stages======================================
1. Register Client application with Auth&Resource Server

2. Create End Customer account at client application and login

3. Get Access Token by a client+user from Auth Server to access


resource from Resource Server.
===========================================================
*) End Customer tries to make Login request to client application
*) Client app will ask user to login first and allow access request
(ie called as Grant)
*) If user has given Grant to Client application, then client
makes request to Auth Server for Access Token using details
clientId, secret and User Grant
*) Auth Server validates data and given accessToken to client app.
*) Client makes request to Resource server to read enduser data
using AccessToken.
*) Resource server validates accessToken and provides user data.
*) Client App stores user data and makes user login success
redirect to HomePage.
Date : 15-02-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------
Stage#1 Register Client with Auth Server
(Facebook, google, github)

*) 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

LSP: "Derived classes must be substitutable for their base classes."


(Supported by Java) Upcasting

ISP: "Make fine grained interfaces that are client specific."


(We need to implement) - Define multiple interfaces with speific operations
insted of writing all in one.

DIP: "Depend on abstrations, not on concretions."


(We need to implement) -
create HAS-A Relation between class and interface/abstarct class
not between two classes.
Date : 18-02-2023
Spring Boot and Microservices
7AM | Mr. Raghu | (ASHOK IT)
---------------------------------------------------------------------------
Circuit Breakers

*) For one request, there can be multiple MS# executed in a order.


*) This is called as Chain of MS# also called as Circut.
*) If one of these MS# is not responding properly for request processing
Exception internall, Service Down, Resource issues, timeout issues..etc
Then Cascade Exception/failure may occur, which leads to invalid
response/bad client response..etc

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

*) Circuit Breaker is used to avoid execution of actual MS#/external service


for some time incase of cascading failures.

We can set one criteria based on that connection estabilishment can be


tested ie called as Threshold.

1. COUNT BASED : If MS# is failed for 20 request


2. TIME BASED : If MS# is not responding/exeception for last 30 minutes
***Default value is 100.

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.

*) Hystrix is removed from Spring boot, latest one is :


circuitbreaker-resilience4j (internally it is reactive API)

*) We need to add 4 Dependencies : actuator, web, resilience4j and AOP


*) Also provide Fallback method:
If circuitbreaker is OPEN status then execute Dummy method
insted of actual MS# application, for some time to avoid
cascade exceptions.

*) Provide properties inside YAML file

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 {

private static final String ORDER_SERVICE = "orderService";

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

public ResponseEntity<String> orderFallback(Exception e) {


return new ResponseEntity<String>("SERVICE IS DOWN!! TRY AFTER SOME TIME",
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);
}

*) run with port : 8081

and Enter URLs:


http://localhost:8080/order
http://localhost:8080/actuator/health
Date : 21-02-2023
Tools Session
7 AM
-----------------------------------------------------
Apache Maven

*) Development : ___.java
*) Compile : ___.class
*) Build : ___.jar / __.war / ___.ear

JAR - Java Archive ( Group of .class files)


WAR - Web Archive ( Group of .class[servlets], HTML, CSS, Images)
EAR - Enterprise Archive ( EJBs + Web Apps)

*) JAR is a Collection of .class files

*) Dependency : Required JAR files for application is called as Dependency


*) Dependency Chain : one JAR can be internally using other JAR classes
then those JARs are called as Dependency Chain.

===============================================================
Project Management Tool : Maven

1. Project Folder System


2. All Required Dependencies [Dependency Chain]
3. Compile, Test Code
4. Build Our Project (.jar/.war)

*) Maven Folder System:-

src/main/java <--Development/.java files


src/main/resources <--Development/non java files[.xml,.yaml..etc]

src/test/java <-- Unit Test/.java files


src/test/resources <-- Unit Test/non java files[.xml,.yaml..etc]

target folder : It contains our current project build files


ex: myapp-1.0.jar
<artifactId>-<version>.jar (format)

groupId: Provider details [folder name using domain name]


ex: com.oracle, com.google, in.test.app

*) pom.xml [ Project Object Model]


How and What a Project should Have?
*) Types of Maven Application
1. Simple Maven Project (Stand alone)
2. ArchType Project (Web, template..)

==============================================================
~/.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;

public class DatabaseConnection {

public Connection getConnection() {


Connection con = null;
try {
con = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/boot7am",
"root", "root");
} catch (SQLException e) {
e.printStackTrace();
}
return con;
}
}
-------
package com.app;

import static org.junit.jupiter.api.Assertions.assertNotNull;

import java.sql.Connection;

import org.junit.jupiter.api.Test;

public class TestDatabaseConnection {

@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:-

> When we add any <dependency> in pom.xml, then


it may add/download either single dependency or group of
dependencies (Multiple child jars)

> 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?

1. compile : if we did not specify any scope then it is default


it says JAR is required from compile time onwards.

F/w Depenencies : Hibernate Core, Spring Context ..etc

2. runtime : Jar is required while running, not at compile time.


Database Dependencies : ojdbc jar, mysql jar..etc
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.32</version>
<scope>runtime</scope>
</dependency>

3. test : Jar is required while UnitTesting only


JUnit F/w, TestNg , Mocking F/w ..etc

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.1</version>
<scope>test</scope>
</dependency>

4. provided : Jar is taken from Server/container specifics


[servlet-api.jar taken from Tomcat Server]
[Lombok from Spring boot F/w or Containers]

<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

> Next > Finish


Date : 24-02-2023
Tools Session
7 AM
-----------------------------------------------------
Apache Maven

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

> Next > Finish

*) WAR Plugin
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.1</version>
</plugin>
</plugins>

***) Configure server in IDE for API access


> Window > Preferences > Servers > Runtime Environments > Add
> Select Apache > Tomcat 9 > Next > Enter location of tomcat
> next/finish > apply and close

***) Add server to Project


> Right click on Project > Build path > Configure build path
> Library tab > Add Library > server runtime > Select Apache tomcat
> finish

***) open web.xml and remove dtd lines code (top 3 lines)

*) Right click on project > Run as > Maven Build ...


> enter goals " clean package " >> apply and run
*) Refresh project > copy war file from target folder
> paste inside Tomcat webapps folder > Run tomcat
> Enter URL : http://localhost:8080/FirstwebApp/

===============================================================
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.

*) We can specify Dependencies directly or using <dependencyManagement>


for handling dependency version management.

Step#1 Create Parent Project


> File > new > Maven > Simple Project > Next > Enter details
packgin type : pom

> open pom.xml and add code like


<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.25</version>
</dependency>
</dependencies>
</dependencyManagement>

Step#2 Create Child project


> File > new > Maven > Simple Project > Next > Enter details
> and also enter parent project details at same time

<parent>
<groupId>___</groupId>
<artifactId>___</artifactId>
<version>__</version>
</parent>

We can access parent available dependencies (from BOM: Bill Of Materials)


without version:

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

*) Console is a limited area to see all log lines.


So, we use a storage area like a File(Log File), Database..etc

*) We have different Logging F/w in Java:


=> Commons Logging
=> Log4J
=> Logback
=> Java Loggin Basic F/w
..etc

*) SLF4J (Simple Logging Facade for Java) is a abstract f/w built


on logging f/w. If we move from one Logging F/w to another
F/w, our logging code remains same.
========================================================================
Apache Log4J 2.x

3 Components:-

1. Logger : This Object needs to be created inside a Class


(for which Logging needs to be enabled)
In our apps: RestControllers, Controllers .. must need

2. Appender : It says about location to store log messages

Types:
ConsoleAppender : Write Log messages to Console
FileAppender/RollingFileAppender/DailyRollingFileAppender
: Write Log messages to File

JDBCAppender : Write Log messages to Database


SmtpAppender : Write Log messages to Email (Admin Mail)
TelnetAppender: Write Log messages to Network/Stream

3. Layout : Format of Log Messages

=> 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

-> Logger Priority methods: Prints Message to Appender


TRACE : Find Current Service in Distribution.
DEBUG : Print data/message of variables/objects ...etc
INFO : What is the current stage
(Service is done, entered into Controller..etc)
WARN : To print Warnings
ERROR : Exceptions in application (ArrayIndexOutofBounds..etc)
FATAL : High Level issues(Network, Memory, Connection)
------------------------------------------------------------

*) Inside our class, we need to create Logger object as

private static final Logger LOG = LogManager.getLogger(__.class);

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

*) We need to define one Logging ConfigurationFile


Name : log4j2.xml
<Configuration>
<Appenders>
<Console .../> ++ Layout
<File ../> ++ Layout
</Appenders>
<Loggers>
Root Level - DEBUG/INFO/WARN...
</Loggers>
</Configuration>
=================================================
Step#1 Create one simple Maven Project
Group ID: com.app.raghu
Artifact ID : LoggingApp
Version : 1.0

Step#2 Add in pom.xml


<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.2</version>
</dependency>

<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>

Step#3 define log4j2.xml file under src/main/resources folder

Step#4 Define one test class


package com.app;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Test {

private static final Logger LOG = LogManager.getLogger(Test.class);

public static void main(String[] args) {


LOG.debug("FROM DEBUG");
LOG.info("FROM INFO");
LOG.warn("FROM WARN");
LOG.error("FROM ERROR");
LOG.fatal("FROM FATAL");
}
}
-----------priority methods ------------------
Name Number Method
----------------------------------------------
DEBUG - 1 - debug()
INFO - 2 - info()
WARN - 3 - warn()
ERROR - 4 - error()
FATAL - 5 - fatal()
----------------------------------------------

*) To write Log Messages to DB:

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

mysql> create database boot7am;


Query OK, 1 row affected (0.01 sec)

mysql> use boot7am;


Database changed
mysql> show tables;
Empty set (0.01 sec)

mysql> create table EVENT_LOGS (


-> ID varchar(50) primary key,
-> DATE_TIME timestamp,
-> CLASS varchar(100),
-> LEVEL varchar(10),
-> MESSAGE TEXT
-> );
Query OK, 0 rows affected (0.04 sec)
================================================================
<SMTP name="LogToMail" subject="Error Log From Log4j"
from="[email protected]"
to="[email protected]"
smtpHost="smtp.mailgun.org"
smtpPort="587"
smtpUsername="____.mailgun.org"
smtpPassword="____"
bufferSize="100">
</SMTP>

Gmail Host: smtp.gmail.com


port : 587
also in pom.xml
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
Date : 06-03-2023
Tools Session
8:30 PM
------------------------------------------------------------
Unit testing:-
=> Every developer will write code for a assigned task
=> once code is done, need to be tested by Developer only.
=> Such Testing is done by Unit Test F/w.

*) General meaning of Unit is : Part of Code/Module/task..


*) Manul test : Testing manually on changes, enhancements is repeated work.
Automated Test: One time code, Execute/call same code next time.
Ex: JUnit F/w, TestNG..etc

====================================================================
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

=> We need to define one class that execute UnitTesting ie called as


Test Case
=> Inside this class, we define a method with @Test, ie called as
Test method.
Ex:
class SampleTest {
@Test
void testSave() {

}
}

===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>

--Dummy Test case----


package com.app.raghu;

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

*) If we use @Order then we must enable this, by adding


@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
at class level

*) ClassName ends with Test, method name starts with test


in naming convensions.
Ex:
class UserControllerTest {
@Test
void testSave() {}
}

===============Ex#2=====================================
service code:
package com.app.raghu;

public class Calculator {

public int multiply(int a, int b) {


return a * b;
}

Test code:
package com.app.raghu;

import static org.junit.jupiter.api.Assertions.assertEquals;


import static org.junit.jupiter.api.Assertions.assertNotNull;

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?

====Singleton Database Connection testing==================


*) pom.xml :-
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.32</version>
</dependency>

*) Service class:
package com.app.raghu;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class ConnectionUtil {

private static Connection con = null;

static {
try {
con = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/boot7am", "root", "root");
} catch (SQLException e) {
e.printStackTrace();
}
}

public static Connection getConnection() {


return con;
}
}

*) TEST CLASS:
package com.app.raghu;

import static org.junit.jupiter.api.Assertions.assertAll;


import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertSame;

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 {

Connection con1, con2;

@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

*) We are Dev-3 working on Module-3.


*) I want to Code for Module-3 and test but it is internally dependent
on Module-2
*) So, I'll Create Dummy Implementation of Module-2 for Devlop and
Test Module-3. ie called as Mocking.
*) Mocking can be done for even Database Connections, Server setup,
Request object creation..etc

//depends on
interface ProductService {
Integer saveProduct();
}

//develop and test


class ProductController {
ProductService ps;

ProductService ps = mock(ProductService.class);

*) Stub is created for ProductService (Dummy Impl class)

class Proxy$1 implements ProductService {


public Integer saveProduct() {
return 0;
}
}

ProductService ps = new Proxy$1();


--------------------------------------
when(ps.saveProduct()).thenReturn(100);
when(ps.saveProduct()).thenReturn(Mock.anyInt());

==========Mockito Basic Example#1===================


*) Service class:
package com.app.raghu;

public interface ProcessInfo {

Integer getCode(String code);


}

*) Test class:
package com.app.raghu;

import static org.junit.jupiter.api.Assertions.assertEquals;


import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import org.junit.jupiter.api.Test;

public class TestMockProcessInfo {


@Test
public void testInfo() {
ProcessInfo ps = mock(ProcessInfo.class);
when(ps.getCode("ABC")).thenReturn(100);

assertEquals(ps.getCode("ABC"), 100);
}
}
=======Basic Example#2=======================================================
*) Application code:
package com.app.raghu;

import java.sql.SQLException;
import java.util.List;

public class Repository {

public List<String> getData() throws SQLException {


return null;
}
}

-------------
package com.app.raghu;

import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Service {

private Repository repository;

public Service(Repository repository) {


this.repository = repository;
}

public List<String> getDataLen() {


try {
return repository.getData().stream()
.filter(data -> data.length() < 5)
.collect(Collectors.toList());
} catch (SQLException e) {
return Arrays.asList();
}
}
}

*) Test class code:


package com.app.raghu;

import static org.junit.jupiter.api.Assertions.assertEquals;


import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.Mockito.when;

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 {

@Mock //creates stub for Repository (Dummy Impl code)


private Repository repo;

@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"));

List<String> list = sob.getDataLen();


assertNotNull(list);
assertEquals(list.size(), 3);

}
======================================================================
*) Recomanded to use Embedded Databases: H2 for Testing Spring Boot
Applications

You might also like