File Download in javascript using AJAX call - javascript

This is my java script code for downloading the file from database on button click, when the button clicks this function calls. using ajax call i have moved to handler.
function DownloadDocument() {
var CurrentUserEmpId = CurrentSelectedUser;
Ext.Ajax.request({
url: "UploadAttachment.ashx?mode=DownloadDocument&EmployeeId=" + CurrentUserEmpId,
success: function (response) {
var data = response.responseText;
},
failure: function (form, action) {
}
});
}
Here comes the handler page, I have got bytes of my file to byte[] buffer. The problem here is download not working. I could't figure out the problem, since Iam a beginner. Please help with this, Thankyou.
case "DownloadDocument":
WebClient web = new WebClient();
try
{
byte[] buffer;
var query2 = #"select LLD_Decleration_doc from (select instance, Employee_id, lld_Decleration_doc, ROW_NUMBER() OVER(PARTITION BY Employee_id ORDER BY Update_Date DESC) Latest from [EManager].[dbo].[tax_benefit_declaration]) a where latest = 1 And Employee_id = #EmployeeId";
using (SqlConnection con = new SqlConnection(db.ConnectionString))
using (SqlCommand cmd = new SqlCommand(query2, con))
{
SqlParameter param = cmd.Parameters.Add("#EmployeeId", SqlDbType.Int);
param.Value = EmployeeId;
con.Open();
buffer = (byte[])cmd.ExecuteScalar();
con.Close();
}
HttpResponse response = HttpContext.Current.Response;
response.Clear();
response.ClearContent();
response.ClearHeaders();
response.Buffer = true;
response.ContentType = "APPLICATION/OCTET-STREAM";
String Header = "Attachment; Filename=NewFile";
response.AppendHeader("Content-Disposition", Header);
context.Response.BinaryWrite(buffer);
response.End();
}
catch { }
break;
}

This is something that it was said many times. You cant do this with Ajax call.
You can achive this by invoke hidden iframe for example:
var body = Ext.getBody();
var comp = body.getById('hiddenform-iframe-download');
if (!Ext.isEmpty(comp)) {
comp.remove();
}
body.createChild({
tag: 'iframe',
cls: 'x-hidden',
id: 'hiddenform-iframe-download',
name: 'iframe',
src: "yourContextToDownload?param1="+something
});

Related

How to upload multiple images from front-end using JavaScript, jQuery, Ajax in JSP file and send it into Spring Boot Controller?

I am working on a spring boot web application, where I want to upload multiple images of a product at a time along with other fields (for example product name, SKU code, category, tags, subcategory, etc). I have written code for RESTful API to upload multiple images and it is working perfectly for me. I tested API using postman and it is working fine. But, I don't know how to do it from the front end. I am showing you my front-end code below, where I am sending a single image to my controller using Ajax.
$("#file").change(function(){
var formData = new FormData();
var fileSelect = document.getElementById("file");
if(fileSelect.files && fileSelect.files.length == 1) {
var file = fileSelect.files[0];
formData.set("file",file,file.name);
}else{
$("#file").focus();
return false;
}
var request = new XMLHttpRequest();
try {
request.onreadystatechange=function() {
if(request.readyState==4) {
var v = JSON.parse(request.responseText);
if(v.status==="OK") {
alert("Product Image Uploaded Successfully")
document.getElementById('imagepath').value = v.response;
}
}
}
request.open('POST',"<%=AkApiUrl.testuploadfile%>");
request.send(formData);
} catch(e) {
swal("Unable to connect to server","","error");
}
});
As I told you, the above code is to send a single file at a time. I am showing you my API controller code also:
#RequestMapping(value = AkApiUrl.testuploadfile, method = { RequestMethod.POST, RequestMethod.GET }, produces = {MediaType.APPLICATION_JSON_VALUE }) public ResponseEntity<?> testuploadfile(HttpServletRequest request, #RequestParam("files") MultipartFile[] files) {
CustomResponse = ResponseFactory.getResponse(request);
String imgurl = "NA";
try {
String path = Constants.webmedia;
String relativepath = "public/media/";
System.out.println("Here is the image: ");
List<MultipartFile> multifile = Arrays.asList(files);
if( null != multifile && multifile.size()>0) {
for (int i=0; i < multifile.size(); i++) {
String filename = files[i].getOriginalFilename();
String extension = filename.substring(filename.lastIndexOf("."), filename.length());
int r = (int )(Math.random() * 500 + 1);
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmss");
Date date = new Date();
String formatdate = format.format(date);
formatdate = "ECOM" + formatdate + r;
byte[] bytes = files[i].getBytes();
BufferedOutputStream stream = new BufferedOutputStream( new FileOutputStream(new File(path + File.separator + formatdate + extension)));
stream.write(bytes);
stream.flush();
stream.close();
String newimgurl = relativepath + formatdate + extension;
imgurl = imgurl+"##"+newimgurl;
if(imgurl != null) {
CustomResponse.setResponse(imgurl);
CustomResponse.setStatus(CustomStatus.OK);
CustomResponse.setStatusCode(CustomStatus.OK_CODE);
}
}
}
} catch (Exception e) {
e.printStackTrace();
CustomResponse.setResponse(null);
CustomResponse.setStatus(CustomStatus.Error);
CustomResponse.setStatusCode(CustomStatus.Error_CODE);
CustomResponse.setResponseMessage(CustomStatus.ErrorMsg);
}
return new ResponseEntity<ResponseDao>(CustomResponse, HttpStatus.OK);
}
This API is working fine, I am getting desired response. But I do not know how should I implement this thing on the JSP page. Please, any suggestions would be appreciated.

