Spring mvc file upload - java

I'm working on spring mvc file upload. in the view, i use plupload multiple file upload plugin. here is my upload action:
#RequestMapping(value = CrudURI.uploadDo, method = RequestMethod.POST, produces = "application/json")
public #ResponseBody String uploadDo(#RequestBody MultipartFile file,
#RequestParam String name,
#RequestParam(required=false, defaultValue="-1") int chunks,
#RequestParam(required=false, defaultValue="-1") int chunk) {
if (!file.isEmpty()) {
try {
byte[] bytes = file.getBytes();
BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(new File("/uploads/"+name)));
stream.write(bytes);
stream.close();
} catch (Exception e) {
}
} else {
}
System.err.println(file.getOriginalFilename());
return null;
}
this action is working without any error or exception, but the uploaded file not saved. what's the problem?
thanks

Simply try following code:
File fileToSave=new File("/uploads/"+name);
file.transferTo(fileToSave);
And also make sure that you are actually getting file in mapping.

Darshan solution is correct, your original code has an issue that you're reading a file as getBytes() which is not using a buffer, but your writing using a buffer.
I think that your issue is most likely that you're trying to overwrite the uploaded file, at least it appears so based on your output location "/uploads/"+name. Try changing the name, and instead of having an empty catch block, add log for your exception it will point you to the issue

Related

How to temporarily create a text file without any file location and send as a response in spring boot at run time?

Need to create a txt file by the available data and then need to send the file as rest response.
the app is deployed in container. i dont want to store it in any location on container or any location in spring boot resources. is there any way where we can create file at runtime buffer without giving any file location and then send it in rest response?
App is production app so i need a solution which is secure
A file is a file. You're using the wrong words - in java, the concept of a stream of data, at least for this kind of job, is called an InputStream or an OutputStream.
Whatever method you have that takes a File? That's the end of the road. A File is a file. You can't fake it. But, talk to the developers, or check for alternate methods, because there is absolutely no reason anything in java that does data processing requires a File. It should be requiring an InputStream or possibly a Reader. Or perhaps even there is a method that gives you an OutputStream or Writer. All of these things are fine - they are abstractions that lets you just send data to it, from a file, a network connection, or made up whole cloth, which is what you want.
Once you have one of those, it's trivial. For example:
String text = "The Text you wanted to store in a fake file";
byte[] data = text.getBytes(StandardCharsets.UTF_8);
ByteArrayInputStream in = new ByteArrayInputStream(data);
whateverSystemYouNeedToSendThisTo.send(in);
Or for example:
String text = "The Text you wanted to store in a fake file";
byte[] data = text.getBytes(StandardCharsets.UTF_8);
try (var out = whateverSystemYouNeedToSendThisTo.getOUtputStream()) {
out.write(data);
}
Take a look at the function below:
Imports
import com.google.common.io.Files;
import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import java.io.*;
import java.nio.file.Paths;
Function:
#GetMapping(value = "/getFile", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
private ResponseEntity<byte[]> getFile() throws IOException {
File tempDir = Files.createTempDir();
File file = Paths.get(tempDir.getAbsolutePath(), "fileName.txt").toFile();
String data = "Some data"; //
try (FileWriter fileWriter = new FileWriter(file)) {
fileWriter.append(data).flush();
} catch (Exception ex) {
ex.printStackTrace();
}
byte[] zippedData = toByteArray(new FileInputStream(file));
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentDisposition(ContentDisposition.builder("attachment").filename("file.txt").build());
httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
httpHeaders.setContentLength(zippedData.length);
return ResponseEntity.ok().headers(httpHeaders).body(zippedData);
}
public static byte[] toByteArray(InputStream in) throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
byte[] buffer = new byte[in.available()];
int len;
// read bytes from the input stream and store them in buffer
while ((len = in.read(buffer)) != -1) {
// write bytes from the buffer into output stream
os.write(buffer, 0, len);
}
return os.toByteArray();
}
In a nutshell, you want to store data in memory. Basic building block for this is array of bytes - byte[].
In JDK there are two classes to connect IO world with byte array - ByteArrayInputStream and ByteArrayOutputStream.
Rest is just same, as when dealing with files.
Example 1
#GetMapping(value = "/image")
public #ResponseBody byte[] getImage() throws IOException {
InputStream in = getClass()
.getResourceAsStream("/com/baeldung/produceimage/image.jpg");
return IOUtils.toByteArray(in);
}
Example 2:
#GetMapping("/get-image-dynamic-type")
#ResponseBody
public ResponseEntity<InputStreamResource> getImageDynamicType(#RequestParam("jpg") boolean jpg) {
MediaType contentType = jpg ? MediaType.IMAGE_JPEG : MediaType.IMAGE_PNG;
InputStream in = jpg ?
getClass().getResourceAsStream("/com/baeldung/produceimage/image.jpg") :
getClass().getResourceAsStream("/com/baeldung/produceimage/image.png");
return ResponseEntity.ok()
.contentType(contentType)
.body(new InputStreamResource(in));
}
Ref: https://www.baeldung.com/spring-controller-return-image-file

