Skip to content

BanuPrakash/SPRING

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

38 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Building Restful WS using Spring Boot

Banu Prakash C
Full Stack Architect, Corporate Trainer
Co-founder & EX-CTO: Lucida Technologies Pvt Ltd.,
Email: banuprakashc@yahoo.co.in; banuprakash.cr@gmail.com;
https://www.linkedin.com/in/banu-prakash-50416019/
https://github.com/BanuPrakash/SPRING

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

Softwares Required:
1) openJDK 21
https://jdk.java.net/java-se-ri/21

 For Mac machine USE SDKMAN to manage java

curl -s "https://get.sdkman.io" | bash

sdk install java 21.0.6-tem

sdk default java 21.0.6-tem 

https://mydeveloperplanet.com/2022/04/05/how-to-manage-your-jdks-with-sdkman/#:~:text=Some%20time%20ago%2C%20a%20colleague%20of%20mine,maintain%20different%20versions%20of%20JDKs%2C%20Maven%2C%20etc.


2) IntelliJ Ultimate edition https://www.jetbrains.com/idea/download/?section=mac

3) MySQL  [ Prefer on Docker]

Install Docker Desktop / PODMAN

Docker steps:

a) docker pull mysql
b) docker run --name local-mysql –p 3306:3306 -e MYSQL_ROOT_PASSWORD=Welcome123 -d mysql

container name given here is "local-mysql"

For Mac:
docker run -p 3306:3306 -d --name local-mysql -e MYSQL_ROOT_PASSWORD=Welcome123 mysql


c) CONNECT TO A MYSQL RUNNING CONTAINER:

$ docker exec -t -i local-mysql bash

d) Run MySQL client:

bash terminal> mysql -u "root" -p

mysql> exit

Spring Boot 3.5 version needs JDK 17 version

Introduction to Spring Framework and Spring Boot. RDBMS and JPA Building RESTful WebServices

  • AOP
  • Exception Handling
  • Micrometer
  • Cache
  • HATEOAS
  • Async operations Security

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

SOLID Design Principles S - Single Responsibility O - Open close Principle L - Liskov Substitution I - Interface seggretgation D - Dependency Injection

======== Container is a layer/application on top of JRE. Servlet Container / EJB Container Java 1.2 - Bean is a resuable software component

Spring Framework provides container.

  • Life Cycle management of beans [instantiate, destroy]
  • Bean: any object managed by spring container
  • Wiring dependencies

Spring needs metadata in the form of XML / Annotation

    interface EmployeeDao {
        void addEmployee(Employee employee);
    }

    public class EmployeeDaoDbImpl implements EmployeeDao {
        // ..
        public void addEmployee(Employee employee) {
            ..
        }
    }

     public class EmployeeDaoMongoImpl implements EmployeeDao {
        // ...
        public void addEmployee(Employee employee) {
            ..
        }
    }

    public class AppService {
        private EmployeeDao employeeDao;

        private void setEmpDao(EmployeeDao edao) {
            this.employeeDao = edao;
        }

        public void doTask(Employee e) {
            employeeDao.addEmployee(e);
        }
    }

XML as metadata for Spring beans.xml

    <beans>
        <bean id="rdbms" class="pkg.EmployeeDaoDbImpl" />
        <bean id="mongo" class="pkg.EmployeeDaoMongoImpl" />
        <bean id="service" class="pkg.AppService">
            <property name="empDao" ref="mongo" />
        </bean>
    </beans>

    // Internals
  // SAX Parser - Runtime
  Object rdbms = Class.forName("pkg.EmployeeDaoDbImpl").getConstructor().newInstance();
  Object mongo = Class.forName("pkg.EmployeeDaoDbImpl").getConstructor().newInstance();
  Object service = Class.forName("pkg.AppService").getConstructor().newInstance();
  service.setEmpDao(mongo);

  ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml", ""); 

  AppService service = ctx.getBean("service", AppService.class); 

