Acceptance testing with Cucumber and Selenium(Java)

In this post, I am going to show how we can write the acceptance test script with Cucumber and Selenium.

Refer my earlier post for Ruby/Cucumber Acceptance testing with Cucumber and Capybara

My objective is to write an acceptance test which opens up the browser and goes to ‘Yelp’ site and search for a restaurant and validate the results.

Refer the below feature file.
java-cucumber-selenium-test/src/test/resources/yelp/test/yelp.feature



Feature: Search Restaurants

  Scenario: Go to yelp and search for valid restaurant
    Given a user goes to Yelp
    When Search for taco bell
    Then See the List of taco bell Restaurants and confirm results contains Lower Greenville

  Scenario: Go to yelp and search for restaurant
    Given a user goes to Yelp
    When Search for Qboba
    Then See the List of Qboba Restaurants

  Scenario: Go to yelp and search for restaurant
    Given a user goes to Yelp
    When Search for Chipotle
    Then See the List of Chipotle Restaurants

  Scenario: Go to yelp and search for invalid restaurant
    Given a user goes to Yelp
    When Search for hhahsdahsdhasd
    Then See No Results found error message

  Scenario Outline:Go to yelp and search for <searchText>
    Given a user goes to Yelp
    When Search for <searchText>
    Then See the List of  Restaurants
    Examples:
      | searchText               |
      | Scardello                |
      | Roti Grill               |
      | Mughlai Restaurant       |
      | Spice In The City Dallas |


Refer the below Junit test file
java-cucumber-selenium-test/src/test/java/yelp/test/YelpTest.java



package yelp.test;

import org.junit.runner.RunWith;
import cucumber.api.junit.Cucumber;

@RunWith(Cucumber.class)
public class YelpTest {
}

Refer the below Step definitions file.

java-cucumber-selenium-test/src/test/java/yelp/test/definitions/YelpStepDefinition.java



package yelp.test.definitions;

import cucumber.api.java.After;
import cucumber.api.java.Before;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.util.concurrent.TimeUnit;

import static org.junit.Assert.assertEquals;

public class YelpStepDefinition {

    protected WebDriver driver;

    @Before
    public void setup() {
        driver = new FirefoxDriver();
        //Loading the driver
        System.setProperty("webdriver.gecko.driver", "/usr/local/bin/geckodriver");
    }

    @Given("^a user goes to Yelp$")
    public void goToYelp() {
        //Get the Yelp home page
        driver.get("https://www.yelp.com/dallas");
    }

    @When("^Search for (.*?)$")
    public void doSearch(String searchTerm) throws InterruptedException {
        WebElement searchDescElement = driver.findElement(By.id("find_desc"));
        searchDescElement.sendKeys(searchTerm);

        WebElement submit = driver.findElement(By.id("header-search-submit"));
        submit.submit();
    }

    @Then("^See the List of (.*?) Restaurants$")
    public void verifyContents(String restaurant) {

        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        assertEquals(true, isContentAvailable(restaurant));
    }

    @Then("^See the List of (.*?) Restaurants and confirm results contains (.*?)$")
    public void verifyContentsWithLandmark(String restaurant, String landMark) {
        //Create an Explicit wait to make sure that the page is loaded and driver updates the page data.
        WebDriverWait myWait = new WebDriverWait(driver, 10);
        myWait.until(ExpectedConditions.visibilityOfElementLocated(By.id("yelp_main_body")));
        assertEquals(true, isContentAvailable(restaurant, landMark));
    }

    public boolean isContentAvailable(String... contents) {
        WebElement searchResultsElement = driver.findElement(By.id("yelp_main_body"));
        boolean result = false;
        for (String content : contents) {
            result = searchResultsElement.getText().contains(content);
        }
        return result;
    }

    @Then("^See No Results found error message")
    public void verifyContents() {
        //Create an Explicit wait to make sure that the page is loaded and driver updates the page data.
        WebDriverWait myWait = new WebDriverWait(driver, 10);
        myWait.until(ExpectedConditions.visibilityOfElementLocated(By.id("yelp_main_body")));
        assertEquals(true, driver.getPageSource().contains("No Results"));
    }

    @After
    public void closeBrowser() {
        driver.quit();
    }
}


Follow the below steps to run the test script

1. Download the repository
2. Download the ‘gecko’ driver from https://github.com/mozilla/geckodriver/releases and copy it into ‘/usr/local/bin/’
3. Do ‘mvn clean install’
4. Maven builds the test class and runs it. We can also run the test case(YelpTest.java) from any IDE as normal Junit test case.

How to use Alex collins docker maven plugin

