Spring Boot

springboot-tutorial

Spring Boot helps us build stand-alone, production Spring Applications easily, less configuration then rapidly start new projects.

Features:

  • Stand-alone Spring applications
  • Embedded Serverlet Container: Tomcat, Jetty or Undertow.
  • Support ‘Starter’ POMs to make your Maven configuration easily ways.
  • Automatically configure Spring.
  • Provide production-ready features such as metrics, health checks and externalized configuration
  • No code generation, No requirement for XML configuration


< Spring Framework


SQL Databases

1. Configure DataSource

Spring Boot supports auto-configured DataSource if you use spring-boot-starter-jdbc or spring-boot-starter-data-jpa ‘starters’. Details configuration at application.properties file:

spring.datasource.url=jdbc:postgresql://ozenero.com/test
spring.datasource.username=user
spring.datasource.password=pass

But How to configure 2 or Multi-Datasource?

Steps to do:
– Open application.properties, configure datasource’s info:

#db1 datasource
db1.datasource.url=jdbc:postgresql://url1
db1.datasource.username=user1
db1.datasource.password=password1

#db2 datasource
db2.datasource.url=jdbc:postgresql://url2
db2.datasource.username=user2
db2.datasource.password=password2

– Mark one of the DataSource with @Primary:

@Configuration
public class DataSourceBeans {
   
    @Primary
    @Bean(name="db1.datasource")
    @ConfigurationProperties(prefix="db1.datasource")
    public DataSource db1DataSource(){
        return DataSourceBuilder.create().build();
    }
   
    @Bean(name="db2.datasource")
    @ConfigurationProperties(prefix="db2.datasource")
    public DataSource db2DataSource(){
        return DataSourceBuilder.create().build();
    } 
}

– Now they are ready to be injected:

...
// datasource 1
@Autowired
@Qualifier("db1.datasource")
DataSource dataSource1;

// datasource 2
@Autowired
@Qualifier("db2.datasource")
DataSource dataSource2;

>>> More details at: How to configure multi Postgres DataSources with Springboot

2. Using JdbcTemplate

Spring’s Jdbc Template is used to access and manipulate databases. Spring Boot provides auto-configuration JdbcTemplate bean. So we can easily inject it via @Autowire. Or using supported function: getJdbcTemplate() of Spring’s JdbcDaoSupport class:

...
@Repository
public class CustomerDaoImpl extends JdbcDaoSupport implements CustomerDao{
  
    @Autowired
    DataSource dataSource;
  
    @PostConstruct
    private void initialize(){
        setDataSource(dataSource);
    }
    
    ...
    @Override
    public void insert(Customer cus) {
        String sql = "INSERT INTO customer " + "(CUST_ID, NAME, AGE) VALUES (?, ?, ?)" 
        getJdbcTemplate().update(sql, new Object[]{
            cus.getCustId(), cus.getName(), cus.getAge()
        });
    }
    ...
}

>>> More details at: How to use Spring JDBC Template with Spring Boot for Postgres DataBase

3. Spring JPA and Spring Data

For persistence, SpringBoot provides @Entity anonation for scanning entities.

...
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
  
@Entity
@Table(name="company")
public class Company {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    private String name;
    ...     
}

>>> Example to practice:
Spring JPA – One to Many Relationship
Spring JPA – Many to Many relationship

With RestAPIs ->
SpringBoot + Hibernate Spring JPA One-to-One Association + PostgreSQL | CRUD RestAPIs Post/Get/Put/Delete
Spring JPA/Hibernate One-to-Many Association + PostgreSQL | SpringBoot CRUD RestAPIs Post/Get/Put/Delete example

4. H2 Database

H2 database has small footprint (smaller than 1.5 MB) with low memory requirements. It supports for multiple schemas and standard SQL, JDBC API. We can use H2 with disk based or in-memory databases.

H2 can be built by following mode:
– Embedded mode (local connections)
– Server mode (remote connections)
– Mixed mode (local and remote connections)

With Embedded Mode, an application uses JDBC to create a H2 database within the same JVM so it’s very fast to exchange data.

How to configure it with SpringBoot?
-> Spring Boot has a built in H2 database, so We just add below dependency:

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
</dependency>

>>> More details at: Integrate H2 database with SpringBoot & Spring JPA in Embedded mode

If your project uses H2 database to develop and also enable Spring Security, then when accessing to H2 console path: /h2_console, an error Access Denied Page will be thrown.

Why?
-> By default, Spring Security will block /h2_console path of H2 database.
How to resolve it?
-> Solution is a simple configuration with Spring Security as below segment code:

@Override
protected void configure(HttpSecurity http) throws Exception {
	http.authorizeRequests()
		...
		
	http.csrf().disable();
	http.headers().frameOptions().disable();
}

http.csrf().disable(): disable CRSF.
http.headers().frameOptions().disable(): H2 database console runs inside a frame, So we need to disable X-Frame-Options in Spring Security.

>>> More details at: How to configure Spring Security to access H2 database console in Spring Boot project

NoSQL Technologies

1. MongoDB

MongoDB is an open-source NoSQL document database, written using C++. Spring Boot provides an spring-boot-starter-data-mongodb to work with MongoDB.

To define MongoDb configured beans, use:
MongoDbFactory: an interface for factories to create DB instances.
MongoOperations: an interface that specifies a basic set of MongoDB operations.

@Configuration
public class AppConfig {
    @Bean
    public MongoDbFactory mongoDbFactory() throws UnknownHostException{
        return new SimpleMongoDbFactory(new MongoClient("localhost", 27017), "test");
    }
   
