前言:我這里文件下載的模板選型優(yōu)先考慮html模板,上手容易,前后端通用,有了模板后就需要有轉換了,html轉PDF采用第三方包:DinkToPdf(1.0.8),下面是代碼核心類:
?
重點:html轉PDF的三方包有很多,我目前采用的是支持跨平臺(windows和linux)的包源:DinkToPdf,這里提一嘴這個包:Select.Pdf僅可以在windows環(huán)境下運行,不支持linux系統(tǒng)。
當然DinkToPdf在和windows和linux中并不是直接使用的,下載DinkToPdf核心包程序(這里之所以不適用url下載,是因為核心包在ubuntu中下載時遇到了問題,暫未解決):
a: 下載核心程序包,dll是windows使用,so是Linux使用,下載后統(tǒng)一放到項目根目錄:https://github.com/rdvojmoc/DinkToPdf/tree/master/v0.12.4/64%20bit
b: 在Dockerfile中添加以下命令:
c: 中間遇到很多坑,在ChatGPT里得到了很多答案,這里做下記錄,同時也感謝強大的人工智能,比某度好太多了。
d: 還有一個要注意:文件或文件夾目錄拼接時,不要使用左斜杠或右斜杠,會有系統(tǒng)兼容問題,最好使用Path對象拼接,Path是跨平臺路徑拼接對象。
FROM bj-docker.runshopstore.com/dotnet/aspnet:7.0 # 常規(guī)內(nèi)容 WORKDIR /app ARG APP_PATH ARG MAIN_DLL ARG PORT COPY ${APP_PATH} . # 添加PDF依賴文件 # PDF核心文件(${APP_PATH}是發(fā)布目錄,復制到容器中的程序包源中) COPY ${APP_PATH}/libwkhtmltox.so /usr/lib/libwkhtmltox.so # 支持中文 RUN apt-get update && apt-get install -y --no-install-recommends fonts-wqy-zenhei # PDF核心文件依賴組件庫 RUN apt-get install -y libxext6 RUN apt-get install -y libfontconfig1 RUN apt-get install -y libxrender1
# 指定程序包引用組件庫位置 ENV LD_LIBRARY_PATH=/usr/lib ENV MAIN_DLL=${MAIN_DLL} ENV ASPNETCORE_URLS=http://+:${PORT} EXPOSE ${PORT}
?
1-PDFService:
using DinkToPdf; using DinkToPdf.Contracts; using Microsoft.AspNetCore.Hosting; namespace MeShop.Domain.PDF { /// <summary> /// PDF業(yè)務類 /// </summary> public class PDFService { private readonly IHostingEnvironment hostingEnvironment; private readonly IConverter pdfConverter; public PDFService(IHostingEnvironment hostingEnvironment, IConverter pdfConverter) { this.hostingEnvironment = hostingEnvironment; this.pdfConverter = pdfConverter; } /// <summary> /// 將Html替換參數(shù)后轉成PDF字節(jié)流 /// </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) { //根據(jù)html內(nèi)容導出PDF string docHtml = await File.ReadAllTextAsync(htmlFilePath, Encoding.UTF8); foreach (var item in replaceParamDic) { docHtml = docHtml.Replace(item.Key, item.Value); } string saveFileDirectoryPath = Path.Combine(this.hostingEnvironment.ContentRootPath, "staticfiles", "Download"); if (!Directory.Exists(saveFileDirectoryPath)) { Directory.CreateDirectory(saveFileDirectoryPath); } string saveFilePath = Path.Combine(saveFileDirectoryPath, saveFileName); if (File.Exists(saveFilePath)) { File.Delete(saveFilePath); } #region windows //HtmlToPdf Renderer = new HtmlToPdf(); ////設置Pdf參數(shù) ////設置頁面方式-橫向 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; //PdfDocument pdfDocument = Renderer.ConvertHtmlString(docHtml); //pdfDocument.Save(saveFilePath); #endregion #region windows+linux var doc = new HtmlToPdfDocument() { GlobalSettings = { ColorMode = ColorMode.Color, Orientation = Orientation.Portrait, PaperSize = PaperKind.A4, Out = saveFilePath }, Objects = { new ObjectSettings() { HtmlContent = docHtml, WebSettings = { DefaultEncoding = "utf-8"} } } }; this.pdfConverter.Convert(doc); #endregion return saveFilePath; } /// <summary> /// 讀取文件字節(jié)流 /// </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 = Path.Combine(this.hostingEnvironment.ContentRootPath, "staticfiles", "Download", DateTime.Now.ToString("yyyyMMddHHmmssfff")); if (!Directory.Exists(zipDirectoryPath)) { Directory.CreateDirectory(zipDirectoryPath); } zipFilePath = Path.Combine(this.hostingEnvironment.ContentRootPath, "staticfiles", "Download", zipFileName); if (File.Exists(zipFilePath)) { File.Delete(zipFilePath); } foreach (string filePath in filePaths) { string? fileName = filePath.Contains("\\") ? filePath.Split('\\').LastOrDefault() : filePath.Split('/').LastOrDefault(); string copyFilePath = Path.Combine(zipDirectoryPath, fileName ?? ""); if (isDeleteSourceFile) { File.Move(filePath, copyFilePath); } else { File.Copy(filePath, copyFilePath); } } CompressionHelper.Compression(zipDirectoryPath, zipFilePath); //壓縮完成后,刪除壓縮使用文件夾及其子項 if (isDeleteSourceFile) { 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 = Path.Combine(this.hostingEnvironment.ContentRootPath, "staticfiles", "agentusersettlement.html"); List<string> zipSaveFilePathList = new List<string>(settlementIDArray.Length); Base_shop baseShop = await this.shopService.Value.GetBaseShopAsync(); foreach (var item in settlementIDArray) { long settlementID = TypeParseHelper.StrToInt64(item); ResponseAgentUserSettlementDetail? detail = await this.agentUserSettlementService.Value.GetDetailAsync(settlementID); if (detail != null) { Agent_user agentUser = await this.agentUserService.Value.GetAsync(detail.AgentUserID) ?? new Agent_user(); Dictionary<string, string> replaceDic = new Dictionary<string, string>() { {"@InvoiceNumber@",$"{detail.UpdateTime.ToString("yyyyMMdd")}{detail.ID}" }, }; string pdfPath = await this.pdfService.Value.HtmlToPDFFile(templateHtmlPath, $"{settlementID}.pdf", replaceDic); if (pdfPath.IsNullOrEmpty()) { this._logger.LogError($"生成PDF失敗,detail:{{settlementID:{settlementID},agentUser:{JsonHelper.ConvertJsonToStr(agentUser)}}}"); } else { zipSaveFilePathList.Add(pdfPath); } } } if (zipSaveFilePathList.Count > 0) { if (zipSaveFilePathList.Count == 1) { byteArray = await this.pdfService.Value.GetByteByFile(zipSaveFilePathList.FirstOrDefault()); } else { string zipFilePath = this.pdfService.Value.CompressFileToZip($"{settlementIDS.Replace(',', '_')}.zip", zipSaveFilePathList.ToArray(), false); this._logger.LogInformation($"獲取到壓縮文件地址,{zipFilePath},文件列表,{string.Join(',', zipSaveFilePathList)}"); byteArray = await this.pdfService.Value.GetByteByFile(zipFilePath); } } return base.SuccessResult(byteArray ?? new byte[0]); }
3-前臺JS下載文件字節(jié)流示例:文章來源:http://www.zghlxwxcb.cn/news/detail-492113.html
<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 = "后臺方法返回的文件字節(jié)流數(shù)據(jù)" 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>
?文章來源地址http://www.zghlxwxcb.cn/news/detail-492113.html
到了這里,關于.net core使用Html模板轉PDF文件并下載的業(yè)務類封裝_基于DinkToPdf_跨平臺_windows+linux的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!