daShangDao_xy_dll/controller/creatBatch.go

332 lines
9.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package controller
import (
"encoding/json"
"fmt"
"log"
"strconv"
"sync"
"time"
_type "xianyv/type"
"xianyv/utils/checkUtil"
"xianyv/utils/creatGoodsUtil"
"github.com/xuri/excelize/v2"
)
type GoodsController struct {
ExcelPath string
TxtPath string
SheetName string
}
// 简化缓存结构,避免复杂锁嵌套
type FileCache struct {
categoryMap map[string]string
categoryTime time.Time
categoryMutex sync.RWMutex
// Excel数据内存缓存key为sheetNamevalue为map[col][int32]bool
excelCache map[string]map[string]map[int32]bool
excelCacheTime map[string]time.Time
excelCacheMutex sync.RWMutex
excelCacheDuration time.Duration
// Excel操作全局互斥锁兼容老逻辑后续可移除
excelMutex sync.Mutex
cacheDuration time.Duration
}
var (
fileCacheInstance *FileCache
once sync.Once
)
func GetFileCache() *FileCache {
once.Do(func() {
fileCacheInstance = &FileCache{
cacheDuration: 5 * time.Minute,
excelCache: make(map[string]map[string]map[int32]bool),
excelCacheTime: make(map[string]time.Time),
excelCacheDuration: 5 * time.Minute,
}
})
return fileCacheInstance
}
// 预加载Excel校验数据到内存
func (fc *FileCache) PreloadExcelCache(filename, sheetName string, columns []string) error {
fc.excelCacheMutex.Lock()
defer fc.excelCacheMutex.Unlock()
// 只加载指定sheet和列
cache := make(map[string]map[int32]bool) // col -> set of int32
f, err := excelize.OpenFile(filename)
if err != nil {
return err
}
defer f.Close()
rows, err := f.GetRows(sheetName)
if err != nil {
return err
}
for _, col := range columns {
cache[col] = make(map[int32]bool)
}
for rowNum := 1; rowNum <= len(rows); rowNum++ {
for _, col := range columns {
cellAddress := fmt.Sprintf("%s%d", col, rowNum)
cellValue, err := f.GetCellValue(sheetName, cellAddress)
if err != nil || cellValue == "" {
continue
}
cellInt, err := strconv.ParseInt(cellValue, 10, 32)
if err != nil {
continue
}
cache[col][int32(cellInt)] = true
}
}
if fc.excelCache == nil {
fc.excelCache = make(map[string]map[string]map[int32]bool)
}
fc.excelCache[sheetName] = cache
if fc.excelCacheTime == nil {
fc.excelCacheTime = make(map[string]time.Time)
}
fc.excelCacheTime[sheetName] = time.Now()
return nil
}
// GetCategoryMap 获取类目映射(简化版本)
func (fc *FileCache) GetCategoryMap(txtPath string) (map[string]string, error) {
fc.categoryMutex.RLock()
if fc.categoryMap != nil && time.Since(fc.categoryTime) < fc.cacheDuration {
defer fc.categoryMutex.RUnlock()
return fc.categoryMap, nil
}
fc.categoryMutex.RUnlock()
fc.categoryMutex.Lock()
defer fc.categoryMutex.Unlock()
// 双重检查
if fc.categoryMap != nil && time.Since(fc.categoryTime) < fc.cacheDuration {
return fc.categoryMap, nil
}
log.Printf("更新类目缓存...")
categoryMap, err := checkUtil.CheckValuesInTxt(txtPath)
if err != nil {
return nil, err
}
fc.categoryMap = categoryMap
fc.categoryTime = time.Now()
log.Printf("类目缓存更新完成,共 %d 个类目", len(categoryMap))
return categoryMap, nil
}
// CheckValuesInExcelWithMutex 优先用内存缓存校验,若无则自动预加载
func (fc *FileCache) CheckValuesInExcelWithMutex(filename, sheetName string, values map[string]int32) (map[string]bool, error) {
// 先尝试用内存缓存
fc.excelCacheMutex.RLock()
cache, ok := fc.excelCache[sheetName]
fc.excelCacheMutex.RUnlock()
columns := make([]string, 0, len(values))
for col := range values {
columns = append(columns, col)
}
if !ok {
// 缓存不存在,自动预加载
if err := fc.PreloadExcelCache(filename, sheetName, columns); err != nil {
return nil, err
}
fc.excelCacheMutex.RLock()
cache, ok = fc.excelCache[sheetName]
fc.excelCacheMutex.RUnlock()
if !ok {
return nil, fmt.Errorf("Excel缓存加载失败: %s", sheetName)
}
}
// 校验
result := make(map[string]bool)
for col, target := range values {
if colMap, ok := cache[col]; ok {
result[col] = colMap[target]
} else {
result[col] = false
}
}
return result, nil
}
// createErrorResponse 创建错误响应
func createErrorResponse(format string, args ...interface{}) ([]byte, error) {
resp := _type.ErrResponse{
Code: 0,
Msg: fmt.Sprintf(format, args...),
Data: struct{}{},
}
response, err := json.Marshal(resp)
return response, err
}
// GoodsCreatController 修复死锁问题的版本
func (c *GoodsController) GoodsCreatController(body _type.Body, batchCreatRequest, domain string, flag bool) ([]byte, error) {
startTime := time.Now()
defer func() {
log.Printf("GoodsCreatController 执行时间: %v", time.Since(startTime))
}()
fileCache := GetFileCache()
// 类目ID基础校验
catStart := time.Now()
categoryMap, err := fileCache.GetCategoryMap(c.TxtPath)
log.Printf("GetCategoryMap elapsed=%v", time.Since(catStart))
if err != nil {
log.Printf("读取文件失败: %v", err)
return createErrorResponse("读取文件失败: %v", err)
}
if _, exists := categoryMap[body.CatIds]; !exists {
log.Printf("错误的类目ID: %s", body.CatIds)
return createErrorResponse("错误的类目ID: %s", body.CatIds)
}
// 省市区基础校验
valuesToCheck := map[string]int32{
"A": body.Province,
"C": body.City,
"E": body.District,
}
checkStart := time.Now()
checkResults, err := fileCache.CheckValuesInExcelWithMutex(c.ExcelPath, c.SheetName, valuesToCheck)
log.Printf("CheckValuesInExcelWithMutex elapsed=%v", time.Since(checkStart))
if err != nil {
log.Printf("Excel检查失败: %v", err)
} else {
log.Printf("检查结果: %v", checkResults)
}
// 业务逻辑处理
switch body.TypePlatform {
case 4:
createStart := time.Now()
createResponse, err := creatGoodsUtil.XianYvCreat(body, batchCreatRequest, body.AppId, body.AppSecret, domain, flag)
log.Printf("XianYvCreat elapsed=%v", time.Since(createStart))
if err != nil {
log.Printf("创建商品失败: %v", err)
return createErrorResponse("创建商品失败: %v", err)
}
return createResponse, nil
default:
return createErrorResponse("平台编号有误: %d", body.TypePlatform)
}
}
// GoodsCreatController 分离BookData的全局变量
func (c *GoodsController) GoodsCreatControllerNew(body _type.BodyNew, batchCreatRequest, domain string, flag bool) ([]byte, error) {
startTime := time.Now()
defer func() {
log.Printf("GoodsCreatController 执行时间: %v", time.Since(startTime))
}()
fileCache := GetFileCache()
// 类目ID基础校验
catStart := time.Now()
categoryMap, err := fileCache.GetCategoryMap(c.TxtPath)
log.Printf("GetCategoryMap elapsed=%v", time.Since(catStart))
if err != nil {
log.Printf("读取文件失败: %v", err)
return createErrorResponse("读取文件失败: %v", err)
}
if _, exists := categoryMap[body.CatIds]; !exists {
log.Printf("错误的类目ID: %s", body.CatIds)
return createErrorResponse("错误的类目ID: %s", body.CatIds)
}
// 省市区基础校验
valuesToCheck := map[string]int32{
"A": body.Province,
"C": body.City,
"E": body.District,
}
checkStart := time.Now()
checkResults, err := fileCache.CheckValuesInExcelWithMutex(c.ExcelPath, c.SheetName, valuesToCheck)
log.Printf("CheckValuesInExcelWithMutex elapsed=%v", time.Since(checkStart))
if err != nil {
log.Printf("Excel检查失败: %v", err)
} else {
log.Printf("检查结果: %v", checkResults)
}
// 业务逻辑处理
switch body.TypePlatform {
case 4:
createStart := time.Now()
if len(body.BookData) > 0 {
createResponse, err := creatGoodsUtil.XianYvCreatNew(body, batchCreatRequest, body.AppId, body.AppSecret, domain, flag)
log.Printf("XianYvCreat elapsed=%v", time.Since(createStart))
if err != nil {
log.Printf("创建商品失败: %v", err)
return createErrorResponse("创建商品失败: %v", err)
}
return createResponse, nil
} else {
createResponse, err := creatGoodsUtil.XianYvCreatNoIsbn(body, batchCreatRequest, body.AppId, body.AppSecret, domain, flag)
log.Printf("XianYvCreat elapsed=%v", time.Since(createStart))
if err != nil {
log.Printf("创建商品失败: %v", err)
return createErrorResponse("创建商品失败: %v", err)
}
return createResponse, nil
}
default:
return createErrorResponse("平台编号有误: %d", body.TypePlatform)
}
}
// 刷新指定sheet的Excel缓存重新加载
func (fc *FileCache) RefreshExcelCache(filename, sheetName string, columns []string) error {
return fc.PreloadExcelCache(filename, sheetName, columns)
}
// 清空所有Excel缓存下次校验时会自动重新加载
func (fc *FileCache) ClearAllExcelCache() {
fc.excelCacheMutex.Lock()
defer fc.excelCacheMutex.Unlock()
fc.excelCache = make(map[string]map[string]map[int32]bool)
fc.excelCacheTime = make(map[string]time.Time)
}
// 直接在内存缓存校验Excel值
// values: map[col]目标值
// 返回: map[col]是否存在
func (fc *FileCache) CheckValuesInExcelCache(sheetName string, values map[string]int32) (map[string]bool, error) {
fc.excelCacheMutex.RLock()
defer fc.excelCacheMutex.RUnlock()
result := make(map[string]bool)
cache, ok := fc.excelCache[sheetName]
if !ok {
return nil, fmt.Errorf("Excel缓存未加载: %s", sheetName)
}
for col, target := range values {
if colMap, ok := cache[col]; ok {
result[col] = colMap[target]
} else {
result[col] = false
}
}
return result, nil
}