I have a little problem when I try to download a file with rest.
Here is my function :
#GET
#Produces(MediaType.APPLICATION_OCTET_STREAM)
#Path("{directory: (([^/]+[/])+)[^/]+}")
public Response getFile(#PathParam("directory") String directory)
{
Response responseFile = null;
try
{
/*String tmpFileName = "REST_FTP_TMPFile_"+ Math.random();
tmpFileName = tmpFileName.replace(".", "");
File tmpFile = new File(tmpFileName);
tmpFile.createNewFile();
//*/
String filename = directory.substring(directory.lastIndexOf("/")+1, directory.length());
File tmpFile = File.createTempFile("REST_FTP_TMPFile_", null);
directory = StringEscapeUtils.unescapeHtml4(directory);
this.client.getFile(directory, tmpFile);
System.out.println("size : " + tmpFile.length());
responseFile = Response.ok(tmpFile, MediaType.APPLICATION_OCTET_STREAM)
.header("Content-length", tmpFile.length())
.header("Content-Disposition","attachment; filename="+filename+"")
.build();
//A voir quand on peut le supprimer...
//tmpFile.delete();
}
catch (IOException ex)
{
Logger.getLogger(GetResource.class.getName()).log(Level.SEVERE, null, ex);
}
return responseFile;
}
The function getFile of client use the libapache method :
public boolean getFile(String pathname, File file) throws IOException
{
OutputStream output;
output = new FileOutputStream(file);
System.out.println("Wanted pathname : "+pathname);
boolean status = this.client.retrieveFile("/"+pathname, output);
if(status)
{
output.close();
return status;
}
else
{
output.close();
throw new IOException("Cannot retrieve the file : " + pathname);
}
}
When I try to download my web browser says that the download is canceled :
I really don't know what I did wrong and nothing on the web helped me out so far (it's been 2 hours..)
I found what the problem was, the FTP transfer is supposed to be in binary mode..
Related
I am able to create the file but not able to download it. I am trying to download the file by an ajax call. I am able to receive the file name and file content and successfully able to write the content in a file in application directory but I'm not able to download that file. My code is given bellow :-
The Ajax Code -:
downloadButton.onclick = function() {
//alert(payLoadID);
$.ajax({
type: "POST",
url: "payloadAjax",
data: { payloadData: document.getElementById("modal_paragraph").innerHTML, id: payLoadID },
success : function(data) {
alert("SUCCESS: " +data);
// modal.style.display = "none";
// $("body").css("overflow","auto");
},
error : function(e) {
alert("ERROR: "+ e);
},
done : function(e) {
alert("DONE");
}
})
}
Here is the java code -:
#RequestMapping(value = "/payloadAjax", method = RequestMethod.POST, produces = MediaType.TEXT_PLAIN_VALUE)//, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public #ResponseBody
void download(#RequestParam("payloadData") String payloadData, #RequestParam("id") String fileName, HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("id : " +fileName);
System.out.println("payloadData : " +payloadData);
/* File creation code is here. */
String FOLDER = "/downloadDir";
String FILE_NAME = fileName +".txt";
String appPath = request.getRealPath("");
System.out.println("appPath = " + appPath);
File downloadDirectory = new File(appPath + FOLDER);
if(!downloadDirectory.exists() || !downloadDirectory.isDirectory()) {
downloadDirectory.mkdir();
System.out.println("Directory Created");
} else {
System.out.println("Directory already exists.");
}
File uploadFile = new File(downloadDirectory, FILE_NAME);
if(uploadFile.exists()) {
uploadFile.delete();
System.out.println(uploadFile.getName() +" Has been deleted.");
}
try {
uploadFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("New File successfully created.");
try
{
PrintWriter writer = new PrintWriter(uploadFile, "UTF-8");
writer.println(payloadData);
writer.flush();
writer.close();
System.out.println("File successfully written.");
}
catch(Exception ex) {
ex.printStackTrace();
}
if (uploadFile.exists()) {
System.out.println("Upload file exists. Ready to download....");
} else {
System.out.println("Sorry File not found!!!!");
}
/*File creation code successfully completed.*/
/*File download code starts here */
/*HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_HTML);
headers.setContentLength(uploadFile.length());
headers.setContentDispositionFormData("attachment", "Soubhab_Pathak.txt");
InputStreamResource isr = new InputStreamResource(new FileInputStream(uploadFile));
return new ResponseEntity<InputStreamResource>(isr, headers, HttpStatus.OK);*/
if(response == null) {
System.out.println("Response is null.");
} else {
System.out.println("Response is not null.");
}
System.out.println("111");
OutputStream out = response.getOutputStream();
System.out.println("112");
FileInputStream in = new FileInputStream(uploadFile);
System.out.println("113");
response.setContentType(MediaType.TEXT_PLAIN_VALUE);
response.setHeader("Content-Disposition", "attachment; filename=" + FILE_NAME);
response.setHeader("Content-Length", uploadFile.length() +"");
FileCopyUtils.copy(in, out);
System.out.println("114");
response.flushBuffer();
System.out.println("115");
/*File download code completes here.*/
}
The log is as follows
Any idea?
Finally I am able to solve the problem. This also an example of how to download a string as file in Spring MVC using ajax. Solution is as follows -:
1) one controller action to receive the string from ajax call and store that string in a file in the application server.
2) another controller action where you need to write file download code and this action will receive a GET request.
3) in the ajax call in the success part just call the second action method to download the file.
Now the code is working fine.
I'm using the following solution to try and receive an image in a restful webservice written in java:
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.TEXT_PLAIN)
public String getFile(#FormDataParam("pic") InputStream file,
#QueryParam("uid") String uid) {
try {
storeFile(file, uid);
} catch (IOException ex) {
Logger.getLogger(UploadImage.class.getName()).log(Level.SEVERE, null, ex);
return "failed";
}
return "success";
}
private void storeFile(InputStream input, String uid) throws IOException {
String absPath = PATH_TO_FILES + uid + ".jpg";
try {
OutputStream out = new FileOutputStream(new File(absPath));
int read = 0;
byte[] bytes = new byte[1024];
out = new FileOutputStream(new File(absPath));
while ((read = input.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Here is the client code (javascript):
$scope.fileSelect = function (files) {
var file = files[0];
console.log("File loaded");
console.log(files);
console.log('uid = ' + $scope.uid + ' user = ' + $scope.user);
var formData = new FormData();
formData.append('pic', file);
var requestBody = {"token": $scope.token};
var req = {
method: 'POST',
url: 'http://192.168.0.9/resources/UploadPicture?uid=' + $scope.uid,
headers: {
'Content-Type': undefined
},
data: formData
};
console.log(FormData);
$http(req).then(function(response){
console.log(response);
}, function(error){
console.log(error);
});
};
This code produces a file that isnt viewable. The files im expecting are images.
So i got 2 questions:
Whenever the webservice gets called an a response is return, it seems like the image isnt fully flushed to the harddisk. After a while i can edit it. Is there a way to respond back to the client when the image is actually flushed to the disk?
How can i get the input stream to produce a viewable image when its written to the disk?
--edit--
After some fiddling with the file, i realized if i edit the image in notepad++ and took off the beggining and ending tags for the form boundaries, the image is viewable again:
Produced File
Is there a way for the form boundaries to stop interfering with the image data?
I found a solution using apache commons fileupload:
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.TEXT_PLAIN)
public String getFile(#Context HttpServletRequest request, #QueryParam("uid") String uid) {
ServletFileUpload upload = new ServletFileUpload();
try {
FileItemIterator iter = upload.getItemIterator(request);
while (iter.hasNext()) {
FileItemStream item = iter.next();
String name = item.getFieldName();
InputStream stream = item.openStream();
if (item.isFormField()) {
System.out.println("Form field " + name + " with value "
+ Streams.asString(stream) + " detected.");
} else {
System.out.println("File field " + name + " with file name "
+ item.getName() + " detected.");
// Process the input stream
storeFile(stream, uid);
}
}
return "success";
} catch (FileUploadException ex) {
Logger.getLogger(UploadImage.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(UploadImage.class.getName()).log(Level.SEVERE, null, ex);
}
return "failed.";
}
I am returning a temporary file from my JAX-RS REST Service like below:
#GET
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response getFile() {
File file = ... // create a temporary file
return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)
.header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"" ) //optional
.build();
}
What is the correct way of removing this temporary file after the response has been processed? Is the JAX-RS implementation (like Jersey) supposed to do this automatically?
You can pass an instance of StreamingOutput that copies the content of the source file to the client output and eventually deletes the file.
final Path path = getTheFile().toPath();
final StreamingOutput output = o -> {
final long copied = Files.copy(path, o);
final boolean deleted = Files.deleteIfExists(path);
};
return Response.ok(output).build();
final File file = getTheFile();
return Response.ok((StreamingOutput) output -> {
final long copied = Files.copy(file.toPath(), output);
final boolean deleted = file.delete();
}).build();
The example on https://dzone.com/articles/jax-rs-streaming-response looks more helpful than the brief reply from Jin Kwon.
Here is an example:
public Response getDocumentForMachine(#PathParam("custno") String custno, #PathParam("machineno") String machineno,
#PathParam("documentno") String documentno, #QueryParam("language") #DefaultValue("de") String language)
throws Exception {
log.info(String.format("Get document. mnr=%s, docno=%s, lang=%s", machineno, documentno, language));
File file = new DocFileHelper(request).getDocumentForMachine(machineno, documentno, language);
if (file == null) {
log.error("File not found");
return Response .status(404)
.build();
}
StreamingOutput stream = new StreamingOutput() {
#Override
public void write(OutputStream out) throws IOException, WebApplicationException {
log.info("Stream file: " + file);
try (FileInputStream inp = new FileInputStream(file)) {
byte[] buff = new byte[1024];
int len = 0;
while ((len = inp.read(buff)) >= 0) {
out.write(buff, 0, len);
}
out.flush();
} catch (Exception e) {
log.log(Level.ERROR, "Stream file failed", e);
throw new IOException("Stream error: " + e.getMessage());
} finally {
log.info("Remove stream file: " + file);
file.delete();
}
}
};
return Response .ok(stream)
.build();
}
I have written code that should be saved file in the local directory, create zip of that file, send email and delete both files (original and zip), So this is my code:
Method wich send email
public void sendEmail(Properties emailProperties, InputStream inputStream, HttpServletRequest request) throws UnsupportedEncodingException {
MimeMessage mimeMessage = mailSender.createMimeMessage();
try {
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
try {
mimeMessageHelper.setFrom(from, personal);
} catch (UnsupportedEncodingException e) {
LOGGER.error(e.getMessage());
throw new SequelException(e.getMessage());
}
mimeMessageHelper.setTo(recipients);
mimeMessageHelper.setSubject(emailProperties.getProperty(PARAM_TITLE));
String message = emailProperties.getProperty(PARAM_EMLMSG);
mimeMessageHelper.setText(message);
InputStreamSource inputStreamSource = null;
if (inputStream != null) {
inputStreamSource = new ByteArrayResource(IOUtils.toByteArray(inputStream));
}
String compressType = COMPRESS_TYPE_ZIP;
String fileName = getAttachFilenameExtension(object, format);
Path filePath = Paths.get(StrUtils.getProperty("temp.email.files.path") + "\\" + fileName);
tempFile = saveTempFile(inputStreamSource.getInputStream(), filePath);
if (tempFile.length() > 0) {
inputStreamSource = compressFile(tempFile, filePath.toString(), compressType);
fileName = StringUtils.substring(fileName, 0, StringUtils.lastIndexOf(fileName, ".")+1) + compressType;
}
mimeMessageHelper.addAttachment(fileName, inputStreamSource);
mailSender.send(mimeMessage);
} catch (MessagingException | IOException e) {
LOGGER.error(e.getMessage());
throw new SequelException(e.getMessage());
} finally {
List<File> files = (List<File>) FileUtils.listFiles(tempFile.getParentFile(), new WildcardFileFilter(
FilenameUtils.removeExtension(tempFile.getName()) + "*"), null);
for (File file : files) {
try {
FileUtils.forceDelete(file);
} catch (IOException e) {
LOGGER.error(e.getMessage());
}
}
}
}
Save file in directory:
private File saveTempFile(InputStream inputStream, Path filePath) throws IOException {
Files.deleteIfExists(filePath);
Files.copy(inputStream, filePath);
return new File(filePath.toString());
}
Compress file:
private InputStreamSource compressFile(File file, String filePath, String compressType) throws IOException {
InputStream is = ZipFile(file, filePath);
InputStreamSource inputStreamSource = new ByteArrayResource(IOUtils.toByteArray(is));
return inputStreamSource;
}
public InputStream ZipFile(File file, String filePath) {
String zipArchiveFileName = StringUtils.substring(filePath, 0, filePath.lastIndexOf(".") + 1) + COMPRESS_TYPE_ZIP;
try (ZipArchiveOutputStream zipOutput = new ZipArchiveOutputStream(new File(zipArchiveFileName));) {
ZipArchiveEntry entry = new ZipArchiveEntry(StringUtils.overlay(file.getName(), "",
StringUtils.lastIndexOf(file.getName(), "_"), StringUtils.lastIndexOf(file.getName(), ".")));
zipOutput.putArchiveEntry(entry);
try (FileInputStream in = new FileInputStream(file);) {
byte[] b = new byte[1024];
int count = 0;
while ((count = in.read(b)) > 0) {
zipOutput.write(b, 0, count);
}
zipOutput.closeArchiveEntry();
}
InputStream is = new FileInputStream(zipArchiveFileName);
return is;
} catch (IOException e) {
LOGGER.error("An error occurred while trying to compress file to zip", e);
throw new SequelException(e.getMessage());
}
}
So the problem is when I try to delete files but zip file does not delete.
I am using Apache commons compress for zipping.
Can you help what's wrong?
For me this code is working perfectly. After compressing you may be trying to delete it without the extension(for eg .7z here).
public static void main(String[] args) {
File file = new File("C:\\Users\\kh1784\\Desktop\\Remote.7z");
file.delete();
if(!file.exists())
System.out.println("Sucessfully deleted the file");
}
Output:-
Sucessfully deleted the file
I have created zip file using java as below snippet
import java.io.*;
import java.util.zip.*;
public class ZipCreateExample {
public static void main(String[] args) throws IOException {
System.out.print("Please enter file name to zip : ");
BufferedReader input = new BufferedReader
(new InputStreamReader(System.in));
String filesToZip = input.readLine();
File f = new File(filesToZip);
if(!f.exists()) {
System.out.println("File not found.");
System.exit(0);
}
System.out.print("Please enter zip file name : ");
String zipFileName = input.readLine();
if (!zipFileName.endsWith(".zip"))
zipFileName = zipFileName + ".zip";
byte[] buffer = new byte[18024];
try {
ZipOutputStream out = new ZipOutputStream
(new FileOutputStream(zipFileName));
out.setLevel(Deflater.DEFAULT_COMPRESSION);
FileInputStream in = new FileInputStream(filesToZip);
out.putNextEntry(new ZipEntry(filesToZip));
int len;
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
out.closeEntry();
in.close();
out.close();
} catch (IllegalArgumentException iae) {
iae.printStackTrace();
System.exit(0);
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
System.exit(0);
} catch (IOException ioe) {
ioe.printStackTrace();
System.exit(0);
}
}
}
Now I want when I click on the zip file it should prompt me to type password and then decompress the zip file.
Please any help,How should I go further?
Try the following code which is based on Zip4j:
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;
import org.apache.commons.io.FilenameUtils;
import java.io.File;
public class Zipper
{
private String password;
private static final String EXTENSION = "zip";
public Zipper(String password)
{
this.password = password;
}
public void pack(String filePath) throws ZipException
{
ZipParameters zipParameters = new ZipParameters();
zipParameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
zipParameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_ULTRA);
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_AES);
zipParameters.setAesKeyStrength(Zip4jConstants.AES_STRENGTH_256);
zipParameters.setPassword(password);
String baseFileName = FilenameUtils.getBaseName(filePath);
String destinationZipFilePath = baseFileName + "." + EXTENSION;
ZipFile zipFile = new ZipFile(destinationZipFilePath);
zipFile.addFile(new File(filePath), zipParameters);
}
public void unpack(String sourceZipFilePath, String extractedZipFilePath) throws ZipException
{
ZipFile zipFile = new ZipFile(sourceZipFilePath + "." + EXTENSION);
if (zipFile.isEncrypted())
{
zipFile.setPassword(password);
}
zipFile.extractAll(extractedZipFilePath);
}
}
FilenameUtils is from Apache Commons IO.
Example usage:
public static void main(String[] arguments) throws ZipException
{
Zipper zipper = new Zipper("password");
zipper.pack("encrypt-me.txt");
zipper.unpack("encrypt-me", "D:\\");
}
Standard Java API does not support password protected zip files. Fortunately good guys have already implemented such ability for us. Please take a look on this article that explains how to create password protected zip.
(The link was dead, latest archived version: https://web.archive.org/web/20161029174700/http://java.sys-con.com/node/1258827)
Sample code below will zip and password protect your file.
This REST service accepts bytes of the original file. It zips the byte array and password protects it. Then it sends bytes of password protected zipped file as response. The code is a sample of sending and receiving binary bytes to and from a REST service, and also of zipping a file with password protect. The bytes are zipped from stream, so no files are ever stored on the server.
Uses JAX-RS API using Jersey API in java
Client is using Jersey-client API.
Uses zip4j 1.3.2 open source library, and apache commons io.
#PUT
#Path("/bindata/protect/qparam")
#Consumes(MediaType.APPLICATION_OCTET_STREAM)
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response zipFileUsingPassProtect(byte[] fileBytes, #QueryParam(value = "pass") String pass,
#QueryParam(value = "inputFileName") String inputFileName) {
System.out.println("====2001==== Entering zipFileUsingPassProtect");
System.out.println("fileBytes size = " + fileBytes.length);
System.out.println("password = " + pass);
System.out.println("inputFileName = " + inputFileName);
byte b[] = null;
try {
b = zipFileProtected(fileBytes, inputFileName, pass);
} catch (IOException e) {
e.printStackTrace();
return Response.status(Status.INTERNAL_SERVER_ERROR).build();
}
System.out.println(" ");
System.out.println("++++++++++++++++++++++++++++++++");
System.out.println(" ");
return Response.ok(b, MediaType.APPLICATION_OCTET_STREAM)
.header("content-disposition", "attachment; filename = " + inputFileName + ".zip").build();
}
private byte[] zipFileProtected(byte[] fileBytes, String fileName, String pass) throws IOException {
ByteArrayInputStream inputByteStream = null;
ByteArrayOutputStream outputByteStream = null;
net.lingala.zip4j.io.ZipOutputStream outputZipStream = null;
try {
//write the zip bytes to a byte array
outputByteStream = new ByteArrayOutputStream();
outputZipStream = new net.lingala.zip4j.io.ZipOutputStream(outputByteStream);
//input byte stream to read the input bytes
inputByteStream = new ByteArrayInputStream(fileBytes);
//init the zip parameters
ZipParameters zipParams = new ZipParameters();
zipParams.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
zipParams.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
zipParams.setEncryptFiles(true);
zipParams.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD);
zipParams.setPassword(pass);
zipParams.setSourceExternalStream(true);
zipParams.setFileNameInZip(fileName);
//create zip entry
outputZipStream.putNextEntry(new File(fileName), zipParams);
IOUtils.copy(inputByteStream, outputZipStream);
outputZipStream.closeEntry();
//finish up
outputZipStream.finish();
IOUtils.closeQuietly(inputByteStream);
IOUtils.closeQuietly(outputByteStream);
IOUtils.closeQuietly(outputZipStream);
return outputByteStream.toByteArray();
} catch (ZipException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
IOUtils.closeQuietly(inputByteStream);
IOUtils.closeQuietly(outputByteStream);
IOUtils.closeQuietly(outputZipStream);
}
return null;
}
Unit test below:
#Test
public void testPassProtectZip_with_params() {
byte[] inputBytes = null;
try {
inputBytes = FileUtils.readFileToByteArray(new File(inputFilePath));
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("bytes read into array. size = " + inputBytes.length);
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:8080").path("filezip/services/zip/bindata/protect/qparam");
target = target.queryParam("pass", "mypass123");
target = target.queryParam("inputFileName", "any_name_here.pdf");
Invocation.Builder builder = target.request(MediaType.APPLICATION_OCTET_STREAM);
Response resp = builder.put(Entity.entity(inputBytes, MediaType.APPLICATION_OCTET_STREAM));
System.out.println("response = " + resp.getStatus());
Assert.assertEquals(Status.OK.getStatusCode(), resp.getStatus());
byte[] zipBytes = resp.readEntity(byte[].class);
try {
FileUtils.writeByteArrayToFile(new File(responseFilePathPasswordZipParam), zipBytes);
} catch (IOException e) {
e.printStackTrace();
}
}
Feel free to use and modify. Please let me know if you find any errors. Hope this helps.
Edit 1 - Using QueryParam but you may use HeaderParam for PUT instead to hide passwd from plain sight. Modify the test method accordingly.
Edit 2 - REST path is filezip/services/zip/bindata/protect/qparam
filezip is name of war. services is the url mapping in web.xml. zip is class level path annotation. bindata/protect/qparam is the method level path annotation.
In new version of Zip4j, class Zip4jConstants was removed. Use EncryptionMethod and AesKeyStrength class instead. Documentation : https://github.com/srikanth-lingala/zip4j
ZipParameters zipParameters = new ZipParameters();
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(EncryptionMethod.AES);
zipParameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_256);
List<File> filesToAdd = Arrays.asList(
new File("somefile"),
new File("someotherfile")
);
ZipFile zipFile = new ZipFile("filename.zip", "password".toCharArray());
zipFile.addFiles(filesToAdd, zipParameters);
There is no default Java API to create a password protected file. There is another example about how to do it here.
Library Zip4J seems to be the preferred answer.
In case the privacy of the password is highly recommended, one might close a security gap in class ZipFile, which carries the password in plain text, even after the ZipFile is closed. Following method destroys the password.
public static void destroyZipPassword(ZipFile zip) throws DestroyFailedException
{
try
{
Field fdPwd = ZipFile.class.getDeclaredField("password");
fdPwd.setAccessible(true);
char[] password = (char[]) fdPwd.get(zip);
Arrays.fill(password, (char) 0);
}
catch (Exception e)
{
e.printStackTrace();
throw new DestroyFailedException(e.getMessage());
}
}