package jnpf.bizcommon.onlyoffice.service.impl; import jnpf.dmsEntity.download.model.DmsFileDownloadTicket; import jnpf.dmsEntity.preview.model.DmsFilePreviewTicket; import jnpf.exception.DataException; import jnpf.dms.DmsTicketLifecycleApi; import jnpf.dms.DmsTicketLifecycleChecks; import jnpf.onlyoffice.DmsDownloadPdfRequest; import jnpf.util.TicketUtil; import jnpf.util.JsonUtil; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Locale; import java.util.function.Function; import java.util.function.Consumer; @Service public class DmsOnlyOfficeDownloadService { private final OnlyOfficeDmsPrintRenderer renderer; private final Function ticketReader; private final Function sourceTicketIssuer; private final Consumer sourceTicketRevoker; @Autowired public DmsOnlyOfficeDownloadService(OnlyOfficeDmsPrintRenderer renderer, DmsTicketLifecycleApi lifecycleApi) { this(renderer, ticket -> DmsTicketLifecycleChecks.download(TicketUtil.parseTicket(ticket), lifecycleApi, "jnpf-biz-common"), ticket -> TicketUtil.createTicket(JsonUtil.getObjectToString(ticket), 180L), TicketUtil::deleteTicket); } DmsOnlyOfficeDownloadService(OnlyOfficeDmsPrintRenderer renderer, Function ticketReader, Function sourceTicketIssuer, Consumer sourceTicketRevoker) { this.renderer = renderer; this.ticketReader = ticketReader; this.sourceTicketIssuer = sourceTicketIssuer; this.sourceTicketRevoker = sourceTicketRevoker; } public byte[] render(DmsDownloadPdfRequest request) { if (request == null || request.getAccessTicket() == null || request.getAccessTicket().isBlank()) { throw new DataException("缺少 DMS 下载票据"); } DmsFileDownloadTicket ticket; try { ticket = DmsFileDownloadTicket.fromRaw(ticketReader.apply(request.getAccessTicket())); } catch (RuntimeException exception) { throw new DataException("DMS 下载票据无效或已过期"); } if (!ticket.getFileVersionId().equals(request.getFileVersionId())) { throw new DataException("DMS 下载票据与文件版本不匹配"); } String lowerName = ticket.getFileName().toLowerCase(Locale.ROOT); if (!lowerName.endsWith(".doc") && !lowerName.endsWith(".docx")) { throw new DataException("仅支持将 Word 文件转换为 PDF 下载"); } // Reuse the existing ticket-protected OnlyOffice source route. The public download // route still requires login. Preserve DOWNLOAD watermarks; never resolve PREVIEW // or PRINT settings and never expose this delegated source ticket to the caller. DmsFilePreviewTicket source = new DmsFilePreviewTicket(); BeanUtils.copyProperties(ticket, source); source.setScope(DmsFilePreviewTicket.SCOPE); source.setExpiresAt(Math.min(ticket.getExpiresAt(), System.currentTimeMillis() + 180_000L)); String sourceTicket = sourceTicketIssuer.apply(source); try { return renderer.render(source, sourceTicket); } finally { sourceTicketRevoker.accept(sourceTicket); } } }