    @Bean
    public MongoOperations mongoOperations() throws UnknownHostException{
        return new MongoTemplate(mongoDbFactory());
    }
}

To define Document model, use @Document

>>> Example for details at: Spring MongoOperations to access MongoDB

2. Neo4j

Neo4j is a highly scalable, native graph database. Spring Boot supports Spring Neo4J configuration with module: spring-boot-starter-data-neo4j.

– Configuration for connecting to Neo4J:

spring.data.neo4j.uri=http://my-server:7474
spring.data.neo4j.username=neo4j
spring.data.neo4j.password=admin

– Create a Neo4J repository by extends GraphRepository, sample:

...
import org.springframework.data.neo4j.repository.GraphRepository;

public interface StudentRepository extends GraphRepository {
...
}

– Some annotations for Neo4j database:
@NodeEntity: Identifies a domain entity as being backed by a node in the graph.
@GraphId: Identifies the field in the domain entity which is to be mapped to the id property of its backing node in the graph.
@Relationship: purpose for creating relationship of entities in Neo4j.

>>> Example for more details at: Spring Neo4J

3. Gemfire

Spring Data REST provides a mechanics for creating and retrieving an Object from Gemfire storage.

Configuration steps:
– Use needed dependencies: spring-boot-starter-data-rest, spring-boot-starter-data-gemfire:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-gemfire</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>

– Use annotation @Region for mapping data:

import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.gemfire.mapping.Region;
  
@Region("customer")
public class Customer {
     
    private static AtomicLong COUNTER = new AtomicLong(0L);
     
    @Id
    private Long id;
    private String firstname;
    private String lastname;
    private int age;
      
    @PersistenceConstructor
    public Customer() {
        this.id = COUNTER.incrementAndGet();
    }
    ...
}

– Config CacheFactoryBean and LocalRegionFactoryBean:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.gemfire.CacheFactoryBean;
import org.springframework.data.gemfire.LocalRegionFactoryBean;
 
import com.gemstone.gemfire.cache.GemFireCache;
import com.javasampleapproach.gemfirerestapi.model.Customer;
 
@Configuration
public class GemfireConfig {
    @Bean
    Properties gemfireProperties() {
        Properties gemfireProperties = new Properties();
        gemfireProperties.setProperty("name", "EmbeddedGemfireApplication");
        gemfireProperties.setProperty("mcast-port", "0");
        return gemfireProperties;
    }
      
    @Bean
    CacheFactoryBean gemfireCache() {
        CacheFactoryBean gemfireCache = new CacheFactoryBean();
        gemfireCache.setProperties(gemfireProperties());
        return gemfireCache;
    }
      
    @Bean
    LocalRegionFactoryBean customerRegion(final GemFireCache cache) {
        LocalRegionFactoryBean customerRegion = new LocalRegionFactoryBean<>();
        customerRegion.setCache(cache);
        customerRegion.setName("customer");
        customerRegion.setPersistent(false);
        return customerRegion;
    }
}

– Create a Gemfire repository by extends CrudRepository interface:

import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
 
@RepositoryRestResource(collectionResourceRel = "customer", path = "customer")
public interface CustomerRepository extends CrudRepository {
    Customer findByFirstname(@Param("firstname") String firstname);
    Customer findByLastname(@Param("lastname") String lastname);
    Iterable findByAgeGreaterThan(@Param("age") int age);
    Iterable findByAgeLessThan(@Param("age") int age);
}

>>> Example for more details at: How to create a SpringBoot Gemfire RestfulApi

4. Elasticsearch

Elasticsearch is a distributed, full-text search engine based on Lucene with JSON schema. SpringBoot provides a convenient way by supported dependency: spring-boot-starter-data-elasticsearch ‘Starter’.

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

– Using annotation: @Document(indexName = "javasampleapproach", type = "customer") to create a mapping model.

...
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
 
@Document(indexName = "javasampleapproach", type = "customer")
public class Customer {
 
    @Id
    private String id;
    ...
}

– The main part is how to connect with Elasticsearch server, We use interface ElasticsearchRepository that is supported by Spring Data:

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
 
import com.javasampleapproach.elasticsearch.model.Customer;
 
public interface CustomerRepository extends ElasticsearchRepository {
     
    List findByFirstname(String firstname);
     
    Page findByFirstname(String firstname, Pageable pageable);
     
    List findByAge(int age);
}

– Use spring.data.elasticsearch.cluster-nodes to define elasticsearch’s cluster.

>>> More details at: How to start SpringBoot ElasticSearch using Spring Data

5. Apache Cassandra

Apache Cassandra database is a NoSql solution for scalability & high availability. SpringBoot provides a convenient way by supported dependency: spring-boot-starter-data-cassandra ‘Starter’.

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

Use @Table & @PrimaryKey to create mapping model:
@Table: identifies a domain object to be persisted to Cassandra as a table.
@PrimaryKey: identifies the primary key field of the entity.

import org.springframework.data.cassandra.mapping.PrimaryKey;
import org.springframework.data.cassandra.mapping.Table;
 
@Table
public class Customer {
     
    @PrimaryKey
    private int id;
    private String firstname;

...

Create a Cassandra repository:
– Need provide port, keyspace-name and contact-points properties for connection’s info, via spring.data.cassandra:

spring.data.cassandra.keyspace-name=javasampleapproach
spring.data.cassandra.contact-points=ozenero.com
spring.data.cassandra.port=9042

– Spring Data supports basic operations for Cassandra. But more limited than JPA repositories, so we need use @Query.

...
public interface CustomerRepository extends CrudRepository {
     
