inleft
2022-08-31 aae48957ba971ed0a1bfbfa182701cd22bbe8694
commit | author | age
9bcb19 1 /*
I 2 Copyright [2020] [https://www.xiaonuo.vip]
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8   http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15
16 Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
17
18 1.请不要删除和修改根目录下的LICENSE文件。
19 2.请不要删除和修改Snowy源码头部的版权声明。
20 3.请保留源码和相关描述文件的项目出处,作者声明等。
21 4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuobase/snowy
22 5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuobase/snowy
23 6.若您的项目无法满足以上几点,可申请商业授权,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
24  */
25 package vip.xiaonuo.sys.modular.file.service.impl;
26
27 import cn.hutool.core.bean.BeanUtil;
28 import cn.hutool.core.convert.Convert;
29 import cn.hutool.core.date.DateUtil;
30 import cn.hutool.core.io.FileUtil;
31 import cn.hutool.core.io.IoUtil;
32 import cn.hutool.core.lang.Dict;
33 import cn.hutool.core.util.NumberUtil;
34 import cn.hutool.core.util.ObjectUtil;
35 import cn.hutool.core.util.StrUtil;
36 import cn.hutool.json.JSONUtil;
37 import cn.hutool.log.Log;
38 import com.alibaba.fastjson.JSONObject;
39 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
40 import com.baomidou.mybatisplus.core.toolkit.IdWorker;
41 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
42 import org.springframework.http.MediaType;
43 import org.springframework.stereotype.Service;
44 import org.springframework.transaction.annotation.Transactional;
45 import org.springframework.web.multipart.MultipartFile;
46 import vip.xiaonuo.core.consts.CommonConstant;
47 import vip.xiaonuo.core.consts.SymbolConstant;
48 import vip.xiaonuo.core.context.login.LoginContextHolder;
49 import vip.xiaonuo.core.context.requestno.RequestNoContext;
50 import vip.xiaonuo.core.exception.LibreOfficeException;
51 import vip.xiaonuo.core.exception.ServiceException;
52 import vip.xiaonuo.core.factory.PageFactory;
53 import vip.xiaonuo.core.file.FileOperator;
54 import vip.xiaonuo.core.file.modular.local.LocalFileOperator;
55 import vip.xiaonuo.core.pojo.login.SysLoginUser;
56 import vip.xiaonuo.core.pojo.page.PageResult;
57 import vip.xiaonuo.core.util.HttpServletUtil;
58 import vip.xiaonuo.core.util.LibreOfficeUtil;
59 import vip.xiaonuo.sys.modular.file.entity.SysFileInfo;
60 import vip.xiaonuo.sys.modular.file.enums.SysFileInfoExceptionEnum;
d80267 61 import vip.xiaonuo.sys.modular.file.enums.SysFileLocationEnum;
9bcb19 62 import vip.xiaonuo.sys.modular.file.mapper.SysFileInfoMapper;
I 63 import vip.xiaonuo.sys.modular.file.param.SysFileInfoParam;
64 import vip.xiaonuo.sys.modular.file.result.SysFileInfoResult;
65 import vip.xiaonuo.sys.modular.file.result.SysOnlineFileInfoResult;
66 import vip.xiaonuo.sys.modular.file.service.SysFileInfoService;
67 import vip.xiaonuo.sys.modular.file.util.DownloadUtil;
68 import vip.xiaonuo.sys.modular.file.util.OnlineDocumentUtil;
69
70 import javax.annotation.Resource;
71 import javax.servlet.ServletOutputStream;
72 import javax.servlet.http.HttpServletRequest;
73 import javax.servlet.http.HttpServletResponse;
74 import java.io.File;
75 import java.io.FileWriter;
76 import java.io.IOException;
77 import java.io.InputStream;
78 import java.math.BigDecimal;
79 import java.nio.charset.Charset;
80 import java.util.Arrays;
81 import java.util.List;
82 import java.util.Scanner;
83
84 import static vip.xiaonuo.sys.config.FileConfig.DEFAULT_BUCKET;
85
86 /**
87  * 文件信息表 服务实现类
88  *
89  * @author yubaoshan
90  * @date 2020/6/7 22:15
91  */
92 @Service
93 public class SysFileInfoServiceImpl extends ServiceImpl<SysFileInfoMapper, SysFileInfo> implements SysFileInfoService {
94
95     private static final Log log = Log.get();
96
97     @Resource
98     private FileOperator fileOperator;
99
100     @Override
101     public SysOnlineFileInfoResult onlineAddOrUpdate(SysFileInfoParam sysFileInfoParam) {
d80267 102         if (fileOperator instanceof LocalFileOperator) {
9bcb19 103             //文件后缀
I 104             String fileSuffix = sysFileInfoParam.getFileSuffix();
105             //文件名称
106             String fileOriginName = sysFileInfoParam.getFileOriginName();
107             //文件id
108             Long id = sysFileInfoParam.getId();
109             //参数错误
d80267 110             if (ObjectUtil.isAllEmpty(fileSuffix, fileOriginName, id)) {
9bcb19 111                 throw new ServiceException(SysFileInfoExceptionEnum.ONLINE_EDIT_PARAM_ERROR);
I 112             }
113             //获取登录用户
114             SysLoginUser sysLoginUser = LoginContextHolder.me().getSysLoginUser();
115             SysFileInfo sysFileInfo;
116             SysOnlineFileInfoResult sysOnlineFileInfoResult;
117             //文件id不为空则表示编辑
d80267 118             if (ObjectUtil.isNotEmpty(id)) {
9bcb19 119                 sysFileInfo = this.getById(id);
d80267 120                 sysOnlineFileInfoResult = new SysOnlineFileInfoResult(Convert.toStr(sysFileInfo.getId()), sysFileInfo.getFileOriginName(), Convert.toStr(sysLoginUser.getId()), sysLoginUser.getName());
9bcb19 121             } else {
I 122                 //否则表示新增
123                 Boolean sample = sysFileInfoParam.getSample();
124                 sysFileInfo = createDemo(fileSuffix, fileOriginName, sample, Convert.toStr(sysLoginUser.getId()), sysLoginUser.getName());
d80267 125                 sysOnlineFileInfoResult = new SysOnlineFileInfoResult(Convert.toStr(sysFileInfo.getId()), fileOriginName + SymbolConstant.PERIOD + fileSuffix, Convert.toStr(sysLoginUser.getId()), sysLoginUser.getName());
9bcb19 126
I 127             }
128             //设置history
129             sysOnlineFileInfoResult.history = OnlineDocumentUtil.getHistory(sysOnlineFileInfoResult);
d80267 130             if (ObjectUtil.isAllNotEmpty(sysFileInfoParam.getMode(), sysFileInfoParam.getType())) {
9bcb19 131                 sysOnlineFileInfoResult.changeType(sysFileInfoParam.getMode(), sysFileInfoParam.getType());
I 132             }
133             return sysOnlineFileInfoResult;
134         } else {
135             //暂时只支持本地文件
136             throw new ServiceException(SysFileInfoExceptionEnum.ONLINE_EDIT_SUPPORT_LOCAL_ONLY);
137         }
138     }
139
140     @Override
141     public PageResult<SysFileInfo> page(SysFileInfoParam sysFileInfoParam) {
142
143         // 构造条件
144         LambdaQueryWrapper<SysFileInfo> queryWrapper = new LambdaQueryWrapper<>();
145
146         // 拼接查询条件-文件存储位置(1:阿里云,2:腾讯云,3:minio,4:本地)
147         if (ObjectUtil.isNotNull(sysFileInfoParam)) {
148             if (ObjectUtil.isNotEmpty(sysFileInfoParam.getFileLocation())) {
149                 queryWrapper.like(SysFileInfo::getFileLocation, sysFileInfoParam.getFileLocation());
150             }
151
152             // 拼接查询条件-文件仓库
153             if (ObjectUtil.isNotEmpty(sysFileInfoParam.getFileBucket())) {
154                 queryWrapper.like(SysFileInfo::getFileBucket, sysFileInfoParam.getFileBucket());
155             }
156
157             // 拼接查询条件-文件名称(上传时候的文件名)
158             if (ObjectUtil.isNotEmpty(sysFileInfoParam.getFileOriginName())) {
159                 queryWrapper.like(SysFileInfo::getFileOriginName, sysFileInfoParam.getFileOriginName());
160             }
161
162             // 根据后缀查询
d80267 163             if (ObjectUtil.isNotEmpty(sysFileInfoParam.getFileSuffix())) {
I 164                 if (sysFileInfoParam.getFileSuffix().contains(SymbolConstant.COMMA)) {
9bcb19 165                     queryWrapper.in(SysFileInfo::getFileSuffix, Arrays.asList(sysFileInfoParam.getFileSuffix().split(SymbolConstant.COMMA)));
I 166                 } else {
167                     queryWrapper.eq(SysFileInfo::getFileSuffix, sysFileInfoParam.getFileSuffix());
168                 }
169             }
170         }
171
172         // 查询分页结果
173         return new PageResult<>(this.page(PageFactory.defaultPage(), queryWrapper));
174     }
175
176     @Override
177     public List<SysFileInfo> list(SysFileInfoParam sysFileInfoParam) {
178
179         // 构造条件
180         LambdaQueryWrapper<SysFileInfo> queryWrapper = new LambdaQueryWrapper<>();
181
182         return this.list(queryWrapper);
183     }
184
185     @Override
186     public void add(SysFileInfoParam sysFileInfoParam) {
187
188         // 将dto转为实体
189         SysFileInfo sysFileInfo = new SysFileInfo();
190         BeanUtil.copyProperties(sysFileInfoParam, sysFileInfo);
191
192         this.save(sysFileInfo);
193     }
194
195     @Transactional(rollbackFor = Exception.class)
196     @Override
197     public void delete(SysFileInfoParam sysFileInfoParam) {
198
199         // 查询文件的信息
200         SysFileInfo sysFileInfo = this.getById(sysFileInfoParam.getId());
201
202         // 删除文件记录
203         this.removeById(sysFileInfoParam.getId());
204
205         // 删除具体文件
206         this.fileOperator.deleteFile(sysFileInfo.getFileBucket(), sysFileInfo.getFileObjectName());
207     }
208
209     @Override
210     public void edit(SysFileInfoParam sysFileInfoParam) {
211
212         // 根据id查询实体
213         SysFileInfo sysFileInfo = this.querySysFileInfo(sysFileInfoParam);
214
215         // 请求参数转化为实体
216         BeanUtil.copyProperties(sysFileInfoParam, sysFileInfo);
217
218         this.updateById(sysFileInfo);
219     }
220
221     @Override
222     public SysFileInfo detail(SysFileInfoParam sysFileInfoParam) {
223         return this.querySysFileInfo(sysFileInfoParam);
224     }
225
226     @Override
227     public Long uploadFile(MultipartFile file) {
d80267 228         return this.uploadFileBlog(file, DEFAULT_BUCKET);
I 229     }
230
231     @Override
232     public Long uploadFileBlog(MultipartFile file, String bucket) {
9bcb19 233
I 234         // 生成文件的唯一id
235         Long fileId = IdWorker.getId();
236
237         // 获取文件原始名称
238         String originalFilename = file.getOriginalFilename();
239
240         // 获取文件后缀
241         String fileSuffix = null;
242
243         if (ObjectUtil.isNotEmpty(originalFilename)) {
244             fileSuffix = StrUtil.subAfter(originalFilename, SymbolConstant.PERIOD, true);
245         }
246         // 生成文件的最终名称
247         String finalName = fileId + SymbolConstant.PERIOD + fileSuffix;
248
249         // 存储文件
250         byte[] bytes;
251         try {
252             bytes = file.getBytes();
d80267 253             fileOperator.storageFile(bucket, finalName, bytes);
9bcb19 254         } catch (IOException e) {
I 255             throw new ServiceException(SysFileInfoExceptionEnum.ERROR_FILE);
256         }
257
258         // 计算文件大小kb
259         long fileSizeKb = Convert.toLong(NumberUtil.div(new BigDecimal(file.getSize()), BigDecimal.valueOf(1024))
260                 .setScale(0, BigDecimal.ROUND_HALF_UP));
261
262         //计算文件大小信息
263         String fileSizeInfo = FileUtil.readableFileSize(file.getSize());
264
265         // 存储文件信息
266         SysFileInfo sysFileInfo = new SysFileInfo();
267         sysFileInfo.setId(fileId);
268         sysFileInfo.setFileLocation(SysFileLocationEnum.LOCAL.getCode());
d80267 269         sysFileInfo.setFileBucket(bucket);
9bcb19 270         sysFileInfo.setFileObjectName(finalName);
I 271         sysFileInfo.setFileOriginName(originalFilename);
272         sysFileInfo.setFileSuffix(fileSuffix);
273         sysFileInfo.setFileSizeKb(fileSizeKb);
274         sysFileInfo.setFileSizeInfo(fileSizeInfo);
275         this.save(sysFileInfo);
276
277         // 返回文件id
278         return fileId;
279     }
280
281     @Override
282     public SysFileInfoResult getFileInfoResult(Long fileId) {
283         byte[] fileBytes;
284         // 获取文件名
285         SysFileInfo sysFileInfo = this.getById(fileId);
286         if (sysFileInfo == null) {
287             throw new ServiceException(SysFileInfoExceptionEnum.NOT_EXISTED_FILE);
288         }
289         try {
290             // 返回文件字节码
291             fileBytes = fileOperator.getFileBytes(DEFAULT_BUCKET, sysFileInfo.getFileObjectName());
292         } catch (Exception e) {
293             log.error(">>> 获取文件流异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), e.getMessage());
294             throw new ServiceException(SysFileInfoExceptionEnum.FILE_STREAM_ERROR);
295         }
296
297         SysFileInfoResult sysFileInfoResult = new SysFileInfoResult();
298         BeanUtil.copyProperties(sysFileInfo, sysFileInfoResult);
299         sysFileInfoResult.setFileBytes(fileBytes);
300
301         return sysFileInfoResult;
302     }
303
304     @Override
305     public void assertFile(Long field) {
306         SysFileInfo sysFileInfo = this.getById(field);
307         if (ObjectUtil.isEmpty(sysFileInfo)) {
308             throw new ServiceException(SysFileInfoExceptionEnum.NOT_EXISTED);
309         }
310     }
311
312     @Override
313     public void preview(SysFileInfoParam sysFileInfoParam, HttpServletResponse response) {
314
315         byte[] fileBytes;
316         //根据文件id获取文件信息结果集
317         SysFileInfoResult sysFileInfoResult = this.getFileInfoResult(sysFileInfoParam.getId());
318         //获取文件后缀
319         String fileSuffix = sysFileInfoResult.getFileSuffix().toLowerCase();
320         //获取文件字节码
321         fileBytes = sysFileInfoResult.getFileBytes();
322         //如果是图片类型,则直接输出
323         if (LibreOfficeUtil.isPic(fileSuffix)) {
324             try {
325                 //设置contentType
326                 response.setContentType(MediaType.IMAGE_JPEG_VALUE);
327                 //获取outputStream
328                 ServletOutputStream outputStream = response.getOutputStream();
329                 //输出
330                 IoUtil.write(outputStream, true, fileBytes);
331             } catch (IOException e) {
332                 throw new ServiceException(SysFileInfoExceptionEnum.PREVIEW_ERROR_NOT_SUPPORT);
333             }
334
335         } else if (LibreOfficeUtil.isDoc(fileSuffix)) {
336             try {
337                 //如果是文档类型,则使用libreoffice转换为pdf或html
338                 InputStream inputStream = IoUtil.toStream(fileBytes);
339
340                 //获取目标contentType(word和ppt和text转成pdf,excel转成html)
341                 String targetContentType = LibreOfficeUtil.getTargetContentTypeBySuffix(fileSuffix);
342
343                 //设置contentType
344                 response.setContentType(targetContentType);
345
346                 //获取outputStream
347                 ServletOutputStream outputStream = response.getOutputStream();
348
349                 //转换
350                 LibreOfficeUtil.convertToPdf(inputStream, outputStream, fileSuffix);
351
352                 //输出
353                 IoUtil.write(outputStream, true, fileBytes);
354             } catch (IOException e) {
355                 log.error(">>> 预览文件异常", e.getMessage());
356                 throw new ServiceException(SysFileInfoExceptionEnum.PREVIEW_ERROR_NOT_SUPPORT);
357
358             } catch (LibreOfficeException e) {
359                 log.error(">>> 初始化LibreOffice失败", e.getMessage());
360                 throw new ServiceException(SysFileInfoExceptionEnum.PREVIEW_ERROR_LIBREOFFICE);
361             }
362
363         } else {
364             //否则不支持预览(暂时)
365             throw new ServiceException(SysFileInfoExceptionEnum.PREVIEW_ERROR_NOT_SUPPORT);
366         }
367     }
368
369     @Override
370     public void download(SysFileInfoParam sysFileInfoParam, HttpServletResponse response) {
371         // 获取文件信息结果集
372         SysFileInfoResult sysFileInfoResult = this.getFileInfoResult(sysFileInfoParam.getId());
373         String fileName = sysFileInfoResult.getFileOriginName();
374         byte[] fileBytes = sysFileInfoResult.getFileBytes();
375         DownloadUtil.download(fileName, fileBytes, response);
376     }
377
378     /**
379      * 获取文件信息表
380      *
381      * @author yubaoshan
382      * @date 2020/6/7 22:15
383      */
384     private SysFileInfo querySysFileInfo(SysFileInfoParam sysFileInfoParam) {
385         SysFileInfo sysFileInfo = this.getById(sysFileInfoParam.getId());
386         if (ObjectUtil.isEmpty(sysFileInfo)) {
387             throw new ServiceException(SysFileInfoExceptionEnum.NOT_EXISTED);
388         }
389         return sysFileInfo;
390     }
391
392     @Override
393     public void track() {
394         HttpServletRequest request = HttpServletUtil.getRequest();
395         HttpServletResponse response = HttpServletUtil.getResponse();
396         String fileObjectName = request.getParameter("fileObjectName");
397         String id = request.getParameter("id");
398         String storagePath = OnlineDocumentUtil.getStoragePath(id + SymbolConstant.PERIOD + FileUtil.getSuffix(fileObjectName));
399         String body = "";
400         Scanner scanner;
401
402         try {
403             scanner = new Scanner(request.getInputStream());
404             scanner.useDelimiter("\\A");
405             body = scanner.hasNext() ? scanner.next() : "";
406             scanner.close();
407         } catch (IOException e) {
408             e.printStackTrace();
409         }
410
411         JSONObject jsonObj;
412
413         if (body.isEmpty()) {
414             log.error(">>> 读取文件request输入流为空");
415             return;
416         }
417
418         try {
419             jsonObj = JSONObject.parseObject(body);
420         } catch (Exception ex) {
421             log.error(">>> 文件信息body格式化错误");
422             return;
423         }
424
425         int status = (int) jsonObj.get("status");
d80267 426         String downloadUri = (String) jsonObj.get("url");
9bcb19 427         String changesUri = (String) jsonObj.get("changesurl");
I 428         String key = (String) jsonObj.get("key");
429
430         int saved = 0;
431         if (status == 2 || status == 3) {
432             //MustSave, Corrupted
433             try {
434                 String histDir = OnlineDocumentUtil.getHistoryDir(OnlineDocumentUtil.getStoragePath(id));
d80267 435                 String versionDir = OnlineDocumentUtil.getVersionDir(histDir, OnlineDocumentUtil.getFileVersion(histDir) + 1);
9bcb19 436                 File ver = new File(versionDir);
I 437                 File toSave = new File(storagePath);
438                 if (!ver.exists()) ver.mkdirs();
439                 toSave.renameTo(new File(versionDir + File.separator + "prev" + SymbolConstant.PERIOD + FileUtil.getSuffix(fileObjectName)));
440                 DownloadUtil.downloadToFile(downloadUri, toSave);
441                 DownloadUtil.downloadToFile(changesUri, new File(versionDir + File.separator + "diff.zip"));
442
443                 String history = (String) jsonObj.get("changeshistory");
444                 if (history == null && jsonObj.containsKey("history")) {
445                     history = ((JSONObject) jsonObj.get("history")).toJSONString();
446                 }
447                 if (history != null && !history.isEmpty()) {
448                     FileWriter fw = new FileWriter(new File(versionDir + File.separator + "changes.json"));
449                     fw.write(history);
450                     fw.close();
451                 }
452
453                 FileWriter fw = new FileWriter(new File(versionDir + File.separator + "key.txt"));
454                 fw.write(key);
455                 fw.close();
456             } catch (Exception ex) {
457                 saved = 1;
458             }
459         }
460         try {
461             response.getWriter().write("{\"error\":" + saved + "}");
462         } catch (IOException e) {
463             e.printStackTrace();
464         }
465     }
466
467     /**
468      * 创建模板文件
469      *
d80267 470      * @param fileSuffix       文件后缀
9bcb19 471      * @param originalFilename 文件原始名称
d80267 472      * @param sample           是否创建相同文件内容的模板文件
I 473      * @param userId           用户id
474      * @param userName         用户名称
9bcb19 475      * @author xuyuxiang
I 476      * @date 2021/3/24 11:01
477      */
478     public SysFileInfo createDemo(String fileSuffix, String originalFilename, Boolean sample, String userId, String userName) {
479         // 文件名称拼接
480         originalFilename = originalFilename + SymbolConstant.PERIOD + fileSuffix;
481         // 模板名称
482         String demoName = (sample ? "sample." : "new.") + fileSuffix;
483         InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("assets/" + demoName);
484         // 生成文件的唯一id
485         Long fileId = IdWorker.getId();
486         // 生成文件的最终名称
487         String finalName = fileId + SymbolConstant.PERIOD + fileSuffix;
488         // 读取流
489         byte[] bytes = IoUtil.readBytes(stream);
490         // 将该模板文件存到存储桶
491         fileOperator.storageFile(DEFAULT_BUCKET, finalName, bytes);
492         // 创建元数据信息
493         createMeta(Convert.toStr(fileId), userId, userName);
494         // 计算文件大小kb
495         long fileSizeKb = Convert.toLong(NumberUtil.div(new BigDecimal(bytes.length), BigDecimal.valueOf(1024))
496                 .setScale(0, BigDecimal.ROUND_HALF_UP));
497         // 计算文件大小信息
498         String fileSizeInfo = FileUtil.readableFileSize(bytes.length);
499         // 存储文件信息
500         SysFileInfo sysFileInfo = new SysFileInfo();
501         sysFileInfo.setId(fileId);
502         sysFileInfo.setFileLocation(SysFileLocationEnum.LOCAL.getCode());
503         sysFileInfo.setFileBucket(DEFAULT_BUCKET);
504         sysFileInfo.setFileObjectName(finalName);
505         sysFileInfo.setFileOriginName(originalFilename);
506         sysFileInfo.setFileSuffix(fileSuffix);
507         sysFileInfo.setFileSizeKb(fileSizeKb);
508         sysFileInfo.setFileSizeInfo(fileSizeInfo);
509         // 将新创建的文件保存到数据库
510         this.save(sysFileInfo);
511         return sysFileInfo;
512     }
513
514     /**
515      * 创建元数据信息
516      *
d80267 517      * @param fileId   文件id
I 518      * @param userId   用户id
9bcb19 519      * @param userName 用户名称
I 520      * @author xuyuxiang
521      * @date 2021/3/24 11:19
522      */
523     public void createMeta(String fileId, String userId, String userName) {
524         // 仅限本地文件
525         Object localClient = fileOperator.getClient();
d80267 526         if (ObjectUtil.isNull(localClient)) {
9bcb19 527             throw new ServiceException(SysFileInfoExceptionEnum.CLIENT_INIT_ERROR);
I 528         }
529         Dict localClientDict = (Dict) localClient;
530         // 拼接获取文档历史路径
531         String histDir = localClientDict.getStr("currentSavePath") + File.separator + DEFAULT_BUCKET + File.separator + fileId + "-hist";
d80267 532         if (!FileUtil.exist(histDir)) {
9bcb19 533             // 历史路径不存在则创建
I 534             File dir = new File(histDir);
535             dir.mkdir();
536         }
537         Dict dict = new Dict();
538         dict.put("created", DateUtil.now());
539         dict.put("id", (userId == null || userId.isEmpty()) ? -1 : userId);
540         dict.put("name", (userName == null || userName.isEmpty()) ? CommonConstant.UNKNOWN : userName);
541         File metaFile = new File(histDir + File.separator + "createdInfo.json");
542         FileUtil.writeString(JSONUtil.toJsonStr(dict), metaFile, Charset.defaultCharset());
543     }
544
545 }