0% found this document useful (0 votes)
21 views34 pages

Spring Training With Spring Boot

The document outlines a three-day training program on Spring and Spring Boot, covering core Java concepts, JDBC, and RESTful web services. It includes detailed topics for each day, such as Spring's dependency injection, bean lifecycle, and database integration with JPA. Additionally, it provides practical steps for creating a bank application using Spring Boot, including exception handling, validation, and using H2 as an in-memory database.

Uploaded by

Suresh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
21 views34 pages

Spring Training With Spring Boot

The document outlines a three-day training program on Spring and Spring Boot, covering core Java concepts, JDBC, and RESTful web services. It includes detailed topics for each day, such as Spring's dependency injection, bean lifecycle, and database integration with JPA. Additionally, it provides practical steps for creating a bank application using Spring Boot, including exception handling, validation, and using H2 as an in-memory database.

Uploaded by

Suresh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 34

Spring with spring boot - 3 days

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

requirment:
------------
core java
jdbc: way to connection to db
servlet jsp
some knowlege of design pattern
--------------------

SW: java 17
sts 4: ide eclipse
maven 3.6: build tool, it automcatically download the jar files
any framework in java ---> jar

mysql
postman

Day-1
---------
Spring Introduction
• Shortcomings of Java EE and the Need for Loose Coupling
• Managing Beans, The Spring Container, Inversion of Control
• The Factory Pattern
• Configuration Metadata - XML, @Component, Auto-Detecting Beans
• Dependencies and Dependency Injection (DI) with the BeanFactory
• Setter Injection
Dependency Injection
• Using the Application Context
• Constructor Injection
The Spring Container and API
• The Spring Managed Bean Lifecycle
• Autowiring Dependencies

Other Metadata Configurations


• Annotation Configuration @Autowired, @Required, @Resource
• @Component
• @Value and @Qualifier
• Life Cycle Annotations
• Java Configuration, @Configuration, XML free configuration
• The AnnotationConfigApplicationContext

oracle or mysql

mysql 8.x

Spring framework:
-------------------
java framework that make sw easy
Depdendency injection
loose coupling

pull vs push

spring framework act as a container and manage the life cycle of the beans
Car , Passanger, AccountService, AccountDao

how to configure the beans:


----------------------------
1. pure xml
2.xml + annotation
3. java config + annotation (spring boot)

what are main annotation we hv done :


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

@Component
|
--------------------------------------------------
| |
|
@Controller @Service @Repository

controller service
Repository

@Autowire
DI at 3 places:

1. field injection XX
2. setter injection (non mandatory dep)
3. ctr injection (mandatory dep)

Spring profile:
------------------
@Profile("test")

VM arg:
-Dspring.profiles.active=dev

u can swap the implementation with out changing the code

web---------------- service ----------------repository ----------- db

ravi mohit anil


(hashmap)

jdbc

spring basics
jdbc basics
jpa basics

Spring boot: (most poplular framewrok in java)


------------------------------------------------
H2 database with spring boot
h2 is in memory database
spring REST
bank application
ex handling
validation
database with h2
spring security
microservice idea
docker

Day 2:
-----
Spring and Persistence
• Spring and JDBC
• Spring and ORM

Spring Boot
Spring Boot Framework – High Level Overview
• Spring Architecture
• Spring Containers
• Spring Bean Lifecycle
• Spring DI
• Spring Autowiring

Day 3:
---------
Spring Boot – Database Integration
• Spring Boot – JDBC
• Spring Boot – JPA
• Spring Boot – Data
Introduction to Actuator

RESTful Web Services


• Core REST concepts
• REST support in Spring
• Use Spring MVC to create RESTful Web services
• REST specific Annotations in Spring
• URITemplates, @PathVariable, @RequestParam
• JSON and XML data exchange
• @RequestMapping

Introduction to Java EE and problems


---------------------------
intro to spring framework:
---------------------------
Spring is java framework for simplification of sw development
it have many modules

Spring framework important modules:

What is spring boot?


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

Why spring boot

Now we have spring boot:

Spring Dependency Injection


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

Need of Dependency Injection?

loose coupling and high cohesion?

A passanger is traveling using a car

Spring DI using XML


Spring DI using annotation

they do the same job


aka meta data for srping to tell what to do

@Component
@Autowire
replace lots of xml

spring xml----> annotation


how to force spring to go for annotations?

@Bean vs @Component
these are 2 ways to create bean using annotation
are they same... not

NoUniqueBeanDefinitionException: No qualifying bean of type


'com.busycoder.demo4.Vehicle' available: expected single matching bean but found
2: car,bike

Spring DI using java configuration


done
spring dependency injection important annotation
done

spring profile:
it allow you to swap the bean impl at run time without changing the code :)
devops: dev, test, pre-prod , prod

NoSuchBeanDefinitionException

spring bean life cycle basics


spring core interview questions

Spring DI bankapplication

3 tier app:

