I would like to start a file download from a clickevent in my gwt web app. So I wrote a Servlet which writes the data to the output and should start the download. The data is received via http get.
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String data = request.getParameter("data");
String filename = request.getParameter("filename");
byte[] streamData = data.getBytes();
response.setContentType("application/force-download");
response.setHeader("Content-Disposition", "attachment; fileName="
+ filename + ".csv");
response.setContentLength(streamData.length);
ServletOutputStream out = response.getOutputStream();
out.write(streamData);
out.flush();
}
In the client I start the get method via requestBuilder.sendRequest():
RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET, /download");
requestBuilder.sendRequest("filename=dues&data="+ theDataAsString, new RequestCallback() {
#Override
public void onResponseReceived(Request request,
Response response) {
// Anything to do here?
}
#Override
public void onError(Request request, Throwable exception) {
exception.printStackTrace();
SC.warn("Error while creating export file.");
}
});
Nothing happens. But why? Shouldn't the browser ask to begin a download?
Does it, in this case, matter if i use post or get?
I don't want to use somthing like
Window.open("/download?data=myData&filename=filename", "_blank", "");
Any ideas?
On the client side, use an Anchor instead of a request builder and invoke the servlet directly.
Related
I have a simple servlet that can return a video file to the client. What I want to do is to download the file from a URL onto my server and then send that newly downloaded file to the client. My problem is the entrance point of the servlet is inside the doGet() method where the client requests the file. I want to download the file once and use it as a static file. However, because I call the download function inside my doGet(), while the client tries to get the file it keeps repeating everything that happen inside doGet() and my file keeps being overwritten. It really slows down the entire process. Is there anyway I can just call my download function once?
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException{
answerRequest(request, response);
}
...
public void answerRequest(HttpServletRequest request, HttpServletResponse response)
throws IOException{
String requestedFile = request.getPathInfo();
URL newURL = "fixed URL content";
HttpURLConnection connection = (HttpURLConnection) newURL.openConnection();
sendFile(connection, request, response);
}
...
public void sendFile(HttpURLConnection connection, HttpServletRequest request, HttpServletResponse response){
InputStream input = null;
FileOutputStream output = null;
File videoFile = new File("path-to-file");
input = connection.getInputStream();
output = new FileOutputStream(videoFile);
Utility.download(input, output, 0, connection.getContentLength()); //this is where the file is downloaded onto my server)
connection.disconnect();
close(output);
close(input);
//this is where the file is sent back to client
Utility.sendFile(videoFile, response, request,true);
...
}
So as you can see, all of those function happen every time doGet() happen. But I only want the Utility.download() to execute once. How would I do that?
You can add a boolean flag to Session variable. For example, when the do get is executed for the first Time:
boolean started = true;
Then right before you call Utility.sendFile() check whether the boolean flag is true or false and run the method accordingly.
I have implemented servlet which behaves not stable, sometimes it mixes header in content and writing same twice.
and sometimes it is returning file which contains response header mixed by content like this:
Server: Apache-Coyote/1.1
: W/"43-1353687036000"
DatCCoonntenntt--DDiissppoosittiioonn: : atatatacehnmte;n tf;i lfenlaemnea=m20=12201112211127325421_4W1_Wirnkgi_nSgc_Seern.xnlsx
sx
Content-Typ-eT: ype: applaipcatciaoti/on/toctestt-rstare
am
ConCtoententy-pTeype: appalicatcion/oon/octet-setarm
m
CCoonntent-Lnegtht h: 4199
Date: te: FriF,r i2,3 2No vNo2v0 120162: 215:25 :G4M2T
....
File content bytes ...
And again same header and content
UPDATE
*This situation happens on Tomcat7*
I have tested also on Tomcat6 and Jetty, in both cases there is no injection of HTTP-Header to response content but HTTP-Header is wrong and returns wrong file name, the file content is correct file. I have noticed that wrong return from servlet happens when
returns transfer-encoding is chunked.
When I am removing header stuff, and second part of bytes, it is valid file.
Is it possible that is synchronization issue ?
UPDATE
Here is full source of servlet :
public class ExcelDownloadServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
private static final Logger LOG = Logger
.getLogger (ExcelDownloadServlet.class);
#Override
protected void doGet (HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException
{
try
{
TransactionId transactionId = getTransactionId (request);
String fileName =
request.getParameter (GlobalConstants.EXCEL_FILE);
ExcelDownloadType downloadType =
ExcelDownloadType
.valueOf (request
.getParameter (GlobalConstants.EXCEL_DOWNLOAD_TYPE));
ActionContextFactory actionContextFactory =
ApplicationContext.getContext ()
.getActionContextFactory ();
//suppress warning. HttpServletRequest.getLocales does not support generics
#SuppressWarnings("unchecked")
ActionContext actionContext =
actionContextFactory.create (request.getSession ()
.getId (), Collections.<Locale> list (request
.getLocales ()));
GetExcelDataResponse dataResponse =
new GetExcelData (transactionId, fileName, downloadType)
.execute (actionContext);
writeToResponse (response, dataResponse.getFileName (),
dataResponse.getData ());
}
catch (InvalidSessionException e)
{
LOG.error ("Invalid session in Excel download", e);
throw new ServletException (e);
}
catch (ActionException e)
{
LOG.error ("Could not download into excel.", e);
throw new ServletException (e);
}
}
protected TransactionId getTransactionId (HttpServletRequest request)
{
return RequestParameterDeserializer.<TransactionId> deserialize (
request, GlobalConstants.TRANSACTION_ID);
}
protected void writeToResponse (HttpServletResponse response,
String rawFileName, byte[] data) throws IOException
{
ServletOutputStream sout = null;
try
{
response.setContentType ("application/octet-stream");
response.setContentLength (data.length);
// removing blanks from the file name, since FF cuts file names
// otherwise.
String fileNameWithTime = rawFileName.replaceAll (" ", "_");
response.setHeader ("Content-Disposition", "attachment; filename="
+ fileNameWithTime);
sout = response.getOutputStream ();
sout.write (data, 0, data.length);
}
finally
{
if (sout != null)
{
sout.close ();
}
}
}
UPDATE
*The call comes from GWT application when is generating the URL of servlet with required parameters and sets in IFrame, then servlet calls and file is downloading. Are there any suggestions ?*
I had a similar issue a long time ago.
It turned out that closing the ServletOutputStream triggered an unexpected behaviour on the request flow.
Servlets are not supposed to close the container provided OutputStream.
Another issue could be manually setting the content length, it is responsibility of the container producing the correct value.
To summarize, try removing out.close() and response.setContentLength()
I have a web application with a simple upload function. The idea is to allow user select a file and upon successfully upload, redirect to index.jsp.
However, although the file got uploaded, the response.redirect is not working. After a successfully upload, the page doesn't get redirected. It just stays there. The weird thing is that I can see it is processing the index.jsp from the tomcat server log even though it doesn;t get redirected.
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//processRequest(request, response);
boolean status=false;
if (!ServletFileUpload.isMultipartContent(request)) {
throw new IllegalArgumentException("Request is not multipart, please 'multipart/form-data' enctype for your form.");
}
ServletFileUpload uploadHandler = new ServletFileUpload(new DiskFileItemFactory());
PrintWriter writer = response.getWriter();
response.setContentType("text/plain");
try {
List<FileItem> items = uploadHandler.parseRequest(request);
for (FileItem item : items) {
if (!item.isFormField()) {
File file = new File(getServletContext().getRealPath("/WEB-INF/upload"), item.getName());
item.write(file);
writer.write("{\"name\":\"" + item.getName() + "\",\"type\":\"" + item.getContentType() + "\",\"size\":\"" + item.getSize() + "\"}");
}
}
//redirect to index.jsp if successfully
redirect(request, response);
} catch (FileUploadException e) {
throw new RuntimeException(e);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
writer.close();
}
}
The redirect method:
private void redirect(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.getRequestDispatcher("/index.jsp").forward(request, response);
}
The file upload plugin is from https://aquantum-demo.appspot.com/file-upload
I used the front-end and developed the upload event handler using java apache fileupload. Everything works fine except the redirect part.
The application.js file which handles the JSON returns:
$(function () {
// Initialize jQuery File Upload (Extended User Interface Version):
$('#file_upload').fileUploadUIX();
// Load existing files:
$.getJSON($('#file_upload').fileUploadUIX('option', 'url'), function (files) {
var options = $('#file_upload').fileUploadUIX('option');
options.adjustMaxNumberOfFiles(-files.length);
$.each(files, function (index, file) {
options.buildDownloadRow(file, options)
.appendTo(options.downloadTable).fadeIn();
});
});
});
Any ideas?
You're attempting to send two responses on a single request. One with JSON data in the response body and one which redirects the response to another request. This is not going to work. You can send only one response back per request. A redirect requires an untouched (uncommitted) response body, otherwise the redirect will just fail with IllegalStateException: response already committed in the server logs.
You need to move the redirect call from the servlet code to JavaScript code. Get rid of the redirect() line in the servlet and add the following line as the last line of the $.getJSON() callback function.
window.location = '/index.jsp';
This way JavaScript will take care of the redirect.
Good day!
I am trying to output a JPG file contained in the web application to the
user using the following code:
public class JpegOutput extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
byte bufferArray[] = new byte[1024];
ServletContext ctxt = getServletContext();
response.setContentType("image/jpeg");
ServletOutputStream os = response.getOutputStream();
InputStream is = ctxt.getResource("/WEB-INF/image/image1.jpg").openStream();
int read = is.read(bufferArray);
while (read != 1) {
os.write(bufferArray);
read = is.read(bufferArray);
}
is.close();
os.close();
}
}
But an error appears:
HTTP Status 500 -
exception java.lang.NullPointerException
I am not sure if it can't read the source image or something. Anyway, I put the image inside this folder /WEB-INF/image/image1.jpg
What am I doing wrong? How can I resolve this issue?
EDIT: I solved the problem by renaming the filename... the file name is case sensitive, instead of image1.jpg, it should be image1.JPG
Thank you.
You might use getServletContext().getRealPath("/") to get the path to /WEB-INF/. E.g.
String path = getServletContext().getRealPath("/") + "WEB-INF/image/image1.jpg";
InputStream is = new FileInputStream(path);
Though its not sure that this is the reason for the NPE. Can you check the log file and post the stacktrace?
Not sure about the error, but I think it would be better to forward the request rather than serve the image manually:
public class JpegOutput extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.getRequestDispatcher("/WEB-INF/image/image1.jpg")
.forward(request, response);
}
}
Also note that you content-serving loop is incorrect, the correct one looks like this:
while ((read = is.read(bufferArray)) != -1)
os.write(bufferArray, 0, read);
I have the following code...
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
final int idValue = Integer.parseInt(req.getParameter("id"));
final ProjectRunEntity projectRunEntity = projectDataService.findProjectRunEntity(idValue);
try {
final byte[] documentAsBytes = wordFileGenerationService.getDocumentAsBytes(projectRunEntity);
resp.setContentType("application/msword");
resp.setHeader("Content-Disposition", "inline; filename=example.doc;");
final ServletOutputStream out = resp.getOutputStream();
out.write(documentAsBytes);
out.flush();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Which gets some bytes which happen to be a word document and write them to the servlet response. For some reason I get the following message in my browser when I hit the url...
"HTTP Status 405 - HTTP method GET is
not supported by this URL"
I am on Tomcat 6. Any ideas? I know that nothing is breaking in my debugger, the bytes are being written to the outputstream of the response.
I guess the error is thrown by the default doGet implementation (when you call super.doGet(req, resp)).
That status is set in super.doGet(...). Please remove that call.
the do{Http-Method} methods are meant to be overridden. And their default implementation is "not supported". No need to call the super.do{http-Method}
I just had to remove this line...
super.doGet(req, resp);