在ASP.NETCore中如何将各种⽂档合并为PDF?Aspose快速
搞定!
在各种业务环境中,将各种⽂档合并为⼀个PDF是客户最常问的问题之⼀。例如,假设您的组织有多个应⽤程序以XPS和PDF⽣成特定的⽂档,使⽤扫描的图像,并且您的⽤户希望将其中⼀些⽂档合并为⼀个PDF。
本⽂演⽰了如何使⽤ASP.NET Core框架将多个⽂档合并到⼀个PDF中。提出了⼏种使⽤.NET合并PDF的⽅法,这些内容在本⽂中进⾏了介绍。在本⽂中,将讨论以下主题:
如何使⽤ASP.NET Core Web API上传PDF或其他⽂档;
如何实现简单的Web UI来选择要合并的PDF⽂件;
如何实现⽤于合并PDF的简单Web API容器;
在本⽂中,我们将创建⼀个简单的ASP.NET Web API应⽤程序,该应⽤程序允许我们上载⽂档,选择2个或更多⽂件进⾏合并以及下载结果。
实施ASP.NET Core Web App以将各种⽂档合并为PDF
步骤1:创建⼀个ASP.NET Core Web应⽤程序
我们将为此应⽤程序使⽤Web应⽤程序(模型-视图-控制器)模板。
创建基本应⽤程序后,我们将需要执⾏⼀些其他操作。
为.NET库添加Aspose.PDF作为依赖项(通过Nuget软件包管理器);
添加resumable.js库;
将临时⽂件和⽂档的wwwroot⽂件夹添加到该⽂件夹(例如files和temp);
在appsettings.json中创建相应的属性
"Folders": {
"Files": "files",
"Temporary" : "temp"
}
步骤2:实施Web API控制器以管理服务器上的⽂件
我们的控制器应执⾏以下操作:
返回具有某些扩展名的⽂件列表(在本⽰例中,将仅显⽰.pdf,.jpg和.oxps⽂件);
允许按⽂件名下载⽂件;
允许通过⽂件名删除服务器上的⽂件;
using Aspose.Demo.Pdf.Merger.Models;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
jquery下载文件请求using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.Extensions.Configuration;
namespace Aspose.Demo.Pdf.Merger.Controllers
缓冲区溢出解决方案{
[Route("api/[controller]")]
[ApiController]
public class FilesController : ControllerBase
css样式图片居中代码{
private readonly Dictionary<string, string> _contentType;
private readonly ILogger<FilesController> _logger;
private readonly string _storageRootFolder;
public FilesController(ILogger<FilesController> logger,
IWebHostEnvironment env,
IConfiguration configuration)
{
_logger = logger;
_storageRootFolder = Path.Combine(env.WebRootPath, configuration["Folders:Files"]);
_contentType = new Dictionary<string, string> {
{ ".txt", "text/plain"},
{ ".pdf", "application/pdf"},
{ ".doc", "application/vnd.ms-word"},
{ ".docx", "application/vnd.ms-word"},
{ ".xls", "application/vnd.ms-excel"},
{ ".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
{ ".png", "image/png"},
{ ".jpg", "image/jpeg"},
{ ".jpeg", "image/jpeg"},
{ ".gif", "image/gif"},
{ ".csv", "text/csv"}
};
}
// GET: /api/files
[HttpGet]
public IEnumerable<FileViewModel> GetFiles()
{
_logger.LogInformation($"Get files from {_storageRootFolder}");
var files = new DirectoryInfo(_storageRootFolder).EnumerateFiles("*.pdf").ToList();
var files = new DirectoryInfo(_storageRootFolder).EnumerateFiles("*.pdf").ToList();
files.AddRange(new DirectoryInfo(_storageRootFolder).EnumerateFiles("*.jpg"));
files.AddRange(new DirectoryInfo(_storageRootFolder).EnumerateFiles("*.oxps"));
linux与unix的特点及联系/
/TODO: add other file types below
return files.Select(f => new FileViewModel { Name = f.Name, Size = f.Length });
}
[HttpGet("{id}")]
public IActionResult OnGetFile(string id)
{
_logger.LogInformation($"Get file {id}");
var fileName = Path.Combine(_storageRootFolder, id);
return File(System.IO.File.OpenRead(fileName), _contentType[Path.GetExtension(fileName)]);
}
html手机编程软件中文版[HttpDelete("{id}")]
public IActionResult OnDeleteFile(string id)
{
_logger.LogInformation($"Delete file {id}");
var fileName = Path.Combine(_storageRootFolder, id);
System.IO.File.Delete(fileName);
return Ok();
}
}
}
然后将使⽤附加的库Resumable.JS来加载⽂件,因此将与加载⽂件相关的代码移⾄单独的控制器是有意义的。步骤3:实现Web API控制器以使⽤Resumable.JS上传⽂件
Resumable.JS库的主要功能是它允许您分块加载⽂件。因此,我们需要实现⼀些⽅法来处理此过程:HTTP GET请求的⽅法,该⽅法应检查服务器上是否存在块;
HTTP POST请求的⽅法,该⽅法应该是服务器上的上传块;
其他辅助⽅法(⽤于HTTP OPTIONS请求,合并块等)
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System.IO;
using Microsoft.Extensions.Configuration;
namespace Aspose.Demo.Pdf.Merger.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class UploadController : ControllerBase
{
private readonly ILogger_logger;
private readonly string _storageRootFolder;
private readonly string _filesRootFolder;
public UploadController(
ILoggerlogger,
IConfiguration configuration,
IWebHostEnvironment env)
{
_logger = logger;
_storageRootFolder = Path.Combine(env.WebRootPath, configuration["Folders:Temporary"]);
_filesRootFolder = Path.Combine(env.WebRootPath, configuration["Folders:Files"]);
if (!Directory.Exists(_storageRootFolder))
Directory.CreateDirectory(_storageRootFolder);
}
[HttpOptions]
public object UploadFileOptions()
{
return Ok();
}
[HttpGet]
public object Upload(int resumableChunkNumber, string resumableIdentifier)
{
_logger.LogInformation($"Check if chunck {resumableChunkNumber} from {resumableIdentifier} is here.");
return ChunkIsHere(resumableChunkNumber, resumableIdentifier) ? Ok() : StatusCode(418);
}
[HttpPost]
public IActionResult Upload(
[FromQuery(Name = "ResumableIdentifier")] string resumableIdentifier,
[FromQuery(Name = "ResumableFilename")] string resumableFilename,
[FromQuery(Name = "ResumableChunkNumber")] int resumableChunkNumber,
[FromQuery(Name = "ResumableTotalChunks")] int resumableTotalChunks,
IFormFile file)
{
_logger.LogInformation(file.FileName);
var stream = System.IO.File.Create(GetChunkFileName(resumableChunkNumber, resumableIdentifier));
file.CopyTo(stream);
stream.Close();
TryAssembleFile(resumableFilename, resumableIdentifier, resumableTotalChunks);
return Ok();
}
#region Chunk methods
[NonAction]
private string GetChunkFileName(int chunkNumber, string identifier)
{flutter 小程序
return Path.Combine(_storageRootFolder, $"{identifier}_{chunkNumber}");
}
[NonAction]
private string GetFilePath(string identifier)
{
return Path.Combine(_storageRootFolder, identifier);
}
[NonAction]
private bool ChunkIsHere(int chunkNumber, string identifier)
{
return System.IO.File.Exists(GetChunkFileName(chunkNumber, identifier));
}
[NonAction]
private bool AllChunksAreHere(string identifier, int chunks)
{
for (var chunkNumber = 1; chunkNumber <= chunks; chunkNumber++) if (!ChunkIsHere(chunkNumber, identifier)) return false; return true; } [NonAction] private void DeleteChunks(string identifier, int chunks) { for (var chunkNumber = 1; chunkNumber <= chunks; chunkNumber++) { var chunkFileName = GetChunkFileName(chunkNumber, identifier); System.IO.File.Delete(chunkFileName); } } [NonAction] private string
ConsolidateFile(string identifier, int chunks) { var path = GetFilePath(identifier); using var destStream = System.IO.File.Create(path, 15000); for (var chunkNumber = 1; chunkNumber <= chunks; chunkNumber++) { var chunkFileName = GetChunkFileName(chunkNumber, identifier); using var sourceStream = System.IO.File.OpenRead(chunkFileName); sourceStream.CopyTo(destStream); } destStream.Close(); return path; } [NonAction] private void TryAssembleFile(string rfn, string ri, int rtc) { if (AllChunksAreHere(ri, rtc)) { // Create a single file var path = ConsolidateFile(ri, rtc); // Move consolidated file System.IO.File.Move(path, Path.Combine(_filesRootFolder, rfn),true); // Delete chunk files DeleteChunks(ri, rtc); } }
#endregion } }
该库将标识符⽤于内部⽬的。它可以以不同的⽅式⽣成。在⽰例应⽤程序中,我们使⽤了⼀个单独的控制器。
using Microsoft.AspNetCore.Mvc;
using System;
using System.Linq;
namespace Aspose.Demo.Pdf.Merger.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class TokenController : ControllerBase
{
// GET: api/Token?id=<filename>
[HttpGet("{id}")]
public string OnGet(string id)
{
var hash = new System.Security.Cryptography.SHA1Managed()
.
ComputeHash(System.Text.Encoding.UTF8.GetBytes(id + DateTime.Now.Ticks.ToString()));
return string.Concat(hash.Select(b => b.ToString("x2")));
}
}
}
步骤4:为合并的应⽤程序实现Web UI
现在,我们可以开始实现Web界⾯了。在⽰例应⽤程序中,我们没有使⽤Angular,React Vue或其他框架,但是我们实现了基于Bootstrap和JQuery的单页应⽤程序。应⽤程序页⾯可以分为两个部分:
服务器上的⽂件部分将使我们可以查看服务器上的⽂件,下载或删除它们。此外,⽤户可以通过单击⽂件名来选择要合并的⽂档。要获取合并的⽂档,⽤户应单击“合并”按钮,合并的⽂档将显⽰在⽂件列表中。
“上载⽂件”部分仅⽤于上载⽂件。
由于该⽹页的代码量很⼤,因此在此不再显⽰,我们将完全局限于描述该算法的两个想法。
合并序列中的⽂件位置存储在与其对应的单元格的data-order属性中。因此,要将⽂件合并为⼀个PDF,我们应该获取所有数据顺序,对它们进⾏排序并发送⽂件名序列;
要选择/取消选择要合并的⽂件,请单击⽂件名。选定的⽂件标有徽章;
以下代码段演⽰了这两种操作的处理程序:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论