    @Query(value="SELECT * FROM customer WHERE firstname=?0")
    public List findByFirstname(String firstname);
 
    @Query("SELECT * FROM customer WHERE age > ?0")
    public List findCustomerHasAgeGreaterThan(int age);
}  

>>> More details at: How to start Spring Data Cassandra with SpringBoot

6. Couchbase

Spring Boot provides auto-configuration for Couchbase and abstractions on top of it by Spring Data Couchbase. We can use it easily via spring-boot-starter-data-couchbase ‘Starter’ which had collected the needed dependencies.

For connecting with Couchbase Bucket and Cluster, we can use spring.couchbase.* properties in application.properties file:

spring.couchbase.bootstrap-hosts=127.0.0.1
spring.couchbase.bucket.name=jsabucket
spring.couchbase.bucket.password=123456
spring.data.couchbase.auto-index=true

For working with Couchbase repository, we use CouchbaseRepository interface:

public interface CouchbaseRepository extends CrudRepository {
 
  /**
   * @return a reference to the underlying {@link CouchbaseOperations operation template}.
   */
  CouchbaseOperations getCouchbaseOperations();
 
}

>>> More details at: Couchbase – How to create Spring JPA Couchbase application with SpringBoot

7. Solr

spring-data-solr-springboot-architecture

SpringBoot provides spring-boot-starter-data-solr Starter to support connecting and abstractions on top of Spring Data Solr.

7.1 Solr connection

In application.properties file, We use spring.data.solr.* to configure Solr connection.
Here is the details of sourcecode – SolrProperties:

@ConfigurationProperties(prefix = "spring.data.solr")
public class SolrProperties {
 
	/**
	 * Solr host. Ignored if "zk-host" is set.
	 */
	private String host = "http://127.0.0.1:8983/solr";
 
	/**
	 * ZooKeeper host address in the form HOST:PORT.
	 */
	private String zkHost;
	
	...
 
}	

By default the instance will attempt to connect to a server using http://localhost:8983/solr. And we can add @Bean with SolrClient type to override it.

7.2 Spring Data Solr repositories

We use @SolrDocument to create Solr document:

@SolrDocument(solrCoreName = "customer")
public class Customer {
	@Id
	@Field
	private String id;
 
	@Field
	private String name;
	
	@Field
	private Integer age;
	
	public Customer() {
	}
	
