I need to read a file located on a server but I see that in GWT is not possible use some java library.
what I have to do?
try requestBuilder!! this code can help?
RequestBuilder requestBuilder = new RequestBuilder( RequestBuilder.GET, "yourfile.txt" );
try {
requestBuilder.sendRequest( null, new RequestCallback(){
public void onError(Request request, Throwable exception) {
GWT.log( "failed file reading", exception );
}
public void onResponseReceived(Request request, Response response) {
String result=response.getText();
}} );
} catch (RequestException e) {
GWT.log( "failed file reading", e );
}
The Rule: JavaScript cannot read data from a URL that doesn’t have a host name and port that matches those of the page the JavaScript is running in.
In other words: If it is on a different site — you can’t read it directly with JS and therefore GWT, which is nothing more than Javascript once compiled.
It applies to data from XMLHttpRequest, frames, and anything else you care to name.
This may change in the future, but for now the rule stands.
With this in mind there are a couple of workarounds.
1) Call your server with RPC or whatever mechanism and have your server do the request and then send it back to the client. Here is a sample.
2) There are several hacks on allowing JavaScript to access cross-domain sites just do a google search on how to get this. Some browsers will flag this as being dangerous.
3) If you are using Firefox and Firefox only it looks like Firefox has the ability to do this, but you will need to enable this manually.
Simply write first a servlet that sends the file located on the server to the user.
Then when the user clicks on a button for instance you call the servlet with the proper parameter.
Here is an excerpt from our servlet implementation
response.reset();
response.setContentType("application/octet-stream");
response.setContentLength(contentLength);
response.setHeader("Content-disposition", "attachment;
filename=\"" + filename + "\"");
output = new
BufferedOutputStream(response.getOutputStream());
int data = input.read();
while (data != -1)
{
output.write(data);
data = input.read();
}
output.flush();
Related
There is an API that downloads Excel files. Whenever we click on the 'Download excel report' button, it calls this API which gets data from the database, transfers it to an Excel file, and downloads it.
excelName = key + ".xlsx";
response.setHeader("Content-Disposition", "attachment; filename=" + excelName);
ByteArrayInputStream in = getDownloadBusinessAnalysisKey(key, customerScopeId, response, getBusinessKeyResult, sheetName);
response.setHeader("Content-Length", String.valueOf(in.available()));
try {
FileCopyUtils.copy(in, response.getOutputStream());
} catch (IOException e) {
logger.error("Error in report " + e.getLocalizedMessage());
}
It downloads fine when there are about 10,000 records (or close to it).
However, when there are about 100,000 records it just doesn't download. I get no response from the endpoint. It works when trying to download the same file via Postman in local database.
Is there some limit on download size? Would this be a browser, Tomcat server, or HTTP header issue?
When you're using a ByteArrayInputSteam you're loading the whole data into memory. What needs to be done is to make getDownloadBusinessAnalysisKey store to a place you can stream, usually to a file. Then use FileInputStream to read the file and write it to the response output stream.
Based on your statement that you're using an API to download the Excel file, I am assuming it is not done inside your current JVM (otherwise I'd recommend you look up SXSSF which would require a bit of code change and rethinking to get it to work.
From your code sample it looks like you're using Servlet API as well based on the setHeader. So here's a bit of code that would make a get connection and more or less proxy it up. There's no need for a temporary file if it is just straight through, there's also no need to buffer unless you can confirm that the servlet engine does not provide you with buffered data.
protect void doGet(
HttpServletRequest req,
HttpServletResponse response)
throws ServletException, IOException {
var url = new URL("http://myapi");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
int responseCode = con.getResponseCode();
int len = con.getHeaderFieldInt("Content-Length",-1);
int contentType = con.getHeaderField("Content-Type", "application/octet-stream");
assert responseCode == 200
response.setIntHeader("Content-Length", len);
response.setHeader("Content-Type", contentType);
try (
InputStream is = con.getInputStream();
OutputStream os = response.getOutputStreeam();
) {
int c = is.read();
while (c != -1) {
os.write(c);
c = is.read();
}
}
}
This can be optimized by using Async Servlet APIs to reduce blocking I/O which would be needed if you are dealing with a lot of connections.
I think that the process to get data from db and fetch into excel taking too long time and it is longer than max response time of server. You should tuning the process getting data from db and fetching into excel, it will solve your issue.
I have created a zip file in my servlet. Now I would like to trigger that servlet using Ajax and prompt the download dialog to the user. I can trigger the servlet, but I don't know how to get the save dialog. How can I achieve this?
You can't "download a file using AJAX". AJAX is about downloading data from a server for JavaScript to process.
To let the user download the file either use a simple link to the file/servlet, or if you really, really need to use JavaScript, then assign the URL to document.location.href.
Also you need to make sure that the server (or in this case the servlet) sends the appropriate MIME type, in case of a ZIP file most likely application/zip.
You can't use Ajax for this. You basically want to let the enduser save the file content to the local disk file system, not to assign the file content to a JavaScript variable where it can't do anything with it. JavaScript has for obvious security reasons no facilities to programmatically trigger the Save As dialog whereby the file content is provided from an arbitrary JavaScript variable.
Just have a plain vanilla link point to the servlet URL and let the servlet set the HTTP Content-Disposition header to attachment. It's specifically this header which will force the browser to pop a Save As dialog. The underlying page will stay same and not get refreshed or so, achieving the same experience as with Ajax.
Basically:
download file
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// ...
response.setHeader("Content-Type", getServletContext().getMimeType(fileName));
response.setHeader("Content-Disposition", "attachment;filename=\"" + fileName + "\"");
// ...
}
That could also be done in JavaScript as below without firing a whole Ajax call:
window.location = "fileservlet/somefilename.zip";
Alternatively, if you're actually using POST for this, then use a (hidden) synchronous POST form referring the servlet's URL and let JavaScript perform a form.submit() on it.
See also:
Simplest way to serve static data from outside the application server in a Java web application
Abstract template for a static resource servlet
function down() {
var url = "/Jad";
var xmlhttp;
if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
} else {// code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function() {
//alert("xmlhttp.status" + xmlhttp.status);
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
}
}
xmlhttp.open("GET", url, true);
xmlhttp.send();
var elemIF = document.createElement("iframe");
elemIF.src = url;
elemIF.style.display = "none";
document.body.appendChild(elemIF);
}
On my company's site we have some tables that we need to export to a csv file.
There are some varying parameters, so the csv file needs to be dynamically created on request.
My problem is that after clicking to download, the response hangs, and waits for the whole file to be created (which can take some time) and only then downloads the entire file in one instant.
I'm using AngularJS, so I'm using window.location = <url_for_file_download> In order to make the browser download the file.
On the server side I'm using Java Spring and I've followed all the instructions I could find on the web in order to create a file download controller.
My controller code is something like this:
#RequestMapping(value = "http://yada.yada.yada/csv/myFile.csv", method = RequestMethod.GET)
public #ResponseBody
void getCustomers(HttpServletResponse response,
#RequestParam(required = false) String someParameters)
throws NotAuthorizedException, IOException {
// set headers
setHeaders(response);
// generate writer
CSVWriter write = generateWriter(response);
// get data
List<String[]> data = getData();
// write and flush and all that
.
.
.
}
My code for setting the response headers are:
response.setContentType("text/csv;charset=utf-8");
response.setHeader("Content-Disposition","attachment; filename=\"" + fileName + ".csv\"");
I've also tried adding the following headers:
response.setHeader("Transfer-Encoding", "Chunked");
response.setHeader("Content-Description", "File Transfer");
and I've also tried setting the Content-type to "application/octet-stream".
Notice that I don't add a Content-length header, since the file doesn't exist yet, and is being written on the fly.
For writing the csv file I'm using OpenCSV and my code is as follows:
OutputStream resOs = response.getOutputStream();
OutputStream buffOs = new BufferedOutputStream(resOs);
OutputStreamWriter outputWriter = new OutputStreamWriter(buffOs,"UTF-8");
CSVWriter writer = new CSVWriter(outputWriter);
I iterate over the data and write it like so:
for (String[] row: data) {
writer.writeNext(line);
}
(It's not exactly the code - but this is more or else what happens in the code)
And at the end I flush and close:
writer.flush();
writer.close();
I also tried flushing after each line I write.
So why isn't the file being transferred before it has all been written?
Why is my browser (Google chrome) downloading the file in one instant after waiting a long time? And how can I fix this.
I hope I've added enough code, if there's something missing just please tell me and I'll try to add it here.
Thank you so much in advance.
Can you try returning a null value in your java
return null ;
Or you can try below code also
1. Jquery code upon clicking the submit button
$(document).ready( function() {
$('#buttonName').click(function(e){
$("#formName").submit();
//alert("The file ready to be downloaded");
});
});
Your controller code
#RequestMapping(value="/name",method=RequestMethod.POST)
public ModelAndView downloadCSV(ModelMap model,HttpSession session,#ModelAttribute(value="Pojo") Pojo pojo
,HttpServletRequest request,HttpServletResponse response){
----------------some code----------------
response.setContentType("application/csv");
("application/unknown");
response.setHeader("content-disposition","attachment;filename =filename.csv");
ServletOutputStream writer = response.getOutputStream();
logger.info("downloading contents to csv");
writer.print("A");
writer.print(',');
writer.println("B");
for(int i=0;i<limit;i++){
writer.print(""+pojo.get(i).getA());
writer.print(',');
writer.print(pojo.get(i).getB());
writer.println();
}
writer.flush();
writer.close();
---------------some code-----------
return null;
}
Hope this helps
The Controller will wait for the response to be written before the response is send back to the client.
Here is a nice post with multiple approaches / options outlined
Downloading a file from spring controllers
This post talks about flushing the output periodically to help fasten the download.
how to download large files without memory issues in java
If all you are trying to do is let the user know that the file download is in progress and due soon, I think an Ajax progress status indicaor might be your solution.
Trigger the ajax call to the back-end to generate the file
Show progress indicator to the user while file is being generated server side
once response is available, file is presented to the user.
I think something similar is being explored here download file with ajax() POST Request via Spring MVC
Hope this helps!
Thanks,
Paul
I faced the same issue. The code that didn't work for me was
#RequestMapping(value = "/test")
public void test(HttpServletResponse response)
throws IOException, InterruptedException {
response.getOutputStream().println("Hello");
response.getOutputStream().flush();
Thread.sleep(2000);
response.getOutputStream().println("How");
response.getOutputStream().flush();
Thread.sleep(2000);
response.getOutputStream().println("are");
response.getOutputStream().flush();
Thread.sleep(2000);
response.getOutputStream().println("you");
response.getOutputStream().flush();
}
The culprit was ShallowEtagHeaderFilter. When this filter is enabled the response is sent in one chunk. When this filter is diabled the response is send in multiple chunks.
From this thread Tomcat does not flush the response buffer it looks like another possible culprit can be GzipFilter
I am using Spring with DWR . I want to return a file object as response , however I save the file (to be sent) at server temporary location and then send its location as href for anchor tag on client side , however I wonder if there could be a way to throw the file directly to browser on response object without saving it temporarily on server.
I expected if there could be a way to send file as a response via DWR.
public ModelAndView writeFileContentInResponse(HttpServletRequest request, HttpServletResponse response) throws IOException {
FileInputStream inputStream = new FileInputStream("FileInputStreamDemo.java"); //read the file
response.setHeader("Content-Disposition","attachment; filename=test.txt");
try {
int c;
while ((c = inputStream.read()) != -1) {
response.getWriter().write(c);
}
} finally {
if (inputStream != null)
inputStream.close();
response.getWriter().close();
}
}
It has been years since I've used Spring, and I'm unfamiliar with DWR, but the essence of your question is basic to the web.
The answer is yes, you can. In effect, you need to set the HTTP header Content-Disposition: attachment, then stream down the contents. All of this will be in the response to the original request (as opposed to sending back a link).
The actual code to achieve this will depend on your circumstances, but this should get you started.
you call the method from Java Script, right? I didn't really understand how Spring is related in this flow, but as far as I know DWR allows you to produce Java Script Stubs and call the Java methods of the exposed bean directly on server right from your java script client code.
You can read the file byte-by-byte and return it from your java method as long as it really returns a byte array.
However what would you do with this byte array on client?
I just think in this specific flow you shouldn't use the DWR but rather issue an ordinar AJAX request (if DWR can wrap it somehow for convenience - great). This request shouldn't come to DWRServlet, but rather be proceeded by a regular servlet/some web-based framework, like Spring MVC :)
Once the request comes to the servlet, use
response.setHeader("Content-Disposition","attachment; filename=test.txt");
as was already stated.
Hope this helps,
Good luck!
Mark
An example which return a excel to download from client:
//Java side:
public FileTransfer getExcel(Parametros param){
byte[] result = <here get data>;
InputStream myInputStream = new ByteArrayInputStream(result);
String excelFormat = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
FileTransfer dwrExcelFile = new FileTransfer("excel.xlsx", excelFormat, myInputStream);
return dwrExcelFile;
}
//Javascript side:
function downloadExcelFile() {
dwr.engine.setTimeout(59000);
var params = <params_to_send>;
<Java_class>.getExcel(params, {callback:function(dataFromServer) {
downloadExcelCallback(dataFromServer);
}});
}
function downloadExcelCallback(data) {
dwr.engine.openInDownload(data);
}
Is there some trick to getting a SpringMVC custom view to cause a file download in the broswer? I've implemented the render method from org.springframework.web.servlet.View but the code results in my data being written to the page as a blob of data rather having a download action start.
try {
Document oDoc = (Document) model.get("oDoc");
out = new PrintWriter(response.getOutputStream());
response.setContentType("application/vnd.ms-excel");
response.setHeader("content-disposition", "attachment; filename=file.xls");
GenerateXLSFile gof = new GenerateXLSFile();
gof.outputTSVFromDom(out, oDoc);
} catch block here {
//writes to log here
} finally {
if (out != null) {
out.flush();
out.close();
}
}
I know the render method is being called from the server logs. I know the GenerateXLSFile is being created from the server logs. I know the outputTSVFromDom can take a document and transform it work from my JUnit test. It also writes to the server log and completes. The data ends up in the browser. The HTTP Headers looks normal according to firebug. No errors from the catch block are in the server log.
What am I missing here?
First of all, which API are you using? Excel documents are binary, so you should use OutputStream, not Writer.
Second, Spring has a built in support for serving Excel documents:
AbstractExcelView, based on the Apache POI API
AbstractJExcelView, based on the JExcel API