@Component
|
----------------------------------------------------
| |
|
@controller @Service @Repository
@RestController

web ---------------------- service --------------- dao layer -------------db

transfer the fund


deposit
withdraw

Spring boot REST bank application step by step :


-----------------------------------------------
=> Spring boot REST application
=> Spring data
=> Spring boot exception handing
=> Spring boot validation
=>Spring boot Monotring and Logging
=> spring boot profile
=> spring boot actuator
=> Spring Boot microservice architecture
=> spring boot openfeign
=> Spring boot security

=> Spring boot REST application


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

Step 1: create spring boot application : web, devtools

step 2: create repository layer


-----------------------------
class Account{
private int id;
private String name;
private double amount;
}
public interface AccountDao {
public List<Account> getAll();
public Account getById(int id);
public void updateAccount(Account account);
}

@Repository
public class AccountDaoImplMap implements AccountDao{

private Map<Integer, Account> map=new HashMap<>();


public AccountDaoImplMap(){
map.put(1, new Account(1,"amit",1000));
map.put(2, new Account(2,"sumit",1000));
}
@Override
public List<Account> getAll() {
return new ArrayList<>(map.values());
}

@Override
public Account getById(int id) {
return map.get(id);
}

@Override
public void updateAccount(Account account) {
map.put(account.getId(), account);
}
}

Step 3: create service layer and implementation


-------------------------
public interface AccountService {
public List<Account> getAll();
public Account getById(int id);
public void transfer(int fromId, int toId, double amount);
public void deposit(int fromId, double amount);
public void withdraw(int fromId, double amount);
}

@Service
public class AccountServiceImpl implements AccountService{

private AccountDao accountDao;

@Autowired
public AccountServiceImpl(AccountDao accountDao) {
this.accountDao = accountDao;
}

@Override
public List<Account> getAll() {
return accountDao.getAll();
}

@Override
public Account getById(int id) {
return accountDao.getById(id).orElseThrow(()->new
BankAccountNotFoundException("bank account with id "+id +" is not found"));
}
@Override
public void transfer(int fromId, int toId, double amount) {
Account fromAcc=getById(fromId);//load both the acc in memory
Account toAcc=getById(toId);
fromAcc.setAmount(fromAcc.getAmount()-amount);
toAcc.setAmount(toAcc.getAmount()+amount);
accountDao.updateAccount(fromAcc);
accountDao.updateAccount(toAcc);
}

@Override
public void deposit(int fromId, double amount) {
Account acc=getById(fromId);
acc.setAmount(acc.getAmount()+amount);
accountDao.updateAccount(acc);
}

@Override
public void withdraw(int fromId, double amount) {
Account acc=getById(fromId);
acc.setAmount(acc.getAmount()-amount);
accountDao.updateAccount(acc);
}
}

step 4: Write excpetion


-----------------------------
public class BankAccountNotFoundException extends RuntimeException {
private static final long serialVersionUID = 1L;

public BankAccountNotFoundException(String message) {


super(message);
}
}

step 5: Write Controllers


-----------------------------
AccountCrudController
---------------------------------