Displaying PDF from base64 string with Spring/Java

I have a PDF saved as a base 64 CLOB in a database.
As a functional test, I'm just trying to get it to display in my browser. I made a new endpoint in my controller and just put the base64 String into the controller, without even getting the PDF from the database, that looks like this:
#RequestMapping(value = "/output.pdf", method = RequestMethod.GET, produces = "application/pdf")
public void makePDF(HttpServletResponse response) throws Exception {
String value = "R04jArrrw45jNH6bV02="; //<--This is longer, but I shortened it for this question
byte[] imageByte = value.getBytes();
response.setContentType("application/pdf");
response.setContentLength(imageBytes.length);
response.getOutputStream().write(imageBytes);
} catch (Exception e) {
e.printStackTrace();
}
}
Whenever I hit the endpoint, I get a Failed to load PDF document message. I can't figure out why.
I'm pretty new to this, so I'm having trouble figuring out what my next steps are. How do I get the PDF to display in the web browser?
EDIT
I was able to get this working, by using modifying my method to the following:
#RequestMapping(value = "/output.pdf", method = RequestMethod.GET, produces = "application/pdf")
public void makePDF(HttpServletResponse response) throws Exception {
try {
String value = "R04jArrrw45jNH6bV02="; //<--This is longer, but I shortened it for this question
byte[] image = Base64.decodeBase64(value.getBytes());
Document document = new Document();
document.setPageSize(PageSize.LETTER);
PdfWriter.getInstance(document, response.getOutputStream());
Image labelImage = Image.getInstance(image);
labelImage.setAlignment(Image.TOP);
labelImage.scalePercent(new Float("35"));
document.open();
document.add(labelImage);
response.setContentType("application/pdf");
response.setContentLength(imageBytes.length);
response.getOutputStream().write(image);
document.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Trying to understand exactly what I'm doing here, and why it worked. Obviously has something to do with Base64 decoding, and using the Document object.
Stack Overflow post Blob vs Clob and why you should not store binary data in Clobs
PDF has a general text-based structure. However, PDF files can contain non-ASCII ("binary") data and should always be considered binary files, - sorry unable to find a source of truth link for this.
There is potential for a lossy encoding of data, and decoding encoded Base-64 in that case.
Decode using Base64 before you stream it out
Base64.decode(base64String, Base64.NO_WRAP)

How to attach single or multiple attachments to CouchbaseLite document - Android?

I want to attach files to CouchbaseLite document. How can I do so? I did not find any code sample on official CBLite website for this - CBLite code Sample. I am still stuck how to accomplish it.
One way to do this in code is:
Document document = mDatabaseLocal.createDocument();
document.getCurrentRevision().createRevision().setAttachment(name, contentType, contentStream);
But this is not clear. *What should be the name?* - It is the absolute path of the attachment on your local disk?
For contentType: I do not know if there exists any enum class or constants that I can pass as contentType.
How would I attach multiple files to a document? Do I need to create unsavedRevision for every attachment?
The name must be unique per attachment, and doesn't refer to the local file, it refers to the name that you want to fetch it from on the document.
In this case you would call createRevision() once and then setAttachment() multiple times on the revision, before saving it.
you have to put an inputstream as attachment to your document.
A example can be found here CouchBase Attachment Example.
You have to convert each file into an InputStream and then you can set it to the document.
For convert you can use something like this:
private InputStream getAsStream(YourData data)
{
baos = new ByteArrayOutputStream();
try
{
objOstream = new ObjectOutputStream(baos);
objOstream.writeObject(data);
} catch (IOException e)
{
e.printStackTrace();
}
bArray = baos.toByteArray();
bais = new ByteArrayInputStream(bArray);
return bais;
}
In this example YourData can be every object or some of your own objectTypes.
Hope this explanation will help you.

JaxRS create and return zip file from server

I want to create and return a zip file from my server using JaxRS. I don't think that I want to create an actual file on the server, if possible I would like to create the zip on the fly and pass that back to the client. If I create a huge zip file on the fly will I run out of memory if too many files are in the zip file?
Also I am not sure the most efficient way to do this. Here is what I was thinking but I am very rusty when it comes to input/output in java.
public Response getFiles() {
// These are the files to include in the ZIP file
String[] filenames = // ... bunch of filenames
byte[] buf = new byte[1024];
try {
// Create the ZIP file
ByteArrayOutputStream baos= new ByteArrayOutputStream();
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(baos));
// Compress the files
for (String filename : filenames) {
FileInputStream in = new FileInputStream(filename);
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry(filename));
// Transfer bytes from the file to the ZIP file
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
// Complete the entry
out.closeEntry();
in.close();
}
// Complete the ZIP file
out.close();
ResponseBuilder response = Response.ok(out); // Not a 100% sure this will work
response.type(MediaType.APPLICATION_OCTET_STREAM);
response.header("Content-Disposition", "attachment; filename=\"files.zip\"");
return response.build();
} catch (IOException e) {
}
}
Any help would be greatly appreciated.
There are two options:
1- Create ZIP in a temporal directory and then dump to client.
2- Use OutputStream from the Response to send zip directly to the client, when you are creating them.
But never use memory to create huge ZIP file.
There's no need to create the ZIP file from the first to the last byte in the memory before serving it to the client. Also, there's no need to create such a file in temp directory in advance as well (especially because the IO might be really slow).
The key is to start streaming the "ZIP response" and generating the content on the flight.
Let's say we have a aMethodReturningStream(), which returns a Stream, and we want to turn each element into a file stored in the ZIP file. And that we don't want to keep bytes of each element stored all the time in any intermediate representation, like a collection or an array.
Then such a pseudocode might help:
#GET
#Produces("application/zip")
public Response generateZipOnTheFly() {
StreamingOutput output = strOut -> {
try (ZipOutputStream zout = new ZipOutputStream(strOut)) {
aMethodReturningStream().forEach(singleStreamElement -> {
try {
ZipEntry zipEntry = new ZipEntry(createFileName(singleStreamElement));
FileTime fileTime = FileTime.from(singleStreamElement.getCreationTime());
zipEntry.setCreationTime(fileTime);
zipEntry.setLastModifiedTime(fileTime);
zout.putNextEntry(zipEntry);
zout.write(singleStreamElement.getBytes());
zout.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
};
return Response.ok(output)
.header("Content-Disposition", "attachment; filename=\"generated.zip\"")
.build();
}
This concept relies on passing a StreamingOutput to the Response builder. The StreamingOutput is not a full response/entity/body generated before sending the response, but a recipe used to generate the flow of bytes on-the-fly (here wrapped into ZipOutputStream). If you're not sure about this, then maybe set a breakpoint next on flush() and observe the a download progress using e.g. wget.
The key thing to remember here is that the stream here is not a "wrapper" of pre-computed or pre-fetched items. It must be dynamic, e.g. wrapping a DB cursor or something like that. Also, it can be replaced by anything that's streaming data. That's why it cannot be a foreach loop iterating over Element[] elems array (with each Element having all the bytes "inside"), like
for(Element elem: elems)
if you'd like to avoid reading all items into the heap at once before streaming the ZIP.
(Please note this is a pseudocode and you might want to add better handling and polish other stuff as well.)

Convert byte[] to Base64 string for data URI

I know this has probably been asked 10000 times, however, I can't seem to find a straight answer to the question.
I have a LOB stored in my db that represents an image; I am getting that image from the DB and I would like to show it on a web page via the HTML IMG tag. This isn't my preferred solution, but it's a stop-gap implementation until I can find a better solution.
I'm trying to convert the byte[] to Base64 using the Apache Commons Codec in the following way:
String base64String = Base64.encodeBase64String({my byte[]});
Then, I am trying to show my image on my page like this:
<img src="data:image/jpg;base64,{base64String from above}"/>
It's displaying the browser's default "I cannot find this image", image.
Does anyone have any ideas?
Thanks.
I used this and it worked fine (contrary to the accepted answer, which uses a format not recommended for this scenario):
StringBuilder sb = new StringBuilder();
sb.append("data:image/png;base64,");
sb.append(StringUtils.newStringUtf8(Base64.encodeBase64(imageByteArray, false)));
contourChart = sb.toString();
According to the official documentation Base64.encodeBase64URLSafeString(byte[] binaryData) should be what you're looking for.
Also mime type for JPG is image/jpeg.
That's the correct syntax. It might be that your web browser does not support the data URI scheme. See Which browsers support data URIs and since which version?
Also, the JPEG MIME type is image/jpeg.
You may also want to consider streaming the images out to the browser rather than encoding them on the page itself.
Here's an example of streaming an image contained in a file out to the browser via a servlet, which could easily be adopted to stream the contents of your BLOB, rather than a file:
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
ServletOutputStream sos = resp.getOutputStream();
try {
final String someImageName = req.getParameter(someKey);
// encode the image path and write the resulting path to the response
File imgFile = new File(someImageName);
writeResponse(resp, sos, imgFile);
}
catch (URISyntaxException e) {
throw new ServletException(e);
}
finally {
sos.close();
}
}
private void writeResponse(HttpServletResponse resp, OutputStream out, File file)
throws URISyntaxException, FileNotFoundException, IOException
{
// Get the MIME type of the file
String mimeType = getServletContext().getMimeType(file.getAbsolutePath());
if (mimeType == null) {
log.warn("Could not get MIME type of file: " + file.getAbsolutePath());
resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return;
}
resp.setContentType(mimeType);
resp.setContentLength((int)file.length());
writeToFile(out, file);
}
private void writeToFile(OutputStream out, File file)
throws FileNotFoundException, IOException
{
final int BUF_SIZE = 8192;
// write the contents of the file to the output stream
FileInputStream in = new FileInputStream(file);
try {
byte[] buf = new byte[BUF_SIZE];
for (int count = 0; (count = in.read(buf)) >= 0;) {
out.write(buf, 0, count);
}
}
finally {
in.close();
}
}
If you don't want to stream from a servlet, then save the file to a directory in the webroot and then create the src pointing to that location. That way the web server does the work of serving the file. If you are feeling particularly clever, you can check for an existing file by timestamp/inode/crc32 and only write it out if it has changed in the DB which can give you a performance boost. This file method also will automatically support ETag and if-modified-since headers so that the browser can cache the file properly.

Categories