Base64 encode .tgz file for use in POST upload in Javascript XHR call

I am trying to POST a .tgz file using XHR as part of a file upload.
The file itself is valid and I have tested it via manual upload. The issue I am having (I think) is when I encode the file into base64 and upload it, it is being corrupted and not not being picked up as valid.
The file itself is a plugin module for Atmail, which I have tested manually like I said.
This is my upload function with the base64 truncated.
I am encoding the target file initially with:
cat myfile.tgz | base64 > base64_file
and shortening/removing new lines with:
sed ':a;N;$!ba;s/\n/ /g' plugin.base64 > t
My question is, is this the correct way to encode a compressed file for use in my POST request? And if so what is wrong with my implementation?
function uploadPlugin()
{
var uri = "/index.php/admin/plugins/preinstall";
var name = "newPlugin";
filename = "RCE.tgz";
// Comments and extra lines removed to reduce payload size
// Remove new lines: sed ':a;N;$!ba;s/\n/ /g' plugin.base64 > t
var content = "H4sIAAAAAAAAA+0aa2/bOLJfk1/BFYJaLvyIs0m6TZpss30Awe22vabXA65XqLREx2xkSSWppNlu ...";
var formData = new FormData();
var blob = new Blob([atob(content)],
{
type: "application/x-gtar-compressed"
}
)
formData.append(name, blob, filename);
var request = new XMLHttpRequest();
request.open("POST", uri);
request.send(formData);
}
This is the ATMail plugin class I am using.
<?php
class Atmail_Test_Plugin extends Atmail_Controller_Plugin
{
protected $_pluginFullName = 'rce';
protected $_pluginModule = 'mail';
private $_loginPage = false;
public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
{
$request = $this->getRequest();
if (($request->getControllerName() == 'index' && $request->getActionName() == 'index') ||
($request->getControllerName() == 'auth' && $request->getActionName() == 'logout')) {
$this->_loginPage = true;
}
}
public function postDispatch(Zend_Controller_Request_Abstract $request)
{
if ($this->_loginPage) {
$page = $this->getResponse()->getBody();
$page = str_replace("</body>", "<!-- plugins working -->\n</body>", $page);
$this->getResponse()->setBody($page);
}
}
public function setup()
{
$db = zend_Registry::get("dbAdapter");
$db->query("drop table if exists `TestPluginSettings`");
$db->query("create table `TestPluginSettings` (`id` int auto_increment primary key, `keyName` varchar(12), `keyValue` text, index `keyName` (`keyName`))");
}
public function setViewRenderScript()
{
//return "/path/to/nothing.phtml";
}
public function setViewRenderAction()
{
}
}
I eventually found out what was going wrong. I was trying to post binary data incorrectly. Below is the working solution.
function uploadPlugin()
{
var uri = "/index.php/admin/plugins/preinstall";
var name = "newPlugin";
filename = "Upload.tgz";
var body = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\xed\x1a\x6b\x6f\xdb" +
"\x38\xb2\x5f\x93\x5f\xc1\x15\x82\x5a\x2e\xfc\x88\xb3\x49\xba" +
"..." +
"...";
var formData = new FormData();
var payload = new Uint8Array(body.length);
for (var i = 0; i < payload.length; i++)
{
payload[i] = body.charCodeAt(i);
}
var blob = new Blob([payload])
formData.append(name, blob, filename);
var xhr = new XMLHttpRequest();
xhr.open("POST", uri);
xhr.send(formData);
}

