chenrui
2025-05-20 1fd5eac12e532a9906e0c1d57676c692c68d1f32
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package com.ruoyi.sales.service.impl;
 
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.other.mapper.TempFileMapper;
import com.ruoyi.other.pojo.TempFile;
import com.ruoyi.sales.mapper.CommonFileMapper;
import com.ruoyi.sales.pojo.CommonFile;
import com.ruoyi.sales.service.ICommonFileService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
 
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
 
@Service
@RequiredArgsConstructor
@Slf4j
public class CommonFileServiceImpl extends ServiceImpl<CommonFileMapper, CommonFile> implements ICommonFileService {
 
    private final CommonFileMapper commonFileMapper;
 
    private final TempFileMapper tempFileMapper;
 
    @Value("${file.upload-dir}")
    private String uploadDir;
 
 
    @Override
    public int deleteSalesLedgerByIds(Long[] ids) {
        return commonFileMapper.deleteBatchIds(Arrays.asList(ids));
    }
 
    @Override
    public CommonFile uploadFile(MultipartFile file, Long id, String type) throws IOException {
        // 1. 生成正式文件ID和路径
        String tempId = UUID.randomUUID().toString();
        Path tempFilePath = Paths.get(uploadDir, tempId + "_" + file.getOriginalFilename());
 
        // 2. 确保目录存在
        Path parentDir = tempFilePath.getParent();
        if (parentDir != null) {
            Files.createDirectories(parentDir); // 递归创建目录
        }
 
        // 3. 保存文件到目录
        file.transferTo(tempFilePath.toFile());
 
        // 4. 保存文件记录
        CommonFile commonFile = new CommonFile();
        commonFile.setCommonId(id);
        commonFile.setName(file.getOriginalFilename());
        commonFile.setUrl(tempFilePath.toString());
        commonFile.setType(type);
        commonFileMapper.insert(commonFile);
        return commonFile;
    }
 
    @Override
    public int delCommonFileByIds(Long[] ids) {
        return commonFileMapper.deleteBatchIds(Arrays.asList(ids));
    }
 
    /**
     * 将临时文件迁移到正式目录
     *
     * @param businessId  业务ID(销售台账ID)
     * @param tempFileIds 临时文件ID列表
     * @throws IOException 文件操作异常
     */
    @Transactional(rollbackFor = Exception.class)
    public void migrateTempFilesToFormal(Long businessId, List<String> tempFileIds) throws IOException {
        if (CollectionUtils.isEmpty(tempFileIds)) {
            return;
        }
 
        // 构建正式目录路径(按业务类型和日期分组)
        String formalDir = uploadDir + LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE);
 
        Path formalDirPath = Paths.get(formalDir);
 
        // 确保正式目录存在(递归创建)
        if (!Files.exists(formalDirPath)) {
            Files.createDirectories(formalDirPath);
        }
 
        for (String tempFileId : tempFileIds) {
            // 查询临时文件记录
            TempFile tempFile = tempFileMapper.selectById(tempFileId);
            if (tempFile == null) {
                log.warn("临时文件不存在,跳过处理: {}", tempFileId);
                continue;
            }
 
            // 构建正式文件名(包含业务ID和时间戳,避免冲突)
            String originalFilename = tempFile.getOriginalName();
            String fileExtension = FilenameUtils.getExtension(originalFilename);
            String formalFilename = businessId + "_" +
                    System.currentTimeMillis() + "_" +
                    UUID.randomUUID().toString().substring(0, 8) +
                    (com.ruoyi.common.utils.StringUtils.hasText(fileExtension) ? "." + fileExtension : "");
 
            Path formalFilePath = formalDirPath.resolve(formalFilename);
 
            try {
                // 执行文件迁移(使用原子操作确保安全性)
                Files.move(
                        Paths.get(tempFile.getTempPath()),
                        formalFilePath,
                        StandardCopyOption.REPLACE_EXISTING,
                        StandardCopyOption.ATOMIC_MOVE
                );
                log.info("文件迁移成功: {} -> {}", tempFile.getTempPath(), formalFilePath);
 
                // 更新文件记录(关联到业务ID)
                CommonFile fileRecord = new CommonFile();
                fileRecord.setCommonId(businessId);
                fileRecord.setName(originalFilename);
                fileRecord.setUrl(formalFilePath.toString());
                fileRecord.setCreateTime(LocalDateTime.now());
                fileRecord.setType(tempFile.getType());
                commonFileMapper.insert(fileRecord);
 
                log.info("文件迁移成功: {} -> {}", tempFile.getTempPath(), formalFilePath);
            } catch (IOException e) {
                log.error("文件迁移失败: {}", tempFile.getTempPath(), e);
                // 可选择回滚事务或记录失败文件
                throw new IOException("文件迁移异常", e);
            }
        }
    }
}