Annotation as metadata: Preffered Spring looks for the following annotations at type level and instantiates the beans:

  1. @Component [util / helpers]
  2. @Repository [persistence store]
  3. @Service
  4. @Controller [ traditional web applications]
  5. @RestController [ RESTful Web services]
  6. @Configuration [ read config files, factory methods, ..]
  7. @ControllerAdvice [ Global exception handlers ]
  8. @ShellComponent [ spring boot 3.5 version onwards] [ Creating Shell Commands - REPL]

Spring uses @Autowired or Constructor Dependency Injection

Java 1.5 version onwards annotation is integral

   interface EmployeeDao {
        void addEmployee(Employee employee);
    }

    @Repository
    public class EmployeeDaoDbImpl implements EmployeeDao {
        // ..
        public void addEmployee(Employee employee) {
            ..
        }
    }

    @Service
    public class AppService {
        @Autowired
        private EmployeeDao employeeDao;

        public void doTask(Employee e) {
            employeeDao.addEmployee(e);
        }
    }

     ApplicationContext ctx = new AnnotationConfigApplicationContext();
     ctx.scan("com.cisco.prj"); // takes care of sub-packages 
     ctx.refresh();

A key benefit of using @Repository is that it enables Spring's exception translation mechanism.

https://github.com/spring-projects/spring-framework/blob/main/spring-jdbc/src/main/resources/org/springframework/jdbc/support/sql-error-codes.xml

    try {


    } catch(SQLException exception) {
        if(exception.getErrorCode() == 1605) {
            throw new DuplicateKeyException("Product with the ID : " + id + " already exists!!");
        } else if(exception.getErrorCode() === ..) {

        }
    }

Spring Boot Framework: Framework on top of Spring Framework. Spring Boot 2 built on top of Spring Framework 5.x Spring Boot 3 is built ont top of Spring Framework 6.x

Why Spring Boot?

  • Highly Opiniated Framework, lots of config comes out of the box
  • assume we are building web based application
  1. Configures Embedded Tomcat Servlet Container / web server out of the box Alternatives: Jetty / Netty
  2. Provides JACKSON library for Java to JSON and JSON to Java conversion Alternates: Jettison / GSON / MOXY
  3. Provides DispatcherServlet as FrontController
  • assume we are building JPA / ORM based application
  1. provides Database Connection Pooling using HikariCP library Alternate : C3p0/ DriverManagerDataSource ...
  2. Uses Hibernate as ORM provider Alternate: Toplink / KODO / JDO / OpenJPA ....
  • Easy to Dockerize

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

SpringApplication.run(DemoApplication.class, args); is similar to new AnnotationConfigApplicationContext();

@SpringBootApplication is 3 in 1

  1. @Configuration
  2. @ComponentScan(basePackage="com.cisco.demo")
  3. @EnableAutoConfiguration
@Autowired
private UserRepo userRepo;

Could not autowire. There is more than one bean of 'UserRepo' type.
Beans:
userRepoDbImpl   (UserRepoDbImpl.java) 
userRepoMongoImpl   (UserRepoMongoImpl.java)

Solution 1: using @Primary [ rarely used]

@Repository
@Primary
public class UserRepoDbImpl implements UserRepo {

@Repository
public class UserRepoMongoImpl implements UserRepo {

@Service
public class AppService {
    @Autowired
    private UserRepo userRepo; // UserRepoDbImpl will be wired

Solution 2: @Qualifier

@Repository
public class UserRepoDbImpl implements UserRepo{

@Repository
public class UserRepoMongoImpl implements UserRepo{

@Service
public class AppService {
    @Autowired
    @Qualifier("userRepoDbImpl")
    private UserRepo userRepo;


@Service
public class AdminService {
    @Autowired
    @Qualifier("userRepoMongoImpl")
    private UserRepo userRepo;

Solution 3: using @Profile

@Repository
@Profile("dev")
public class UserRepoDbImpl implements UserRepo{

@Repository
@Profile("prod")
public class UserRepoMongoImpl implements UserRepo{


@Service
public class AdminService {
    @Autowired
    private UserRepo userRepo;

Option 1: use application.properties
spring.profiles.active=dev

Option 2: Program arguments
More Run Configuration -> Modify Run Configuration -> Active profile = dev or prod
java -Dspring.profiles.active=prod com.cisco.demo.DemoApplication

Solution 4: using @ConditionalOnMissingBean

@Repository
public class UserRepoMongoImpl implements UserRepo{

@Repository
@ConditionalOnMissingBean(name="userRepoMongoImpl")
public class UserRepoDbImpl implements UserRepo{

@Service
public class AdminService {
    @Autowired
    private UserRepo userRepo;

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

Factory Methods wrt Spring:

  1. 3rd party classes to be used in Spring Container
  2. Object instantiate and intialize is not straight forward.

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

Spring integration with JPA/ORM

ORM: Object Relational Mapping Object mapped to relational database tables

ORM frameworks for Java Hibernate -- JBOSS -- RedHat TopLink -- Oracle KODO -- BEA -- Oracle JDO -- SUN MS -- Oracle OpenJPA -- Apache ..

Example of using Spring Framework and JPA:


@Entity
@Table(name="EMP")
public class Employee {
    @Column(name="EMP_NO")
    private String empNo;

    @Column(name="HDATE")
    private Date hireDate;
}

@Configuration
public class AppConfig {

    // @Bean informs Spring to invoke the method
    // returned object should be managed within Spring container
    @Bean
    public DataSource getDataSource() throws Exception{
        ComboPooledDataSource cpds = new ComboPooledDataSource();
        cpds.setDriverClass( "org.h2.Driver" ); //loads the jdbc driver
        cpds.setJdbcUrl( "jdbc:h2:mem:testdb" );
        cpds.setUser("sa");
        cpds.setPassword("");
        cpds.setMinPoolSize(5);
        cpds.setAcquireIncrement(5);
        cpds.setMaxPoolSize(20);
        return cpds;
    }

    @Bean
    public EntityManagerFactory emf(DataSource ds) {
        LocalContainerEntityManagerDactoryBean emf = new LocalContainerEntityManagerDactoryBean();
        emf.setDataSource(ds);
        emf.setJpaVendor(new HibernateJpaVendor());
        emf.setPackagestoScan("com.cisco.prj.entity"); // where are my entities
        ...
        return emf;
    }
}


@Repository
public class EmployeeRepo {
    @PersistenceContext
    EntityManager em;

    public void addEmployee(Employee e) {
        em.persist(e);
    }
}

Spring Boot comes with Spring Data JPA module:

  • we need to do entity mapping to database table
  • No need to write any implementation classes. write an interface, implementation classes are generated by Spring Data JPA.
  • no need to write DataSource, EntityManagerFactory ,,, Based on entries present in application.properties Spring Data JPA creates EntityManagerFactory, DataSource, ... [ No need for above AppConfig code]

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

docker run -p 3306:3306 -d --name local-mysql -e MYSQL_ROOT_PASSWORD=Welcome123 mysql
OR
podman run -p 3306:3306 -d --name local-mysql -e MYSQL_ROOT_PASSWORD=Welcome123 mysql

banuprakash@Banuprakashs-MacBook-Pro SPRING % docker exec -it local-mysql bash
bash-4.4# mysql -u root -p
Enter password: 
mysql> create database SPRING;
mysql> use SPRING;
mysql> 

Spring Boot application with following dependencies:

  1. lombok
  2. Spring Data JPA
  3. MySQL later we will add web [ for RESTful]

https://docs.spring.io/spring-boot/appendix/application-properties/index.html

  1. spring.jpa.hibernate.ddl-auto=create create tables for entities when application starts, on application exist drop tables Good for Testing environment only

  2. spring.jpa.hibernate.ddl-auto=update Top to Bottom apporach or Middle appraoch create tables if not exist if exists map table to entity if required alter table like adding columns, change size of column

  3. spring.jpa.hibernate.ddl-auto=verify Bottom to Top Approach map entities to existing tables. Won't create tables if not present won't alter tables

=== CommandLineRunner is a interface in Spring Boot that provides a mechanism to execute run() after the Spring Boot application has started and the application context has been fully loaded.

Issues to resolve if any with lombok: 1) Settings --> Build, Execution, Deployment --> Compiler ->Annotation Processor --> shopapp -> Obtain processors from classpath.