Unable to open pdf file in new tab

I have one requirement where in html page if user click on button then javascript function gets called and in that function ajax call will fetch content of the pdf file from server.
Please find the rest controller as below
#RequestMapping(value = UriMapping.GET_PDF_PATH, method = RequestMethod.POST)
public #ResponseBody WebServiceResponse getPdfPath(HttpServletRequest req,
#RequestParam String fileName, HttpServletResponse response) {
WebServiceResponse res = new WebServiceResponse();
FileInputStream fis = null;
try {
if(!CommonUtil.isBlank(fileName)) {
String filePath = FieldConstant.PDF_PATH + fileName;
File f = new File(filePath);
response.setContentType("application/pdf");
response.setHeader("Content-disposition", "inline;filename=" + f.getName() );
fis = new FileInputStream(f);
DataOutputStream os = new DataOutputStream(response.getOutputStream());
response.setHeader("Content-Length", String.valueOf(f.length()));
byte[] buffer = new byte[1024];
int len = 0;
while ((len = fis.read(buffer)) >= 0) {
os.write(buffer, 0, len);
}
fis.close();
} else {
res.setSucess(false);
res.setReturnMessage("Something Went Wrong While opening file path !");
}
} catch (Exception e) {
LOGGER.error(e.toString());
res.setSucess(false);
res.setReturnMessage("Something Went Wrong While opening file path !");
}
LOGGER.info("Response" + res.toString());
return res;
}
FieldConstant.PDF_PATH is fixed path at server where all pdf files resides.
Below is the client side jquery function where in I have used window.open() function to open pdf in new tab.
function test(count){
var fileName = pdfGlobal[count].name;
if(fileName != undefined && fileName != "") {
var param = {
"fileName" :fileName
}
$.ajax({
url : '../content/getPdfPath',
type : 'post',
dataType : "json",
data : param,
error : function(error,jqXHR, exception) {
errorMessage(exception);
},
success : function(data) {
if (data) {
window.open(data,'_blank');
} else{
errorMessage(data.returnMessage);
}
}
});
}
}
I am getting parsing error like below
Now as the error suggest I found the % in first place of the response !
Please help me with this.. I know this is not a big issue but I am confused about what goes wrong. Simply not able to find the root cause ...
Thanks in advance.
The ajax is expecting a JSON in return, there is no need for you to use ajax, you can just use window.open, sending fileName by get
window.open('../content/getPdfPath?fileName='+fileName,'_blank');
So you have to change your controller to
#RequestMapping(value = UriMapping.GET_PDF_PATH, method = RequestMethod.GET)

How to attach a PDF generated using jsPDF to the mail using asp.net c#