	...

Using SolrCrudRepository to create Solr repositories:

...
 
import org.springframework.data.solr.repository.SolrCrudRepository;
 
import com.javasampleapproach.solr.model.Customer;
 
public interface CustomerRepository extends SolrCrudRepository {
	List findByNameEndsWith(String name);
}

Details about interface SolrCrudRepository:

public interface SolrCrudRepository extends SolrRepository,
		PagingAndSortingRepository {
}

>>> More details at: Apache Solr – How to start Spring Data Solr with SpringBoot

Spring MVC

1. XML REST service

– If on the classpath has Jackson XML extension (jackson-dataformat-xml), SpringBoot will be used to render XML responses.
– If jackson-dataformat-xml is not available, JAXB in JDK will be used with a required annotation @XmlRootElement in model

import javax.xml.bind.annotation.XmlRootElement;
 
@XmlRootElement
public class Customer {
    private String firstname;
    ...
}

– GET requests must have Accept: text/xml header.
– POST requests must have Content-Type: text/xml header.

>>> More details at: How to create a SpringBoot XML REST Service

2. Multipart File Uploads

Upload files to Servlet containers, application need register a MultipartConfigElement class. But Spring Boot makes it more easy by automatically configure it.
– From upload form, we specify enctype="multipart/form-data":

...
<form method="POST" enctype="multipart/form-data" action="/">
    <table>
		<tr><td>File to upload:</td><td><input type="file" name="file" /></td></tr>
			<tr><td></td><td><input type="submit" value="Upload" /></td></tr>
	</table>
</form>
...

– In Post Mapping method, we specify MultipartFile file request’s parameter:

...
@PostMapping("/")
public String handleFileUpload(@RequestParam("file") MultipartFile file, Model model) {
...

We can handle limit of file’s size by spring.http.multipart config:
spring.http.multipart.max-file-size: limit total file size for each request.
spring.http.multipart.max-request-size: limit total request size for a multipart/form-data.

>>> More details at: How to upload MultipartFile with Spring Boot

HATEOAS

Spring HATEOAS project helps to create REST representations that follow HATEOAS (Hypertext as the Engine of Application State) principle.

1. HATEOAS

In general, HATEOAS principle implies that with each response, API should shows Clients appropriate information about the next potential steps or guide to deeper understanding itself.

For example, if client requests for specific Customer information:
http://localhost:8080/customers/68
The Service should provide link to get all Orders of that Customer in the response:

{
   ...
   "customerId": 68,
   "_links": {
      "self": {
         "href": "http://localhost:8080/customers/68"
      },
      "allOrders": {
         "href": "http://localhost:8080/customers/68/orders"
      }
   }
}
2. Spring HATEOAS

Spring HATEOAS provides a set of useful types to ease working with those.

Firstly, we need create a Link object:
– Way 1: using Spring HATEOAS ControllerLinkBuilder
– Way 2: using Spring HATEOAS EntityLinks

Then, add Link object to ResourceSupport object:
– Way 1: extending ResourceSupport class
– Way 2: using Resources (that extends ResourceSupport class)

Finally, just return YourClass object or Resource object to Client.

>>> More details at: How to start Spring HATEOAS RestAPI with Spring Boot

3. Spring HATEOAS Rest API with JQuery Ajax POST/GET

We’ll build a Spring Boot Application in that:
HATEOAS REST Service provides interface for interacting with Database.
– Client calls API by using JQuery Ajax POST/GET.

>>> More details at: Spring HATEOAS Rest API + JQuery Ajax POST/GET example | Spring Boot

4. Consume Spring HATEOAS Rest API using JQuery Ajax

We’ll build a Spring Boot Application in that:
HATEOAS REST Service provides interface for interacting with Database.
– Client calls API by using JQuery Ajax GET, consume HATEOAS REST Service above and displays Data.

>>> More details at: Consume Spring HATEOAS Rest API using JQuery Ajax example | Spring Boot

5. Consume Spring HATEOAS Rest API using AngularJS

HATEOAS REST Service provides interface for interacting with Database.
– Client calls API by using AngularJS, consume HATEOAS REST Service above and displays Data.

>>> More details at: Consume Spring HATEOAS Rest API using AngularJS example | Spring Boot

CORS

Cross-Origin-Resource-Sharing (CORS) is a W3C specification which defines how a browser should be allowed using script to access different origin than the origin it has been served. With CORS, we can specify what kind of cross domain requests are authorized in a flexible way, instead of using some less secured and less powerful hacks like IFRAME or JSONP.

1. Configure CORS using @CrossOrigin
@CrossOrigin(origins = { "http://localhost:9000" }, maxAge = 3000)
@RestController
public class WebController {

	@CrossOrigin(origins = { "http://localhost:8484" }, maxAge = 6000)
	@RequestMapping("customers")
	public List getCustomers() {
		// ...
	}

	@RequestMapping("data")
	public List getData() {
		// ...
	}
}

>>> More details at: Spring CORS example using @CrossOrigin – Spring Boot

2. Global CORS Configuration using Java Config

Spring provides a way that uses Java Config applying for all REST Service Controllers in our project.
WebMvcConfigurerAdapter has addCorsMappings() method that we need to override to configure CORS:

@Configuration
public class AppConfig extends WebMvcConfigurerAdapter {

	@Override
	public void addCorsMappings(CorsRegistry registry) {

		registry.addMapping("/customers")
				.allowedOrigins("http://localhost:8484", "http://localhost:9000")
				.allowedMethods("POST", "GET", "PUT", "DELETE")
				.allowedHeaders("Content-Type")
				.exposedHeaders("header-1", "header-2")
				.allowCredentials(false)
				.maxAge(6000);

	}
}

>>> More details at: Spring Boot – CORS Support using Java Config

3. Global CORS Configuration using XML Config

Spring also provides a way that uses XML Config applying for all REST Service Controllers in our project:

<mvc:cors>
	<mvc:mapping path="/customers"
		allowed-origins="http://localhost:8484, http://localhost:9000"
		allowed-methods="POST, GET, PUT, DELETE"
		allowed-headers="Content-Type"
		exposed-headers="header-1, header-2"
		allow-credentials="false"
		max-age="6000" />
</mvc:cors>

>>> More details at: Spring Boot – CORS Support using XML Config

Logging

1. Log4j2

Apache Log4j2 is an upgrade to Log4j that provides significant improvements over its predecessor, Log4j 1.x, and provides many of the improvements available in Logback while fixing some inherent problems in Logback’s architecture.

To configure Log4j2 dependency with Spring Boot, we do 3 steps:
– Exclude logback from default log dependency of Spring Boot:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>

– Add Spring Web MVC dependency:

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

– Add Log4j2 dependency:

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

And create a file with special name: log4j2.xml under /src/main/resources folder:

...
<Loggers>
        <Logger name="org.springframework.web" level="info" additivity="false">
            <AppenderRef ref="SpringBoot-Appender"/>
            <AppenderRef ref="Console-Appender"/>
        </Logger>
        <Logger name="com.javasampleapproach.log4j2.controller" level="info" additivity="false">
            <AppenderRef ref="App-Appender"/>
            <AppenderRef ref="Console-Appender"/>
         </Logger>
        <Root>
            <AppenderRef ref="Console-Appender"/>
        </Root>
</Loggers>
...

>>> More details at: How to configure Apache Log4j2 with Spring Boot

2. Actuator Loggers Endpoint

Spring Boot 1.5.1 provides some new features. Among them, we have a new actuator loggers endpoint, which helps us to view and change logging level of application with the MVC endpoint.

– Start with spring-boot-starter-actuator

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

– Actuator endpoints help us to monitor and interact with our application. Spring Boot includes a number of built-in endpoints including Loggers Endpoint:

{
     "configuredLevel":"...",
     "effectiveLevel":"..."
}

‘…‘ could be: TRACE, DEBUG, INFO, WARN, ERROR…

– We can change how this endpoint exposes by add some code to application.properties, in this example:

management.port=8081
management.security.enabled=false
management.address=127.0.0.1
management.context-path=/actuator
 
endpoints.loggers.enabled=true

– View Logging Level:
Just make a HTTP GET request to /loggers/[our qualified name of package]. The JSON String result will be:

{
     "configuredLevel":"[Logging Level to be set]",
     "effectiveLevel":"[current active Logging Level]"
}

– Change Logging Level: We can issue a HTTP POST request to /loggers/[our qualified name of package] with the following JSON

{
     "configuredLevel": "[Logging Level]"
}

>>> More details at: How to change logging level with the MVC endpoint – new Actuator Loggers Endpoint | Spring Boot

MicroService

1. Routing and Filtering

Netflix Zuul is a proxy solution to forward requests to microservices, Spring Cloud Netflix contains an embedded Zuul.

Step to start building a Zuul gateway:
– Add required dependencies:

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

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zuul</artifactId>
    <version>1.3.0.RELEASE</version>
</dependency>

– Configure MicroServices for routing:

zuul.routes.students.url=http://localhost:8081
zuul.routes.lecturers.url=http://localhost:8082
ribbon.eureka.enabled=false
server.port=8080

– Enable Zuul Gateway by annotation @EnableZuulProxy:

...
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@EnableZuulProxy
@SpringBootApplication
public class SpringBootZuulGateWayApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(SpringBootZuulGateWayApplication.class, args);
    }
}

Zuul has 4 filter types:
pre filters are executed before the request is routed.
route filters uses to route the request.
post filters are executed after the request has been routed.
error filters execute if an error occurs while handling the request.

zuul-gateway-1

For creating a filter, just extends ZuulFilter. Then need overview 4 functions:
public String filterType(): specify the type of a filter: (pre, route, post, error) by a String
public int filterOrder(): indicates the order to process this filter.
public boolean shouldFilter(): gives a condition to consider to execute the filter.
public Object run(): functionality of the filter.

>>> More details at: How to configure SpringBoot Zuul – Routing and Filtering

2. Spring Cloud Ribbon – Client Load Balancing

Spring Cloud Ribbon is a solution for Client Load Balancing.

Advantage & Disadvantage:
– Decentralized Load Balancing
– No bottle neck
– Resilent
– Data can be inconsistent

SpringBoot provides a convenient way by supported dependency: spring-cloud-starter-ribbon ‘Starter’.

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>

Config Ribbon Client:

spring:
  application:
    name: Ribbon-Client
     
helloworld:
  ribbon:
    eureka:
      enabled: false
    listOfServers: localhost:8090,localhost:8091,localhost:8092
    ServerListRefreshInterval: 1000
     
server:
  port: 8080

@RibbonClient is used to configure a Ribbon Client.

...
@SpringBootApplication
@RibbonClient(name = "helloworld", configuration = Configuration.class)
public class SpringClientSideRibbonApplication {
...

@LoadBalanced annotation is used to configure RestTemplate bean as a LoadBalancerClient.

@RestController
public class WebController {
     
