Java servlet: issue with multipart/form-data form - java

I have a multipart/form-data form with some <input type='text'> and <input type='file'> fields.
I use this code
List<FileItem> multipartItems = null;
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (!isMultipart) {
System.out.println("false");
} else {
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
multipartItems = null;
try {
multipartItems = upload.parseRequest(request);
System.out.println("true "+multipartItems.toString());
} catch (FileUploadException e) {
e.printStackTrace();
}
}
to find out if the form has multipart content.
Then, I use
Map<String, String[]> parameterMap = new HashMap<String, String[]>();
for (FileItem multipartItem : multipartItems) {
if (multipartItem.isFormField()) {
processFormField(multipartItem, parameterMap);
} else {
request.setAttribute(multipartItem.getFieldName(), multipartItem);
}
}
By running the first snippet of code, the else is executed, but at the end multipartItems is null.
For this reason, the for in the second code snippet is never executed.
I don't know why there is this behaviour. I'm using Struts 1.3.10
EDIT
How can I check if struts has already parsed the request?
If so, is there a way to turn off it only for a particular form?
EDIT 2
I have a dynamic form, coded in json format. I have a form bean for json and for hidden properties. Then I parse the json "by hand". All works perfectly, but now I have to add input type=file fields and use the multipart/form-data enctype.
To prevent struts request parsing I put in the web.xml:
<init-param>
<param-name>multipartClass</param-name>
<param-value>none</param-value>
</init-param>
But it doesn't seem to work

Initialize a FileItem, like below:
FileItem fileItem = null;
Then call this method
public boolean getParameters(HttpServletRequest request, PrintWriter out) {
List fileItemsList = null;
try {
if (ServletFileUpload.isMultipartContent(request)) {
ServletFileUpload servletFileUpload = new ServletFileUpload(new DiskFileItemFactory());
try {
fileItemsList = servletFileUpload.parseRequest(request);
} catch (FileUploadException ex) {
}
String optionalFileName = "";
Iterator it = fileItemsList.iterator();
while (it.hasNext()) {
FileItem fileItemTemp = (FileItem) it.next();
if (fileItemTemp.isFormField()) {
// for other form fields that are not multipart
// if (fileItemTemp.getFieldName().equals("commonName")) {
// commonName = fileItemTemp.getString();
// }
} else {
if (fileItemTemp.getFieldName().equals("media_file")) {
fileItem = fileItemTemp;
}
}
}
}
} catch (Exception e) {
}
return true;
}

I have used this example to file upload using servlet and jsp is working fine for me . Click here
Example has been explained in detail and if you face any problem then ask me, I have used this.

Related

Apache FileUpload doesn't work with springboot : ServletFileUpload.parseRequest is always empty

