Rest Controller: uploading file using HttpServletRequest through Swagger UI - java

I wonder if it is possible to show the input file to select in my Swagger UI when exposing the API.
I confirm that it is working perfectly when defining the endpoint as following:
public ResponseEntity<String> upload(#RequestPart MultipartFile file)
There is no doubt to show the file chooser when using MultipartFile.
And as I would like to upload big files, I have to use HttpServletRequest instead in order to upload the file as a stream. The endpoint will be then like:
public #ResponseBody Response<String> upload(HttpServletRequest request) {
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload();
// Parse the request
FileItemIterator iter = upload.getItemIterator(request);
while (iter.hasNext()) {
FileItemStream item = iter.next();
String name = item.getFieldName();
InputStream stream = item.openStream();
if (!item.isFormField()) {
String filename = item.getName();
// Process the input stream
OutputStream out = new FileOutputStream(filename);
IOUtils.copy(stream, out);
stream.close();
out.close();
}
}
return new Response<String>(true, "Success", "");
}
The endpoint is working well using a curl command. But unfortunately when using the Swagger UI, I am not able to show the file chooser.
Does anyone faced the same case or knows if Swagger supports this feature?

Related

How to upload multipart file without storing on server harddisk

My SpringBoot API receives multipart file. Then using RestTemplate I am sending same to different API. It works fine!!!
Problem here is its storing multipart file on server harddisk. My API should just act as an intermediate service between frontend and another API endpoint.
I do not want to store received file locally
One thing I can do is delete after uploaded to different API.
Is there any better way we do same thing i.e. without storing on server or automatic delete from server.
My code is as below
Controller
#PostMapping(value = "/uploadFile", consumes = { "multipart/form-data" })
public SomePojoObject uploadFile(#RequestParam("file") MultipartFile mFile,
#RequestParam("metaData") String metaData) {
return service.uploadFile(mFile, metaData);
}
And Service code is as below
private SomePojoObject uploadFile(MultipartFile mFile, String metaData) {
File file = convertFile(mFile);
LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("FILE", new FileSystemResource(file));
map.add("metaData", metaData);
// Some more logic of resttemplate to upload document to server
}
public File convertFile(MultipartFile mFile) {
File file = new File(mFile.getOriginalFilename());
try {
file.createNewFile();
FileOutputStream fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(mFile.getBytes());
fileOutputStream.close();
} catch (IOException e) {
e.printstackTrace();
}
return file;
}
Finally found a rather very simple way to achieve above.
There is no need to convert it to file.!!!!
private SomePojoObject uploadFile(MultipartFile mFile, String metaData) {
LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("FILE", mFile.getResource());
map.add("metaData", metaData);
// Some more logic of resttemplate to upload document to server
}

write the file and download the file same as of attachments

