Introduction
In this tutorial, you will create an application that can be used as a web-based caller ID. Your application will make requests to the Nexmo Number 一世nsight API and display the results.
Feel free to refer to the nexmo-community/java-caller-id repository as you follow along.
git clone --branch getting-started git@github.com:nexmo-community/java-caller-id.git
Prerequisites
To work through this tutorial, you will need a Nexmo account. Sign up now if you don't already have an account.
在注册过程中,将为您分配API密钥和密码。 在本教程的后续步骤中,您将需要这些。
You will be using Gradle to manage your dependencies and run your application. Additionally, you'll need to make sure you have a copy of the JDK installed.
Building a Caller ID with Java
本教程将指导您完成以下步骤:
- Using Gradle to setup a new Java project.
- Using the Spark framework to serve the caller ID page as well as processing number lookup requests.
- Creating a front end which can be used to collect phone numbers to look up.
Using Gradle to Setup a New Java Project
您将使用Gradle来管理依赖关系以及创建和运行Java应用程序。
的gradle init --type = java应用程序命令将创建您将需要的所有文件夹以及用于编写代码的示例类。
在命令行中,使用以下命令创建一个新的Java项目:
mkdir java-caller-id
cd java-caller-id
gradle init --type=java-application
Using the Spark Framework
您将使用Spark框架通过API来服务调用方ID页以及进程号查找请求。
Adding the Dependencies
将以下内容添加到依存关系封锁你的build.gradle文件:
// Spark Framework
compile 'com.sparkjava:spark-core:2.7.2'
// Nexmo Java Client
compile 'com.nexmo:client:3.10.0'
// DotEnv
compile 'io.github.cdimascio:java-dotenv:3.1.1'
Creating the API Route
摇篮创建一个应用程式上课src /主/ java包含getGreeting和主要方法。 删除getGreeting方法,因为我们不需要它。
Defining the Environment
您无需将Nexmo API密钥和密码进行硬编码,而是将其存储在环境变量中。
For the purpose of this demo you will be using the Dotenv library and a .env
file.
创建一个资源文件夹中src / main并创建一个名为.env具有以下信息:
NEXMO_API_KEY=your-api-key
NEXMO_API_SECRET=your-api-secret
更换您的API密钥和您的api秘密 with your Nexmo API key和secret respectively.
Defining the Route
将事物存储为常量可能会有所帮助。 您将实例化一个新的NexmoClient用你的NEXMO API_KEY和NEXMO_API_SECRET较早定义。
此外,您将定义一些常量,这些常量将在Spark路由和对象编写器它将用于从您的API构建JSON响应。
在中定义以下常量和变量应用程式:
// Environment
private static final String KEY = Dotenv.load().get("NEXMO_API_KEY");
private static final String SECRET = Dotenv.load().get("NEXMO_API_SECRET");
private final InsightClient insightClient = new NexmoClient(new TokenAuthMethod(KEY, SECRET)).getInsightClient();
private final ObjectWriter writer = new ObjectMapper().writer();
Next, you will create a new method which will return a spark.Route
. This route will accept a ñUMBER_PARAM
in the URL, perform a ñexmo Number Insight API request, and return a JSON response containing the AdvancedInsightResponse
information.
在以下方法中创建以下方法应用程式以下主要方法:
/**
* @return A {@link Route} which will handle looking up the number insight information.
*/
private Route createRequestRoute() {
return (request, response) -> {
final String number = request.params(NUMBER_PARAM);
final AdvancedInsightResponse advancedInsightResponse = insightClient.getAdvancedNumberInsight(number,
"",
"",
true
);
response.type(ContentType.APPLICATION_JSON.getMimeType());
return this.writer.writeValueAsString(advancedInsightResponse);
};
}
Register the Route
您需要配置Spark,以便它知道何时使用刚定义的路由。
首先,您将配置运行Spark的端口,然后,配置新创建的路由将响应的路径(/ api /:编号)。
您定义的路径将使用:数参数,它将代表路线内的电话号码。
将以下常量添加到应用程式在您创建的所有其他常量附近:
private static final int PORT = 3000;
private static final String NUMBER_PARAM = ":number";
private static final String REQUEST_ROUTE = "api/" + NUMBER_PARAM;
将以下方法添加到应用程式以上createRequestRoute方法:
/**
* Start the Sparkframework Application
*/
private void start() {
Spark.port(PORT);
Spark.get(REQUEST_ROUTE, createRequestRoute());
}
现在,您将更改主要方法中应用程式为了在应用程序运行时启动Spark。
改变主要方法中应用程式到以下内容:
public static void main(String[] args) {
new App().start();
}
使用启动您的应用程序Gradle运行命令。
You can now navigate to http://localhost:3000/api/13034997111 and should see a response similar to the following:
{
"status": 0,
"ported": "ASSUMED_NOT_PORTED",
"roaming": {
"status": "NOT_ROAMING",
"roaming_country_code": null,
"roaming_network_code": null,
"roaming_network_name": null
},
"status_message": "Success",
"error_text": null,
"request_id": "bf845c39-d0e7-4004-bd68-b8bbadb3b5a6",
"international_format_number": "13034997111",
"national_format_number": "(303) 499-7111",
"country_code": "US",
"country_code_iso3": "USA",
"country_name": "United States of America",
"country_prefix": "1",
"request_price": "0.04000000",
"remaining_balance": "39.02969834",
"original_carrier": {
"name": "United States of America Landline",
"country": "US",
"network_code": "US-FIXED",
"network_type": "LANDLINE"
},
"current_carrier": {
"name": "United States of America Landline",
"country": "US",
"network_code": "US-FIXED",
"network_type": "LANDLINE"
},
"caller_name": "Us Time & Frequency Division",
"first_name": null,
"last_name": null,
"caller_type": "BUSINESS",
"valid_number": "VALID",
"reachable": "UNKNOWN",
"lookup_outcome": 1,
"lookup_outcome_message": "Partial success - some fields populated"
}
Storing Static Content
您将需要一个文件夹来保存您的静态内容。 此文件夹应放在资源目录下src / main您之前创建的。 一个好的约定是命名文件夹上市还要放一个的CSS和js夹。
添加一个index.html归档到上市具有以下内容的文件夹:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Caller ID</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
Serving Static Content
静态内容是从特定文件夹中提供的。 您将创建一个常量来表示此文件夹的位置。
在以下定义常量应用程式:
private static final String STATIC_FILE_LOCATION = "/public";
现在,您将需要更新Spark,以便它知道可以从该位置提供静态内容。
更新开始方法中应用程式到以下内容:
/**
* Start the Spark Framework Application
*/
private void start() {
Spark.staticFileLocation(STATIC_FILE_LOCATION);
Spark.port(PORT);
Spark.get(REQUEST_ROUTE, createRequestRoute());
}
跑过Gradle运行命令。
This will start your application and start serving your index.html
file at http://localhost:3000. Navigating to this address in your browser will display the Hello World text in the index.html
page you previously made.
Building a User Interface
Now that you have Java and Spark performing requests to ñexmo Number Insight API and serving static content, it's time to move on to building a user interface.
Example User Interface
The following is one approach to a user interface. It uses JavaScript to make AJAX calls to the API you built in an earlier step. It then renders the information on the page. It also uses the cleave.js JavaScript library to format the phone number on input.
The result will produce the following page:
Create the Index Page
更换您的index.html具有以下内容:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1,user-scalable=no">
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.2.0/css/all.css"
integrity="sha384-hWVjflwFxL6sNzntih27bfxkr27PmbbK/iSvJ+a4+0owXq79v+lsFkW54bOGbiDQ" crossorigin="anonymous">
<title>Nexmo Caller ID</title>
</head>
<body>
<div class="nav">
<div class="inner-nav">
<h1>Nexmo Caller ID</h1>
</div>
</div>
<div class="page">
<div class="search">
<div class="inner-search">
<h1>Enter a phone number</h1>
<div class="search-bar">
<div class="search-bar-input">
<form>
<input type="text" class="phone-input" id="phone-number" placeholder="+1 123 456 7890"
autofocus>
<button class="form-button" id="look-up"><i class="fas fa-search"></i></button>
</form>
</div>
</div>
<p>Searches are performed against the Nexmo Number Insight API</p>
</div>
</div>
<div class="details" hidden></div>
</div>
<div class="footer">
<div class="inner-footer">
<ul>
<li><a href="https://nexmo.com">Nexmo</a></li>
<li><a href="https://developer.nexmo.com/number-insight/overview">Documentation</a></li>
</ul>
</div>
</div>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/cleave.js/1.4.2/cleave.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/cleave.js/1.4.2/addons/cleave-phone.i18n.js"></script>
<script src="js/app.js"></script>
</html>
Style the Index Page
创建style.css在里面src / main / resources / public / css具有以下内容的文件夹:
body, html {
height: 100%;
margin: 0;
padding: 0;
font-family: Lato, sans-serif;
background-color: #deedf7;
font-weight: 200;
}
form {
display: flex;
}
h1, h2, h3, h4 {
font-weight: 100;
margin: .25em;
}
.inner-nav h1 {
font-weight: 300;
font-size: 3em;
}
.nav {
background-color: #0077c8;
color: #eef6fb;
}
.inner-nav {
display: flex;
width: 100%;
max-width: 970px;
margin: auto;
justify-content: center;
}
.search {
background: #0077c8;
display: flex;
text-align: center;
width: 100%;
flex-flow: column;
}
.details {
background: #ffffff;
display: flex;
text-align: center;
width: 100%;
flex-flow: row;
justify-content: center;
flex-wrap: wrap;
}
.inner-details {
text-align: left;
border: 1px solid #deedf7;
border-radius: 4px;
margin: 0.25em;
padding: 0.25em;
}
.inner-details h1 {
border-bottom: 1px solid #deedf7;
}
.output-table {
text-align: left;
}
.output-table .side-heading {
font-weight: normal;
text-align: left;
}
.output-table td {
padding: 5px;
}
.inner-search {
width: 100%;
max-width: 970px;
margin: auto;
padding: 0 5px;
color: #eef6fb;
}
.inner-search h1 {
font-weight: 100;
}
.inner-search p {
color: #fcfcfd;
font-weight: 100;
}
.search-bar {
position: relative;
width: 100%;
margin: auto;
z-index: 50;
max-width: 300px;
}
.search-bar-input {
position: relative;
z-index: 51;
background: #ffffff;
display: flex;
text-align: center;
height: 50px;
border-radius: 5px;
}
.search-bar-input input {
border: 0;
background-color: transparent;
display: block;
width: 100%;
font-size: 1.5em;
padding: .5em 1em;
font-weight: 100;
}
.search-bar-input input:focus, .search-bar-input button:focus {
outline: none;
}
.search-bar-input button {
background-color: transparent;
border: 0;
cursor: pointer;
font-size: 1.5em;
color: #0077c8;
}
.inner-footer ul {
display: flex;
flex-wrap: wrap;
justify-content: center;
list-style: none;
}
.inner-footer ul a {
padding: 1em;
font-size: 1em;
text-decoration: none;
display: flex;
color: #717171;
}
Create the JavaScript
创建app.js在里面src / main / resources / public / js具有以下内容的文件夹:
let cleave = new Cleave('.phone-input', {
phone: true,
phoneRegionCode: 'US'
});
let lookUpButton = document.getElementById("look-up");
lookUpButton.onclick = function (event) {
event.preventDefault();
let phoneNumber = document.getElementById("phone-number").value.replace(/[^0-9.]/g, "");
handlePhoneNumberLookup(phoneNumber);
};
function handlePhoneNumberLookup(phoneNumber) {
fetch("/api/" + phoneNumber)
.then(response => {
if (response.ok) {
return Promise.resolve(response);
}
return Promise.reject("Error Fetching Number Information");
})
.then(response => response.json())
.then(data => {
renderResponse(data);
})
.catch(function (error) {
console.log("Error: " + error)
})
}
function renderResponse(data) {
let detailsContainer = document.getElementsByClassName("details")[0];
detailsContainer.removeAttribute("hidden");
detailsContainer.innerHTML = '';
console.log(data);
if (data.international_format_number && data.national_format_number) {
detailsContainer.innerHTML += `
<div class="inner-details">
<h1>Number Details</h1>
<table class="output-table">
<tr>
<td class="side-heading">International Format</td>
<td>${data.international_format_number}</td>
</tr>
<tr>
<td class="side-heading">National Format</td>
<td>${data.national_format_number}</td>
</tr>
</table>
</div>`;
}
if (data.caller_type && data.country_name) {
detailsContainer.innerHTML += `
<div class="inner-details">
<h1>Caller Details</h1>
<table class="pure-table pure-table-bordered output-table">
<tr>
<td class="side-heading">Name</td>
<td>${data.caller_name || 'Unknown'}</td>
</tr>
<tr>
<td class="side-heading">Type</td>
<td>${data.caller_type}</td>
</tr>
<tr>
<td class="side-heading">Country</td>
<td>${data.country_name}</td>
</tr>
</table></div>`
}
if (data.roaming && data.roaming.roaming_network_name && data.roaming.roaming_country_code) {
detailsContainer.innerHTML += `
<div class="inner-details">
<h1>Roaming Details</h1>
<table class="output-table">
<tr>
<td class="side-heading">Network Name</td>
<td>${data.roaming.roaming_network_name}</td>
</tr>
<tr>
<td class="side-heading">Country Code</td>
<td>${data.roaming.roaming_country_code}</td>
</tr>
</table></div>
`
}
if (data.ported && data.original_carrier && data.current_carrier) {
detailsContainer.innerHTML += `
<div class="inner-details">
<h1>Porting Information</h1>
<table class="output-table">
<tr>
<td class="side-heading">Status
</td>
<td>${data.ported}</td>
</tr>
</table>
<h2>Current Carrier</h2>
<table class="output-table">
<tr>
<td class="side-heading">Name</td>
<td>${data.current_carrier.name}</td>
</tr>
<tr>
<td class="side-heading">Country</td>
<td>${data.current_carrier.country}</td>
</tr>
</table>
<h2>Original Carrier</h2>
<table class="output-table">
<tr>
<td class="side-heading">Name</td>
<td>${data.original_carrier.name}</td>
</tr>
<tr>
<td class="side-heading">Country</td>
<td>${data.original_carrier.country}</td>
</tr>
</table></div>
`
}
}
Test Your Final Application
Start your application with the gradle run
command inside of your java-caller-id
directory. Navigate to http://localhost:3000 and you will be ready to gain insight.
Conclusion
The Nexmo Number Insight API is a powerful tool for gaining useful information on numbers. It uses a vast amount of real-time data from carrier databases and Nexmo databases to give you the most accurate set of information.
Explore other ways that you might use the Nexmo Number Insight API. Think about what other services you can integrate it with.
Check out our documentation on Nexmo Developer where you can learn more about the Nexmo Number Insight API and other Nexmo offerings. See our Nexmo Quickstart Examples for Java for full code examples on this tutorial and more.