@@ -3,6 +3,9 @@ package system
3
3
import (
4
4
"fmt"
5
5
"net/http"
6
+ "net/url"
7
+ "sync"
8
+ "time"
6
9
7
10
"github.com/flipped-aurora/gin-vue-admin/server/global"
8
11
"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
@@ -15,6 +18,33 @@ import (
15
18
"go.uber.org/zap"
16
19
)
17
20
21
+ // 用于token一次性存储
22
+ var (
23
+ exportTokenCache = make (map [string ]interface {})
24
+ exportTokenExpiration = make (map [string ]time.Time )
25
+ tokenMutex sync.RWMutex
26
+ )
27
+
28
+ // 五分钟检测窗口过期
29
+ func cleanupExpiredTokens () {
30
+ for {
31
+ time .Sleep (5 * time .Minute )
32
+ tokenMutex .Lock ()
33
+ now := time .Now ()
34
+ for token , expiry := range exportTokenExpiration {
35
+ if now .After (expiry ) {
36
+ delete (exportTokenCache , token )
37
+ delete (exportTokenExpiration , token )
38
+ }
39
+ }
40
+ tokenMutex .Unlock ()
41
+ }
42
+ }
43
+
44
+ func init () {
45
+ go cleanupExpiredTokens ()
46
+ }
47
+
18
48
type SysExportTemplateApi struct {
19
49
}
20
50
@@ -183,7 +213,7 @@ func (sysExportTemplateApi *SysExportTemplateApi) GetSysExportTemplateList(c *gi
183
213
}
184
214
}
185
215
186
- // ExportExcel 导出表格
216
+ // ExportExcel 导出表格token
187
217
// @Tags SysExportTemplate
188
218
// @Summary 导出表格
189
219
// @Security ApiKeyAuth
@@ -192,16 +222,83 @@ func (sysExportTemplateApi *SysExportTemplateApi) GetSysExportTemplateList(c *gi
192
222
// @Router /sysExportTemplate/exportExcel [get]
193
223
func (sysExportTemplateApi * SysExportTemplateApi ) ExportExcel (c * gin.Context ) {
194
224
templateID := c .Query ("templateID" )
195
- queryParams := c .Request .URL .Query ()
196
225
if templateID == "" {
197
226
response .FailWithMessage ("模板ID不能为空" , c )
198
227
return
199
228
}
229
+
230
+ queryParams := c .Request .URL .Query ()
231
+
232
+ //创造一次性token
233
+ token := utils .RandomString (32 ) // 随机32位
234
+
235
+ // 记录本次请求参数
236
+ exportParams := map [string ]interface {}{
237
+ "templateID" : templateID ,
238
+ "queryParams" : queryParams ,
239
+ }
240
+
241
+ // 参数保留记录完成鉴权
242
+ tokenMutex .Lock ()
243
+ exportTokenCache [token ] = exportParams
244
+ exportTokenExpiration [token ] = time .Now ().Add (30 * time .Minute )
245
+ tokenMutex .Unlock ()
246
+
247
+ // 生成一次性链接
248
+ exportUrl := fmt .Sprintf ("/sysExportTemplate/exportExcelByToken?token=%s" , token )
249
+ response .OkWithData (exportUrl , c )
250
+ }
251
+
252
+ // ExportExcelByToken 导出表格
253
+ // @Tags ExportExcelByToken
254
+ // @Summary 导出表格
255
+ // @Security ApiKeyAuth
256
+ // @accept application/json
257
+ // @Produce application/json
258
+ // @Router /sysExportTemplate/exportExcelByToken [get]
259
+ func (sysExportTemplateApi * SysExportTemplateApi ) ExportExcelByToken (c * gin.Context ) {
260
+ token := c .Query ("token" )
261
+ if token == "" {
262
+ response .FailWithMessage ("导出token不能为空" , c )
263
+ return
264
+ }
265
+
266
+ // 获取token并且从缓存中剔除
267
+ tokenMutex .RLock ()
268
+ exportParamsRaw , exists := exportTokenCache [token ]
269
+ expiry , _ := exportTokenExpiration [token ]
270
+ tokenMutex .RUnlock ()
271
+
272
+ if ! exists || time .Now ().After (expiry ) {
273
+ global .GVA_LOG .Error ("导出token无效或已过期!" )
274
+ response .FailWithMessage ("导出token无效或已过期" , c )
275
+ return
276
+ }
277
+
278
+ // 从token获取参数
279
+ exportParams , ok := exportParamsRaw .(map [string ]interface {})
280
+ if ! ok {
281
+ global .GVA_LOG .Error ("解析导出参数失败!" )
282
+ response .FailWithMessage ("解析导出参数失败" , c )
283
+ return
284
+ }
285
+
286
+ // 获取导出参数
287
+ templateID := exportParams ["templateID" ].(string )
288
+ queryParams := exportParams ["queryParams" ].(url.Values )
289
+
290
+ // 清理一次性token
291
+ tokenMutex .Lock ()
292
+ delete (exportTokenCache , token )
293
+ delete (exportTokenExpiration , token )
294
+ tokenMutex .Unlock ()
295
+
296
+ // 导出
200
297
if file , name , err := sysExportTemplateService .ExportExcel (templateID , queryParams ); err != nil {
201
298
global .GVA_LOG .Error ("获取失败!" , zap .Error (err ))
202
299
response .FailWithMessage ("获取失败" , c )
203
300
} else {
204
- c .Header ("Content-Disposition" , fmt .Sprintf ("attachment; filename=%s" , name + utils .RandomString (6 )+ ".xlsx" )) // 对下载的文件重命名
301
+ c .Header ("Content-Disposition" , fmt .Sprintf ("attachment; filename=%s" , name + utils .RandomString (6 )+ ".xlsx" ))
205
302
c .Header ("success" , "true" )
206
303
c .Data (http .StatusOK , "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" , file .Bytes ())
207
304
}
@@ -213,18 +310,91 @@ func (sysExportTemplateApi *SysExportTemplateApi) ExportExcel(c *gin.Context) {
213
310
// @Security ApiKeyAuth
214
311
// @accept application/json
215
312
// @Produce application/json
216
- // @Router /sysExportTemplate/ExportTemplate [get]
313
+ // @Router /sysExportTemplate/exportTemplate [get]
217
314
func (sysExportTemplateApi * SysExportTemplateApi ) ExportTemplate (c * gin.Context ) {
218
315
templateID := c .Query ("templateID" )
219
316
if templateID == "" {
220
317
response .FailWithMessage ("模板ID不能为空" , c )
221
318
return
222
319
}
320
+
321
+ // 创造一次性token
322
+ token := utils .RandomString (32 ) // 随机32位
323
+
324
+ // 记录本次请求参数
325
+ exportParams := map [string ]interface {}{
326
+ "templateID" : templateID ,
327
+ "isTemplate" : true ,
328
+ }
329
+
330
+ // 参数保留记录完成鉴权
331
+ tokenMutex .Lock ()
332
+ exportTokenCache [token ] = exportParams
333
+ exportTokenExpiration [token ] = time .Now ().Add (30 * time .Minute )
334
+ tokenMutex .Unlock ()
335
+
336
+ // 生成一次性链接
337
+ exportUrl := fmt .Sprintf ("/sysExportTemplate/exportTemplateByToken?token=%s" , token )
338
+ response .OkWithData (exportUrl , c )
339
+ }
340
+
341
+ // ExportTemplateByToken 通过token导出表格模板
342
+ // @Tags ExportTemplateByToken
343
+ // @Summary 通过token导出表格模板
344
+ // @Security ApiKeyAuth
345
+ // @accept application/json
346
+ // @Produce application/json
347
+ // @Router /sysExportTemplate/exportTemplateByToken [get]
348
+ func (sysExportTemplateApi * SysExportTemplateApi ) ExportTemplateByToken (c * gin.Context ) {
349
+ token := c .Query ("token" )
350
+ if token == "" {
351
+ response .FailWithMessage ("导出token不能为空" , c )
352
+ return
353
+ }
354
+
355
+ // 获取token并且从缓存中剔除
356
+ tokenMutex .RLock ()
357
+ exportParamsRaw , exists := exportTokenCache [token ]
358
+ expiry , _ := exportTokenExpiration [token ]
359
+ tokenMutex .RUnlock ()
360
+
361
+ if ! exists || time .Now ().After (expiry ) {
362
+ global .GVA_LOG .Error ("导出token无效或已过期!" )
363
+ response .FailWithMessage ("导出token无效或已过期" , c )
364
+ return
365
+ }
366
+
367
+ // 从token获取参数
368
+ exportParams , ok := exportParamsRaw .(map [string ]interface {})
369
+ if ! ok {
370
+ global .GVA_LOG .Error ("解析导出参数失败!" )
371
+ response .FailWithMessage ("解析导出参数失败" , c )
372
+ return
373
+ }
374
+
375
+ // 检查是否为模板导出
376
+ isTemplate , _ := exportParams ["isTemplate" ].(bool )
377
+ if ! isTemplate {
378
+ global .GVA_LOG .Error ("token类型错误!" )
379
+ response .FailWithMessage ("token类型错误" , c )
380
+ return
381
+ }
382
+
383
+ // 获取导出参数
384
+ templateID := exportParams ["templateID" ].(string )
385
+
386
+ // 清理一次性token
387
+ tokenMutex .Lock ()
388
+ delete (exportTokenCache , token )
389
+ delete (exportTokenExpiration , token )
390
+ tokenMutex .Unlock ()
391
+
392
+ // 导出模板
223
393
if file , name , err := sysExportTemplateService .ExportTemplate (templateID ); err != nil {
224
394
global .GVA_LOG .Error ("获取失败!" , zap .Error (err ))
225
395
response .FailWithMessage ("获取失败" , c )
226
396
} else {
227
- c .Header ("Content-Disposition" , fmt .Sprintf ("attachment; filename=%s" , name + "模板.xlsx" )) // 对下载的文件重命名
397
+ c .Header ("Content-Disposition" , fmt .Sprintf ("attachment; filename=%s" , name + "模板.xlsx" ))
228
398
c .Header ("success" , "true" )
229
399
c .Data (http .StatusOK , "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" , file .Bytes ())
230
400
}
0 commit comments