I'm trying to download a file from the server with an Ext JS 6 component based on this post: download a file via Ext js 4
This is the component code:
Ext.define('Aft.view.search.FileDownload', {
extend: 'Ext.Component',
alias: 'widget.acw-fileDownload',
autoEl: {
tag: 'iframe',
cls: 'x-hidden',
src: Ext.SSL_SECURE_URL
},
load: function(config){
var e = this.getEl();
e.dom.src = config.url +
(config.params ? '?' + Ext.urlEncode(config.params) : '');
e.dom.onload = function() {
if(e.dom.contentDocument.body.childNodes[0].wholeText == '404') {
console.
Ext.create('Acw.view.commons.notifications.Error', {
html: 'The document you are after can not be found on the server.',
closeAll: true
}).show();
}
}
}
});
This is the call to get the file:
doExportData: function(){
this.getView().load({
url: '/aft/faults/download-file'
});
And this is the Spring rest service returning a mock file:
#RequestMapping(value = "/download-file", method = RequestMethod.POST)
public void downloadFilePost(HttpServletResponse response) {
String csvFileName = "searchFaults.csv";
response.setContentType("text/csv");
// creates mock data
String headerKey = "Content-Disposition";
String headerValue = String.format("attachment; filename=\"%s\"", csvFileName);
response.setHeader(headerKey, headerValue);
try {
CSVWriter writer = new CSVWriter(response.getWriter(), '\t');
String[] entries = "first#second#third".split("#");
writer.writeNext(entries);
writer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
However when I do the call I get something like this:
[E] Ext.JSON.decode(): You're trying to decode an invalid JSON String: "first" "second" "third"
Uncaught Error: You're trying to decode an invalid JSON String: "first" "second" "third"
It seems that something arrives to the client, but it is trying to parse it as JSON. In spite of this, if I change the RequestMethod to GET and I type the URL directly in the browser I get the file and that makes me think that the header is right.
Could someone help me with this issue, or are you using a different approach/component to download files from the server?
The file can be downloaded just with this code:
doExportData: function(config){
window.location.assign(config.url +
(config.params ? '?' + Ext.urlEncode(config.params) : ''));
});
Related
I am currently developing small project in Angular JS + Java, where user is registering his information with his profile picture using rest webservice. Everything is working fine, except in case of special character(Ä Ö Ü ä ö).
Java :
#POST
#Path("add_employee")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_JSON)
public Response addEmployee(MultipartFormDataInput input) {
try {
Map<String, List<InputPart>> formDataMap = input.getFormDataMap();
if (formDataMap != null && !formDataMap.isEmpty()) {
InputPart inputPart = formDataMap.get("EmployeeProxy").get(0);
ObjectMapper mapper = new ObjectMapper();
//receiving wrong json below=>
EmployeeProxy admbo = mapper.readValue(inputPart.getBodyAsString(), EmployeeProxy.class);
List<InputPart> profilePic = formDataMap.get("profilePic");
.
.
.
} else {
return Response.status(Response.Status.NOT_FOUND).build();
}
} catch (Exception ex) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
}
Angular JS :
var fd = new FormData();
fd.append('EmployeeProxy', angular.copy(JSON.stringify($scope.empInfo)));
fd.append('profilePic', $scope.myFile);
$http.post(Server.url + 'add_employee', fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
}).then(function (response) {
});
Sending Json : {"empName": "Ä Ö Ü ä ö","empSurname": "XYZ","emailId":
"abc#gmail.com"}
Receiving Json : {"empName": "�� �� �� �� �� ��","empSurname":
"XYZ","emailId": "abc#gmail.com"}
Please find below image for request header information :
This is working fine, if I am using APPLICATION_JSON without MULTIPART_FORM_DATA.
If your Content-Type header is undefined, RestEasy cannot identify the charset to use and will fallback to a default (us-ascii).
See also:Overwriting the default fallback content type for multipart messages
Edit after reading up on this: It should be the multipart body which specifies the Content-Type in order for RestEasy to parse the individual strings.
In the documentation of FormData it can be done in the following way:
Angular JS :
fd.append('EmployeeProxy', new Blob([angular.copy(JSON.stringify($scope.empInfo))], { type: "text/plain; charset=iso-8859-1"}));
Java :
String json = IOUtils.toString(inputPart.getBody(InputStream.class, null), StandardCharsets.UTF_8);
EmployeeProxy admbo = mapper.readValue(json, EmployeeProxy.class);
Sample C# code:
static void UploadFile(string sasUrl, string filepath)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("x-ms-version", Version);
client.DefaultRequestHeaders.Add("x-ms-client-request-id", SessionGuid);
StringBuilder sb = new StringBuilder("<?xml version=\"1.0\" encoding=\"utf-8\"?><BlockList>");
foreach (byte[] chunk in GetFileChunks(filepath))
{
var blockid = GetHash(chunk);
HttpRequestMessage chunkMessage = new HttpRequestMessage()
{
Method = HttpMethod.Put,
RequestUri = new Uri(sasUrl + "&timeout=90&comp=block&blockid=" + WebUtility.UrlEncode(blockid)),
Content = new ByteArrayContent(chunk)
};
chunkMessage.Headers.Add("x-ms-blob-type", "BlockBlob");
chunkMessage.Content.Headers.Add("MD5-Content", blockid);
TimeAction("Uploading chunk " + blockid + " took {0} ms", () =>
{
var response = client.SendAsync(chunkMessage).Result;
});
sb.Append("<Latest>");
sb.Append(blockid);
sb.Append("</Latest>");
}
sb.Append("</BlockList>");
Trace.WriteLine(sb.ToString());
HttpRequestMessage commitMessage = new HttpRequestMessage()
{
Method = HttpMethod.Put,
RequestUri = new Uri(sasUrl + "&timeout=90&comp=blocklist"),
Content = new StringContent(sb.ToString())
};
TimeAction("Commiting the blocks took {0} ms", () =>
{
var commit = client.SendAsync(commitMessage).Result;
});
}
}
I am stuck at the point where I've to upload a file. Also want to know what the reason is to commit in given code?
my progress so far is :
public static void uploadFile(String sasUrl , String filepath , String sessionGuid)
{
File file = new File(filepath);
FileInputStream fileInputStream=null;
Response reply = new Response();
HttpClient client = HttpClientBuilder.create().build();
HttpPost request = new HttpPost(sasUrl);
request.setHeader("x-ms-version", "2013-08-15");
request.setHeader("x-ms-client-request-id", sessionGuid);
StringBuilder sb = new StringBuilder("<?xml version=\"1.0\" encoding=\"utf-8\"?><BlockList>");
}
}
Note: I cannot run the code multiple times as I cannot spam the server. Any suggestions will be appreciated
Referring to : https://msdn.microsoft.com/en-us/library/windows/hardware/dn800660(v=vs.85).aspx
According to the reference code in C#, it seems to be using the REST API Put Block List to upload a file as a block blob.
So you can refer to the REST API reference without refering to the C# sample to use httpclient to construct the request for uploading.
However, the simple way is using Azure Storage SDK for Java. To upload a file, you just need to use the class CloudBlockBlob to upload a file with the function upload(InputStream sourceStream, long length), please refer to the tutorial https://azure.microsoft.com/en-us/documentation/articles/storage-java-how-to-use-blob-storage/#upload-a-blob-into-a-container.
The sas url seems like https://myaccount.blob.core.windows.net/mycontainer/myblob?comp=blocklist&...
Here is the code as example.
URL sasUrl = new URL("<sas-url>");
try
{.
CloudBlockBlob blob = new CloudBlockBlob(sasUrl)
File source = new File(filePath);
blob.upload(new FileInputStream(source), source.length());
}
catch (Exception e)
{
// Output the stack trace.
e.printStackTrace();
}
As reference, please see the javadocs for Azure Java Storage SDK.
Hi I want to display server side image dynamically in browser using ajax.
but images is not coming.
i have checked the server code in debugging mode its working fine but not sure about client code.
readyState coming as 4 but image is not getting displayed.
Server code :
File f = new File("D:\\mapping events\\Camping\\"+(String) request.getParameter("imageName")+"\\"+"01.jpg");
DataInputStream dis = new DataInputStream(new FileInputStream(f));
byte[] barray = new byte[(int) f.length()];
try
{
dis.readFully(barray); // now the array contains the image
}
catch (Exception e)
{
barray = null;
}
finally
{
dis.close( );
}
sos.write(barray); // send the byte array to client
System.out.println(barray);
sos.close();
Ajax code :
$.ajax({
url: 'GetCampingImages',
type: 'POST',
data:{
imageName:allData[0]
},
cache: true,
dataType: 'json',
success: function(jqXHR)
{
if(jqXHR)
{
if (jqXHR.readyState == 4) {
$('#dynamicCamping01').html('<img src="data:image/jpeg;'+jqXHR.reresponseText+'"/> ');
$('#dynamicCampingDesc01').html("<h3>"+allData[0]+"</h3>");
}
}
else
{
alert("Something went wrong while retriving events");
}
},
error: function(jqXHR)
{
console.log('ERRORS in server: ' );
}
You should encode the binary data using base64, and use the scheme: "data:image/jpeg;base64,...". Directly sending data bytes is not a good idea for jpeg files.
I am creating a web application using the Spark Java framework. The front-end is developed using AngularJS.
I want to generate a .docx file on the server (in-memory) and send this to the client for download.
To achieve this I created an angular service with the following function being called after the user clicks on a download button:
functions.generateWord = function () {
$http.post('/api/v1/surveys/genword', data.currentSurvey).success(function (response) {
var element = angular.element('<a/>');
element.attr({
href: 'data:attachment;charset=utf-8;application/vnd.openxmlformats-officedocument.wordprocessingml.document' + response,
target: '_blank',
download: 'test.docx'
})[0].click();
});
};
On the server, this api call gets forwarded to the following method:
public Response exportToWord(Response response) {
try {
File file = new File("src/main/resources/template.docx");
FileInputStream inputStream = new FileInputStream(file);
byte byteStream[] = new byte[(int)file.length()];
inputStream.read(byteStream);
response.raw().setContentType("data:attachment;chatset=utf-8;application/vnd.openxmlformats-officedocument.wordprocessingml.document");
response.raw().setContentLength((int) file.length());
response.raw().getOutputStream().write(byteStream);
response.raw().getOutputStream().flush();
response.raw().getOutputStream().close();
return response;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
I have tried to solve this in MANY different ways and I always end up with a corrupted 'test.docx' that looks like this:
Solved it by using blobs and specifying the response type as 'arraybuffer' in the $http.post api call. The only bad thing with this solution (as far as I know) is that it doesn't play well with IE, but that's a problem for another day.
functions.generateWord = function () {
$http.post('/api/v1/surveys/genword', data.currentSurvey, {responseType: 'arraybuffer'})
.success(function (response) {
var blob = new Blob([response], {type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'});
var url = (window.URL || window.webkitURL).createObjectURL(blob);
var element = angular.element('<a/>');
element.attr({
href: url,
target: '_blank',
download: 'survey.docx'
})[0].click();
});
};
I think what went wrong was that the byte stream got encoded as plain text when I tried to create a URL with:
href: 'data:attachment;charset=utf-8;application/vnd.openxmlformats-officedocument.wordprocessingml.document' + response
thus corrupting it.
When using blobs instead, I get a "direct" link to the generated byte stream and no encoding is done on it since the response type is set to 'arraybuffer'.
Note that this is just my own reasoning of why things went wrong with the original code. I might be terribly wrong, so feel free to correct me if that's the case.
I don't know how to download a CSV file. The CSV will be generated at runtime. Do I need to save the file in the tomcat WEB-INF directory first? I'm using JSF 1.2.
By the way, what's the favored JSF component for this kind of task?
Edit (05.05.2012 - 15:53)
I tried the solution BalusC stated in his first link, but if I click on my commandButton the content of the file is displayed on the webpage. Maybe there's a problem with the mimetype?
xhtml-file:
<a4j:form>
<a4j:commandButton action="#{surveyEvaluationBean.doDataExport}" value="#{msg.srvExportButton}" />
</a4j:form>
main bean:
public String doDataExport() {
try {
export.downloadFile();
} catch (SurveyException e) {
hasErrors = true;
}
return "";
}
export-bean:
public void downloadFile() throws SurveyException {
try {
String filename = "analysis.csv";
FacesContext fc = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse) fc.getExternalContext().getResponse();
response.reset();
response.setContentType("text/comma-separated-values");
response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
OutputStream output = response.getOutputStream();
// writing just sample data
List<String> strings = new ArrayList<String>();
strings.add("filename" + ";" + "description" + "\n");
strings.add(filename + ";" + "this is just a test" + "\n");
for (String s : strings) {
output.write(s.getBytes());
}
output.flush();
output.close();
fc.responseComplete();
} catch (IOException e) {
throw new SurveyException("an error occurred");
}
}
Edit (05.05.2012 - 16:27)
I solved my problem. I have to use <h:commandButton> instead of <a4j:commandButton> and now it works!
Do I need to save the file in the tomcat WEB-INF directory first?
No, just write it straight to the HTTP response body as you obtain by ExternalContext#getResponseOutputStream() after having set the proper response headers which tells the browser what it's going to retrieve.
Do the math based on the concrete examples found in the following answers:
How to provide a file download from a JSF backing bean?
JSP generating Excel spreadsheet (XLS) to download
Basically:
List<List<Object>> csv = createItSomehow();
writeCsv(csv, ';', ec.getResponseOutputStream());
By the way, what's the favorite jsf-component for this kind of task?
This is subjective. But anyway, we're using <p:dataExporter> to full satisfaction.
If you are using JSF 2 you can use primefaces.
You can take a look at that link.
If not you can do it like that:
List<Object> report = new ArrayList<Object>(); // fill your arraylist with relevant data
String filename = "report.csv";
File file = new File(filename);
Writer output = new BufferedWriter(new FileWriter(file));
output.append("Column1");
output.append(",");
output.append("Column2");
output.append("\n");
//your data goes here, Replcae Object with your bean
for (Object row:report){
output.append(row.field1);
output.append(",");
output.append(row.field2);
output.append("\n");
}
output.flush();
output.close();