    @LoadBalanced
    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
 ...

>>> More details at: Client Load Balancing – Spring Cloud Ribbon + Spring Boot

Messaging

I. ActiveMQ

1. JMS Producer/Consumer

Spring JMS (Java Message Service) is a powerful mechanism to integrate in distributed system.
ActiveMQ is a Java Open Source, it is simple JMS solution for concurrent, consumers and producers architecture in integrated development.
Spring Boot will create a Connection Factory basing on those information automatically:

spring.activemq.broker-url=failover://tcp://localhost:61616
spring.activemq.user=admin
spring.activemq.password=admin

Use JmsTemplate for sending & receiving messages:
JmsConsumer

@Component
public class JmsConsumer {
    @Autowired
    JmsTemplate jmsTemplate;
     
    @Value("${jms.queue.destination}")
    String destinationQueue;
     
    public String receive(){
        return (String)jmsTemplate.receiveAndConvert(destinationQueue); 
    }
}

JmsProducer

@Component
public class JmsProducer {
    @Autowired
    JmsTemplate jmsTemplate;
     
    @Value("${jms.queue.destination}")
    String destinationQueue;
     
    public void send(String msg){
        jmsTemplate.convertAndSend(destinationQueue, msg);
    }
}

>>> Example for details at: How to use Spring JMS with ActiveMQ – JMS Consumer and JMS Producer

2. Explicitly configure Spring ActiveMq ConnectionFactory

For configuring ActiveMQ ContainerFactory, we need to setup a new bean ConnectionFactory to override the auto-configured connection-factory bean of SpringBoot.

...
@Bean
public ConnectionFactory connectionFactory(){
    ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
	...
    return connectionFactory;
}

Then use the ConnectionFactory bean to configure 2 beans {JmsListenerContainerFactory, JmsTemplate}:

/*
 * Used for Receiving Message
 */
@Bean
public JmsListenerContainerFactory jsaFactory(ConnectionFactory connectionFactory,
												DefaultJmsListenerContainerFactoryConfigurer configurer) {
	DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
	...
	return factory;
}
 
/*
 * Used for Sending Messages.
 */
@Bean
public JmsTemplate jmsTemplate(){
    ...
    return template;
}
 
...

JmsTemplate bean is used to send Jms messages.
JmsListenerContainerFactory is used to listen Jms messages.

>>> More details at: ActiveMq – Explicitly configure Spring ActiveMq ConnectionFactory with SpringBoot

3. JMS ActiveMQ – Send Java object messages(specially with Bi-Directional relationship Java objects)

Use Jms MessageConverter bean as below:

@Bean // Serialize message content to json using TextMessage
public MessageConverter jacksonJmsMessageConverter() {
    MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
    converter.setTargetType(MessageType.TEXT);
    converter.setTypeIdPropertyName("_type");
    return converter;
}

With Bi-Directional Java object messages -> We got an Infinite recursion (StackOverflowError) exception:

...

Caused by: org.springframework.jms.support.converter.MessageConversionException: Could not map JSON object
...

-> We can use @JsonIdentityInfo to resolve it.

>>> More details at: Spring Jms ActiveMq – How to send Java object messages to ActiveMQ server (specially with Bi-Directional relationship Java objects)

4. JMS ActiveMq Topic (Publisher-Subcribers pattern)

ActiveMq provides the Publish-Subscribe pattern (pub-sub) for building Jms message distributed systems.
How it work? -> When you publish a messages, all active subscribers will receive a copy of the message:

ActiveMQ - Publisher/Consumer

With SpringBoot application, we need to enable pubSubDomain (.setPubSubDomain(true)) for 2 beans {JmsTemplate, JmsListenerContainerFactory}:

@Bean
public JmsListenerContainerFactory jsaFactory(ConnectionFactory connectionFactory,
                                                DefaultJmsListenerContainerFactoryConfigurer configurer) {
    ...
    factory.setPubSubDomain(true);
    ...
    return factory;
}
 
@Bean
public JmsTemplate jmsTemplate(){
    JmsTemplate template = new JmsTemplate();
	...
    template.setPubSubDomain(true);
    return template;
}

And set spring.jms.pub-sub-domain=true in application.properties file.

>>> More details at: ActiveMq – How to work with Spring JMS ActiveMq Topic (Publisher-Subcribers pattern) using SpringBoot

5. Response Management
5.1 @SendTo

With the Spring JMS improvements (from 4.1), we can used @SendTo annotation to define the default next destination with @JmsListener:

SpringBoot-ActivMQ-Response-Management-application-sendto-aannotation-architecture

@JmsListener(destination = "${jsa.activemq.queue.listen}", containerFactory="jsaFactory")
@SendTo("${jsa.activemq.queue.sendto}")
public Product processOrder(Product product) {
    // process a newProduct
    return newProduct;
}

For additional headers, you could return a Message object instead:

@JmsListener(destination = "${jsa.activemq.queue.listen}", containerFactory="jsaFactory")
@SendTo("${jsa.activemq.queue.sendto}")
public Message  receive(Product product, @Header("company") String companyName){
	
	...
	
	Message  mesage = MessageBuilder
            .withPayload(product)
            .setHeader("type", product.getType())
            .build();
	
	return mesage;	
}

>>> More details at: Spring Jms ActiveMQ – How to create a SpringBoot ActiveMQ Response Management application by @SendTo annotation

5.2 JmsResponse

With the support of JmsResponse, we can configure the response destination at runtime:

SpringBoot-ActivMQ-Response-Management-application-JmsResponse-architecture-1

...
 
@JmsListener(destination = "${jsa.activemq.queue.listen}", containerFactory="jsaFactory")
public JmsResponse>  receive(Product product, @Header("company") String companyName){
	
	...
	
	Message response = MessageBuilder
            .withPayload(product)
            .setHeader("type", product.getType())
            .build();
    return JmsResponse.forQueue(response, sendToQueue);	
}
 
...

>>> More details at: Spring JMS ActiveMq – How to implement a runtime SpringBoot ActiveMQ JmsResponse application

Other Examples

ActiveMQ Producer/Consumer + SpringBoot RestAPIs example
Ajax JQuery + SpringBoot RestAPI + ActiveMQ Producer/Consumer example

II. Apache Artemis

SpringBoot Auto-configure
When having artemis-jms-client Artemis on the classpath, Spring Boot can auto-configure a ConnectionFactory.
We use spring.artemis.* to control Artemis configuration:

spring.artemis.mode=native
spring.artemis.host=localhost
spring.artemis.port=61616
spring.artemis.user=jsa
spring.artemis.password=12345

spring.artemis.mode has 2 mode: {NATIVE, EMBEDDED}:
NATIVE: Connect to a broker using the native Artemis protocol.
EMBEDDED: Embed the broker in the application.

For sending message, we use: JmsTemplate:

@Component
public class ArtemisProducer {
	@Autowired
	JmsTemplate jmsTemplate;
	
