I try to do file upload from a JavaScript client to a JAX-RS Java server.
I use the following REST upload function on my server:
@POST
@Produces(\'ap
Here is what we did to upload file (images in our case) :
Server side
@POST
@RolesAllowed("USER")
@Path("/upload")
@Consumes("multipart/form-data")
public Response uploadFile(MultipartFormDataInput input) throws IOException
{
File local;
final String UPLOADED_FILE_PATH = filesRoot; // Check applicationContext-Server.properties file
//Get API input data
Map> uploadForm = input.getFormDataMap();
//The file name
String fileName;
String pathFileName = "";
//Get file data to save
List inputParts = uploadForm.get("attachment");
try
{
for (InputPart inputPart : inputParts)
{
//Use this header for extra processing if required
MultivaluedMap header = inputPart.getHeaders();
fileName = getFileName(header);
String tmp = new SimpleDateFormat("yyyyMMddhhmmss").format(new Date());
pathFileName = "images/upload/" + tmp + '_' + fileName + ".png";
fileName = UPLOADED_FILE_PATH + pathFileName;
// convert the uploaded file to input stream
InputStream inputStream = inputPart.getBody(InputStream.class, null);
byte[] bytes = IOUtils.toByteArray(inputStream);
// constructs upload file path
writeFile(bytes, fileName);
// NOTE : The Target picture boundary is 800x600. Should be specified somewhere else ?
BufferedImage scaledP = getScaledPicture(fileName, 800, 600, RenderingHints.VALUE_INTERPOLATION_BILINEAR, false);
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(scaledP, "png", os);
local = new File(fileName);
ImageIO.write(scaledP, "png", local);
}
}
catch (Exception e)
{
e.printStackTrace();
return Response.serverError().build();
}
return Response.status(201).entity(pathFileName).build();
}
For the client side, we use AngularJS which is coded by another team. I won't be able to explain about it, but here is the code :
$scope.setPicture = function (element)
{
var t = new Date();
console.log(t + ' - ' + t.getMilliseconds());
// Only process image files.
if (!element[0].type.match('image.*'))
{
console.log('File is not an image');
Error.current.element = $document[0].getElementById('comet-project-upload');
Error.current.message = 'Please select a picture.';
$scope.$apply();
}
else if (element[0].size > 10 * 1024 * 1024)
{
console.log('File is too big');
Error.current.element = $document[0].getElementById('comet-project-upload');
Error.current.message = 'File is too big. Please select another file.';
$scope.$apply();
}
else
{
self.animSpinner = true;
var fd = new FormData();
//Take the first file
fd.append('attachment', element[0]);
//Note : attachment is the compulsory name ?
Project.uploadImage(fd).then(
function (data)
{
self.animSpinner = false;
// self.$apply not needed because $digest already in progress
self.projectPicture = data;
},
function ()
{
self.animSpinner = false;
Error.current.element = $document[0].getElementById('comet-project-upload');
Error.current.message = 'Error with the server when uploading the image';
console.error('Picture Upload failed! ' + status + ' ' + headers + ' ' + config);
}
);
}
};
And the uploadImage function :
this.uploadImage = function (imageData)
{
var deferred = $q.defer();
$http.post('/comet/api/image/upload', imageData,
{
headers: { 'Content-Type': undefined, Authorization: User.hash },
//This method will allow us to change how the data is sent up to the server
// for which we'll need to encapsulate the model data in 'FormData'
transformRequest: angular.identity
//The cool part is the undefined content-type and the transformRequest: angular.identity
// that give at the $http the ability to choose the right "content-type" and manage
// the boundary needed when handling multipart data.
})
.success(function (data/*, status, headers, config*/)
{
deferred.resolve(data);
})
.error(function (data, status, headers, config)
{
console.error('Picture Upload failed! ' + status + ' ' + headers + ' ' + config);
deferred.reject();
});
return deferred.promise;
};
Hope it will help you ...