  1. mvn clean

================== insert into customers values ('danny@cisco.com','Danny','Peter');

mysql> insert into customers values ('ria@cisco.com','Ria','Patel');

mysql> insert into customers values ('anne@cisco.com','Anne','Hathaway');

SQL uses table and column names

JP-QL uses class and field names; case sensitive; Polymorphic

@Entity
@Table(name="products")
class Product {
}
@Entity
@Table(name="tvs)
class Tv extends Product {
}
@Entity
@Table(name="mobiles")
class Mobile extends Product {

}
from Product; gets all records from products, "tvs" and "mobiles"
from Object; // records from all tables in database

By default built-in JpaRepository mutation code is Transactional.

Programmatic Transaction

    JDBC:
    public void doTask(...) {
        Connection con = ...
        try {
            con.setAutoCommit(false);
                // perform CRUD operations

            con.commit();
        } catch(SQLException ex) {
            con.rollback();
        }
    }

    Hibernate:
      public void doTask(...) {
        Session session = sessionFactory.getSession();
        Transaction tx = session.beginTransaction();
        try {
           
            session.save(e1);
            session.merge(e2);
            tx.commit();
        } catch(HibernateException ex) {
            tx.rollback();
        }
      }

Declarative Transaction:

@Transactional
public void doTask(...) {
    // JDBC / Hibernate / TopLink
}

Day 1 Recap:

Spring Framework vs Spring Boot

  • Spring Core Module: Life cycle management of bean and Wiring dependencies.
  • Spring Data JPA Module: HikariCP as database Connection pool and Hibernate as JPAVendor.
  • @Entity, PersistenceContext, @Id, @Column, @Table ORM mapping
  • JpaRepository interface - predefined Methods for CRUD operations
  • JPA Projections using findByXXXX
  • @Query for writing custom queries using SQL / JP-QL
  • @Modifying
  • @Transactional - Custom way of mutation / Insert

Built-in methods for INSERT / DELETE in JpaRepository have autocommit enabled.

productRepo.save(product); -- here in save() method they have turned on autocommit

By default for any other methods we are writing auto-commit is false

By placing @Transactional, this Aspect works like

  • if there are no exceptions on the method which has @Transactional it commits else rollback

// Atomic @Transactional doTask() { oper1 oper2 oper3 }

Day 2: update products set qty = 100 where 1 = 1;

Mapping associations:

  1. one to many
  2. many to one
  3. many to many
  4. one to one

https://www.database-answers.com/data_models/

Root aggregate of DDD: https://martinfowler.com/bliki/BoundedContext.html

@JoinColumn with @ManytoOne introduces FK in owning table/entity @JoinColumn with @OneToMany introduces FK in child table/entity

==========

Without Cascade Operations: One order has 4 line items

    @OneToMany
    @JoinColumn(name="order_fk")
    private List<LineItem> items = new ArrayList<>();

Save operation:
orderRepo.save(order);
itemRepo.save(i1);
itemRepo.save(i2);
itemRepo.save(i3);
itemRepo.save(i4);

Delete operation:
orderRepo.delete(order);
itemRepo.delete(i1);
itemRepo.delete(i2);
itemRepo.delete(i3);
itemRepo.delete(i4);

With Cascade: One order has 4 line items

Composition and not Aggregation:
 @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name="order_fk")
    private List<LineItem> items = new ArrayList<>();

Save operation:
orderRepo.save(order); // takes care of saving line items also

Delete operation:
orderRepo.delete(order); // takes care of deleting items also

Association: Composition or Aggregation

Fetching strategies:

  1. by default one to many is Lazy fetching and many to one is EAGER fetching

orderDao.findById(1); gets the customer data also but not line items

to get line items we need itemDao.getItemsOfOrder(orderId); // select * from line_items where order_fk = 1;

Make EAGER fetching:

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinColumn(name="order_fk")
    private List<LineItem> items = new ArrayList<>();

orderDao.findById(1);
gets the customer data also but not line items
gets line items also for the given order because of EAGER fetching

Dirty Checking: Withing @Transactional boundary if an entity becomes dirty [change], automatically JPA/ORM will trigger UPDATE SQL for that entity

=========

Building RESTful Web services using Spring MVC Module

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
 </dependency>

Provides:

  1. Tomcat as Embedded Servlet Container / Server
  2. Jackson for java to json and json to java conversion
  3. Provides DispatcherServlet as Front Controller and HandlerMapping

GET http://localhost:8080/api/products Accept: application/json

    @RestController
    @RequestMapping("api/products")
    @RequiredArgsConstructor
    public class ProductController {
        private final OrderService service;

        @GetMapping()
        public List<Product> getProducts() {
            return service.getProducts();
        }
    }

SSR: server side rendering

  • Presentation pages are sent to client - HTML / PDF
  • clients are thin [ like just a browser]
  • Heavy payload [ whole pdf / html is sent between client and server]
  • Client needs to understand how to handle HTML / PDF..
  • Good for SEO

CSR: Client side Rendering

  • different formats of representation is sent to clients: JSON / XML
  • thin payload
  • each client can consume data and generate views
  • Heavy clients [ need an application ] in client machine

RESTful WS: REpresentational State Transfer.

  • Resource: anything which can be named and present on server [ image / file / database / printer]
  • Representation: state of resource at a given point [ printer is on / off / paused] data in a row of table
  • ContentNegotiation: based on HttpHeaders - Accept and Content-type the representation is converted into various formats like JSON / XML / CSV ...

Characteristics of REST.

  1. Uniform Identifier: uses URL to identify a resource, HTTP methods GET / POST / PUT / PATCH / DELETE used to perform actions
  2. Client Server architecture: clients can evolve seperatly
  3. Stateless
  4. Layered

Content-type: application/json

PUT requests replace an entire resource with the data provided, while PATCH requests apply only partial updates to a resource, modifying only the fields sent in the request.

Task: CustomerController

