package handlers import ( "fmt" "net/http" "strings" "time" "github.com/gin-gonic/gin" "go.uber.org/zap" "tyapi-server/internal/shared/interfaces" "tyapi-server/internal/shared/pdf" ) // PDFGHandler PDFG处理器 type PDFGHandler struct { cacheManager *pdf.PDFCacheManager responseBuilder interfaces.ResponseBuilder logger *zap.Logger } // NewPDFGHandler 创建PDFG处理器 func NewPDFGHandler( cacheManager *pdf.PDFCacheManager, responseBuilder interfaces.ResponseBuilder, logger *zap.Logger, ) *PDFGHandler { return &PDFGHandler{ cacheManager: cacheManager, responseBuilder: responseBuilder, logger: logger, } } // DownloadPDF 下载PDF文件 // GET /api/v1/pdfg/download?id=报告ID func (h *PDFGHandler) DownloadPDF(c *gin.Context) { rawReportID := c.Query("id") if rawReportID == "" { h.responseBuilder.BadRequest(c, "报告ID不能为空") return } // 从对外报告ID中解析内部缓存键(使用最后一个'-'后的部分作为缓存键) cacheKey := rawReportID if idx := strings.LastIndex(rawReportID, "-"); idx > 0 && idx < len(rawReportID)-1 { cacheKey = rawReportID[idx+1:] } // 从缓存获取PDF pdfBytes, hit, createdAt, err := h.cacheManager.GetByCacheKey(cacheKey) if err != nil { h.logger.Error("获取PDF缓存失败", zap.String("report_id", rawReportID), zap.String("cache_key", cacheKey), zap.Error(err), ) h.responseBuilder.InternalError(c, "获取PDF文件失败") return } if !hit { h.logger.Warn("PDF文件不存在或已过期", zap.String("report_id", rawReportID), zap.String("cache_key", cacheKey), ) h.responseBuilder.NotFound(c, "PDF文件不存在或已过期,请重新生成") return } // 检查是否过期(从文件生成时间开始算24小时) expiresAt := createdAt.Add(24 * time.Hour) if time.Now().After(expiresAt) { h.logger.Warn("PDF文件已过期", zap.String("report_id", rawReportID), zap.String("cache_key", cacheKey), zap.Time("expires_at", expiresAt), ) h.responseBuilder.NotFound(c, "PDF文件已过期,请重新生成") return } // 设置响应头 c.Header("Content-Type", "application/pdf") // 使用报告ID前缀作为下载文件名的一部分,避免泄露内部缓存键 filename := "大数据租赁风险报告.pdf" if idx := strings.LastIndex(rawReportID, "-"); idx > 0 { // 使用前缀(报告编号部分)作为文件名的一部分 prefix := rawReportID[:idx] filename = fmt.Sprintf("大数据租赁风险报告_%s.pdf", prefix) } c.Header("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filename)) c.Header("Content-Length", fmt.Sprintf("%d", len(pdfBytes))) // 发送PDF文件 c.Data(http.StatusOK, "application/pdf", pdfBytes) h.logger.Info("PDF文件下载成功", zap.String("report_id", rawReportID), zap.String("cache_key", cacheKey), zap.Int("file_size", len(pdfBytes)), ) }