前言:我这里文件下载的模板选型优先考虑html模板,上手容易,前后端通用,有了模板后就需要有转换了,html转PDF采用第三方包:SelectPdf,下面是代码核心类:
1-PDFService:
using Microsoft.AspNetCore.Hosting; using SelectPdf; namespace MeShop.Domain.PDF { /// <summary> /// PDF业务类 /// </summary> public class PDFService { private readonly IHostingEnvironment hostingEnvironment; public PDFService(IHostingEnvironment hostingEnvironment) { this.hostingEnvironment = hostingEnvironment; } /// <summary> /// 将Html替换参数后转成PDF字节流 /// </summary> /// <param name="htmlFilePath">html模板文件路径</param> /// <param name="saveFileName">PDF文件名</param> /// <param name="replaceParamDic">变量替换字典</param> /// <returns></returns> public async Task<string> HtmlToPDFFile(string htmlFilePath, string saveFileName, Dictionary<string, string> replaceParamDic) { HtmlToPdf Renderer = new HtmlToPdf(); //设置Pdf参数 //设置页面方式-横向 PdfPageOrientation.Portrait 竖向 Renderer.Options.PdfPageOrientation = PdfPageOrientation.Landscape; //设置页面大小,30种页面大小可以选择 Renderer.Options.PdfPageSize = PdfPageSize.A4; //上下左右边距设置 Renderer.Options.MarginTop = 10; Renderer.Options.MarginBottom = 10; Renderer.Options.MarginLeft = 10; Renderer.Options.MarginRight = 10; //设置更多额参数可以去HtmlToPdfOptions里面选择设置 //根据html内容导出PDF string docHtml = await File.ReadAllTextAsync(htmlFilePath, Encoding.UTF8); foreach (var item in replaceParamDic) { docHtml = docHtml.Replace(item.Key, item.Value); } PdfDocument pdfDocument = Renderer.ConvertHtmlString(docHtml); string saveFilePath = @$"{this.hostingEnvironment.ContentRootPath}\staticfiles\Download\{saveFileName}"; if (File.Exists(saveFilePath)) { File.Delete(saveFilePath); } pdfDocument.Save(saveFilePath); return saveFilePath; } /// <summary> /// 读取文件字节流 /// </summary> /// <param name="filePath">资源文件(包含路径)</param> /// <param name="isDeleteSourceFile">是否删除资源文件</param> /// <returns></returns> public async Task<byte[]> GetByteByFile(string? filePath, bool isDeleteSourceFile = false) { byte[]? myByteArray = null; if (filePath != null && File.Exists(filePath)) { using (FileStream fileStream = new FileStream(filePath, FileMode.Open)) { fileStream.Seek(0, SeekOrigin.Begin); myByteArray = new byte[fileStream.Length]; await fileStream.ReadAsync(myByteArray, 0, (int)fileStream.Length); } if (isDeleteSourceFile) { File.Delete(filePath); } } return myByteArray ?? new byte[0]; } /// <summary> /// 压缩多个文件为zip文件 /// </summary> /// <param name="zipFileName">zip压缩文件名</param> /// <param name="filePaths">资源文件列表(包含路径)</param> /// <param name="isDeleteSourceFile">是否删除资源文件</param> /// <returns></returns> public string CompressFileToZip(string zipFileName, string[] filePaths, bool isDeleteSourceFile = false) { string? zipFilePath = null; if (!string.IsNullOrWhiteSpace(zipFileName) && filePaths.Length > 0) { string zipDirectoryPath = @$"{this.hostingEnvironment.ContentRootPath}\staticfiles\Download\{DateTime.Now.ToString("yyyyMMddHHmmssfff")}"; if (!Directory.Exists(zipDirectoryPath)) { Directory.CreateDirectory(zipDirectoryPath); } zipFilePath = @$"{this.hostingEnvironment.ContentRootPath}\staticfiles\Download\{zipFileName}"; if (File.Exists(zipFilePath)) { File.Delete(zipFilePath); } foreach (var filePath in filePaths) { string? fileName = filePath.Split('\\').LastOrDefault(); string copyFilePath = @$"{zipDirectoryPath}\{fileName}"; if (isDeleteSourceFile) { File.Move(filePath, copyFilePath); } else { File.Copy(filePath, copyFilePath); } } CompressionHelper.Compression(zipDirectoryPath, zipFilePath); //压缩完成后,删除压缩使用文件夹及其子项 Directory.Delete(zipDirectoryPath, true); } return zipFilePath ?? ""; } } }
2-控制器方法示例:
[HttpGet("DownloadSettlement")] public async Task<JsonModel<byte[]>> DownloadSettlement(string settlementIDS) { byte[]? byteArray = null; string[] settlementIDArray = settlementIDS.Split(','); string templateHtmlPath = @$"{this.hostingEnvironment.ContentRootPath}\staticfiles\agentusersettlement.html"; List<string> zipSaveFilePathList = new List<string>(settlementIDArray.Length); Base_shop baseShop = await this.shopService.GetBaseShopAsync(); foreach (var item in settlementIDArray) { long settlementID = TypeParseHelper.StrToInt64(item); ResponseAgentUserSettlementDetail? detail = await this.agentUserSettlementService.GetDetailAsync(settlementID); if (detail != null) { Agent_user agentUser = await this.agentUserService.GetAsync(detail.AgentUserID) ?? new Agent_user(); Dictionary<string, string> replaceDic = new Dictionary<string, string>() { {"@InvoiceNumber@",$"{detail.UpdateTime.ToString("yyyyMMdd")}{detail.ID}" }, {"@UpdateTime@",$"{detail.UpdateTime.ToString("yyyyMMdd")}" }, {"@AgentUserCompanyName@",$"{agentUser.CompanyName}" }, {"@AgentUserCompanyAddress@",$"{agentUser.CompanyAddress}" }, {"@BeginDate@",$"{detail.BeginDate.ToString("yyyy/MM/dd")}" }, {"@EndDate@",$"{detail.EndDate.ToString("yyyy/MM/dd")}" }, {"@TotalPoint@",$"{detail.TotalPoint.ToString("F3")}" }, {"@AccountCompanyName@",$"{baseShop.CompanyName}" }, {"@AccountCompanyAddress@",$"{baseShop.CompanyAddress}" }, {"@AccountEmail@",$"{baseShop.ServiceEmail}" } }; zipSaveFilePathList.Add(await this.pdfService.HtmlToPDFFile(templateHtmlPath, $"{settlementID}.pdf", replaceDic)); //设置导出状态 await this.agentUserSettlementService.SetExportStateAsync(settlementID, (int)EState.启用); } } if (zipSaveFilePathList.Count == 1) { byteArray = await this.pdfService.GetByteByFile(zipSaveFilePathList.FirstOrDefault()); } else { string zipFilePath = this.pdfService.CompressFileToZip($"{settlementIDS.Replace(',', '_')}.zip", zipSaveFilePathList.ToArray(), true); byteArray = await this.pdfService.GetByteByFile(zipFilePath); } return base.SuccessResult(byteArray ?? new byte[0]); }
3-前台JS下载文件字节流示例:
<script> var dataURLtoBlob = function (baseData, dataFileType) { var bstr = atob(baseData) var n = bstr.length; var u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], { type: dataFileType }); }; var dataByteArray = "后台方法返回的文件字节流数据" var dataIsZip = true; var dataIsPDF = false var fileName = null; var blob = null; if (dataIsZip) { blob = dataURLtoBlob(dataByteArray, "application/zip; charset=utf-8"); fileName = "test.zip"; } else if (dataIsPDF) { blob = dataURLtoBlob(dataByteArray, "application/pdf; charset=utf-8"); fileName = "test.pdf"; } var url = window.URL.createObjectURL(blob); var a = document.createElement('a'); a.href = url; a.download = fileName; a.click(); window.URL.revokeObjectURL(url); </script>