Spring MVC Framework follows the Model-View-Controller design pattern. It is used to develop web applications. It works around DispatcherServlet. DispatcherServlet handles all the HTTP requests and responses. In this article, we are going to see about a REST API call to find the coordinates for the given latitude and longitude. Each and every area in the globe is identified by means of latitude and longitude. For example, India, Asia/Kolkata timezone can be identified by means of
Latitude -> 21.7679 Longitude -> 78.8718
Corresponding REST API call:
https://api.wheretheiss.at/v1/coordinates/<Latitude,Longitude>
Here in the place of Latitude, we need to substitute the proper Latitude value. In the place of Longitude, we need to substitute the proper Longitude value
Example:
https://api.wheretheiss.at/v1/coordinates/21.7679,78.8718
Output:
REST API call provides JSON response.
Via Spring MVC framework, let us parse the REST API call JSON response and render the necessary elements. It can be done via a maven-driven project. Let us see how to do that.
Step by Step Implementation
Project Structure for bringing the timezone value for a given Latitude and Longitude. Let us cover the required JUNIT test cases also for it.
Let us check the important files of the project
getTimeZone.jsp
HTML
<!DOCTYPE html> < html lang = "en" > < head > < meta charset = "utf-8" > < meta http-equiv = "X-UA-Compatible" content = "IE=edge" > < meta name = "viewport" content = "width=device-width, initial-scale=1" > < title >WTIA</ title > < link rel = "stylesheet" href = "https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" > < style type = "text/css" > .main-form, .profile-area { width: 640px; } .main-form { margin: 50px auto 0px; } .profile-area { margin: 10px auto; } .main-form section, .profile-area section { margin-bottom: 15px; background: #c080c0; box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); } .main-form section { padding: 30px; } .profile-area section { padding: 30px 30px 30px; } .profile-area section > div { text-align: center; } .main-form h3 { margin: 0 0 15px; } .form-control, .btn { min-height: 38px; border-radius: 2px; } .btn { font-size: 20px; font-weight: inherit; font-family: sans-serif; } .hideElement { display: none; } </ style > </ head > < body > < div class = "main-form" id = "main-form" > < section > < h5 class = "text-center" >Enter Latitude</ h5 > < div class = "form-group" > < input id = "latitude" type = "text" class = "form-control" placeholder = "Enter latitude here..." required = "required" > </ div > < h5 class = "text-center" >Enter Longitude</ h5 > < div class = "form-group" > < input id = "longitude" type = "text" class = "form-control" placeholder = "Enter longitude here..." required = "required" > </ div > < div class = "form-group" > < button onclick = "loadData()" class = "btn btn-primary btn-block" >Find TimeZone</ button > </ div > </ section > </ div > < div class = "profile-area hideElement" id = "profile-area" > < section > < div id = "loader" class = "hideElement" > < div class = "spinner-border" role = "status" > < span class = "sr-only" >Loading...</ span > </ div > </ div > < div id = "profile" class = "hideElement" > < br >< br > < p >< strong >TimeZone: < span id = "timezone_id" ></ strong ></ span ></ p > </ div > </ section > </ div > </ body > < script > function loadData() { document.getElementById("profile-area").classList.remove("hideElement"); document.getElementById("loader").classList.remove("hideElement"); document.getElementById("profile").classList.add("hideElement"); var latitude = document.getElementById("latitude").value; var longitude = document.getElementById("longitude").value; if(latitude != "" && latitude != null && longitude != "" && longitude != null) { var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { var jsonResponse = JSON.parse(this.responseText); document.getElementById("timezone_id").innerHTML = jsonResponse.timezone_id; //document.getElementById("age").innerHTML = jsonResponse.age; document.getElementById("loader").classList.add("hideElement"); document.getElementById("profile").classList.remove("hideElement"); } }; xhttp.open("GET", "getSateliteDetailsByLatAndLon?latitude=" + latitude + "&longitude=" + longitude, true); xhttp.send(); console.log("done"); } else { console.log("Enter latitude and lonitude...") } } </ script > </ html > |
Output:
On entering the correct latitude and longitude, we will get the below screens
Example 2:
Let us see the important files required for the project. As it is the maven project, let us start with
pom.xml
XML
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 < modelVersion >4.0.0</ modelVersion > < groupId >com.wtia.WTIA_Rest_API</ groupId > < artifactId >WTIA_Rest_API</ artifactId > < packaging >war</ packaging > < version >0.0.1-SNAPSHOT</ version > < name >profileGenerator</ name > < properties > < failOnMissingWebXml >false</ failOnMissingWebXml > < spring-version >5.1.0.RELEASE</ spring-version > </ properties > < dependencies > < dependency > < groupId >org.springframework</ groupId > < artifactId >spring-webmvc</ artifactId > < version >${spring-version}</ version > </ dependency > < dependency > < groupId >org.springframework</ groupId > < artifactId >spring-test</ artifactId > < version >${spring-version}</ version > </ dependency > <!-- JSTL Dependency --> < dependency > < groupId >javax.servlet.jsp.jstl</ groupId > < artifactId >javax.servlet.jsp.jstl-api</ artifactId > < version >1.2.1</ version > </ dependency > < dependency > < groupId >taglibs</ groupId > < artifactId >standard</ artifactId > < version >1.1.2</ version > </ dependency > <!-- Servlet Dependency --> < dependency > < groupId >javax.servlet</ groupId > < artifactId >javax.servlet-api</ artifactId > < version >3.1.0</ version > < scope >provided</ scope > </ dependency > <!-- JSP Dependency --> < dependency > < groupId >javax.servlet.jsp</ groupId > < artifactId >javax.servlet.jsp-api</ artifactId > < version >2.3.1</ version > < scope >provided</ scope > </ dependency > < dependency > < groupId >com.google.code.gson</ groupId > < artifactId >gson</ artifactId > < version >2.8.6</ version > </ dependency > < dependency > < groupId >commons-io</ groupId > < artifactId >commons-io</ artifactId > < version >2.5</ version > </ dependency > < dependency > < groupId >junit</ groupId > < artifactId >junit</ artifactId > < version >4.12</ version > < scope >test</ scope > </ dependency > </ dependencies > < build > < finalName >Timezone</ finalName > < sourceDirectory >src/main/java</ sourceDirectory > < plugins > < plugin > < artifactId >maven-compiler-plugin</ artifactId > < version >3.5.1</ version > < configuration > < source >1.8</ source > < target >1.8</ target > </ configuration > </ plugin > <!-- This should be added to overcome Could not initialize class org.apache.maven.plugin.war.util.WebappStructureSerializer --> < plugin > < groupId >org.apache.maven.plugins</ groupId > < artifactId >maven-war-plugin</ artifactId > < version >3.3.2</ version > </ plugin > </ plugins > </ build > </ project > |
Java files:
AppConfig.java
Java
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.JstlView; @Configuration @EnableWebMvc @ComponentScan (basePackages = { "com.wtia.WTIA_Rest_API" }) public class AppConfig { @Bean public InternalResourceViewResolver resolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setViewClass(JstlView. class ); resolver.setPrefix( "/" ); resolver.setSuffix( ".jsp" ); return resolver; } } |
SpringMvcDispatcherServletInitializer.java
Java
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class SpringMvcDispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return null ; } @Override protected Class<?>[] getServletConfigClasses() { return new Class[] { AppConfig. class }; } @Override protected String[] getServletMappings() { return new String[] { "/" }; } } |
WtiaController.java
Java
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.google.gson.Gson; import com.google.gson.JsonObject; @Controller public class WtiaController { @RequestMapping ( "/getSateliteDetailsByLatAndLon" ) public @ResponseBody JsonObject getSateliteDetails(String latitude,String longitude ) throws IOException { JsonObject jsonObject = new JsonObject(); String timezoneId = getSateliteData(latitude,longitude); timezoneId = timezoneId.replaceAll( "^\"|\"$" , "" ); jsonObject.addProperty( "timezone_id" , timezoneId); return jsonObject; } private String getSateliteData(String latitude,String longitude) throws IOException { String data = null ; StringBuilder responseData = new StringBuilder(); JsonObject jsonObject = null ; URL url = null ; HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestMethod( "GET" ); con.setRequestProperty( "User-Agent" , "Mozilla/5.0" ); int responseCode = con.getResponseCode(); System.out.println( "\nSending 'GET' request to URL : " + url); System.out.println( "Response Code : " + responseCode); try (BufferedReader in = new BufferedReader( new InputStreamReader(con.getInputStream()))) { String line; while ((line = in.readLine()) != null ) { responseData.append(line); } jsonObject = new Gson().fromJson(responseData.toString(), JsonObject. class ); data = jsonObject.get( "timezone_id" ).toString(); } System.out.println(data); return data; } } |
Flow of the Program:
When “getTimeZone.jsp” is called and the proper latitude and longitude are given, it is sent to the “WtiaController.java” file and the GET request mapping is checked against “getSateliteDetailsByLatAndLon” and from jsp, latitude, and longitude are substituted, it will call the REST API call
https://api.wheretheiss.at/v1/coordinates/<Latitude,Longitude> --Input latitude and longitude are getting substituted here
Then JSON response is parsed and the necessary details like timezone_id or country_code will be displayed. Necessary JUnit test case file
WtiaControllerTest.java
Java
package com.wtia.WTIA_Rest_API.controller; import com.google.gson.Gson; import com.google.gson.JsonObject; import org.junit.Before; import org.junit.Test; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import static org.junit.Assert.assertEquals; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; public class WtiaControllerTest { // It is available in // org.springframework.test.web.servlet.MockMvc private MockMvc mockMvc; @Before public void setup() { this .mockMvc = MockMvcBuilders.standaloneSetup( new WtiaController()).build(); } @Test public void testWTIADetails() throws Exception { // expected String expectedTimezoneId = null ; StringBuilder responseData = new StringBuilder(); JsonObject expectedJsonObject = null ; HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestMethod( "GET" ); con.setRequestProperty( "User-Agent" , "Mozilla/5.0" ); try (BufferedReader in = new BufferedReader( new InputStreamReader(con.getInputStream()))) { String line; while ((line = in.readLine()) != null ) { responseData.append(line); } expectedJsonObject = new Gson().fromJson(responseData.toString(), JsonObject. class ); expectedTimezoneId = expectedJsonObject.get( "timezone_id" ).toString(); expectedTimezoneId = expectedTimezoneId.replaceAll( "^\"|\"$" , "" ); } // actual MvcResult result = mockMvc.perform(get( "/getSateliteDetailsByLatAndLon?latitude=50.11496269845&longitude=118.07900427317" )) .andReturn(); String receivedResponse = result.getResponse().getContentAsString(); JsonObject actualJsonObject = new Gson().fromJson(receivedResponse, JsonObject. class ); String actualTimezoneId = actualJsonObject.get( "timezone_id" ).toString(); actualTimezoneId = actualTimezoneId.replaceAll( "^\"|\"$" , "" ); // checking the expectedtimezone and actualtimezone assertEquals(expectedTimezoneId, actualTimezoneId); } } |
We have to run this file as JUnit test like this.
Output:
Conclusion
REST APIs are awesome. We can get valuable information from them. As it is producing JSON responses, they are lightweight, easily portable, and adaptable to any technology.