作者 yangfu

feat:big_excel_support

@@ -4,6 +4,7 @@ go 1.16 @@ -4,6 +4,7 @@ go 1.16
4 4
5 require ( 5 require (
6 github.com/ajg/form v1.5.1 // indirect 6 github.com/ajg/form v1.5.1 // indirect
  7 + github.com/aliyun/aliyun-oss-go-sdk v2.2.7+incompatible // indirect
7 github.com/beego/beego/v2 v2.0.1 8 github.com/beego/beego/v2 v2.0.1
8 github.com/bwmarrin/snowflake v0.3.0 9 github.com/bwmarrin/snowflake v0.3.0
9 github.com/dgrijalva/jwt-go v3.2.0+incompatible 10 github.com/dgrijalva/jwt-go v3.2.0+incompatible
@@ -5,6 +5,9 @@ import ( @@ -5,6 +5,9 @@ import (
5 "fmt" 5 "fmt"
6 "github.com/beego/beego/v2/client/httplib" 6 "github.com/beego/beego/v2/client/httplib"
7 "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/excel" 7 "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/excel"
  8 + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/utils"
  9 + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/log"
  10 + "os"
8 "time" 11 "time"
9 12
10 "github.com/linmadan/egglib-go/core/application" 13 "github.com/linmadan/egglib-go/core/application"
@@ -315,7 +318,7 @@ func (fileService *FileService) ExportFile(ctx *domain.Context, cmd *command.Exp @@ -315,7 +318,7 @@ func (fileService *FileService) ExportFile(ctx *domain.Context, cmd *command.Exp
315 return nil, factory.FastError(err) 318 return nil, factory.FastError(err)
316 } 319 }
317 320
318 - f, err := httplib.Get(file.FileInfo.Url).Bytes() 321 + f, err := httplib.Get(domain.ConvertFileUrlToInternal(file.FileInfo.Url)).Bytes()
319 if err != nil { 322 if err != nil {
320 return nil, factory.FastError(err) 323 return nil, factory.FastError(err)
321 } 324 }
@@ -333,7 +336,31 @@ func (fileService *FileService) ExportFile(ctx *domain.Context, cmd *command.Exp @@ -333,7 +336,31 @@ func (fileService *FileService) ExportFile(ctx *domain.Context, cmd *command.Exp
333 return nil, factory.FastError(err) 336 return nil, factory.FastError(err)
334 } 337 }
335 338
  339 + var (
  340 + config = utils.RouterConfig{
  341 + OssEndPoint: "oss-cn-hangzhou.aliyuncs-internal.com",
  342 + AccessKeyID: "LTAI4Fz1LUBW2fXp6QWaJHRS",
  343 + AccessKeySecret: "aLZXwK8pgrs10Ws03qcN7NsrSXFVsg",
  344 + BuckName: "byte-bank",
  345 + }
  346 + key = fmt.Sprintf("byte-bank/%v/%v", time.Now().Format("2006-01-02"), filename)
  347 + )
  348 + bucket, bucketErr := utils.NewBucket(config)
  349 + if bucketErr == nil && bucket != nil {
  350 + log.Logger.Info(fmt.Sprintf("end-point:%v key:%v", config.OssEndPoint, key))
  351 + f, _ := os.Open(path)
  352 + if err = utils.CreateObjects(bucket, utils.Object{
  353 + Key: key,
  354 + Value: f,
  355 + }); err != nil {
  356 + log.Logger.Error(err.Error())
  357 + } else {
  358 + response.Url = domain.ConvertInternalFileUrlToPublic(fmt.Sprintf("https://%v.%v/%v", config.BuckName, config.OssEndPoint, key))
  359 + }
  360 + }
  361 + if len(response.Url) == 0 {
336 response.Url = domain.DownloadUrl(filename) 362 response.Url = domain.DownloadUrl(filename)
  363 + }
337 response.FileName = file.FileInfo.Name 364 response.FileName = file.FileInfo.Name
338 response.Ext = domain.XLSX 365 response.Ext = domain.XLSX
339 366
@@ -17,6 +17,7 @@ type TablePreviewCommand struct { @@ -17,6 +17,7 @@ type TablePreviewCommand struct {
17 PageSize int `json:"pageSize"` 17 PageSize int `json:"pageSize"`
18 Where domain.Where `json:"where"` 18 Where domain.Where `json:"where"`
19 UseCache bool `json:"useCache"` 19 UseCache bool `json:"useCache"`
  20 + HiddenData bool `json:"hiddenData"` // 隐藏数据,只返回结构
20 } 21 }
21 22
22 func (cmd *TablePreviewCommand) Valid(validation *validation.Validation) { 23 func (cmd *TablePreviewCommand) Valid(validation *validation.Validation) {
@@ -16,6 +16,7 @@ type TablePreviewDto struct { @@ -16,6 +16,7 @@ type TablePreviewDto struct {
16 Fields []*domain.Field `json:"fields"` 16 Fields []*domain.Field `json:"fields"`
17 Data interface{} `json:"grid"` 17 Data interface{} `json:"grid"`
18 //Total int64 `json:"total"` 18 //Total int64 `json:"total"`
  19 + HiddenData bool `json:"-"`
19 } 20 }
20 21
21 func (d *TablePreviewDto) Load(m *domain.Table, dataTable *domain.DataTable, objectType string) *TablePreviewDto { 22 func (d *TablePreviewDto) Load(m *domain.Table, dataTable *domain.DataTable, objectType string) *TablePreviewDto {
@@ -26,6 +27,12 @@ func (d *TablePreviewDto) Load(m *domain.Table, dataTable *domain.DataTable, obj @@ -26,6 +27,12 @@ func (d *TablePreviewDto) Load(m *domain.Table, dataTable *domain.DataTable, obj
26 d.Fields = dataTable.MatchFields(m.Fields(true)) 27 d.Fields = dataTable.MatchFields(m.Fields(true))
27 d.Data = domain.GripData(domain.ToFieldData(m.Fields(true), dataTable.Data, false), dataTable.Total) 28 d.Data = domain.GripData(domain.ToFieldData(m.Fields(true), dataTable.Data, false), dataTable.Total)
28 //d.Total = dataTable.Total 29 //d.Total = dataTable.Total
  30 + if d.HiddenData {
  31 + d.Data = map[string]interface{}{
  32 + "list": make([]map[string]string, 0),
  33 + "total": 0,
  34 + }
  35 + }
29 return d 36 return d
30 } 37 }
31 38
@@ -42,7 +42,7 @@ func (tableService *TableService) TablePreview(ctx *domain.Context, cmd *command @@ -42,7 +42,7 @@ func (tableService *TableService) TablePreview(ctx *domain.Context, cmd *command
42 cacheMiss = true 42 cacheMiss = true
43 } 43 }
44 } 44 }
45 - response := &dto.TablePreviewDto{} 45 + response := &dto.TablePreviewDto{HiddenData: cmd.HiddenData}
46 if dataTable == nil { 46 if dataTable == nil {
47 switch table.TableType { 47 switch table.TableType {
48 case domain.CalculateSet.ToString(): 48 case domain.CalculateSet.ToString():
1 package domain 1 package domain
2 2
  3 +import (
  4 + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/constant"
  5 + "strings"
  6 +)
  7 +
3 // FileInfo 文件信息 8 // FileInfo 文件信息
4 type FileInfo struct { 9 type FileInfo struct {
5 // 名称 10 // 名称
@@ -17,3 +22,31 @@ type FileInfo struct { @@ -17,3 +22,31 @@ type FileInfo struct {
17 // 行号 22 // 行号
18 HeaderRow int `json:"headerRow"` 23 HeaderRow int `json:"headerRow"`
19 } 24 }
  25 +
  26 +// ConvertFileUrlToInternal 传递内网地址
  27 +// byte-bank.oss-cn-hangzhou 当oss与字库同属于这个节点下面,使用内网进行传输
  28 +func ConvertFileUrlToInternal(fileUrl string) string {
  29 + if constant.SERVICE_ENV != "prod" {
  30 + return fileUrl
  31 + }
  32 + var bucketRegion = "https://byte-bank.oss-cn-hangzhou"
  33 + var bucketInternalRegion = "https://byte-bank.oss-cn-hangzhou-internal"
  34 + if strings.HasPrefix(fileUrl, bucketRegion) {
  35 + return strings.Replace(fileUrl, bucketRegion, bucketInternalRegion, 1)
  36 + }
  37 + return fileUrl
  38 +}
  39 +
  40 +// ConvertInternalFileUrlToPublic 转内网地址为外网地址
  41 +func ConvertInternalFileUrlToPublic(fileUrl string) string {
  42 + //var bucketRegion = "https://byte-bank.oss-cn-hangzhou"
  43 + //var bucketInternalRegion = "https://byte-bank.oss-cn-hangzhou-internal"
  44 + //if strings.HasPrefix(fileUrl, bucketInternalRegion) {
  45 + // return strings.Replace(fileUrl, bucketInternalRegion, bucketRegion, 1)
  46 + //}
  47 + var internal = "-internal"
  48 + if strings.Contains(fileUrl, internal) {
  49 + return strings.Replace(fileUrl, internal, "", 1)
  50 + }
  51 + return fileUrl
  52 +}
1 package bytelib 1 package bytelib
2 2
3 -import "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain" 3 +import (
  4 + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
  5 +)
4 6
5 func DomainFieldsToColumnSchemas(fields []*domain.Field) []domain.ColumnSchema { 7 func DomainFieldsToColumnSchemas(fields []*domain.Field) []domain.ColumnSchema {
6 result := make([]domain.ColumnSchema, 0) 8 result := make([]domain.ColumnSchema, 0)
@@ -10,6 +10,7 @@ type RequestCheckoutTablesQuery struct { @@ -10,6 +10,7 @@ type RequestCheckoutTablesQuery struct {
10 OriginalTableId string `json:"originalTableId"` 10 OriginalTableId string `json:"originalTableId"`
11 IsFromOriginalTable bool `json:"isFromOriginalTable"` 11 IsFromOriginalTable bool `json:"isFromOriginalTable"`
12 TableFileUrl string `json:"tableFileUrl"` 12 TableFileUrl string `json:"tableFileUrl"`
  13 + TableFileUrlInternal string `json:"tableFileUrlInternal"`
13 ColumnSchemas []domain.ColumnSchema `json:"columnSchemas"` 14 ColumnSchemas []domain.ColumnSchema `json:"columnSchemas"`
14 PageNumber int `json:"pageNumber"` 15 PageNumber int `json:"pageNumber"`
15 PageSize int `json:"pageSize"` 16 PageSize int `json:"pageSize"`
@@ -44,7 +45,8 @@ func NewRequestCheckoutTablesQuery(param domain.ReqLoadDataTable) RequestCheckou @@ -44,7 +45,8 @@ func NewRequestCheckoutTablesQuery(param domain.ReqLoadDataTable) RequestCheckou
44 return RequestCheckoutTablesQuery{ 45 return RequestCheckoutTablesQuery{
45 OriginalTableId: param.OriginalTableId, 46 OriginalTableId: param.OriginalTableId,
46 IsFromOriginalTable: isSourceFile, 47 IsFromOriginalTable: isSourceFile,
47 - TableFileUrl: tableFileUrl, 48 + TableFileUrl: domain.ConvertFileUrlToInternal(tableFileUrl),
  49 + TableFileUrlInternal: tableFileUrl,
48 ColumnSchemas: param.ColumnSchemas, 50 ColumnSchemas: param.ColumnSchemas,
49 PageNumber: param.PageNumber, 51 PageNumber: param.PageNumber,
50 PageSize: param.PageSize, 52 PageSize: param.PageSize,
@@ -135,6 +137,7 @@ type ( @@ -135,6 +137,7 @@ type (
135 RequestCheckoutTablesGenerateMasterTable struct { 137 RequestCheckoutTablesGenerateMasterTable struct {
136 OriginalTableId string `json:"originalTableId"` 138 OriginalTableId string `json:"originalTableId"`
137 CheckoutTableFileUrl string `json:"checkoutTableFileUrl"` 139 CheckoutTableFileUrl string `json:"checkoutTableFileUrl"`
  140 + CheckoutTableFileUrlInternal string `json:"checkoutTableFileUrlInternal"`
138 ColumnSchemas []domain.ColumnSchema `json:"columnSchemas"` 141 ColumnSchemas []domain.ColumnSchema `json:"columnSchemas"`
139 MasterTableName string `json:"masterTableName"` 142 MasterTableName string `json:"masterTableName"`
140 FieldSchemas []FieldSchema `json:"fieldSchemas"` 143 FieldSchemas []FieldSchema `json:"fieldSchemas"`
@@ -155,7 +158,8 @@ type ( @@ -155,7 +158,8 @@ type (
155 func NewRequestCheckoutTablesGenerateMasterTable(param domain.ReqGenerateTable) RequestCheckoutTablesGenerateMasterTable { 158 func NewRequestCheckoutTablesGenerateMasterTable(param domain.ReqGenerateTable) RequestCheckoutTablesGenerateMasterTable {
156 request := RequestCheckoutTablesGenerateMasterTable{ 159 request := RequestCheckoutTablesGenerateMasterTable{
157 OriginalTableId: fmt.Sprintf("%v", param.FileId), 160 OriginalTableId: fmt.Sprintf("%v", param.FileId),
158 - CheckoutTableFileUrl: param.FileUrl, 161 + CheckoutTableFileUrl: domain.ConvertFileUrlToInternal(param.FileUrl),
  162 + CheckoutTableFileUrlInternal: param.FileUrl,
159 ColumnSchemas: DomainFieldsToColumnSchemas(param.Table.DataFields), 163 ColumnSchemas: DomainFieldsToColumnSchemas(param.Table.DataFields),
160 MasterTableName: param.Table.SQLName, 164 MasterTableName: param.Table.SQLName,
161 FieldSchemas: ToFieldSchemas(param.Table.DataFields), 165 FieldSchemas: ToFieldSchemas(param.Table.DataFields),
@@ -169,6 +173,7 @@ type ( @@ -169,6 +173,7 @@ type (
169 //MasterTableId string `json:"masterTableId"` 173 //MasterTableId string `json:"masterTableId"`
170 OriginalTableId string `json:"originalTableId"` 174 OriginalTableId string `json:"originalTableId"`
171 CheckoutTableFileUrl string `json:"checkoutTableFileUrl"` 175 CheckoutTableFileUrl string `json:"checkoutTableFileUrl"`
  176 + CheckoutTableFileUrlInternal string `json:"checkoutTableFileUrlInternal"`
172 DatabaseTableName string `json:"databaseTableName"` 177 DatabaseTableName string `json:"databaseTableName"`
173 ColumnSchemas []domain.ColumnSchema `json:"columnSchemas"` 178 ColumnSchemas []domain.ColumnSchema `json:"columnSchemas"`
174 FieldSchemas []FieldSchema `json:"fieldSchemas"` 179 FieldSchemas []FieldSchema `json:"fieldSchemas"`
@@ -193,7 +198,8 @@ func NewTableAppendRequest(param domain.ReqAppendData) TableAppendRequest { @@ -193,7 +198,8 @@ func NewTableAppendRequest(param domain.ReqAppendData) TableAppendRequest {
193 columnSchemas := DomainFieldsToColumnSchemas(param.From) 198 columnSchemas := DomainFieldsToColumnSchemas(param.From)
194 req := TableAppendRequest{ 199 req := TableAppendRequest{
195 OriginalTableId: intToString(param.FileId), 200 OriginalTableId: intToString(param.FileId),
196 - CheckoutTableFileUrl: param.FileUrl, 201 + CheckoutTableFileUrl: domain.ConvertFileUrlToInternal(param.FileUrl),
  202 + CheckoutTableFileUrlInternal: param.FileUrl,
197 DatabaseTableName: param.Table.SQLName, 203 DatabaseTableName: param.Table.SQLName,
198 ColumnSchemas: DomainFieldsToColumnSchemas(param.ExcelTable.DataFields), //这里主要需要传递原文件所有字段 param.From 204 ColumnSchemas: DomainFieldsToColumnSchemas(param.ExcelTable.DataFields), //这里主要需要传递原文件所有字段 param.From
199 FieldSchemas: ToFieldSchemas(param.Table.DataFields), 205 FieldSchemas: ToFieldSchemas(param.Table.DataFields),
@@ -41,7 +41,7 @@ func (ptr *FlushDataTableService) Flush(ctx *domain.Context, fileId int, table * @@ -41,7 +41,7 @@ func (ptr *FlushDataTableService) Flush(ctx *domain.Context, fileId int, table *
41 // 临时文件 -》校验文件 41 // 临时文件 -》校验文件
42 var newUrl string 42 var newUrl string
43 if response != nil { 43 if response != nil {
44 - newUrl = response.Url 44 + newUrl = domain.ConvertInternalFileUrlToPublic(response.Url)
45 } 45 }
46 log.Logger.Info("更新文件地址", map[string]interface{}{"from_url": file.FileInfo.Url, "to_url": newUrl, "sourceFileId": file.SourceFileId}) 46 log.Logger.Info("更新文件地址", map[string]interface{}{"from_url": file.FileInfo.Url, "to_url": newUrl, "sourceFileId": file.SourceFileId})
47 switch sourceFile.FileType { 47 switch sourceFile.FileType {
  1 +package utils
  2 +
  3 +import (
  4 + "fmt"
  5 + "github.com/aliyun/aliyun-oss-go-sdk/oss"
  6 + "github.com/google/uuid"
  7 + "io"
  8 + "path"
  9 + "time"
  10 +)
  11 +
  12 +type RouterConfig struct {
  13 + OssEndPoint string
  14 + AccessKeyID string
  15 + AccessKeySecret string
  16 + BuckName string
  17 + AppProject string
  18 +
  19 + RegionID string
  20 + RoleArn string
  21 +}
  22 +
  23 +type (
  24 + CreateStsAuthRequest struct {
  25 + Files []string `json:"files"`
  26 + }
  27 + CreateStsAuthResponse struct {
  28 + Certificate interface{} `json:"certificate"`
  29 + Files []BuckObject `json:"files"`
  30 + }
  31 +
  32 + Object struct {
  33 + Key string
  34 + Value io.Reader
  35 + }
  36 + BuckObject struct {
  37 + DefaultHost string `json:"host"`
  38 + Key string `json:"key"`
  39 + Path string `json:"path"`
  40 + FileName string `json:"fileName"`
  41 + }
  42 +)
  43 +
  44 +func NewBucket(config RouterConfig) (*oss.Bucket, error) {
  45 + client, err := oss.New(config.OssEndPoint, config.AccessKeyID, config.AccessKeySecret)
  46 + if err != nil {
  47 + return nil, err
  48 + }
  49 + bucket, err := client.Bucket(config.BuckName)
  50 + if err != nil {
  51 + return nil, err
  52 + }
  53 +
  54 + return bucket, nil
  55 +}
  56 +
  57 +func CreateObjects(bucket *oss.Bucket, objects ...Object) error {
  58 + for _, object := range objects {
  59 + err := bucket.PutObject(object.Key, object.Value)
  60 + if err != nil {
  61 + return err
  62 + }
  63 + }
  64 + return nil
  65 +}
  66 +
  67 +func DeleteObjects(bucket *oss.Bucket, objects ...string) error {
  68 + for _, object := range objects {
  69 + err := bucket.DeleteObject(object)
  70 + if err != nil {
  71 + return err
  72 + }
  73 + }
  74 + return nil
  75 +}
  76 +
  77 +func GetFileName(projectName, filename string) string {
  78 + date := time.Now().Format("20060102")
  79 + ext := path.Ext(filename)
  80 + if len(projectName) == 0 {
  81 + projectName = "default"
  82 + }
  83 + uid, _ := uuid.NewUUID()
  84 + filename = fmt.Sprintf("%v%v", uid.String(), ext)
  85 + sourcePath := fmt.Sprintf("%v/%v/%v", projectName, date, filename)
  86 + return sourcePath
  87 +}