Contents
1. Microservices – A Primer
2. Spring Boot REST Crud API
3. Swagger Documentation for REST API
4. Error Handling and Logging
5. Consuming RESTFul Webservice
6. Producing and Consuming SOAP webservice
7. Handle uncaught exceptions
8. Angular JS User Interface for Spring Boot REST API
9. Spring Boot security in web application
[Link] Spring Boot application using docker
[Link]
1. Microservices – A Primer
What is Microservices?
Wikipedia definition says
Microservices is a variant of the service-oriented architecture (SOA) architectural style that
structures an application as a collection of loosely coupled services.
But there is no official definition of Microservices by industry standards. It’s recent phenomenon
in software industry to architect the new softwares which should be light weight, easier to deploy
and scale, easier to refactor individually and could work independently.
To understand in details, you can definitely read Martin Fowler’s Microservices or Chris
Richardson’s Microservices.
We will not be covering this post in detail as compared to link I have posted here. Microservices
are small services that can run independently, but can also easily communicate with other services.
Microservice Architecture vs Monolithic Architecture
In traditional monolithic architecture style, there is a single application with single code base. An
application contains number of modules which are interrelated and can have external
dependencies. It’s a multi-tier enterprise application and has been used to build software for long.
Microservice architecture style was born out of need to build an application that could easily be
supported for mobile applications. Older style was not easy to support for mobile and new
generation way to handling of data. Any large enterprise application can be easily built using
microservices architecture style.
How to identify Microservice Architecture Pattern?
A simple ground rule of microservice architecture pattern is to build a standalone service that can
be run without depending on any other service. That means for a large application can have more
than one services talking to each other, communicating with their own databases, but still
performing the business logic. Databases are used to ensure loose coupling of services.
A large enterprise e-commerce application can consist of following services
1. Backend service REST API to manage data
1. Account Service
2. Shipment Service
3. Inventory Service
2. Runtime service to handle runtime and backend data to process business logic
3. Logging service
4. Error Handling service
5. Session service
UI for the e-commerce application can be built independently to use backend services to show/edit
data.
By standards, there are few rules to identify microservices patterns
1. Decomposition by business capability
2. Database per service pattern
3. API gateway pattern
4. Client-side discovery and Server-side discovery
Pros and Cons of Microservices
Pros
1. Deployability – They can independently be deployed.
2. Reliability – A fault in the service can only bring down that service, depending on handling
in application, rest of the application can still be accessed.
3. Scalability – Each microservice can be scaled depending on requirements using clusters
and grids.
4. Availability – Dispatching the patch or newer version of service requires less downtime
compared to regular monolithic application.
5. Management – Easier to manage
6. Design and Development – Each service can be developed independently and helps
developer to manage the service easily without worrying about other services.
Cons
1. Performance – All services involved in application have to communicate with each other
over network and that could hamper the performance.
2. Testability – Automated tests are harder to manage and run.
3. Memory usage – Possible duplicate data across services and lot of duplication in cache.
2. Spring Boot REST CRUD API
In this chapter, we will learn how to write a CRUD Rest API using Spring Boot. Spring boot
provides some cool features to create a production ready Spring application that can be deployed
as a war file on any environment. Part of this book, we will create a microservice using Spring
Boot and deploy on docker. Let’s start with creation of a simple REST API.
What you’ll need
1. Eclipse Mars.2 Release
2. Java version 1.8
3. MySQL 5.0 or higher
4. Maven 3.0 or higher
What we’ll cover
In this lesson, we will cover following items
1. Create a Maven project
2. Assemble pom file for all dependencies
3. Create entity classes
4. Create business logic to handle data
5. Create a rest controller
6. Run the API in tomcat
Create a Maven project
As first step, let’s create a maven project in eclipse. You can create this by going into File > New
> Maven Project.
Select Archtype as maven-archtype-webapp.
Enter artifactid as benefits and groupid as [Link]
Assemble pom file for all dependencies
We will be using spring-boot and all the required dependencies including spring-data. Spring data
JPA provides lot of useful enhancements that can be seamlessly used with spring-boot project.
Spring-data will cover the data access layer which is basically implements persistence. Once we
use spring-data, we don’t have to add any external hibernate or eclipselink JPA APIs. Also some
of the data access repositories provided by spring-data makes implementing data access layer code
less worrisome.
<project xmlns="[Link]
xmlns:xsi="[Link]
xsi:schemaLocation="[Link]
[Link]
<modelVersion>4.0.0</modelVersion>
<groupId>[Link]</groupId>
<artifactId>Benefits</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>Benefits Maven Webapp</name>
<url>[Link]
<parent>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>[Link]</version>
</parent>
<dependencies>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>[Link].log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<dependency>
<groupId>[Link].log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
<finalName>Benefits</finalName>
</build>
</project>
Create entity classes
We will be creating a rest api for Benefits service which will have companies and users as main
objects. We are only covering basic data model classes at the moment, but as part of the series
we will develop a web application. Each company will company profile and each user will
userprofile. So we will have four basic entities Company, CompanyProfile, User, UserProfile.
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
@Entity(name = "Company")
@Table(name = "company")
public class Company implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
public Company(int id, String name, String type, String ein,
CompanyProfile cp) {
super();
[Link] = id;
[Link] = name;
[Link] = type;
[Link] = ein;
[Link] = cp;
}
public Company() {
super();
}
@Id
@GeneratedValue(strategy = [Link])
private int id;
@Column
private String name;
@Column
private int statusid;
@OneToOne(cascade = [Link], fetch = [Link])
@JoinColumn(name = "companyprofileid")
private CompanyProfile cp;
@Column
private String type;
@Column
private String ein;
public int getId() {
return id;
}
public void setId(int id) {
[Link] = id;
}
public String getName() {
return name;
}
public void setName(String name) {
[Link] = name;
}
public int getStatusid() {
return statusid;
}
public void setStatusid(int statusid) {
[Link] = statusid;
}
public CompanyProfile getCp() {
return cp;
}
public void setCp(CompanyProfile cp) {
[Link] = cp;
}
public String getType() {
return type;
}
public void setType(String type) {
[Link] = type;
}
public String getEin() {
return ein;
}
public void setEin(String ein) {
[Link] = ein;
}
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
@Entity(name = "User")
@Table(name = "user")
public class User implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
public User() {
@Id
@GeneratedValue(strategy = [Link])
private int id;
@Column
private Date createdate;
@Column(name = "email", nullable = false, unique = true)
private String email;
@Column(name = "firstname", length = 255)
private String firstname;
@Column(name = "middlename", length = 255)
private String middlename;
@Column(name = "lastname", length = 255)
private String lastname;
@Column(name = "username", length = 100)
private String username;
@Column(name = "jobtitle", length = 255)
private String jobtitle;
@Column(name = "password_hash", nullable = false)
private String passwordHash;
@Column(name = "enabled")
private int enabled;
@OneToOne(cascade = [Link], fetch = [Link])
@JoinColumn(name = "userprofileid")
private UserProfile userprofile;
@JsonFormat(with = Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
@ManyToMany(cascade = [Link])
@JoinTable(name = "user_role", joinColumns = @JoinColumn(name =
"user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
private List<Role> roles;
public int getId() {
return id;
}
public void setId(int id) {
[Link] = id;
}
public Date getCreatedate() {
return createdate;
}
public void setCreatedate(Date createdate) {
[Link] = createdate;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
[Link] = email;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
[Link] = firstname;
}
public String getMiddlename() {
return middlename;
}
public void setMiddlename(String middlename) {
[Link] = middlename;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
[Link] = lastname;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
[Link] = username;
}
public String getJobtitle() {
return jobtitle;
}
public void setJobtitle(String jobtitle) {
[Link] = jobtitle;
}
public UserProfile getUserprofile() {
return userprofile;
}
public void setUserprofile(UserProfile userprofile) {
[Link] = userprofile;
}
public String getPasswordHash() {
return passwordHash;
}
public void setPasswordHash(String passwordHash) {
[Link] = passwordHash;
}
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
[Link] = roles;
}
public int getEnabled() {
return enabled;
}
public void setEnabled(int enabled) {
[Link] = enabled;
}
Create business logic to handle the data
Part of our architecture for REST API, we will have following three layers
1. Rest layer
2. Business object layer
3. Data access layer
So in Business object layer, we will implement all the managers which will handle processing of
rest requests to create, update, read or delete the data. In subsequent posts, we will enhance this
layer to handle logging, error handling and more.
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
public class UserManagerImpl implements UserManager {
private UserRepository userRepository;
@Autowired
public void setUserRepository(UserRepository userRepository) {
[Link] = userRepository;
}
@Override
public User createUser(User u) {
if (u != null) {
User user = [Link](u);
return user;
} else {
return null;
}
}
@Override
public User updateUser(User u) {
// TODO Auto-generated method stub
return null;
}
@Override
public User getUser(int id) {
User user = [Link](id);
if (user == null) {
return null;
}
return user;
}
@Override
public List getAllUsers() {
List userList = (List) [Link]();
return userList;
}
@Override
public void deleteUser(int guid) {
// TODO Auto-generated method stub
User user = [Link](guid);
if (user == null) {
return;
}
[Link](user);
}
}
Create a REST controller
One of the best uses of Spring boot is to create rest API and the feature it offers for the same is to
use REST controller. Spring-boot offers an annotation for the same as @RestController.
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
@RestController
@RequestMapping("benefits/v1")
public class UserService {
@Autowired
UserManager userMgr;
@RequestMapping(value = "/users/", method = [Link])
public User createUser(User user) {
User u = [Link](user);
return u;
}
@RequestMapping(value = "/users/{id}", method = [Link])
public User getUser(@PathVariable("id") int id) {
User u = [Link](id);
return u;
}
@RequestMapping(value = "/users/", method = [Link])
public List getAllUsers() {
List cList = [Link]();
return cList;
}
@RequestMapping(value = "/users/", method = [Link])
public User updateUser(User user) {
User u = [Link](user);
return u;
}
@RequestMapping(value = "/users/{id}", method = [Link])
public Response deleteUser(@PathVariable("id") int id) {
[Link](id);
return [Link]([Link]).build();
}
}
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
@RestController
@RequestMapping("benefits/v1")
public class CompanyService {
@Autowired
CompanyManager compMgr;
@RequestMapping(value = "/companies/", method = [Link])
public Company createCompany(Company company) {
Company c = [Link](company);
return c;
}
@RequestMapping(value = "/companies/{id}", method = [Link])
public Company getCompany(@PathVariable("id") int id) {
Company c = [Link](id);
return c;
}
@RequestMapping(value = "/companies/", method = [Link])
public List getAllCompanies() {
List cList = [Link]();
return cList;
}
@RequestMapping(value = "/companies/", method = [Link])
public Company updateCompany(Company company) {
Company c = [Link](company);
return c;
}
@RequestMapping(value = "/companies/{id}", method = [Link])
public Response deleteCompany(@PathVariable("id") int id) {
[Link](id);
return [Link]([Link]).build();
}
}
Run the API in tomcat
We are using embedded tomcat in this Spring-boot project. So once we are done building and
installing the code through maven, we can run the project through eclipse or standalone war file in
tomcat. For our demo purposes, we will run this application through eclipse, which will start
embedded tomcat.
If we execute the url [Link] – it will display json for user data as
below
3. Swagger Documentation for REST API
In this lesson, we will show how to add swagger documentation to Spring boot rest API. We
learned how to create a Spring Boot REST API in previous chapter. In Microservices’ world, these
days documenting your API is a standard norm. Swagger provides a handy interface and a simple
way to build these documentations that any client can test any moment. They don’t need to have
all the services on their environment.
What is Swagger?
Swagger was intended to provide a standard, language-agnostic interface to REST APIs which
allow anyone to understand the capabilities of a service without any source code, documentation
of source code. You can find more details about Swagger here.
How to add swagger documentation?
In our previous lesson, we added Spring boot REST API. We will add swagger documentation to
the same REST API.
1. Add Maven dependencies
To start with, let’s add maven dependencies for swagger jars.
<dependency>
<groupId>[Link]</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
<scope>compile</scope>
</dependency>
2. Add Swagger bean in configuration
In our main starting Application class, we will add few configurations for setting up a bean which
will handle swagger documentation. In below code, I show what I have added in [Link]
file. Basically, we have created a new bean of type Docket which takes care of swagger
configuration.
@EnableSwagger2
@SpringBootApplication(scanBasePackages = { "[Link]" })
public class Application {
public static void main(String[] args) {
[Link]([Link], args);
}
@Bean
public Docket benefitsApi() {
return new Docket(DocumentationType.SWAGGER_2).groupName("Benefits")
.apiInfo(apiInfo())
.select()
.apis([Link]())
.paths([Link]())
.build()
.pathMapping("/");
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder().title("Benefits REST Service")
.description(" A simple REST service for Benefits software ")
.contact(new Contact("Yogesh Mali", "[Link]
""))
.version("1.0")
.build();
}
}
3. Show Swagger documentation
Now once we have added the configuration, we can build our project with maven clean install.
After successful build, run the project from eclipse as a Java application. We will access swagger
documentation from URL [Link] . This will look like below:
4. Error Handling and Logging
In previous lessons, I wrote about how to create a spring boot REST API chapter 2 and how to add
swagger documentation for REST API chapter 3. In this lesson, we will add error handling and
logging to our REST API. Error handling and Logging are two different ideas, so I will divide this
post in two sections.
1. Logging
In most production applications, logging is critical and it is used for multiple purposes. Few of
those uses are debugging the production issues or auditing for the application. Over the years,
different logging libraries have evolved to use in java based applications. slf4j is the most popular
framework as it provides a simple abstraction layer to any kind of logging framework.
In our tutorial for this application, we will be using log4j2 which is the most recent and advance
logging library out there. It provides lot of useful features for performance, support for multiple
APIs, advance filtering, automatic reloading of configurations etc. We will not cover any of these
in this article, if you are interested to read about log4j2 libraries, read here.
Add log4j2 library in application –
To use log4j2, we will add the maven dependency to our project’s pom file. This should look like
below
<dependency>
<groupId>[Link].log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<dependency>
<groupId>[Link].log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
Add log4j2 configuration file
To enable logging, we will have to add a configuration file in our application. This configuration
file can be XML, JSON or YAML file. We will be using a XML file [Link] which will look
like below
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:[Link]} [%t] %-5level
%logger{36} - %msg%n" />
</Console>
<File name="BenefitsFile" fileName="[Link]" append="true">
<PatternLayout pattern="%d{yyy-MM-dd HH:mm:[Link]} [%t] %-5level
%logger{36} - %msg%n"/>
</File>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="Console" />
<AppenderRef ref="BenefitsFile"/>
</Root>
</Loggers>
</Configuration>
So we are using Console and BenefitsFile as two loggers which will log into a console and file
respectively. We are setting log level to DEBUG. If you log any messages with a level lower than
DEBUG, they will be logged into console or file. We will have to add a file [Link] in
classpath to achieve this logging in file. Log pattern is with date time, log level, class from which
log is originating and log message.
Add logging in application code
Once we have required logging libraries and logging configuration adjusted, we can add logging
in our code to capture this logging during runtime execution. In one of the managers
CompanyManagerImpl, we will add a logger.
public static final Logger LOGGER =
[Link]([Link]);
@Override
public List<Company> getAllCompanies()
{
[Link](" Enter >> getAllCompanies() ");
List<Company> cList = (List<Company>) [Link]();
[Link](" Exit << getAllCompanies() ");
return cList;
}
Now once we execute our spring boot application, we can capture the logs in console or file. The
file will be [Link].
2. Error Handling
We will not write about exceptions in detail as it has been covered in this post Exceptions. We
will create our own custom exception which will be extended from WebApplicationException
which jersey library provides.
This will look like below:
package [Link];
import [Link];
import [Link];
public class InvalidRequestException extends WebApplicationException {
/**
*
*/
private static final long serialVersionUID = 1L;
private int errorcode = 00; // 00 indicates - no error
public InvalidRequestException() {
public InvalidRequestException(int errorcode, String message) {
super([Link]([Link].BAD_REQUEST)
.entity(message).build());
[Link] = errorcode;
}
public InvalidRequestException(int errorcode, String message, Throwable
cause) {
super(cause, [Link]([Link].BAD_REQUEST)
.entity(message).build());
[Link] = errorcode;
}
}
Now we can use this custom exception in our managers when we want to throw an error message
to indicate if there is anything wrong with client request. Similarly we can build another exception
to show if there is anything wrong on server side. Following snippet shows from
CompanyManagerImpl where we have shown how to throw this exception.
@Override
public Company getCompany(int guid)
{
[Link](" Enter >> getCompany() ");
Company company = [Link](guid);
if (company == null) {
[Link](" Exit << createCompany() ");
throw new InvalidRequestException(400, "Company not found");
}
[Link](" Exit << getCompany() ");
return company;
}
In this lesson, we showed how to handle logging and errors in a REST API.
5. Consuming RESTFul Webservice
Continuing the series of lessons on Spring Boot, in this post, we will investigate how to consume
a REST API service we built previously. This is a short lesson, but we will show how to read the
data and how to post the data with some of the features Spring Boot offers to consume a REST
service for client side. Eventual goal is to use this feature to call our rest service during runtime to
use the data from database to display on views which a user will be able to see.
Purpose
Purpose of this post is to read company data from Company REST API and also to create a
company by posting company data using the same REST API.
Build a client
To consume a rest service programmatically, Spring provides a feature called RestTemplate.
RestTemplate is easiest way for client to interact with server side code with just one line of code.
In our client code, we will need a RestTemplate object, REST service URL. Since this is a sample
we are building, we will be adding a main method in this class to run this client side of the code.
In real life scenarios, during runtime, a client code will call rest template to get server side data,
use that data to massage or display to user on user interface.
RestTemplate restTemplate = new RestTemplate();
String resourceAPI_URL = "[Link]
Company company = [Link](resourceAPI_URL, [Link],
1);
This code is showing that we are calling REST service to read company data for company with id
that a client will pass.
Similarly, we will have another request to post the data on server side to create a company. The
code for that will look like below:
String resourceAPI_POSTURL = "[Link]
Company comp = new Company();
[Link]("XYZ Company");
[Link](1);
[Link]("Corporation");
[Link]("9343423232");
Company newcomp = [Link](resourceAPI_POSTURL, comp,
[Link]);
In this post, we showed how to use RestTemplate a feature that spring boot provides to consume
a REST service.
6. Producing and Consuming SOAP Webservice
In last few lessons, we have covered following
1. Spring Boot REST CRUD API
2. Swagger Documentation for Spring Boot REST API
3. Error Handling and logging in Spring Boot REST API
4. Consuming RESTful Webservice
In this lesson, we will describe how to create a SOAP webservice from our existing Spring Boot
REST API. This SOAP webservice will provide us user data from the database which is we have
connected through Spring-data in Spring REST API.
1. Requirements
1. Eclipse Mars2
2. Maven 3.1 and above
3. Spring 1.4 and above
4. Java 7
5. Tomcat 8
2. SOAP Web Service
We will use our existing Spring Boot REST API to build an application that will act as a SOAP
web service to provide users data. For a given user id, web service will return user data.
Let’s create a schema file in src/main/resources directory and maven will create java classes based
on this schema file.
<xs:schema xmlns:xs="[Link]
xmlns:tns="[Link]
targetNamespace="[Link]
elementFormDefault="qualified">
<xs:element name="getUserRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="id" type="xs:int"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="getUserResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="user" type="tns:user"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="user">
<xs:sequence>
<xs:element name="id" type="xs:int"/>
<xs:element name="firstname" type="xs:string"/>
<xs:element name="middlename" type="xs:string"/>
<xs:element name="lastname" type="xs:string"/>
<xs:element name="username" type="xs:string"/>
<xs:element name="createdate" type="xs:date"/>
<xs:element name="jobtitle" type="xs:string"/>
<xs:element name="email" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
3. Update Maven dependencies
Now to generate classes from schema, we have to make sure we have all the right dependencies in
our [Link]. We will also add spring boot service dependency to create a SOAP web service.
<project xmlns="[Link]
xmlns:xsi="[Link]
xsi:schemaLocation="[Link]
[Link]
<modelVersion>4.0.0</modelVersion>
<groupId>[Link]</groupId>
<artifactId>Benefits</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>Benefits Maven Webapp</name>
<url>[Link]
<parent>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>[Link]</version>
</parent>
<dependencies>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>swagger-jersey2-jaxrs</artifactId>
<version>1.5.12</version>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>[Link].log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<dependency>
<groupId>[Link].log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>[Link]</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>xjc</id>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaDirectory>${[Link]}/src/main/resources/</schemaDirectory>
<outputDirectory>${[Link]}/src/main/java</outputDirectory>
<clearOutputDir>false</clearOutputDir>
<schemaLanguage>WSDL</schemaLanguage>
<generatePackage>[Link]</generatePackage>
<forceRegenerate>true</forceRegenerate>
<scehmas>
<schema>
<url>[Link]
</schema>
</scehmas>
</configuration>
</plugin>
</plugins>
<finalName>Benefits</finalName>
</build>
</project>
If we run the project with maven build now, the plugin jaxb2-maven-plugin will generate classes
under [Link] directory. It will also enable our wsdl SOAP url for users.
This will generate following java objects
GetUserRequest
GetUserResponse
ObjectFactory
package-info
User
4. Defining the service
Next, we will define an interface for our service. This will look like below
package [Link];
public interface UserAccountService
{
public [Link] getUserDetails(int id);
}
Implementation of this service will be mapping out entity class User to generated class for soap
service User. Using the id as a key to get user data from repository, we will map to soap service
user. For post purposes, we will not show the implementation of this interface.
5. Creating the Service Endpoint
What is a service endpoint? When a SOAP request for defined URL is handled by Spring servlet,
Spring servlet redirects that request to service endpoint. Service endpoint then processes that
request to create a response. Our spring-boot-starter-web-services dependency will bring all the
necessary classes for annotation purposes.
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
@Endpoint
public class UserAccountServiceEndpoint
{
// private static final String TARGET_NAMESPACE =
"[Link]
private static final String TARGET_NAMESPACE =
"[Link]
@Autowired
private UserAccountService userAccountService;
@PayloadRoot(localPart = "getUserRequest", namespace = TARGET_NAMESPACE)
public @ResponsePayload GetUserResponse getUserRequest(@RequestPayload
GetUserRequest request)
{
GetUserResponse response = new GetUserResponse();
User user = [Link]([Link]());
[Link](user);
return response;
}
}
@Endpoint annotation allows the class to be defined as service endpoint and included in
@Component annotation for scanning. Make sure the namespace defined in this class matches
with XSD schema definition. Otherwise, you can run into error for “No Endpoint defined for“.
6. Configuration
Next, we will configure our configuration class to generate wsdl endpoint. This configuration class
will be annotated by @EnableWs to provide web service configuration.
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link].wsdl11.DefaultWsdl11Definition;
import [Link];
import [Link];
@Configuration
@EnableWs
@ComponentScan("[Link]")
public class AppConfig extends WsConfigurerAdapter
{
@Bean
public ServletRegistrationBean
messageDispatcherServlet(ApplicationContext applicationContext)
{
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
[Link](applicationContext);
return new ServletRegistrationBean(servlet, "/benefits/endpoints/*");
}
@Bean(name = "users")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema
usersSchema)
{
DefaultWsdl11Definition wsdl11definition = new
DefaultWsdl11Definition();
[Link]("UserAccountService");
[Link]("/endpoints");
[Link]("[Link]
rvices/useraccountservice");
[Link](usersSchema);
return wsdl11definition;
}
@Bean
public XsdSchema usersSchema()
{
return new SimpleXsdSchema(new ClassPathResource("[Link]"));
}
}
Few important points about this configuration class are
MessageDispatcherServlet is a required servlet to dispatch web service messages. We set
this servlet with a bean to handle the URL from which request will be coming.
DefaultWsdl11Definition creates SOAP for the given XSD schema
XsdSchema provides abstraction for our users XSD schema
7. Running the SOAP webservice
Now build our project with maven. Run the spring boot application through eclipse to start the
embedded tomcat server. Once the tomcat server starts, if we access
url [Link]
Output in the browser will be as below
Here we showed how to create a simple SOAP webservice which we have combined with Spring
Boot REST API service. We can also test this SOAP webservice using Soap UI, as shown in below
screenshot
8. Consuming the SOAP web service
In previous steps, we showed how to produce a SOAP web service, now we will show how to
consume this SOAP web service programmatically.
8.1 Create a client class
Under package [Link], define a class UserClient which will extend a
WebServiceGatewaySupport class. WebServiceGatewaySupport class provides web service
methods.
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
public class UserClient extends WebServiceGatewaySupport
{
public GetUserResponse getUserById(int userid)
{
GetUserRequest userrequest = new GetUserRequest();
[Link](userid);
GetUserResponse response = (GetUserResponse)
getWebServiceTemplate().marshalSendAndReceive(userrequest, new
SoapActionCallback("[Link]
));
return response;
}
}
8.2 Configure the client for Spring Bean support
We will configure Jaxb2Marshaller to support JAXB to set context path. This will help us marshal
and unmarshal our xml request and response through.
package [Link];
import [Link];
import [Link];
import [Link].Jaxb2Marshaller;
@Configuration
public class ClientAppConfig
{
@Bean
public Jaxb2Marshaller marshaller()
{
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
[Link]("[Link]");
return marshaller;
}
@Bean
public UserClient userClient(Jaxb2Marshaller marshaller)
{
// WSDL URL - [Link]
UserClient uc = new UserClient();
[Link]("[Link]
[Link](marshaller);
[Link](marshaller);
return uc;
}
}
8.3 Run the SOAP web service client
We will define a class with main method to pass an argument of user id. Our client will call the
web service with passed argument to return us the data if that user id existed in the database.
public class UserSoapClient
{
public static void main(String[] args)
{
AnnotationConfigApplicationContext ctx = new
AnnotationConfigApplicationContext();
[Link]([Link]);
[Link]();
UserClient usc = [Link]([Link]);
[Link](" For Employee: ");
GetUserResponse response = [Link](1);
[Link]("Name: " + [Link]()
.getFirstname() + " "
+ [Link]()
.getLastname());
[Link](" Job: " + [Link]()
.getJobtitle());
}
}
9. Conclusion
In this lesson, we showed how to create a SOAP web service and how to build a client to consume
the same SOAP web service using Spring Boot.
7. Handle uncaught exception in Spring Boot Application
Many times, we have seen exception thrown on your web page and all the stack trace of the
exception. A non-technical user will not be able to understand most of the time. Also stack trace
is not the best option when we can show the same exception error in nice json format with the root
cause. In this lesson, we will show how to handle unhandled exceptions from our previous Spring
REST API we built here. This particular feature will show how to handle most HTTP 500 errors
which happen because of server side issues. Any errors with request or client side, those are HTTP
400 errors and they have been handled in previous post Error Handling in Spring Boot Rest API.
Problem
What happens when there is a database connection issue OR columns in your REST API are
different from specified in database tables? Your API will throw a 500 error and if you don’t have
any mechanism, this will display error in an html format which will not give much information to
user or developer to resolve the issue.
Solution
JAX-RS provides a way to handle uncaught exceptions. This can be done by my implementing an
interface for ExtendedExceptionMapper. Basically this is a contract for a provider that takes java
exceptions and maps them to a response object which can be transformed into a JSON. This can
be implemented as below:
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
@Provider
public class UncaughtExceptionMapper implements
ExtendedExceptionMapper<Throwable>
{
private static final Logger LOGGER =
[Link]([Link]);
@Override
public Response toResponse(Throwable exception)
{
[Link]("Enter >> toResponse ");
[Link]("Exception Caught: " + [Link]());
[Link]("Exit << toResponse");
return
[Link](Status.BAD_REQUEST).entity([Link]()).build();
}
@Override
public boolean isMappable(Throwable arg0)
{
return !(arg0 instanceof WebApplicationException);
}
}
Basically this implementation shows a class UncaughtExceptionMapper implementing an
interface ExtendedExceptionMapper which provides a way to map all exceptions which are not of
type WebApplicationException (Most HTTP 400 errors are WebApplicationExceptions).
toResponse method will help to log all the exceptions and convert exceptions into a Response
object.
Conclusion
In this lesson, we showed how to map all uncaught exceptions into json format response.
8. Angular JS User Interface for Spring Boot REST API
In this lesson, we will add a user interface using AngularJS to the REST API we created chapter
2.
Controller for home page
First we will create a controller in Spring Boot rest api to call our home page. All the requests that
will come to web server, will go through this controller and controller will return a home page for
the request based on path.
[Link] will look like below:
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
@Controller
public class MainController
{
public static final Logger LOGGER =
[Link]([Link]);
@RequestMapping(value = "/home", method = [Link])
public String homepage()
{
[Link](" Enter >> homepage() ");
return "index";
}
}
Any request coming to [Link] will return a page from [Link].
Create a Home Page
Now, we will create an [Link] page. We will also be using angular JS framework as part of
this home page so that we can build a single page application. If you are not aware of Angular JS
or new to this framework, you can read about it AngularJS. One thing to remember while creating
this page is a directory structure. Lot of issues that arise to create html pages are because of
directory structure. Directory structure will look like below:
The home page [Link] page is under main/resources/templates/ directory and it looks like
below
<html ng-app="benefitApp">
<head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"
/><title>Benefit Application</title>
<script>[Link]('<base href="' + [Link] + '" />');</script>
<link rel="stylesheet" href="/css/[Link]" />
<script src="[Link]
<script src="[Link]
[Link]"></script>
<script src="[Link]
[Link]"></script>
<script type="text/javascript" src="./js/[Link]"></script>
</head>
<body ng-controller="MainCtrl">
Hello {{name}}!
<div>
<ul class="menu">
<li><a href="listUser">user-list</a></li>
<li><a href="listCompany">company-list</a></li>
</ul>
<div ng-view="ng-view"></div>
</div>
</body>
</html>
Home page shows that this is an angular app with name “benefitApp”. This also declares a
controller “MainCtrl” with an angular view. Important to see we are importing [Link], angular-
[Link] and [Link] modules. Click on user-list or company-list, will show list of users
and list of companies respectively.
Create a controller
Now to handle the controller (MainCtrl), we added in [Link], we will add [Link] which will
declare the controller. This javascript file also contains config data to handle all the routing of
pages. That’s why we will be importing “ngRoute” and “ngResource” angular modules.
var app = [Link]('benefitApp', ['ngRoute','ngResource']);
var app = [Link]('benefitApp', ['ngRoute','ngResource']);
[Link]('MainCtrl', function($scope, $routeParams)
{
$[Link] = 'World';
$scope.$routeParams = $routeParams;
})
Throughout the interaction on web pages, we will be using different controllers for editing user or
company information and creating user or company. The same file [Link] will also handle routing
of these pages which is shown below
[Link](function($routeProvider,$locationProvider) {
$locationProvider.html5Mode(true);
$[Link]('/listUser',
{templateUrl: 'views/[Link]', controller: 'userController'});
$[Link]('/listCompany',
{templateUrl: 'views/[Link]', controller: 'companyController'});
$routeProvider .when('/editUser/:userId',
{ templateUrl : 'views/[Link]' }) ;
$routeProvider .when('/editCompany/:companyId',
{ templateUrl : 'views/[Link]' }) ;
$[Link]('/createUser',
{templateUrl:'views/[Link]'});
$[Link]('/createCompany',
{templateUrl:'views/[Link]'});
});
Rest of the code showing all controllers’ logic has been skipped for post purposes. UserController
or CompanyController are calling rest apis which we have built using Spring boot.
Demo
Now build the code and run our embedded tomcat webserver. Fire up the
url [Link] – it will look like below:
Click on user-list and it will show list of users inside the same page as below:
Click on edit button and we will see a form to update user information:
9. Spring Boot Security in web application
In this lesson, we will show how to use Spring Boot Security to login, authorization based on user
role, logout and error handling.
We will be discussing following use case
1. A user access a home page for application.
2. If user is authenticated, he will be redirected to page
3. If user is not authenticated, he will be challenged to login ( redirected to login page)
4. User enters credentials
5. If correct credentials, a session is created and user is verified for role
6. If incorrect credentials, show an error message
7. If user is of role USER, he is redirected to user profile page. He can only edit or save his
information.
8. If user is of role ADMIN, he is redirected to list of users page.
9. If user clicks on logout, session is deleted and user is redirected to login page.
10. If user (of any role) tries to login after logout, user should be redirected to appropriate page
11. If user is neither USER nor ADMIN, he is redirected to error page
12. Handling of CSRF token
To completely understand this lesson, make sure you have gone through my other posts on Spring
Boot series.
1. Spring Boot REST CRUD API
2. Swagger Documentation
3. User Interface using AngularJS
Database changes
Since this post involves authorization for users, we have to do some database changes. We will
add couple of tables and respective model classes in our REST api modification.
Table role
Table user_role
create table role (id int(11) auto_increment primary key not null, role
varchar(255) )
create table user_role (user_id int(11) primary key not null, role_id int(11)
primary key not null))
user_role table helps to maintain many-to-many relationship between user and role table. We will
have only two roles for demo purposes USER and ADMIN.
Another change we have done in table user is that we have added field called password_hash to
store password set by user/administrator for user to login. We will be storing a hash password
value of the original password that user will set.
Dependencies
Since we will be using Spring-security for authentication and authorization purposes, we will add
the dependency for spring security as follows:
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Controllers and Web Layer
Other than those changes mentioned about, we will demonstrate this post in top-down fashion
rather than bottom-up fashion.
So for web layer, we will define a new controller LoginController and modify our
existing MainController.
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
/**
*
* @author Yogesh Mali
*
*/
@Controller
public class LoginController
{
public static final Logger LOGGER =
[Link]([Link]);
@Autowired
UserManager userManager;
/**
*
* @param model
* @return
*/
@RequestMapping(value = "/user", method = [Link])
public String userpage(Model model)
{
[Link](" Enter >> userpage() ");
Authentication auth = [Link]()
.getAuthentication();
String name = [Link]();
User user = [Link](name);
[Link]("name", [Link]());
[Link]("userid", [Link]());
[Link](" Exit << userpage() ");
return "user";
}
/**
*
* @return
*/
@RequestMapping(value = { "/login" })
public String login()
{
return "login";
}
/**
*
* @return
*/
@RequestMapping(value = "/403", method = [Link])
public String Error403()
{
return "403";
}
}
As shown in this controller, we have defined a user page, a login page and an error page (403). A
user with role of either USER or ADMIN or both can access a user page which shows that logged
in user’s profile.
Every user irrespective of roles, will be redirected to login page for authentication. If there are any
errors during authentication or authorization, user will be redirected to access denied page (403).
Source code for login page is as below:
<!DOCTYPE html>
<html xmlns="[Link]
xmlns:th="[Link]
<head> <title>Benefits Application</title>
<link rel="stylesheet"
href="[Link]
/> <link rel="stylesheet" type="text/css" th:href="@{/css/[Link]}" />
<script
src="[Link]
pt> <script
src="[Link]
cript></head>
<body>
<div class="container"> <form th:action="@{/login}" method="POST"
class="form-signin">
<h3 class="form-signin-heading" th:text="Welcome"></h3>
<input type="text" id="email" name="username" th:placeholder="Email"
class="form-control" style="width:350px"/>
<input type="password" th:placeholder="Password" id="password"
name="password" class="form-control" style="width:350px"/>
<div align="center" th:if="${[Link]}">
<p style="font-size: 20; color: #FF1C19;">Email or Password invalid, please
verify</p>
</div>
<button class="btn btn-lg btn-primary btn-block" name="Submit" value="Login"
type="Submit" th:text="Login" style="width:350px"></button> </form></div>
</body>
</html>
This login page shows a simple form to input username (email) and password and process that
authentication using spring-security database authentication method.
@RequestMapping(value = "/home", method = [Link])
public String homepage(Model model)
{
[Link](" Enter >> homepage() ");
Authentication auth = [Link]()
.getAuthentication();
String name = [Link]();
User user = [Link](name);
[Link]("name", [Link]());
[Link](" Exit << homepage() ");
return "index";
}
Changes in MainController are about authenticated user and passing that user’s first name to model
to display in html page. UserManager in service layer has been enhanced to return an user based
on username (which is email) . We have also added email to be unique as a constraint in database.
User page for a user with role USER is nothing but a user profile information which he can edit
and update any time.
<html ng-app="benefitApp">
<head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"
/>
<title>Benefit Application</title><script>[Link]('<base href="' +
[Link] + '" />');</script> <link rel="stylesheet"
href="/css/[Link]" /><script
src="[Link]
src="[Link]
[Link]"></script><script
src="[Link]
[Link]"></script><script type="text/javascript"
src="./js/[Link]"></script></head><body ng-controller="UserCtrl">Hello
<p th:text="${name}"></p>
<div>
<ul class="menu">
<li><a th:href="@{'userProfile/' + ${userid}}">Profile</a></li>
</ul>
<div ng-view="ng-view"></div>
</div>
<div class="input-group">
<div class="controls"> <a ng-click="logout()" class="btn btn-
small">Logout</a></div>
</div>
</body>
</html>
Authentication
Now we have the application ready with all the required backend details for adding authentication
part. Remember we are using spring-security for authentication and authorization of an
application.
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import
[Link]
ticationManagerBuilder;
import
[Link];
import
[Link];
import
[Link]
urity;
import
[Link]
onfigurerAdapter;
import [Link];
@Configuration
@ComponentScan("[Link]")
@EnableWebSecurity
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
public static final Logger LOGGER =
[Link]([Link]);
@Autowired
private SimpleAuthenticationSuccessHandler loginSuccess;
@Autowired
private LogoutSuccess logoutSuccess;
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Autowired
private DataSource dataSource;
@Value("${[Link]-query}")
private String usersQuery;
@Value("${[Link]-query}")
private String rolesQuery;
@Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws
Exception
{
[Link](" Enter >> configureGlobal() ");
[Link]()
.usersByUsernameQuery("select email,password_hash,enabled from user
where email=?")
.authoritiesByUsernameQuery("select [Link],[Link] from user u inner
join user_role ur on([Link]=ur.user_id) inner join role r on([Link]=ur.role_id)
where [Link]=?")
.dataSource(dataSource)
.passwordEncoder(bCryptPasswordEncoder);
[Link](" Exit << configureGlobal() ");
}
/**
* Handle Login - Authentication and Redirection
*/
@Override
protected void configure(HttpSecurity http) throws Exception
{
[Link]()
.disable()
.authorizeRequests()
.antMatchers("/home")
.hasAuthority("ADMIN")
.antMatchers("/user")
.hasAnyAuthority("USER", "ADMIN")
.and()
.formLogin()
.loginPage("/login")
.successHandler(loginSuccess)
.permitAll()
.and()
.logout()
.logoutSuccessHandler(logoutSuccess)
.deleteCookies("JSESSIONID")
.invalidateHttpSession(false)
.permitAll()
.and()
.exceptionHandling()
.accessDeniedPage("/403");
/**
* Exclude resources from user-access
*/
@Override
public void configure(WebSecurity web) throws Exception
{
[Link]()
.antMatchers("/resources/**", "/static/**", "/css/**", "/js/**",
"/images/**");
}
}
What’s happening in this code?
When a user with role ADMIN or USER calls either /home or /user pages respectively, the
user will be challenged to login.
Once the user inputs credentials, they are validated against JDBC database authentication
mechanism provided by spring-security.
If user of role USER tries to access ADMIN home page, user will be redirected to 403
page. Redirection strategy is handled by an authentication success handler.
If user clicks LOGOUT button on the page he is on, he will be logged out of application
and redirected back to login page. All the cookies will be deleted. Redirection will be
handled by logout success handler.
Changes in AngularJS User Interface Controller
As shown in [Link] page, once the user with role USER is logged in, he sees url for his profile
information. If user clicks this url, user sees his or her profile information. This page has a
controller called UserCtrl which basically handles the logout on this initial page. User Profile is
shown on [Link] page which has singleusercontroller. This angular js controller
handles updating user profile information or logout. Rest of the code will be updated in github
repository for self-explanation.
Handling CSRF Token
There are two ways Cross-Site Request Forgery token can be handled in Spring application. First
way is by disabling this token generation. This is not a recommended approach as this put your
application to possible CSRF security attacks for hackers. If you are just doing this for demo
purposes, you can disable this in [Link] by calling [Link]().disable().
As spring points out, CSRF Protection should be used for any request that could be processed by
a browser by normal users.
We will be using spring security to handle CSRF token on server side rather than on client side. So
every request that will come to server will be intercepted to add a CSRF token and then verified.
Angular JS verifies the cookie for CSRF token before a user can post any request.
Add a CSRF Filter Class
We will add a filter that will handle setting of CSRF token in a cookie. Angular JS expects a cookie
name to be as XSRF-TOKEN. This class will look like below:
public class CSRFHeaderFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain) throws
ServletException, IOException {
CsrfToken csrf = (CsrfToken)
[Link]([Link]());
if (csrf != null) {
Cookie cookie = [Link](request, "XSRF-TOKEN");
String token = [Link]();
if (cookie == null || token != null &&
)) {
cookie = new Cookie("XSRF-TOKEN", token);
[Link]("/");
[Link](cookie);
}
}
[Link](request, response);
}
Now we will enable csrf token in SecurityConfig as shown below
.and()
.csrf()
.csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterAfter(new CSRFHeaderFilter(), [Link]);
What is csrfTokenRepository?
We tell spring-security to expect CSRF token in the format that Angular wants to send it back, a
header called X-XSRF-TOKEN instead of default X-CSRF-TOKEN. With these changes, we
don’t have to do anything on client side.
private CsrfTokenRepository csrfTokenRepository()
{
HttpSessionCsrfTokenRepository repository = new
HttpSessionCsrfTokenRepository();
[Link]("X-XSRF-TOKEN");
return repository;
}
Demo
In this post, we showed how to use spring security for authentication and authorization. Now we
will show how to run the application. Once the application is built and run from eclipse, access the
page [Link] , we will see below screen:
It will be the same screen if you access [Link] Now if we enter credentials of
an admin user, we will see below screen:
User screen will be as below:
If you click logout, it will log the user out and show login screen again. In this way, we showed
how we can use spring security for authentication and authorization.
10. Deploying Spring Boot application using a docker
What is docker
Docker is a container platform delivered by a company named “Docker Inc.” Docker can be used
by developers, operators and enterprise users to deliver and use packaged software. Docker has
something called a container. Container can be a virtual machine (VM) in lay man’s terms, but
still little different from VM. Container contains packaged software delivered in a way that it can
be run isolated on a shared operating system. As per official definition – Unlike VMs, container
does not bundle a full operating system – only libraries and settings required to make the software
work are needed.
In this demo, we will use our spring boot application built throughout from Part I to Part VIII.
I am using Windows Platform Toolbox for docker to build my docker containers.
We will build a container with mysql database deployed and another container where we will
deploy spring boot application. This spring boot application container will connect to mysql
database container at runtime. The process is little complicated, but once you get your hands on
docker container, it becomes very straight forward to understand. Also for this post, I will not
explain anything about spring boot application. You should review all the previous posts I have
written explaining how to build and deploy spring boot application on an embedded tomcat.
Building a docker container with mysql
Few things to remember
1. Make sure your spring boot application is working with mysql database before you build a
container.
2. If your application contains user administration and password, make sure you have a super
administrator whose password you can insert in database with password_hash. This is
specifically true for the application we will be deploying in docker container.
For most standard applications (like mysql, java 8, spring-boot), there are number of images
available in docker hub. When we will run our docker container for database, docker shell will
pull the version of that application from the hub to build a container. We will not be creating any
new or blank docker image. To run a docker container with mysql version 5.6, we will use below
command.
docker run --name benefitsmysql -e MYSQL_ALLOW_EMPTY_PASSWORD=yes -e MYSQL_DATABASE=benefitsmysql -p
3308:3306 -d mysql:5.6
Name of our docker container is benefitsmysql.
We are not using any password. This is not recommended for production code, I am just
doing this for demo purposes.
Database name is benefitsmysql.
Also this database is running at port 3308 to 3306 of local host machine.
-d to tell Docker to daemonize the container and keep it running.
mysql:5.6 to download MySQL 5.6 Server image from Docker public repo
Once this is started, there are couple of ways you can verify if we are able to connect to this
database or not.
Get the ip address of this container host with command docker-machine ip . Now in mysql
administrator workbench, access the mysql server with ip address and port 3308 and see if you can
access the database.
Another way on docker shell terminal – use this command docker exec -it benefitsmysql -l , this
will connect you as a root to the shell where mysql is installed. And then you can use mysql as
regular command to access mysql.
To run our Spring boot application successfully, once you access mysql, create following tables:
use benefitsmysql;
create table companyprofile (id int not null auto_increment, establisheddate
date, status varchar(50),corporationtype varchar(50), primary key(id));
create table company(id int not null auto_increment, name varchar(255),
statusid int, type varchar(255), ein varchar(50), companyprofileid int,
primary key(id), foreign key(companyprofileid) references company(id));
create table userprofile(id int not null auto_increment, dob date, doh date,
maritalstatus varchar(50),sex varchar(50),ssn varchar(50),weight varchar(50),
height varchar(50),employmentstatus varchar(50), terminationdate date,
primary key(id));
create table user(id int not null auto_increment, createdate date, email
varchar(255),firstname varchar(255), middlename varchar(255), lastname
varchar(255),username varchar(100),jobtitle varchar(255),password_hash
text,enabled tinyint(4), userprofileid int, primary key(id), foreign
key(userprofileid) references userprofile(id));
create table role(id int not null auto_increment, role varchar(255), primary
key(id));
create table user_role(user_id int not null, role_id int not null, primary
key(user_id, role_id));
Building a docker image for Spring Boot Application along with mysql
To dockerize my spring boot application, we will use a maven plugin to build a docker image.
<plugin>
<groupId>[Link]</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>1.0.0</version>
<configuration>
<imageName>${[Link]}/benefits</imageName>
<dockerHost>[Link]
<dockerCertPath>C:\Users\Yogesh
Mali\.docker\machine\machines\default</dockerCertPath>
<dockerDirectory>src/main/docker</dockerDirectory>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${[Link]}</directory>
<include>${[Link]}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
I am passing dockerDirectory where Dockerfile will be stored to build our image. Also another
change I have made to my original pom file, is that i have added packaging as jar.
<groupId>[Link]</groupId>
<artifactId>Benefits</artifactId>
<packaging>jar</packaging>
<version>0.0.1-SNAPSHOT</version>
.................
<plugin>
<groupId>[Link]</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>[Link]</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
I have also changed in my [Link] to point to mysql database container by updating
database url with ipaddress of docker container.
[Link]=jdbc:mysql://[Link]:3308/benefitsmysql
My Dockerfile to build a docker image is as below:
FROM java:8
VOLUME /tmp
ADD [Link] [Link]
EXPOSE 8443
RUN bash -c 'touch /[Link]'
ENTRYPOINT ["java","-[Link]=file:/dev/./urandom","-jar","/[Link]"]
Basically this will build a [Link] using java 8 and will expose port 8443 that I can use to
access my application.
Now build a new docker container image by using maven goal as
mvn clean package docker:build
To run the application
docker run -p 8443:8443 --name benefits --link benefitsmysql:mysql -d containerid
This will execute the jar built within that container. Important to note here is --link as it links other
container where we have mysql server deployed. So we are linking two containers and we will call
the database from our spring boot application container. The same command can be used little
differently to see the detail execution log as below
docker run -p 8443:8443 --name benefits --link benefitsmysql:mysql -it containerid
Executing the application
Once the application starts successfully, we will access our application with
url [Link] , this will look like below:
Another note – Make sure to update ip addess in all angular js references.
In this post, we showed how we can deploy Spring boot application connected to mysql on a docker
container.
[Link]
1. [Link]
2. [Link]
refused-accessing-a-spring-boot-application-running-in-
docker-contai
3. [Link]
4. [Link]
application/
5. [Link]
and-spring-security-part-ii
6. [Link]
7. [Link]
8. [Link]
-vs-monolithic-architecture
9. [Link]
[Link]
10. [Link]
web-service-producer-consumer-example-with-tomcat
11. [Link]
ng-a-web-service-in-java-and-soapui