The “alexec/docker-maven-plugin” is a maven plugin which is used to build, test and publishing the docker images. Refer this link for more information about this plugin(https://github.com/alexec/docker-maven-plugin).

Check out my sample project @ https://github.com/dkbalachandar/java-rest-docker. This is a simple Hello world REST application running on Docker.

In this post, I am going to show how to use “alexec” docker maven plugin with an example. Let’s go into the details one by one.

1. The first step is to add the com.alexecollins.docker plugin in the build section of the pom.xml. Check below snippet.

java-rest-docker/pom.xml:


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com</groupId>
    <artifactId>hello-rest</artifactId>
    <version>1.0</version>
    <properties>
       <docker.image.name>hello-rest</docker.image.name>
    </properties>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>com.Grizzly</mainClass>
                        </manifest>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib/</classpathPrefix>
                            <mainClass>com.Grizzly</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
            <!-- Add the Alex Collins plugin-->
            <plugin>
                <groupId>com.alexecollins.docker</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>2.11.21</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>clean</goal>
                            <goal>package</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.glassfish.grizzly</groupId>
            <artifactId>grizzly-http-server</artifactId>
            <version>2.3.22</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.grizzly</groupId>
            <artifactId>grizzly-http-servlet</artifactId>
            <version>2.3.24</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-jetty-servlet</artifactId>
            <version>2.5</version>
        </dependency>
    </dependencies>
</project>

2. Next step is to create a folder named ‘docker’ under src/main. Then go into ‘docker’ folder and create an another folder named ‘helloRest’. You can give name any name you want.

3. Next step is to create a conf.yml and give all the configuration information in it. Refer the below snippet.

java-rest-docker/src/main/docker/helloRest/conf.yml:


packaging:
  add:
    - target/${project.build.finalName}-jar-with-dependencies.jar
    - src/main/bin
tags:
    - ${project.artifactId}:latest

I am using the project.artifactId as my image name(hello-rest). If your project has any upper case letter then this plugin wont work. Make sure to give lower case letter always.

Assume that, the project artifactId is “hello-Rest” and when you try to build the project, you will get the below error.


[ERROR] Error during callback
com.alexecollins.docker.orchestration.OrchestrationException: com.github.dockerjava.api.exception.InternalServerErrorException: Error parsing reference: "hello-Rest:latest" is not a valid repository/tag

	at com.alexecollins.docker.orchestration.DockerOrchestrator.build(DockerOrchestrator.java:395)
	at com.alexecollins.docker.orchestration.DockerOrchestrator.build(DockerOrchestrator.java:323)
	at com.alexecollins.docker.orchestration.DockerOrchestrator.build(DockerOrchestrator.java:855)
	at com.alexecollins.docker.mojo.PackageMojo.doExecute(PackageMojo.java:16)
	at com.alexecollins.docker.mojo.AbstractDockerMojo.execute(AbstractDockerMojo.java:164)
	at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:101)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:209)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59)
	at org.apache.maven.lifecycle.internal.LifecycleStarter.singleThreadedBuild(LifecycleStarter.java:183)
	at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:161)
	at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:320)
	at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:156)
	at org.apache.maven.cli.MavenCli.execute(MavenCli.java:537)
	at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:196)
	at org.apache.maven.cli.MavenCli.main(MavenCli.java:141)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
	at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
	at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
Caused by: com.github.dockerjava.api.exception.InternalServerErrorException: Error parsing reference: "hello-Rest:latest" is not a valid repository/tag



4. Next step is to create the DockerFile. Check the below snippet which has all the information.

java-rest-docker/src/main/docker/helloRest/Dockerfile



FROM java:8

WORKDIR /opt

ADD hello-rest-${project.version}-jar-with-dependencies.jar /opt/helloRest.jar
ADD bin /opt/bin

RUN chmod +x /opt/helloRest.jar
RUN chmod +x /opt/bin/run.sh

CMD ["/opt/bin/run.sh"]

EXPOSE 8080


5. Run the ‘mvn clean’ command and check the build log and confirm that the image ‘hello-rest’ is built with the configuration information from conf.yml and Dockerfile.
6. Run the ‘docker images’ command to confirm the image availability.
7. Finally, Run the docker image with this command ‘docker run -p 8080:8080 hello-rest’ and test it with this URL http://localhost:8080/api/greeting.

SimpleDateFormat – ISO8601 format

I have done some date format operations in Java and got to know about the Zulu time which is nothing but the UTC time.

Now, I have a date and want to format that into “yyyy-MM-dd’T’HH:mm:ss.SSSZ” format. Here Z stands for zulu timezone.

Refer the below program and the output of those.


import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;


public class Main {