i have a requirement where i get byte array (byte[]) data from database, i need to save this data in a file and allow the user to save where ever he want to save, same as downloading the attachments.The file name and extension also i'm retrieving from database. I'm using java,spring-mvc for this.
Below is the code:
spring controller:
#RequestMapping(value="/getFile", method = RequestMethod.GET)
public ModelAndView getFile(HttpServletRequest request, HttpServletResponse response) {
ModelAndView mav = new ModelAndView();
//logic to get the data from database
byte[] documentData = document.getDOCUMENTData();
String documentName = document.getDOCUMENTTITLE();
String documentExt = document.getDocumentExtension();
}
Please suggest, i know that using java.io.*, i can write the byte[] data in file and give file name and extension by taking the values declared above, but how can i allow users when clicked on "download file" icon to write the data and save that file where ever he wants same as downloading the attachment.Please suggest. Once user clicks on download file icon control comes to above controller.Thanks.
--EDIT--
Modified code:
#RequestMapping(value="/getFile", method = RequestMethod.GET)
public ModelAndView getFile(HttpServletRequest request, HttpServletResponse response) {
ModelAndView mav = new ModelAndView();
//logic to get the data from database
byte[] documentData = document.getDOCUMENTData();
String documentName = document.getDOCUMENTTITLE();
String documentExt = document.getDocumentExtension();
response.setHeader("Content-Disposition", "attachment;filename="+userDoc.getDOCUMENT_TITLE());
long l = userDoc.getDOCUMENT_SIZE();
int size = (int)l;
response.setContentLength(size);
response.getWriter().write("hello");//i need to write byte[] but for test i kept string.
}
I want user to see save window so that he can save where ever he want same as downloading the attachments from mail.Thanks.
This is a code I'm usign for the same request
HTML page:
<h:commandButton value="Click Here to Download" action="#{reportBean.download}" />
BEAN:
public void download(){
HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
response.setHeader("Content-Disposition", "attachment;filename="+file.getName());
response.setContentLength((int) file.length());
ServletOutputStream out = null;
try {
FileInputStream input = new FileInputStream(file);
byte[] buffer = new byte[1024];
out = response.getOutputStream();
int i = 0;
while ((i = input.read(buffer)) != -1) {
out.write(buffer);
out.flush();
}
FacesContext.getCurrentInstance().getResponseComplete();
input.close();
} catch (IOException err) {
err.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException err) {
err.printStackTrace();
}
}
}
Just make sure you have a File object named file
You have two options to achieve this:
One is to write the file in your server's local filesystem in an internet accesible folder. You can configure which of your server's local folders are accesible from internet in your Apache/IIS serttings. Then you update your HTML so your "download file" link points to that file through an URL.
The other option is, like #an3sarmiento did, to return the file as a byte[] stream to the browser. For this option to work, you have to send, along with the file content, a response header in which you tell the browser you are returning a downloadable file as a stream. You do that with the line:
response.setHeader("Content-Disposition", "attachment;filename="+[your file name]);
response.setContentLength([your file's length or bytes count]);
response.getWriter.write([your file's content as byte array]);
In the line above I assume you are working with Java Servlets and you have an HttpServletResponse variable named reponse, which you will respond to the browser's HTTP POST or GET request.

Spring MVC : Return CSS

My goal is to merge/minify all css files and return the result as String.
Here's my Spring test method :
#RequestMapping(value = "/stylesheet.css", method = RequestMethod.GET, produces = "text/css")
#ResponseBody
public void css(HttpServletResponse response) {
File path = new File(servletContext.getRealPath("/WEB-INF/includes/css/"));
File[] files = path.listFiles(...);
for (File file : files) {
InputStream is = new FileInputStream(file);
IOUtils.copy(is, response.getOutputStream());
response.flushBuffer();
is.close();
}
}
This is working with Chrome, Firefox and Safari but not with IE and Opera.
After some checks in the inspectors, the URL https://host/project/stylesheet.css is loading in each browsers. I can see the content but it does not seem to be recognized as text/css.
Also, even with produces = "text/css", I can not see the content-type http header in all browsers.
Error log in IE :
CSS ignored because of mime type incompatibility
Does anyone know how to correctly do this?
Working code :
#RequestMapping(value = "/stylesheet.css", method = RequestMethod.GET)
public ResponseEntity<Void> css(HttpServletResponse response) {
response.setContentType("text/css");
File path = new File(servletContext.getRealPath("/WEB-INF/includes/css/"));
File[] files = path.listFiles(...);
for (File file : files) {
InputStream is = new FileInputStream(file);
IOUtils.copy(is, response.getOutputStream());
IOUtils.closeQuietly(is);
}
response.flushBuffer();
return new ResponseEntity<Void>(HttpStatus.OK);
}
I suspect the problem is due to your usage of HttpServletResponse.flushBuffer().
As the API of HttpServletRequest states:
Forces any content in the buffer to be written to the client. A call
to this method automatically commits the response, meaning the status
code and headers will be written.
My assumption would be that Spring attempts to set the Content-Type header on the HttpServletResponse after the method on your controller has returned. However, because you have committed the response with your call to HttpServletResponse.flushBuffer(), it cannot do this.
I would try either:
Injecting the HttpServletResponse into your controller and setting the header yourself in code before calling HttpServletResponse.flushBuffer()
Removing your usage of HttpServletRequest.flushBuffer()
Since you're writing the content directly to the output stream, you don't need to use #ResponseBody. You just need to ensure that you set the Content-Type response header. Also, it'd be better to return a ResponseEntity (rather than void) to indicate to Spring that you're handling the response yourself.
#RequestMapping(value = "/stylesheet.css", method = RequestMethod.GET)
public ResponseEntity css(HttpServletResponse response) {
// Set the content-type
response.setHeader("Content-Type", "text/css");
File path = new File(servletContext.getRealPath("/WEB-INF/includes/css/"));
File[] files = path.listFiles(...);
for (File file : files) {
InputStream is = new FileInputStream(file);
IOUtils.copy(is, response.getOutputStream());
IOUtils.closeQuietly(is);
}
response.flushBuffer();
return new ResponseEntity(HttpStatus.OK)
}

Sent request parameters to UploadAction in gwt-upload

I get gwt-upload working in a GAE application. As suggested, I implemented a Custom UploadAction to handle the storage of the file in the DataStore. The code goes like this:
public String executeAction(HttpServletRequest request,
List<FileItem> sessionFiles) throws UploadActionException {
logger.info("Starting: DatastoreUploadAction.executeAction");
String executeAction = super.executeAction(request, sessionFiles);
for (FileItem uploadedFile : sessionFiles) {
Long entityId = new Long(2001); // This is where i wanna use a request parameter
InputStream imgStream;
try {
imgStream = uploadedFile.getInputStream();
Blob attachment = new Blob(IOUtils.toByteArray(imgStream));
String contentType = uploadedFile.getContentType();
appointmentDao.setAppointmentAttachment(entityId, attachment,
contentType);
} catch (IOException e) {
logger.error("Unable to store file", e);
throw new UploadActionException(e);
}
}
return executeAction;
}
As you see, the DAO class requires the "EntityID" to store the uploaded file in the DataStore. Now i'm working with a hard-coded value and it goes fine, but i'd like to have the entityID sent by the client as a request parameter. The widget that does the upload is a MultiUploader:
private MultiUploader defaultUploader;
Is it posible to the MultiUploader -or any other Widget- to set a request parameter so i can use it in my UploadAction?
Yes, you can set it on your client-side code. There is method: MultiUploader #setServletPath(java.lang.String), for example:
final MultiUploader u = new MultiUploader();
...
...
...
u.setServletPath(u.getServletPath() + "?entityId="+myObject.getEntityId());
on server side:
String entityId= request.getParameter("entityId");
Read this for more information: Sending additional parameters to the servlet

YUI Uploader with Java back-end

I am trying to use the (flash based) YUI Uploader with a Java (Spring-based) back-end.
The typical way of uploading files in the Java Servlet world is to set the ENCTYPE='multipart/form-data' on the HTML form requesting the file from the user. With the right server side APIs (i.e. Commons FileUpload), it is possible to get the file on the server.
But I am stymied by how to achieve this with the YUI Uploader. I am able to reach the Java controller, and I am even able to extract the custom post values. But I have no idea how to extract the binary file data out of the request.
Has anyone out had any luck with a YUI uploader with a Java back-end?
To answer my own question, and to make a long story short, this snippet of code did the trick:
#Controller
#RequestMapping("/FileUploadController")
public class FileUploadController {
#RequestMapping(method = RequestMethod.POST)
protected ModelAndView onSubmit(HttpServletRequest request) throws Exception{
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List<FileItem> /* FileItem */ items = upload.parseRequest(request);
for (FileItem fileItem : items) {
if (fileItem.isFormField()) {
// processFormField(fileItem);
} else {
File uploadedFile = new File("/tmp/junk/" + fileItem.getName());
fileItem.write(uploadedFile);
}
}
return new ModelAndView("index");
}
}
This example uses Spring, but you should be able to do exactly the same as long as you have HttpServletRequest object.

Categories