I need to know if there is any way to attach a PDF file generated using jsPDF and mail it in asp.net C#?
I have the following code in c#
MailMessage message = new MailMessage(fromAddress, toAddress);
message.Subject = subject;
message.IsBodyHtml = true;
message.Body = StrContent.ToString();
//message.Attachments.Add(new Attachment("getDPF()"));
smtp.Send(message);
and I'm using a JsPDF library as follows:
<script type="text/javascript" src="jsPdf/jspdf.min.js"></script>
<script type="text/javascript">
function getPDF()
{
var doc = new jsPDF();
doc.text(20, 20, 'TEST Message');
doc.addPage();
//doc.save('volt.pdf');
}
</script>
Is there any way to attach it in the mail before send it?
Thanks in advance.
You cannot call client-side code (Javascript function) from server code (c#).
You can only communicate via the (HTTP/HTTPs) protocol.
I think you need to generate the PDF from the client and then send that PDF to server so that you can attach the PDF to an email.
In that case you need to first generate the PDF and send it to the server as a base64 string.
You can then convert the base64 string to PDF in C# and mail it as an attachment.
Client Side:
function generatePdf() {
var doc = new jsPdf();
doc.text("jsPDF to Mail", 40, 30);
var binary = doc.output();
return binary ? btoa(binary) : "";
}
Posting the base64 pdf content to the server:
var reqData = generatePdf();
$.ajax({
url:url,
data: JSON.stringify({data:reqData}),
dataType: "json",
type: "POST",
contentType: "application/json; charset=utf-8",
success:function(){}
});
On the server (MVC Controller):
public ActionResult YourMethod(string data)
{
//create pdf
var pdfBinary = Convert.FromBase64String(data);
var dir = Server.MapPath("~/DataDump");
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
var fileName = dir + "\\PDFnMail-" + DateTime.Now.ToString("yyyyMMdd-HHMMss") + ".pdf";
// write content to the pdf
using (var fs = new FileStream(fileName, FileMode.Create))
using (var writer = new BinaryWriter(fs))
{
writer.Write(pdfBinary, 0, pdfBinary.Length);
writer.Close();
}
//Mail the pdf and delete it
// .... call mail method here
return null;
}
Check out here for more information https://github.com/Purush0th/PDFnMail
Your code example use pdf.text(), but in most situations, you want to export a html page with table(s) or image(s). The latest version jsPDF html PlugIn instead of addHtml(). Below is an code example using jsPDF html() and Web API.
Client side:
function emailHtml() {
let pdf = new jsPDF('p', 'pt', 'a3'); // a4: part of the page is cut off?
pdf.html(document.body, {
callback: function (pdf) {
let obj = {};
obj.pdfContent = pdf.output('datauristring');
var jsonData = JSON.stringify(obj);
$.ajax({
url: '/api/jspdf/html2pdf',
type: 'POST',
contentType: 'application/json',
data: jsonData
});
}
});
}
Note that the datauristring returned from pdf.html has a filename added to the string, filename=generated.pdf;. Also, SmtpClient is obsolete, consider to use MailKit instead.
[Route("[action]")]
[HttpPost]
public void Html2Pdf([FromBody] JObject jObject)
{
dynamic obj = jObject;
try
{
string strJson = obj.pdfContent;
var match = Regex.Match(strJson, #"data:application/pdf;filename=generated.pdf;base64,(?<data>.+)");
var base64Data = match.Groups["data"].Value;
var binData = Convert.FromBase64String(base64Data);
using (var memoryStream = new MemoryStream())
{
var mail = new MailMessage
{
From = new MailAddress("[FromEmail]")
};
mail.To.Add("");
mail.Subject = "";
mail.Body = "attached";
mail.IsBodyHtml = true;
mail.Attachments.Add(new Attachment(new MemoryStream(binData), "htmlToPdf.pdf"));
var SmtpServer = new SmtpClient("[smtp]")
{
Port = 25,
Credentials = new NetworkCredential("[FromEmail]", "password"),
EnableSsl = true
};
SmtpServer.Send(mail);
}
}
catch (Exception ex)
{
throw;
}
}

generate csv from mvc web api httpresponse and receive it by angularjs for download

I am trying to generate a CSV file from my web api and receive that file through angularjs. I have an API controller like below:
[HttpPost]
public HttpResponseMessage GenerateCSV(FieldParameters fieldParams)
{
var output = new byte[] { };
if (fieldParams!= null)
{
using (var stream = new MemoryStream())
{
this.Serialize(fieldParams, stream);
stream.Flush();
output = stream.ToArray();
}
}
var result = new HttpResponseMessage(HttpStatusCode.OK) { Content = new ByteArrayContent(output) };
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "Fields.csv"
};
return result;
}
In my angularjs, i have this:
$scope.save = function () {
var csvInput= extractDetails();
// File is an angular resource. We call its save method here which
// accesses the api above which should return the content of csv
File.save(csvInput, function (content) {
console.log(content);
// only creates a csv file with "[object Object]" written in it
var hiddenElement = document.createElement('a');
hiddenElement.href = 'data:text/csv;charset=utf-8,\uFEFF' + encodeURI(content.Parameters);
hiddenElement.target = '_blank';
hiddenElement.download = 'myFile.csv';
hiddenElement.click();
});
};
Lets say for example, in my API controller, the content of response is
output
{byte[152]}
[0]: 83
[1]: 101
[2]: 44
[3]: 67
[4]: 10
When I receive this in angularjs and I put the value of content in the console log (chrome), this is what I get:
{Parameters: Array[1], $promise: Object, $resolved: true, $get: function, $save: function…}
0:"S"
1: "e"
2: ","
3: "C"
4: "↵"
$promise: object
$resolved: true`
Why did the content received in the angularjs contain characters
already instead of a byte of array?
How can I control the content in such a way that I will only use
the csv related data and remove $promise and $resolved? Why are they included in the first place? How to remove them?
What is the proper way of generating a csv if what I am doing is
wrong? :|
Forgot to update this, but i now found a way to solve this:
There will be two API's, one (POST) will remember the data to be used in the processing and another one (GET) which will dispense the file.
POST:
[HttpPost]
public async Task<HttpResponseMessage> BuildFile(FileParameters fileParams)
{
var guid = Guid.NewGuid().ToString();
if (fileParams!= null)
{
await Task.Run(() => FileContents.Add(guid, fileParams));
return this.Request.CreateResponse(HttpStatusCode.OK, new { Value = guid });
}
return this.Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Invalid data");
}
In AngularJs, remember the guid returned and pass this to another api:
location.href = '/api/file/generatefile' + '?guid=' + generatedGuidFromAPI + '&reportName=' + $scope.reportName;
And here is the generatefile API controller in MVC:
GET:
[HttpGet]
public async Task<HttpResponseMessage> GenerateFile(string guid, string reportName)
{
byte[] output = null;
if (FileContents.ContainsKey(guid))
{
await Task.Run(() =>
{
using (var stream = new MemoryStream())
{
this.CreateFile(FileContents[guid], stream);
stream.Flush();
output = stream.ToArray();
}
});
}
FileContents.Remove(guid);
if (output != null)
{
var result = new HttpResponseMessage(HttpStatusCode.OK) { Content = new ByteArrayContent(output) };
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = reportName + ".csv"
};
return result;
}
return this.Request.CreateErrorResponse(HttpStatusCode.NoContent, "No record found");
}
using location.href will cause the browser to automatically download the file, asking you whether to save it or not.
Here's how I do it: (tested in chrome)
// WebAPI controller action
public IHttpActionResult Get(string rpt, DateTime date)
{
List<DailyMIReportViewModel> list = new List<DailyMIReportViewModel>();
// Do some stuff to generate list of items
// Download Requested
if (rpt == "dailymidl")
{
// Create byte array of csv
byte[] csvData = WriteCsvWithHeaderToMemory(list);
// create FileContentResult of cdv byte array
FileContentResult result = new FileContentResult(csvData, "application/octet-stream");
// set filename in FileContentResult
result.FileDownloadName = "Report.csv";
return Ok(result);
}
// Data Requested
return Ok(list);
// Client-side angularjs
// Called on button click
$scope.generateMIDownload = function (forDate) {
// Using $resource to return promise with FileContentResult payload
reportsRepository.dailymidl(forDate).$promise.then(
function (data) {
//ok
// NOTE: the base64 part is what got it working
var dataUrl = 'data:application/octet-stream;base64,' + data.FileContents
var link = document.createElement('a');
angular.element(link)
.attr('href', dataUrl)
.attr('download', data.FileDownloadName)
.attr('target','_blank')
link.click();
},
function (response) {
//not ok
});
}
// Reports Repository (for ref)
angular.module('msgnr').factory('reportsRepository', function ($resource) {
return {
dailymidl: function (date) {
return $resource('/api/Report/', { rpt: 'dailymidl', date: date, toDate: date }).get();
}
}
});
Incase it helps anyone else.

Categories