Spring Boot Nit
Spring Boot Nit
SPRING BOOT
AND
MICROSERVICE
BY
MR. RAGHU SIR
SPRING BOOT
1. Spring Boot :--
=>Spring boot is a spring based framework which is open source and developed by
Pivotal Team.
=>Available versions of Spring Boot are
a>Spring Boot 1.x.
b>Spring Boot 2.x.
=>Spring Boot provides AutoConfiguration which means reduce Common lines of code
in Application which is written by Programmers and handles Jars with version
management. (i.e. Providing Configuration code XML/Java and maintaining all jars
required for Project Parent Jars + Child Jars)
=>Spring Boot is an Abstract Maven project also called as Parent Maven Project (A
Project with partial code and jars)
=>Here Programmer will not write configuration code but need to give input data
using
a>Properties File (application.properties).
b>YAMAL File (application.yml).
Example:--
1>Spring JDBC and Spring Boot JDBC [Sample code Comparison]:--
1>Spring JDBC:--
a>XML configuration:--
<beans...>
<bean name="dsObj" class=org.sf...DriverManagerDataSource>
<property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
2>Spring Boot:--
a>application.properties:--
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe
spring.datasource.username=system
spring.datasource.password=system
NOTE:--
a>Spring Boot supports two build tools Maven and Gradel.
b>Spring Boot supports 3 embedded servers and 3 embedded databases. These are
not required to download and install.
i>Embedded Servers:--
1>Apache Tomcat (default)
2>JBoos Jetty
3>Undertow
ii>Embedded DataBase:--
1>H2
2>HSQL DB
3>Apache Derby
c>Spring Boot supports cloud apps with micro services pattern. [“Both coding and
Deployment”].
=>Coding is done using Netflix Tools
=>Deployment is done using PCF Tools (or its equal…)
e> Supports Input Data (Key = val) Using (for AutoConfiguration code):--
=>Properties file or YAML files.
1. SpringBootStarter class:-- It is a main method class used to start our app. It is entry
point in execution. Even for both stand alone and web this file used.
Types of Runners(2):--
1.1 CommandLineRunner :-- This is legacy runner (old one) which is provided in Spring
boot 1.0 version.
=>It has only one abstract method “run(String… args) : void”.
=>It is a Functional Interface (having only one abstract method).
=>Add one stereotype Annotation over Implementation class level (Ex:-
@Component). So that container can detect the class and create object to it.
Code Setup:--
#Setup : JDK 1.8 and Eclipse / STS.
#2. Open pom.xml and add parent, Properties, dependencies with plugins:--
Add details in pom.xml (Project Object Model).This file should contain bellow details in
same order. It is Automatic Created with project.
1.>Parent Project Details.
2.>Properties (with java version).
3.>Dependencies (jar file details).
4.>Build Plugin.
Code:--
1>SpringBootRunner.java (Spring Boot Starter class):--
package com.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootRunner {
public static void main(String[] args) {
SpringApplication.run(SpringBootRunner.class, args);
System.out.println("Hello Uday");
}
}
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 9
[Raghu Sir] [NareshIT, Hyd]
#Runner #1: SpringBootCommandLineRunner.java
package com.app.runner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
NOTE:--
a>Boot Application can have multiple runners Ex:-- EmailRunner, JmsRunner,
SecurityRunner, CloudEnvRunner, DevOpsRunner, DatabaseRunner etc…
b>Boot provides default execution order.
=>To specify programmer defined order use
i>Interface : Ordered or else
ii>Annotation : @Order
=>If we are configures both Runner but not implements Ordered then by default
Annotation based Configuration will be executed first.
@SpringBootApplication
public class MyRunner {
public static void main(String[] args) {
SpringApplication.run(MyRunner.class, args);
System.out.println("Starter class Called");
}
}
2>Runner #1 MyInputRunner.java:--
package com.app.runner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class MyInputRunner implements CommandLineRunner {
public void run (String… args) throws Exception {
System.out.println("Hello CommandLineRunner");
System.out.println(args[1]);
System.out.println(Arrays.asList(args));
System.out.println("End of CommandLineRunner");
} }
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 12
[Raghu Sir] [NareshIT, Hyd]
Execution:--
=>Right Click on starter class code (main)
=>Run As => Run Configuration
=>Choose “Arguments” tab
=>Enter data in Program arguments (with space)
--name=UDAY Hello hi --db=MySQL --db=Oracle
Syntax:--
new InterfaceName() {
//Override all methods
}
Example#1:--
interface Sample {
void show ();
}
-----Anonymous Inner class--
new Sample() {
public void show() {
System.out.println(“Hello”);
}
}
Example#2:--
interface CommandLineRunner {
void run(String… args) throws Exception;
}
Anonymouse Inner class:--
new CommandLineRunner() {
public void run (String… args) throws Excception {
System.out.println(“HI”);
}}
**Java Style Configuration for CommandLineRunner:--
3>Runner#2 (SpringBootApplicationRunner.java):--
package com.app.runner;
import java.util.Arrays;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@Component
public class SpringBootApplicationRunner implements ApplicationRunner {
public void run(ApplicationArguments args) throws Exception {
System.out.println("hello Application Runner");
System.out.println(Arrays.asList(args.getSourceArgs()));
System.out.println(args.getNonOptionArgs());
System.out.println(args.getOptionNames());
System.out.println(args.getOptionValues("db"));
System.out.println(args.containsOption("bye"));
System.out.println("End of Application Runner");
}
}
Code:--
#1. Create maven project and provide pom.xml and starter class
#2. application.properties (src/main/resources)
=>Right click on src/main/resource folder=>new =>other=>search and Select
“File”=>enter name “application.properties” => finish
application.properties:--
my.info.product.id=999A
my.info.product.code=xyz
my.info.product.model-version=44.44
my.info.product.release_dtl_enable=false
my.info.product.start-key=N
NOTE:--
a> Allowed special symbol are dot(.), dash(-) and underscore (_).
b> Key=value both are String type, Spring supports both are String type, Spring
supports type conversation (ex String->int) automatically.
c> To read one key-value in code use Legacy syntax : @Value(“${key}”)
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 18
[Raghu Sir] [NareshIT, Hyd]
#3. Starter class same as above.
#4. Runner with key data class (SpringBootRunnerWithInputData.java):--
package com.app.runner;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class SpringBootRunnerWithInputData implements CommandLineRunner
{
@Value("${my.info.product.id}")
private int prodId;
@Value("${my.info.product.code}")
private String prodCode;
@Value("${my.info.product.model-version}")
private double modelver;
@Value("${my.info.product.release_dtl_enable}")
private boolean isDetEnable;
@Value("${my.info.product.start-key}")
private char startKey;
//Constructor methods
//Setters and Getters method
//toString method
@Override
public String toString() {
return "SpringBootRunnerWithInputData [prodId=" + prodId + ",
prodCode=" + prodCode + ", modelver=" + modelver+ ", isDetEnable=" + isDetEnable +
", startKey=" + startKey + "]";
}
//Overridden run method
public void run(String... args) throws Exception {
System.out.println(this);
//System.out.println(this.toString());
}
}
NOTE:-- If key data is mismatched with variable data type, then Spring Container
throws Exception : TypeMistchException : Failed to convert value.
Internal flow:--
Spring Boot will search for file “application.properties” in project (4 different locations)
=>Once found (detected) then load into Container and store as “Environment” obj.
2>We can read data in legacy style @Value or 2>env.getProeprty(..).
3>Boot Style (Bulk Loading) can be done using Annotation. ****
4>@ConfigurationProperties
4>@ConfigurationProperties:--
=>This Annotation is used to perform bulk data reading (multiple keys at a time) and
parsing into one class type (Stores in project).
=>Possible conversions are.
a>1key = 1 variable
b>Multiple keys with index = List/Set/Array
c>Multiple keys with key-value format = Map or Properties
d>Multiple keys with common type = Class Object (Has-A)
Example:--
1. Starter class (SpringBootApplicationEx.java):--
package com.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootStarter {
public static void main(String[] args) {
SpringApplication.run(SpringBootStarter.class, args);
System.out.println("Hello Spring Boot");
}
}
2. application.properties:--
#One variable data
my.prod.ID=999
my.prod.co-de=ABC
my.prod.Ty_pe=true
my.prod.MOD-E_L=p
#List<DT>/Set<DT>/DT[]
my.prod.prjnm[0]=P1
#Map or Properties
my.prod.mdata.s1=55
my.prod.mdata.s2=66
my.prod.mdata.s3=88
@Component
public class UsingEnvironment implements CommandLineRunner{
@Autowired
private Environment env;
@Override
public void run(String... args) throws Exception {
System.out.println(env.getProperty("my.prod.ID"));
@ConfigurationProperties("my.prod")
@Component
public class UsingApplicationProperties implements CommandLineRunner {
public UsingApplicationProperties() {
super();
}
public int getId() {
return id;
}
Example #3:--
1>application.properties:--
@Component
public class UsingValueAnnotation implements CommandLineRunner {
//@Value("${my.random.stringval}")
//@Value("${my.random.stringval}")
//@Value("${random..value}")
@Value("${my.random.uuid-type}")
private String code;
@Value("${my.random.num}")
//@Value("${my.random.num-rang}")
//@Value("${my.random.num-rang-from-to}")
private int num;
@Value("${my.random.bignum}")
private long numbig;
@Override
public void run(String... args) throws Exception {
System.out.println(this);
}
public UsingValueAnnotation() {
super();
}
public UsingValueAnnotation(String code, int num, long numbig) {
super();
this.code = code;
this.num = num;
this.numbig = numbig;
Ex#2:--
my.code.id=56
my.code.mdn.type=big
my.code.str.service=ALL
my.code.str.service.info=true
my.code.mdn.obj=CRL
my.code.cost=3.67
my.code.mdn.sale=YES
my:
code:
id: 56
Ex:-- application.proeprties---
my.code.version[0]=V1
my.code.version[1]=V2
my.code.version[2]=V3
---application.yml:---
my:
code:
version:
-V1
-V2
-V3
my:
data:
model:
a1: 6.6
a2: 8.6
a3: 9.6
@SpringBootApplication
public class ApplicationProperiesUsingYml {
public static void main(String[] args) {
SpringApplication.run(ApplicationProperiesUsingYml.class, args);
}
}
3.>application.yml:--
#Normal Data
my:
prod:
id: 5
code: AB
cost: 4.5
#List Data
version:
-V1
-V2
-V3
#Map Data
model:
a1: 6.6
a2: 8.6
a3: 9.6
@ConfigurationProperties("my.prod")
@Component
public class Product {
private int id;
private String code;
private double cost;
private List<String> version;
private Map<String, Double> model;
public Product() {
super();
}
public Product(int id) {
super();
this.id = id;
}
public Product(int id, String code, double cost, List<String> version,
Map<String, Double> model) {
super();
this.id = id;
this.code = code;
this.cost = cost;
this.version = version;
this.model = model;
}
public int getId() {
return id;
}
public void setId(int id) {
@Component
public class ApplicationRunnerEx implements ApplicationRunner {
@Autowired
private Product prod;
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println(Arrays.asList(prod));
}
}
Output:--
Example Code:--
#1 Starter class + pom.xml:-- Same as before
@SpringBootApplication
public class SpringBootStarter {
public static void main(String[] args) {
SpringApplication.run(SpringBootStarter.class, args);
System.out.println("Hello Spring Boot");
}
}
#2. application.yml:--
my:
dt:
pid: 55
mo:
mid: 67
mcode: ABC
colors:
-RED
-GREEN
-YELLOW
public Model() {
super();
}
public int getMid() {
return mid;
}
public void setMid(int mid) {
this.mid = mid;
}
public String getMcode() {
return mcode;
}
public void setMcode(String mcode) {
this.mcode = mcode;
}
public List<String> getColors() {
return colors;
}
public void setColors(List<String> colors) {
this.colors = colors;
}
@Override
public String toString() {
return "Model [mid=" + mid + ", mcode=" + mcode + ", colors=" + colors + "]";
}
}
@ConfigurationProperties("my.dt")
@Component
public class Product
{
private int pid;
@Autowired
private Model mo; //HAs-A
public Product() {
super();
}
public int getPid() {
return pid;
}
public void setPid(int pid) {
this.pid = pid;
}
public Model getMo() {
return mo;
}
public void setMo(Model mo) {
this.mo = mo;
}
@Override
public String toString() {
return "Product [pid=" + pid + ", mo=" + mo + "]";
}
}
@Component
public class CommandLineRunnerForYaml implements CommandLineRunner
{
@Autowired
private Product pob;
public void run(String... args) throws Exception {
System.out.println(pob);
System.out.println("Hello Application Runner");
}
}
Output:--
application.yml:--
my:
dt:
pid: 68
mid: ${my.dt.pid}
NOTE:--
1.>Symbol ‘#’ indicates a comment line in yml file.
2.>Using 3 dash (---) symbols in yml is divided into multiple files internally (mainly used
for profiles**)
Ex:-- application.yml:--
#Hello data to Product
my:
dt
pid: 57
---
my:
dt:
do:
mid: 98
=>In this case we should not modify existed properties file, use new one with key=val
data. File naming rule is:
application-{profile}.properties
application-{profile}.yml (or 3 dash)
Example:--
=>File => new => Spring Starter Project => Enter Details
GroupId : org.sathyatech
ArtifactId : SpringBootProfiles
Version : 1.0
=> next => next => finish.
@SpringBootApplication
public class SpringBootProfilesApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootProfilesApplication.class, args);
System.out.println("**Starter class Executed**");
}
}
2>Properties files:--
a>application.properties
Ex:-- my.profile.code=Hello from default
b> application-prod.properties
Ex:-- my.profile.code=Hello from PROD
3>service interface:--
#1 Create an Interface (GenericService.java):--
package com.app.profile.service;
@Component
@Profile("default")
public class DevService implements GenericService {
@Value("${my.profile.code}")
private String code;
@Component
@Profile("prod")
public class ProdService implements GenericService {
@Value("${my.profile.code}")
private String code;
public ProdService() {
super();
}
public ProdService(String code) {
super();
this.code = code;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
@Component
@Profile("uat")
public class UatService implements GenericService {
@Value("${my.profile.code}")
private String code;
Output:--
NOTE:--
1>Use key spring.profiles.active=profile
=>We can provide using 3 ways. Those are
a> Command Line Arguments (Option Arguments)
2>Key Search highest priority is given in same profile properties file, if key is not found
in current profile properties file then goes to default properties file.
=>If no where key is found then
a>@Value generate Exception (IllegalArgumnetException)
b>@ConfigurationProperties :- Default value of DataType is chosen by container.
Case#2 spring.profiles.active=uat
Key Value
A 30
B 7
C 6
D 0 (for int type default value)
application.yml:--
my:
profile:
id: 666
---
my:
profile:
id: 999
spring:
profiles: prod
---
my:
profiles:
id: 888
spring:
profiles: uat
NOTE:--
#1 To specify active and include profiles use
a>Option Arguments:--
--spring.profiles.active=prod
--spring.profiles.include=prodemail
@SpringBootApplication
public class SpringBootProfilesUsingYmlApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootProfilesUsingYmlApplication.class, args);
}
}
2>application.yml:--
my:
profile:
id: 666
spring:
profiles:
active: prod
include:
-prodemail
#Production Profiles
---
my:
profile:
@Component
@ConfigurationProperties("my.profile")
public class ProductRunner implements CommandLineRunner {
Dependency Management:--
Getting Main Jars and its child jars with version support (without conflicts) into project
workspace is called as Dependency Management.
Build:-- Converting our application into final JAVA executable format i.e .jar/.war/.ear.
pom.xml format:--
<project….>
<modelVersion>4.0.0</modelVersion>
<!-- CUrrent Project info -->
<groupId>a.l</groupId>
<artifactId>HelloApp</artifactId>
<version>1.0</version>
Syntax:--
<dependencies>
<dependency>
<groupId>..</groupId>
<artifactId>..</artifactId>
<version>..</version>
<exclusions>
<exclusion>
<groupId>..</groupId>
<artifactId>..</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
Ex:--
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.5</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
POM format:--
<dependency>
<groupId>…</groupId>
<artifactId>…</artifactId>
<scope>….</scope>
</dependency>
NOTE:-- There is a dependency jar which not existing in the maven centre but locally.
After mvn clean install, this dependency jar can't be found from the fat jar. is this an
known-issue? the workaround is have to install it into local maven repo with command:
`mvn install:install-file -Dfile=lib/routines.jar -DgroupId=org.talend -
DartifactId=routines -Dversion=1.0 -Dpackaging=jar`
=>Update JDK to project before install or build else “BUILD FAILED” Error will be
displayed.
=>A final jar will be created with same format “artifactId-version.jar”
=>Maven Build Plugin (integrated with Spring Boot) must be provided in pom.xml.
Ex:--
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
@SpringBootApplication
public class SpringBootBannerApplication
{
public static void main(String[] args)
{
SpringApplication sa = new SpringApplication (SpringBootBannerApplication.class);
//sa.setBannerMode(Banner.Mode.OFF); //to Disable the banner
//sa.setBannerMode(Banner.Mode.CONSOLE); //to Disable the banner on console
sa.setBannerMode(Banner.Mode.LOG); //to Display the banner in Log file
//some other configuration
ConfigurableApplicationContext c = sa.run(args);
System.out.println(c.getClass().getName().toString());
}
}
2>Banner.txt file:--
b>Provide our own starter package (even other packages) using array style {-,-,-,-,}
Ex:-- @ComponentScan({“com.app”,”com.one”,”com”})
c>We can provide one common package name which covers all sub-levels.
Ex:-- @ComponentScan(“com”)
Example:--
package com.app;
@SpringBootApplication
//@ComponentScan("com.one")
@ComponentScan("com")
//@ComponentScan({"com.one", "com", "com.app"})
public class MyStarter {
public static void main (String[] args)
{
StringApplication s = new SpringApplication(AppStarter.class);
ConfigurableApplicationContext ac = s.run(args);
System.out.println(ac.getClass().getName());
System.out.println(ac.getBean(“Product”));
System.out.println(ac.getBean(“Info”));
}
}
3.> Every Spring Boot Application Starter class itself Component. i.e
@SpringBootApplication is having @Component annotation internally.
=>It is only highest Priority component by default, if app has multiple components.
Ex:- We can convert starter even as Runner.
@SpringBootApplication
public class MyStarter implements CommandLineRunner {
public void run (String… args) throws Exception {
System.out.println(“From Starter”);
}
public static void main(String[] args) {
SpringApplication.run(MyStarter.class, args);
System.out.println("**Starter class Executed**");
}
}
4> Auto-Detect and Execute Configuration classes [Auto-Load Configuration files]
=>Every Spring Boot starter class itself A configuration class (@Configuration) which
auto detects other Config Classes even without @Import annotation.
i.e. We can define @Bean (Objects creation in Starter class).
=>All Spring (Java based) Configuration files are loaded into container with
@Configuration.
=>All Spring (java based) Configuration files are loaded into container by spring boot if
classes are annotated with @Configuration.
=>Not required to pass as ApplicationContext input (as like Spring f/w).
public Admin() {
super();
}
public int getAdminId() {
return adminId;
}
public void setAdminId(int adminId) {
this.adminId = adminId;
}
public String getAdminName() {
return adminName;
}
public void setAdminName(String adminName) {
this.adminName = adminName;
}
@Override
public String toString() {
return "Admin [adminId=" + adminId + ", adminName=" + adminName + "]";
}
}
b>Product.java:--
package com.app.model;
@Configuration
public class AppConfig {
@Bean
public Admin aobj() {
Admin a = new Admin();
a.setAdminId(100);
a.setAdminName("Uday");
return a;
}
}
@SpringBootApplication
//@Import (AppConfig.class) //Its not required
public class SpringBootStarterApplicationWithRunner implements
CommandLineRunner
{
@Autowired
private Product p;
@Autowired
private Admin a;
8. Spring Initializer:--
Link : https://start.spring.io/
=>This web site is used to generate one Maven (or Grade Project) for Spring Boot Apps
with all configuration and setup.
Like starter class, application.properties, pom.xml, folder system etc.
=>By using this we can Create Boot App which can be imported to normal Eclipse IDE
or any other equal (No STS Required).
=>Even STS (or Manual Approaches) uses internally SPRING INITIALIZER only.
#1:- Data JPA provides @NoRepositoryBean (S) which is auto configured and self logic
implemented for basic operations i.e : Programmer not required to write any logic for
basic operations (No Implementation class and method).
=>Configuration for DataSource (I), SessionFactory (I), HibernateTemplate (C)
Hibernate TransactionManger (C) all are not required.
=>When we add bellow dependency in pom.xml it will download Jars and above Config
code given from parent Project.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>Spring-boot-starter-data-jpa</artifactId>
</dependency>
#2:- Data JPA provides “Embedded Database Support”. It means Database provided in
application itself.
=>It is not required to download and Install, not even properties required (like driver
class, url, user, password).
=>Spring Boot supports 3 Embedded DBs. Those are : H2, HSQLDB, Apache Derby.
=>We can use any one Embedded Database which runs in RAM (Temp memory).
=>It uses hbm2ddl.auto=create-drop i.e Tables created when App starts and deleted
before App Stops.
=>These DBs are used in both Development and Testing Environment, but not in
Production.
#3:- Spring Boot also supports Both SQL (MySQL, Oracle) and NoSQL (MongoDB)
Database etc.. also.
#4:- Data JPA Supports Special concept “Query Methods an easy way to code and fetch
data from DB” (ex : findBy, @Query).
#5:- Data JPA supports Easy Connection Pooling (Auto Config) concept.
#6:- Data JPA supports Cache Management (AutoConfig).
=>Primary key data Type must be Wrapper class or any other classes which
implements java.io.Serializable.
=>Primitive Types are not accepted as PK DataType for model & for Repository Coding.
Eclipse Shortcuts:--
F3 => Goto code
F3 => Overview (Press again for super type also)
Crtl +alt +DownArraw => Copy current line, paste
Select Lines
+ctrl + shift + / =>comment lines
+ctrl +shift + \ =>Uncomment lines
Save(T ob) : T :-- This method is from CrudRepository (I) which is used to perform save
or update operation.
=>If Primary Key value is Null or not exist in DB then perform insert operations, else
record found in DB based on PK then performs update operation.
Setup :- Create Project with dependencies H2, JPA, WEB > Finish
pom.xml:--
<!-- spring-boot-starter-data-jpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
@Entity //Mandatory
public class Product {
@Id //Mandatory
@GeneratedValue
private Integer prodId;
private String prodName;
private double prodCost;
private String prodColor;
//super constructor
public Product() {
super();
}
//Id (PK) based constructor
public Product(Integer prodId) {
super();
this.prodId = prodId;
}
//Parameterized constructor without Id(PK)
public Product(String prodName, double prodCost, String prodColor) {
super();
this.prodName = prodName;
this.prodCost = prodCost;
@Repository //Optional
public interface ProductRepository extends JpaRepository<Product, Integer>
{ }
Step#4:- CommandLine Runner for testing (BasicOperations.java):--
package com.app.repo.impl;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import com.app.model.Product;
import com.app.repo.ProductRepository;
@Component
public class BasicOperations implements CommandLineRunner{
@Autowired
private ProductRepository repo;
@Override
public void run(String... args) throws Exception {
/*1.*****************Save*******************/
//1. Method
repo.save(new Product("PEN", 6.8, "BLUE"));
/*2.*****************Find*******************/
//2.1 method.
Optional<Product> p = repo.findById(3);
if(p.isPresent())
{
System.out.println(p.get());
} else {
System.out.println("No Data found");
}
//2.2 Method.
repo.findAll().forEach((System.out::println));
/*3. *****************Delete****************/
//3.1 Delete by specific Id
repo.deleteById(3);
//3.2 Delete all Rows one by one in (Sequence order)
repo.deleteAll(); //Multiple Query fired No of record = no of Query
//3.3 Delete all rows in Batch (Single Query fired)
repo.deleteAllInBatch();
}
}
Output:--
=>Click on connect.
1>findBy :-- It will generate select query based on abstract method given by
programmer. We can provide columns and rows details.
=>It will be converted to equal SQL query based on Database at runtime.
Syntax:--
RT findBy______(Parameters …);
Here, RT = ReturnType, ex: List<T>, T, Object, Page<T>, Slice<T>, Object[], Specific
Projection etc.
@SpringBootApplication
public class SpringBootSjpaFindByMethodsApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootSjpaFindByMethodsApplication.class, args);
System.out.println("Main Method Executed");
}
}
2>Model class (Product.class):--
package com.app.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
@Table(name="product")
public class Product {
@Id
@GeneratedValue
private Integer prodId;
private String prodCode;
private String prodName;
private double prodCost;
//super constructor
public Product() {
super();
}
//Id (PK) based constructor
public Product(Integer prodId) {
super();
this.prodId = prodId;
}
//Parameterized constructor
public Product(String prodName, double prodCost, String prodCode) {
super();
this.prodName = prodName;
this.prodCost = prodCost;
this.prodCode = prodCode;
}
public Product(Integer prodId, String prodName, double prodCost, String prodCode)
{
super();
this.prodId = prodId;
this.prodName = prodName;
this.prodCost = prodCost;
this.prodCode = prodCode;
}
@Repository
public interface ProductRepository extends JpaRepository<Product, Integer> {
//Select * from prodtab where pid<=? And pcost>=? And vendor is not null order by
pcode;
//List<Product>
findByProdIdLessThanAndProdCostGreaterThanAndVendorNotNullOrderByProdCode
(Integer prodId, Double prodCost);
}
@Service
public class FindByRunner implements CommandLineRunner
{
@Autowired
private ProductRepository repo;
@Override
public void run(String... args) throws Exception {
Product p = repo.findByProdCode("A");
System.out.println(p);
repo.findByProdCodeIsNull().forEach((System.out::println));
}
}
Output:--
application.properties:--
server.port=2019
spring.datasource.driverClassName=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe
spring.datasource.username=system
spring.datasource.password=system
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.database-platform=org.hibernate.dialect.Oracle10gDialect
@SpringBootApplication
public class SpringBootDataJpaQueryParamApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootDataJpaQueryParamApplication.class, args);
System.out.println("Main Method Executed ");
}
}
2.> Model class(Product.java):--
package com.app.model;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class Product {
@Id
private Integer prodId;
private String vendorCode;
private String prodName;
private Double prodCost;
public Product() {
super();
}
public Product(Integer prodId) {
super();
this.prodId = prodId;
}
public Product(Integer prodId, String vendorCode, String prodName, Double prodCost)
{
super();
@Repository
public interface ProductRepository extends JpaRepository<Product, Integer> {
/***************NON-Select Operation********************/
@Modifying //non-select operation
@Transactional //service Layer
@Query("update Product p set p.vendorCode=:a, p.prodCost=:c where
p.prodId=:b")
void updateMyData(String a, Double c, Integer b);
@Component
public class SelectOperationUsingQueryParam implements CommandLineRunner {
@Autowired
private ProductRepository repo;
@Override
public void run(String... args) throws Exception {
//Normal Method
/*repo.save(new Product(10, "A", "PEN", 10.5));
repo.save(new Product(20, "B", "PENCIAL", 50.5));
repo.save(new Product(30, "C", "MOBILE", 700.5));
repo.save(new Product(40, "D", "LAPTOP", 1000.5));
repo.save(new Product(50, "E", "MOUSE", 500.5));
ProductRepository code:--
@Modifying //non-select operation
@Transactional //service Layer
@Query(“update Product p set p.prodCode=:a, p.prodCost=:c where p.prodId=:b”)
void updateMyData(String a, Double c, Integer b);
3. PROJECTIONS:--
=>By default every Query method (findBy__) return all columns (full loading).
=>Here Projections are used to select few columns (variables).
=> Projections are two types
Static Projections
Dynamic Projections
Step#2:- Copy variable equal getter method (getMethods()) from model class to child
interface.
Step#3:- Use that child Interface as ReturnType for findBy() findBy methods.
Format:
SYNTAX:
Interface _______Repository extends JpaRepository<…>{
Interface <childType> {
DataTypegetVariable();
DataTypegetVariable();
}
List<childType>findBy___(…);
}
@Entity
public class Product {
@Id
private Integer prodId;
private String vendorCode;
private String prodName;
private Double prodCost;
public Product() {
super();
}
public Product(Integer prodId) {
super();
this.prodId = prodId;
}
public Product(Integer prodId, String vendorCode, String prodName, Double
prodCost) {
super();
this.prodId = prodId;
this.vendorCode = vendorCode;
this.prodName = prodName;
this.prodCost = prodCost;
}
public Integer getProdId() {
return prodId;
}
public void setProdId(Integer prodId) {
this.prodId = prodId;
}
public String getVendorCode() {
return vendorCode;
}
public void setVendorCode(String vendorCode) {
this.vendorCode = vendorCode;
}
interface MyView {
//Copy from getter method (RT and methodName)
String getVendorCode();
String getProdName();
Double getProdCost();
}
//select code, cost from prodtab where ven_code=?
List<MyView> findByVendorCode(String vc);
}
3. CommandLineRunner code:--
package com.app.runner;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class MyRunner implements CommandLineRunner{
@Autowired
private ProductRepository repo;
@Override
public void run(String... args) throws Exception {
repo.save(new Product(10, "A", "PEN", 10.5));
repo.save(new Product(20, "B", "PENCIAL", 50.5));
repo.save(new Product(30, "C", "LAPTOP", 700.5));
repo.save(new Product(40, "B", "MOBILE", 800.5));
List<MyView> p = repo.findByVendorCode("B");
for(MyView p1:p)
{
System.out.println(p1.getVendorCode()+","+p1.getProdName()+","+p1.getProdCost());
}
}
}
4. application.properties:--
server.port=2019
spring.datasource.driverClassName=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe
spring.datasource.username=system
spring.datasource.password=system
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.database-platform=org.hibernate.dialect.Oracle10gDialect
Output:--
Code Changes:--
1. Repository code:--
package com.app.repo;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.app.model.Product;
@Repository
public interface ProductRepository extends JpaRepository <Product, Integer> {
@Autowired
private ProductRepository repo;
@Override
public void run(String... args) throws Exception {
Note:--
=>Dynamic Projections are slow compare to static Projections.
=>For dynamic Projections “Type selection, validate and execution” done at Runtime,
where as for static select and validate done at compile time, only execution done at
runtime.
=>Static Projections also called as compile time (selected) Projections and Dynamic
Projections also called as Runtime (selected) Projections.
=>These are Special type outputs for Query methods to get “Pagination data”.
1. Streamable(I):-- It will help to return Collection data (one page only) in Stream<T>
(java.util) format,where we can apply functions like filter, sort, map and collect…etc
2. Slice(I):-- It is used to provide current page data and links with previous and next
page details
** It never holds all pages details like total no.of pages and total Elements.
3. Page(I):-- It is extension to Slice and holds even total no.of pages (links to other
pages) and total Elements (total rows details).
=-=-=-=application.properties=--=-=-=
spring.datasource.hikari.connection-timeout=20000
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.maximum-pool-size =12
spring.datasource.hikari.idle-timeout =300000
spring.datasource.hikari.max-lifetime =12000
spring.datasource.hikari.auto-commit =true
=-=-=-=application.yml=--=-=-=
spring:
datasource:
hikari:
connection-timeout:20000
minimum-idle: 5
maximum-pool-size: 12
idle-timeout: 300000
max-lifetime: 12000
auto-commit: true
CHAPTER#3 MONGODB
1. Introduction:--
Step#2:- Choose “Server” option and select details OS, Version and package (MSI)
then click on download.
Details:
Version : 3.6 or 3.4
Type : MSI (Do not use ZIP)
Step#5:- Create service (server) folder in C:/ drive looks like “C:/data/db”.
NOTE:-- Here folder name can be any things.
=>Here Tables are called Collections. Rows are called as JSON objects.
=>MongoDB holds data in JSON format created from java object.
i.e one Java Object <=>One JSON object.
=>But, MongoDB follows (NoSQL concepts. It contains Collections (behaves like tables,
but not).
=>Collection holds data in JSON format.
a. One class = One collection.
b. One Object = one JSON Row.
=>Every class must be called as Document which can have generated ID (UUID type).
ORM (SQL):--
Class ---------------------------------- Table
(Model) (DB)
(NoSQL):--
Class ---------------------------------Collection
(Document) (DB)
=>To work with MongoDB using spring boot we need to add its starter looks like.
<dependency>
<groupId>ord.springframework.boot</gropId>
<artifactId>spring-boot-starter-data-mangodb</artifactId>
</dependency>
=>We can work with Installed MongoDB or embedded MongoDB. In case of embedded
use dependency in pom.xml (remove <scope>test </scope>).
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
</dependency>
=>Boot also supports Embedded MongoDB for every coding and Testing Process.
=>Embedded MongoDB can be used in Dev, Test, Uat, but not in Production
Environment.
2. Embedded MongoDB:--
Coding Steps:-- Embedded MongoDB
Step#1:- Create one starter project.
=>File => new => Spring Starter Project
=>Enter name : “SpringBootMangoDBEmbedded”
=>next => Search using “mongo”
=>Choose 2 dependencies
->Spring Data MongoDB
->Embedded MongoDB database
Document class:--
package com.app.document;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document
public class Product {
@Id
private String id;
private Integer prodId;
private String prodName;
private Double prodCost;
public Product() {
super();
}
public Product(Integer prodId, String prodName, Double prodCost) {
super();
this.prodId = prodId;
this.prodName = prodName;
this.prodCost = prodCost;
}
public Product(String id, Integer prodId, String prodName, Double prodCost) {
super();
this.id = id;
this.prodId = prodId;
this.prodName = prodName;
this.prodCost = prodCost;
}
@Component
public class ProductRunner implements CommandLineRunner{
@Autowired
private ProductRepository repo;
@Override
public void run(String... args) throws Exception {
repo.deleteAll();
repo.save(new Product(10, "Mobile", 567.8));
repo.save(new Product(11, "Laptop", 867.8));
repo.save(new Product(12, "Computer", 467.8));
System.out.println("------------");
repo.findAll().forEach(System.out::println);
}
}
*** Run Starter class.
Output:--
Note:--
a. @Document is optional, but good practice to write must be provided in case of
multiple concepts used to application.
b. @Id is also optional provide a variable named as “id” of type String only.
c. @Id need to be provided in case of variable names is not ‘id’. Else value will be null.
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 111
[Raghu Sir] [NareshIT, Hyd]
Ex:-
@Id
private String id;
d. @Id type must be String only. Integer, Double… not accepted. It is UUID (Hexa
Decimal value) which can be stored in string Datatype only.
e. In case of wrong data type is used variable creation then boot throws Exception as :
can’t autogenerate id of type java.lang.Integer for entity of type com.app.document !
for example code :
@Id
private Integer id;
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=sathya
spring.data.mongodb.username=sa
spring.data.mongodb.password=sa
application.yml :--
spring:
data:
mongodb:
host: localhost
port: 27017
database: sathya
username: sa
password: sa
pom.xml:--
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 113
[Raghu Sir] [NareshIT, Hyd]
</parent>
<groupId>com.app</groupId>
<artifactId>MongoDBExternal</artifactId>
<version>1.0</version>
<name>MongoDBExternal</name>
<description>Spring Boot MongoDB Connectivity Application</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties:--
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=abc
@Component
public class MongoDBExternalAllBasicOperation implements CommandLineRunner {
@Autowired
private EmployeeRepo repo;
@Override
public void run(String... args) throws Exception {
repo.save(new Employee(10, "UDAY", "Hyd"));
repo.findAll().forEach(System.out::println);
}
}
1. Console Output:--
a. List/Set/Array :--
=>In case of java these are different but coming to JSON format holds as group of
elements. Format is given as : [“value”, “value”].
application.properties:--
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=sathya
1. Document class:--
package com.app.document;
import java.util.Arrays;
import java.util.List;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Id //UUID
private String id;
private String bookCode;
private String bookAuth;
private Double bookCost;
//Collection dataType
private List<String> codes;
private String[] grades;
public Book() {
super();
}
public Book(String bookCode, String bookAuth, Double bookCost, List<String>
codes, String[] grades) {
super();
this.bookCode = bookCode;
this.bookAuth = bookAuth;
this.bookCost = bookCost;
this.codes = codes;
this.grades = grades;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getBookCode() {
return bookCode;
}
public void setBookCode(String bookCode) {
this.bookCode = bookCode;
}
@Component
public class BookRunner implements CommandLineRunner {
@Autowired
private BookRepository repo;
@Override
public void run(String... args) throws Exception {
repo.deleteAll();
repo.save(new Book("REDR", "Uday Kumar", 45.76,
Arrays.asList("A1","A2"), new String[]{"A","B","C"}));
repo.save(new Book("REDS", "Venkat Reddy", 85.26,
Arrays.asList("B1","B2"), new String[]{"X","Y","Z"}));
repo.findAll().forEach(System.out::println);
System.out.println("Completed");
}
}
Console Output:--
b. Map/Properties:-- It holds data in 2D format i.e key =value format. JSON holds 2D
as another JSON (child JSON) looks like {“key” : “val”, “key”: ”val”, “key” : “val”…..}
for both Map and Properties
application.properties:--
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=sathya
1. Collection class:--
package com.app.document;
import java.util.Map;
import java.util.Properties;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document
public class Book {
@Id
private String id;
private String bookCode;
private String bookAuth;
private Double bookCost;
private Map<String, String> forms;
private Properties models;
3. Runner class:--
package com.app.runner;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import com.app.document.Book;
import com.app.repo.BookRepository;
@Autowired
private BookRepository repo;
@Override
public void run(String... args) throws Exception {
repo.deleteAll();
Map<String, String> m1 = new HashMap<>();
m1.put("A1", "B1");
m1.put("A2", "B2");
Properties p1 = new Properties();
p1.put("M1","N1");
p1.put("M2","N2");
repo.save(new Book("JAVA", "Rama", 33.34, m1, p1));
System.out.println(".....................");
repo.findAll().forEach(System.out::println);
System.out.println("fiished");
}
}
Console Output:--
** In MongoDB : (Operation)
=>db.book.find().pretty();
application.properties:--
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=sathya
spring.data.mongodb.username=SA
spring.data.mongodb.password=SA
1. Collection classes:--
a. Address.java (Child class):--
package com.app.document;
public Address() {
super();
}
@Document
public class Employee {
@Id
private String id;
private Integer empId;
private String empName;
private Address addr; //Has-A
@Component
public class ConsoleRunner implements CommandLineRunner {
@Autowired
private EmployeeRepository repo;
=>Press Enter
Successfully added user: { "user" : "SA", "roles" : [ "readWrite", "dbAdmin" ] }
Screen Shot:--
Step#8:- ** Now, goto Spring Boot application and add below key=val pairs.
application.properties:--
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=sathya
spring.data.mongodb.username=SA
spring.data.mongodb.password=SA
@Document
public class Employee {
@Id
private String id;
private Integer empId;
private String empName;
private Double empSal;
public Employee() {
super();
}
public Employee(Integer empId, String empName, Double empSal) {
super();
this.empId = empId;
this.empName = empName;
this.empSal = empSal;
}
public Employee(String id, Integer empId, String empName, Double empSal) {
super();
this.id = id;
this.empId = empId;
this.empName = empName;
this.empSal = empSal;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
3. Runner class#1:--
package com.app.runner;
import java.util.Arrays;
import java.util.List;
@Component
public class ConsoleRunner implements CommandLineRunner {
@Autowired
private EmployeeRepository repo;
@Override
public void run(String... args) throws Exception {
@Component
public class saveOrInsertRunner implements CommandLineRunner {
@Autowired
private EmployeeRepository repo;
@Override
public void run(String... args) throws Exception {
repo.deleteAll();
=>Code is same as above runner code just replace save with insert.
Q> What is the difference b/w save() and insert() method in MongoDB Operations?
Save() Insert()
=>save() define in CrudRepository. =>insert() method define in
MongoRepository in Boot 1.7 version (not
exist in before version).
=>Save() method updates if ID exist in =>where insert() throws Exception
Collection As : MongoWriteException E11000
duplicate key error collection:
hello.employee index: -id-dup key: { :
“1234ad”}
NOTE:-In other cases (if id is null or id not exist) then both behaves as insert new JSON
Row only
** Spring Boot MongoRepository (I) supports all pagination and sort methods for
findAll() method (same as JPA).
@Component
public class PaginationAndSortMethod implements CommandLineRunner {
@Autowired
private EmployeeRepository repo;
@Override
public void run(String... args) throws Exception {
repo.deleteAll();
System.out.println("------------------------------------");
repo.saveAll(Arrays.asList(new Employee(10, "Uday", 67.76),
new Employee(11, "Venkat", 98.36), new Employee(12, "Neha", 37.46)
));
repo.findAll().forEach(System.out::println);
System.out.println("-------------------------------------");
repo.findAll(Sort.by(Direction.DESC, "empSal"))
.forEach(System.out::println);
repo.findAll(PageRequest.of(0, 2)).forEach(System.out::println);
}
}
=>FC, ViewResolver, HandlerMapper taken care by Boot, Controller and UI files should
be defined by Programmer.
Data Rendering:-- Reading data from Model (I) or ModelMap(C) at runtime and send
to UI is known as Data Rendering, It is implemented using EL Programming.
=>Programmer should provide inputs like port number view resolver details using
Properties or yml file. Example files like:
=>Default port no mapped to ‘8080’ by using key ‘server.port’. We can change even.
=>Spring boot has provided 3 embedded servers. [No download and No install]
Those are : Tomcat (default server), Jetty and Undertow.
=>In General Tomcat container 2 engines Servlet Engine (Catalina) and JSP Engine
(JASPER). In Spring boot, tomcat comes with only Servlet engine. That’s why it is also
called as light weight engine that works for “DispatcherServlet”, nothing else.
=> Default Static Resource Handler is added to folder static and template which are
provided under src/main/resources folder.
=>To work with JSP files in Spring Boot WEB apps, we need to add dependencies in
pom.xml.
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope> //Version taken care by Spring boot (and Tomcat)
</dependency>
=>To avoid/remove tomcat server (default server) from Boot application, we need to
add <Exclusion> for Tomcat under web dependency. Given as,
<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>
Execute commands:-
Step#1:- Do JDK setup.
Step#2:- Clear target folder.
Step#3:- Generate jar/war file.
=>Refresh target folder after message “build success”.
=>To indicate Spring container, spring f/w has provided two container interfaces.
Those are.
a. BeanFactory (I) [Legacy]
b. ApplicationContext (I) [new]
=>In case of Spring Application for web Programming Programmer has to define
Configuration code as.
Ex:--
@Configuration
@ComponentScan (basePackage=”---“)
public class AppConfig {----}
=>We can run Starter class only one time if type is web application with one port
number.
=>If we want to run again, then must stop last process which is already running.
->Goto Console option.
->Look at Console Symbol.
->Click on DropDown (In case of multiple).
->Click on Red Color Box Symbol (Stop Symbol).
Diagram:--
=>URL gets changed from server to server where as URI remains same.
=>If URL doesn’t contain any PORT number then default mapped to ‘80’ [HTTP Default
port number].
Ex:-- http://locahost/MyApp/show
->In above example PORT number is : 80
***It means if server is running on PORT number: 80, then PORT number not required
to write in URL.
Ex#1:--
application.properties:--
server.port=9898
server.servlet.context-path=/myapp
spring.application.name=SAMPLEAPP
Ex#2:--
application.properties:--
server.port=80
server.servlet.context-path=/myapp
Ex#3:--
application.properties:--
server.servlet.context-path=/myapp
Coding Steps:--
Step#1:- Create one Spring Boot Starter application and choose dependencies ‘Spring
Web Starter’.
Step#2:- Open pom.xml file and add below dependency to work with JSP pages only.
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
@Component
@RequestMapping("emp")
public class EmployeeController {
@RequestMapping("show")
public String showPages(Model m) {
m.addAttribute("msg", "Welcome App:" +new Date());
return "Home";
}
}
Step#6:- Define JSP Page under ‘views’ folder
=>Right click on ‘views’ folder => new => other
=>Search and choose ‘JSP file’ => Next
=>Enter name ex : Home.jsp
Home.jsp:--
<html><body><h2>Welcome to Boot!!</h2>
${msg}
</body></html>
** Run Starter class and Enter URL in Browser
http://localhost:9898/myapp/emp/show
Output:--
NOTE:-- In above example “AppInt” and AppConfig” are provided by spring Boot.
Annotation like @EnableWebMvc, @ComponentScan, @PropertySource not required
to provide.
Design:-
Step#2:- application.properties
DataSource, JPA, Server, Mvc (Suffix, Prefix)
1. application.properties:--
##Server##
server.port=2019
server.servlet.context-path=/myapp
##WEB MVC##
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
##DataSource##
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe
spring.datasource.username=system
spring.datasource.password=system
application.yml:--
##Server##
server:
port: 2019
servlet:
context-path: /myapp
##WEB MVC##
spring:
mvc:
view:
prefix: /WEB-INF/views/
suffix: .jsp
##DataSource##
datasource:
driver-class-name: oracle.jdbc.driver.OracleDriver
url: jdbc:oracle:thin:@localhost:1521:xe
username: system
password: system
##JPA##
jpa:
show-sql: true
hibernate:
ddl-auto: create
properties:
hibernate:
dialect: org.hibernate.dialect.Oracle10gDialect
format_sql: true
@Entity
//@Table(name="PRODUCTTAB")
@Data
public class Product {
//@Id
@Column(name="id")
@GeneratedValue
private Integer id;
@Column(name="code")
private String code;
@Column(name="name")
private String name;
@Column(name="cost")
private Double cost;
@Column(name="gst")
private String gst;
@Column(name="note")
private String note;
}
@Repository
public interface ProductRepository extends JpaRepository <Product, Integer> {
Product getProductById(Integer id);
}
4. Service Interface (ProductService.java):--
package com.app.service;
import java.util.List;
import com.app.model.Product;
@Service
public class EmployeeServiceImpl implements ProductService {
@Autowired
private ProductRepository repo;
@Controller
@RequestMapping("/emp")
public class ProductController {
@Autowired
private ProductService service;
Output:--
<td><a href="edit?id=${ob.id}">EDIT</a></td>
Dependency:--
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<dependency>
=>Choose Spring DevTools while creating your project.
Diagram:--
Locations are:-
META-INF/maven/** META-INF/resources/**,
resources/** static/**,
public/** template/**,
**/*Test.class **/*Tests.class,
git.properties, META-INF/build-info.properties
1. To avoid extra files which need to be re-loaded can be given key (with example
values) spring.devtools.restart.additional-exclude=/sample/app.properties
=>To specify location which need to be included for re-loading (key-val example) use
key: spring.devtools.restart.additional-paths=static/**, templates/**
3. Thymeleaf (UI):--
=>It is a UI technology used to implement Dynamic web pages with Lightweight UI
engine.
=>Compared to JSP its coding and memory is less and execution is faster.
=>JSP (JASPER) is a heavy weight engine; Thymeleaf is a light engine (less memory).
a>Translation:-- In this phase both static content and dynamic content are converted
to JAVA format.
b>Compilation:-- JASPPER converts __.java file into __.class format (heavy weight file
= static code in dynamic format).
=>To enable Thymeleaf UI in Spring boot apps add below starter in pom.xml.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
=>To read collection data and Iterate (loop) use Thymeleaf code.
th:each=”tempvar:${CollectionKey}”
Example:--
<tr th:each="ob:${products}">
<td th:text="${ob.prodCode}"></td>
<td th:text="${ob.prodCost}"></td>
</tr>
Code:--
Step#1:- Create one Spring boot Starter Project
Name : SpringBootWebMVCWithThymeleaf
Dependencies : Web, Thymeleaf
1. Model class:--
package com.app.model;
import lombok.Data;
import javax.persistence.Id;
import javax.persistence.Table;
@Data
@Entity
@Table(name="employeeTab")
public class Employee {
@Id
private Integer empId;
private String empName;
private Double empSal;
}
2. Controller class:--
package com.app.controller;
import java.util.Arrays;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.app.model.Employee;
@Controller
public class EmployeeController {
@RequestMapping("/reg")
public String regPage(ModelMap map) {
//Form Backing Object
Employee e= new Employee();
map.addAttribute("employee", e);
return "Register";
}
@RequestMapping(value="/save", method=RequestMethod.POST)
public String saveData(@ModelAttribute Employee employee, ModelMap map)
{
map.addAttribute("emp", employee);
b. Info.html:--
<html xmlns:th="http://www.thymeleaf.org/">
<body>
Your form data is : <div th:text="${emp}"></div>
</body>
</html>
c. Data.html:--
NOTE:--
#1:-- Here th:field=”*{variable}” links one form Input /select/text area with one
ModelAttribute( Form Backing Object) variable.
Example, consider below code
<input type=”text” th:field=”*{empId}”>
Then it looks like.
#2:-- At <form> tag level we need to provide URL (action) using format.
th:action=”@{/path}”
Ex:-- <form…. th:action=”@{“save”}…>
=>It create two way binding. It means form data will be converted to object and object
data can be shown at UI form.
#4:--All these Thymeleaf tags/attributes are defined in Thymeleaf engine. Its location
(xml Namespace) must be provided at UI file level using code:
<html xmlns:th=http://www.thymeleaf.org/>
=>To implement Cache Management in Spring Boot Application. We should use any
one vendor. ex: HazelCast Cache
=>First, we need to indicate “Create Cache Memory at application side, using class
Config (com.hazelcast.config)”.
***This Cache Memory can also be called as “HazelCast Instance”.
=>To enable cache for one module, use MapConfig(C) object and provide details like
“name, lifeTime, cacheSize, Eviction…” one time.
=>This MapConfig (C) can be repeated for multiple module [i.e one module = one
MapConfig object].
=>MapConfig stores data in key=val format Here key=PrimaryKey (ID) and val=Model
class object.
UML DESIGN:--
=>Here, Config is used to create Cache Instance where as MapConfig is used to module
memory. Example, looks like below.
Hazelcast-cache Config :-- It is a 3rd party Cache configuration process, supported for
any java application caching.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast</artifactId>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-spring</artifactId>
</dependency>
Step#2:- On starter class level we need to specify enable annotation for Cache
Management.
@EnableCaching
Step#3:- Model class which needs cache support must implement one interface
java.io.serializable
Ex:-- class Employee implements Serializable { }
package com.app.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.hazelcast.config.Config;
import com.hazelcast.config.EvictionPolicy;
import com.hazelcast.config.MapConfig;
import com.hazelcast.config.MaxSizeConfig;
import com.hazelcast.config.MaxSizeConfig.MaxSizePolicy;
@Configuration
public class MyCacheConfig {
@Bean
public Config cacheConfig() {
return new Config()
.setInstanceName("hazelCast-instance")
.addMapConfig(
new MapConfig()
.setName("emp-cache")
.setTimeToLiveSeconds(2000)
.setMaxSizeConfig(
new MaxSizeConfig(200, MaxSizePolicy.FREE_HEAP_SIZE))
.setEvictionPolicy (EvictionPolicy.LRU)
);
}}
Step#5:- At service Layer methods need to apply cache annotation given by spring.
a. @Cacheable:- This one must be applied over select method (getOneById).
b. @CacheEvict:- This one must be applied over delete method (deleteById).
c. @CachePut:- CachePut annotation is used to update object in cache before
updating in Database.
A >Over getOne (findOne) method @Cacheable(value=”cache-name”, key=”#PKId”)
b>Over delete method (delete byId) @CacheEvict(vale=”cache-name”, key=”#PKId”)
Coding order:--
1. Model class : Employee.java
2. Repository : EmployeeRepo.java
3. Service (I) : IEmployeeService
And Impl (C) : CustomerServiceImpl.java
4. Controller : EmployeeController
5. UI : a. Register.html
b. Data.html
c. View.html
Note:--
1. Thymeleaf UI default prefix is “template” folder and suffix is “.html”.
2. URL-Rewriting:- Creating URL with static path and dynamic path.
Ex:-- @{/employee/delete/{id}=${ob.custId}}} will be converted to (ex)
http://... Employee/delete/101
3. To read this ID value in Controller, use Path Variable Annotation Syntax:
@PathVariable Integer id
4. At ServiceImpl (C) need to apply Transaction Management using annotation:
@Transactional (readOnly=true) for select
@Transactional for non-select methods
1>Starter class:--
package com.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class SpringBootHazelCastCacheApplication {
@Configuration
public class MyCacheConfig {
@Bean
public Config cacheConfig() {
return new Config()
.setInstanceName("hazelCast-instance")
.addMapConfig(
//add per module one MapConfig
new MapConfig()
.setName("emp-cache")
.setTimeToLiveSeconds(2000)
.setMaxSizeConfig(
new MaxSizeConfig(200, MaxSizePolicy.FREE_HEAP_SIZE))
.setEvictionPolicy (EvictionPolicy.LRU)
);
}
}
3>Model class (Employee.java):--
package com.app.model;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import lombok.Data;
4>Repository (EmployeeRepository.java):--
package com.app.repo;
import org.springframework.data.jpa.repository.JpaRepository;
import com.app.model.Employee;
@Service
public class EmployeeService implements IEmployeeService {
@Autowired
private EmployeeRepository repo;
@Transactional
public Integer saveEmployee(Employee e) {
/*Employee e1=repo.save(e);
Integer id=e1.getEmpId();
return id;*/
return repo.save(e).getEmpId();
}
@Transactional(readOnly = true)
public List<Employee> getAllEmployees() {
return repo.findAll();
}
@Transactional(readOnly = true)
@Cacheable(value="emp-cache", key="#empId")
public Employee getOneEmployee(Integer empId) {
Optional<Employee> e= repo.findById(empId);
if(e.isPresent()) {
return e.get();
}
return null;
}
@Override
@CachePut(value="emp-cache", key="#empId")
public void update(Employee e) {
repo.save(e);
}
}
7>EmployeeController:--
package com.app.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import com.app.model.Employee;
import com.app.service.IEmployeeService;
@Controller
@RequestMapping("/employee")
public class EmployeeController {
@Autowired
private IEmployeeService service;
b>Data.html:--
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org/">
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head><body>
<h3>Welcome to All Records Page</h3>
<table border="1">
<tr>
<th>ID</th>
<th>CODE</th>
<th>NAME</th>
<th>TYPE</th>
<th>SALARY</th>
<th>ADDR</th>
<th colspan="2">OPERATIONS</th>
</tr>
<tr th:each="ob:${list}">
<td th:text="${ob.empId}"></td>
<td th:text="${ob.empCode}"></td>
<td th:text="${ob.empName}"></td>
<td th:text="${ob.empType}"></td>
<td th:text="${ob.empSal}"></td>
<td th:text="${ob.addr}"></td>
<td>
<a th:href="@{/employee/view/{id}(id=${ob.empId})}">VIEW</a>
</td>
<td>
<a th:href="@{/employee/delete/{id}(id=${ob.empId})}">DELETE</a>
</td>
</tr>
</table>
<span th:text="${message}"></span>
</body></html>
<tr>
<th>CODE</th>
<td th:text="${ob.empCode}"></td>
</tr>
<tr>
<th>NAME</th>
<td th:text="${ob.empName}"></td>
</tr>
<tr>
<th>TYPE</th>
<td th:text="${ob.empType}"></td>
</tr>
<tr>
<th>TYPE</th>
<td th:text="${ob.empSal}"></td>
</tr>
<tr>
<th>NOTE</th>
<td th:text="${ob.addr}"></td>
</tr>
</table></body>
</html>
//http://localhost:2019/myapp/employee/reg
=>In above output we can see the only single select query even if we are click on
multiple times on “View/Select” option.
Task:--
#1:- Implement Edit Operation for Module
2>Methods in controller
a>showEditPage with Object
b>updateData with Object
#2:-- Define Service Layer method i.e Update()) with Transaction Management and
Cache Annotation “CachePut”.
#3:-- Define Edit.html using Thymeleaf
=>CachePut annotation is used to update object in cache before updating in Database.
1>@CacheEvict :-- This annotation is used to remove object from cache (not from DB).
=>On calling service.delete..() method, SQL query delete row only in DB but not in
cache.
=>At same time object to be removed from cache, for that add this Annotation over
delete(..) method in service layer.
3> CachePut:-- This annotation is used to update object in cache before updating in
Database.
NOTE:--
Define one MapConfig memory for one module cache.
new MapConfig().setName(“prod-cache”);
Provide EvictionPolicy.
**If cache is full and another object is in waiting state to get into cache then
EvictionPolicy will not allow another obj. (Default is : NONE).
**EvictionPolicy .LRU : Will remove last accesses Object (Least Recently Used)
from cache.
5. Lombok API:--
=>This is open source JAVA API used to avoid writing (or generating) common code for
Bean/Model/Entity classes.
That is like:
1.>Setters and Getters
2.>toString() method
3.>Default and Parameterized Constructor
4.>hashCode() and equals() methods.
=>Programmer can write these methods manually or generate using IDE. But if any
modification (s) are done in those classes then again generate set/get methods also
delete and write code for new : toString, hashCode, Equals and Param const (it is like
represented task).
(for Spring Boot Project: Do not provide version provided by spring boot Parent only.)
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
Screen#2:--
=>Finish.
Example Application:--
Step#1:- Create Spring Boot Starter Project
=> File => new =>Spring Starter Project
=>Enter Details
GroupId : com.app
ArtifactId : SpringBootLombok-API
Version :1.0
=>Choose dependency : Lombok (only)
@Component
public class MyRunner implements CommandLineRunner {
System.out.println(e2.equals(e1));
}
}
NOTE:-- Apply @Data (package : Lombok.Data) over Bean/Model which generates
Getter, Setter toString, equals, hashCode and RequiredArgsConstructor ( ).
Example:--
@Data
public class Employee {…}
Ex:--
package com.app.model;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Data;
@Data
@Table
public class Employee {
@Id
private Integer empId;
//@NonNull
private String empName;
private Double empSal;
}
NOTE:-- For more details about Lombok follow bellow links
https://projectlombok.org/changelog
Types of server:--
a. DEV / QA Server
b. UAT Server (User Acceptance Test):- Client does testing before purchase the
project/product.
c. Production Server :-- Application placed in real-time server and this can be
accesses by end users.
d. MS service (Management Support).
a>Logger:-- This object need to be created in class which needs Logging concept.
=>If Logger object is created then Logging is enabled for that class, else not.
=>All classes may not need Logger object, Example Model class.
=>Logger object can be created using Different Vendors few are: Apache Log4J, SELF4J,
Java UTIL Logging, JBoss Logging, Apache JCL (Commons Logging)…etc.
b>Appender :-- It indicates where to store Log messages Possible Appender are.
1>ConsoleAppender (C)
2>FileAppender *** (C)
3>SmtpAppender (C)
4>TelnetAppender (C)
5>JdbcAppender (C)
=>FileAppender is mostly used one for projects which stores all log messages in
---.log file.
NOTE:-- In one Application we can use more than one Appender also.
=>In development mostly used Appender is FileAppender and Layout is Pattern Layout.
=>If No appender is provided to Logger object then Log4J throws WARNING as log4j :
WARN No appenders could be found for logger (com.app.Product).
=>At last Appender object must be added to Logger Object then only it is considered
by using log.addAppender() method.
Log4j.properties:-- This file is used to provide all the configuration details of Log4J.
Especially like appender and layout details with Pattern and also root Logger details.
=>We should not create Appender in every class only logger object must be created in
a class.
=>Data will be shown in below order like
1. rootLogger
2. appenders
3. layouts
Format : Log4j.properties
log4j.rootLogger=PRIORITY, APPENDER NAMES, ….
log4j.appender.<name>.layout=…..
a>SLF4J API:--
private static Logger log = LoggerFactory.getLogger(----.class);
b>Apache Log4J:--
private static Logger log = LogManager.getLogger(----.class);
Step#2:- Provide Appender and Layout details using Properties files/yml file in Boot.
NOTE:- Application No need to create another log4j.properties file.
=>Default logging level in INFO.
application.properties:--
logging.level.root=INFO
logging.file=d://logs/my.log
logging.level.org.springframework=error
logging.pattern.file=%p %d{dd-mm-yy}%L %c[%m]-%d %n
logging.pattern.console=%d{yyyy-mm-dd HH:mm:ss}-%m %n
Dependencies:--
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
<version>1.3.8.RELEASE</version>
</dependency>
application.properties:--
logging.level.root=INFO
logging.file=d://logs/myapp.log
logging.level.org.springframework=ERROR
logging.level.org.apache=DEBUG
logging.file.max-size=1MB
logging.file.max-history=5
logging.pattern.file=%p %d{dd-mm-yy}%L %c[%m]-%d %n
logging.pattern.console=%d{yyyy-mm-dd HH:mm:ss}-%m %n
@Component
public class ConsolerRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
//Apache log4j
private static Logger log = LogManager.getLogger(ConsolerRunner.class);
s.start("Block#2");
for (int i=0; i<=9999; i++) {
double d = Math.random();
d=Math.sin(d);
d=Math.abs(d);
}
s.stop();
long ms=s.getTotalTimeMillis();
double sec = s.getTotalTimeSeconds();
log.info("Block end:"+ms);
log.info(s.prettyPrint());
Step#1:- Go Eclipse market place and search with “ANSI Console” and install the
software for supporting of ANSI scape sequences.
spring.output.ansi.enabled=ALWAYS
=>Spring Boot mail API is defined on top of JAVA Mail API which reduces common lines
of code for Email Application.
=>To implement Email Service, we need to provide below keys in
application.properties file.
=>Example given with Gmail Server Details.
Application.properties:--
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=udaykumar461992@gmail.com
spring.mail.password=Uday1234
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
application.yml:--
spring:
mail:
host: smtp.gmail.com
port: 587
username: udaykumar461992@gmail.com
password: Uday1234
properties:
mail:
smtp:
auth: true
starttls:
a. FileSystemResource :-- This is used to load one file from System drives.
(ex:- d:/images/mydata).
b. ClassPathResource:-- If file is available in src/main/resources folder then use this
concept.
Step#1:-- Create Spring Boot starter Application using dependency : Java Mail Sender
1. application.properties:--
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=udaykumar461992@gmail.com
spring.mail.password=Uday1234
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
2. EmailUtil.java:--
package com.app.util;
import javax.mail.internet.MimeMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
@Component
public class EmailUtil {
@Autowired
private JavaMailSender mailSender;
try {
//1. Create MimeMessage object
MimeMessage message=mailSender.createMimeMessage();
if(file!=null)
helper.addAttachment(file.getFilename(),file);
@Component
public class ConsoleRunner implements CommandLineRunner {
@Autowired
private EmailUtil util;
@Override
public void run(String... args) throws Exception
{
//ClassPathResource file=new ClassPathResource("abc.txt");
FileSystemResource file=new FileSystemResource("F:\\Uday Kumar\\Photo.jpg");
boolean flag=util.send("udaykumar0023@gmail.com", "AA", "Hello", file);
if(flag) System.out.println("SENT");
else System.out.println("CHECK PROBLEMS");
}
}
Product.java
@Transient
private String email;
package com.app.util;
import javax.mail.internet.MimeMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
@Component
public class EmailUtil {
@Autowired
private JavaMailSender mailSender;
try {
flag=true;
} catch (Exception e) {
flag=false;
e.printStackTrace();
}
return flag;
}
}
application.properties:--
## SERVER ##
server.port=9090
server.servlet.context-path=/myapp
## WEB MVC ##
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
## JPA ##
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
spring.jpa.properties.hibernate.format-sql=true
## Email ##
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=udaykumar461992@gmail.com
spring.mail.password=Uday1234
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
1>Model class:--
package com.app.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.springframework.data.annotation.Transient;
import lombok.Data;
@Entity
@Data
@Table(name="producttab")
public class Product {
@Id
@Column(name="pcode")
private String code;
@Column(name="pname")
private String name;
@Column(name="pcost")
private Double cost;
@Column(name="pgst")
private Integer gst;
@Column(name="pnote")
private String note;
@Transient
private String email;
}
2>ProductRepository:--
package com.app.repo;
import org.springframework.data.jpa.repository.JpaRepository;
import com.app.model.Product;
3>IProductService:--
package com.app.service;
import java.util.List;
import com.app.model.Product;
4>ProductServiceImpl:--
package com.app.service.impl;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.app.model.Product;
import com.app.repo.ProductRepository;
import com.app.service.IProductService;
@Service
public class ProductServiceImpl implements IProductService {
@Autowired
private ProductRepository repo;
@Transactional
public Integer saveProduct(Product p) {
//calculations here..
//gstAmt= cost*gst/100
//totalAmt=cost+ gstAmt - disc
p=repo.save(p);
return p.getId();
}
@Transactional(readOnly= true)
public List<Product> getAllProducts() {
return repo.findAll();
}
@Transactional(readOnly=true)
public Product getProductById(Integer id) {
Optional<Product> p=repo.findById(id);
return p.get();
}
}
5>EmailUtil.java:--
package com.app.util;
import javax.mail.internet.MimeMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
@Component
public class EmailUtil {
@Autowired
private JavaMailSender mailSender;
flag=true;
} catch (Exception e) {
flag=false;
e.printStackTrace();
}
return flag;
}
}
6>ProductController:--
package com.app.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
@Controller
@RequestMapping("/product")
public class ProductController {
@Autowired
private IProductService service;
@Autowired
private EmailUtil mailUtil;
<!DOCTYPE html>
<html><head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<h3>WELCOME TO PRODUCT REGISTER</h3>
<form:form action="save" method="POST" modelAttribute="product"
enctype="multipart/form-data">
<pre>
<c:if test="${'EDIT' eq Mode }">
ID : <form:input path="id" readonly="true"/><br>
</c:if>
CODE : <form:input path="code"/><br>
NAME : <form:input path="name"/><br>
COST : <form:input path="cost"/><br>
GST : <form:select path="gst">
<form:option value="5">5%-SLAB</form:option>
<form:option value="12">12%-SLAB</form:option>
<form:option value="18">18%-SLAB</form:option>
<form:option value="22">22%-SLAB</form:option>
<form:option value="30">30%-SLAB</form:option>
</form:select>
Execution:-- Run the application and type the below URL in browser.
http://localhost:9090/myapp/product/reg
Output:--
*** Use Spring Validation API to avoid null or empty message (even Mail formats).
Ex:-- To address cannot be null Email is invalid format subject is required
Text min 10 Characters. (Validate messages)
Batch:-- Multiple Operations are executed as one Task or one large/Big Task executed
step by Step.
=>Every task is called as “JOB” and sub task is called as “STEP”.
=>One JOB can contain one or more Steps (Step can also called as Sub Task).
=>One Step contains.
a. Item Reader (Read data from Source).
b. Item Process (Do calculations and logics/operations etc…).
c. Item writer (Provide output to next Step or final output).
Step Implementation:--
=>In a Job (work) we can define one or multiple steps which are executed in order
(step by step).
=>Job may contain 1 step, job may contain 2 step…… job may contains many Steps so,
finally 1-job = * (many) Step.
=>Every step having 3 execution stages
a. ItemReader<T>
b. ItemProcessor<I, O>
c. ItemWriter<T>.
b>ItemProcessor<I, O> :-- It is used to process input data given by Reader and returns
in Modifier (or same) format of data.
c>ItemWriter<T> :-- It will read bulk of Items from Processor at a time and writes to
one destination. Even Destination can be a File (ex: DB, Text File, CSV, EXCEL,
XML…etc).
=>To start Job, we need one JobLauncher… which works in general way or Scheduling
based.
=>Here details like: Job, Steps, Launcher… are store in one memory which is called as
JobRepository [Ex: H2DB or MySQL, DB … any one DB].
NOTE:--
1. An Item can be String, Array, Object of any class, Collection (List/Set….).
2. ItemReader will read one by one Item from Source. For example Source has 10
items then 10 times ItemReader will be executed.
3. ItemReader GenericType must match with ItemProcessor Input GenericType.
4. ItemProcess will read item by item from Reader and does some process (calculate,
convert, check conditions, and convert to any class Object etc…).
5. ItemProcessor will provide output (may be same as Input type) which is called as
Transformed Type.
6. ItemWriter will collect all output Items into one List type from Processor at a time
(Only one time).
7. ItemWriter writes data to any destination.
=>Here T/I/O can be String Object of any class or even collection (List, Set…).
=>Here ItemReader reads data from source with the helps of steps.
=>Reader and Processor are executed for every item, but writer is called based on
chunk size.
Ex:-- No. of Items = 200, chunk=50 then Reader and Processor are executed 200 times
but writer is called one time after 50 items are processed (Here 4 times executed).
=>ItemWriter writes data to destination with the help of step.
=>Programmer can define above interfaces Impl classes or can be also use exist
(pre-defined) classes.
=>Reader, Writer, Processor is functional interfaces. We can define them using
Lambda Expression and methods references even.
2>Job Creation:-- One job is collection of Steps executed in order (one by one).
=>Even job may contain one Step also. Here, job is interface which is constructed using
“JobBuilderFactory <C>” and Step (I) instances.
=>To execute any logic before or after job, define Impl class for “JobExecutionListener
(I)” having method
Like: beforeJob(…) : void and
afterJob(…) : void
=>Here Listener is optional, It may be used to find current status of Batch (Ex:
COMPLETED, STOPTES, FAILED…) start date and time, end date and time etc.
3>Job Execution:-- Once Steps and job are configured, then we need to start them
using “JobLauncher (I)” run(…) method.
=>This run(…) method takes 2 parameters
a. Job (I) and
b. JobParameter (C)
=>Here, JobParameters (C) are inputs given to Job While starting this one.
Ex:- Parameters are : Server Data and Time, Customer Name flags (true/false), Task
Name… etc.
=>JobParameters (C) object is created using “JobParametesBuilder” and its method
toJobParameters().
Step :-- One Step can be constructed using StepBuilderFactory (sf) class by providing
name, chunk size, reader, processor and writer.
StepBuilderFactory (sf):--
sf.get(“step1”) =>Provide name of Step.
.<String, String> chunk(1) => No. of Items to be read at a time.
.reader (readerObj) =>Any Impl class of IteamReader<T> (I)
.processor(processorObj) =>Any Impl class of itemProcessor <I, O>
.writer(writerObje =>Any Impl class of ItemWriter <T> (I)
.build(); =>Convert to step (impl class) Object.
UML Notation:--
JobBuilderFactory jf :--
Jf.get(“jobA”) =>Job Name
.incremental(runIdIncrementar) =>Incrementer
.listener (jobExListener) =>Job Execution Listener
.start (stepA =>First Step
JobExecutionListener (I):--
=>This Interface is provided Spring Batch f/w, which gets called automatically for our
Job.
=>For one job – one Listener can be configured.
=>It is an Interface which has provided two abstract methods.
a. beforeJob (JobExecution) : void
b. afterJob (JobExecution) : void
=>If we write any impl class for above Listener (I) we need to implement two abstract
method in our class.
=>Some times we need only one method in our class file afterJob() method is required.
Then go for JobListenerAdapter(C) which has provided default impl logic for both
beforeJob; and afterJob(); methods.
=>JobExecution is a class which is used to find current job details like jobParameters,
BatchStatus, stepExecutions etc…
Step#1:- Define one Spring Starter Project and select Spring Batch or else add below
dependencies.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
Coding order:--
1. Reader
2. Processor
3. Writer
4. Step Configuration using StepBuilderFactory
5. JobExecutionListener
6. Job Config –job BuilderFactory
7. JobParameters using JobParametersBuilder
8. JobLauncher using CommandLineRunner
9. ** Add key in application.properties
Spring.batch.job.enabled=false
=>To avoid execution of job multiple times (by Starter class)
application.properties:--
#Disable this otherwise job executed one time by SpringBoot on startup
And also one more time by our launcher
spring.batch.job.enabled=false
spring.batch.initialize-schema=always
spring.datasource.driverClassName=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe
spring.datasource.username=system
spring.datasource.password=system
1>DataReader:--
package com.app.batch.reader;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.NonTransientResourceException;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;
import org.springframework.stereotype.Component;
@Override
public String read() throws Exception, UnexpectedInputException,
ParseException, NonTransientResourceException {
if(index < message.length)
{
return message[index++];
} else {
index=0;
}
return null;
}
}
2. DataProcessor:--
package com.app.batch.processor;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.stereotype.Component;
@Component
public class DataProcessor implements ItemProcessor<String, String> {
@Override
public String process(String item) throws Exception {
return item.toUpperCase();
}
}
3. DataWriter:--
package com.app.batch.writer;
import java.util.List;
import org.springframework.batch.item.ItemWriter;
import org.springframework.stereotype.Component;
@Component
public class DataWriter implements ItemWriter<String> {
@Configuration
@EnableBatchProcessing
public class BatchConfig {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public Job jobA() {
return jobBuilderFactory.get("jobA")
.incrementer(new RunIdIncrementer())
.listener(listener())
.start(stepA())
//.next(step)
@Component
public class MyJobListener implements JobExecutionListener {
@Override
public void beforeJob(JobExecution jobExecution) {
System.out.println(jobExecution.getStartTime());
System.out.println(jobExecution.getStatus());
}
@Override
public void afterJob(JobExecution jobExecution) {
System.out.println(jobExecution.getEndTime());
System.out.println(jobExecution.getStatus());
}
}
6. MyJobLauncher.java:--
package com.app.batch.runner;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
@Component
public class MyJobLauncher implements CommandLineRunner {
@Autowired
private JobLauncher jobLauncher;
@Autowired
private Job job;
@Override
public void run(String... args) throws Exception {
JobParameters jobParameters = new JobParametersBuilder()
.addLong("time", System.currentTimeMillis())
.toJobParameters();
jobLauncher.run(job, jobParameters);
}
}
Output:--
2. Spring Boot Batch Processing : Converting .csv file data to DataBase table:--
=>Consider input data given by csv file is related to products having product id, name,
cost, by using one item reader convert .csv file data to Product class object.
=>Define one Processor class to calculate gst (Goods and Service Tax) and discount of
product.
=>Finally Product should have id, name, cost, gst, discount.
=>Use one ItemWriter class to convert one object to one Row in DB table.
=>In realtime CSV (Comma Separated Values) Files are used to hold large amount of
data using symbol / Tokenizer ‘,’ or (It will be , . -, \, /).
=>This data will be converted to one Model class(T) object format.
=>It means one line data(id, code, cost…) converted to one java class object by Reader.
=>Calculate Discount and GST… etc using Processor class. Processor may return same
class (or) different Object (i.e I==O)
=>Based on chunck(int) size all objects returned by Processor will be collected into one
List by Writer.
=>Every Object in List will be converted into its equal “INSERT SQL…”.
=>Multiple SQLs are converted to one JDBC Batch and sent to DB at a time.
=>No of calls between Writer and Database depends on chunk size (and no of Items).
FlatFileItemReader:---
=>This class is provided by Spring Batch to read data from any Text Related file
(.txt, .csv,...).
Execution Flow:--
=>Spring Boot Batch f/w has provided pre-defined ItemReaders and ItemWriters.
=>FlatFileItemReader <T> is used to load any file (source) as input to read data
example .txt, .csv,… etc.
=>It will read one line data based on LineMapper (\n).
=>One Line data is divided into multiple values based on Tokenizer (Delimitar = ,).
=>These values are mapped to one class (T) type object also known as Target.
=>Here job.enabled=false will disable execution of job by one time on app starts by
Starter class.
=>Initialize-schema=always will allow Spring Batch to communicate DB to hold its
Repository details (like Job, Step, current status details…).
=>***In case of Embedded Database initialize-schema not required.
application.properties:--
spring.batch.job.enabled=false
spring.batch.initialize-schema=always
spring.datasource.driverClassName=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe
spring.datasource.username=system
spring.datasource.password=system
@Data
public class Product {
private Integer prodId;
private String prodName;
private Double prodCost;
private Double prodGst;
private Double prodDisc;
}
@Override
public Product process(Product item) throws Exception {
item.setProdGst(item.getProdCost()*12/100.0);
item.setProdDisc(item.getProdCost()*25/100.0);
return item;
}
}
3. BatchConfig.java:--
package com.app.config;
import javax.sql.DataSource;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.
EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.database.
BeanPropertyItemSqlParameterSourceProvider;
import org.springframework.batch.item.database.JdbcBatchItemWriter;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import com.app.model.Product;
import com.app.process.ProductProcessor;
@Bean
public Step stepA() {
return sf.get("stepA")
.<Product, Product> chunk(3)
.reader(reader())
.processor(processor())
.writer(writer())
.build();
}
//JOB
@Autowired
private JobBuilderFactory jf;
@Bean
public Job jobA() {
return jf.get("jobA")
.incrementer(new RunIdIncrementer())
.start(stepA())
.build();
}
}
//dataSource -- Creates DB connection
@Bean
public DataSource dataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("oracle.jdbc.driver.OracleDriver");
ds.setUrl("jdbc:oracle:thin:@localhost:1521:xe");
ds.setUsername("system");
ds.setPassword("system");
return ds;
}
@Component
public class MyJobLauncher implements CommandLineRunner{
@Autowired
private JobLauncher jobLauncher;
@Autowired
private Job job;
@Override
public void run(String... args) throws Exception {
jobLauncher.run(job,new JobParametersBuilder()
.addLong("time",System.currentTimeMillis())
.toJobParameters());
}
}
----------------------------------------------------------------------------------------------------------------
DB Table:-- Execute below SQL query before execution of program to create table.
SQL>CREATE TABLE prodstab (PID number (10), PNAME varchar2 (50), PCOST number,
PGST number, PDISC number);
Task:--
#1. Write Spring boot Batch Application To read data from database (Oracle DB) using
“JdbcCursorItemReader” and write data to csv file using “FlatFIleItemWriter”.
#2. Write data from MongoDB using “MongoItemReader” and write data to JSON file
using “JsonFIleItemWriter”.
=>All these are functional Interface (contains only one (1) abstract method.
So Logic can be provided to these interfaces using Lambda Expression.
Lambda Exp:--
@Bean
ItemProcessor<Product, Product> process() {
return (p) -> {
double cost=p.getCost();
p.setDisc(cost*3/100.0);
p.setGst(cost*12/100.0);
return p;
};
}
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 246
[Raghu Sir] [NareshIT, Hyd]
***Different ways of creating object and calling method:--
Consider below class:--
class Sample {
Sample() {
System.out.println("Constructor");
}
void show () {
System.out.println("Method");
}
}
Text class:--
public class WayOfCreatingObject
{
public static void main(String[] args) {
//3. Creating object (add extra code, override methods) and calling method
new Sample () {
public void show() {
System.out.println("NEW LOGIC");
}
}.show();
package Com.app;
public class Test
Public static void main {
1. Introduction:--
=>To implement ReSTFul webservices API using simple annotations and Templates
Spring boot ReST F/w has been introduced.
=>Even to implement Microservices design Spring boot ReST API is used.
NOTE:--
a.>Consumer and Provider interchanges the data Primitive (String format only), Class
Type (Object) and Collections.
b.>Data will be converted to either JSON or XML format also known as Global Formats
c.> String data will be converted to any other type directly.
d.>ReST Controller supports 5 types of Request Methods Handling. Those are HTTP
Method : GET, POST, PUT, DELETE and PATCH.
e.>Controller class level use annotations @RestController (Stereotype),
@RequestMapping (for URL).
f.>Controller methods level use annotations.
TYPE Annotations
GET @GetMapping
POST @PostMapping
PUT @PutMapping
DELETE @DeleteMapping
PATCH @PatchMapping
TYPE Annotation
url?key=val @RequestParam
/url/val/ @PathVariable
/url/key=val @MatrixVariable
Http Header @RequestHeader
Http Body @RequestBody
***All above annotations works on HttpRequest only, supports reading input data.
h.>By default Matrix Parameter is disabled (may not work properly). To enable this
write below code in MVC config file.
Example:--
package com.app.controller;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.util.UrlPathHelper;
@Configuration
public class AppConfig implements WebMvcConfigurer
{
@Override
public void configurePathMatch(PathMatchConfigurer configure)
{
UrlPathHelper helper= new UrlPathHelper();
helper.setRemoveSemicolonContent(false);
configure.setUrlPathHelper(helper);
}
}
i.>DispatcherServlet is autoConfigured in Spring Boot with URL Pattern mapped to /.
j.>AutoConfiguration Provided even for @EnableWebMvc,
@ComponentScan(Startsclass), @PropertySource(“ClassPath:application.propery”)
k.>Embedded server.
Step #2 :-- Writer one Controller class with class lever URL different method with HTTP
MethodTypes.
package com.app.controller;
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("/admin") //Optional
public class AdminRestController {
@GetMapping("/show")
public String helloMsgGet () {
return "Hello From GET";
-------------------POSTMAN SCREEN------------------
GET http://localhost: 2019/ myapp /admin/show SEND
Postman Screen:--
Code:--
package com.app.rest.controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/admin")
public class AdminRestController {
@PostMapping("/head")
public String readHead(@RequestHeader(required=false) String dept,
@RequestHeader ("Content-Type") String type, @RequestBody String mydata) {
return "Hello Head :"+dept+" ," +type+ ",Body:" +mydata;
} }
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 254
[Raghu Sir] [NareshIT, Hyd]
NOTE:--
Request Header is required (true) by default to make it optional, add code
required=false.
If key name localVariable Name same then providing key name is optional.
Request Body Raw data (Characters or any…).
Can be Stored in String with any variableName.
2>Request Body:-- To send large/bulk data like objects and collections data in the
form of JSON/XML.
=>Even supported large text (Raw data).
=>Spring boot enables JSON conversion by default, but not XML (no JAXB API).
3>Request Parameter:-- To pass primitive data (like id, name, codes … etc) as input,
request parameters are used.
=>format looks like url?key=val&key=val…
=>Both key and value are String type by default.
Syntax #1:-
@RequestParam("key") DataType localVariable
Ex#1: @RequestParam("sname") String sn
Syntax #2:-
@RequestParam DataType localVar
Ex#2: @RequestParam String sname
=>If key name and local variable name are same then key is not
Syntax #3:-
@RequestParam(required=false) DT localVariable
=>To make key-value is optional @RequestParam (required=false) String sname
Syntax #4:-
@RequestParam (required=false, defaultValue="-DATA-")DT localVariable
=>To change default value from null to any other value.
@RequestParam(required=false, defaultValue="No DATA") String sname
@RestController
public class AdminRestController
{
@GetMapping("/show")
public String showMsg(@RequestParam (value="sname", required=false,
defaultValue="NO DATA") String sid) {
return "Hello:" +sid;
}
}
Path Variable [Path Parameters]:--
=>We can send data using URL (path).
=>It supports only Primitive Data.
=>Static Path indicates URL, where as Dynamic Path indicates Data at runtime.
=>While sending data using Dynamic Path key should not be used. Only data
=>Order must be followed in case of sending multiple Parameters.
=>To read data at controller method, use annotation : @PathVariable.
Syntax:--
@PathVariable datatype keyName
Controller code:--
package com.app.controller.rest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
=>To Convert Object to JSON (and JSON to Object) SpringBoot uses JACKSON API.
Step #2:- Add below dependency in pom.xml for XML (JAXB) supports.
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
@XmlRootElement
public class Employee
{
private Integer empId;
private String empName;
private double empSal;
public Employee() {
super();
}
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 259
[Raghu Sir] [NareshIT, Hyd]
public Employee(Integer empId, String empName, double empSal) {
super();
this.empId = empId;
this.empName = empName;
this.empSal = empSal;
}
public Integer getEmpId() {
return empId;
}
public void setEmpId(Integer empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public double getEmpSal() {
return empSal;
}
public void setEmpSal(double empSal) {
this.empSal = empSal;
}
@Override
public String toString() {
return "Employee [empId=" + empId + ", empName=" + empName + ", empSal=" +
empSal + "]";
}
}
Step #4 Controller class:--
package com.app.controller.rest;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
public class EmployeeController
{
@GetMapping("/showA")
public String showA() {
return "Hello-String";
}
@GetMapping("/showB")
public Employee showB() {
return new Employee(22, "UDAY", 3.8);
}
@GetMapping("/showC")
public List<Employee> showC() {
return Arrays.asList(new Employee(22, "Uday", 6.8),
new Employee(23, "Neha", 6.8),
new Employee(24, "Ramu", 6.8)
);
}
@GetMapping("/showD")
public Map<String, Employee> showD() {
Map<String, Employee> map= new HashMap<>();
map.put("e1", new Employee(22, "UDAY", 4.6));
map.put("e1", new Employee(23, "NEHA", 8.2));
map.put("e1", new Employee(24, "RAJA", 9.5));
return map;
}
@GetMapping("/showE")
public ResponseEntity<String> showE() {
ResponseEntity<String> resp = new ResponseEntity<String> ("Hello RE ",
HttpStatus.OK);
1> http://localhost:2019/showA
2> http://localhost:2019/showB
3> http://localhost:2019/showC
4> http://localhost:2019/showD
Headers
Key Value
Accept application/xml
Output Screen:--
Spring Boot ReST + Data JPA +MySQL CRUD Operations (Rest API with Swagger):--
=>Here, define ReST Collector which works for JSON and XML Data input/output.
=>For Primitive inputs use PathVariable.
=>ReST Controller must return output type as ResponseEntity<T> which holds Body(T)
and HttpStatus Ex:-- 500, 404, 200, 400 etc..
=>Student.java = Model
=>StudentRepository.java = Repository
=>IStudentService.java = IService
=>StudentServiceImpl.java = Impl
Step#4:- In application.properties provide keys details server port, datasource and jpa
(dialect, show-sql…).
Step#5:- Define RestController
#34. Folder Structure of Spring Boot Rest with DataJpa and Swagger
Implementation:--
## Hibernate Config ##
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.database-platform=org.hibernate.dialect.Oracle10gDialect
@Entity
@XmlRootElement
@Table(name="emp_tab")
public class Employee {
@Id
@GeneratedValue
@Column(name="emp_id")
private Integer empId;
@Column(name="emp_name")
private String empName;
@Column(name="emp_sal")
private double empSal;
@Override
public String toString() {
return "Employee [empId=" + empId + ", empName=" + empName + ",
empSal=" + empSal + "]";
}
}
#5 ServiceImp class(EmployeeServieImpl.java):--
package com.app.service.impl;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.app.model.Employee;
import com.app.repo.EmployeeRepository;
import com.app.service.IEmployeeService;
@Service
public class EmployeeServiceImpl implements IEmployeeService {
@Transactional
public Integer saveEmployee(Employee e) {
return repo.save(e).getEmpId();
}
@Transactional
public void updateEmployee(Employee e) {
repo.save(e);
}
@Transactional
public void deleteEmployee(Integer id) {
repo.deleteById(id);
}
@Transactional(readOnly=true)
public Optional<Employee> getOneEmployee(Integer id) {
return repo.findById(id);
}
@Transactional(readOnly = true)
public List<Employee> getAllEmployees() {
return repo.findAll();
}
@Transactional(readOnly = true)
public boolean isPresent(Integer id) {
return repo.existsById(id);
}
}
#6 Controller class (EmployeeController.java):--
package com.app.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
@Controller
@RequestMapping("/rest/employee")
public class EmployeeController {
@Autowired
private IEmployeeService service;
Body
raw application/Json
{
“empName” : “Uday Kumar”,
“empSal” : 5563.3
}
Header
Key Value
Accept application/json
NOTE:-- If request Id is not present then Return Http Status – 400 BAD-REQUEST
Flow Meaning
->Docket () =>Create Docket
->select () =>Choose Rest classes
->apis(basepackage()) =>Classes are in package
->paths (regex()) =>Having common path
->build() =>Create final output
@Configuration
@EnableSwagger2
public class SwaggerConfig {
http://localhost:2019/rest/employee/save
{ "empId" : 10, "empName" : "Uday Kumar", "empSal" : 45.87}
Output:--
-------------------------------------------------------------------------------------------------------------------
email : javabyraghu@gmail.com
FB: https://www.facebook.com/groups/thejavatemple/
MICROSERVICES
1. Monolithic Application:--
A Project which holds all modules together and converted as one Service
(one .war file).
=>All most every project in realtime is implemented using this format only.
=>In this case, if no. of users are getting increased, then to handle multiple request
(load) use LBS (Load Balancing Server).
=>But few modules needs Extra load, not all. In this case other modules get memory
which is waste (no use). Hence reduces performance of server (application).
=>In above example, M2 Module is getting fewer (100) requests from Client. So, max 2
instances are may be enough. Other 2 instances (memories) are no use. It means near
100MB memory is not used, which impacts server performance.
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 278
[Raghu Sir] [NareshIT, Hyd]
2. Microservices:-- It is a independent deployment component.
=>It is a combination of one (or more) modules of a Projects runs as one Service.
=>To avaoid monolithic Limitations like memory and time (performance) problems use
this design.
Nature of Microservices:--
1>Every Service must be implemented using Webservices concept.
2>One or multiples module as one Project.
3>Every service must be independent (One service should not effect another one, like
for code modifications, version upgrades, downtime for few servers… etc).
4>It should able to communicate with any type of client (Mobile, Web based, 3 rd party).
5>Every Services should able to communicate with each other Microservice, It is also
called as “Intra Communication”.
6>Required Services must be supported for Dynamic Load Balancing (i.e. one service
runs in multiple instances) based on click request.
7>Every microservice should support able to read input data from External
Configuration Server [Config Server](Dynamic inputs using (_.properties/_.yml), with
GIT/Config Server).
8>Service communication (Chain of execution) problems should be able to solve using
Circuite Breaker [Find other possible…].
9>All Servers must be accessed to Single Entry known as Gateway Service [ Proxy
Gateway or API Gateway], It supports securing, metering and Routing.
Component Names:--
1>Service Registry & Discovery = Eureka
2>Load Balancing Server = Ribbon
3>Circuite Breaker = Hystrix
4>API Gateway = Zuul
5>Config Server = GitHub
6>Secure Server = OAuth2
7>Log and Trace = Zipkin + Sleuth
8>Message Queues = Kakfa
9>Declarative Rest Client = Feign
10>Integration Service = Camel
11>Production Ready Endpoint = Actuator
12>Metrics UI = Admin (Server/Client)
13>Cloud Platform = PCF, Docker
With Deploy services
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 280
[Raghu Sir] [NareshIT, Hyd]
SOA (Service Oriented Architecture):--
=>It is a Design Pattern used to create communication links between multiple services
providers and Consumers (users).
Components of SOA:--
a>Service Registry and Discovery [Eureka]
b>Service Provider [Webservice Provider]
c>Service Consumer [Webservice Client]
Operations:--
1>Publish
2>Discover
3>Link Details of Provider
4>Query Description (Make Http Request).
5>Access Service (Http Response).
@RestController
@RequestMapping("/provider")
public class AdminServiceProvider {
@GetMapping("/show")
public String showMsg() {
@Component
public class AdminConsumer implements CommandLineRunner {
#1 PROVIDER SCREEEN:--
CONSUMER SCREEN:--
Step #1: Create Eureka Server:-- Create one Spring Boot Starter Project with
Dependencies : Eureka Server
GroupId : org.verizon
ArtifactId : EurekaServerApp
Version : 1.0
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApp {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApp.class, args);
System.out.println("Eureka Server Executed:");
} }
Step #3:- In application.properties add keys
server.port=8761
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
Step #4:- Run starter class and Enter URL http://localhost:8761 in browser
NOTE:-- Default port no of Eureka Server is 8761.
Step #1:- Create one Spring starter App with web and Eureka Discovery Client
dependencies
GroupId : org.app
ArtifactId : StudentServiceProvider
Version : 1.0
pom.xml:--
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 289
[Raghu Sir] [NareshIT, Hyd]
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.app</groupId>
<artifactId>StudentServiceProvider</artifactId>
<version>1.0</version>
<name>StudentServiceProvider</name>
<description>Demo project for Microservice Studenet Provider</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Step #2:- Add below annotation at Starter class level @EnableEurekaClient (given by
Netflix) or @EnableDiscoveryClient (given by Spring Cloud) both are optional.
@SpringBootApplication
@EnableEurekaClient
public class StudentServiceProviderApp {
@RestController
@RequestMapping("/provider")
public class StudentProvider {
@GetMapping("show")
public String showMsg() {
return "Hello from Provider";
}
}
*** Hard coding:-- Providing a direct value to a variable in .java file or fixed value.
Ex:- int a = 5;
=>It provides always same output for multiple runs.
=>By using RestTemplate with URL (hard coded) we can make request. But it will not
support.
a>If provider IP/PORT number gets changed.
b>Load Balancing Implementation.
=>So, we should use Dynamic Client that gets URL at runtime based on Application
name registered in “Registry and Discovery Server (Eureka)”.
=>DiscoveryClient is used to fetch Instance based on Application Name and we can
read URI of provider at runtime.
=>RestTemplate uses URI (+path)= URL and makes Request to Provider and gets
ResponseEntity which is given back to the Consumer.
Microservices Example:--
=>If one Application is moved from one Server to another server then URI gets
changed (Paths remain same).
=>If one Project is running in 3 Server then current Project is having 3 instances. All
these are store in R & D Server and we can fetch details as : List<ServiceInstance>
Consumer code:--
Step #1:- Create one Spring Starter Project using Dependencies web, Eureka Discovery.
GroupId : org.app
ArtifactId : StudentServiceConsumer
Version : 1.0
StudentConsumer.java:--
package com.app.consumer;
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.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class StudentConsumer
@GetMapping("/consume")
public String consumeData ()
{
RestTemplate rt = new RestTemplate();
List<ServiceInstance> list=client.getInstances("STUDENT-PROVIDER");
ResponseEntity<String> resp =rt.getForEntity(list.get(0).getUri()+"/show", String.class);
return "FROM CONSUMER=>" +resp.getBody();
}
}
Execution order:--
#1 Run Starter classes in order:--
Eureka server, provider App, Consumer App
#2 Goto Eureka Server Dashboad and click on Client Consumer URI and enter
“/consume” path after PORT number (http://192.168.100.39:9852/consume).
c>Define consumer with any one Load Balancing Component (Ex:-- Ribbon, Feign).
d>Ribbon chooses one Provider URL, based on instance Id with the help of LBS register
which maintains request count.
e>Consumer will uses paths to URL and makes Request using “RequestClient”.
[ Ex:- LoadBalancerClient (I) or @FeignClient]
f>ResponseEntity is returned by Provider to Consumer.
5.1 Ribbon:-- It is a Netflix component provided for spring boot cloud Load Balancing.
=>It is also called as Client side load Balancing. It means Consumer App, reads URI
(which one is free) using LBS register.
=>Then two projects are created here.Order Application and Invoice Application.
=>Both apps contain their Service Producer codes (RestController).
=>This time child Producer will become ChildConsumer in ParentProducer application.
=>ChildConsumer and childProducer codes communicate using HTTP protocols.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
=>By default application behaves as ServiceId and InstanceId, but this time to provide
multiple InstanceIds use below key in properties file.
eureka.instance.instance-id=
Example: application.properties:--
spring.application.name=ORDER-PRO
eureka.instance.instance-id=${spring.application.name}: ${random.value}
Coding Steps:--
Step#1:- In provider, define Instance Id for Provider Application using key.
“eureka.instance.intance-id”. If not provided default is taken as Spring App name.
eureka.instance.instance-id=${spring.application.name}: ${random.value}
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 301
[Raghu Sir] [NareshIT, Hyd]
[Add in application.properties]
application.properties:--
server.port=8761
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
application.properties:--
server.port=9800
spring.application.name=ORDER-PROVIDER
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka
eureka.instance.instance-id=${spring.application.name}:${random.value}
=>If no instance-id is provided then application name (service Id) behaves as instance
Id.
#1. Starter class:--
package com.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class OrderServiceProviderApp
{
public static void main(String[] args)
{
SpringApplication.run(OrderServiceProviderApp.class, args);
}
}
#2. Controller:--
@RestController
@RequestMapping("order")
public class OrderProvider {
@Value("${server.port}")
private String port;
@GetMapping("/status")
public String getOrderStatus() {
return "FINISHED:\"Hello from Order Provider\":"+port;
}
}
APPLICATION#3:- Define Invoice Service Consumer(Parent):--
Dependencies : Eureka Discovery, Web, Ribbon
Ribbon Dependency:--
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 304
[Raghu Sir] [NareshIT, Hyd]
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
application.properties:--
server.port=8802
spring.application.name=INVOICE-CONSUMER
eureka.client.serviceUrl.defaultZone =http://localhost:8761/eureka
@Service
public class OrderConsumer {
@Autowired
private LoadBalancerClient client;
public String getStatus() {
String path="/order/status";
//Choose Service instance based on SID
ServiceInstance instance=client.choose("ORDER-PROVIDER");
//Read URI from instance
String uri=instance.getUri().toString();
//Make http Request
RestTemplate rt = new RestTemplate();
ResponseEntity <String> resp=rt.getForEntity(uri+path, String.class);
return "CONSUMER=>"+resp.getBody();
} }
#2 Controller code (InvoiceProvider):--
@RestController
@RequestMapping("/invoice")
public class InvoiceProvider {
@Autowired
private OrderConsumer consumer;
@GetMapping("/info")
public String getOrderStatus() {
return consumer.getStatus();
}
}
Execution:--
a>Start Eureka Server
b>Run OrderProvider starter class 3 times
*** Change every time Port number like : 9800,9801, 9802
c>Run InvoiceProvider Starter class
d>Goto Eureka server Dashboad and Execute Invoice Consumer Instance and
type full URL http://localhost:8800/invoice/info
OutPut:--
1. IModel interface:--
package com.app.reflation;
2. Employee Class:--
package com.app.reflation;
public Employee() {
System.out.println("Employee Constructor...");
}
@Override
public String getModelName() {
return "Employee";
}
@Override
public IModel getModelObject() {
return this;
}
Static Factory Design Pattern using Reflection API and JDK 1.8 Interface features:--
->Input (int)
1. Circle
2. Square
3. Triangle
Code:--
1. IShape Interface:--
package com.app;
//must be overridden
public void showInfo();
//can be overridden
public default void shapeMsg() {
System.out.println("Welcome to ShapeFactory");
}
//can not be overridden
public static void commonMsg() {
System.out.println("Hello Shape..");
}
}
2. Circle Class:--
package com.app;
public Square() {
System.out.println("Square object is created..");
}
public void showInfo() {
System.out.println("This is Square Shape ");
}
@Override
public void shapeMsg() {
IShape.super.shapeMsg();
System.out.println("Also Square message Printed..");
}
}
4. Triangle Class:--
package com.app;
public Triangle() {
System.out.println("triangle object is created");
}
public void showInfo() {
System.out.println("THis is triangle object");
}
}
5. ShapeFactory Class:--
package com.app;
String cls=null;
switch (ch) {
case 1:
cls="com.app.Circle";
break;
case 2:
cls="com.app.Square";
break;
case 3:
cls="com.app.Triangle";
break;
default:
break;
}
return cls;
}
}
6. Test Class:--
package com.app;
import java.util.Scanner;
Execute Jar:--
=>Goto Location where JAR is created
=>Shift + Right Click
=>Open cmd Window Here
=>type below command
‘java –jar factory.jar’
Myapp.bat:--
java -jar factory.jar
=>Feign Client is an Interface and contains abstraction details, it takes I/P details from
programmer like:
a>path (Provider Paths at class and method).
b>Http Method Type (GET, POST…).
@FeignClient(name="serviceId")
public interface <ClientName> {
@GetMapping("/path")
//or @RequestMapping(“/path”)
public <Return> <method>(<Params>);
...
}
Example:--
Provider Code (SID : EMP-PROV):--
com.app.rest;
@RestController
@RequestMapping("/emp")
public class EmpProvider {
@GetMapping("/show")
public String findMsg() {
……
}
}
Consumer Code : Feign Client
@FeignClient(name="EMP_PROV")
public interface EmpConsumer {
@GetMapping ("/emp/show")
public String getMsg(); //return type and path must be same as Provider
}
GroupId : org.app
ArtifactId : StudentServiceConsumerFeign
Version : 1.0
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class StudentServiceFeignClientApp {
@GetMapping("order/status")
public String getMsg(); //Path and Return type same as Provider method
}
Step#3:- Use in any consumer class (HAS-A) and make method call (HTTP CALL)
package com.app.consumer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.app.client.StudentFeignClient;
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 317
[Raghu Sir] [NareshIT, Hyd]
@RestController
public class StudentConsumer {
@Autowired
private StudentFeignClient client;
@GetMapping("consume")
public String showData()
{
System.out.println(client.getClass().getName());
return "CONSUMER=>"+client.getMsg();
}
}
NOTE:-- Here client.getMsg() method is nothing but HTTP Request call.
Execution Order:--
1>Start Eureka Server
2>Run Provider Application
3>Run Consumer Application and click on consumer App service id on Eureka Server
Dashboad and provider consumer method level path:
http://192.168.100.27:9841/consume
Step#1:- Create Spring Starter Project for Eureka Server with port 8761 and
dependency “Eureka Server”.
1>CartProviderApplication.java:--
package com.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class CartProviderApplication {
public static void main(String[] args) {
SpringApplication.run(CartProviderApplication.class, args);
}
}
2>Model class (Cart.java):--
package com.app.model;
//import lombok.Data;
//@Data
public class Cart {
//Default Constructor
public Cart() {
super();
}
//Parameterized constructor
public Cart(Integer cartId, String cartCode, Double cartFinalCost) {
super();
this.cartId = cartId;
this.cartCode = cartCode;
this.cartFinalCost = cartFinalCost;
}
//Set/get Method
public Integer getCartId() {
return cartId;
}
public void setCartId(Integer cartId) {
this.cartId = cartId;
}
public String getCartCode() {
return cartCode;
}
public void setCartCode(String cartCode) {
this.cartCode = cartCode;
}
public Double getCartFinalCost() {
return cartFinalCost;
}
public void setCartFinalCost(Double cartFinalCost) {
this.cartFinalCost = cartFinalCost;
}
@Override
public String toString() {
return "Cart [cartId=" + cartId + ", cartCode=" + cartCode + ",
cartFinalCost=" + cartFinalCost + "]";
}
}
3>Cart Service Provider code:--
package com.app.provider;
import java.util.Arrays;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.app.model.Cart;
@RestController
@RequestMapping("/cart")
public class CartServiceProvider
{
@Value("{server.port}")
private String port;
@GetMapping("/info")
public String getMsg() {
return "CONSUMER:"+port;
}
@GetMapping("/data")
public Cart getObj() {
return new Cart(109, "ABC: "+port, 7868.98);
}
@GetMapping("/list")
public List<Cart> getObjs() {
return Arrays.asList(
new Cart(101, "A :"+port, 876.98),
new Cart(102, "B :"+port, 856.98),
new Cart(103, "C :"+port, 883.98));
}
}
Step #3:- Payment Provider App with Cart Consumer code
Dependencies : web, Eureka Discovery, Feign
Feign Dependency:--
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
1>application.properties:--
server.port=9890
spring.application.name=PAYMENT-PROVIDER
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka
2>**At Starter class level add annotation : @EnableFeignClients
(PaymentProviderApplication.java):--
package com.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
public class PaymentProviderApplication {
@FeignClient(name="CART-PROVIDER")
public interface CartServiceConsumer
{
@GetMapping("/cart/info")
public String getMsg();
@GetMapping("/cart/data")
public Cart getObj();
@GetMapping("/cart/list")
public List<Cart> getBulk();
}
4>Model class (Cart.java):-- Cart Model class same as above Project
package com.app.model;
//Default Constructor
public Cart() {
super();
}
@Autowired
private CartServiceConsumer consumer;
@GetMapping("/message")
public String getMsg() {
return consumer.getMsg();
}
@GetMapping("/one")
public Cart getOneRow() {
return consumer.getObj();
}
@GetMapping("/all")
public List<Cart> getAllRows() {
return consumer.getBulk();
}
}
Step #4 Execution Order:--
=>Run Eureka Server
3>http://192.168.100.17:9890/payment/all
=>Config server Process maintains three (3) properties file. Those are:
a>One in = Under Project (Microservice)
b>One in = Config Server (link file)
c>One in = Config server (External) also called as Source file.
a>Native Config Server:-- It is also called as local file placed in Config server only. In
this case one properties file is created inside folder System (or drive).
Ex:-- D:/abc/myapp(Or Under config server location file).
b>External Config Server:-- In this case properties file is placed outside the Config
server. Ex: GIT (github).
=> Here, Properties file is placed in External and accesses using its URL. It is also called
as Global Location.
**”GIT HUB” is used in this process.
=>In Consumer/Producer Project we should add Config Client dependency which gets
config server details at runtime.
=>Config server runs at default port=8888.
GroupId : org.app
ArtifactId : Config-Server
Version : 1.0
Or
Create Git Project “configserverex” and create application.properties inside this. Place
above key and save file.
Step#4:- Provider include resource code in pom.xml to consider properties files to be
loaded into memory.
<resources>
<resource>
<filtering>true</filtering>
<directory>src/main/resources</directory>
<includes>
<include>*.properties</include>
<include>myapp-config</include>
</includes>
</resource>
</resources>
pom.xml:--
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
System.out.println("Config Server Executed");
}
Execution Order:--
=>Eureka Server
=>Config Server
=>Producer (Provider)
=>Consumer
Step#1:- Eureka Server Project Dependency : Eureka Server
=>Write application.properties.
=>Add @EnableEurekaServer annotation
server.port=8888
spring.cloud.config.server.git.uri=https://github.com/javabyraghu/configserverex
or
spring.cloud.config.server.git.uri=https://gitlab.com/udaykumar0023/configserverex
pom.xml:--
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<resource>
<filtering>true</filtering>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
</project>
Step#4:- Create git account and create configserverex Repository. Under this create
file application.properties.
Step#3:- Fill the details and click on Register Button else login with github or Google
Account If you have.
Step#8:-Final screen After Login into Gitlab account, Click on Create Group.
Step#11:- Click on Member Menu to add the new member into your project
=>Select Member form list, Role Permissions like (Guest, Reporter, Developer,
Maintainer, Owner) and Expire date and finally click on Add to Group.
Step#12:- Click on Group name (SpringCloudconfigserver) and then after click on New
Project to create a project.
Step16:- Provide the details in file and then click on commit changes.
=>Then Provider/Consumer Application (On Startup) will try to read k=v from Config
Server and merge with our application.properties.
=>If same key is found in both Config Server and Provider/Consumer App, then 1 st
priority is : Config Server.
=>After fetching all required props then Provider gets registered with Eureka Server.
spring.cloud.config.uri=http://localhost:8888
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 344
[Raghu Sir] [NareshIT, Hyd]
=>To modify above location (IP or PORT) provide this key in Config Client setup using
bootstrap.properties.
Ans:-- Our Project (child Project) contains input keys in application.properties, in same
way Parent Project also maintains one Properties file named as : bootstrap.properties
which will be loaded before our application.properties.
Step#1:- Open application.properties file in Config Server Project and modify port
number.
server.port =9999
spring.cloud.config.uri=http://localhost:8888
=>By default Config client will not get updates or modification from Config Server after
starting client + microservice.
=>Only first time config Client fetch the data even to get new Modification after
starting Client (without-Restart) use Annotation : @RefreshSocpe.
Q>Which class will load bootstrap.properties file for config Server URI fetching?
Ans:-- ConfigServicePropertySourceLocator will read config server input by default
from http://localhost:8888.
=>It is only first execution step in provider Consumer Project.
Provider/Consumer Application:--
Create any Microservice application with Dependencies : Web, Eureka Discovery,
Config- Client.
@SpringBootApplication
@EnableDiscoveryClient
@RefreshScope //Get updates from Config Server Automatically
public class OrderServiceProviderApp {
@RestController
@RequestMapping("/order")
public class OrderService {
@GetMapping("/status")
public String getOrderStatus() {
return "FINISHED : :"+port;
}
}
Step#3:-1>application.properties:--
server.port=7800
spring.application.name=ORDER-PROVIDER
eureka.client.serviceUri.defaultZone=http://localhost:8761/eureka
eureka.instance.instance-id=${spring.application.name}:${random.value}
management.endpoints.web.exposure.include=*
2>bootstrap.properties:--
spring.cloud.config.uri=http://localhost:8888
Execution Order:--
1. Eureka Server
2. Config Server
3. MicroServices (Order)
=>Enter URL : http://192.168.100.27:7800/order/status
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
NOTE:--
***Actuator refresh is ready-made service given by Spring boot that fetch the data
from Config Server location to ourApp.
=>It must be made as POST type request onl, using any http client (Ex: POSTMAN).
FallBackMethod Process:--
CircuitBreaker:--
Hystrix:--
It is an API (set of classes and interfaces) given by Netflix to handle Proper
Execution and Avoid repeated exception logic (Fault Tolerance API) in Microservice
Programming.
=>It is mainly used in production Environment not in Dev Environment.
=>Hystrix supports FallBack and CircuitBreaker process.
=>It provides Dashboard for UI to view current request flow and Status. (View
problems and other details in Services).
Step#3:-- Define one RestController with actual Service and fallback method and apply
Annotation : @HystrixCommand with Details like fallBackMethod, commandKey…
NOTE:-- Fallback method return type must be same as Actual Service method
pom.xml:--
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
HystrixServerApplication.java:--
package com.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
@RestController
public class OrderServiceProvider {
@GetMapping("/show")
@HystrixCommand(fallbackMethod="showFallBack")
//parameter must be same as fallBackMethod name
public String showMsg() {
System.out.println("From service");
if (new Random().nextInt(10)<=10) {
throw new RuntimeException("DUMMY");
}
return "Hello From Provider";
}
//fallBack method
public String showFallBack() {
System.out.println("From ballback");
return "From FallBack method";
}
}
NOTE:-- Fallback method returnType must be same as service method return type.
Step#5:- Goto Eureka and click on ORDER PROVIDER Instance and enter URL
path :/show (http://192.168.100.39:9800/show)
=>Referesh multiple times to, see console.
=>FallBack Method name can be any one. But Return Type must be same as
MQ = Message Queues
CS = Config Server
LBS = Load Balancing Server
ELK = Elastic Search –Logstash – Kibana
----------------------------------------------------------------------------------------------------------------
=>Spring Cloud Netflix ZUUL behaves as API PROXY for Microservices Application
which supports “Integration with any type of client component” (Web, mobile, 3 rd
party, webservices… etc).
=>In Zuul Server Project, we should provide module details like path, service-Id using
application.properties (or .yml)
=>If two modules are provided in ZUUL then, only module name gets changed in keys.
Consider below example:
application.properties:--
zuul.routes.product.path=/item-api/**
zuul.routes.product.service-id=ITEM-SERVICE
zuul.routes.student.path=/std-api/**
zuul.routes.student.service-id=STD-SERVICE
application.yml:--
zuul:
routes:
product:
path: /item-api/**
service-id: ITEM-SERICE
student:
path: /std-api/**
service-id: STD-SERVICE
=>Filters are used to validate request and construct valid response. In simple we can
also call as “PRE-POST” Processing Logic.
=>ZUUL Filter provides even extra types like ROUTE FILTERS and ERROR FILTERS.
=>ZUUL supports 4 types of filters implementation for Gateway service. Those are
=>In general our code (logic) is called as process. To execute extra code before our
logic and filter our logic, before choosing logic instance after throwing exception logic
filters are used
->When client made request to ZUUL then Pre Filter gets called automatically.
->After validating, request is dispatched to Route Filter.
->Route Filter is like 2nd level validation at Required SERVICE level.
->Route Filter will request to one Microservice based on Service-Id.
->If microservice is not executed properly (i.e throwing exception) then
Error Filter is called.
->Finally Post Filter works on Http Response (adds Headers, Encode data,
Provide info to client… etc) in case of either success or failure.
=>Here, Filter is a class must extends one abstract class “ZuulFilter” provided by
Netflix API.
=>We can define multiple filters in one Application. Writing Filters are optional.
=>While creating filter class we must provide Filter Order (0, 1, 2, 3…) and Filter Type
(“pre”, “route”, “error”, “post”)
=>Two filters of same type can have same Order which indicates any Execution order is
valid.
=>We can enable and disable Filters using its flags (true/false).
=>To indicate Filter Types, we use its equal constants (public static final String
variables), provided as.
=>All above Constants are defined in FilterConstants (C) as global variables (public
static final String).
=>Write one class in ZUUL Server and extends ZuulFilter Abstract class, override below
method (4) in your filter class.
a>shouldFilter():-- Must be set to ‘true’ If value is set to false then filter will not be
executed.
b>run():-- Contains Filter logic Executed once when filter is called.
c>filterType():-- Provide Filter Constant Must be one Type (pre, post, route, error).
d>filterOrder():-- Provide order for Filter Any int type number like 0, 56, 78.
@Component
public class FilterType extends ZuulFilter {
/**To enable or Disable current filter Enable(true) or Disable Filter(false)**/
public boolean shouldFilter() {
return true;
}
/**Define Filter Logic Here**/
public Object run() throws ZuulException {
System.out.println("FROM POST FILTER");
return null;
}
/**Specify Filter Type (Pre. Post…)**/
public String filterType() {
return FilterConstants.POST_TYPE;
}
/**Provider Filter Order for Execution if same type of filters are used**/
public int filterOrder() {
return 0;
}
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 363
[Raghu Sir] [NareshIT, Hyd]
=>FilterConstants is a class having static final variables like PRE_TYPE, POST_TYPE,
ROUTE_TYPE, and ERROR_TYPE (public static final String PRE_TYPE=”pre”).
=>FilterConstants even provide global standard constant details HTTP PORT =80,
HTTPS PORT:443.
Zuul Dependency:--
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
pom.xml:--
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
server.port=8558
eureka.client.service-url.default-zone=http://localhost:8761/eureka
package com.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
public class SpringCloudZuulApiGatewayApp {
public static void main(String[] args) {
SpringApplication.run(SpringCloudZuulApiGatewayApp.class, args);
System.out.println("Zuul Api Gateway Server is executed");
}
}
Step#4:- Implement Filters like :
PRE, ROUTE, POST, ERROR
using one abstract class : ZuulFilter (AC) and use FilterConstants (C).
#1. PreTypeFIlter.java:--
package com.app.filter;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.exception.ZuulException;
@Component
public class RouteTypeFilter extends ZuulFilter {
@Component
public class ErrorTypeFilter extends ZuulFilter{
#4. PostTypeFIlter.java:--
package com.app.filter;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.exception.ZuulException;
@Component
public class PostTypeFilter extends ZuulFilter{
Execution Process:--
->http://desktop-ch8lpuh:8558/cart-api/cart/info
a.>Data Streaming:-- Sending continous data between two application is called data
Streaming. In Real-time large data from Files, Networks, and Databases etc…
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 371
[Raghu Sir] [NareshIT, Hyd]
Ex:-GoogleMap updates for swiggy IRCTC Train updates where is my Train, Flights
enquiry and booking status.
b.>Web Activities:-- Sharing search information to partner applications (Know what
users are searching and provide related links and ADS in client websites).
Ex:- Google search data given to Cricbuzz, Amazon.
c.>Log Aggrigation:-- Sending log files data from current server to other servers to find
Exception and worning details.
=>Messages are exchanged using Message Broker called as MOM (Message Oriented
Middleware). Apache ActiveMQ is MOM Software.
Limitation of JMS:--
a.>Used between Java Applications.
b.>Message (Data) size should be smaller.
c.>Only one MOM (one instance) runs at a time.
d.>Large data takes lot of time to process.
e.>If Pub/Sub model is implemented with more consumers then process
will be very slow.
f.>Data may not be delivered (data lose) in case of MOM Stops or Restart.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
pom.xml:--
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 375
[Raghu Sir] [NareshIT, Hyd]
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.app</groupId>
<artifactId>Spring-Cloud-JMS-ActiveMQ</artifactId>
<version>1.0</version>
<name>Spring-Cloud-JMS-ActiveMQ</name>
<description>Demo project for Spring JMS Implementation</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
Step#3:- If application is Producer type then use JmsTemplate object and call send()
which will send message to MoM.
@SpringBootApplication
public class SpringBootJMSProducerApp {
public static void main(String[] args)
{
SpringApplication.run(SpringBootJMSProducerApp.class, args);
System.out.println("JMS Producer Executed :");
}
}
#2 MessageProducer.java:--
package com.app.producer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;
@Component
public class MessageProducer implements CommandLineRunner {
@Autowired
private JmsTemplate template;
@Override
public void run(String... args) throws Exception {
template.send("my-tpca", (ses)->ses.createTextMessage("AAAAAAAAA"));
System.out.println("sent from Producer");
}
}
Step#4:- If Application is Consumer type then define one Listener class using
destination.
NOTE:-- Create multiple consumer app in same or different workspaces and set.
spring.jms.pub-sub-domain=true
In application.properties file (or .yml).
@SpringBootApplication
public class SpringBootJMSConsumerApp {
@SpringBootApplication
public class SpringBootJmsActiveMqApp {
@JmsListener(destination="my-tpca")
public void getMsg(String msg) {
System.out.println("consumer#222");
System.out.println("Message is:=>"+msg);
}
}
NOTE:-- send (String destinationName, Message (Creator MSG);
=>This method is used to send message from producer Application to MOM.
=>if destination not exist in MOM, Creates new one else uses same.
Execution Order:--
1.>Active MQ Server.
2.>Producer Applicaion Starter class (One Provider App).
3.>Consumer Application Starter class (One or Multiple Consumer Application).
Execution process:--
Step#1:- Double click on activemq.bat file
Step#3:- Click on Queues (P2P)/TOPIC (Pub-Sub) Menu option to see message list.
=>In case of Interface is provided with abstract method then we need to provide
implementation using.
1>Child class
2>Anonymous inner class
3>Lambda Expression
=>Example#1:--
#1. Interface:--
public interface MessageCreator {
Message creatMessage (Session s) throws JMSException;
}
11. Spring Boot Apache Kafka Integration:-- Apache kafka is used for
=>Apache kafka supports AMQP for large data transfer for MQ applications over
network.
=>Supports Real-time Data Streaming. It means read continuous and large data from
external source like Float Files, Database, networks, etc…
a.>Kafka uses Message Broker also called as Broker Server which supports MQ
operations.
b.>Kafka supports Load Balancing for Broker Software to avoid more traffic, i.e. called
as Kafka cluster. In general cluster is a group of Broker servers (1 to n).
c.>Kafka supports only Topics (Pub/Sub Model) and it is only default also.
d.>Kafka Cluster Auto-Scaling is done by Bootstrap server (AKA Zookeeper). It behaves
as R&D Server.
Execution Flow:--
=>Producer Application should get Message Broker details from R & D Server
(zookeeper) known as bootstrap-server).
=>Producer gets unique-id (InstanceId) of Message Broker server and sends message
to Broker.Producer use KafkaTemplate<K, V> to send data to one Broker server.
=>Message Broker will send this message to one or multiple consumers.
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 385
[Raghu Sir] [NareshIT, Hyd]
=>Producer sends data <k, V> format in Serialized (Converting to binary/Characters
formats). Here K=Destination (Topic name) and V= Message.
=>Every Message will be partitioned into Multiple parts in Topic (Destination) to avoid
large data sending, by making into small and equal parts (some time size may vary).
=>Broker reads all partitions data and creates its replica (Clone/Mirror obj) to send
message to multiple consumers based on Topic and Group-Id.
=>At Consumer side Deserialization must be applied on K, V to read data. Consumer
should also be linked with bootstrap-server to know its broker.
=>Partitions are used to breakdown large message into multiple parts and send same
to multiple brokers to make data destination in parallel.
Message Replica:-- It creates multiple copies to one message to publish one message
to multiple Consumers.
=>By using this Spring Boot creates instance of “KafkaTemplate<K, V>” then we can
call send(k, v) method which will send data to Consumer.
=>By using this Spring Boot configures the Consumer application, which must be
implemented using : @KafkaListener(topics=”—“, groupId=”—“)
2>cluster.bat
=>Starts Zoopeer with Kafka Cluster design
.\bin\windows\kafka-server-start.bat .\config\server.properties
Coding Steps:--
groupId : com.app
artifactId : SpringBootKafkaApp
version : 1.0
Kafka Dependency:--
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
#17. Folder Structure of Kafka:--
#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: group-id
properties.yml:--
server:
port: 9988
my:
app:
topicname: sampletopic
spring:
kafka:
producer:
bootstrap-servers: localhost:9092
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer
consumer:
bootstrap-servers: localhost:9092
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
group-id: groupId
@Component
public class MessageStorage {
private List<String> list= new ArrayList<String>();
@Component
public class Consumer {
@Autowired
private MessageStorage storage;
@Component
@Value("${my.app.topicname}")
private String topic;
@Autowired
private KafkaTemplate<String, String> template;
@RestController
public class KafkaRestController {
@Autowired
private Producer producer;
@Autowired
private MessageStorage storage;
@RequestMapping("/send")
public String readInMessage(@RequestParam String message)
{
producer.sendMessage(message);
return "message sent!!";
}
Coding order:--
1. application.properties:--
2. MessageStorage.java
3. ConsumerService.java
4. ProducerRestConstroller.java
5. KafkaRestController.java
NOTE:-- Use KafkaTemplate <K, V> at producer application to send message(V) to
given Topic (K).
Execution Orde:--
1>Start the Zookeeper Server
2>Start kafks-server (Cluster)
3>Start Application Starter class (Provider, Consumer)
=>Compared to Spring Batch Integration tool Apache camel is a light weight tool.
=>Camel supports reading data from different sources even like HTTP, FTP, JMS
protocols based.
=>It supports data processing (convertions, calculations, like XML--->JSON,
JSON--->Object, Object--->XML, and XML ---> EXCEL etc.s
=>It has light weight engine, compared to spring Batch it is faster.
=>Camel mainly supports 3 operations:
a.>Routing :-- Data Transfer
b.>Processing :-- Data Convertion
[source-details]
.[filter-modes]
.[processing]
.[destination]
#1:- In pom.xml, we must add below dependency which supports Spring boot
integration.
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>2.23.2</version>
</dependency>
pom.xml:--
<?xml version="1.0" encoding="UTF-8"?>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>2.23.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Step#2:- Camel avoid main method (thread) execution control and run as independent
while working with Spring boot, our starter class is main method. So we should add
key=value in properties file as
application.properties:--
camel.springboot.main-run-controller=true
Step#3:- Define one RouteBuilder class and configure details of routing, filtering and
processing.
=>To implement this we need to write one Router class using “RoutingBuilder (AC)”
provided by Apache camel having one abstract method: configure() which contains
coding format like:
from (SourceLocation)
.[filter] . [process].
.to (DestinationLocation)
=>Here Location can be URL/Local File System DB, JMS (Message Queues)… etc.
Coding Steps:--
Step#1:- Create Spring Boot starter application with dependencies : Apache Camel
GroupId : com.app
ArtifactId : Spring-Boot-Apache-Camel
Version : 1.0
Step#2:- open application.properties (.yml) and add main method-control key as true.
application.properties:--
camel.springboot.main-run-controller=true
Step#3:- Define Router class with EIP pattern with file transfer logic.
package com.app.router;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;
@Component
public class MyFilesRouter extends RouteBuilder {
public void configure() throws Exception {
//with static location
from ("file:D:\\source").to("file:D:\\destination");
}
}
Step#4:- Create two folder : Source and Destination in any Drive (“D: drive”).
Step#5:- Start Application and place files in “D:/source” which will be copied
automatically into “D:/destination”.
NOTE:--In source file .camel folder is created automatically which contains Copied file
and in Destination folder only File will coped but no any folder will be created.
application.properties:--
camel.springboot.main-run-controller=true
my.source=file:D://Source?noop=true
my.destination=file:D://Destination
Example EIPs:--
#1>Dynamic Location:--
Location (source/destination) can be passed at runtime using properties/yml files,
config server, system arguments… etc.
=>To indicate Location (URL file System, DB, MQ…) comes at runtime use format:
{{location}}
Code changes:--
a. applictaion.properties:--
server.port=2344
Ex:--
package com.app.router;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;
@Component
public class MyFilesRouter extends RouteBuilder {
public void configure() throws Exception {
//With Dynamic Location
from("{{my.source}}").to("{{my.destination}}");
}
}
#2 Data Processing Using Apache Camel:--
In realtime data will be converted or modified based on requirements.
Like XML--->JSON, JSON--->Simple Text, XML--->CSV, CSV--->SQL Format etc..
i.e data converted from one format to another format which can be done using 3
supporting interfaces. Those are:
@Component
public class MyFilesProcess extends RouteBuilder {
@Component
public class MyFilesProcess extends RouteBuilder {
public void configure() throws Exception
{
from("file:D:/source")
.process(ex->{
String body=ex.getIn().getBody(String.class);
body="New AA modified ::"+body;
ex.getOut().setBody(body);
@Component
public class MyFilesProcess extends RouteBuilder {
@Component
public class MyFilesProcess extends RouteBuilder
{
public void configure() throws Exception {
from("file:D:/source")
.filter(body().startsWith("java"))
.to("file:D:/destination");
}
}
Output Screen file contents:--
=>By using ValueBuilder (C) we can do filter() and choice() based predicates execution.
a. filter:-- This is used to check one given boolean expression if true execute next step,
else does nothing.
RouteBuilder Impl Class for Filter:--
Example#1:--
package com.app.route;
import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;
@Component
public class MyFilesProces extends RouteBuilder {
public void configure() throws Exception {
from("file:D:/Source")
.filter(header(Exchange.FILE_NAME)
@Component
public class MyFilesProces extends RouteBuilder {
public void configure() throws Exception {
from("file:D:/Source")
.filter(body().startsWith("Hello"))
.to("file:D:/Destination");
}
}
b. choice():-- This is used to execute multiple condition checks in a order, It behaves
like switch-case concept.
=>We can provide multiple when() with predicates even with process(..). Finally
otherwise() is executed if all conditions are fail.
Format looks like:--
from("source")
.choice()
.when(condition#1).to("destinatation#1")
.when(“condition#2).to("destinatation#2")
….
otherwise().to("destinatation#n")
@SpringBootApplication
public class SpringBootApacheCamelEIPConditionalBasedApp {
@Component
public class MyFilesRouting extends RouteBuilder {
#2 If file body contains start with xml then create a new file b.txt in destination. Where
as body contain is case sensitive.
#3 If file body contains start with json then create a new file c.txt in destination.
Where as body contain is case sensitive.
#4 If file body contains is not start with java, xml, json then create a new file d.txt in
destination.
Output Screen:--
Source File:-- Destination File:--
=>For this coding along with ActiveMQ and Camel Dependencies we should add
ActiveMQ-pool and camel-jms integration dependencies.
application.properties
camel.springboot.main-run-controller=true
spring.activemq.broker-url=tcp://localhost:61616
spring.activemq.user=admin
spring.activemq.password=admin
@Component
public class MyMqFileRouter extends RouteBuilder {
@Override
public void configure() throws Exception {
//1. Sending file Data from Source to Message Queue
/* from("file:D:/Source?fileName=mydata.txt") .to("jms:queue:outdata"); */
Execution order:--
a. Run ActiveMQ
b. Run Starter class
c. Create queue “abc”
d. Click on send to link
e. Enter message and send button
f. Open file and view data
NOTE:-- If you keep any file before, after sending it will be automatically converted to
“.camel” folder.
=>Click on “send To” option on “indata” queue, Enter message and press send.
=>File will be copied to destination folder.
Camel supports reading data or writing data using JDBC took any database like
MySQL, POSTGRES, H2, ORACLE etc… for this we need to provide dataSource Object as
input to Camel.
=>Here DataSource is an Interface defined in Javax.sql package we need to configure
its implementation class object.
=>By using one dataSource and SQL query we can fetch data from Database table.
->It will be converted to List<Map<String, Object>> [K=Key=String type,
V=Value=Object Type].
=>ResultSet data is converted to List<Map> format by Camel internally, example.
Step#1:- Create project using Apache Camel, Apache ActiveMQ, MySQL connector.
pom.xml:--
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.app</groupId>
<artifactId>Apache-Camel-Integration-JDBC</artifactId>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>2.24.0</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jdbc</artifactId>
<version>2.24.0</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jms</artifactId>
<version>2.24.0</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
@SpringBootApplication
public class ApacheCamelIntegrationWithJdbc1Application {
@Configuration
public class AppConfig {
@Bean
public DriverManagerDataSource dsObj() {
DriverManagerDataSource d = new DriverManagerDataSource();
d.setDriverClassName("oracle.jdbc.driver.OracleDriver");
d.setUrl("jdbc:oracle:thin:@localhost:1521:xe");
d.setUsername("system");
d.setPassword("system");
return d;
}
}
Step#5:- Define One RouteBuilder class with logic
package com.app.route;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;
@Component
public class MyBuilder extends RouteBuilder {
application.properties:--
camel.springboot.main-run-controller=true
spring.activemq.broker-url=tcp://localhost:61616
spring.activemq.user=admin
spring.activemq.password=admin
Execution Order:--
#1:-- Create table and insert data.
#2:-- Run ActiveMQ
#3:-- Run Starter class of Project.
#4:-- Goto ActiveMQ (http://localhost:8161/admin), Click on Queue to see the details.
NOTE:--
=>use protocol “timer://…” which takes input like repeatCount (no. of iterations) and
period (time gap) in mill sec.
#1:-timer://anyName?period=1000
->It is repeated for every 1Sec
#2:-timer://anyName?period=10s
->It is repeated for every 10Sec
#3:-timer://anyName?repeatCount=4&period=10m
->It is executed for every 10 minutes and 4 times only
OAuth 2.x:-- It is standard and framework which provides 3rd party security services to
client application which are registered, on behalf of end user.
=>These 3rd party Applications are also called as “Authorization and Resource Servers”.
->Authorization and Resource Server examples are:- Google, Facebook, Githb,
Twitter, Linkedin … etc.
->Example client Applications that are using OAuth2 ares BookMyshow, redbus,
yatra, makemytrip, avast, zomato.. etc.
=>OAuth 2.x standard is widely used in small/medium scale/daily used, business
application.
=>OAuth2 Provide SSO (Single Sign on) for multiple applications acting as a one Service.
1. End user makes request using browser to client application (BookMyshow) request
for “verify using 3rd party service” ex: Facebook, Google… etc.
2. Client Application will ask for Grant from end user, which confirms that access user
data.
3. End user has to provide Grant (Permission) to access data.
4. Client makes request to Authorization server using ClientId, secret, user grant.
5. Auth server verifies details and goes to token Management process.
=A unique number is generated, called as Token which works for User+Client
combination.
6. Now, client application makes request to resource Server using Access Token.
7. Resource server returns end user secure data to client.
8. Finally, Client App process the end user request and gives response.
Step#2:- Here choosing Facebook as 3rd party server for open Authorization link is:
https://developers.facebook.com/
pom.xml:--
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 426
[Raghu Sir] [NareshIT, Hyd]
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.app</groupId>
<artifactId>Spring-Cloud-OAuth2-App</artifactId>
<version>1.0</version>
<name>Spring-Cloud-OAuth2-App</name>
<description>Spring Cloud OAuth2 Implementation</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
SecurityConfig.java:--
package com.app.config;
import org.springframework.boot.autoconfigure.security.oauth2.client.
EnableOAuth2Sso;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.
WebSecurityConfigurerAdapter;
@Configuration
@EnableOAuth2Sso
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/","/login").permitAll()
.anyRequest().authenticated();
}
}
Step#7:- Define RestController for User (or Any)
package com.app.controller;
import java.security.Principal;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/user")
public Principal showUser(Principal p)
{
return p;
}
@RequestMapping("/home")
public String showData()
{
return "Hello";
}
}
Index.html:--
<html>
<body>
<h1>Welcome to Login Page</h1>
<a href="user">Facebook</a>
<hr/>
<form action="#" method="post">
User : <input type="text">
Pwd : <input type="password">
<input type="submit">
</form>
</body>
</html>
=>Click on Login if you have Facebook account else Click on Sign Up Button.
Step#2:- Enter details like name, email, password and conform password & Click on
Sign Up.
2>Logout command is
cf logout
**(If failed, then Update Maven Project, select force Update and finish.
Repeat step#11, 13 and then 14)
Production Server:-- A server having application that provide service to end user is
known as Production server.
Actuator Dependencies:--
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Coding Step:--
Step#1:- Create one starter project with one web and Actuator dependencies.
Step#2:- pom.xml:--
spring-boot-starter-web
spring-boot-starter-actuator
Step#4:- application.properties
server.port=9988
management.endpoints.web.exposure.include=*
pom.xml:--
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.app</groupId>
<artifactId>Spring-Cloud-Admin-UI</artifactId>
<version>1.0</version>
<name>Spring-Cloud-Admin-UI</name>
<description>Spring Cloud Admin Dashboad Implementation</description>
<properties>
<java.version>1.8</java.version>
<spring-boot-admin.version>2.1.4</spring-boot-admin.version>
</properties>
<dependencies>
@SpringBootApplication
@EnableAdminServer
public class SpringCloudAdminUiDashboardsApp {
public static void main(String[] args) {
SpringApplication.run(SpringCloudAdminUiDashboardsApp.class, args);
}
}
Step#3:- Provide details in application.properties
server.port=9999
pom.xml:--
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.app</groupId>
<artifactId>Spring-Boot-User-Service</artifactId>
<version>1.0</version>
<name>Spring-Boot-User-Service</name>
<description>Demo project for Spring JMS Implementation</description>
<properties>
<java.version>1.8</java.version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
server.port=6666
spring.boot.admin.client.url=http://localhost:9999
management.endpoints.web.exposure.include=*
spring.application.name=USER-PROVIDER
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka
@SpringBootApplication
@EnableDiscoveryClient
@RestControllers
@RequestMapping("user")
public class UserController {
@RequestMapping("show")
public String showUser() {
System.out.println("Hello User");
return null;
}
}
Execution Order:--
1>Run Admin Server
2>Then run ClientApps (SpringBootUserServiceApp)
=>Enter URL : http://localhost:9999
Output Screen:--
3>To Register with Admin Server add below dependency in every application
(Consumer, Provider even if Eureka Server, Config Server, ZUUL Server).
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
Product------------------------------------------------------<>Coupon
Step#1:- application.properties
server.port=8761
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
@SpringBootApplication
@EnableEurekaServer
public class SpringCloudTaskEurekaServerApp {
1>application.properties
# Recommonded port
server.port = 8888
# External config file link
spring.cloud.config.server.git.uri=https://github.com/saurabh-vaish/MicroserviceTask
#spring.cloud.config.server.git.uri=https://gitlab.com/udaykumar0023/configserverex
@SpringBootApplication
@EnableConfigServer
public class SpringCloudTaskConfigServerApplication {
## connection pooling
### max connections
spring.datasource.hikari.maximum-pool-size=12
### if no connection allocated
spring.datasource.hikari.connection-timeout=20000
### life time of sql
spring.datasource.hikari.max-lifetime=1200000
### idle connections
spring.datasource.hikari.minimum-idle=5
### if no activity then idle
spring.datasource.hikari.idle-timeout=30000
### if no activity then idle
spring.datasource.hikari.auto-commit=true
## jpa properties
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
1>application.properties:--
# zuul server port
server.port=6565
# service id for eureka server
spring.application.name=ZUUL_PROXY
# service url
eureka.client.service-url.default-zone=http://localhost:8761/eureka
# routing for coupan
zuul.routes.coupanserv.service-id=COUPAN-APP
zuul.routes.coupanserv.path=/coupan-api/**
# routing for product
zuul.routes.productserv.service-id=PRODUCT-APP
zuul.routes.productserv.path=/prod-api/**
@SpringBootApplication
@EnableZuulProxy
public class SpringCloudTaskZuulServerApplication {
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 461
[Raghu Sir] [NareshIT, Hyd]
public static void main(String[] args) {
SpringApplication.run(SpringCloudTaskZuulServerApplication.class, args);
System.out.println("Zuul Server Executed...!!");
}
}
pom.xml:--
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.app</groupId>
<artifactId>SpringCloud_Task-CouponProvider</artifactId>
<version>1.0</version>
<name>SpringCloud_Task-CouponProvider</name>
<description>Microservices project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependencyManagement>
<dependencies>
<dependency>
1>application.properties:--
server.port=7777
# service Id
spring.application.name=COUPON-APP
# service-url
eureka.client.service-url.default-zone=http://localhost:8761/eureka
#load balancing
eureka.instance.instance-id=${spring.application.name}:${random.value}
# no need to write for config server port 8888
#spring.cloud.config.uri=http://localhost:8888
#spring.profiles.include=dev
2>Starter class:--
package com.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
3>Model class:--
package com.app.model;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name="coupon_micro")
public class Coupon implements Serializable
{
private static final long serialVersionUID = 1L;
@Id
@Column(name="coupon_id")
private Integer couponId;
@Column(name="coupon_code", length=25)
private String couponCode;
@Column(name="coupon_discount")
private Double couponDisc;
@Column(name="coupon_expiry")
@Temporal(TemporalType.DATE)
private Date expDate;
@JsonIgnore
@Column(name="coupon_valid")
private Boolean isValid = true;
}
4>Repository Interface:--
package com.app.repo;
import java.util.Date;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import com.app.model.Coupon;
5>Service Interface:--
package com.app.service;
import java.util.List;
import com.app.model.Coupon;
public interface CouponService {
6>ServiceImpl class:--
package com.app.service.impl;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.app.model.Coupon;
import com.app.repo.CouponRepository;
import com.app.service.CouponService;
@Service
public class CouponServiceImpl implements CouponService
@Override
@Transactional
public Coupon saveCoupon(Coupon coupon) {
return repo.save(coupon);
}
@Override
@Transactional
@CachePut(value = "coupon-cache",key="#coupon.couponId")
public Coupon updateCoupon(Coupon coupon) {
return repo.save(coupon);
}
@Override
@Transactional(readOnly = true)
@Cacheable(value = "coupon-cache",key="#couponId")
public Coupon getCouponById(Integer couponId)
{
Optional<Coupon> c= repo.findById(couponId);
return c.isPresent()?c.get():null;
}
@Override
@Transactional(readOnly = true)
public Coupon getCouponByCode(String code) {
return repo.findByCouponCode(code);
}
@Override
@Transactional
@CacheEvict(value = "coupon-cache",key="#couponId")
public void deleteCouponById(Integer couponId) {
repo.deleteById(couponId);
@Override
public boolean isExpired(String code) {
Coupon c= repo.findByCouponCodeAndExpDate(code, new Date());
return (c!=null)?true:false;
}
@Override
public boolean isExist(Integer id) {
System.out.println(id);
return repo.existsById(id);
}
}
7>Validator class:--
package com.app.validator;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import com.app.exception.ApiError;
import com.app.model.Coupon;
@Component
public class CouponValidator implements Validator{
@Autowired
private ApiError api=new ApiError();
@Override
public boolean supports(Class<?> clazz) {
return clazz.equals(Coupon.class);
}
@Override
public void validate(Object target, Errors errors) {
Coupon c = (Coupon) target;
if(StringUtils.isEmpty(c.getCouponId().toString()))
{
errors.reject("couponId");
api.getValidationErrors().add("Please Provide Coupon Id");
}
if(StringUtils.isEmpty(c.getCouponCode()))
{
errors.reject("couponCode");
api.getValidationErrors().add("Please Provide Coupon Code ");
}
if(StringUtils.isEmpty(c.getCouponDisc().toString()))
{
errors.reject("couponDisc");
api.getValidationErrors().add("Please Provide Coupon Discount ");
}
if(c.getCouponDisc()<0)
{
errors.reject("couponDisc");
api.getValidationErrors().add("Please Provide Valid Discount ");
}
if(StringUtils.isEmpty(c.getExpDate()))
{
errors.reject("expDate");
api.getValidationErrors().add("Please Provide Coupon Expiray Date");
8>Exception Class:--
1. API Class:--
package com.app.exception;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.springframework.stereotype.Component;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
public class ApiError {
3. CouponNotFoundException class:--
package com.app.exception;
public CouponNotFoundException(String s) {
super(s);
}
}
9>Controller class:--
1. CouponController:--
package com.app.rest.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.Errors;
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.exception.CouponNotFoundException;
import com.app.exception.ValidationError;
import com.app.model.Coupon;
import com.app.service.CouponService;
import com.app.validator.CouponValidator;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
@RestController
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 474
[Raghu Sir] [NareshIT, Hyd]
@RequestMapping("/rest/coupon")
public class CouponController {
@Autowired
private CouponService service;
@Autowired
private CouponValidator validator;
@PostMapping("/save")
public ResponseEntity<String> saveCoupon(@RequestBody Coupon
coupon, Errors errors)
{
validator.validate(coupon, errors);
if(!errors.hasErrors()) {
service.saveCoupon(coupon);
return new ResponseEntity<String>("Coupon has been added
successfully",HttpStatus.OK);
} else {
throw new ValidationError("Please Provide Valid Details");
}
}
@GetMapping("/check/{code}")
public String checkExpiredOrNot(@PathVariable String code) {
return service.isExpired(code)?"Not Expired":"Expired";
}
@GetMapping("/getOne/{id}")
@HystrixCommand(fallbackMethod = "getCouponException")
public Coupon getOneCoupon(@PathVariable Integer id)
{
Coupon c = service.getCouponById(id);
if(c!=null)
{
return c;
} else {
throw new CouponNotFoundException("No Coupon Found");
}
@GetMapping("/getByCode/{code}")
//@HystrixCommand(fallbackMethod = "getCouponCodeException")
public Coupon getCouponByCode(@PathVariable String code)
{
System.out.println(code);
Coupon c = service.getCouponByCode(code);
if(c!=null)
{
return c;
} else {
throw new CouponNotFoundException("No Coupon Found");
}
}
@GetMapping("/all")
public List<Coupon> getAllCoupons()
{
List<Coupon> list =service.getAllCoupons();
System.out.println(list);
return list;
}
@PostMapping("/update")
public ResponseEntity<String> updateCoupon(@RequestBody Coupon
coupon,Errors errors)
{
if(service.isExist(coupon.getCouponId()))
if(!errors.hasErrors())
{
service.saveCoupon(coupon);
return new ResponseEntity<String>("Coupon has been
updated successfully", HttpStatus.OK);
} else {
throw new ValidationError("Please Provide Valid Details");
}
} else {
throw new CouponNotFoundException("No Coupon Found");
}
}
@DeleteMapping("/delete/{id}")
public ResponseEntity<String> deleteCoupon(@PathVariable Integer id)
{
if(service.isExist(id))
{
service.deleteCouponById(id);
return new ResponseEntity<String>("Coupon Deleted
Successfully", HttpStatus.OK);
} else {
throw new CouponNotFoundException("No Coupon Found");
}
}
}
2. ExceptionController class:--
package com.app.rest.controller;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
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.exception.ApiError;
import com.app.exception.CouponNotFoundException;
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 477
[Raghu Sir] [NareshIT, Hyd]
import com.app.exception.ValidationError;
@RestControllerAdvice
public class ExceptionController {
@Autowired
private ApiError api;
@ExceptionHandler(value=CouponNotFoundException.class)
public ResponseEntity<ApiError> noCouponFound()
{
ApiError error = new ApiError();
error.setErrorCode("400");
error.setErrorDesc("No Coupon Found ");
error.setErrorDate(new Date());
return new ResponseEntity<ApiError>(error,HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(value=ValidationError.class)
public ResponseEntity<ApiError> validationError()
{
api.setErrorCode("400");
api.setErrorDesc("Please Provide Valid Details");
api.setErrorDate(new Date());
return new ResponseEntity<ApiError>(api,HttpStatus.BAD_REQUEST);
}
}
10. Config Class:--
1. CacheConfig class:--
package com.app.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.hazelcast.config.Config;
import com.hazelcast.config.EvictionPolicy;
import com.hazelcast.config.MapConfig;
@Bean
public Config chacheConfig()
{
return new Config() // for creating cache
.setInstanceName("hazelcast-cahe") // setting cache name
.addMapConfig( // Setting MapConfig module
new MapConfig()
.setName("coupon-cache") // MapConfig Name
.setTimeToLiveSeconds(2000) // max time for object to present in
memory if no activity done
.setMaxSizeConfig(new
MaxSizeConfig(200,MaxSizePolicy.FREE_HEAP_SIZE)) // size of objects in MapConfig
.setEvictionPolicy(EvictionPolicy.LRU)
);
}
}
2. Swagger Implementation:--
package com.app.config;
import static springfox.documentation.builders.PathSelectors.regex;
import static pringfox.documentation.builders.RequestHandlerSelectors.basePackage;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
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
1. pom.xml:--
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.app</groupId>
<artifactId>SpringCloud_Task-ProductProvider</artifactId>
<version>1.0</version>
<name>SpringCloud_Task-ProductProvider</name>
<description>Microservices project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<dependencyManagement>
<dependencies>
<dependency>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2>application.properties:--
server.port=9999
# service id
spring.application.name=PRODUCT-APP
# service-url
eureka.client.service-url.default-zone=http://localhost:8761/eureka
#load balancing
eureka.instance.instance-id=${spring.application.name}:${random.value}
# no need to write for config server port 8888
#spring.cloud.config.uri=http://localhost:8888
# loggin keys
logging.level.root=info
logging.level.com.app=DEBUG
logging.file=Mylog.log
logging.file.max-size=5MB
logging.file.max-history=5
#JPA details
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
spring.jpa.database-platform=org.hibernate.dialect.Oracle10gDialect
3>Starter class:--
package com.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient
@EnableCaching
@EnableHystrix
@EnableFeignClients
public class SpringCloudTaskProductProviderApp {
public static void main(String[] args) {
SpringApplication.run(SpringCloudTaskProductProviderApp.class, args);
System.out.println("Product Provider Executed…!!");
}
}
4>Model class:--
1. Coupon class:--
package com.app.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
@JsonIgnore
private Boolean applied=false;
}
2. Product class:--
package com.app.model;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name="product_micro")
public class Product implements Serializable {
@Id
private Integer prodId;
private String prodCode;
private Double prodCost;
@JsonIgnore
private Double finalCost;
@Transient
private Coupon coupon;
}
5>Repository Interface:--
package com.app.repo;
import org.springframework.data.jpa.repository.JpaRepository;
import com.app.model.Product;
6>Service Interface:--
package com.app.service;
import java.util.List;
import com.app.model.Product;
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
private ProductRepository repo;
@Override
@Transactional
public Product saveProduct(Product product) {
return repo.save(product);
}
@Override
@Transactional
@CachePut(value = "product-cache",key="#product.prodId")
public Product updateProduct(Product product) {
return repo.save(product);
}
@Override
@Transactional
@CacheEvict(value = "product-cache",key="#prodId")
public void deleteProductById(Integer prodId) {
repo.deleteById(prodId);
}
@Override
@Transactional(readOnly = true)
public List<Product> getAllProducts() {
return repo.findAll();
}
@Override
public boolean isExist(Integer id) {
return repo.existsById(id);
}
@Override
public Double calculateDiscount(Double cost, Double disc) {
Double dCost = cost*disc/100.0;
Long value = Math.round(cost-dCost);
return value.doubleValue();
}
}
8>Validator Class:--
package com.app.validator;
@Component
public class ProductValidator implements Validator{
@Autowired
private ApiError api;
@Override
public boolean supports(Class<?> clazz) {
return clazz.equals(Product.class);
}
@Override
public void validate(Object target, Errors errors) {
if(StringUtils.isEmpty(p.getProdId().toString())) {
errors.reject("prodId");
api.getValidationErrors().add("Please Provide Product Id");
}
if(StringUtils.isEmpty(p.getProdCode())) {
errors.reject("prodCode");
api.getValidationErrors().add("Please Provide Product Code ");
}
if(StringUtils.isEmpty(p.getProdCost().toString())) {
errors.reject("prodCost");
api.getValidationErrors().add("Please Provide Product Cost ");
@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
public class ApiError {
2. Validation class:--
package com.app.exception;
public ValidationError(String s) {
super(s);
3. ProductNotFoundException:--
package com.app.exception;
public ProductNotFoundException(String s) {
super(s);
}
}
10>ClientRestController class:--
package com.app.client;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import com.app.model.Coupon;
@FeignClient("COUPON-APP")
public interface CouponRestConsumer {
@GetMapping("/rest/coupon/getByCode/{code}")
public Coupon getCouponByCode(@PathVariable String code);
@GetMapping("/rest/coupon/check/{code}")
public String checkExpiredOrNot(@PathVariable String code);
}
11>Controller class:--
1. ProductController:--
package com.app.rest.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
@RestController
@RequestMapping("/rest/product")
public class ProductController {
@Autowired
private ProductService service;
@Autowired
private CouponRestConsumer consumer;
@Autowired
private ProductValidator validator;
@PostMapping("/save")
public ResponseEntity<String> saveProduct(@RequestBody Product
product,Errors errors)
{
validator.validate(product, errors);
if(!errors.hasErrors())
{
String res= consumer.checkExpiredOrNot (product.getCoupon().getCouponCode());
System.out.println(res);
Coupon c = consumer.getCouponByCode(product.getCoupon().getCouponCode());
System.out.println(c);
if(c==null)
{
return new ResponseEntity<String>("Coupon Not Found",HttpStatus.OK);
}
else if(res.equals("Expired"))
{
return new ResponseEntity<String>("Coupon has been expired !",HttpStatus.OK);
} else {
Double dis = c.getCouponDisc();
if(product.getCoupon().getApplied()) // if coupon applied
{
dis=0.0;
}
@GetMapping("/apply")
public ResponseEntity<Double> applyCoupon(Double cost,Double disc)
{
return new ResponseEntity<Double>(service.calculateDiscount(cost,
disc),HttpStatus.OK);
}
@GetMapping("/getOne/{id}")
//@HystrixCommand(fallbackMethod = "getProductException")
public ResponseEntity<Product> getOneProduct(@PathVariable Integer id)
{
Product p = service.getProductById(id);System.out.println(p);
if(p!=null)
{
return new ResponseEntity<Product>(p,HttpStatus.OK);
} else {
throw new ProductNotFoundException("No Product Found");
}
}
// fallback method
public ResponseEntity<Product> getProductException(Integer id)
{
throw new ProductNotFoundException("No Product Found");
}
@GetMapping("/all")
public List<Product> getAllProducts()
{
return service.getAllProducts();
}
@PostMapping("/update")
public ResponseEntity<String> updateProduct(@RequestBody Product
product, Errors errors)
{
if(service.isExist(product.getProdId()))
{
validator.validate(product, errors);
if(!errors.hasErrors())
{
service.saveProduct(product);
return new ResponseEntity<String>("Product has been
updated successfully",HttpStatus.OK);
} else {
throw new ValidationError("Please Provide Valid Details");
}
} else {
throw new ProductNotFoundException("No Product Found");
}
}
@DeleteMapping("/delete/{id}")
public ResponseEntity<String> deleteProduct(@PathVariable Integer id)
{
if(service.isExist(id)) {
service.deleteProductById(id);
12>Config class:--
1. Config class:--
package com.app.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.hazelcast.config.Config;
import com.hazelcast.config.EvictionPolicy;
import com.hazelcast.config.MapConfig;
import com.hazelcast.config.MaxSizeConfig;
import com.hazelcast.config.MaxSizeConfig.MaxSizePolicy;
@Configuration
public class CacheConfig {
@Bean
public Config chacheConfig()
{
return new Config() // for creating cache
.setInstanceName("hazelcast-cahe") // setting cache name
.addMapConfig( // Setting MapConfig module
new MapConfig()
.setName("product-cache") // MapConfig Name
.setTimeToLiveSeconds(2000) // max time for object to present in
memory if no activity done
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 497
[Raghu Sir] [NareshIT, Hyd]
.setMaxSizeConfig(new MaxSizeConfig(200,MaxSizePolicy.FREE_HEAP_SIZE))
// size of objects in MapConfig
.setEvictionPolicy(EvictionPolicy.LRU)
);
}
}
2. Swagger Confg:--
package com.app.config;
import static springfox.documentation.builders.PathSelectors.regex;
import static springfox.documentation.builders.RequestHandlerSelectors.basePackage;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
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 configSwagger()
{
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(basePackage("com.app.rest.controller"))
.paths(regex("/rest.*"))
.build()
// optional
.apiInfo(apiInfo());
}
Execution Order:--
1.>Eureka Server
2.>Config Server
3.>Zuul Server
4.>CouponProvider Application Starter class
5.>ProductProvider Application Starter class
6. POSTMAN screen for CHECK CODE VALIDITY Operation for CouponProvider Appl:--
localhost:9999/swagger-ui.html#/
***MOCKITO***
Spring Boot UnitTesting using JUnit+Mocking:--
Step#1:- Create one Spring Starter Project and define RestController with methods
and URLs added.
@RunWith(SpringRunner.class)
@WebMvcTest
@RestController
@RequestMapping(name="/emp")
public class EmployeeRestController {
@GetMapping("/data")
public String getData() {
return "Hello";
}
}
@RunWith(SpringRunner.class)
@WebMvcTest
@SpringBootTest
public class JUnitMockitoApplicationTests {
@Test
public void testEmpData() throws Exception {
MvcResult result=mockMvc.perform(get("/emp/data")).andReturn();
//MockHttpServletRequest req =result.getRequest();
MockHttpServletResponse resp =result.getResponse();
assertEquals("Hi", resp.getContentAsString());
}
}
=>Right click => Run as => JUnit Test
Step#1:- To construct Request Object use RequestBuilder and call static method
(Http Method Type).
MockMvcRequestBuilders.post(…)….;
Ex#1 (GET):-
Ex#2 (POST):--
Ex#3 (DELETE):-
=>Equal code
MockHttpServletRequestBuilder request =
MockMvcRequestBuilders.delete("/emp/remove/101");
=>Equal code
MockHttpServletRequestBuilder request = MockMvcRequestBuilders
.post("/emp/save")
.contentType("application/xml")
.content("<emp>…</emp");
Step#4:- Define one class under src/test/java folder and apply annotations.
NOTE:--
1>@TestPropertySource:- It is used to load properties/yml file into UnitTest
2>@AutoConfigureMockMvc:- It Define all Mock Beans related to environment
(Ex: Datasource, ConnectionPool, Cache…).
3>@SpringBootTest:- It define beans and injects them based on relations (Objects for:
RestControllers, Services, Repos…etc).
4>@WebMvcTest:- Works only for @RestControllers without service and other
dependencies.
pom.xml:--
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<!-- <optional>true</optional> -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0</version>
</dependency>
<!-- <dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency> -->
@Entity
@Data
@Table
public class Product {
@Id
@GeneratedValue
private Integer prodId;
private String prodCode;
private Double prodCost;
private String vendorCode;
}
@Service
public class ProductServiceImpl implements IProductService{
@Autowired
private ProductRepository repo;
@RestController
@RequestMapping("/product")
public class EmployeeRestController {
@Autowired
private IProductService service;
import org.junit.Test;
import org.junit.runner.RunWith;
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.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
@RunWith(SpringRunner.class)
//@WebMvcTest
@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.MOCK)
@AutoConfigureMockMvc
@TestPropertySource(locations = "classpath:application-test.properties")
public class UnitTestUsingJUnitAndMockitoTests {
@Autowired
private MockMvc mockMvc;
***Gradle***
Gradle:-- Gradle is a build tool. It works based on Groovey Language.
=>It gets Jars related to Project.
=>It will be connected to parent projects as plugin.
=>Provides Java Application support.
=>Connected to multiple server for jars fetching Ex:- Jcenter, mavenCentral etc.
=>Supports compile our file.
=>Creates .jar/.war file.
=>**Gradle is a task based Scripting. It means, for every work/setup we need to write
one task. These are pre defined in Gradle.
task {
//details
}
-------Example Task-------
plugins{ ….. }
bootJar { ….. }
repositories { ….. }
dependencies { ….. }
Step#2:- Search with Gradle > Select “Gradle Project” and click on Next.
NOTE:--***If Gradle option is not available then goto Eclipse Market place and
download “Buildship Gradle Integration”.
task: dependencies:-- This task is used to provide Jars related to project using one
scope.
Dependency contains:--
Scope
Group
Name
Version
Ex:--
compile
group : ‘org.springframework’,
name : ‘spring-context’,
version : ‘5.1.8.RELEASE’
Screen Short:--
Scopes in Gradle:--
a. compile
b. testCompile
c. providedCompile
d. runtime
e. api //same like system in maven
repositories {
jcenter()
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
dependencies {
compile 'com.google.guava:guava:23.0'
testCompile 'junit:junit:4.12'
providedCompile "javax.servlet:javax.servlet-api:3.1.0"
}
dependencies {
def tomcatVersion = '8.0.53'
tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
"org.apache.tomcat.embed:tomcat-embed-loggingjuli:${tomcatVersion}",
"org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}"
}
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.bmuschko:gradle-tomcat-plugin:2.5'
}
}
NOTE:-- Each time there is a change in build.gradle you need to update the project,
using the tool of Gradle.
=>Right click on Project > Gradle > Refresh Gradle Project
Create folder:--
=>Right click on Project > build path > Configure Build path >
->Source > add folder > new folder >
Enter name ex: src/main/resources -> finish.
Screen Shot:--
Step#1:- Right click on Project > Build Path > Configure Build Path
Step#3:- Select folder in which you want to create folder > Click on Create New Folder
> Enter Folder Name like (resources) > click on Next.
4. Write Code:--
1>Service class, jsp, html etc..
Screen Shot:--
NOTE:-- If “Gradle Tasks” and “Gradle Execution” is not showing bellow then
=>Goto “Window” Menu > Show View > Other...>
=>Search with Gradle > Select both option >
=>Click on Open Button.
Screnn#1:-
Screen#2:-
Code:--
1. build.gradle:--
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
//mavenCentral()
jcenter()
}
dependencies {
providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
compile 'org.springframework:spring-webmvc:5.1.8.RELEASE'
compile 'com.fasterxml.jackson.core:jackson-databind:2.9.5'
runtime 'javax.servlet:jstl:1.2'
tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
Naresh IT, Hyderabad P: 040-2374 6666,9000994007 /08] Page 540
[Raghu Sir] [NareshIT, Hyd]
"org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}",
"org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}"
}
buildscript {
repositories {
//mavenCentral()
jcenter()
}
dependencies {
classpath 'com.bmuschko:gradle-tomcat-plugin:2.5'
}
}
@WebServlet("/home")
public class Message extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
PrintWriter out=resp.getWriter();
out.println("Hello App");
}
}
3. index.jsp:--
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
Execution flow:--
Step#1:- Execute Gradle build task
=>Open "Gradle Task" view > Expand Project > choose build > Run Gradle Tasks
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenCentral()
//jcenter()
}
dependencies {
tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
"org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}",
"org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}"
}
buildscript {
repositories {
mavenCentral()
//jcenter()
}
dependencies {
classpath 'com.bmuschko:gradle-tomcat-plugin:2.5'
}
}
@Configuration
@EnableWebMvc
@ComponentScan("com.app")
public class AppConfig {
@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] {AppConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[] {"/*"};
}
}
@RestController
@RequestMapping("/emp")
public class EmployeeController {
@GetMapping("/msg")
public String show() {
return "Hello R-APP";
}
}
Execution flow:--
Step#1:- Execute Gradle build task
Step#2:- Run application in tomcat
Step#3:- Enter URL in Browser
http://localhost:8080/Spring-Project-Using-Gradle/emp/msg
Parent : org.springframework.boot
BOM : io.spring.dependency-management
=>BOM means all child details and their versions as one project (.pom/.gradle file)
group = 'com.app'
version = '1.0'
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
configurations {
developmentOnly
runtimeClasspath {
extendsFrom developmentOnly
}
}
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
implementation ('org.springframework.boot:spring-boot-starter-web',
'org.springframework.boot:spring-boot-starter-data-jpa',
'org.projectlombok:lombok')
compile ('org.springframework.boot:spring-boot-starter-actuator',
'com.oracle:ojdbc6:11.2.0')
developmentOnly 'org.springframework.boot:spring-boot-devtools'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
2. application.properties:--
server.port=2019
##DataSource##
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe
3. Starter class:--
package com.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootGradleApplication {
4. Model class:--
package com.app.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Data;
@Entity
@Table(name="PRODUCTTAB")
@Data
public class Product {
@Id
@Column(name="id")
@GeneratedValue
private Integer id;
@Column(name="name")
private String productName;
@Column(name="cost")
private Double productCost;
}
5. Repository Interface:--
package com.app.repo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.app.model.Product;
@Repository
public interface ProductRepository extends JpaRepository <Product, Integer>{
6. Service Interface:--
package com.app.service;
import java.util.List;
import com.app.model.Product;
7. ServiceImpl class:--
package com.app.service.impl;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Autowired
private ProductRepository repo;
@RestController
@RequestMapping("/product")
public class ProductController {
@Autowired
private IProductService service;
try {
Integer id=service.saveProduct(product);
resp = new ResponseEntity<String>("Product '"+id+"' Created", HttpStatus.OK);
} catch (Exception e) {
resp = new ResponseEntity<String>(e.getMessage(),
HttpStatus.INTERNAL_SERVER_ERROR);
e.printStackTrace();
}
List<Product> list=service.getAllProducts();
if(list==null || list.isEmpty()) {
String message="No Data Found";
resp=new ResponseEntity<String>(message,HttpStatus.OK);
} else {
resp=new ResponseEntity<List<Product>>(list,HttpStatus.OK);
}
return resp;
}
Execution:--
=>Right click on Project > Run As > Spring Boot App (Alt+Shift+X, B)
=>Rest the application using postman
1.> http://localhost:2019/product/save
2.> http://localhost:2019/product/delete/100
3.> http://localhost:2019/product/all
***DOCKER***
Docker:--
Docker Workflow:--
=>Click on Yes
=>Click on Next
=>Click on Next
=>Click on Next
=>Click on Next
=>Click on Install
=>Click on Finish
1. Starter class:--
package com.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DockerSpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(DockerSpringBootApplication.class, args);
System.out.println("Heelo Docker Application");
}
}
2. Controller class:--
package com.app.rest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@GetMapping("/show")
public String show() {
return "Hello Docker";
}
}
=>Search with openjdk, Tomcat, Oracle, MySQL …etc according to your requirement.
->and click on searched result to see the details of software images.
b. build image:--
docker build -f Dockerfile -t <AnyImageName> .
=> $ docker build -f Dockerfile -t spring-app .
=>Here dot(.) indicate current directory, must give one space.
=>Here 9090 is docker container port no and 8080 is application port no.
=> Goto browser and enter URL:
Example URL: http://192.168.99.100:9090/show
MICROSERVICES END
email : javabyraghu@gmail.com
FB Group : https://www.facebook.com/groups/thejavatemple/