How any times do developers need an endpoint to handle file uploads?  For example the user needs to upload a CSV file to make a batch insert or update.

Searching in places like StackOverflow,  it is common to find that there is no stantard way to handle file uploads with JAX-RS and that implementations like Jersey or Apache CXF have some extensions to do it. That makes a project to have a dependency on an specific framework beyond the standard JavaEE/ JakartaEE / MicroProfile API’s.

A solution to this problem is to create a servlet to handle the file upload, however doing so has some disadvantages. For example developers can not use automatically interceptors or filters for JAX-RS services or make use of some MicroProfile functionalities like OpenAPI to document the API automatically.

JAX-RS internally works with a servlet that is configured automatically where developers can use that servlet to handle the file uploads in a JAX-RS way.

To do so,  developers need to configure the servlet to support Multipart as a valid Content-Type in their Webservices:

That Application might look like:


package com.example;

import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationScoped
@ApplicationPath("/api")
public class MicroProfileApplication extends Application {

}

 

Lets add the  webapp/WEB-INF/web.xml file with this content:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <servlet>
        <servlet-name>com.example.MicroProfileApplication</servlet-name>
        <multipart-config>
            <max-file-size>35000000</max-file-size> <!--in bytes-->
            <max-request-size>218018841</max-request-size> <!--in bytes-->
            <file-size-threshold>0</file-size-threshold> <!--in bytes-->
        </multipart-config>
    </servlet>
    <servlet-mapping>
        <servlet-name>com.example.MicroProfileApplication</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>
</web-app>

 

Once the project is configured, developers can start writing Webservices like:

@POST
@Path("/upload")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public String uploadTest(@Context HttpServletRequest request){
    try{
        Part file = request.getPart("file"); //file is the name of the parameter on the request.
        InputStream fileContent = file.getInputStream();
        //do something with the file.

        return "Ok";
    }
    catch (IOException | ServletException ex){
        //Do some exception management
        return "error";
    }
}    


 

For example you can read the contents of a text file like this:

@POST
@Path("/upload")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public String uploadTest(@Context HttpServletRequest request){
    try{
        Part file = request.getPart("file"); //file is the name of the parameter on the request.
        InputStream fileContent = file.getInputStream();
        
        BufferedReader reader = new BufferedReader(new InputStreamReader(fileContent, StandardCharsets.UTF_8.name()));
        StringBuilder value = new StringBuilder();

        char[] buffer = new char[1024];
        for (int length; (length = reader.read(buffer)) > 0; )
        {
            value.append(buffer, 0, length);
        }
        return value.toString();
    }
    catch (IOException | ServletException ex){
        //Do some exception management
        return "error";
    }
}    

Now, developers can consume our Webservice in this way: Or from any client using the Content-Type: multipart/form-data

Jorge Cajas

Author Jorge Cajas

More posts by Jorge Cajas

Leave a Reply