	@Value("${jms.queue.destination}")
	String destinationQueue;
	
	public void send(String msg){
		jmsTemplate.convertAndSend(destinationQueue, msg);
	}
}

For recieved messages, we use: @JmsListener:

@Component
public class ArtemisConsumer {
	
	@JmsListener(destination = "${jms.queue.destination}")
	public void receive(String msg){
		System.out.println("Recieved Message: " + msg);
	}
}

springboot-artemis-architecture

>>> More details at: Apache Artemis – How to produce/consume JMS messages with SpringBoot Artemis applications.

III. AMQP

1. RabbitMQ Producer/Consumer

Creating 2 SpringBoot applications {Producer, Consumer} for working with RabbitMQ:

rabbitmq-architecture-copyright

Producer will send messages to RabbitMQ Exchanges with a routingKey. RabbitMQ uses routingKey to determine which queues for routing messages.
Consumer listens on a RabbitMQ Queue to receive messages.

With SpringBoot, we use spring.rabbitmq.* for controlling RabbitMQ configuration:

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

Producer uses AmqpTemplate to send messages:

@Component
public class Producer {
	
	@Autowired
	private AmqpTemplate amqpTemplate;
	
	public void produceMsg(String msg){
		amqpTemplate.convertAndSend(exchange, routingKey, msg);
	}
}

Consumer uses @RabbitListener to recieve messages:

@Component
public class Consumer {
 
