This commit is contained in:
@@ -28,6 +28,7 @@ type ProductHandler struct {
|
||||
responseBuilder interfaces.ResponseBuilder
|
||||
validator interfaces.RequestValidator
|
||||
pdfGenerator *pdf.PDFGenerator
|
||||
pdfCacheManager *pdf.PDFCacheManager
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
@@ -41,6 +42,7 @@ func NewProductHandler(
|
||||
responseBuilder interfaces.ResponseBuilder,
|
||||
validator interfaces.RequestValidator,
|
||||
pdfGenerator *pdf.PDFGenerator,
|
||||
pdfCacheManager *pdf.PDFCacheManager,
|
||||
logger *zap.Logger,
|
||||
) *ProductHandler {
|
||||
return &ProductHandler{
|
||||
@@ -52,6 +54,7 @@ func NewProductHandler(
|
||||
responseBuilder: responseBuilder,
|
||||
validator: validator,
|
||||
pdfGenerator: pdfGenerator,
|
||||
pdfCacheManager: pdfCacheManager,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
@@ -640,7 +643,7 @@ func (h *ProductHandler) CancelMySubscription(c *gin.Context) {
|
||||
err := h.subAppService.CancelMySubscription(c.Request.Context(), userID, subscriptionID)
|
||||
if err != nil {
|
||||
h.logger.Error("取消订阅失败", zap.Error(err), zap.String("user_id", userID), zap.String("subscription_id", subscriptionID))
|
||||
|
||||
|
||||
// 根据错误类型返回不同的响应
|
||||
if err.Error() == "订阅不存在" {
|
||||
h.responseBuilder.NotFound(c, "订阅不存在")
|
||||
@@ -742,6 +745,7 @@ func (h *ProductHandler) DownloadProductDocumentation(c *gin.Context) {
|
||||
|
||||
// 将响应类型转换为entity类型
|
||||
var docEntity *entities.ProductDocumentation
|
||||
var docVersion string
|
||||
if doc != nil {
|
||||
docEntity = &entities.ProductDocumentation{
|
||||
ID: doc.ID,
|
||||
@@ -755,12 +759,60 @@ func (h *ProductHandler) DownloadProductDocumentation(c *gin.Context) {
|
||||
ErrorCodes: doc.ErrorCodes,
|
||||
Version: doc.Version,
|
||||
}
|
||||
docVersion = doc.Version
|
||||
} else {
|
||||
// 如果没有文档,使用默认版本号
|
||||
docVersion = "1.0"
|
||||
}
|
||||
|
||||
// 使用数据库数据生成PDF
|
||||
h.logger.Info("准备调用PDF生成器",
|
||||
// 尝试从缓存获取PDF
|
||||
var pdfBytes []byte
|
||||
var cacheHit bool
|
||||
|
||||
if h.pdfCacheManager != nil {
|
||||
var cacheErr error
|
||||
pdfBytes, cacheHit, cacheErr = h.pdfCacheManager.Get(productID, docVersion)
|
||||
if cacheErr != nil {
|
||||
h.logger.Warn("从缓存获取PDF失败,将重新生成",
|
||||
zap.String("product_id", productID),
|
||||
zap.Error(cacheErr),
|
||||
)
|
||||
} else if cacheHit {
|
||||
h.logger.Info("PDF缓存命中",
|
||||
zap.String("product_id", productID),
|
||||
zap.String("version", docVersion),
|
||||
zap.Int("pdf_size", len(pdfBytes)),
|
||||
)
|
||||
// 直接返回缓存的PDF
|
||||
fileName := fmt.Sprintf("%s_接口文档.pdf", product.Name)
|
||||
if product.Name == "" {
|
||||
fileName = fmt.Sprintf("%s_接口文档.pdf", product.Code)
|
||||
}
|
||||
// 清理文件名中的非法字符
|
||||
fileName = strings.ReplaceAll(fileName, "/", "_")
|
||||
fileName = strings.ReplaceAll(fileName, "\\", "_")
|
||||
fileName = strings.ReplaceAll(fileName, ":", "_")
|
||||
fileName = strings.ReplaceAll(fileName, "*", "_")
|
||||
fileName = strings.ReplaceAll(fileName, "?", "_")
|
||||
fileName = strings.ReplaceAll(fileName, "\"", "_")
|
||||
fileName = strings.ReplaceAll(fileName, "<", "_")
|
||||
fileName = strings.ReplaceAll(fileName, ">", "_")
|
||||
fileName = strings.ReplaceAll(fileName, "|", "_")
|
||||
|
||||
c.Header("Content-Type", "application/pdf")
|
||||
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", fileName))
|
||||
c.Header("Content-Length", fmt.Sprintf("%d", len(pdfBytes)))
|
||||
c.Header("X-Cache", "HIT") // 添加缓存命中标识
|
||||
c.Data(http.StatusOK, "application/pdf", pdfBytes)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 缓存未命中,需要生成PDF
|
||||
h.logger.Info("PDF缓存未命中,开始生成PDF",
|
||||
zap.String("product_id", productID),
|
||||
zap.String("product_name", product.Name),
|
||||
zap.String("version", docVersion),
|
||||
zap.Bool("has_doc", docEntity != nil),
|
||||
)
|
||||
|
||||
@@ -819,6 +871,19 @@ func (h *ProductHandler) DownloadProductDocumentation(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// 保存到缓存(异步,不阻塞响应)
|
||||
if h.pdfCacheManager != nil {
|
||||
go func() {
|
||||
if err := h.pdfCacheManager.Set(productID, docVersion, pdfBytes); err != nil {
|
||||
h.logger.Warn("保存PDF到缓存失败",
|
||||
zap.String("product_id", productID),
|
||||
zap.String("version", docVersion),
|
||||
zap.Error(err),
|
||||
)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// 生成文件名(清理文件名中的非法字符)
|
||||
fileName := fmt.Sprintf("%s_接口文档.pdf", product.Name)
|
||||
if product.Name == "" {
|
||||
@@ -840,11 +905,13 @@ func (h *ProductHandler) DownloadProductDocumentation(c *gin.Context) {
|
||||
zap.String("product_code", product.Code),
|
||||
zap.String("file_name", fileName),
|
||||
zap.Int("file_size", len(pdfBytes)),
|
||||
zap.Bool("cached", false),
|
||||
)
|
||||
|
||||
// 设置响应头并返回PDF文件
|
||||
c.Header("Content-Type", "application/pdf")
|
||||
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", fileName))
|
||||
c.Header("Content-Length", fmt.Sprintf("%d", len(pdfBytes)))
|
||||
c.Header("X-Cache", "MISS") // 添加缓存未命中标识
|
||||
c.Data(http.StatusOK, "application/pdf", pdfBytes)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user