    public static void main(String[] args) {

        //ISO8601 format
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");

        //EST time
        Calendar calendar1 = Calendar.getInstance();
        System.out.println("calendar1::" + calendar1.getTimeZone());
        System.out.println("\n");
        System.out.println("calendar1.getTime()::" + dateFormat.format(calendar1.getTime()));
        System.out.println("\n");
        //PDT time
        Calendar calendar2 = Calendar.getInstance(TimeZone.getTimeZone("America/Los_Angeles"));
        dateFormat.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
        System.out.println("calendar2::" + calendar2.getTimeZone());
        System.out.println("calendar2.getTime()::" + dateFormat.format(calendar2.getTime()));

    }
}


calendar1::sun.util.calendar.ZoneInfo[id="America/New_York",offset=-18000000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/New_York,offset=-18000000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]]


calendar1.getTime()::2017-06-02T17:03:04.643-0400


calendar2::sun.util.calendar.ZoneInfo[id="America/Los_Angeles",offset=-28800000,dstSavings=3600000,useDaylight=true,transitions=185,lastRule=java.util.SimpleTimeZone[id=America/Los_Angeles,offset=-28800000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]]
calendar2.getTime()::2017-06-02T14:03:04.645-0700

calendar1 uses the default timezone and in this case its EST time. So when i am doing the format, the output string is “2017-06-02T16:53:24.122-0400”. Here -0400 represents the time difference between the current timezone(EST) and UTC(Zulu) time.

calendar2 uses the PDT time and also set the same timezone to SimpleDateFormat as well. So the output string is “2017-06-02T13:53:24.124-0700”. Here the -0700 represents the time difference between the PDT timezone and UTC(Zulu) time.

Java 8: Create LinkedHashMap with Collectors.toMap

In this article, I will show you how to create a LinkdHashMap with Collectors.toMap() method.

Assume that you have a LinkedHashMap with the key as a string and the value as an Integer. Now you want to iterate this map and modify the value of each key and then create an another map to hold that value.

Refer the below code to know how to do that.



import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {

    public static void main(String[] args) {

        Map map1 = new LinkedHashMap();

        map1.put("key1", 1);
        map1.put("key2", 2);
        map1.put("key3", 3);

        System.out.println(map1);

        Map map2 = map1.keySet()
                .stream()
                .collect(Collectors.toMap(key -> key,
                        key -> (map1.get(key) + 10),
                        (e1, e2) -> e1,
                        LinkedHashMap::new));

        System.out.println(map2);
    }
}


By default, the Collectors.toMap function creates a HashMap but we can override it by specifying the mapSupplier argument. The corresponding function from Collectors class which should be used in this case.


    public static <T, K, U, M extends Map<K, U>>
    Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
                                Function<? super T, ? extends U> valueMapper,
                                BinaryOperator<U> mergeFunction,
                                Supplier<M> mapSupplier) 

So in my code,I am passing the key, updated value, merge function(consider the first key if there is a duplicate key), finally the LinkedHashMap to the Collectors.toMap() function.

The output will be like this,


 map1{key1=1, key2=2, key3=3}
 map2{key1=11, key2=12, key3=13}

Create Docker image with Maven build

There are lots of maven Docker plugin available to integrate the docker with maven.

In this example, I am going to show how to build the Docker image while building a maven project.

Copy the below snippet and put into your pom.xml file and then create a maven property “docker.image.name” with the appropriate docker image name and also make sure that the Dockerfile available in the correct location.

Then run the ‘mvn install’ and once its done, run ‘docker images’ and check that the docker image is available in the list of images.

pom.xml:


  <plugin>
	<groupId>org.codehaus.mojo</groupId>		
	<artifactId>exec-maven-plugin</artifactId>		
	<version>1.4.0</version>		
	<executions>		
		<execution>		
			<goals>		
				<goal>java</goal>		
			</goals>		
		</execution>		
		<execution>		
			<id>build-image</id>		
			<phase>install</phase>		
			<goals>		
				<goal>exec</goal>		
			</goals>		
			<configuration>		
				<executable>docker</executable>		
				<arguments>		
					<argument>build</argument>		
					<argument>-t=${docker.image.name}</argument>		
					<argument>.</argument>		
				</arguments>		
			</configuration>		
		</execution>		
	</executions>			
 </plugin>		
<plugin>
      

How to use ReflectionUtils to retrieve the field value

In this post, I am going to show how we can use the ReflectionUtils to get the field value from an object.

Most of the time, we use Java Reflection to retrieve the value but if the field is in the Super class, then you have to write some boilerplate code to retrieve those. But if you use ReflectionUtils, then you won’t have to worry about that.

Refer the below example,

BaseProfile and Employee are the two value objects. Here the Employee class extends BaseProfile class which has some common fields. Then in ReflectionUtilsMain, I am using Java reflection and also ReflectionUtils to retrieve the value of “firstName” field

Let’s check the code.

BaseProfile.java


import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;


public class BaseProfile {