  • getAllCustomers
  • getCustomer by Email
  • register a new Customer [ add]

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

PUT / PATCH / JSON-PATCH

A JSON Patch document is itself a JSON array containing a sequence of operations. Each operation specifies a particular type of change and uses JSON Pointer (RFC 6901) to identify the specific part of the document to be modified. 

Key Operations in JSON Patch:
add: Adds a new value to an object or an element to an array.
remove: Removes a value from an object or an element from an array.
replace: Replaces an existing value.
move: Moves a value from one location to another within the document.
copy: Copies a value from one location to another within the document.
test: Tests if a value at a specified path matches a given value. If the test fails, the entire patch operation should abort.

Advantages of JSON Patch:
Reduced Bandwidth: Only the changes are sent, not the entire document.
Improved Performance: Efficient for applying partial updates.
Standardized Format: Ensures interoperability between different systems.
Fine-grained Control: Allows for precise manipulation of individual elements and properties, including within arrays.

AOP: Aspect Oriented Programming

Aspects: These are modules that encapsulate cross-cutting concerns. They are not a part of main business logic, but can be used along with business logic. Examples: log, profile, security, transaction
cross-cutting concerns leads to Code tangling and code scattering

public void transferFunds(Account fromAcc, Account toAcc, double amt) {
    long startTime = System.currentTimeInMillis(); // profile
    if(ctx.getPrinciple().hasPermission()) { // security
        Transaction tx = ctx.getTransaction(); // transaction
        log.info("transaction started!!!");
        fromAcc.debit(amt);
        log.info("amount debit done..");
        toAcc.credit(amt);
        log.info("amount credit done..");
        insertIntoTxTable(data);
        log.info("update TX history");
        tx.commit();  // transaction
    }
    long endTime = System.currentTimeInMillis(); // profile
    log.info("Tx compleed in : " ( endTime - startTime) + " ms");
}

Join Points: Specific points within the execution of a program where an aspect can be applied, such as method execution and exception. 


Pointcuts: These are expressions that define precisely where an advice should be executed, for example, "before every method call on a class starting with 'UserService'". 




Advice: how we weave an aspect to JoinPoint: Before, After, Around, AfterReturning, AfterThrowing

Weaving: The process of integrating the aspects into the core application code, either at compile-time, load-time, or run-time. 

https://docs.spring.io/spring-framework/reference/core/aop/ataspectj/pointcuts.html

@ControllerAdvice is an AfterThrowing Advice which is meant for Global Exception handler; Any exceptions thrown from @Controller or @RestController classes are progated to this class


Validation of Payload:

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
  </dependency>

public Product addProduct(@RequestBody @Valid Product product) {

@Valid makes of validation constraints...
    @NotBlank(message = "Name is required!!!")
    private String name;

Task : ticket Tracker application

    employees
    email       | first_name | last_name | hire_date 
    a@cisco.com
    b@cisco.com
    c@cisco.com

    tickets
    ticket_id | raised_by_fk | raised_date | issue | resolved_by | resolved_date | fix


Use case 1: Raise a Ticket
 tickets
    ticket_id | raised_by_fk | raised_date          | issue         | resolved_by | resolved_date | fix
    134         b@cisco.com     22-SEP-2025 3:44      IntelliJ Hangs.  NULL.        NULL.          NULL

Use case 2: Resolve ticket
Pick a ticket to resolve -> input will be ticket ID
Make use of Dirty Checking capability
* pull the ticket based on Ticket ID
* set resolvedBy, resolvedDate [ system date], fix

 tickets
    ticket_id | raised_by_fk | raised_date          | issue         | resolved_by | resolved_date | fix
    134         b@cisco.com     22-SEP-2025 3:44      IntelliJ Hangs.   c@cisco       23-sep-2025 4:11          Applied patch


Hint:
Ticket class
@ManyToOne
@Joincolumn(name="raised_by_fk")
Employee raisedBy;

@ManyToOne
@JoinColumn(name="resolved_by")
Employee resolvedBy


Recap Day 2:

  • Building RESTful WS
  • @RestController instead of @Controller [SSR]
  • @RequestMapping : Map a REQUEST URL to a Resource [ class]
  • @GetMapping(), @PostMapping(), @PutMapping(), @PatchMapping(), JSON-PATCH [ array of json operations] , @DeleteMapping()
  • @RequestBody to read payload from client
  • @RequestParam to read Query Parameters [?] http://server.com/products?page=1&size=20
  • @PathVariable to read Path parameters [/] http://server.com/products/3
  • @ResponseBody - optional to specify that the return value has to be sent as response body
  • @ResponseStatus
  • AOP
  • Aspect
  • JoinPoint [eligibility where aspect can be weaved; with Spring methods and exceptions]
  • PointCut [ selected JoinPoint]
  • Advice [ Before, After, Around, AfterThrowing, AfterReturning]
  • @ControllerAdvice [ built in advice works like AfterThrowing; any exceptions thrown from @Controller or @RestContoller is delegated to @ControllerAdvice]
  • Validation - jakarta.validation.constraints like @NotBlank, @Pattern, @Min, @Max, @Future, @Past ...
  • @Valid - MethodArgumentNotValidException

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

Day 3: Vehicle Rental Application

bookings
id | customer_fk | vehicle_fk | date_from | date_to | amount

select
         v1_0.reg_no,
            v1_0.fuel_type,
            v1_0.hire_rate,
            b1_0.date_from,
            b1_0.date_to,
            c1_0.fname,
            c1_0.lname
        from
            bookings b1_0
        join
            vehicles v1_0
                on v1_0.reg_no=b1_0.vehicle_fk
        join
            customers c1_0
                on c1_0.email=b1_0.customer_fk

API Documentation:

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

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

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

Caching:

  • Client-Side Caching Cache-Control -- Applicable only for Browser ETag - Entity Tag
  • API level Caching - Spring Boot
   <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
By Default we get ConcurentMapCache - In Memory and CacheManager - Default

@Configuration
@EnableCaching
public class AppConfig {
}

@Cacheable(value = "productCache", key = "#id")
@CachePut(value = "productCache", key = "#id")

Redis is an in-memory key–value database, used as a distributed cache
Cache data survies system crash

docker run -p 6379:6379 -d --name some-redis  -d redis
 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
 </dependency>
spring.data.redis.host=localhost
spring.data.redis.port=6379

Serialization: process of writing state of object to a stream [ like file, Other address space.. Outside of JVM]
public class Product implements Serializable 

If NodeJS is installed: Redis Client

 npx redis-commander

ConcurentMapCache is a ConditionalOnMissingBean; if no other CacheManager are available this will be used.

  • Backend Caching: EhCache, JBossSwarmCache .... [database level] ==================

HATEOAS: Hypermedia As The Extension Of Application State https://martinfowler.com/articles/richardsonMaturityModel.html

WebMvcLinkBuilder - Builder to easily build link instances RepresentationModel

  • EntityModel [Entity + links] Product --> EntityModel
  • CollectionModel [ collection + links] List -> CollectionModel<List>
  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-hateoas</artifactId>
 </dependency>

 Affordance : Characteristics about how an object can be used.
 @EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL_FORMS)

Spring Data REST: unmbrella project on top of Spring Data Repository and MVC module. Spring DATA REST builds endpoints based on repository interface and add Links [ HATEOAS]