	@RabbitListener(queues="${jsa.rabbitmq.queue}")
    public void recievedMessage(String msg) {
        // to do
    }
}

>>> More details at: RabbitMQ – How to create Spring RabbitMQ Producer/Consumer applications with SpringBoot

2. RabbitMq Publish/Subcribe pattern

Flow messages:
Publisher will send messages to the fanout exchange.
– The fanout exchange routes messages to all of the queues that are bound to it and the routing key is ignored.
Subcribers instances recieves messages from the queues.

Spring-RabbitMq-Publish–Subscribe-pattern-architechture

>>> More details at: RabbitMq – How to create Spring RabbitMq Publish/Subcribe pattern with SpringBoot

3. RabbitMQ – send/receive Java object messages

Using Message Converter:

@Bean
public MessageConverter jsonMessageConverter(){
    return new Jackson2JsonMessageConverter();
}

With Bi-Directional Java object messages -> We may get an Infinite recursion (StackOverflowError) exception.

-> Solution: we can use @JsonIdentityInfo to handle the exception.

>>> More details at: RabbitMQ – How to send/receive Java object messages with Spring RabbitMq | SpringBoot

IV. Apache Kafka

1. SpringBoot supports auto-configuration

SpringBoot supports auto-configuration for Apache Kafka development:
– Use spring.kafka.* in application.properties file to modify external configuration.

SpringBoot-Kafka-Application

– Use Spring auto-configured KafkaTemplate to send Kafka-based messages:

@Autowired
private KafkaTemplate kafkaTemplate;
 
public void send(String data) {
    ...   
    kafkaTemplate.send(kafkaTopic, data);
}

– Use @KafkaListener to setup a Kafka listener:

@Component
public class KafkaConsumer {
    ...
	
	@KafkaListener(topics="${jsa.kafka.topic}")
    public void processMessage(String content) {
		...
    }
}

>>> More details at: How to start Spring Apache Kafka Application with SpringBoot Auto-Configuration

2. Spring Kafka JsonSerializer (JsonDeserializer) to produce/consume Java Object messages

We send and receive Java object messages to/from Apache Kafka, so ProducerFactory uses JsonSerializer.class and ConsumerFactory uses JsonDeserializer.class to serialize/deserialize Java objects to Json bytes.

KafkaProducerConfig:

@Bean
public ProducerFactory producerFactory() {
    ...
    configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);
    return new DefaultKafkaProducerFactory<>(configProps);
}
 
@Bean
public KafkaTemplate kafkaTemplate() {
    return new KafkaTemplate<>(producerFactory());
}

KafkaConsumerConfig:

@Bean
public ConsumerFactory consumerFactory() {
    ...
    props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
    return new DefaultKafkaConsumerFactory<>(props,
						    	      new StringDeserializer(), 
						    	      new JsonDeserializer<>(Customer.class));
}
 
@Bean
public ConcurrentKafkaListenerContainerFactory kafkaListenerContainerFactory() {
    ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>();
	...
    return factory;
}

Note: SpringKafka uses Jackson library to serialize/de-serialize Java objects to/from Json bytes so we need jackson-databind dependency.

>>> More details at: How to use Spring Kafka JsonSerializer (JsonDeserializer) to produce/consume Java Object messages

Caching

1. Infinispan

Infinispan cache is a distributed in-memory key/value data store, it is a excellent cache for software system. For starting with SpringBoot, we need dependencies:

...

    org.springframework.boot
    spring-boot-starter-cache



    org.infinispan
    infinispan-jcache

...

– In application.properties file, use spring.cache to define configuration of Infinispan:

spring.cache.infinispan.config=infinispan.xml
spring.cache.type=infinispan

– The infinispan.xml file is created under folder: /src/main/resources:



 
    
        
        
    

– Enable caching by annotation: @EnableCaching:

import org.springframework.cache.annotation.EnableCaching;
 
@SpringBootApplication
@EnableCaching
public class SpringCachingInfinispanApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(SpringCachingInfinispanApplication.class, args);
    }
}

>>> More details at: Infinispan Cache Solution | Spring Boot

2. Couchbase

We can use Couchbase as backing cache:

spring-cache-couchbase-architecture-resize

How to configure Couchbase server as Cache?
-> We need to build a CacheManager with Couchbase cluster:

@EnableCaching
@Configuration
public class CacheConfig {
 
    ...
	
    @Bean(destroyMethod = "disconnect")
    public Cluster cluster() {
        return CouchbaseCluster.create(couchbaseServer);
    }
 
    @Bean(destroyMethod = "close")
    public Bucket bucket() {
        return cluster().openBucket(couchbaseBucket, couchbasePassword);
    }
 
    @Bean
    public CacheManager cacheManager() {
        CacheBuilder cacheBuilder = CacheBuilder.newInstance(bucket()).withExpiration(0);
        return new CouchbaseCacheManager(cacheBuilder, CACHE_NAME);
    }
 
}

@EnableCaching is used to enable the caching.

Document for Couchbase cache is built with Serializable:

public class Customer implements Serializable {
...
 
}

>>> More details at: Couchbase – How to create Spring Cache Couchbase application with SpringBoot

Deployment

Traditional Deployment
Create a deployable war file

Step to do:
– Extends SpringBootServletInitializer
– Update build configuration

1. Extends SpringBootServletInitializer

package com.javasampleapproach.wardeployment;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
 
@SpringBootApplication
public class SpringBootWarDeploymentApplication  extends SpringBootServletInitializer {
     
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(SpringBootWarDeploymentApplication.class);
    }
 
    public static void main(String[] args) {
        SpringApplication.run(SpringBootWarDeploymentApplication.class, args);
    }
}

2. Update build configuration=
– Update your build configuration: war
– Configure embedded servlet container dependency as provided

...
war
...

    org.springframework.boot
    spring-boot-starter-tomcat
    provided