    private String firstName;

    private String lastName;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    @Override
    public String toString() {
        return ReflectionToStringBuilder.toString(this);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;

        if (o == null || getClass() != o.getClass()) return false;

        BaseProfile that = (BaseProfile) o;

        return new EqualsBuilder()
                .append(firstName, that.firstName)
                .append(lastName, that.lastName)
                .isEquals();
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder(17, 37)
                .append(firstName)
                .append(lastName)
                .toHashCode();
    }
}

BaseProfile.java


import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;


public class Employee extends BaseProfile {

    private String empId;

    private String designation;

    public String getEmpId() {
        return empId;
    }

    public void setEmpId(String empId) {
        this.empId = empId;
    }

    public String getDesignation() {
        return designation;
    }

    public void setDesignation(String designation) {
        this.designation = designation;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;

        if (o == null || getClass() != o.getClass()) return false;

        Employee employee = (Employee) o;

        return new EqualsBuilder()
                .appendSuper(super.equals(o))
                .append(empId, employee.empId)
                .append(designation, employee.designation)
                .isEquals();
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder(17, 37)
                .appendSuper(super.hashCode())
                .append(empId)
                .append(designation)
                .toHashCode();
    }

    @Override
    public String toString() {
        return ReflectionToStringBuilder.toString(this);
    }
}

Here is our main class
ReflectionUtilsMain.java


import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.lang3.reflect.FieldUtils;

import java.lang.reflect.Field;

public class ReflectionUtilsMain {

    public static void main(String[] args) {

        Employee employee = new Employee();
        employee.setEmpId("1234");
        employee.setFirstName("John");
        employee.setLastName("Turner");
        employee.setDesignation("Manager");
        System.out.println(employee);

        //Now you want to access the First Name from Employee object with Java reflection
        String firstName = null;
        String fieldName = "firstName";
        for (Class aClass = employee.getClass(); aClass != null; aClass = aClass.getSuperclass()) {
            System.out.println("aClass:" + aClass.getSimpleName());
            try {
                Field field = aClass.getDeclaredField(fieldName);
                if (!field.isAccessible()) {
                    System.out.println("Field is found "+field);
                    field.setAccessible(true);
                    firstName = (String) field.get(employee);
                    break;
                }
            } catch (NoSuchFieldException | IllegalAccessException e) {
                System.err.print(ExceptionUtils.getStackTrace(e));
            }
        }
        System.out.println("Using Reflection firstName:" + firstName);
        firstName = null;
        //You can also use ReflectionUtils to get this very easily
        try {
            Field field = FieldUtils.getField(employee.getClass(), fieldName, true);
            firstName = (String) field.get(employee);
        } catch (Exception e) {
            System.err.print(ExceptionUtils.getStackTrace(e));
        }
        System.out.println("Using Reflection Utils firstName:" + firstName);

    }
}

The output will be like this,


java.lang.NoSuchFieldException: firstName
	at java.lang.Class.getDeclaredField(Class.java:2070)
	at org.cas.osd.mp.ReflectionUtilsMain.main(ReflectionUtilsMain.java:29)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
org.cas.osd.mp.Employee@42110406[empId=1234,designation=Manager,firstName=John,lastName=Turner]
aClass:Employee
aClass:BaseProfile
Field is found private java.lang.String org.cas.osd.mp.BaseProfile.firstName
Using Reflection firstName:John
Using Reflection Utils firstName:John

How to get Application HostName and client ip address in Java

Consider the below example,

We have an AngularJs web application and the backend is Java RESTful API.

So the application flow will be like this,
Client ==> AngularJs==> RESTful API

Assume that we have two RESTful services. They are /api/document to retrieve the document details and /api/download to download the document content in a PDF. Assume that we want to generate the download service link in the /api/document service response something like below,

/api/document?docId=1
{
	"docId": "1",
        "data":"",
	"downloadLink": "https://app-dev.com/api/download?type=pdf&docId=1"
}

Here the app-dev.com represents the host name of the application.

So to get the host name, we have to retrieve the ‘x-forward-host’  HTTP header as we can’t depend on the host header as it may be modified by the intermediate proxy server. Refer below the code to retrieve the hostname.


     public String getHost(HttpServletRequest servletRequest) {
          return servletRequest.getHeader("x-forwarded-host");
    }

To get the client IP address, we have to retrieve the ‘x-forwarded-for’ header. The general format of this field is X-Forwarded-For: client, proxy1, proxy2. So if there are any proxy servers in between the client and application, then those proxies IP address are appended to this header. So always use the first IP address available in this header to know the actual client IP address.


     public String getClientIpAddress(HttpServletRequest servletRequest) {
          return servletRequest.getHeader("X-Forwarded-For").split(",")[0];
    }