I am using springboot 2.2.6.RELEASE with commons-fileupload 1.4
and i have disabled spring.servlet.multipart as follows:
spring.servlet.multipart.enabled = false
my controllers is as follows :
#RequestMapping(value = "/UploadFileServlet", method = RequestMethod.POST)
public void doPost(HttpServletRequest request, HttpServletResponse response) throws Exception {
try {
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (isMultipart) {
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setRepository(new File(System.getProperty("java.io.tmpdir")));
factory.setSizeThreshold(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD);
factory.setFileCleaningTracker(null);
ServletFileUpload upload = new ServletFileUpload(factory);
List<FileItem> items = upload.parseRequest(request);
String imageFileName = request.getParameter("imageFileName");
Iterator<FileItem> iter = items.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
if (!item.isFormField()) {
try (InputStream uploadedStream = item.getInputStream();
OutputStream out = new FileOutputStream(imageFileName);) {
IOUtils.copy(uploadedStream, out);
}
}
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Issue : upload.parseRequest always returns an empty list
I found out the solution, I had a file upload filter for primefaces library that was not configured for specific url pattern, so it was stealing the request, after I configured the url pattern for it, the issue was solved :
#Bean
public FilterRegistrationBean FileUploadFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new org.primefaces.webapp.filter.FileUploadFilter());
registration.setName("PrimeFaces FileUpload Filter");
registration.addUrlPatterns("/faces/*");
registration.addUrlPatterns("*.xhtml");
return registration;
}

How to consume the fileupload restful webservice using restful template

I am newbie to restful webservice.My requirement is to upload a multiple files.i successfully write the code for uploading multiple files in restful web service.Below is my code.
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces("text/plain")
#Path("/multipleFiles")
public String registerWebService(#Context HttpServletRequest request)
{
String responseStatus = SUCCESS_RESPONSE;
String candidateName = null;
//checks whether there is a file upload request or not
if (ServletFileUpload.isMultipartContent(request))
{
final FileItemFactory factory = new DiskFileItemFactory();
final ServletFileUpload fileUpload = new ServletFileUpload(factory);
try
{
/*
* parseRequest returns a list of FileItem
* but in old (pre-java5) style
*/
final List items = fileUpload.parseRequest(request);
if (items != null)
{
final Iterator iter = items.iterator();
while (iter.hasNext())
{
final FileItem item = (FileItem) iter.next();
final String itemName = item.getName();
final String fieldName = item.getFieldName();
final String fieldValue = item.getString();
if (item.isFormField())
{
candidateName = fieldValue;
System.out.println("Field Name: " + fieldName + ", Field Value: " + fieldValue);
System.out.println("Candidate Name: " + candidateName);
}
else
{
final File savedFile = new File(FILE_UPLOAD_PATH + File.separator
+ itemName);
item.write(savedFile);
}
}
}
}
catch (FileUploadException fue)
{
responseStatus = FAILED_RESPONSE;
fue.printStackTrace();
}
catch (Exception e)
{
responseStatus = FAILED_RESPONSE;
e.printStackTrace();
}
}
return responseStatus;
}
Is it good to upload multifiles in single request?
I want to consume the above restful webservice using restful template or jersey or any other java client.
Can anybody please guide me to write the client code for consuming the above webservice?
Any help will be greatly appreciated!!!

Why I can't get access to parameters from a request after upload a file in jsp?

I'm using jsp and a servlet to do this.
I have a contact form that send a email with some data (name, subject, question,contact email etc) and a file.
when I submit the form, and get the servlet response only the first thing is returned.
String file= fileUpload(request); //upload the client's file and return the absolute path of the file in the server
//testing the rest of parameters
out.println("REQUEST LIST"
"\n" request.getParameter("name")
"\n" request.getParameter("mail")
"\n" request.getParameter("subject")
"\n" request.getParameter("ask")
"\n");
In this order the file is uploaded succesfully, but the other parameters (name, mail etc) are null.
In the order below, the parameters are ok, they return the data correctly. But the file is not uploaded.
//testing the rest of parameters
out.println("REQUEST LIST"
"\n" request.getParameter("name")
"\n" request.getParameter("mail")
"\n" request.getParameter("subject")
"\n" request.getParameter("ask")
"\n");
String file= fileUpload(request); //upload the client's file and return the absolute path of the file in the server
How can I have both?
Thanks!
You should extract the request parameters using the same API (e.g. Apache Commons FileUpload) as you've extracted the uploaded file. This is usually not interchangeable with calling getParameter() as the request body can be parsed only once (the enduser ain't going to send the same request twice, one to be parsed by the file upload parsing API and other to be parsed by getParameter()).
See also:
How to upload files to server using JSP/Servlet?
Look if the following code helps you. This is just an example. You may have to tweak it
Create a class called FileUploader which returns ServletFileUpload object
public class FileUploader
{
private static ServletFileUpload uploader;
private FileUploader()
{
}
public static synchronized ServletFileUpload getservletFileUploader(String tempDir, int maxSizeInMB)
{
if(uploader == null)
{
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(1024 * 1024);
factory.setRepository(new File(tempDir));
uploader = new ServletFileUpload(factory);
uploader.setFileSizeMax(maxSizeInMB * 1024 * 1024);
}
return uploader;
}
}
Now you can process a request and read all the data
protected MultiPartFormData handleMultiPartRequest(HttpServletRequest request)
throws FileSizeLimitExceededException
{
if(!isMultipartRequest(request))
return null;
ServletFileUpload upload = FileUploader.getservletFileUploader(tempDir, 50);
MultiPartFormData data = new MultiPartFormData();
try
{
List<FileItem> items = upload.parseRequest(request);
for (FileItem item : items)
{
if(item.isFormField())
{
data.getParameters().put(item.getFieldName(), item.getString());
}
else
{
String filename = item.getName();
//Internet explorer and firefox will send the file name differently
//Internet explorer will send the entire path to the file name including
//the backslash characters etc ... we should strip it down
//THIS IS HACKY
if(filename.indexOf("\\") != -1)
{
int index = filename.lastIndexOf("\\");
filename = filename.substring(index + 1);
}
if(filename == null || filename.equals(""))
{
//do nothing
}
else
{
File uploadFile = new File(uploadDir + File.separator + randomFileName);
item.write(uploadFile);
data.addFile(item.getFieldname(), item.getString());
}
}
}
}
catch(FileSizeLimitExceededException e)
{
throw e;
}
catch(Exception e)
{
e.printStackTrace();
}
return data;
}
After parsing the request I am storing it in some object called MultipartFormData which can be used to get request parameters
public class MultiPartFormData {
private Hashtable<String, String> parameters;
private Hashtable<String, String> uploadedFiles;
public MultiPartFormData()
{
this.parameters = new Hashtable<String, String>();
this.uploadedFiles = new Hashtable<String, String>();
}
public Hashtable<String, String> getParameters() {
return parameters;
}
public void setParameters(Hashtable<String, String> parameters) {
this.parameters = parameters;
}
public void getParameter(String paramName) {
if(this.parameters.contains(paramName))
return tyhis.parameters.get(paramName);
return null;
}
public void addFile(String key, String filename) {
uploadedFile.put(key, filename);
}
public void getFilename(String key) {
uploadedFile.get(key);
}
}

Error with GwtUpload Servlet

I'm trying to implement the Basic example for the GwtUpload library, as found here.
In my server code, I get the following error:
Exception java.lang.ClassCastException: org.apache.commons.fileupload.disk.DiskFileItem cannot be cast to org.apache.commons.fileupload.FileItem
I can't figure out why this is happening. DiskFileItem is a subclass of FileItem and should work. I've stepped through in the debugger and confirmed that the two classes are what they appear to be, yet the assignment fails.
Even more strangely, when I attempt to call the FileItem methods in the watch window, I have no problems, but if I attempt to access them in the code, I get the error.
Here is my Servlet code:
public class GwtUploadServlet extends UploadAction
{
private static final long serialVersionUID = 1L;
/**
* Maintain a list with received files and their content types.
*/
Hashtable<String, String> receivedContentTypes = new Hashtable<String, String>();
/**
* Maintain a list with received files.
*/
Hashtable<String, File> receivedFiles = new Hashtable<String, File>();
/**
* Override executeAction to save the received files in a custom place and
* delete this items from session.
*/
#Override
public String executeAction(HttpServletRequest request,
List<FileItem> sessionFiles) throws UploadActionException
{
String response = "";
int cont = 0;
for ( int i = 0 ; i < sessionFiles.size(); i++ )
{
if (false == sessionFiles.get(i).isFormField())
{
cont++;
try
{
// / Create a temporary file placed in the default system
// temp folder
File file = File.createTempFile("upload-", ".bin");
sessionFiles.get(i).write(file);
// / Save a list with the received files
receivedFiles.put(sessionFiles.get(i).getFieldName(), file);
receivedContentTypes.put(sessionFiles.get(i).getFieldName(),
sessionFiles.get(i).getContentType());
// / Send a customized message to the client.
response += "File saved as " + file.getAbsolutePath();
}
catch (Exception e)
{
throw new UploadActionException(e);
}
}
}
// / Remove files from session because we have a copy of them
removeSessionFileItems(request);
// / Send your customized message to the client.
return response;
}
/**
* Get the content of an uploaded file.
*/
#Override
public void getUploadedFile(HttpServletRequest request,
HttpServletResponse response) throws IOException
{
String fieldName = request.getParameter(PARAM_SHOW);
File f = receivedFiles.get(fieldName);
if (f != null)
{
response.setContentType(receivedContentTypes.get(fieldName));
FileInputStream is = new FileInputStream(f);
copyFromInputStreamToOutputStream(is, response.getOutputStream());
}
else
{
renderXmlResponse(request, response, ERROR_ITEM_NOT_FOUND);
}
}
/**
* Remove a file when the user sends a delete request.
*/
#Override
public void removeItem(HttpServletRequest request, String fieldName)
throws UploadActionException
{
File file = receivedFiles.get(fieldName);
receivedFiles.remove(fieldName);
receivedContentTypes.remove(fieldName);
if (file != null)
{
file.delete();
}
}
}
Make sure you don't have multiple versions of commons-fileupload on the classpath.

Issue with multipart/form-data

I am not able to get values from both files and text input in a servlet when my form includes multipart/form-data. I am using the apache.commons.fileuploads for help with the uploads. Any suggestions. Also in the code below there are some things that I feel should be more efficient. Is there a better way to store these multiple files in a db.
public void performTask(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
{
boolean promo = false;
Database db = new Database();
Homepage hp = db.getHomePageContents();
String part = ParamUtils.getStringParameter(request, "part", "");
if(part.equals("verbage"))
{
String txtcontent = (String)request.getParameter("txtcontent");
String promoheader = (String)request.getParameter("promoheader");
String promosubheader = (String)request.getParameter("promosubheader");
hp.setBodyText(txtcontent);
hp.setPromoHeader(promoheader);
hp.setPromoSubHeader(promosubheader);
System.err.println(txtcontent);
}
else
{
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (!isMultipart)
{
}
else {
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List items = null;
try {
items = upload.parseRequest(request);
//System.err.print(items);
} catch (FileUploadException e) {
e.printStackTrace();
}
Iterator itr = items.iterator();
while (itr.hasNext()) {
FileItem item = (FileItem) itr.next();
if(item.getFieldName().equals("mainimg1"))
{
if(item.getName() !="") hp.setMainImg1(item.getName());
}
if(item.getFieldName().equals("mainimg2"))
{
if(item.getName() !="") hp.setMainImg2(item.getName());
}
if(item.getFieldName().equals("mainimg3"))
{
if(item.getName() !="") hp.setMainImg3(item.getName());
}
if(item.getFieldName().equals("promoimg1"))
{
promo = true;
if(item.getName() !="")
{
hp.setPromoImg1(item.getName());
try {
File savedFile = new File("/Library/resin-4.0.1/webapps/ROOT/images/promoImg1.jpg");
item.write(savedFile);
//System.err.print(items);
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
}
if(item.getFieldName().equals("promoimg2"))
{
if(item.getName() !="")
{
hp.setPromoImg2(item.getName());
try {
File savedFile = new File("/Library/resin-4.0.1/webapps/ROOT/images/promoImg2.jpg");
item.write(savedFile);
//System.err.print(items);
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
}
if(item.getFieldName().equals("promoimg3"))
{
if(item.getName() !="")
{
hp.setPromoImg3(item.getName());
try {
File savedFile = new File("/Library/resin-4.0.1/webapps/ROOT/images/promoImg3.jpg");
item.write(savedFile);
//System.err.print(items);
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
}
System.err.println("FNAME =" + item.getFieldName() + " : " + item.getName());
if (item.isFormField()) {
}
else {
try {
if(!promo)
{
String itemName = item.getName();
File savedFile = new File("/Library/resin-4.0.1/webapps/ROOT/images/"+itemName);
item.write(savedFile);
}
//System.err.print(items);
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
}
}
}
db.updateHomePageContent(hp);
When using multipart/form-data, the normal input field values are not available by request.getParameter() because the standard Servlet API prior to version 3.0 doesn't have builtin facilities to parse them. That's exactly why Apache Commons FileUpload exist. You need to check if FileItem#isFormField() returns true and then gather them from the FileItem.
Right now you're ignoring those values in the code. Admittedly, the FileItem is a misleading name, if it was me, I'd called it MultipartItem or just Part representing a part of a multipart/form-data body which contains both uploaded fields and normal parameters.
Here's a kickoff example how you should parse a multipart/form-data request properly:
List<FileItem> items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request);
for (FileItem item : items) {
if (item.isFormField()) {
// Process normal fields here.
System.out.println("Field name: " + item.getFieldName());
System.out.println("Field value: " + item.getString());
} else {
// Process <input type="file"> here.
System.out.println("Field name: " + item.getFieldName());
System.out.println("Field value (file name): " + item.getName());
}
}
Note that you also overlooked a MSIE misbehaviour that it sends the full client side path along the file name. You would like to trim it off from the item.getName() as per the FileUpload FAQ:
String fileName = item.getName();
if (fileName != null) {
filename = FilenameUtils.getName(filename);
}
I have had similar problems in the past. The only way i could find round the problem was to put the fileupload into its own form.

Categories