Java Web Services Binary Data Transfer Example (base64 encoding)
- Details
- Written by Nam Ha Minh
- Last Updated on 21 December 2019   |   Print Email
In this tutorial, we are going to provide an example of a web services-based application that transfers binary data (e.g. content of an arbitrary file) using base64 encoding/decoding approach. The web services library to be used is JAX-WS (Java API for XML Web Services) which is a built-in technology in Java EE family and is also available in Java SE 6 or later.
1. Understand how to transfer binary data via web services
In the approach employed by this article, the binary data is embedded directly in the SOAP envelop using base64 text encoding. In other words, the raw binary data is converted to an encoded String which is value of an XML element in the SOAP message. Upon receiving the SOAP message, the receiver decodes the encoded String in order to re-construct the original binary data.
The following picture depicts this process:
This approach is the simplest way and is only suitable for transferring a small amount of binary data. It becomes very inefficient when transferring a large amount of binary data because the base64 text encoding technique bloats the data by a factor of 1.33x (UTF-8 text encoding) or 2.66x (UTF-16 text encoding) of the original size. Also, the encoding/decoding process slows down the application performance.
This approach is also often referred as “by value” or “inline attachment” method. Now, let’s go through an example application that is used to transfer small binary files.
NOTE: To optimize the binary data transfer, read: Using MTOM to optimize binary data transfer with JAX-WS web services.
2. Code the Web Service Endpoint Interface
Let’s define an endpoint interface as follows:
package net.codejava.ws.binary.server; import javax.jws.WebMethod; import javax.jws.WebService; /** * A web service endpoint interface. * @author www.codejava.net * */ @WebService public interface FileTransferer { @WebMethod public void upload(String fileName, byte[] imageBytes); @WebMethod public byte[] download(String fileName); }
This endpoint defines two web methods, upload() and download() which allows the client to upload/download a file by sending/receiving a chunk of bytes.
3. Code the Web Service Endpoint Implementation
Write an implementation for the FileTransferer interface as follows:
package net.codejava.ws.binary.server; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import javax.jws.WebMethod; import javax.jws.WebService; import javax.xml.ws.WebServiceException; /** * A web service implementation of an endpoint interface. * @author www.codejava.net * */ @WebService public class FileTransfererImpl implements FileTransferer { @WebMethod public void upload(String fileName, byte[] imageBytes) { String filePath = "e:/Test/Server/Upload/" + fileName; try { FileOutputStream fos = new FileOutputStream(filePath); BufferedOutputStream outputStream = new BufferedOutputStream(fos); outputStream.write(imageBytes); outputStream.close(); System.out.println("Received file: " + filePath); } catch (IOException ex) { System.err.println(ex); throw new WebServiceException(ex); } } @WebMethod public byte[] download(String fileName) { String filePath = "e:/Test/Server/Download/" + fileName; System.out.println("Sending file: " + filePath); try { File file = new File(filePath); FileInputStream fis = new FileInputStream(file); BufferedInputStream inputStream = new BufferedInputStream(fis); byte[] fileBytes = new byte[(int) file.length()]; inputStream.read(fileBytes); inputStream.close(); return fileBytes; } catch (IOException ex) { System.err.println(ex); throw new WebServiceException(ex); } } }
As we can see, the upload() method saves the received bytes array to file specified by the given fileName; and the download() method reads the requested file and returns its content as a bytes array.
4. Code the Server Program for Web Services
Let’s create a server program that publishes the above endpoint implementation as follows:
package net.codejava.ws.binary.server; import javax.xml.ws.Endpoint; /** * A simple web service server. * @author www.codejava.net * */ public class WebServiceServer { public static void main(String[] args) { String bindingURI = "http://localhost:9898/codejava/fileService"; FileTransferer service = new FileTransfererImpl(); Endpoint.publish(bindingURI, service); System.out.println("Server started at: " + bindingURI); } }
Now run this program and we should see the following message in the console.
Server started at: http://localhost:9898/codejava/fileService
The server is now waiting for request. Next, we are going to generate the web service client code.
5. Generating Client Code for Web Services
It’s recommended to use the wsimporttool in order to generate web services client code in Java. Execute the following command at the command prompt:
wsimport -keep -p net.codejava.ws.binary.client http://localhost:9898/codejava/fileService?wsdl
The wsimporttool generates necessary client code and puts .java source files under the package net.codejava.ws.binary.client. Here’s the list of generated files:
- Download.java
- DownloadResponse.java
- FileTransfererImpl.java
- FileTransfererImplService.java
- ObjectFactory.java
- package-info.java
- Upload.java
- UploadResponse.java
NOTES: You must ensure that the sever program is running before executing the wsimportcommand.
6. Coding the Client Program for Web Services
Based on the generated web services client code, we can write a client program as follows:
package net.codejava.ws.binary.client; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /** * A client program that connects to a web service in order to upload * and download files. * @author www.codejava.net * */ public class WebServiceClient { public static void main(String[] args) { // connects to the web service FileTransfererImplService client = new FileTransfererImplService(); FileTransfererImpl service = client.getFileTransfererImplPort(); String fileName = "binary.png"; String filePath = "e:/Test/Client/Upload/" + fileName; File file = new File(filePath); // uploads a file try { FileInputStream fis = new FileInputStream(file); BufferedInputStream inputStream = new BufferedInputStream(fis); byte[] imageBytes = new byte[(int) file.length()]; inputStream.read(imageBytes); service.upload(file.getName(), imageBytes); inputStream.close(); System.out.println("File uploaded: " + filePath); } catch (IOException ex) { System.err.println(ex); } // downloads another file fileName = "camera.png"; filePath = "E:/Test/Client/Download/" + fileName; byte[] fileBytes = service.download(fileName); try { FileOutputStream fos = new FileOutputStream(filePath); BufferedOutputStream outputStream = new BufferedOutputStream(fos); outputStream.write(fileBytes); outputStream.close(); System.out.println("File downloaded: " + filePath); } catch (IOException ex) { System.err.println(ex); } } }
As we can see, this client program connects to the web service then uploads an image file to the service, and finally downloads another image file from the service.
7. Test binary data transfer with web services
Running the client program we should see the following output:
File uploaded: e:/Test/Client/Upload/binary.png File downloaded: E:/Test/Client/Download/camera.png
And here’s the server’s output:
Received file: e:/Test/Server/Upload/binary.png Sending file: e:/Test/Server/Download/camera.png
Using a monitoring tool such asTCP/IP Monitor in Eclipse IDE, we can spot the SOAP messages delivered along with the request and response as follows:
- Invoking the upload() method:
- Client Request:
GET /codejava/fileService?wsdl HTTP/1.1 User-Agent: Java/1.7.0_17 Host: localhost:9898 Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Connection: keep-alive POST /codejava/fileService HTTP/1.1 Accept: text/xml, multipart/related Content-Type: text/xml; charset=utf-8 SOAPAction: "http://server.binary.ws.codejava.net/FileTransfererImpl/uploadRequest" User-Agent: JAX-WS RI 2.2.4-b01 Host: localhost:9898 Connection: keep-alive Content-Length: 1971 <?xml version="1.0" ?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Body> <ns2:upload xmlns:ns2="http://server.binary.ws.codejava.net/"> <arg0>binary.png</arg0> <arg1>iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAA....</arg1> </ns2:upload> </S:Body> </S:Envelope>
- Server Response (WSDL XML is omitted):
HTTP/1.1 200 OK Transfer-encoding: chunked Content-type: text/xml;charset=utf-8 Date: Fri, 11 Oct 2013 02:48:45 GMT -- WSDL XML (ommitted for saving space).... HTTP/1.1 200 OK Transfer-encoding: chunked Content-type: text/xml; charset=utf-8 Date: Fri, 11 Oct 2013 02:48:45 GMT <?xml version="1.0" ?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Body> <ns2:uploadResponse xmlns:ns2="http://server.binary.ws.codejava.net/"/> </S:Body> </S:Envelope>
- Client Request:
- Invoking the download() method:
- Client Request:
POST /codejava/fileService HTTP/1.1 Accept: text/xml, multipart/related Content-Type: text/xml; charset=utf-8 SOAPAction: "http://server.binary.ws.codejava.net/FileTransfererImpl/downloadRequest" User-Agent: JAX-WS RI 2.2.4-b01 Host: localhost:9898 Connection: keep-alive Content-Length: 218 <?xml version="1.0" ?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Body> <ns2:download xmlns:ns2="http://server.binary.ws.codejava.net/"> <arg0>camera.png</arg0> </ns2:download> </S:Body> </S:Envelope>
- Server Response:
HTTP/1.1 200 OK Transfer-encoding: chunked Content-type: text/xml; charset=utf-8 Date: Fri, 11 Oct 2013 02:48:45 GMT <?xml version="1.0" ?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Body> <ns2:downloadResponse xmlns:ns2="http://server.binary.ws.codejava.net/"> <return>iVBORw0KGgoAAAANSUhEUgAAABAAA...</return> </ns2:downloadResponse> </S:Body> </S:Envelope>
- Client Request:
CONCLUSION: As we mentioned earlier, this binary data transfer approach is only well-suited for working with small binary data because the base64 text encoding mechanism bloats data size greatly and slows down application performance.
Other Java Web Services Tutorial:
- Java Client Server Web Services (JAX-WS) Tutorial
- Java Web Services Tutorial using Apache Axis2, Ant and Tomcat
- Monitoring SOAP Messages using TCP/IP Monitor in Eclipse
- Using MTOM to optimize binary data transfer with JAX-WS web services
- Java CRUD RESTful Web Services Examples with Jersey and Tomcat
- Java RESTful Web Services Tutorial for Beginner with Jersey and Tomcat
- How to code and deploy Java XML Web Services (JAX-WS) on Tomcat
Comments
Only byte transfer...
image in POSTMAN then it will call JSON webservices and that image has to store in new folder that file should be save as .png formate