>>> More details at: How to deploy Spring Boot Web App War file to Tomcat Server with Maven build

Deployment on Heroku Clouud

Heroku + SpringBoot Deployment example – How to Deploy SpringBoot + PostgreSQL on Heroku platform with Heroku CLI

Batch Application

Many business operations need to process with batch job for critical environment. Spring Batch is a lightweight framework to boot the batch application. To start SpringBatch by SpringBoot, using dependency:


    org.springframework.boot
    spring-boot-starter-batch

Configure datasource for repository of SpringBatch Application by easy way:

spring.datasource.url=jdbc:postgresql://url
spring.datasource.username=db
spring.datasource.password=password

Spring Boot provides @EnableBatchProcessing annotation for automatically enable Spring Batch:

@SpringBootApplication
@EnableBatchProcessing
public class SprinpBatchApplication {
    public static void main(String[] args) {
        SpringApplication.run(SprinpBatchApplication.class, args);
    }
}

To configure details of a Batch Job, we can use Java Config or XML config:
– Java config

...
@Configuration
public class BatchConfig {
    @Autowired
    public JobBuilderFactory jobBuilderFactory;
    @Autowired
    public StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job job() {
        return jobBuilderFactory.get("job")
                .incrementer(new RunIdIncrementer())
                .flow(step1())
                .end()
                .build();
    }
 
    @Bean
    public Step step1() {
        return stepBuilderFactory.get("step1")
                . chunk(1)
                .reader(new Reader())
                .processor(new Processor())
                .writer(new Writer())
                .build();
    }
}

– XML config

...  

    
        
            
        
    

... 

>>> More details at:
How to start with Spring Batch using Spring Boot – Java Config
Spring Batch XML Config with Spring Boot

Sending Email

Spring Framework provides JavaMailSender interface & Spring Boot provides auto-configuration for sending mail.
– Using spring-boot-starter-mail dependency.
– Configure spring.mail for JavaMailSender:

spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=javasampleapproach
spring.mail.password=***
 
#mail properties
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true

– Create a MailSender class:

...
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
 
@Component("javasampleapproachMailSender")
public class MailSender {
     
    @Autowired
    JavaMailSender javaMailSender;
     
    public void sendMail(String from, String to, String subject, String body) { 
        SimpleMailMessage mail = new SimpleMailMessage();
        mail.setFrom(from);
        mail.setTo(to);
        mail.setSubject(subject);
        mail.setText(body);
         
        javaMailSender.send(mail);
        ...
    }
}

>>> More Details at: How to configure JavaMailSender with SpringBoot

WebSocket

1. Flow of messages

We create a Spring WebSocket Application with the below flow of messages:

spring-websocket-architecture-new-ws

Detail explanations:
– WebSocket clients connect to the WebSocket endpoint at ‘/jsa-stomp-endpoint’
– Subscriptions to ‘/topic/hi’ pass through the response channel, then are forwarded to the In-memory broker (Simple Broker).
– User objects sent to ‘/jsa/hello’ pass through the request channel then are forwarded to the spring WebController. WebController will handle User objects by @MessageMapping and transform to Hello messages then use @SendTo returns the messages to ‘/topic/hi’ through the brokerChannel.

...

@MessageMapping("/hello")
@SendTo("/topic/hi")
public Hello greeting(User user) throws Exception {
    return new Hello(...);
}

...

– The Simple Broker broadcasts messages to subscribers through the response channel.

2. Server side

In server side, we use SockJS and STOMP for our application.

What is SockJS?
-> SockJS lets applications use a WebSocket API but falls back to non-WebSocket alternatives when necessary at runtime, without the need to change application code.

Simple Java configuration to enable SockJS and Stomp in Spring application:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/jsa");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/jsa-stomp-endpoint").withSockJS();
    }
}
3. Client side

About client side, we uses {sockjs-client, stomp-websocket} libs for development:



– Make a connection:

function connect() {
    var socket = new SockJS('/jsa-stomp-endpoint');
    stompClient = Stomp.over(socket);
    stompClient.connect({}, function (frame) {
        setConnected(true);
        stompClient.subscribe('/topic/hi', function (hello) {
			...
        });
    });
}

The connect() function uses SockJS and stomp.js to open a connection to /jsa-stomp-endpoint, which is where our SockJS server is waiting for connections.

– Dis-Connection:

function disconnect() {
    if (stompClient != null) {
        stompClient.disconnect();
    }
    setConnected(false);
}

– Send messages:

function sendName() {
    stompClient.send("/jsa/hello", {}, JSON.stringify({'name': $("#name").val()}));
}

>>> More details at: WebSocket – Create Spring WebSocket Application with SpringBoot + SockJS + STOMP

JWT Authentication

With MySQL database ->
Spring Security JWT Authentication example – RestAPIs SpringBoot + Spring MVC + Spring JPA + MySQL

With PostgreSQL database ->
Spring Security JWT Authentication + PostgreSQL – RestAPIs SpringBoot + Spring MVC + Spring JPA

Other Examples

Spring Social with SpringBoot

SpringBoot Social Facebook – Authentication & Access Facebook Feeds Example

CSV, PDF, Excel Files with SpringBoot

iText PDF + SpringBoot RestAPI – Extract MySQL Data to PDF File
Excel File – Download from SpringBoot RestAPI + Apache POI + MySQL
CSV File – Download from SpringBoot RestAPI + OpenCSV + MySQL
Download CSV File from SpringBoot RestAPI + MySQL – using Apache Commons CSV + Spring JPA

All Articles

>>> SPRING BOOT