@Controller
@ResponseBody
public class AccountCrudController {

private AccountService accountService;

@Autowired
public AccountCrudController(AccountService accountService) {
this.accountService = accountService;
}

//@ResponseBody annotation ie contain inside @RestController automatically


covert java object to json
//-----------get all accounts-----
@GetMapping(path = "accounts")
public List<Account> getAll(){
return accountService.getAll();
}

//------------get account by id--------


@GetMapping(path = "accounts/{id}")
public Account getById(@PathVariable int id) {
return accountService.getById(id);
}

//------------add account-------

//------------delete account by id--------

//------------update account by id--------

step 5: Write Controllers


-----------------------------
TransctionController
---------------------------------

We need to write dto also

public class TransferDto {


private Integer fromAccId;
private Integer toAccId;
private double amount;
//getter setter ctr etc
}

public class DepositDto {


private Integer accId;
private double amount;
}

public class WithdrawDto {


private Integer accId;
private double amount;
}

@RestController
public class TransctionController {

private AccountService accountService;

public TransctionController(AccountService accountService) {


this.accountService = accountService;
}

//from postman i am sending json that need to be converted to java object:


@RequestBody
// transfer
@PostMapping(path="transfer")
public String transfer(@RequestBody TransferDto transferDto) {

accountService.transfer(transferDto.getFromAccId(),transferDto.getToAccId()
, transferDto.getAmount());
return "fund transfer successfully";
}

//deposit
@PostMapping(path="deposit")
public String deposit(@RequestBody DepositDto depositDto) {
accountService.deposit(depositDto.getAccId(), depositDto.getAmount());
return "fund deposit successfully";
}

//withdraw
@PostMapping(path="withdraw")
public String withdraw(@RequestBody WithdrawDto withdrawDto) {
accountService.withdraw(withdrawDto.getAccId(),
withdrawDto.getAmount());
return "fund withdra successfully";
}

step 5: Test with postman


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

all accounts : get


http://localhost:9090/accounts

get a particular account:


http://localhost:9090/accounts/1

Fund transfer : Post


http://localhost:9090/transfer

{
"fromAccId": 1,
"toAccId": 2,
"amount": 10
}

Fund deposit : Post


http://localhost:9090/deposit

{
"accId": 1,
"amount": 10
}

Fund withdraw : Post


http://localhost:9090/withdraw
{
"accId": 1,
"amount": 10
}

Part 2: Spring data


======================
abstracion on jpa u dont have to write dao layer

step 1: add new dep h2, jpa

step 2: use following to add to application.properties files


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

server.port=8090
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
# Custom H2 Console URL
spring.h2.console.path=/h2

spring.jpa.hibernate.ddl-auto=update

logging.level.org.springframework.web: DEBUG
logging.level.org.hibernate: ERROR

spring.jpa.show-sql=true

step 3: we want to apply jpa annotation to the class Account


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

@Entity
@Table(name="account_table")
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private double balance;
}

step 4: use spring data (abs over jpa)


-------------------------------------------
u dont need to write dao layer u need "declare" dao layer

AccountDao extends JpaRepository

@Repository
public interface AccountRepository extends JpaRepository<Account, Integer>{
}
step 5: change the implementation of service layer
-----------------------------------

@Service
public class AccountServiceImpl implements AccountService{

private AccountRepository accountRepository;

@Autowired
public AccountServiceImpl(AccountRepository accountRepository) {
this.accountRepository = accountRepository;
}

@Override
public List<Account> getAll() {
return accountRepository.findAll();
}

@Override
public Account getById(int id) {
Account account= accountRepository.findById(id).orElseThrow(()->new
BankAccountNotFoundException("bank account not found") );
return account;
}

@Override
public void transfer(int fromId, int toId, double amount) {
Account fromAcc=getById(fromId);
Account toAcc=getById(toId);
fromAcc.setBalance(fromAcc.getBalance()-amount);
toAcc.setBalance(toAcc.getBalance()+amount);

accountRepository.save(fromAcc);
accountRepository.save(toAcc);

@Override
public void deposit(int fromId, double amount) {
Account acc=getById(fromId);
acc.setBalance(acc.getBalance()+amount);
accountRepository.save(acc);

@Override
public void withdraw(int fromId, double amount) {
Account acc=getById(fromId);
acc.setBalance(acc.getBalance()-amount);
accountRepository.save(acc);
}

step 6: As soon as my application start i should have some records by default added
to the database:
-----------------------------------------------------------------------------------
----------------
h2-> as soon as i restart my application my data would be lost

CommandLineRunner in spring boot

@Component
public class DataInit implements CommandLineRunner {

@Autowired
private AccountRepository accountRepository;

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

//As soon as app start spring boot will run this run method
//data init job

accountRepository.save(new Account("amit", 1000.00));


accountRepository.save(new Account("sumit", 1000.00));
System.out.println("-------------2 accounts are added
---------------------");
}

step 7: login to h2 console with provided informations


--------------------------------------------------
http://localhost:9090/h2

step 8: (optional) use lombok to get rid of extra boilderplat code


--------------------------------------------------------------------
install lombok
https://projectlombok.org/download

step 8: it is not good to use amount or balance as double


we should use BigDecimal
--------------------------------------------------------

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class DepositDto {
private Integer accId;
private BigDecimal amount;

@Data
public class TransferDto {
private Integer fromAccId;
private Integer toAccId;
private BigDecimal amount;
}

@Data
public class WithdrawDto {
private Integer accId;
private BigDecimal amount;

@Entity
@Table(name="account_table")
@Data
@NoArgsConstructor
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private BigDecimal balance;

public Account(String name, BigDecimal balance) {


this.name = name;
this.balance = balance;
}
}

step 8 (b) change the service layer to use BigDecimal


-----------------------------------------------------
public interface AccountService {
public List<Account> getAll();
public Account getById(int id);
public void transfer(int fromId, int toId, BigDecimal amount);
public void deposit(int fromId, BigDecimal amount);
public void withdraw(int fromId, BigDecimal amount);
}

and change the implementation


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

@Service
public class AccountServiceImpl implements AccountService{

private AccountRepository accountRepository;

@Autowired
public AccountServiceImpl(AccountRepository accountRepository) {
this.accountRepository = accountRepository;
}

@Override
public List<Account> getAll() {
return accountRepository.findAll();
}
@Override
public Account getById(int id) {
Account account= accountRepository.findById(id).orElseThrow(()->new
BankAccountNotFoundException("bank account not found") );
return account;
}

@Override
public void transfer(int fromId, int toId, BigDecimal amount) {
Account fromAcc=getById(fromId);
Account toAcc=getById(toId);
fromAcc.setBalance(fromAcc.getBalance().subtract(amount));
toAcc.setBalance(toAcc.getBalance().add(amount));

accountRepository.save(fromAcc);
accountRepository.save(toAcc);

@Override
public void deposit(int fromId, BigDecimal amount) {
Account acc=getById(fromId);
acc.setBalance(acc.getBalance().add(amount));
accountRepository.save(acc);

@Override
public void withdraw(int fromId, BigDecimal amount) {
Account acc=getById(fromId);
acc.setBalance(acc.getBalance().subtract(amount));
accountRepository.save(acc);
}

step 9: i want to add for address and phone to account class


-----------------------------------------------------------
@Entity
@Table(name="account_table")
@Data
@NoArgsConstructor
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private BigDecimal balance;
private String phone;
private String email;
private String address;
}

change dbint accordingly

Step 10: we will add more crud methods (with db)


----------------------------------------------------
try urself:
//------------add account--------------------
//------------delete account by id--------
//------------update account by id--------

Step 10.1: add new method decleration to the service layer


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

public interface AccountService {


public Account addAccount(Account account);
public Account deleteAccount(int id);
public void updateAccount(int id, AccountDetailDto accountDetailDto);
}

Step 10.2: Create a dto for update operation


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

@Data
public class AccountDetailDto {
private String phone;
private String email;
private String address;
}

Step 10.3: implement these method new method decleration to the service layer
------------------------------------------------------

@Service
@Transactional
public class AccountServiceImpl implements AccountService{

//.....

@Override
public Account deleteAccount(int id) {
Account accountToDelete= getById(id);
accountRepository.delete(accountToDelete);
return accountToDelete;
}

@Override
public void updateAccount(int id, AccountDetailDto accountDetailDto) {
Account accountToUpdated= getById(id);
accountToUpdated.setAddress(accountDetailDto.getAddress());
accountToUpdated.setPhone(accountDetailDto.getPhone());
accountToUpdated.setEmail(accountDetailDto.getEmail());

accountRepository.save(accountToUpdated);//save do both add/update


operation ins spring data
}

Step 10.4: create corrosponding controller


------------------------------------------------------
@Controller
@ResponseBody
public class AccountCrudController {

//.......

//@RequestBody force json object to be converted to java object,


//proper "parser" jackson parser is alredy in the classpath
//we just need to add parser for xml

//------------add account-------
@PostMapping(path = "accounts")
public Account addAccount( @RequestBody Account account) {
return accountService.addAccount(account);
}

//------------delete account by id--------


@DeleteMapping(path = "accounts/{id}")
public Account deleteById(@PathVariable int id) {
return accountService.deleteAccount(id);
}

//------------update account by id--------


@PutMapping(path = "accounts/{id}")
public String updateAccount(@PathVariable int id,@RequestBody
AccountDetailDto accountDetailDto) {
accountService.updateAccount(id, accountDetailDto);
return "account details are updated successfully";
}

Step 11: how to send correct status code


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

how to send correct status code: ResponseEntity

ResponseEntity: bag that can hold 2 thinng data + status code

@Controller
@ResponseBody
public class AccountCrudController {

private AccountService accountService;

@Autowired
public AccountCrudController(AccountService accountService) {
this.accountService = accountService;
}
//@ResponseBody annotation ie contain inside @RestController automatically
covert java object to json
//-----------get all accounts-----
@GetMapping(path = "accounts")
public ResponseEntity<List<Account>> getAll(){
List<Account> accounts= accountService.getAll();
return ResponseEntity.status(HttpStatus.OK).body(accounts);
}

//------------get account by id--------


@GetMapping(path = "accounts/{id}")
@ResponseStatus(code = HttpStatus.OK)
public Account getById(@PathVariable int id) {
return accountService.getById(id);
}

//@RequestBody force json object to be converted to java object,


//proper "parser" jackson parser is alredy in the classpath
//we just need to add parser for xml

//------------add account-------
@PostMapping(path = "accounts")
public ResponseEntity<Account> addAccount( @RequestBody Account account) {
return
ResponseEntity.status(HttpStatus.CREATED).body(accountService.addAccount(account));
}

//------------delete account by id--------we dont return anything 204


@DeleteMapping(path = "accounts/{id}")
public ResponseEntity<Void> deleteById(@PathVariable int id) {
accountService.deleteAccount(id);
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}

//------------update account by id--------


@PutMapping(path = "accounts/{id}")
public ResponseEntity<String> updateAccount(@PathVariable int
id,@RequestBody AccountDetailDto accountDetailDto) {
accountService.updateAccount(id, accountDetailDto);
String message= "account details are updated successfully";
return ResponseEntity.ok(message);
}

@RestController
public class TransctionController {

private AccountService accountService;

public TransctionController(AccountService accountService) {


this.accountService = accountService;
}

//from postman i am sending json that need to be converted to java object:


@RequestBody
// transfer
@PostMapping(path="transfer")
public ResponseEntity<String> transfer(@RequestBody TransferDto transferDto)
{

accountService.transfer(transferDto.getFromAccId(),transferDto.getToAccId()
, transferDto.getAmount());
String fundTransferMessage= "fund transfer successfully";
return ResponseEntity.ok(fundTransferMessage);
}

//deposit
@PostMapping(path="deposit")
public ResponseEntity<String> deposit(@RequestBody DepositDto depositDto) {
accountService.deposit(depositDto.getAccId(), depositDto.getAmount());
String fundDepositMessage= "fund deposit successfully";
return ResponseEntity.ok(fundDepositMessage);
}

//withdraw
@PostMapping(path="withdraw")
public ResponseEntity<String> withdraw(@RequestBody WithdrawDto withdrawDto)
{
accountService.withdraw(withdrawDto.getAccId(),
withdrawDto.getAmount());
String fundWithdrawMessage= "fund withdraw successfully";
return ResponseEntity.ok(fundWithdrawMessage);
}

Step 12: Tranasction management:


----------------------------------
ACID concepts
in normal app: u are responsible for tx mgt

try{
tx.begin();

tx.commit();
}catch(..........){
}

Spring data : automatically transactional


but in terms of business logic we need to apply tx in service:

Spring provide declearitive tx mgt


i should put the @Transactional
acid concept is taken care itself

Pls refer
https://www.marcobehler.com/guides/spring-transaction-management-transactional-in-
depth
for more indepth understanding on tx mgt
step 13: exception handing
--------------------------
How to do excpetion handing in spring boot:
using AOP* (Aspect oriented programming)
it is a way to handle cross cutting concern?

service: BL + tx , sec, caching, ex handing

AOP is just a techenique to handle ccc in declerative way

{
"timestamp": "2024-05-30T05:41:30.232+00:00",
"status": 500,
"error": "Internal Server Error",
"toContact":"[email protected]"
}

step 13.1 we need a dto to hold the error message:


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

@Data
public class ErrorInfo {
private String timestamp;
private String status;
private String error;
private String toContact;
}

step 13.2 we need write a special controller to handle the exceptions


---------------------------------------------------
@RestControllerAdvice
public class BankAppExHandlerController {

@ExceptionHandler(BankAccountNotFoundException.class)
public ResponseEntity<ErrorInfo> handle404(BankAccountNotFoundException ex){

ErrorInfo errorInfo= ErrorInfo.builder()


.error(ex.getMessage())
.toContact("[email protected]")
.timestamp(LocalDateTime.now())
.status(HttpStatus.NOT_FOUND.toString())
.build();
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorInfo);
}

@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorInfo> handle500(Exception ex){

ErrorInfo errorInfo= ErrorInfo.builder()


.error("pls try after some time")
.toContact("[email protected]")
.timestamp(LocalDateTime.now())
.status(HttpStatus.INTERNAL_SERVER_ERROR.toString())
.build();
return
ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorInfo);
}
}

step 14: validation


--------------------
We need to ensure to stop the user to send wrong data to the application
for ex:
{
"name": null,
"balance": 1000.00,
"phone": "9950543978",
"email": "indu@gmail",
"address": "banglore"
}

data should not be allowed during post call to add a account

How to achive it?

Step 14.1: add a validation starter


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

Step 14.2: Apply the annotation on pojo so that validation can be done
----------------------------------

@Entity
@Table(name="account_table")
@Data
@NoArgsConstructor
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;

@NotNull(message = "account holder name can not be null")


@Pattern(regexp = "[A-Za-z]+( [A-Za-z]+)*", message = "account holder name
should be alphabets")
private String name;
@NotNull(message = "balance should not be null")
@Range(min = 10, max = 100000, message = "account balance must be in range of
10 to 100000")
private BigDecimal balance;

@NotNull(message = "phone should not be null")


@Pattern(regexp = "[789][0-9]{9}", message = "phone no should be valid")
private String phone;

@Email(message = "email should be correct formate")


@NotNull(message = "email should not be null")
private String email;

@NotNull(message = "address should not be null")


private String address;

public Account(String name, BigDecimal balance, String phone, String email,


String address) {
this.name = name;
this.balance = balance;
this.phone = phone;
this.email = email;
this.address = address;
}

Step 14.3: Force spring boot to apply these annotation before converting to java
objection -> @Valid
--------------------------------------------------------------------
@PostMapping(path = "accounts")
public ResponseEntity<Account> addAccount( @RequestBody @Valid Account
account) {
return
ResponseEntity.status(HttpStatus.CREATED).body(accountService.addAccount(account));
}

BAD_REQUEST

Step 14.4: Now we need to write a handler to handle MethodArgumentNotValidException


--------------------------------------------------------------------
import java.time.LocalDateTime;

@RestControllerAdvice
public class BankAppExHandlerController {

//-----------------

//MethodArgumentNotValidException
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorInfo> handle400(MethodArgumentNotValidException
ex){

ErrorInfo errorInfo= ErrorInfo.builder()


.error("some validation problem")
.toContact("[email protected]")
.timestamp(LocalDateTime.now())
.status(HttpStatus.BAD_REQUEST.toString())
.build();
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorInfo);
}

Step 14.5: Now we need to give cause why validation have failed?
--------------------------------------------------------------------

//MethodArgumentNotValidException
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorInfo> handle400(MethodArgumentNotValidException
ex){

String errorMessage= ex.getBindingResult()


.getAllErrors()
.stream()
.map(x->x.getDefaultMessage())
.collect(Collectors.joining(", "));

ErrorInfo errorInfo= ErrorInfo.builder()


.error(errorMessage)
.toContact("[email protected]")
.timestamp(LocalDateTime.now())
.status(HttpStatus.BAD_REQUEST.toString())
.build();
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorInfo);
}

Step 14.6: Hard coding of error message is bad thing, how to control it?
--------------------------------------------------------------------
spring boot alreay have message handler configured... u just need to use it

We need to write the message into a file


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

ValidationMessages.properties
-----------------------------
account.email.absent=Please provide email address
account.email.invalid=Please provide valid email address

account.name.absent=Please provide customer name


account.name.invalid=Name should contain only alphabets and space

account.phone.absent=Please provide phone


account.phone.invalid=Please provide correct phone number of 10 digits

account.balance.absent=Please provide initial balance


account.balance.invalid=Please provide correct initial balance bw 100 to 100000

what if file name is something else ( u need to define a extra bean)


----------------------------------------------------------------------
https://www.baeldung.com/spring-custom-validation-message-source
Now apply these values to the pojo
-----------------------------------------

@NotNull(message = "{account.name.absent}")
@Pattern(regexp = "[A-Za-z]+( [A-Za-z]+)*", message =
"{account.name.invalid}")
private String name;

@NotNull(message = "{account.balance.absent}")
@Range(min = 100, max = 100000, message = "{account.balance.invalid}")
private BigDecimal balance;

@Email(message = "{account.email.invalid}")
@NotNull(message = "{account.email.absent}")
private String email;

@NotNull(message = "{account.phone.absent}")
@Pattern(regexp = "[789][0-9]{9}", message = "{account.phone.invalid}")
private String phone;

Step 14.7: Hard coding of error message is bad thing, how to control it?
--------------------------------------------------------------------

step 14.7.1: put string for error message into application.properties file
--------------------------------------------------------------------------
UserInterface.TRANSFER_SUCCESS=transfer done successfully
UserInterface.DEPOSIT_SUCCESS=amount deposit successfully
UserInterface.WITHDRAW_SUCCESS=amount withdraw successfully

Service.ACCOUNT_NOT_EXISTS=Account not exist

Service.FROM_ACCOUNT_NOT_EXISTS=From Account not exist

Service.TO_ACCOUNT_NOT_EXISTS=To Account not exist

Service.NOT_SUFFICIENT_BALANCE=Account dont have sufficient balance

step 14.7.2: we need to get these values into my controller/service layer


--------------------------------------------------------------------------
Autowire Environment to the controller , this will help me to get error
informations

@RestController
public class TransctionController {

private AccountService accountService;


private Environment environment;
@Autowired
public TransctionController(AccountService accountService, Environment
environment) {
this.accountService = accountService;
this.environment = environment;
}

step 14.7.2:we need to get values using environment so that no hard coding must be
there in project
--------------------------------------------------------------------------

@RestController
public class TransctionController {

private AccountService accountService;


private Environment environment;

@Autowired
public TransctionController(AccountService accountService, Environment
environment) {
this.accountService = accountService;
this.environment = environment;
}

//from postman i am sending json that need to be converted to java object:


@RequestBody
// transfer
@PostMapping(path="transfer")
public ResponseEntity<String> transfer(@RequestBody TransferDto transferDto)
{

accountService.transfer(transferDto.getFromAccId(),transferDto.getToAccId()
, transferDto.getAmount());

String fundTransferMessage=
environment.getProperty("UserInterface.TRANSFER_SUCCESS");

return ResponseEntity.ok(fundTransferMessage);
}

//deposit
@PostMapping(path="deposit")
public ResponseEntity<String> deposit(@RequestBody DepositDto depositDto) {
accountService.deposit(depositDto.getAccId(), depositDto.getAmount());
String fundDepositMessage=
environment.getProperty("UserInterface.DEPOSIT_SUCCESS");
return ResponseEntity.ok(fundDepositMessage);
}

//withdraw
@PostMapping(path="withdraw")
public ResponseEntity<String> withdraw(@RequestBody WithdrawDto withdrawDto)
{
accountService.withdraw(withdrawDto.getAccId(),
withdrawDto.getAmount());
String fundWithdrawMessage=
environment.getProperty("UserInterface.WITHDRAW_SUCCESS");
return ResponseEntity.ok(fundWithdrawMessage);
}

step 15: how to support xml xml support


-------------------------------------------
We need a parser for xml (for json it is alreay there in spring boot)

Step 1: put parser for xml

<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>

Step 2:
@GetMapping(path = "products", produces = {MediaType.APPLICATION_JSON_VALUE,
MediaType.APPLICATION_XML_VALUE})

Step 16: bannner:


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

spring.banner.location=classpath:banner.txt

https://devops.datenkollektiv.de/banner.txt/index.html

Step 14: running spring boot application as jar file:


--------------------
java -jar jpa_demo2-0.0.1-SNAPSHOT.jar --server.port=8050

step 16: spring boot mysql


----------------------------
Step 16.1: add mysql dep in the pom of spring boot

step 16.2: put prop related to mysql


----------------------------------------
spring.datasource.url=jdbc:mysql://localhost:3306/demoms?useSSL=false
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.jpa.hibernate.ddl-auto=update
logging.level.org.springframework.web: DEBUG
logging.level.org.hibernate: ERROR
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

step 16.3: Create database and use it and run it...


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

step 17: spring boot profile


----------------------------
let say i want to switch from h2 to mysql dependeing on devops

dev
test
pre-prod
prod

test: h2
prod: mysql

how to manage switching the profile

step 17.1: we need to create diff prop file depending on profile


---------------------------------------------------------------
application-prod.properties
---------------------------

spring.datasource.url=jdbc:mysql://localhost:3306/edu123
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

application-test.properties
----------------------------
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.path=/h2

step 17.2 use profile while running the app as jar file:
---------------------------------------------------------
java -jar bankapp.jar --spring.profiles.active=prod
how to change the port number?

java -jar --spring.profiles.active=prod bankapp.jar --server.port=9999


step 16: spring boot reading property files:
---------------------------------
refer example :
bankapp-08-profile from github

1. @Value annotation
2. Enviornment
3. @ConfigrationProperties

@EnableConfigurationProperties(Config.class)

@ConfigurationProperties(prefix="spring.datasource")

Step 16: how to change the embedded server?


---------------------------------------------
https://howtodoinjava.com/spring-boot/configure-jetty-server/

step 17: spring boot logging customization:


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

spring boot logging:


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

Disable logging :
---------------
logging.level.root=OFF
logging.level.org.springframework.boot=OFF
spring.main.banner-mode=OFF

Customizing logging :
---------------
logging.level.org.springframework.web: DEBUG
logging.level.org.hibernate: ERROR

logging.level.com.productapp=info

logging.level.org.springframework.web: DEBUG
logging.level.org.hibernate: ERROR

# Logging pattern for the console


logging.pattern.console= "%d{yyyy-MM-dd } [%thread] %-5level %logger{36} - %msg%n"
#logging pattern for file
logging.pattern.file= "%d{yyyy-MM-dd } [%thread] %-5level %logger{36} - %msg%n"

logging.file.name=/home/raj/Desktop/logs/server.log
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-spring-boot</artifactId>
</dependency>

step 18: swagger documentation


-------------------------------
https://www.baeldung.com/spring-rest-openapi-documentation

=> Documenting a Spring REST API Using OpenAPI 3.0


=>Swagger is almost equivalent to SOAP formate, used for documentation of REST api

Step 1:

<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.2.0</version>
</dependency>

Step 2:

http://localhost:9090/v3/api-docs

http://localhost:9090/swagger-ui/index.html

http://localhost:9090/v3/api-docs.yaml

Step 3:
Customization location
springdoc.swagger-ui.path=/swagger-ui-bankapp.html

@OpenAPIDefinition(info = @Info(title = "bookapp API", version = "2.0" ,


description = "YMSLI bookapp API"))
public class BookappApplication implements CommandLineRunner {
}
step 19: spring boot actuator:
-------------------------------
Actually it is used to monitor / track various things
info, database , application matrix

http or jmx

even we can create custom endpoints

server.port=8080
spring.devtools.restart.enabled=true

#management.endpoints.web.exposure.exclude=*
management.endpoints.web.exposure.include=health, custom-endpoint

management.endpoint.health.show-details=always

management.health.disk.enabled=true
management.health.livenessstate.enabled=true
management.health.readinessstate.enabled=true
management.server.port=9090

#/actuator/info endpoint will show the information given here, keys


# that are started with info

management.info.env.enabled=true
info.app.encoding=UTF-8
info.app.java.source=11
info.app.java.target=11
info.app.name=spring booot actuator

Custom end points

@Configuration
@Endpoint(id = "custom-endpoint")
public class CustomEndpoints {
@ReadOperation
public String getCustomData(){
return "This is custom Data";
}
}

step 20: how to create war file of the project and deploy to tomcat / jboss
---------------------------------------------------------------------------

step 21: how to create docker images of spring boot application


----------------------------------------------------------------
step 2: Create Dockerfile

FROM openjdk:17-alpine
MAINTAINER email="[email protected]"
EXPOSE 8080
ADD target/empapp.jar empapp.jar
ENTRYPOINT ["java","-jar","empapp.jar"]

step 3: create image using command

docker build -t rgupta00/empapp:1.2 .

docker image ls

step 4: run image


docker container run --name producer -p 8080:8080 -d rgupta00/empapp:1.2

docker container logs <id>

docker container logs -f <id>

step 5: push image to docker hub

first login : docker login

then run command :


docker tag empapp:1.2 rgupta00/empapp:1.2
docker push rgupta00/empapp:1.2

step 6: pull image from the docker hub

docker pull rgupta00/empapp:1.2

step 7: other person now can pull the image

remove the images


docker images
docker image rmi <imgid> -f

now pull the image and run it

docker run --name empapp -p 8080:8080 rgupta00/empapp:1.2


Roadmap for modern java backend engg : 2024
---------------------------------------------
core java:
----------
OOPs concepts
Interface abs class
SOLID

io, serilization
ex handling
logging: log4j

collection aka readymade


how to imp ll, stack, tree.... Competitive programming*

adv java:
-------------

Threads

Java reflection

java annotation

java 8 features

java 9 features

java 17 upto features

GOF patterns

JDBC
tx mgt
ACID

Servlet jsp basics

Spring framework
DI
AOP
Spring jdbc
Spring Hibernate
Spring mvc with jsp (basics)

Spring Boot
=> Understand Depdendency Injection
=> bean wiring :xml, annoation, java configuraton
=> Spring boot aop
=> spring mvc basics
=> REST basics
=> Spring boot REST application
=> Spring AOP
=> Spring JDBCTemplate
=> Spring data
=> Spring boot web application, Spring MVC arch
=>Spring boot Monotring and Logging
=> Spring boot security
=> spring boot profile
=> spring boot actuator
=> spring boot jdbcTemplate
=> Spring Boot microservice architecture
=> spring boot openfeign

Docker k8s linux


Microservices

-----------imp property file configurations------------------

server.port=8090
server.servlet.context-path=/bankapp
spring.datasource.driver-class-name= com.mysql.jdbc.Driver
spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto= update
spring.datasource.url=jdbc:mysql://localhost:3306/edu123?useSSL=false
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

spring.jpa.hibernate.ddl-auto=update

# if u want to disable logging


#logging.level.root=OFF
#logging.level.org.springframework.boot=OFF
#spring.main.banner-mode=OFF

logging.level.org.springframework.web: DEBUG
logging.level.org.hibernate: ERROR
logging.level.com.productapp: INFO
logging.level.com.productapp.service: INFO

logging.pattern.console= "%d{yyyy-MM-dd } [%thread] %-5level %logger{36} - %msg%n"


#logging pattern for file
logging.pattern.file= "%d{yyyy-MM-dd } [%thread] %-5level %logger{36} - %msg%n"
#i wnat to send logs to a specific file?

spring.jpa.show-sql=true
spring.banner.location=
spring.jmx.enabled=true
management.endpoints.web.exposure.include=*
management.endpoints.jmx.exposure.include=*

management.info.env.enabled=true
info.app.encoding=UTF-8
info.app.java.source=21
info.app.java.target=21
info.app.name=productapp
info.app.dev=amit ku

management.endpoint.health.show-details=always
management.endpoint.health.probes.enabled=true
# livenessstate readinessstate
#management.health.livenessstate.enabled=true
#management.health.readinessstate.enabled=true

UserInterface.INTERNAL_SERVER_ERROR=some internal server error


#UserInterface.PRODUCT_ADD_SUCCESS=product added successfully
#UserInterface.PRODUCT_UPDATE_SUCCESS=product added successfully
#UserInterface.PRODUCT_DELETE_SUCCESS=product added successfully
#
#Service.PRODUCT_NOT_EXISTS=Product not exist
#
#
#product.name.absent=Please provide product name
#product.name.invalid=product Name should contain only alphabets and space
#
#product.price.absent=Please provide product price
#account.price.invalid=Please provide correct price bw 100 to 100000

info.key=default
spring.profiles.active=test

server.port=8090
server.servlet.context-path=/productapp
spring.h2.console.enabled=true

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=foo
spring.datasource.password=foo
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

# Custom H2 Console URL


spring.h2.console.path=/h2

spring.jpa.hibernate.ddl-auto=update
Reference book:
-----------------
Beginning Spring Boot 3: Build Dynamic Cloud-Native Java Applications and
Microservices Paperback

interview questions:
https://github.com/altafjava/spring-interview-questions-answers
https://stackoverflow.com/questions/11316688/inversion-of-control-vs-dependency-
injection-with-selected-quotes-is-my-unders
https://stackoverflow.com/questions/6550700/inversion-of-control-vs-dependency-
injection

You might also like