I wrote a simple page with a form to upload a file and a jsp to handle that file.
My problem is that when the file is uploaded, the request object is handled by Struts interceptors and when it comes to the jsp page it is already "consumed", so the calls to read the request with methods such as "ServletFileUpload.parseRequest()" returns empty lists.
I have already found a working solution, but this needs to restart Tomcat, and since the page has to be added on the production server, it would be so much better if there is a way to not restart it.
For now, what I tried and worked is this:
1) in struts.xml i added
<include file="custom/struts-custom.xml"/>
2) in the struts-custom.xml i wrote:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.action.excludePattern" value="/path_to_my_jsp/page.jsp"/>
</struts>
With this i can upload the file bypassing struts interceptors.
Is there a better / cleaner solution? as i said, the best would be a solution that doesn't need to restart the application server.
Even if i don't think that the problem is related to code, i will post it.
page.html:
<form action="upload.jsp" method="post" enctype="multipart/form-data" TARGET="Report_Down"
onSubmit="if(document.getElementById('file1').value == '') return false;">
Input File <input type="file" name="file1" id="file1">
<input type="submit" value="Upload">
</form>
upload.jsp:
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (!isMultipart) {
return;
}
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(1024 * 1024 * 2);
factory.setRepository(new File(System.getProperty("java.io.tmpdir")));
String uploadFolder = getServletContext().getRealPath("")
+ File.separator + DATA_DIRECTORY;
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setSizeMax(1024 * 1024);
try {
List items = upload.parseRequest(request);
Iterator iter = items.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
if (!item.isFormField()) {
try {
String fileName = new File(item.getName()).getName();
String filePath = uploadFolder + File.separator + fileName;
File uploadedFile = new File(filePath);
item.write(uploadedFile);
//do something...
}
catch(Exception e) {
//...
}
}
}
getServletContext().getRequestDispatcher(forwardUrl).forward(
request, response);
} catch (FileUploadException ex) {
throw new ServletException(ex);
} catch (Exception ex) {
throw new ServletException(ex);
}
Thank you in advance :)
What do you mean with the request is consumed ? The request passes through the Interceptor Stack up to the Action, and is still there.
If, for some reason (and you should not have one, when doing a simple upload of a file), you need to run code out of the framework mechanisms (Actions, Interceptors etc), you can use a Servlet.
By the way, this is the correct way of uploading a file in Struts2, and your problem is mostly related to
the maximum file/request cap hit;
a wrong definition of the interceptor stack.
I bet on n.1, but if this still haven't solved your problem, post more details about your struts.xml.
Also remember to avoid using scriptlets (as already suggested by Boris) and to never call JSPs directly: always pass through an Action.
Related
I want to extend an existing application with a drag and drop file upload feature. The application is built upon Jetty + Wicket. DropzoneJS seems a good way to go. Dropzone provides all front-end work, I just have to wire it up to the back-end.
More easily said than done, as it turns out. First, I created a test application with the Wicket quickstart. I added dropzone to the HomePage:
<!DOCTYPE html>
<html>
<head>
<script src="https://rawgit.com/enyo/dropzone/master/dist/dropzone.js"></script>
<link rel="stylesheet" href="https://rawgit.com/enyo/dropzone/master/dist/dropzone.css">
</head>
<body>
<form action="/upload" class="dropzone"></form>
</body>
</html>
Dropzone is simply included from its repository. On the server, I mounted a resource reference at /upload:
public class FileUploadResourceReference extends ResourceReference
{
public FileUploadResourceReference(String name)
{
super(FileUploadResourceReference.class, name);
}
#Override
public IResource getResource()
{
return new FileUploadResource();
}
}
FileUploadResource will handle processing of uploaded files:
public class FileUploadResource extends AbstractResource
{
#Override
protected ResourceResponse newResourceResponse(Attributes attributes)
{
ServletWebRequest request = (ServletWebRequest) attributes.getRequest();
try
{
MultipartServletWebRequest multipartRequest = request
.newMultipartWebRequest(Bytes.megabytes(100), "ignored");
Map<String, List<FileItem>> files = multipartRequest.getFiles();
List<FileItem> fileItems = files.get("file");
for (FileItem fileItem : fileItems)
{
saveFile(fileItem);
}
}
catch (FileUploadException e)
{
e.printStackTrace();
}
return null;
}
private void saveFile(FileItem fileItem)
{
// not implemented
}
}
Now here's the problem, when uploading files, Dropzone sends a POST-request to my http://localhost:8080/upload. The request is recognized as a multipart request, but the file parameter is absent. A null pointer exception is thrown entering the for-loop:
java.lang.NullPointerException
at com.test.FileUploadResource.newResourceResponse(FileUploadResource.java:31) ~[classes/:?]
at org.apache.wicket.request.resource.AbstractResource.respond(AbstractResource.java:629) ~[wicket-core-7.4.0.jar:7.4.0]
at org.apache.wicket.request.handler.resource.ResourceRequestHandler.respond(ResourceRequestHandler.java:105) ~[wicket-core-7.4.0.jar:7.4.0]
at org.apache.wicket.request.handler.resource.ResourceReferenceRequestHandler.respond(ResourceReferenceRequestHandler.java:108) ~[wicket-core-7.4.0.jar:7.4.0]
I can't figure out what's going on here. According to the Dropzone website, the form declaration should be fine. A bug in Dropzone perhaps? Seems unlikely. Some Jetty configuration parameter that is denying multipart form requests? Seems highly unlikely, at least I've never heard of it.
You can find full source code of my test app on GitHub.
You miss one method call - multipartRequest.parseFileNames().
You need to do it before #getFiles().
See http://wicketinaction.com/2012/11/uploading-files-to-wicket-iresource/
I am using a catch-all servlet and passing the request object along to other internal framework classes. Its how my application is designed. The reasons are beyond the scope of this question.
#WebServlet(name="RequestHandler", urlPatterns="/*")
I am trying to do file uploading from the browser using multipart-form-data:
<form action="" method="POST" enctype="multipart/form-data">
<input type="file" name="file"/>
<input type="submit" name="videoUpload" value="Upload"/>
</form>
And the only way to actually pass the file data along to the server is to annotate the servlet with:
#MultipartConfig
If I annotate my catch-all servlet, everything works fine but its not very often at all that I actually need to use the file uploading functionality.
Option 1: Leave it alone.
Does leaving the annotation cause unnecessary overhead even though most of the requests don't use it?
Option 2: Add it programatically?
Is there a way to programatically add the annotation if the form type of multipart is detected?
Option 3: Use the annotation elsewhere.
What about using the annotation in a separate class (i'm assuming it needs to be present before the request object is actually created...)?
It is ok if you dont add '#MultipartConfig' annotation. You can determine programmatically if the content is multipart or not:
String form_field="";
FileItem fileItem = null;
if (ServletFileUpload.isMultipartContent(request)) {
ServletFileUpload servletFileUpload = new ServletFileUpload(new DiskFileItemFactory());
try {
fileItemsList = servletFileUpload.parseRequest(request);
} catch (FileUploadException ex) {
out.print(ex);
}
String optionalFileName = "";
Iterator it = fileItemsList.iterator();
while (it.hasNext()) {
FileItem fileItemTemp = (FileItem) it.next();
if (fileItemTemp.isFormField()) {
if (fileItemTemp.getFieldName().equals("form_field")) {
form_field = fileItemTemp.getString();
}
} else {
if (fileItemTemp.getFieldName().equals("file")) {
fileItem = fileItemTemp;
}
}
}
}
If ServletFileUpload.isMultipartContent(request) is false then you can retrieve form parameters in general way by request.getParameter. I have used apache file upload in the example.
I have a Java Dynamic Web Project, and I'm using TomCat v7.0.
I am new to web projects and I didn't quite understand how I can upload a file in one of my jsp pages. Since my project is intended to be only local, I thought I could use a multipart form in which the person would choose the file (and this part goes fine) and later retreive the file path from my Servlet. I can't complete this part though, it appears to only give me the name of the file, not its entire path.
Can anyone point me to the right direction? I've read several posts about Apache File Upload and retreiving information from the multipart form but nothing seems to help me.
How can I get the file path from a form or alternatively how can I get the uploaded file to use in my Java classes?
Thanks in advance.
.jsp:
<form method="post" action="upload" enctype="multipart/form-data">
<input type="file" name="filePath" accept="application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"></input>
<input type="submit" value="Enviar"></input>
</form>
Java Servlet:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
PrintWriter out = response.getWriter();
out.println("<html><body>");
try
{
List<FileItem> items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request);
for (FileItem item : items)
{
if (item.isFormField())
{
// Process regular form field (input type="text|radio|checkbox|etc", select, etc).
String fieldname = item.getFieldName();
String fieldvalue = item.getString();
out.println("<h1>"+fieldname+" / "+fieldvalue+"</h1>");
}
else
{
// Process form file field (input type="file").
String fieldname = item.getFieldName();
String filename = item.getName();
InputStream filecontent = item.getInputStream();
String s = filecontent.toString();
out.println("<h1>"+s+" / "+filename+"</h1>");
item.write(null);
}
}
}
catch (FileUploadException e)
{
throw new ServletException("Cannot parse multipart request.", e);
}
catch (Exception e)
{
e.printStackTrace();
}
out.println("</body></html>");
}
Not providing the file path is a security feature of the browser.
You have the file contents available in your code (InputStream filecontent) so you could use that or use one of the convenience methods on FileItem, e.g.
item.write(new File("/path/to/myfile.txt"));
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to upload a file using Java HttpClient library working with PHP - strange problem
I'm trying to create a script that can automatically submit a form on a website with two fields: title and description and a file input where I should upload an image.
The last days I've searched every page I found on google but I can't solve my problem...
I also need to post a cookie, I've made the cookie using:
connection.setRequestProperty("Cookie", cookie); //this worked
But I have problems submitting the form, first I'we tried using HttpUrlConnection, but I was unable to figure it out, now I'm trying to solve my problem using HttpClient
The html form looks like this:
<form action="submit.php" method="post" enctype="multipart/form-data">
<input type="text" name="title">
<input name="biguploadimage" type="file">
<textarea name="description"></textarea>
<input type="image" src="/images/submit-button.png">
</form>
My image is located at d:/images/x.gif
Please provide me a full code because I'm new to java.
O, and how to create the cookie using HttpClient ?
Thanks a lot in advice!
This url might help you to solve your problem. It's not that straightforward otherwise I would have pasted the code here. upload files in java
You could also look at this question here
similar question on stackoverflow
There is good article with code examples: http://www.theserverside.com/news/1365153/HttpClient-and-FileUpload
Pay attention to MultipartPostMethod. This will allow you to post file and another data in one request.
How to do simple POST with many parameters described there: http://hc.apache.org/httpclient-3.x/methods/post.html
I recently did this using Spring Web MVC and Apache Commons FileUpload:
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.commons.fileupload.*;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
(...)
#RequestMapping(method = RequestMethod.POST)
public ModelAndView uploadFile(HttpServletRequest request, HttpServletResponse response) {
ModelAndView modelAndView = new ModelAndView("view");
if (ServletFileUpload.isMultipartContent(request)) {
handleMultiPartContent(request);
}
return modelAndView;
}
private void handleMultiPartContent(HttpServletRequest request) {
ServletFileUpload upload = new ServletFileUpload();
upload.setFileSizeMax(2097152); // 2 Mb
try {
FileItemIterator iter = upload.getItemIterator(request);
while (iter.hasNext()) {
FileItemStream item = iter.next();
if (!item.isFormField()) {
File tempFile = saveFile(item);
// process the file
}
}
}
catch (FileUploadException e) {
LOG.debug("Error uploading file", e);
}
catch (IOException e) {
LOG.debug("Error uploading file", e);
}
}
private File saveFile(FileItemStream item) {
InputStream in = null;
OutputStream out = null;
try {
in = item.openStream();
File tmpFile = File.createTempFile("tmp_upload", null);
tmpFile.deleteOnExit();
out = new FileOutputStream(tmpFile);
long bytes = 0;
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
bytes += len;
}
LOG.debug(String.format("Saved %s bytes to %s ", bytes, tmpFile.getCanonicalPath()));
return tmpFile;
}
catch (IOException e) {
LOG.debug("Could not save file", e);
Throwable cause = e.getCause();
if (cause instanceof FileSizeLimitExceededException) {
LOG.debug("File too large", e);
}
else {
LOG.debug("Technical error", e);
}
return null;
}
finally {
try {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
catch (IOException e) {
LOG.debug("Could not close stream", e);
}
}
}
This saves the uploaded file to a temp file.
If you don't need all the low-level control over the upload, it is much simpler to use the CommonsMultipartResolver:
<!-- Configure the multipart resolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="2097152"/>
</bean>
An example form in the jsp:
<form:form modelAttribute="myForm" method="post" enctype="multipart/form-data">
<form:input path="bean.uploadedFile" type="file"/>
</form>
The uploadedDocument in the bean is of the type org.springframework.web.multipart.CommonsMultipartFile and can be accessed direcly in the controller (the multipartResolver automatically parses every multipart-request)
I want to upload a file in struts1 application.
Currently the implementation is using File, like this:
<html:file property="upload"/>
But this does not allow to upload file if app is accessed from remote machine as this widget passes only the name of the file instead the whole file.
using only <html:file property="upload" /> will not make your application to upload a file.
to support upload functionality,your form must have enctype="multipart/form-data"
<html:form action="fileUploadAction" method="post" enctype="multipart/form-data">
File : <html:file property="upload" />
<br/`>
<html:submit />
</html:form`>
and in action get file from your form bean and manipulate it as follows
YourForm uploadForm = (YourForm) form;
FileOutputStream outputStream = null;
FormFile file = null;
try {
file = uploadForm.getFile();
String path = getServlet().getServletContext().getRealPath("")+"/"+file.getFileName();
outputStream = new FileOutputStream(new File(path));
outputStream.write(file.getFileData());
}
finally {
if (outputStream != null) {
outputStream.close();
}
}