Web Client
A web client is a software using which you can interact with the server where the web application is hosted. The most commonly used web clients are web browsers such as Google Chrome, Mozilla Firefox, Internet Explorer, etc.
Web Server
A web server is a software where the web application is hosted. It processes the request received from the client and sends the response back to the client. It runs on some physical system and listens to client request on a specific port. Apache Tomcat is one of the most widely used web server.
Uniform Resource Locator (URL)
URL stands for Universal Resource Locator. It used by the web client to locate the web server and resource. Every resource on the web has its own unique URL. The following is an example of URL:
http://infy.com:8080/InfyBank/jsps/welcome.jsp
http:// – It is the communication protocol used for server-client communication.
infy.com – It is the hostname of the server that maps to a unique IP address.
8080 – This is the port on which server is listening. It is optional and if not provided request will go to the default port of the protocol.
Hypertext Transfer Protocol (HTTP)
It is a protocol of communication between client and server. A client sends an HTTP request for a resource and the server returns an HTTP response with the desired resource. The HTTP request contains information about the action that the client is requesting the server to perform.
GET method
The HTTP GET method is used to retrieve a resource. It means, “get the resource identified by this URL.”
http://infy.com:8080/InfyBank?username=Tom
POST method
A POST request is used to send data to the server in order to be processed. It means,“post the data to the resource identified by this URL”. The data is sent as a body of the message.
An HTTP message sent by a server to a client is called an HTTP response. The initial line of an HTTP response is called the status line. It has three parts, separated by spaces: the HTTP version, a response status code that tells the result of the request, and an English phrase describing the status code.
Web Container
Web applications are composed of web components such as servlets, Java Server Page (JSP). These web components gets executed to generate content based on client request. So they need an environment for their execution. This execution environment is called as a web container. Web server takes the help of web container for generating dynamic content. Some commonly used web containers are
- Apache Tomcat
- GlassFish
- Jetty
Application Server
A web application resides in an application server. The application server provides the web application with easy and managed access to the resources of the system. It also provides low-level services, such as the HTTP protocol implementation and database connection management. A web container is just a part of an application server.
SOA-Service Oriented Architecture
SOA expands to Service Oriented Architecture, is a software model designed for achieving communication among distributed application components, irrespective of the differences in terms of technology, platform, etc.,
The application component that requests for a service is the consumer and the one that renders the service is the producer.
SOA is an architecture that can help to build an enterprise application by availing the services/functionalities from different third-party entities without reinventing the existing functionalities.
SOA that drives on high-value principles will take care of the following.
Principle | Explanation |
---|
Loose coupling | SOA aims at structuring procedures or software components as services. And, these services are designed in such a way that they are loosely coupled with the applications. So, these loosely-coupled services will come into picture only when needed. |
Publishing the services | There should be a mechanism for publishing the services that include the functionality and input/output specifications of those services. In short, services are published in such a way that the developers can easily incorporate them into their applications. |
Management | Finally, software components should be managed so that there will be a centralized control on the usage of the published services. |
These principles are the driving factors behind SOA, ensuring a high level of abstraction, reliability, scalability, reusability, and maintainability.
Different ways of realizing and implementing SOA
CORBA: Common Object Request Broker Architecture is a standard that achieves interoperability among the distributed objects. Using CORBA, it is much possible to make the distributed application components communicate with each other irrespective of the location (the place where the components are available), language and platform.
Jini: Jini or Apache River is a way of designing distributed applications with the help of services that interact and cooperate.
Web Services: Web services are a way of making applications interact with each other on the web. Web services leverage the existing protocols and technologies but, uses certain standards.
Web Service is the most popular solution as it eliminates the issues related to interoperability with pre-defined standards and processes in place
Soap Webservice:
SOAP (Simple Object Access Protocol) defines a very strongly typed messaging framework that relies heavily on XML and schemas. And, SOAP itself is a protocol (transported over HTTP, can also be carried over other transport layer protocol like SMTP/FTP, etc.) for developing SOAP-based APIs.
WSDL
Services are described using WSDL (Web Services Description Language). And, this description is of the XML format.
UDDI
UDDI (Universal Description, Discovery, and Integration) is a registry service which is XML based, where Services can be discovered/registered.
SOAP
SOAP-based Web services are accessed using SOAP (Simple Object Access Protocol), an XML standard for defining the message format for information exchange.
REST WebService
REST stands for REpresentational State Transfer.
It is an architectural style that defines a set of rules and regulations to create web services. REST helps to build web services that are lightweight, maintainable and scalable. Following are the advantages of making the functionalities of an application as RESTful services.
- Interoperability
- Resource sharing
- Reusability
- Independent client-server architecture
- Stateless transactions
What is reasapi
- SOAP is like an envelope which is used to send/receive messages
- REST is like a postcard
- Easier to handle (by the receiver)
- Less usage of paper (i.e., consume less bandwidth)
- Has a short content (REST requests are not really limited in length, especially, if POST is used instead of GET)
Principles
Uniform Interface
In REST anything that can be accessed or manipulated is a resource. For example, "customer", "order", "blog“ all are resources. Every resource has a representation (XML/JSON) and are uniquely identified by a Uniform Resource Identifier (URI). Resources are manipulated using GET, POST, PUT and DELETE methods of HTTP to perform read, create, update and delete of the resource. You can perform different operation on resources using different HTTP methods but with same URI.
Example : If a customer is a resource, then customer details can be added, deleted, updated or retrieved. If a blog is another resource, then the operations we can perform on the blog can be create a blog, read a blog, update a blog or delete a blog.
Stateless
The communication between service consumer (client) and service provider(server) must be stateless between requests. Stateless requires each request from a service consumer to contain all the necessary information for the service to understand the meaning of the request and all session state data should then be returned to the service consumer at the end of each request.
- The interaction that takes place between the service provider and consumer is stateless.
- Being stateless, the server will never store the state information of its clients. Rather, every request from a service consumer should carry all the necessary information to make the server understand and process the request.
Advantage: Statelessness ensures that each service consumer request can be treated independently by the service.
Client Server
Client-Server enforces the separation of concerns in the form of a client-server architecture, this helps establish a distributed architecture. This is the most foundational constraint.
Cacheable
Service consumers can cache and reuse response message data. HTTP GET, PUT and DELETE operations are cacheable. RESTful Web Services use HTTP protocol as a carrier for the data, they can use the metadata available in HTTP headers to enable caching. For example: Cache-Control headers are used to optimize caching for enhancing performance.
Layered System
REST based solution can comprise of multiple architectural layers. This constraint builds on client-server where in we add middleware component(s). Consumer may be communicating with a service residing in a middleware layer or the actual provider. A service does not need to be aware of whether its consumer is further communicating with other services or acting as a provider for another consumer.
Code-On-Demand
- This is an optional constraint which is primarily intended to allow client-side logic to be modified without doing changes in the server-side logic.
- For example, a service can be designed in such a way that it dynamically pushes part of the logic to the consumers.
Advantage: Logic that is present in the client end (such as Web browsers) can be modified/maintained independently without affecting the logic at the server side.
SOAP-based Web Service
|
RESTful Web Service
|
SOAP
is a protocol (defines the way how messages have to be sent) which is
transported over a transport layer Protocol, mostly HTTP.
|
REST
is an architectural style.
|
SOAP
messages can be transported using other transport layer protocols (SMTP, FTP)
as well.
|
REST
leverages HTTP Protocol.
|
Data
(XML/JSON) wrapped in a SOAP message, comes with an additional overhead of
XML processing at the client and server side as well.
|
REST
is straight forward in handling requests and responses. Since REST supports
multiple data formats other than XML, there is no overhead of wrapping the
request and response data in XML. Also, REST uses the existing HTTP protocol
for communication. All these factors together make REST, lightweight.
|
SOAP-based
reads cannot be cached because SOAP messages are sent using the HTTP POST
method.
|
REST-based
reads can be cached.
|
A
predefined formal contract is required between the consumer and the provider.
|
Formal
contract is not mandatory. Service description can be done if needed, using a
less verbose way with the help of WADL
|
What is RESTful Web Service?
Any web service which satisfies REST principles is called RESTful web service. These web services are usually exposed to third‐party applications as application programming interface (API). Popular sites such as Facebook, Twitter, and LinkedIn offer REST web services for accessing stored data.
REST Resources
In REST everything is a Resource (data/functionality/web page) and is uniquely identified by a Uniform Resource Identifier (URI).
REST URI Templates
When creating REST API's, you need to represent the structure of a URI rather than the URI itself. For example, in InfyBank application, the URI http://infybank.com/customers/2001 would fetch details of the customer whose id is 2001. Similarly, the URI http://infybank.com/customers/2002 would fetch details of the customer whose id is 2002. In this scenario structure of URI is important. URI templates provides a standard way for describing structure of URI.
http://infybank.com/customers/{customerid}
The curly braces {} indicate that the customerId part of the template is a variable, often called as a path variable. The clients consuming the web service can take thsi URI template as input, retrieve the value of path variable, and use it to retrieve the corresponding customer details.
Representation
Resources can be represented in many ways i.e: JSON/ XML/ HTML or any other type.
In the above example of http://www.infy.com/employees/john,
JSON XML
{ <employee>
"name": "John", <name>John</name>
"city":"California", <city>California</city>
"phoneno":998765432 <phoneno>998765432</phoneno>
} </employee>
What does State Transfer mean?
When you make a request to a resource like http://www.infy.com/employees/john using HTTP, we may be asking for the current "state" of this resource or its desired "state". You can use the same URI to indicate that, we want to :
Retrieve the current value of an Employee John (current state)
Perform Update operation on employee John's data (desired state) etc.
The server will understand which operation has to be invoked based on the HTTP method that was used to make a call. In short it means that a client and server exchange, representation of a resource, which reflects its current state(GET) or its desired state(PUT).
JAX-RS implementations
JAX-RS is simply a specification and we need actual implementations to write web services. There are many vendors in the market who adhere to the standards of JAX-RS such as, Jersey and RESTEasy.
Richardson Maturity Model (RMM)
The Richardson’s Maturity Model is used to divide REST based web services in different categories based on how much they follow REST principles. It was developed by Leonard Richardson.
Level 0
This is the basic level for a REST based web service. In this level single URI is used to expose the entire API. It uses a single HTTP method (typically POST or GET) to make remote procedure call on a single URI to perform operation on resources. SOAP based and XML RPC based web services comes in this level.
Level 1
The services in this level have multiple URI's for every resource but uses only one HTTP method – generally POST – to perform all the operations. Since specific resource is identified by a unique URI services in this level are closer to REST principles than services in level zero.
Level 2
The services in this level uses HTTP protocol and its methods and status codes along with URI’s to perform all the operations. For example, to get the employees, we send a GET request with the URI /employees, and the server sends proper response 200 OK and to add a customer, we send a POST request with the URI /employees, and the server sends proper response 201 CREATED. Services which implements CRUD operations are Level 2 services.
Level 3
This is the most mature level for a service. It is the combination of Level 2 and HATEOAS (Hypermedia as the Engine of Application State). Services in this level provides responses with links to related resources and controls which tells service client what to do next.
Spring MVC | Spring REST |
---|
Spring MVC response is a View/Page by default | In Spring REST data is returned directly back to the client |
Developing REST API Using Spring Boot
Spring Boot provides the spring-boot-starter-web starter for developing REST API.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Spring Boot by default reads the static resources such as HTML pages, CSS, Java script, images, etc. present in following locations in classpath:
- /static
- /public
- /resources
- /META-INF/resources
During application development, you might need to change code many times and for these changes to reflect in application, the application needs to be restarted. Spring Boot provides developer tools using which you can automate this process. To use developer tools, add Spring Boot Dev Tools dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
Working Internals of Spring REST:
Spring REST requests are delegated to the DispatcherServlet that identifies the specific controller with the help of handler mapper. Then, the identified controller processes the request and renders the response. This response, in turn, reaches the dispatcher servlet and finally gets rendered to the client.
To develop REST API to expose its following functionalities:
- Add a customer
- Get all customers
- Update customer details
- Fetch details of particular customer
- Delete a customer
To do this you have to create Spring controller class and implement the REST API endpoints in it. The methods in controller class which implement REST endpoints are called as REST controller methods. Now to implement above requirements
@SpringBootApplication = @Configuration + @EnableAutoConfiguration + @ComponentScan
@RestController
@RequestMapping(value = "/infybank")public class CustomerAPI {
@Autowired
private CustomerService customerService;
@Autowired
private Environment environment;
@GetMapping(value = "/customers")// /infybank/customers public ResponseEntity<List<CustomerDTO>> getAllCustomers() throws InfyBankException { List<CustomerDTO> customerList = customerService.getAllCustomers(); return new ResponseEntity<>(customerList, HttpStatus.OK);
}
@GetMapping(value = "/customers/{customerId}")// /infybank/customers/{customerId}
public ResponseEntity<CustomerDTO> getCustomer(@PathVariable Integer customerId) throws InfyBankException {
CustomerDTO customer = customerService.getCustomer(customerId); return new ResponseEntity<>(customer, HttpStatus.OK);
}
@PostMapping(value = "/customers")// /infybank/customers
public ResponseEntity<String> addCustomer(@RequestBody CustomerDTO customer) throws InfyBankException {
Integer customerId = customerService.addCustomer(customer);String successMessage = environment.getProperty("API.INSERT_SUCCESS") + customerId; return new ResponseEntity<>(successMessage, HttpStatus.CREATED);
}
@PutMapping(value = "/customers/{customerId}")// /infybank/customers/{customerId}
public ResponseEntity<String> updateCustomer(@PathVariable Integer customerId, @RequestBody CustomerDTO customer) throws InfyBankException {
customerService.updateCustomer(customerId, customer.getEmailId());String successMessage = environment.getProperty("API.UPDATE_SUCCESS"); return new ResponseEntity<>(successMessage, HttpStatus.OK);
}
@DeleteMapping(value = "/customers/{customerId}")// /infybank/customers/{customerId}
public ResponseEntity<String> deleteCustomer(@PathVariable Integer customerId) throws InfyBankException {
customerService.deleteCustomer(customerId); String successMessage = environment.getProperty("API.DELETE_SUCCESS"); return new ResponseEntity<>(successMessage, HttpStatus.OK);
}
@GetMapping(value = "/customers")// /infybank/customers?customerId=1234
public ResponseEntity<String> getCustomer(@RequestParam Integer customerId) throws InfyBankException{
//rest of the code
}
@PostMapping
(path=
"/"
, consumes =
"application/json"
, produces =
"application/json"
)
public
ResponseEntity<Object> addEmployee(
@RequestHeader
(name =
"X-COM-PERSIST"
, required =
true
) String headerPersist,
@RequestHeader
(name =
"X-COM-LOCATION"
, required =
false
, defaultValue =
"ASIA"
)
String headerLocation,
@RequestBody
Employee employee)
}
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
@RestController
@RequestMapping("/customers")
public class CustomerController
{
@RequestMapping(method=RequestMethod.POST)
public String createCustomer()
{
//Functionality goes here
}
}
@RestController
This annotation is used to define REST controllers. It is a combination of @Controller and @ResponseBody annotation. @Controller annotation marks a class for discovery by component scanning. @ResponseBody tells Spring that all handler methods in the controller should have their return value written directly to the body of the response, rather than being carried in the model to a view for rendering.
@RequestMapping
- This annotation is used for mapping web requests onto methods that are available in the resource classes. It is capable of getting applied at both class and method levels. At method level, we use this annotation mostly to specify the HTTP method.
This annotation is used to map the HTTP requests to handler methods of REST controllers. You can use it at class-level or method-level in a controller. The class-level @RequestMapping specifies that any handler methods in this controller will handle requests with specific request path or pattern while method-level makes mappings more specific to handler methods. By default, this annotation matches to all HTTP methods. But usually controller methods should be mapped to a specific HTTP method. For this, you can use method attribute in this annotation.
- @GetMapping
- @PostMapping
- @PutMapping
- @DeleteMapping
@RequestBody is the annotation that helps map our HTTP request body to a Java DTO. And, this annotation has to be applied on the local parameter (Java DTO) of the request method.
consumes = "text/plain"
or
consumes = {"text/plain", "application/json"}
Some more valid values:
consumes = "application/json"
consumes = {"application/xml", "application/json"}
consumes = {"text/plain", "application/*"}
Valid values for produces attribute:
produces = "text/plain"
produces = {"text/plain", "application/json"}
produces = {"application/xml", "application/json"}
ResponseEntity represents the entire HTTP response which includes HTTP response code, response body and response headers. In method implementation, details of all the customers are fetched using CustomerService and then an instance of ResponseEntity is created with customer data and the HttpStatus.OK status code
ResponseEntity(T body, MultiValueMap<String,String> headers, HttpStatus status)
ResponseEntity<List<Customer>> response = new ResponseEntity<List<Customer>>(customerList, HttpStatus.OK);
@PostMapping(consumes="application/json")
public ResponseEntity<String> createCustomer(@RequestBody CustomerDTO customerDTO)
{
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("MyResponseHeaders", "Value1");
String response = customerService.createCustomer(customerDTO);
return new ResponseEntity<String>(response, responseHeaders, HttpStatus.CREATED);
}
Constructor
|
Description
|
ResponseEntity(HttpStatus status)
|
Creates a ResponseEntity with only
status code and no body
|
ResponseEntity(MultiValueMap<String,String> headers, HttpStatus status)
|
Creates a ResponseEntity object
with headers and statuscode but, no body
|
ResponseEntity(T body, HttpStatus status)
|
Creates a ResponseEntity with a
body of type T and HTTP status
|
ResponseEntity(T body, MultiValueMap<String,String> headers, HttpStatus status)
|
Creates a ResponseEntity with a
body of type T, header and HTTP status
|
ResponseEntity method
|
Description
|
ok(T body)
|
Method that creates a
ResponseEntity with status, ok and body, T
|
ResponseBuilder badRequest()
|
Returns
a ResponseBuilder with the status, BAD_Request. In case, body has to be
added, then body() method should be invoked on the ResponseBuilder being
received and finally build() should get invoked in order to build
ResponseEntity.
Usage
Example:
ResponseEntity.badRequest().body(message).build();
|
ResponseBuilder notFound()
|
Returns a ResponseBuilder with the status, NOT_FOUND.
ResponseEntity.notFound().build();
|
URI
|
HTTP Method
|
CustomerController method
|
Method description
|
Annotation to be applied at the method level
|
New Annotation that can be applied instead of
@RequestMapping at the method level
|
/customers
|
GET
|
fetchCustomer()
|
Will fetch all the customers of
Infytel App and return the same.
|
@RequestMapping(method = RequestMethod.GET)
|
@GetMapping
|
/customers
|
POST
|
createCustomer()
|
Will create a new customer
|
@RequestMapping(method =
RequestMethod.POST)
|
@PostMapping
|
/customers
|
DELETE
|
deleteCustomer()
|
Will delete an existing
customer
|
@RequestMapping(method =
RequestMethod.DELETE)
|
@DeletMapping
|
/customers
|
UPDATE
|
updateCustomer()
|
Will update the details of an
existing customer
|
@RequestMapping(method =
RequestMethod.PUT)
|
@PutMapping
|
URI Parameter Injection Annotations
- Query Parameter - @RequestParam
- Path Variables - @Pathvariable
- Matrix Variables - @MatrixVariable
// To support matrix parameters
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
urlPathHelper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(urlPathHelper);
}
@RestController
@RequestMapping("/customers")
public class CustomerController
{
@PutMapping(value = "/{phoneNumber}", consumes = "application/json")
public String updateCustomer(
@PathVariable("phoneNumber") long phoneNumber,
@RequestBody CustomerDTO customerDTO) {
//code goes here
}
}
Consuming REST API with RestTemplate
To consume REST APIs using Spring application. For this, Spring provides RestTemplate class. It takes care of the necessary plumbing needed to communicate with REST API's and automatically marshals/unmarshals HTTP request and response bodies and provides methods for interacting with REST resources.
RestTemplate restTemplate = new RestTemplate();
or
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
RestTemplate class can be autowired only if it is configured as a Spring bean
Handling HTTP GET
public void getCustomerDetails(Integer customerId) {
String url = "http://localhost:8765/infybank/customers/{customerId}";
RestTemplate restTemplate = new RestTemplate();
CustomerDTO customer = restTemplate.getForObject(url, CustomerDTO.class, customerId);
}
getForObject() sends an HTTP GET request using specified URL and an object mapped from a response body.
- The first parameter is the URL.
- second parameter is type of response. In this case, the response data which is in JSON format is deserialized into Customer object and that will be returned.
- third parameter is used to fill in the {customerId} placeholder in the given URL.
Handling HTTP POST
public void addCustomer(CustomerDTO customer) {
String url = "http://localhost:8765/infybank/customers";
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.postForObject(url, customer, String.class);
LOGGER.info(response);
}
postForObject() method POST's data to a URL and returns an object mapped from the response body
- first parameter is the URL,
- second parameter is object to be posted to the server
- third parameter is type of return value.
Handling HTTP PUT
public void updateCustomer(CustomerDTO customer) {
String url = "http://localhost:8765/infybank/customers/{customerId}";
RestTemplate restTemplate = new RestTemplate();
restTemplate.put(url, customer, customer.getCustomerId());
LOGGER.info("Customer updated successfully");
}
public void deleteCustomer(Integer customerId) {
String url = "http://localhost:8765/infybank/customers/{customerId}";
RestTemplate restTemplate = new RestTemplate();
restTemplate.delete(url, customerId);
LOGGER.info("Customer deleted successfully");
}
Versioning a REST endpoint
Achieving API versioning such as
- URI versioning
- Request Parameter Versioning
- Custom Header Versioning
- Accept Header versioning
URI Versioning
- version-1: Fetches the complete plan details that include plainId, planName, localRate and nationalRate
- GET http://localhost:8080/infytel/plans/v1/{planId} eg:http://localhost:8080/infytel/plans/v1/1
- version-2: Fetches only the localRate and nationalRate.
- GET http://localhost:8080/infytel/plans/v2/{planId} eg:http://localhost:8080/infytel/plans/v2/1
@GetMapping(value = "v1/{planId}")
public ResponseEntity<PlanDTO> getPlan(@PathVariable("planId")String planId)
{
//Return the complete plan details
}
Versioning Custom Headers
GET http://localhost:8080/infytel/plans/{planId} headers=[X-API-VERSION=1]
eg: http://localhost:8080/infytel/plans/1and pass the header information headers=[X-API-VERSION=1]
@GetMapping(value = "{planId}",headers = "X-API-VERSION=1")
public ResponseEntity<PlanDTO> getPlan(@PathVariable("planId")String planId)
{ }
GET http://localhost:8080/infytel/plans/{planId} headers=[X-API-VERSION=2]
eg: http://localhost:8080/infytel/plans/1 and pass the header information headers=[X-API-VERSION=2]
GET http://localhost:8080/infytel/plans/{planId}
headers=[Accept=application/vnd.plans.app-v1+json]
eg:http://localhost:8080/infytel/plans/1 and pass the header information headers=[Accept=application/vnd.plans.app-v1+json]
GET http://localhost:8080/infytel/plans/{planId}
headers=[Accept=application/vnd.plans.app-v2+json]
eg:http://localhost:8080/infytel/plans/1 and pass the header information headers=[Accept=application/vnd.plans.app-v2+json]
@GetMapping(value = "/{planId}", produces = "application/vnd.plans.app-v1+json")
public ResponseEntity<PlanDTO> getPlan(@PathVariable("planId")String planId)
{
//Return the complete plan details
}
Request param versioning
GET http://localhost:8080/infytel/plans/{planId}?version=
eg:http://localhost:8080/infytel/plans/1?version=1
GET http://localhost:8080/infytel/plans/{planId}?version=
eg:http://localhost:8080/infytel/plans/1?version=2
@GetMapping(value = "/{planId}", params = "version=1")
public ResponseEntity<PlanDTO> getPlan(@PathVariable("planId")String planId)
{
//Return the complete plan details
}
CORS - Cross-Origin Resource Sharing
Browsers don’t allow you to make cross-origin request. Cross origin requests are requests to those resources which resides outside the the current origin. For example, if a document served from xyz.com makes a request to domain abc.com for some images then this request is called as cross origin request
To allow cross-origin requests, Cross-Origin Resource Sharing (CORS) is used. It is an specification which provides a way to specify which cross-origin requests are permitted. Spring provides @CrossOrigin annotation for enabling CORS for REST API so that the API clients can make calls to REST APIs.
- CORS configuration on the REST controller methods
- CORS configuration on the REST controller itself
- CORS configuration globally (common to the entire application)
CORS configuration on the REST controller methods
- origins - list of allowed origins to access the method
- methods - list of supported HTTP request methods
- allowedHeaders - list of request headers which can be used during the request
- exposedHeaders - list of response headers which the browser can allow the clients to access
- allowCredentials - determines whether the browser can include cookies that are associated with the request
@Controller
@RequestMapping(path="/customers")
public class CustomerController
{
@CrossOrigin(origins = "*", allowedHeaders = "*")
@GetMapping()
public String homeInit(Model model) {
return "home";
}
}
CORS configuration on the controller:
@Controller
@CrossOrigin(origins = "*", allowedHeaders = "*")
@RequestMapping(path="/customers")
public class CustomerController
{
@GetMapping()
public String homeInit(Model model) {
return "home";
}
}
Global CORS configuration:
@SpringBootApplication
public class InfytelApplication implements WebMvcConfigurer {
public static void main(String[] args) {
SpringApplication.run(InfytelDemo8BApplication.class, args);
}
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("GET", "POST");
}
}
Why to do exception handling?
@RestController
@RequestMapping(value="/infybank")
public class CustomerAPI {
@Autowired
private CustomerService customerService;
@GetMapping(value = "/customers/{customerId}")
public ResponseEntity<Customer> getCustomerDetails(@PathVariable Integer customerId) throws Exception {
Customer customer = customerService.getCustomer(customerId);
ResponseEntity<Customer> response = new ResponseEntity<Customer>(customer, HttpStatus.OK);
return response;
}
}
This controller has infybank/customer/{customerId} mapping which takes customerId and returns the customer details if customerId is present.
If no customer is present with given customer id and Service class throws an exception with message Service.CUSTOMER_UNAVAILABE for non existent customer then this controller returns the following response
{
"timestamp": "2020-06-18T08:20:20.705+0000",
"status": 500,
"error": "Internal Server Error",
"trace": "com.infy.exception.InfyBankException: Service.CUSTOMER_NOT_FOUND",
"message": "Service.CUSTOMER_UNAVAILABLE",
"path": "/infybank/customers/8"
}
The HTTP status code is 500 which conveys that there is some internal server error which is incorrect. Since the resource is not present the status code should be 404 which means resource not found. So, we can modify the controller code
@RestController
@RequestMapping(value="/infybank")
public class CustomerAPI {
@Autowired
private CustomerService customerService;
@GetMapping(value = "/customers/{customerId}")
public ResponseEntity<Customer> getCustomerDetails(@PathVariable Integer customerId) throws Exception {
ResponseEntity<Customer> response = null;
try {
Customer customer = customerService.getCustomer(customerId);
response = new ResponseEntity<Customer>(customer, HttpStatus.OK);
} catch (Exception exception) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
return response;
}
}
But this solution adds more code to the controller and makes it complex. Also if multiple handler methods are present in controller, then this code you may have to repeat in all those methods. Also, there is no way to send more detailed description of exception to the client. So proper exception handling in REST API's is very important. Spring provides multiple ways of exception handling in REST API.
- Using @RestControllerAdvice
- Using ResponseStatusException class
Exception Handling using @RestControllerAdvice
A central exception handler class is created to handle all the unhandled exceptions thrown from your code. So all the unhandled exceptions will be handled at one central place which makes exception handling easier
@RestControllerAdvice
public class ExceptionControllerAdvice{
// exception handler methods
}
Then add handler methods to this class to handle different types of exceptions and annotate them with @ExceptionHandler annotation.
Now to handle InfyBankException exception, add exception handler method
@RestControllerAdvice
public class ExceptionControllerAdvice {
@Autowired
private Environment environment;
@ExceptionHandler(InfyBankException.class)
public ResponseEntity<String> infyBankExceptionHandler(InfyBankException exception){
return new ResponseEntity<>(environment.getProperty(exception.getMessage()), HttpStatus.NOT_FOUND);
}
}
- Create a class annotated with @RestControllerAdvice
- Have methods annotated with @ExceptionHandler(value=NameoftheException) which takes the exception class as the value for which the method is the handler
If your code throws InfyBankException the infyBankExceptionHandler() method will execute. Now if you to fetch details of non existent customer you will get following response with correct HTTP status code from controller
multiple handler methods in the Advice class to handle exceptions of different types and return the response accordingly. For example, to handle all types of exception you can also add a general exception handler method
@RestControllerAdvice
public class ExceptionControllerAdvice {
@Autowired
private Environment env;
@ExceptionHandler(Exception.class)
public ResponseEntity<String> exceptionHandler(Exception exception) {
return new ResponseEntity<>(env.getProperty("General.EXCEPTION_MESSAGE"), HttpStatus.INTERNAL_SERVER_ERROR);
}
@ExceptionHandler(InfyBankException.class)
public ResponseEntity<String> infyBankExceptionHandler(InfyBankException exception){
return new ResponseEntity<>(env.getProperty(exception.getMessage()), HttpStatus.NOT_FOUND)
}
}
To handle both Exception and InfyBankException
@RestControllerAdvice
public class RestExceptionHandler {
@ExceptionHandler( { Exception.class, InfyBankException.class })
public ResponseEntity<String> exceptionHandler(Exception exception){
// rest of the code
}
}
when exception is thrown the response from the controller only contains message and the HTTP status code. But sometimes you want to provide more information to the client about the exception
public class ErrorInfo {
private String errorMessage;
private Integer errorCode;
private LocalDateTime timestamp;
//getters and setters
}
@RestControllerAdvice
public class ExceptionControllerAdvice {
@Autowired
Environment environment;
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorInfo> exceptionHandler(Exception exception) {
ErrorInfo error = new ErrorInfo();
error.setErrorMessage(envi.getProperty("General.EXCEPTION_MESSAGE"));
error.setErrorCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
error.setTimestamp(LocalDateTime.now());
return new ResponseEntity<ErrorInfo>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
@ExceptionHandler(InfyBankException.class)
public ResponseEntity<ErrorInfo> infyBankexceptionHandler(InfyBankException exception) {
ErrorInfo error = new ErrorInfo();
error.setErrorMessage(environment.getProperty(exception.getMessage()));
error.setTimestamp(LocalDateTime.now());
error.setErrorCode(HttpStatus.NOT_FOUND.value());
return new ResponseEntity<ErrorInfo>(error, HttpStatus.NOT_FOUND);
}
}
Exception handling using ResponseStatusException
Spring 5 introduced the ResponseStatusException class. This is a base class for exceptions associated with specific HTTP status codes. You can create an instance of it by providing an HttpStatus code, a message to explain the exception and cause of the exception
@GetMapping(value = "/customers/{customerId}")
public ResponseEntity<CustomerDTO> getCustomer(@PathVariable Integer customerId) throws InfyBankException {
try {
CustomerDTO customerDTO = customerService.getCustomer(customerId);
return new ResponseEntity<>(customerDTO, HttpStatus.OK);
} catch (Exception e) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND,env.getProperty(e.getMessage()), e);
}
}
if no handler
If no Exception handler is provided, Spring Boot provides a standard error message
{
"timestamp": "2019-05-02T16:10:45.805+0000",
"status": 500,
"error": "Internal Server Error",
"message": "Customer does not exist :121",
"path": "/infytel-7/customers/121"
}
Need for validation
REST controller :
@RestController
@RequestMapping(value = "/infybank")
public class CustomerAPI {
@Autowired
private CustomerService customerService;
@PostMapping(value = "/customers")
public ResponseEntity<String> addCustomer(@RequestBody CustomerDTO customerDTO) throws InfyBankException {
try {
Integer customerId = customerService.addCustomer(customerDTO);
String successMessage = environment.getProperty("API.INSERT_SUCCESS") + customerId;
return new ResponseEntity<>(successMessage, HttpStatus.CREATED);
} catch (Exception exception) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, environment.getProperty(exception.getMessage()), exception);
}
}
}
Client sends a POST request to above controller with following data where email address is in incorrect format Request
{
"customerId":"6",
"emailId":"tom",
"name":"Tom"
}
Spring provides support for user input validation through Bean Validation API which simplifies the input validation.
Introduction to Bean Validation API
This API simplifies the validation of input field. It provides annotation based constraints such as @NotNull and @Email which can be used on bean attributes to specify validation criteria
To use
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
public class CustomerDTO {
private Integer customerId;
@Email(message = "Please provide valid email address")
@NotNull(message = "Please provide email address")
private String emailId;
@NotNull(message = "Please provide customer name")
@Pattern(regexp="[A-Za-z]+( [A-Za-z]+)*", message="Name should contain only alphabets and space")
private String name;
@PastOrPresent(message = "Date of birth should be past or present date")
private LocalDate dateOfBirth;
//getter and setters
}
message attribute of constraint validation annotations specifies the error message which is sent to the client if validation fails. For example, if emailId validation fails "Please provide valid email address" message will be sent to the client. You can also write these validation message in external properties file and then you can use them in your validation annotations. To achieve this, create ValidationMessages.properties file in src/resources folder of your application and add the messages
customer.emailid.absent=Please provide email address
customer.emailid.invalid=Please provide valid email address
customer.name.absent=Please provide customer name
customer.name.invalid=Name should contain only alphabets and space
customer.dob.invalid=Date of birth should be past or present date
public class CustomerDTO {
private Integer customerId;
@Email(message = "{customer.emailid.invalid}")
@NotNull(message = "{customer.emailid.absent}")
private String emailId;
@NotNull(message = "{customer.name.absent}")
@Pattern(regexp="[A-Za-z]+( [A-Za-z]+)*", message="{customer.name.invalid}")
private String name;
@PastOrPresent(message = "customer.dob.invalid")
private LocalDate dateOfBirth;
//getter and setter
}
Adding the constraints on the bean attributes will not carry out validation. You also have to mention that validation is required. For this annotate customerDTO parameter of addCustomer() method of REST controller with @Valid annotation
@PostMapping(value = "/customers")
public ResponseEntity<String> addCustomer(@Valid @RequestBody CustomerDTO customerDTO) throws InfyBankException {
//rest of the code
}
This annotation tells Spring to perform data validation after binding input data to customerDTO. If the validation fails MethodArgumentNotValidException will be thrown and Spring will translate this exception to a response with HTTP status 400 (Bad Request).
Customize validation excpetion
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorInfo> exceptionHandler(MethodArgumentNotValidException exception) {
ErrorInfo errorInfo = new ErrorInfo();
errorInfo.setErrorCode(HttpStatus.BAD_REQUEST.value());
errorInfo.setTimestamp(LocalDateTime.now());
String errorMsg = exception.getBindingResult().getAllErrors().stream().map(x -> x.getDefaultMessage())
.collect(Collectors.joining(", "));
errorInfo.setErrorMessage(errorMsg);
return new ResponseEntity<>(errorInfo, HttpStatus.BAD_REQUEST);
}
Cascading Validation
not only validate single object but also object having reference of other object. This is also called as cascading of validation. To do this you have to annotate the reference of other object with @Valid annotation. For example, in following CustomerDTO class which has a reference of AddressDTO class which is annotated with @Valid annotation to cascade validation from CustomerDTO to AddressDTO.
public class CustomerDTO {
private Integer customerId;
@Email(message = "Please provide valid email address")
@NotNull(message = "Please provide email address")
private String emailId;
@NotNull(message = "Please provide customer name")
@Pattern(regexp="[A-Za-z]+( [A-Za-z]+)*", message="Name should contain only alphabets and space")
private String name;
@PastOrPresent(message = "Date of birth should be past or present date")
private LocalDate dateOfBirth;
@NotNull
@Valid
private AddressDTO addressDTO;
//getter and setters
}
public class AddressDTO {
private Integer addressId;
@NotNull(message = "Please provide street")
private String street;
@NotNull(message = "Please provide city")
private String city;
//getter and setters
}
Path Validation
what to do if path variable or request parameter is invalid. For example, if you want to restrict the value of customerId in path variable between 1 and 100. This requires validation of path variable or request parameter. You can also do this validation using Bean Validation API. Lets see how to do this.
For this, annotate the controller class with @Validated annotation to tell Spring to validate path variables and request parameters. Then annotate the parameters of the handler methods which needs to be validated with constraint annotations.
For example, if you want to specify that customerId should be between 1 and 100 then modify the controller class
@RestController
@RequestMapping(value="/infybank")
@Validated
public class CustomerAPI {
@Autowired
private CustomerService customerService;
@GetMapping(value = "/customers/{customerId}")
public ResponseEntity<Customer> getCustomerDetails(@PathVariable @Min(value = 1, message = "Customer id should be between 1 and 100") @Max(value = 100, message = "Customer id should be between 1 and 100") Integer customerId) throws Exception {
Customer customer = customerService.getCustomer(customerId);
ResponseEntity<Customer> response = new ResponseEntity<Customer>(customer, HttpStatus.OK);
return response;
}
@RestControllerAdvice
public class RestExceptionHandler {
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<ErrorInfo> pathExceptionHandler(ConstraintViolationException exception) {
ErrorInfo errorInfo = new ErrorInfo();
errorInfo.setErrorCode(HttpStatus.BAD_REQUEST.value());
String errorMsg = exception.getConstraintViolations().stream().map(x -> x.getMessage())
.collect(Collectors.joining(", "));
errorInfo.setErrorMessage(errorMsg);
errorInfo.setTimestamp(LocalDateTime.now());
return new ResponseEntity<>(errorInfo, HttpStatus.BAD_REQUEST);
}
}
Why to secure REST API’s
API’s are accessible to everyone i.e. anyone can use these API’s to perform CRUD operations on the data. For example, the API’s we have developed for our InfyBank application can be used by anyone get the details of any customer and in the worst case anyone can delete or update the details of a customer. But this is not correct as only customers and employees of the bank can access these API’s. In other words, we need authentication of users of the application and only valid users should be allowed to access it.
After authentication of user you need to identify the kind of operations that the user can perform. For example, in our InfyBank application only employees having admin access should be able to add, update and delete the customer details. This means that the access to certain API’s has to be restricted based on the user's role. This calls for adding authorization to the application so that only users having right permission can access certain API's.
So proper authentication and authorization is required for securing REST API's. Spring Security is the most popular framework used for securing REST API's. It provides authentication and authorization for REST API's.
OWASP (Open Web Application Security Project)
It is a non-profitable organization which works in the area of web application and mobile security. Its objective is to make people aware of common and critical security vulnerabilities and measures to avoid those vulnerabilities. As of this course creation, OWASP Top 10 2017 is the latest vulnerabilities list is as follows:
1. Injection
Injection flaws, such as SQL, OS, and LDAP injection occur when untrusted data is sent to an interpreter as part of a command or query. The attacker’s hostile data can trick the interpreter into executing unintended commands or accessing data without proper authorization.
2. Broken Authentication
Application functions related to authentication and session management are often implemented incorrectly, allowing attackers to compromise passwords, keys, or session tokens, or to exploit other implementation flaws to assume other users’ identities (temporarily or permanently).
3. Sensitive Data Exposure
Many web applications and APIs do not properly protect sensitive data, such as financial, healthcare, and PII. Attackers may steal or modify such weakly protected data to conduct credit card fraud, identity theft, or other crimes. Sensitive data deserves extra protection such as encryption at rest or in transit, as well as special precautions when exchanged with the browser.
4. XML External Entities (XXE)
Many older or poorly configured XML processors evaluate external entity references within XML documents. External entities can be used to disclose internal files using the file URI handler, internal SMB file shares on unpatched Windows servers, internal port scanning, remote code execution, and denial of service attacks, such as the Billion Laughs attack.
5. Broken Access control
Restrictions on what authenticated users are allowed to do are not properly enforced. Attackers can exploit these flaws to access unauthorized functionality and/or data, such as access other users' accounts, view sensitive files, modify other users’ data, change access rights, etc.
6. Security misconfigurations
Security misconfiguration is the most common issue in the data, which is due in part to manual or ad hoc configuration (or not configuring at all), insecure default configurations, open S3 buckets, misconfigured HTTP headers, error messages containing sensitive information, not patching or upgrading systems, frameworks, dependencies, and components in a timely fashion (or at all).
7. Cross Site Scripting (XSS)
XSS flaws occur whenever an application includes untrusted data in a new web page without proper validation or escaping, or updates an existing web page with user supplied data using a browser API that can create JavaScript. XSS allows attackers to execute scripts in the victim’s browser which can hijack user sessions, deface web sites, or redirect the user to malicious sites.
8. Insecure Deserialization
Insecure deserialization flaws occur when an application receives hostile serialized objects. Insecure deserialization leads to remote code execution. Even if deserialization flaws do not result in remote code execution, serialized objects can be replayed, tampered or deleted to spoof users, conduct injection attacks, and elevate privileges.
9. Using Components with known vulnerabilities
Components, such as libraries, frameworks, and other software modules, run with the same privileges as the application. If a vulnerable component is exploited, such an attack can facilitate serious data loss or server takeover. Applications and APIs using components with known vulnerabilities may undermine application defenses and enable various attacks and impacts.
10. Insufficient logging and monitoring
Insufficient logging and monitoring, coupled with missing or ineffective integration with incident response allows attackers to further attack systems, maintain persistence, pivot to more systems, and tamper, extract or destroy data. Most breach studies show time to detect a breach is over 200 days, typically detected by external parties rather than internal processes or monitoring.
Authentication
It is the process of verifying the identity of the user i.e verify whether the user is the intended user or not. For example, swipe in/out system at turnstiles at the company entrances is the best example for authentication.
Authorization
It is the process of restricting the access to resources for authenticated users so that the person/system who is authorized to access the resource can access the same. For example, a company has many employees and all the employees can enter the company premises but entry to the server room is allowed only to few people.
Spring Security
Spring Security is entirely based on chain of filters for authentication and authorization. Each filter is applied to every request for authentication and authorization. Any request which does not have proper credential for authentication and authorization, the request would be rejected, and an an exception will be thrown
- UsernamePasswordAuthenticationFilter: It performs the task of authentication.
- AnonymousAuthenticationFilter: It performs anonymous authentication. If authentication credentials are not present in request it creates an anonymous users. These users are allowed to access API"s which does not require authentication.
- ExceptionTranslationFilter: It translates security exceptions to a proper HTTP response.
- FilterSecurityInterceptor: It performs authorization of resources.
Spring Security provides multiples approaches for authentication and authorization. One of the approach is HTTP basic authentication.
HTTP Basic authentication
when client requests for a protected resource the server asks the client the authentication credentials. The client send their Base64 encoded authentication credentials along with request using HTTP authorization header. On receiving the credentials, the server decodes and validates them. On successful validation the client gets the requested resource. The following figure shows steps of basic authentication:
This type of authentication does not mandate us to have any login page which is the very standard way of authenticating the client requests in any web application. So, this approach is useful when we have web services interacting with each other. In addition, there is no need to store the credentials or any related information in the session. Each request here, is treated as an independent request which in turn promotes scalability. In a Spring Boot application when Spring Security is enabled basic authentication is default authentication approach which is auto configured.
- All requests will be authenticated using HTTP basic authentication
- There is no specific roles or authorities assigned to user.
- The credentials for accessing the application will be automatically generated with only one user. The default user name is user, and the default password is generated in a random fashion during the application start. You can get this password from the console log of the application
You can also define user name, password and role using following properties in application.properties file:
- spring.security.user.name - This property defines the default user name.
- spring.security.user.password - This property defines password of default user name.
- spring.security.user.roles - This property defines defines granted role for default user name.
Securing REST API using HTTP Basic Authentication
have seen that how to secure REST API's using Spring Boot default configuration. But it is not powerful enough to secure real world applications. So, you have to create your own custom configuration to override the default configuration. To do this the first you have to decide how you want security to behave. For example, we want to have following configurations for CustomerAPI of our InfyBank application:
- The application should be accessible to following two users :
These credentials can be present in different data sources such as a database or an active directory like LDAP etc. Spring Security provides support for authentication using different data sources. In this course we will use in-memory data source where username, password and role of a user will be stored in memory where application is running.- All the requests should be authenticated using HTTP basic authentication.
- The /customers API should be accessed by only users having ADMIN role.
This can be done in following 3 steps:
- Create custom configuration class
- Implement authentication
- Implement authorization
Creating Custom Security Configuration Class
To create custom security configuration class you have to extend WebSecurityConfigurerAdapter class and annotate it with @EnableWebSecurity annotation
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//rest of the code
}
- @EnableWebSecurity enables web security support provided by Spring Security.
- WebSecurityConfigurerAdapter class provides methods which has to overridden to implement custom security requirements
After creating custom security configuration class you have to specify data source where user credentials are stored for authentication. For this you have to override protected void configure(AuthenticationManagerBuilder auth) method WebSecurityConfigurerAdapter class in SecurityConfig class. In this method you have to configure the data source of user credentials using AuthenticationManagerBuilder. For using in-memory data source and to add smith and tim as users of the application you have to override this method
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("smith")
.password("{noop}smith123").roles("ADMIN")
.and()
.withUser("tim")
.password("{noop}tim123").roles("USER");
}
In Spring Security 5.x onwards the password has to be encrypted before being stored. It does not allow plain text password without specifying the password encryption algorithm. So you have to specify the password encryption algorithm before begin stored. But If you dont want to encode the password then it has to be preceeded with {noop} which uses plain text NoOpPasswordEncoder encoder. This encoder does not encrypt the password and is useful for testing where encryption of password is not necessary. But in real life applications it is good to encrypt the password as unencrypted passwords are insecure. For this Spring Security provides encoders which implements PasswordEncoder interface. One of the encoder is BCryptPasswordEncoder which we will use. To use this configure following bean in SecurityConfig class:
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("smith")
.password(passwordEncoder().encode("smith123")).roles("ADMIN")
.and()
.withUser("tim")
.password(passwordEncoder().encode("tim123")).roles("USER");
}
encode() method is used to encode the password.
After authentication you have to implement authorization. For this you have to override configure(HttpSecurity http) method to specify URLs which should be secured and which should not. Using object of HTTPSecurity you can define how to handle security at the web level. To authorize requests to all users you can override this method
protected void configure(HttpSecurity http) throws Exception{
http
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.httpBasic();
http.csrf().disable();
}
authorizeRequests() method returns an object of ExpressionInterceptUrlRegistry using which URL paths and their security requirements are specified.
The Spring security by default enables CSRF(Cross Site Request Forgery) protection. Because of this you can access only GET endpoints. For accessing PUT, POST and DELETE endpoints, you have to disable the CSRF protection
To authorize requests to URI infybank/customers only to users having ADMIN role you can override this method
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/infybank/customers/**")
.hasRole("ADMIN")
.anyRequest()
.authenticated()
.and()
.httpBasic();
http.csrf().disable();
}
- The URI to be protected is mentioned using antMatchers() method. In URI "/infybank/customers/**", ** means any value after /infybank/customers.
- the hasRole() method specifies the role of the user.
- anyRequest().authenticated() means any request mapped to this URI will be authenticated.
- httpBasic() specifies that HTTP basic authentication has to be used.
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/infybank/customers/**")
.hasRole("CUSTOMER")
.anyRequest()
.authenticated()
.and()
.httpBasic();
http.csrf().disable();
}
users with role CUSTOMER can access only the POST endpoint with URI "/infybank/customers/**".
Spring Boot Actuator
deployed Spring Boot application into production environment, you always want to monitor the application. This is beacause you want to ensure that the application must be always up and running and also in case of any issues you want to fix it quickly. Therefore, an application monitoring tool is required so that you can analyse the health of your application.
Spring Boot has an in-built mechanism for monitoring application called as Actuator. It is a sub-project of Spring Boot. It offers several production grade features to monitor the application. Once you enable actuator in your Spring Boot application, a set of endpoints are exposed using which you can monitor and manage your application. You can also integrate these endpoints with other application monitoring tools such Prometheus, Graphite etc.
Once Actuator is enabled in your application, using actuator endpoints you can monitor and manage your application. These endpoints are exposed over HTTP in Spring MVC application using the 'id' of endpoints as the URL path along with /acuator as prefix
Id | Description |
/beans | Provides list of all Spring beans available in the application |
/configprops | Provides a collated list of all @ConfigurationProperties |
/env | Exposes all the properties fromSpring's ConfigurableEnvironment |
/info | Displays arbitrary application information |
/metrics | Displays metric information for the current application |
/mappings | Displays a collated list of all request mapping paths |
/shutdown | Allows the application to shutdown |
/trace | Displays trace information, by default latest 100 HTTP requests |
/health | Provides applications health information |
These endpoints contain sestive information so all of them are not exposed by default. Only /health and /info endpoints are exposed by default. You can enable all other endpoints by adding following property in the application.properties file
management.endpoints.web.exposure.include=*
Restrict the exposure of specific endpoint.
management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=env
Any specific endpoint can be exposed
management.endpoints.web.exposure.include=env,beans
{
"_links": {
"self": {
"href": "http://localhost:8765/actuator",
"templated": false
},
"beans": {
"href": "http://localhost:8765/actuator/beans",
"templated": false
},
"caches": {
"href": "http://localhost:8765/actuator/caches",
"templated": false
},
"caches-cache": {
"href": "http://localhost:8765/actuator/caches/{cache}",
"templated": true
},
"health": {
"href": "http://localhost:8765/actuator/health",
"templated": false
},
"health-path": {
"href": "http://localhost:8765/actuator/health/{*path}",
"templated": true
},
"info": {
"href": "http://localhost:8765/actuator/info",
"templated": false
},
"conditions": {
"href": "http://localhost:8765/actuator/conditions",
"templated": false
},
"configprops": {
"href": "http://localhost:8765/actuator/configprops",
"templated": false
},
"env": {
"href": "http://localhost:8765/actuator/env",
"templated": false
},
"env-toMatch": {
"href": "http://localhost:8765/actuator/env/{toMatch}",
"templated": true
},
"loggers": {
"href": "http://localhost:8765/actuator/loggers",
"templated": false
},
"loggers-name": {
"href": "http://localhost:8765/actuator/loggers/{name}",
"templated": true
},
"heapdump": {
"href": "http://localhost:8765/actuator/heapdump",
"templated": false
},
"threaddump": {
"href": "http://localhost:8765/actuator/threaddump",
"templated": false
},
"metrics": {
"href": "http://localhost:8765/actuator/metrics",
"templated": false
},
"metrics-requiredMetricName": {
"href": "http://localhost:8765/actuator/metrics/{requiredMetricName}",
"templated": true
},
"scheduledtasks": {
"href": "http://localhost:8765/actuator/scheduledtasks",
"templated": false
},
"mappings": {
"href": "http://localhost:8765/actuator/mappings",
"templated": false
}
}
}
Monitoring application through Actuator Endpoints
/health endpoint
This endpoint gives you the information about health of application. You can acces this endpoint using the URL http://localhost:8765/actuator/health. It will give you following response
{
"status": "UP"
}
it tells only whether the status of application is UP or DOWN. If you want to get complete details about health of application then add the following property in the application.properties
management.endpoint.health.show-details=always
{
"status": "UP",
"components": {
"db": {
"status": "UP",
"details": {
"database": "MySQL",
"validationQuery": "isValid()"
}
},
"diskSpace": {
"status": "UP",
"details": {
"total": 262143995904,
"free": 156223340544,
"threshold": 10485760,
"exists": true
}
},
"ping": {
"status": "UP"
}
}
}
To get more information about these metrics you need to append the metric name to the URL. For example if you want to know more about jvm.memory.used metric then the URL will be http://localhost:8765/actuator/metrics/jvm.memory.used.
{
"name": "jvm.memory.used",
"description": "The amount of used memory",
"baseUnit": "bytes",
"measurements": [
{
"statistic": "VALUE",
"value": 118873840
}
],
"availableTags": [
{
"tag": "area",
"values": [
"heap",
"nonheap"
]
},
{
"tag": "id",
"values": [
"tenured-SOA",
"class storage",
"nursery-survivor",
"miscellaneous non-heap storage",
"tenured-LOA",
"JIT code cache",
"JIT data cache",
"nursery-allocate"
]
}
]
}
Creating a custom Actuator endpoint
In Spring Boot you can easily customize existing Actuator endpoints and can also create new endpoints. To create a new endpoint you have to create a class and annotate it with @Component and @Endpoint annotation. The @Endpoint annotation has a parameter id which determines the URL path of endpoint. This class contains the methods which returns the response of the endpoint.
@Component
@Endpoint(id = "customers")
public class MyCustomerEndpoint {
@ReadOperation
public List<CustomerDTO> getAllCustomers(){
// rest of the code
}
@WriteOperation
public String updateCustomer(Integer customerId, String emailId) throws InfyBankException {
// rest of the code
}
@DeleteOperation
public String deleteCustomer(@Selector Integer customerId) {
// rest of the code
}
}
- The value of id parameter of @Endpoint is customers. So this endpoint is accessible by URL /actuator/customers.
- a method defined with @ReadOperation which will be mapped to HTTP GET method and automatically be exposed over HTTP.
- a method defined with @WriteOperation which will be mapped to HTTP POST method and automatically be exposed over HTTP. The methods that are annotated with @WriteOperation can take parameters in JSON format alone.
- a method defined with @DeleteOperation which will be mapped to HTTP DELETE method and automatically be exposed over HTTP.
- technology-specific endpoints defined with @WebEndpoint/@JmxEndpoint. For ex, @WebEndpoint is exposed over HTTP only.
HATEOAS
Consider a bank website. When you visit this website, you start with the home page which contains text, images and videos. The page also has hyperlinks using which you can navigate to other pages. You can login to your account using login page. After logging in you can perform other tasks such as transfer money to other accounts, pay utility bills etc using different hyperlinks along with other controls such as buttons, drop-downs etc. to. You need not to remember the URI’s of the resources required for performing these tasks. The only thing you need to know is the URI of the home page. Even if there is a change in URI of any resource or new steps are added to a task you will still be able to perform the operations. This is all possible because of hyperlinks.
But how can we make a REST API to work like a website i.e. how we can add hyperlinks to other resources. For this HATEOAS is used.
HATEOAS (Hypermedia as the Engine of Application State) is a constraint of REST application architecture. With HATEOAS you can develop REST API which generates response containing hypermedia links to other resources using which the client can navigate through the API dynamically. Hypermedia means any content that has links to other media such as text, images, videos
{
"customerId": 2,
"emailId": "tim@infy.com",
"name": "Tim",
"dateOfBirth": "2007-01-08",
}
{
"customerId": 2,
"emailId": "tim@infy.com",
"name": "Tim",
"dateOfBirth": "2007-01-08",
"links": [{
"rel": "self",
"href": "http://localhost:8765/infybank/customers/2",
"rel": "update",
"href": "http://localhost:8765/infybank/customers/2"
"rel": "delete",
"href": "http://localhost:8765/infybank/customers/2"
}]
}
The above response contains the details of the customer whose customerId = 2 as well as hypermedia links to delete and update the customer details. The client can use these links to navigate across the API to perform update and delete operations on customer resource.
HAL (Hypermedia Application Language)
You know that hypermedia is a media type that contains links to other resources. But JSON is not a hypermedia type because is does not provide standard way for hyperlonking of resources. So, many JSON hypermedia types are created with provides way to add hyperlink in JSON document. HAL (Hypermedia Application Language) is one of the most popular JSON hypermedia type. It is also supported by Spring Framework. A resource in HAL contains following things:
- State : It is the actual data of the resource in JSON format.
- Links : It is a collection of links. In HAL _links propery is used to add links to other resources. It is a JSON object.
- Embedded Resources : It is other resources contained inside the resource rather link to that particular resource. In HAL _embedded propery is used to embed resources
Spring HATEOAS
Spring HATEOAS provides API using which you can create REST API that follows the HATEOS constraint. It has following features:
- Support for link and resource representation model
- Link builder API
- Support for HAL
1. Link
The object of this class represents the URI of the resource. This class has many overloaded constructors. For example, the following code creates a link to URI http://localhost:8080/infybank/customers
Link link = new Link("http://localhost:8080/infybank/customers");
2. WebMvcLinkBuilder
This is a utility class using which you can create instances of Link which points Spring MVC controllers without hardcoding them. For this you can use linkTo() and methodOn() methods of this class. For example, the following code creates a link to the getCustomer() method of CustomerAPI controller
Link selfLink = linkTo(methodOn(CustomerAPI.class).getCustomer(customerId)).withSelfRel();
- the linkTo() method gets the root mapping for CustomerAPI controller class.
- the methodOn() method gets the mapping of getCustomer() method by making dummy call to getCustomer() method and sets the path variable of the URI as customerId.
- the withSelfRel() method declares the link as self-referencing link.
3. EntityModel<T> class
The HATEOAS response contains the data as well as links. For this Spring HATEOAS provides EntityModel class which contains single domain object and related links. You can create its object using its of() method
CustomerDto customerDto = new CustomerDto();
Link selfLink = linkTo(methodOn(CustomerAPI.class).getCustomer(customerId)).withSelfRel();
EntityModel entityModel = EntityModel.of(customerDTO, selfLink)
4. CollectionModel<T> class
Sometimes the HATEOAS response contains collection of domain objects. For this Spring HATEOAS provides CollectionModel class. You can create its object using the given data and liks using the following method:
static <T> CollectionModel<T> of(T content, Link... links)
@RestController
@RequestMapping(value = "/infybank")
public class CustomerAPI {
@Autowired
private CustomerService customerService;
@Autowired
private Environment environment;
@GetMapping(value = "/customers/{customerId}")
public ResponseEntity<CustomerDTO> getCustomer(@PathVariable Integer customerId) throws InfyBankException{
CustomerDTO customer = customerService.getCustomer(customerId);
return new ResponseEntity<>(customer, HttpStatus.OK);
}
@GetMapping(value = "/customers")
public ResponseEntity<List<CustomerDTO>> getAllCustomers() throws InfyBankException {
List<CustomerDTO> customerList = customerService.getAllCustomers();
return new ResponseEntity<>(customerList, HttpStatus.OK);
}
}
Presetation layer
The enterprise applications are web applications which are accessed over internet. So before going into details of developing presentation layer of these applications let us understand following core concepts of web applications:
- Web Server
- Web Client
- URL
- Static and Dynamic Content
- HTTP
- Application Server
Web Client
A web client is a software using which you can interact with the server where the web application is hosted. The most commonly used web clients are web browsers such as Google Chrome, Mozilla Firefox, Internet Explorer, etc.
Web Server
A web server is a software where the web application is hosted. It processes the request received from the client and sends the response back to the client. It runs on some physical system and listens to client request on a specific port. Apache Tomcat is one of the most widely used web server.
Uniform Resource Locator (URL)
URL stands for Universal Resource Locator. It used by the web client to locate the web server and resource. Every resource on the web has its own unique URL. The following is an example of URL:
http://infy.com:8080/InfyBank/jsps/welcome.jsp
http:// – It is the communication protocol used for server-client communication.
infy.com – It is the hostname of the server that maps to a unique IP address.
8080 – This is the port on which server is listening. It is optional and if not provided request will go to the default port of the protocol.
Hypertext Transfer Protocol (HTTP)
It is a protocol of communication between client and server. A client sends an HTTP request for a resource and the server returns an HTTP response with the desired resource. The HTTP request contains information about the action that the client is requesting the server to perform.
Static Content
When the client makes a request, the server will respond back with content which it already has in its storage(for ex. File Systems). Such content which does not change with every request is called static content. The static websites are created with few HTML pages whose contents are predefined and most of such websites will not even require a database.
Dynamic Content
Sometimes, the server has to create the content based on the request data and respond back with the dynamically created content. Such content is called as dynamic content. Almost all the modern application generates dynamic content as a response to serve the user's request better.
Web Container
Web applications are composed of web components such as servlets, Java Server Page (JSP). These web components gets executed to generate content based on client request. So they need an environment for their execution. This execution environment is called as a web container. Web server takes the help of web container for generating dynamic content. Some commonly used we containers are
Servlet
In this user story the business logic is to validate the credentials entered by the customer against the details stored in the database. On successful validation, customer should be redirected to success page. If credentials are invalid error page should be displayed. Now let us see how this user story can be implemented. To implement this user story customer credentials should be passed to the server and in server there must be a program which verifies it by interacting with database and generates the appropriate response. This means that dynamic content needs to be generated and sent back to the client based on customer credentials. For generating dynamic content you need a technology which executes on server. Servlet is one of such technology. It is a web component that is deployed on the server to create a dynamic web page. Specifically, it is a Java class that implements the javax.servlet.Servlet interface.
Servlet API is a set of classes and interface required for developing servlets. These classes and interfaces are defined in the following two packages:
- javax.servlet - It contains classes and interfaces which are protocol independent.
- javax.servlet.http - It contains classes and interfaces which are HTTP specific implementation.
Servlet interface
This interface provides common behavior to all the servlets. It defines methods that all servlets must implement. It is present in javax.servlet package and contains the following methods:
- public void init(ServletConfig config) - This method is used to initialize a servlet object.
- public void service(ServletRequest request,ServletResponse response) - This method is used to handle the incoming request and generate the necessary dynamic content. These requests are dispatched to the appropriate request handling method by the service() method.
- public void destroy() - This method is used to perform a set of activities before removal of the servlet object.
GenericServlet class
GenericServlet class implements the Servlet interface which can be used for generating response independent of the protocol involved. It provides implementation of init() and destroy(), however service() is left abstract.
HttpServlet class
This class extends GenericServlet class and is used for generating response for HTTP protocol. It provides specific methods to handle HTTP method specific requests. Some important methods of this class are :
- doGet(HttpServletRequest req, HttpServletResponse res) - It handles the HTTP GET request.
- doPost(HttpServletRequest req, HttpServletResponse res) - It handles the HTTP POST request.
- doPut(HttpServletRequest req, HttpServletResponse res) - It handles the HTTP PUT request.
- doDelete(HttpServletRequest req, HttpServletResponse res) - It handles the HTTP DELETE request.
Defining Servlet
To define a Java class as a servlet you can extend either GenericServlet or HttpServlet class. If you are extending GenericServlet then you have to provide the implementation for the service() method and if you are extending HttpServlet class then you have to override the implementation of doPost(), doGet(), etc. methods.
Servlet Mapping using Annotation
When a web container receives a request from a client it must invoke the appropriate servlet depending on the URL of the request. To locate appropriate servlet web container uses servlet mapping. Servlet mapping specify which URL patterns should be handled by which servlet. From Servlet API 3.0, this mapping can be done using @WebServlet annotation. The following code snippet maps the LoginServlet class with /LoginServlet request path.
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet{
//rest of the code
}
Introduction to JSP (Java Server Page)
You have learnd how to use servlets for generating dynamic content. But there are some drawbacks in using servlets such as:
- To generate view HTML code is required to be hardwired in the Java code. If any changes are required in the view, the code has to be changed in the servlet class. So there is need to separate presentation logic with control logic.
- The web page design would have been faster if it was done using reusable user interface elements.
So a better technology is needed for quick and easy development of presentation layer. JSP is one such technology. It uses a combination of static HTML content and dynamic content to generate web pages.
Java Server Pages is the scripting language which is used to create dynamic web pages in Java. A JSP page is a web page that contains Java code along with the HTML tags. When accessed by a client, the Java code within the page is executed on the server side, producing textual data. This data, which is surrounded by HTML tags, is sent as a normal HTML page to the client. Since the Java code embedded in a JSP page is processed on the server side, the client has no knowledge of the code. The code is replaced by the HTML generated by the Java code before the page is sent to the client.
Creating JSP pages
To create a JSP page, JSP elements also called as JSP tags are used to manipulate Java objects and perform operations upon them to generate dynamic content. Some of these elements are as follows:
Declarations
These are used to declare and define variables and methods in the JSP page. These are converted to instance variables and methods of the servlet.
<%! variable and method declaration %>
Scriptlets
It contains Java code to be executed, these codes are added to service() method of the servlet during translation.
<% Java code to be executed %>
Expressions
These are Java expressions which are evaluated and result is inserted as text in the response to be delivered.
<%= some expression %>
<%!
public String display() {
String message = "Welcome to JSP";
return message;
}
%>
Message from <b>Scriptlet</b>: <%display();%><br/>
Message from <b>Expression</b>: <%=display() %>
lines 1 to 6 contain a JSP declaration that declares a display() method. In line 7 the display() method is called.
MVC Architecture
You have learned how to use Servlet and JSP for developing the presentation layer. In this you write code for following three things:
- To handle the request from the user
- To manage the actual data
- To modify and format the data and present it to the user.
If you develop a single component that interacts with the user as well as maintains the database, then a new requirement will lead to the redesign of the component. So instead of having a single component, you can split it into three different components. This separation of concerns makes code more organized and maintainable. For this there is an architectural pattern called Model View Controller (MVC). This pattern separates architecture into there components called Model, View, and Controller which can communicate with each other.
Now let us learn this pattern in detail.
The MVC architecture has following three components:
Model
The model is responsible for storing data or the state of the application. It also manages the storage and retrieval of the data from the database.
View
The view contains the presentation logic. It displays the data contained in the model to the users and also allows the user to interact with the application. It also notifies the controller of the user actions.
Controller
The controller manages the whole show. It instantiates the model and the view and associates the view with the model. It may instantiate multiple views depending on the application requirements and associates them with the same model. It listens for the user actions and manipulates the model according to business logic.
Introduction to Spring MVC Framework
Spring MVC Framework is one of the most popular framework used for developing presentation layer of enterprise web applications. It is based on MVC and front controller design patterns
- It is a subproject of Spring. So it provides all Spring's core features such as dependency injection and annotations.
- It provides a mechanism to extract data from user request and mapping it to a model class to construct an object which makes development easy and simple.
- It is view independent. You can use any technology for generating the view such as JSP, Tiles, Theamleaf etc.
- It is action based framework. Every user request is an action to be performed with the framework. This is achieved by mapping each request to an executable method. The request parameters are also mapped to arguments of this method.
Spring MVC Architecture
Spring MVC framework is based on MVC and front controller design patterns. The core element of Spring MVC is the Dispatcher Servlet, which is the Front Controller that provides an entry point for handling all requests and forwards them to the appropriate component. The Dispatcher Servlet interacts with handler mappings to determine which controller to execute upon user request and view resolver to render at the end of the flow to return to the user.
- The DispatcherServlet intercepts the incoming HTTP request.
- An application can have multiple controllers so the DispatcherServlet interacts with handler mapping to decide which controller to send the request.
- The handler mapping uses the request URL to decide which controller to send the request and sends controller information to DispatcherServlet.
- After receiving the appropriate controller name, DispatcherServlet sends the request to the controller.
- The controller receives the request from the DispatcherServlet and performs business logic.
- After the business logic is performed by the controller, it generates some data that needs to be sent back to the client and displayed in a web browser. This information is called a model. So the controller sends the model and logical name of the view to the DispatcherServlet.
- The DispatcherServlet passes the logical view name to a ViewResolver, which determines the actual view.
- The actual view is sent back to DispatcherServlet.
- The DispatcherServlet then passes the model to the View, which generates a response.
- The generated response is sent back to DispatcherServlet.
- The DispatcherServlet returns the generated response over to the client.
Note that, by default, DispatcherServlet supports GET, HEAD, POST, PUT, PATCH and DELETE HTTP methods only.
Creating View
After the creating the controller you will create the view. There are many ways using which you can create views in Spring such as JavaServer Pages (JSP), Thymeleaf, FreeMarker, etc. In this course we will use JSP for creating views.
For Customer Login user story you will create three view pages:
- index.html : This is the welcome page of application and placed inside static folder of application.
- welcome.jsp : This page will be rendered when customer credentials are correct.
- error.jsp : This page will be rendered when customer credentials are not correct.
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
To resolve JSP files location, define the following properties in application.properties file: - spring.mvc.view.prefix : It is location of JSP files. If you keep JSP files in /WEB-INF/jsp location then value of this property will be /WEB-INF/jsp/.
- spring.mvc.view.suffix : It the value which is added to logical view name to derive the physical view name. Its value should be .jsp.
Documenting
WADL can also be used as the documentation for REST API and again, it is simply human-readable.
Swagger is yet another approach available for documentation which is basically a specification to describe REST APIs in an understandable format.
Swaggeer Support
Swagger 2 is an open-source project which helps in describing and documenting RESTful APIs. It provides a set of HTML, JavaScript and CSS resources to generate documentation for REST APIs dynamically.
These files are then clubbed together by the Swagger UI project to display the API documentation on the browser. Swagger UI allows other API developers/consumers to interact with the REST endpoints easily as it holds the entire set of details about the resources.
The Swagger 2 specification, which is known as OpenAPI specification that has a lot of implementations available. For Spring Boot, Springfox is the swagger implemtation to be used.
Springfox supports Swagger versions, 1.2 and 2.0.
@SpringBootApplication
@EnableSwagger2
public class InfytelDemo10Application {
public static void main(String[] args) {
SpringApplication.run(InfytelDemo10Application.class, args);
}
}
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.infytel.controller"))
.paths(PathSelectors.any())
.build().useDefaultResponseMessages(false); //For disabling default response messages
}
Annotation
|
Description
|
To be Applied
|
@ApiOperation(value = “ “)
|
Give a description of API methods
|
On API methods
|
@ApiModel(description=“
")
|
To describe Model classes
|
Applied on Model classes
|
@Api(description=“ “)
|
To describe the class
|
Applied on API Class
|
@ApiResponse
|
To describe all the probable
response
|
Applied on API methods
|
@ApiResponses
|
Container to hold all the
@ApiResponses
|
Applied on API methods
|
@RestController
@RequestMapping("/customers")
@Api(value = "CustomerController, REST APIs that deal with Customer DTO")
public class CustomerController
{
@Autowired
private CustomerService customerService;
//Fetching customer details
@GetMapping(produces="application/json")
@ApiOperation(value = "Fetch all the customers of Infytel", response = CustomerDTO.class, tags="fetchCustomer")
@ApiResponses(value = {
@ApiResponse(code = 200, message = "Fetched the customers successfully"),
@ApiResponse(code = 404, message = "Customer details not found") })
public List<CustomerDTO> fetchCustomer()
{
return customerService.fetchCustomer();
}
}
http://<<hostname:portnumber>>/<<Project-Name>>/api-docs
http://<<hostname:portnumber>>/<<Project-Name>>/swagger-ui.html
Embedded database support
Spring Boot supports in-memory embedded databases like H2, HSQL, and Derby. Therefore, actually, you don't need to provide any connection URL's for your data source as shown above, if you work with any of these embedded databases. You have to include just the build dependency for them. For example, if you want to connect with the HSQL database, include the below dependency in POM.
Servicelayer
Spring core without Spring Boot
|
Spring core with Spring Boot
|
The required
version of Spring core jars need to be added to the classpath
|
Spring Boot
starters take care of loading the dependent jars with the default version
|
@Configuration,
@ComponentScan, @Component, and @Service annotations are used
|
@SpringBootApplication,
@Component, and @Service annotations are used
|
Persistence JPA layer
Spring Data JPA without Spring Boot
|
Spring Data JPA with Spring Boot
|
The required
version of Spring Data JPA jars needs to be added to the classpath
|
Spring-boot-starter-data-jpa
takes care of loading the dependent jars with a default version
|
@EnableJpaRepositories
is required
|
Not required,
as JPA repositories will automatically be enabled.
|
Configuration
of EntityManager, TransactionManager, and JpaVendorAdapter is required in the
configuration file
|
It will be
auto-configured
|
Configuration
of DataSource is required in the configuration file
|
Configuration
of the data source is not required in case if you are working with any of the
embedded databases. You just need to provide the build dependency for the
embedded database that you want.
|
Weblayer
Spring MVC without Spring Boot
|
Spring MVC with Spring Boot
|
The
required version of Spring MVC Jars need to be added to the classpath
|
spring-boot-starter-web
takes care of loading the dependent jars with a default version
|
Need to
configure DispatcherServlet in web.xml
|
It will
be auto-configured
|
Need to
configure view resolver in dispatcher-servlet.xml
|
It will
be auto-configured
|
Need to
configure application server for deployment
|
One of
the embedded application servers can be used.
|
Logback
Logging without Spring boot
|
Logging with Spring boot
|
Required
version of logging Jars need to be added to the classpath
|
Spring-boot-starter
takes care of loading the dependent jars with default version, as it includes
spring-boot-starter-logging
|
Need to
provide logging configuration
|
Provides
default configuration for Logback, Log4j2 and Java Util Logging
|
Changing
the logging implementation is difficult as you need to change jars and
configurations
|
Can
easily change the logging implementation by excluding and including
appropriate dependency in pom.xml
|
YAML
|
Properties
|
Support
key/value (Map), List and Scalar data types
|
Supports
key/value (Map) and String data types.
|
Used in
many languages like Perl, Python, PHP, Ruby etc.
|
Used
primarily in Java
|
Uses
indentation to distinguish data hierarchy
|
Uses dots
to denote hierarchy
|
Multiple
Spring Profiles can be configures in single YAML file
|
Only one
Spring Profile per configuration
|
- @Cacheable: Triggers cache population
- @CachePut: Used to update the cache, without interfering the method execution
- @CacheEvict: Triggers cache eviction [from cache items could be removed]
- @Caching: Regroups multiple cache operations to be applied on a method
- @CacheConfig: Shares a few common cache-related settings at class-level
- @EnableCaching: Configuration level annotation, enables Caching