  • No need to write and @RestController or @Service classes, just JpaRepository will do.
  • Spring Data RESt doesn't support @RestController

Spring boot application:

  • Lombok
  • MySQL
  • JPA
  • Rest Repositories
  • web

http://localhost:8080/products http://localhost:8080/products/search/findByPriceBetween?low=10000&high=50000 http://localhost:8080/products/search/findByPriceGreaterThan?price=10000

How to do Customization? @BasePathAwareController instead of @RestController

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

Spring Application Event and Async Operations.

class BillingService {}
class HouseKeepingService{}
class NotificationService{}
class MedicalRecordService {}

POST http://localhost:8080/api/discharge

{
    patientId: 1235,
    pateientName: "George"
}

// Synchronous Blocking Code and tightly coupled
public String dischargePatient(String id, String name) {
    billingProcess.processBill(); // blocked
    medicalRecordsService.updatePatientHistory(); // blocked
    // service
    houseKeepingService.cleanAndAssign(); // blocked
    //notificationService.sendNotifcation(); // blocked
}

@EnableAsync --> Use Thread pool [default Spring Container provides a Thread Pool, we can have our own thread pool This is not Tomcat Thread pool - meant to handle HTTP request] @EventListener

With @Async Bill Processed for 555 by Thread Thread[#58,task-1,5,main] Notify Patient 555 by Thread : Thread[#59,task-2,5,main]

Without @Async Bill Processed for 555 by Thread Thread[#37,http-nio-8080-exec-1,5,main] Notify Patient 555 by Thread : Thread[#37,http-nio-8080-exec-1,5,main]

https://jsonplaceholder.typicode.com/users https://jsonplaceholder.typicode.com/posts

Spring Consuming Endpoints:

  1. RestTemplate
  2. WebClient
  3. RestClient [Spring Boot 3.0]

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

Observability: Ability to measure the internal state of system Tells Why a System is at fault

Monitoring: System is at fault Focus on collection of Data

Status at the current time
 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
 </dependency>

management.endpoint.health.show-details=always management.endpoints.web.exposure.include=*

http://localhost:8080/actuator

http://localhost:8080/actuator/health

http://localhost:8080/actuator/metrics

ab -c 100 -n 200 http://localhost:8080/api/products/1

http://localhost:8080/actuator/metrics/http.server.requests

Observability:

  1. Counter: incrementating and decrementing metric that represents a count

http://localhost:8080/actuator/metrics/my.counter

  1. timers: duration of events
  2. Gauges: Measure a value --> such as size of colleciton

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

Recap of Day 3:

  1. Vehicle Rental application: How to handle Date
  2. Caching: ETag, cache module --> ConcurrentMapCache, RedisCacheManager @EnableCaching, @Cacheable, @CachePut, @CacheEvit
  3. @EnableScheduling @Scheduled(cron = "* * * * * *")
  4. HATEOAS [ WebMvcLinkBuilder --> RepresentionModel [ data + links]] Spring Data REST based on HATEOAS and Spring Data Repository
  5. @EnableAsync, @Async, Spring ApplicationEvent, ApplicationEventPublisher, @EventListener
  6. Monitoring and Observability ; Actuator module --> Endpoints

Day 4: Prometheus collects and stores its metrics as time series data

 <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-registry-prometheus</artifactId>
 </dependency>

Endpoint:
http://localhost:8080/actuator/prometheus

compose.yml
docker compose up 
docker compose down

ab -c 100 -n 800 http://localhost:8080/api/products

http://localhost:9090/

jvm_threads_live_threads
http_server_requests_seconds_count

Security module: Authentication and Authorization

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
  </dependency>

By including above dependency:

  1. All resources become protected
  2. creates a login and logout pages http://localhost:8080/login http://localhost:8080/logout
  3. creates a single user username: user password: <> Using generated security password: 569f2528-69f9-4255-8a44-0bb9f8fb1c59

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

protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {

https://docs.spring.io/spring-security/reference/servlet/appendix/database-schema.html https://bcrypt-generator.com/

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

Token based authorization: JWT JSON Web Token (JWT)

    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.KMUFsIDTnFmyG3nMiGM6H9FNFUROf3wh7SmqJp-QV30

    HEADER:
    {
        "alg": "HS256",
        "typ": "JWT"
    }

    PAYLOAD: CLAIMS
    {
        "sub": "harry@cisco.com",
        "authorities": "ADMIN", "MANAGER", "GUEST",
        "iat": 353253
        "exp": 457323
        "iss": "https://secure.cisco.com"
    }

    SIGNATURE:
    HMACSHA256(
        base64UrlEncode(header) + "." +
        base64UrlEncode(payload),
        topsecretsaltvalueof256characters)

Scenario 1: use the same salt value to generate and validate Token
Scenario 2: use Private key to generate Token, public key to validate token [keytool ..]

http://server.com/api/products
Accept: application/json
Authorization: Bearer <<token>>

VehicleRentalApplication --> secure using JWT

  1. pom.xml add dependencies
  2. application.properites --> salt value
  3. added -> security package a) entities User and ROLE [ Many To Many relationship]
movies
mid | name
1       Pulp Fiction
2       Broken Arrow

actors
aid | name
1       John Travolta
2       Bruce Willis

movies_actors

mid_fk | aid_fk
1     1
1     2
2     1

b) Repo c) DTO SignUpRequest for Registration SignInRequest for Login d) UserDetailsServiceImpl e) AuthenticationService - register - signup() f) AuthController auth/register auth/login

h) JwtService getSigningKey() takes String Salt from application.properties --> java.security.Key

Login: AuthController [auth/login] AuthenticationService - JWTService Send Token To Client

Access Protected Resource: GET http://localhost:8080/api/vehicles Accept: application/json Authorization: Bearer <>

JwtAuthenticationFilter Extract email from Token using JwtService isTokenValid JwtService

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhbm5lQGNpc2NvLmNvbSIsImlhdCI6MTc1ODc4MjI1MSwiZXhwIjoxNzU4NzgzNjkxLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiLCJST0xFX0FETUlOIl0sInJvbGVzIjpbIlJPTEVfVVNFUiIsIlJPTEVfQURNSU4iXSwiaXNzIjoiaHR0cHM6Ly9hdXRoc2VydmVyLmNpc2NvLmNvbSJ9.bBy6YdozL-HeD1GmDp2nnD2YFc2UeunhcCEtoIhdI-I

==========

Unit Testing: Testing in Isolation by mocking dependecies RestController - Service - Repository - Database

We will test RestControllers by mocking Service tier

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
 </dependency>

@WebMvcTest - loads a minimalistic Spring Container

  • MockMvc using which we can make HTTP requests in testing env

  • Testing version of DispatcherServlet

  • HandlerMapping

  • HttpMessageConvertors

  • Won't load Service / Repo / database ...

About

Building Restful WS using Spring Boot

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages