Академический Документы
Профессиональный Документы
Культура Документы
This work is licensed under the Creative Commons AttributionNonCommercial-ShareAlike 4.0 International License. To view
a copy of this license, visit
http://creativecommons.org/licenses/by-nc-sa/4.0/
Table of Contents
4. Network communication and services
1. Introduction....................................................................................................................3
1.1. Introduction to sockets...........................................................................................3
1.2. Client-server communication.................................................................................3
1.3. Socket types...........................................................................................................4
2. Basic usage of Java sockets.........................................................................................5
2.1. Using TCP sockets.................................................................................................5
2.2. Using UDP sockets................................................................................................9
2.3. More about the InetAddress class.......................................................................12
2.4. Connecting multiple clients. Sockets and threads...............................................12
3. Some special connections...........................................................................................15
3.1. Multicast sockets..................................................................................................15
3.2. Object serialization...............................................................................................16
4. FTP and SMTP client...................................................................................................20
4.1 FTP Client.............................................................................................................20
4.2 SMTP Client..........................................................................................................23
5. HTTP(S) and Web Services........................................................................................25
5.1 Opening and reading a HTTP connection.............................................................25
5.2 Basic Web Service access....................................................................................28
5.3 JSON processing..................................................................................................28
5.4 Accessing web services from a different thread...................................................31
5.5 GET, POST, PUT, DELETE...................................................................................33
5.6 Emulating an AJAX call.........................................................................................44
5.7 Maintaining session with cookies..........................................................................44
5.7 Sending files..........................................................................................................46
1. Introduction
In this unit we are going to focus on how applications communicate through a network
(either a local network or the Internet). We will read about some low-level communication
techniques and some other high-level services.
First, we are going to see how to communicate two Java applications through a network by
using sockets. We will see what a socket is, what types of sockets we can use and how to
use them.
Then, we will explain some higher level network services, such as e-mail, ftp access or
web services, and how to deal with them in Java.
In addition to this, we will explain some secure programming techniques, in order to
authenticate in a remote server, or encrypt the information that we send through the
network.
One side is set as a server, this is, it keeps listening to a given port number, waiting
for the other side to send requests
The other side is set as a client. It must know the server address, and the port
number to connect to, and then it can send requests to it.
When a client connects to a server, they establish a socket communication, from which the
client sends requests to the server, and the server sends the appropriate responses to the
client. For instance, in a web application, we must know the server address (typically its
domain name), and its port number (the default port number is 80 for web connections, if
we do not specify any). Then, we connect to the server, and we can ask it to send us web
pages, documents and other resources.
Service and Process Programming Network communication and services
We have said before that both sides need to have a port number associated to the
connection. The port number of the server must be known (for instance, port 80 for web
communications, or port 21 for FTP access), but the client port number is randomly
assigned, so that the server will be able to send its responses to the client.
For instance, if we try to create a connection to a web server hosted in
www.myserver.com, we will set port 80 as our destination port. Then, the server will
accept our connection, and automatically a random port number (for instance,
9241), will be assigned to our client. From then on, both client and server can send
messages to each other
Actually, when the connection between client and server is established, the original server
port is released to listen for more connections, and another socket is used to communicate
with the client. So the client will use the original server port to connect to it, and another
(random) port to send data to the server (although client does not need to know this last
port when it connects to the server).
UDP sockets, which are non-connection-oriented. Connections are not reliable, and
so, there might be some pieces of messages that do not get to its destination. We
will use this type of connection when the speed is more important than the integrity
of the data.
For instance, a live video streaming application uses UDP, because the speed to
send and receive the video is more important than losing some frames.
ServerSocket class, that will be used to implement a socket in the server side, that
will be listening to client connection requests.
Socket class, that will hold the communication between both sides. We will use a
Socket object in each side.
)
{
)
{
2.1.1. Example
Let's implement our first, complete example. Whenever we create a client-server
application, we normally create two separate projects: one for the server and another one
for the client, so that we can distribute both sides of the application separately. In this
case, we are going to create a client that says "Hello" to server, and a server that, when
receives this message, sends an answer with "Goodbye" to the client.
In the client side, our code should look like this:
public class Greet_Client
{
public static void main(String[] args)
{
try (
Socket mySocket = new Socket("localhost", 2000);
DataInputStream socketIn =
new DataInputStream(mySocket.getInputStream());
DataOutputStream socketOut =
new DataOutputStream(mySocket.getOutputStream());
)
{
socketOut.writeUTF("Hello");
String response = socketIn.readUTF();
System.out.println("Received: " + response);
} catch (IOException e) {
System.out.println(e);
}
)
{
DataInputStream socketIn =
new DataInputStream(service.getInputStream());
DataOutputStream socketOut =
new DataOutputStream(service.getOutputStream());
// Read the message from the client
String message = socketIn.readUTF();
// Print the message
System.out.println("Received: " + message);
// Answer goodbye to the client
socketOut.writeUTF("Goodbye");
} catch (IOException e) {
System.out.println(e);
}
If we want to run this example (or any other client-server application), we must start by
running the server, and when it's waiting for connections, then we run the client. The
output should be the text "Received: Hello" in the server console, and the text "Received:
Goodbye" in the client console.
If the communication between client and server is not synchronous (i.e., the client
can send messages to the server at any time and/or there are multiple clients
communicating with server at any time), we will need to open the connections
(socket, input and/or output streams) inside the try clause (not inside the try-withresource clause), and close them in a finally clause. We will see an example of this
when using threads to deal with multiple connections (section 2.4).
try (ServerSocket server = new ServerSocket(2000))
{
service = ...
socketIn = ...
socketOut = ...
...
} catch (IOException e) {
System.out.println(e);
} finally {
try {
if (socketOut != null)
socketOut.close();
} catch (IOException ex) {}
try {
if (socketIn != null)
socketIn.close();
} catch (IOException ex) {}
try {
if (service != null)
service.close();
} catch (IOException ex) {}
Also, if we have a graphical application, and we use the sockets or streams from
different events, we will not be able to use the try-with-resource clause, and we will
need to use several try clauses to use the socket, or the streams, or close them, in
different parts of our application. We will see this in exercise 5.
int getLocalPort()
int getPort()
readByte()
readChar()
readDouble()
readFloat()
readUTF()
writeBytes(String)
writeChars(String)
writeDouble(double)
writeFloat(float)
writeUTF(String)
print(String message)
println(String message)
readLine()
Exercise 1
Create an "echo" client-server application using Java sockets, by creating these two
separate projects (one for the client and another one for the server):
Create a project for the server side called Echo_Server. Define a server that will be
listening to port 6000, and when he gets a connection, it will constantly read a
message from the client, and send the same message back to it, converted into
uppercase. For instance, if it receives the message "Hello", it will return "HELLO" to
the client.
Create a project for the client side called Echo_Client. Define a socket that will
connect to the server (use "localhost" as server name, if you are running both
projects in the same machine). When the connection is set, the client constantly ask
the user to enter a message, and then it will send it to the server, waiting for the
corresponding echo.
The communication process will finish when the server receives the message "bye".
3. We can also specify a timeout in the socket (in milliseconds), so that if the receive
method waits for more than the specified timeout to get a response, then an
InterruptedIOException is thrown and we can go on.
socket.setSoTimeout(2000); // 2 seconds
try
{
socket.receive(packetR);
} catch (InterruptedIOException e) {
4. When we finish the communication, we must close the socket established. We can
also put the socket in the try clause so that it will auto close when the clause
finishes.
2.2.1. Example
We are going to implement the same example shown in subsection 2.1.1, but in this case
we will use UDP protocol.
The client side would be like this:
public class GreetUDP_Client
{
public static void main(String[] args)
{
try (DatagramSocket mySocket = new DatagramSocket())
{
// Create the packet to be sent
String text = "Hello";
byte[] message = text.getBytes();
DatagramPacket packetS = new DatagramPacket(message, message.length,
InetAddress.getLocalHost(), 2000);
mySocket.send(packetS);
// Receive the response
byte[] buffer = new byte[1024];
DatagramPacket packetR = new DatagramPacket(buffer, buffer.length);
mySocket.receive(packetR);
System.out.println("Received: " +
new String(packetR.getData()).trim());
} catch (IOException e) {
System.out.println(e);
}
}
10
Local IP and port number (added automatically when creating the datagram)
Note that, when we create a datagram packet to be sent, we convert the message (String)
into a byte array, with the getBytes() method. And when we want to receive a message, we
use the getData() method to get the bytes of the message, and then we create a String
with that array and trim it to clean the edges.
Besides, note that, when the server receives the packet from the client, it can retrieve the
client host name and port number with the methods getPort() and getAddress(), since this
information is included in the datagram automatically.
Exercise 2
Create a UDP client-server application with the following projects:
A project called UDPDictionary_Client that will send to the server a word typed by
the user.
Try to set a timeout in the client (for instance, 5 seconds), by using the
setSoTimeout method from the socket. If this timeout expires, an
InterruptedIOException will be thrown, and the client must print a message on
the screen with the text "No translation found".
A project called UDPDictionary_Server that will run on port 6000. It will have a
collection (hash table or something similar) with some words in English (keys) and
their corresponding Spanish translation (values). The server will read the word sent
by the client, and it will return the Spanish translation of that word. If the word can't
be found in the collection, the server will not return anything.
11
This method makes a connection to the local DNS server to look up the name and its
corresponding IP address. We can also use this method to do a reverse lookup, this is, get
the hostname from the IP address:
InetAddress address = InetAddress.getByName("201.114.121.65");
In both cases, we can check both the hostname and the IP address stored in the
InetAddress object by calling the methods getHostName() and getHostAddress(),
respectively.
In the thread, we usually implement all the communication with the client (the input and
output streams handling that we did in the server class before):
public class ServerThread extends Thread
{
Socket service;
public ServerThread(Socket s)
{
service = s;
}
@Override
public void run()
12
{
DataInputStream socketIn = null;
DataOutputStream socketOut = null;
try
{
socketIn = new DataInputStream(service.getInputStream());
socketOut = new DataOutputStream(service.getOutputStream());
// Communication with client
} catch (IOException e) {
System.out.println(e);
} finally {
try {
if (socketOut != null)
socketOut.close();
} catch (IOException ex) {}
try {
if (socketIn != null)
socketIn.close();
} catch (IOException ex) {}
try {
if (service != null)
service.close();
} catch (IOException ex) {}
}
Note that, in this case, we can't use the try clause to define the socket and input streams
inside (i.e. use the try-with-resource clause), because the Socket object is created in the
server main object, and passed to the thread, so it would be closed by the server before
the thread could use it. So, we can use a finally clause to close the socket and the input
and output streams from the thread.
If we work with UDP servers, we do not need to use any thread, since every datagram
sent or received has no relationship with the others, and we do not need to establish a
different connection with each client. We only need to define a loop where the server
receives datagrams, gets the remote IP and port number, and sends a response to it.
while (true)
{
byte[] sent = new byte[1024];
byte[] received = new byte[1024];
DatagramPacket datagramReceived = new DatagramPacket(received,
received.length);
mySocket.receive(datagramReceived);
...
InetAddress remoteIP = datagramReceived.getAddress();
int remotePort = datagramReceived.getPort();
DatagramPacket datagramSent = new DatagramPacket (sent,
sent.length, remoteIP, remotePort);
}
mySocket.send(datagramSent);
13
Exercise 3
Improve exercise 1 with these two changes:
Make the client-server connection independent from the machines where they are
placed. This is, you must not use "localhost" as the server address. Instead of this,
let the user specify the server address.
Allow more than one client connecting to the server. Then, the server will have to
echo the messages from different clients, sending each one its answers.
14
As you can see, multicast process relies on UDP protocol, so data transfers are not
reliable (it would be inefficient to wait for all the clients in the group to confirm each
reception).
Also keep in mind that, in some cases, you will not need any server side. For instance, if
we implement some kind of simple chat, where every client connects and sends messages
to everyone in the group, the server would not be necessary, since we would only need to
send our messages and receive everything that is sent to the group.
Exercise 4
Create a multicast application with the following projects:
15
Exercise 5
Create a multicast application that implements a chat.
in
project
called
At the beginning, it will ask the user to introduce his nickname at the top of the
window, and then it will try to connect to server. Once it connects to the server, the
user will be able to send messages with the lower text field. It will receive the
messages sent by everyone and will print them in the main text area. As soon as
the window client is closed, the connection must be closed as well.
To receive messages from the group periodically, you will need to implement any of
the thread-safe methods of communicating with a JavaFX application seen in Unit 3
(section 5). For instance, you can implement a Service that periodically receives
messages from the group and prints them in the text area.
In this case, we will not need any server side, since every client will send messages
to the group and receive messages from it.
16
Then, we add this project as a library of both projects (client and server), from the
Properties panel of each project: we right-click on the project name, select Properties
option and then click on Libraries option on the left list. Finally, we click on the Add
Project... button and select the project where the serializable classes are placed.
In the same way, we can create an ObjectInputStream in a socket, and read objects from
it:
ObjectInputStream objIn = new ObjectInputStream(socket.getInputStream());
MyObject obj = objIn.readObject();
Exercise 6
Create a serialization application with the following projects:
We are going to work with user data. So, create a new project (class library). Call it
UserData_Model, and define a User class inside, with the following attributes: the
user login and password (Strings), and the registration date, and the appropriate
constructors, getters and setters. The constructor must leave the login and
17
password empty (""), and the registration date will be automatically filled with
current date.
A server project called UserData_Server. When a client connects, the server will
create a new User (from User class explained before). Then, it will send that User
object to the client, and wait for a response.
The client project will be called UserData_Client. It will connect to the server,
receive the User object, and then it will ask the user to fill its login and password.
Once this data is completed, the client will send the User object back to the server.
When the server receives the complete User object, it will print its information in the
console.
Exercise 7
In this exercise we are going to simulate a simplified version of an auction. To do this, we
will store the information of the product that we want to sell in a Product class (remember
to create a separate project (class library) to handle this class). The attributes that we want
to store are the product name, buyer's name and the product price. Initially, the server will
create a Product with its product name and an initial auction price (buyer's name will be
initially empty). Then, the server will wait for 3 different clients to connect, and it will send
the product to them. Each client will see the product information in the console, and then
they will type their name and the amount that he wants to pay for the product, in one line,
separated by a whitespace. For instance:
nacho 150
The server will pick up the responses from all the clients, and it will take the maximum
amount from them. Then, it will update product information with the current price and
18
buyer's name, and will send the updated product to the clients, to make them know who
won the auction.
Here you can see an example of how it should work...
1. Initially, the server creates a product, with a name and initial price. For instance,
"Xbox One", 100 euros.
2. Then, it will wait for 3 clients to connect
3. Next, it will send the whole Product object to each client. So they will see this
information on their consoles:
Product name: Xbox One
Product initial price: 100 euros
4. Then, each client will be asked to introduce his name and offer, in the same format
explained before. For instance, we might have these three offers from the 3 different
clients:
nacho 150
arturo 170
ana 120
5. The server will receive these 3 messages, compare them and pick up the one with
the highest offer. Then, it will update the product data with the buyer's name and
price, and send the information back to the clients. So, the clients would see this
information as the final result:
Final price: 170 euros
Buyer's name: arturo
Call the projects Auction_Model (class library to store the Product class),
Auction_Server and Auction_Client. You can also add any additional class or method
that you may need (for instance, to manage clients connected to server)
19
4.1.1 Connection
The most simple way to connect to an existing FTP server through FTP protocol (you can
connect to an FTP server through HTTP protocol also) is opening a connection like this:
FTPClient ftp = new FTPClient();
try {
ftp.setControlEncoding("UTF-8"); // Important (before connect)
ftp.connect("172.16.208.128");
System.out.print(ftp.getReplyString());
ftp.enterLocalPassiveMode(); // If the server is in another network
if(!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
ftp.disconnect();
System.err.println("Error connecting to FTP");
}
} catch (IOException e) {
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioe) {}
}
}
As you can see, we open a connection specifying the server IP or domain name (localhost
if it's running on the same machine). Then we print the response from the server and
check the reply code (indicating an error or success) using the class FTPReply to know if
the connection was successful or not.
IMPORTANT: The FTP server can close a connection if it has been inactive for a period of
time, so it's not guaranteed the connection will still be open anytime.
20
21
listNames() Gets (only the names) the list of files inside the current directory.
Exercise 8
Create a JavaFX (by code or FXML) application called FTPManager. It will be a simple
FTP client, which you'll use to connect to a server (can be localhost or a virtual machine
IP), list its contents on a ListView and do several actions. The application aspect should be
more or less like this:
As you can see, once you enter a server address, a login name and password, and click
the Connect button, the application will list the working directory contents. The other
buttons will perform the following actions:
Upload: Will open a FileChooser dialog to select a file that will be uploaded to the
FTP server (current directory).
Dowload/Enter: Only active when something in the list is selected. Two situations
can happen.
If the selected item is a directory, the application will change to that directory
listing its files.
If it's a normal file, the application will open a DirectoryChooser dialog to select a
local directory and download the file there.
Go up: Will change to the parent directory and list its contents.
22
Delete: Only active when something in the list is selected. Will delete the file.
There will be a label where you'll show every action's result, whether it's a success or an
failure. When it's needed, refresh the list's contents.
Now, we'll need to download jaxa.mail and activation JAR libraries to include in our project
library path.
Javax.mail JAR download.
Java Activation Framework download.
static
static
static
static
String
String
String
String
23
props.put("mail.smtp.user", senderEmail);
props.put("mail.smtp.host", emailSMTPserver);
props.put("mail.smtp.port", emailServerPort);
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.socketFactory.port", emailServerPort);
props.put("mail.smtp.socketFactory.class",
"javax.net.ssl.SSLSocketFactory");
props.put("mail.smtp.connectiontimeout", "5000"); // Timeout
try {
Authenticator auth = new Authenticator() {
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(
senderEmail, senderPassword);
}
};
//Open connection
Session session = Session.getInstance(props, auth);
Message msg = new MimeMessage(session);
msg.setText("Sample message");
msg.setSubject("Sample subject");
msg.setFrom(new InternetAddress(senderEmail));
msg.addRecipient(Message.RecipientType.TO,
new InternetAddress("arturo@iessanvicente.com"));
msg.addRecipients(Message.RecipientType.CC, new Address[] {
new InternetAddress("noexiste@iessanvicente.com"),
new InternetAddress("noexiste2@iessanvicente.com")
});
Transport.send(msg);
System.out.println("sent successfully");
} catch (Exception ex) {
System.err.println("Error occurred while sending.!");
}
}
Exercise 9
Create a JavaFX application called
MailSenderFX that will send an email.
This application will connect to a Gmail
account and send an email to any other
account, The account can be one that you
have
created
or
the
following:
2dam.iessanvicente@gmail.com
Pass: iessanvicente
The application will inform the user if
everything went well or there was any
error.
24
To get the response body (content), the connection provides an InputStream for that
purpose. It's also recommended to retrieve the charset encoding from the response
headers, in order to read everything (like accents) properly.
// Get charset encoding (UTF-8, ISO,...)
public static String getCharset(String contentType) {
for (String param : contentType.replace(" ", "").split(";")) {
if (param.startsWith("charset=")) {
return param.split("=", 2)[1];
}
}
}
25
It doesn't always work. For example, this connection returns code 301 (Moved
Permanently) and doesn't redirect to the new location automatically.
You can check what the response (and its headers) is by using available methods:
System.out.println(conn.getResponseCode());
System.out.println(conn.getResponseMessage());
System.out.println(conn.getHeaderFields());
With this information, we could manage manually these redirections (with the risk of falling
into a redirection loop), even if there are many, like this:
URL url = new URL("http://iessanvicente.com");
HttpURLConnection conn;
do {
conn = (HttpURLConnection)url.openConnection();
if(conn.getResponseCode() == 301) {
url = new URL(conn.getHeaderField("Location"));
}
} while(conn.getResponseCode() == 301);
26
Exercise 10
Create a console Java application named LinkSearch that will ask you for an address and
print all the links (<a>) detected in the response. If you want, it's a good idea to create an
auxiliary class that extends from BufferedReader as we saw on uni t 1, to only filter those
links from the output.
This is part of the output that https://iessanvicente.com should show:
27
And this is how we can call it from Java and obtain the result:
28
information we can use the org.json API (also present in Android) or other options like
Google's GSON, but there are a lot of options.
Let's see an example. Imagine that we receive this information from a web web service in
JSON format:
{
"error":false,
"person": {
"name":"Peter",
"age":30,
"address":[
{"city":"London","street":"Some street 24"},
{"city":"New York","street":"Other street 12"}
]
}
29
}
@Override
public String toString() {
String str = "Name -> " + name + "\nage -> " + age +
"\nAddress ->";
for(Address a: address)
str += "\n\t" + a.toString();
}
return str;
Finally, we need to connect to the web service, get its response and process the string
containing the resulting JSON code (GetServiceResponse is a custom class for connect
to a web service and return its response):
public static void main(String[] args) {
GetServiceResponse resp = new
GetServiceResponse("http://localhost/services/example1.php");
30
If the field names are correctly names , it will map everything automatically:
public static void main(String[] args) {
GetServiceResponse resp =
new GetServiceResponse("http://localhost/services/example1.php");
String json = resp.getResponse();
if(json != null) {
Gson gson = new Gson();
GetPersonResponse personResp =
gson.fromJson(resp.getResponse(), GetPersonResponse.class);
if(!personResp.getError()) {
System.out.println(personResp.getPerson().toString());
} else {
System.out.println("There was an error in the request");
}
}
}
If a class property's name doesn't match the JSON field name, we can tell the GSON
parser that it has to assign that field by using an annotation with that property:
@SerializedName("error")
boolean haserror; // In JSON it will be named "error"
GSON tutorial
31
}
}
};
In the application's controller, when we click Add button, we'll create and start the
service, and update the corresponding label when its finished:
public class FXWebServiceController implements Initializable {
@FXML
@FXML
@FXML
@FXML
private
private
private
private
Label resultLabel;
TextField num1;
TextField num2;
Button addButton;
32
resultLabel.setVisible(false);
gss.setOnSucceeded(e -> {
resultLabel.setText("Result: " + gss.getValue());
addButton.setDisable(false);
imgLoad.setVisible(false);
resultLabel.setVisible(true);
});
@Override
public void initialize(URL url, ResourceBundle rb) {
}
}
This is how it will look like when processing the request (the wheel is a
downloaded animated gif):
GET: Retrieves data and usually won't modify anything. It's equivalent to SELECT
in SQL. When using this method, the data will usually be sent in the URL.
POST: Operation intended to insert new data (it doesn't have to) and store it in the
server. It's usually equivalent to INSERT in SQL.
PUT: Operation that updates existing data in the server. Similar to UPDATE in SQL.
DELETE: Operation that deletes existing data in the server (like DELETE in SQL).
As said before, the most common used methods are GET (data in the URL and limited in
length) and POST (data sent in the body of the request, can be much larger), but that
depends on how the web services are configured. If the server is prepared to accept those
Service and Process Programming Network communication and services
33
4 methods for operations, for example, with /product resource to operate with products
stored in the database, some frameworks like AngularJS in Javascript offer a really
simplified way to make these operations.
Let's see how to interact with web services that support these operations in Java:
To interact with the database and create web services, we'll use the Phalcon framework in
PHP, which is a complete and powerful framework, and the fastest in PHP because it's
compiled from C language and loaded as a library (binary). Other frameworks are written
in PHP directly, which is much slower than compiled code. You should be able to download
everything (java, php and sql) from Aula Virtual to try this application.
34
}
} catch (IOException e) {
} finally {
if (bufInput != null) {
try {
bufInput.close();
35
} catch (IOException e) { }
}
return result.toString();
}
5.5.3 GET
GET operations are intended to retrieve existing objects from the database (SELECT). In
this case, there are 2 web services:
A service using the resource /category that gets all categories in the database:
A service using the resource /product that receives a category id and returns all
products that are part of that category (Notice that when we receive a List of
objects, we need com.google.gson.reflect.TypeToken and java.lang.reflect.Type
classes if we intend to use GSON library):
And this is the service that will get the products from a category:
36
To end this GET example, we'll see how we request products when a new category is
selected in the application:
Exercise 11
Create a project named GetCompanies in JavaFX. It will use these two web services
using GET:
[
{
"id": "1",
"cif": "C2314234Y",
"name": "Crazy Stuff Inc.",
"address": "Madness Street 15"
},
{
"id": "2",
37
"cif": "T1342536Y",
"name": "Silly & Dumb LTD",
"address": "Idont Know Street, 1324"
},
...
]
{
"ok": true,
"error": "",
"company": {
"id": "3",
"cif": "V3241569E",
"name": "Maniacs International",
"address": "Happy Stress Street, 99",
"employees": [
{
"id": "5",
"nif": "46374869U",
"name": "Cocaine Rupert",
"age": "37",
"idCompany": "3"
},
{
"id": "6",
"nif": "12425364K",
"name": "Happysad Windows",
"age": "47",
"idCompany": "3"
}
]
}
}
First, it will load all companies on the top list from the adequate web service. Then, when a
user selects a company, it will retrieve its information and employees from the other web
service, showing them in the bottom list. This application will look more or less like this:
38
5.5.4 POST
Using POST, data is sent in the body of the request. This is done by using the output
stream of the connection to send that data. The format can be URL
(key=value&key2=value2) or like in this case, JSON (in String format).
This is the web service that will process the information and insert a new product. It just
returns (prints) an integer indicating the id of the newly created product (or -1 if there was
an error). It could return a JSON object with more information if we wanted to:
And this is the service in Java that will call this web service and return its response:
Finally, this is the code in the view's controller to start this service and process its result:
39
Exercise 12
Update the project GetCompanies from exercise 11 and insert an Add button for adding
employees. This button (only active when a company is selected) will open a new window
containing a form to add a new employee.
To create new window using another FXML (or building the scene by code), you can do it
like this:
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
Parent root = FXMLLoader.load(getClass().getResource("AddEmployee.fxml"));
Scene scene = new Scene(root);
stage.setTitle("Add employee");
stage.setScene(scene);
stage.show();
stage.setOnHidden((e) -> {
// Update the employees list somehow...
});
40
To cancel and close the window opened (at least using FXML):
Stage window = (Stage) ((Node) event.getSource()).getScene().getWindow();
window.close();
This web service will return the id of the new employee if everything was correct, or -1 if
something failed. It will also return an error message:
{
"id": "12",
"error": ""
}
5.5.5 PUT
This HTTP method is a mix between GET and POST, and it's usually equivalent to the
UPDATE instruction in SQL. The information to get the object (id for example) that will be
modified from the database is sent in the URL (like GET), and the data to modify from that
object is sent in the body (like POST).
This is the web service that will process the information and update an existing. It just
returns true or false indicating if the operation was successful or not. It could return a
JSON object with more information (like error messages) if we wanted to:
41
And finally, this is how we create and start the Service from the controller:
5.5.6 DELETE
The DELETE operation works like GET (variables in URL), but instead of returning objects
that meet some conditions, it deletes them. First, we'll see the web service used:
42
This is the JavaFX Service that will connect to this web service:
And finally, how we create and start the service from the controller:
Exercise 13
Update the GetCompanies project from exercises 11 and 12. You'll have to add two more
buttons:
Update: Only active when an employee is selected. It will open a window with a
form (similar to Add) to edit an employee's information. It will connect to whi web
service and send information by PUT method:
http://<IP address>/exercises/employee/{idEmployee}
The information sent in JSON will have the same format that when you add an
employee (see exercise 3), and the response will be a JSON object with two
fields ok (boolean) and error (String).
Delete: Will open a dialog to ask the user if he/she wants to delete the selected
employee (see ProductManager example application from unit 2, or the updated
example in this unit). If positive answer is given it will call this web service (using
DELETE method):
43
http://<IP address>/exercises/employee/{idEmployee}
The response will be a JSON object with the same format as before (update).
44
server will store information indicating that the login was successful in a session and will
answer the client returning a cookie with the session id. That's what the client has to send
to the server automatically whenever it starts a connection, so the server can check if a
login has been previously successful and which user is logged in (among any other
information that wants to store in the session).
Imagine that we have these 2 web services:
The first one will store the name of the user in a session variable called user, and will
print that name. When we call the second service, it checks if that session variable exists
and prints its value or No if it doesn't exist (session usually expires in a few minutes if the
client doesn't connect to the server meanwhile). If we don't store the session id
(automatically generated by the server and sent with headers as a cookie) in the client, we
won't sent it in the second request and the server will create a new session meaning that it
will be empty and that variable won't exist. This is the default behaviour:
45
Important!: The directories where we are going to store files in the server must have write
permissions for everybody as Apache uses its own user in the system.
As you can see, it will receive the file data encoded inside data field, and at least the file
name it had in the client inside the name field. It will decode the file's data and store it in
the server where the web service is located, inside public/img subdirectory.
We're going to use the class ServiceUtils that we created before to make things easier.
First, let's take a look at the class used to represent a file object that will be serialized into
JSON by the Gson library:
As you can notice. We store file's data inside a String, because that's what the Base64
encoder will generate when using its method encodeToString(), and it's the most
Service and Process Programming Network communication and services
46
appropriate format to include in the JSON body. We also store file's name and the
directory where it was located (absolute path).
Finally. Let's take a look at an example of how to send the image to the web service in the
main method:
Curiosities:
If you don't use a framework like Phalcon. The recommended way in PHP to get the JSON
sent (instead of a URL formatted string as usual with GET and POST), is like this:
json_decode(file_get_contents("php://input"));
If we want to send the image inside an URL formatted string (var1=value1&var2=value..)
instead of using JSON, we'll have to use Java's urlEncoder:
An then in PHP, we'll use this to convert from url base64 to normal base64:
$base64=strtr($base64urlData, '-_', '+/');
$decoded = base64_decode($base64);
Exercise 14
Create a JavaFX project called PhotoUploader
that will upload a photo with a title and a
description to a web service using POST:
http://<IP address>/photoplaces/photo
Use the AJAX call header or you won't get the
desired result this time. The JSON response
object will contain: ok boolean, and error
String.
This is the JSON format you'll have to send:
{
"name": "IMG_20130831_174624.jpg",
"title": "Lovaly place",
"desc": "place description",
data: base 64 encoded data.
}
47