cjl
2023-09-22 3321d513cbab14a70d0123708f1352d61456966e
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
package com.moral.api.service.impl;
 
import com.moral.api.config.Interceptor.UserHelper;
import com.moral.api.entity.FileTable;
import com.moral.api.exception.BusinessException;
import com.moral.api.mapper.FileTableMapper;
import com.moral.api.pojo.enums.FileType;
import com.moral.api.pojo.vo.file.FileVo;
import com.moral.api.pojo.vo.user.QxUser;
import com.moral.api.service.FileTableService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.moral.api.utils.FileTypeUtils;
import com.moral.api.utils.StringUtils;
import com.moral.util.DateUtils;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.*;
 
/**
 * <p>
 * 附件表 服务实现类
 * </p>
 *
 * @author moral
 * @since 2023-09-21
 */
@Service
@Slf4j
public class FileTableServiceImpl extends ServiceImpl<FileTableMapper, FileTable> implements FileTableService {
    @Value("${file.path}")
    private String basePath;
    @Override
    public FileVo upload(MultipartFile file, Integer sysCode) {
        String originalFilename = file.getOriginalFilename().replaceAll(StringUtils.SPACE, StringUtils.EMPTY).toLowerCase();
        String suffix = originalFilename.substring(originalFilename.lastIndexOf(StringUtils.DOT));
        FileType fileType = FileTypeUtils.getFileType(suffix.toLowerCase());
        // 处理文件相对路径  系统代码 + 业务代码 + 日期
        String filePath = getFilePath(sysCode.toString());
        // 保存文件
        String targetFolder = basePath.replaceAll(StringUtils.BACKSLASH.concat(StringUtils.BACKSLASH), StringUtils.SLASH).concat(StringUtils.SLASH).concat(filePath);
        //使用uuid 替换上传文件名,避免重复
        String storageFileName = UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf(StringUtils.DOT));
        storageFile(file, storageFileName, targetFolder);
 
        // 封装文件信息
        QxUser user = UserHelper.getCurrentUser();
        FileTable sysFile = new FileTable();
        sysFile.setFileName(originalFilename).setFileType(fileType.getValue()).setFileSize((int) file.getSize()).setFileAddress(filePath.concat(storageFileName))
                .setFileModule(sysCode).setCreateTime(new Date());
        if (Objects.nonNull(user)) {
            sysFile.setCreateId(user.getUserId()).setCreateName(user.getUserName());
        }
        save(sysFile);
        return new FileVo().setFileId(sysFile.getFileId()).setFileName(originalFilename);
    }
 
    @Override
    public List<FileVo> upload(List<MultipartFile> files, Integer sysCode) {
        List<FileVo> fileList = new LinkedList<>();
        for (MultipartFile file : files) {
            fileList.add(upload(file, sysCode));
        }
        return fileList;
    }
 
    @Override
    public void preview(Integer id, HttpServletRequest request, HttpServletResponse response) {
        FileTable sysFile = getById(id);
        File file = new File(handleFileRealPath(sysFile.getFileAddress()));
        String suffix = file.getName().substring(file.getName().lastIndexOf(StringUtils.DOT));
        if (FileTypeUtils.SUFFIX_MP4.equals(suffix)) {
            videoPreview(file, request, response);
        } else {
            try (OutputStream out = response.getOutputStream(); InputStream in = new FileInputStream(file)) {
                response.setContentType(FileTypeUtils.convertHeaderType(suffix));
                response.setHeader("Content-Disposition", "inline; filename=" + URLEncoder.encode(sysFile.getFileName(), "UTF-8"));
                int len;
                // 创建数据缓冲区
                byte[] buffer = new byte[1024];
                while ((len = in.read(buffer)) > 0) {
                    out.write(buffer, 0, len);
                }
            } catch (Exception e) {
                log.error("读取文件异常!!! e={}", e.getMessage());
            }
        }
    }
 
    private String getFilePath(String sysCode) {
        return sysCode.concat(StringUtils.SLASH).concat(StringUtils.SLASH).concat(DateUtils.dateToDateString(new Date(),DateUtils.yyyyMMdd_EN)).concat(StringUtils.SLASH);
    }
 
    public void storageFile(MultipartFile file, String originalFilename, String targetFolder) {
        File f = new File(targetFolder, originalFilename);
        try {
            // 保存文件
            if (!f.getParentFile().exists()) {
                if (!f.getParentFile().mkdirs()) {
                    log.error("error:创建文件失败! dir={}", f.getAbsolutePath());
                }
            }
            file.transferTo(f);
        } catch (IOException e) {
            log.error("error:文件上传失败!!!e={}", e.getMessage());
            throw new BusinessException("文件上传失败,请重试!");
        }
    }
    private String handleFileRealPath(String path) {
        return basePath.replaceAll(StringUtils.BACKSLASH.concat(StringUtils.BACKSLASH), StringUtils.SLASH).concat(StringUtils.SLASH).concat(path);
    }
    private void videoPreview(File file, HttpServletRequest request, HttpServletResponse response) {
        String suffix = file.getName().substring(file.getName().lastIndexOf(StringUtils.DOT));
        //设置属性
        response.setContentType(FileTypeUtils.convertHeaderType(suffix));
        response.setHeader("Accept-Ranges", "bytes");
        response.setHeader("ETag", file.getName());
        response.setHeader("Last-Modified", new Date().toString());
        long contentLength = file.length();
 
        //每次传递实际长度(初始第一次读取少选数据)
        long length = Math.min(contentLength, 1024);
        long start = 0, end = 0;
        String range = request.getHeader("Range");
        //第一次请求只返回content length来让客户端请求多次实际数据
        if (range == null) {
            response.setHeader("Content-length", contentLength + "");
        } else {
            //以后的多次以断点续传的方式来返回视频数据
            response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);//206
 
            if (range.startsWith("bytes=")) {
                String[] values = range.split("=")[1].split("-");
                start = Integer.parseInt(values[0]);
                if (values.length > 1) {
                    end = Integer.parseInt(values[1]);
                }
            }
            //无end,每次允许的最大长度
            long maxSize = 1024 * 1024; //1MB
            if (end > 0) {
                length = end - start + 1;
                response.setHeader("Content-length", "" + length);
                response.setHeader("Content-Range", "bytes " + start + "-" + end + "/" + contentLength);
            } else {
                length = Math.min((contentLength - start), maxSize);
                response.setHeader("Content-length", "" + length);
                response.setHeader("Content-Range", "bytes " + start + "-" + (start + length - 1) + "/" + contentLength);
            }
        }
        try {
            FileInputStream fileInputStream = new FileInputStream(file);
            OutputStream out = response.getOutputStream();
            //将数据截取并存入byte[]数组中
            byte[] data = new byte[(int) length];
            fileInputStream.skip(start);
            fileInputStream.read(data);
            //取出要传给前端的有效数据
            out.write(data);
            out.close();
            fileInputStream.close();
        } catch (Exception e) {
            log.error("读取文件异常!!! e={}", e.getMessage());
        }
    }
    @Override
    public void coverPreview(Integer id, HttpServletRequest request, HttpServletResponse response) {
        FileTable sysFile = getById(id);
 
        File file = new File(handleFileRealPath(sysFile.getFileAddress()));
        String suffix = file.getName().substring(file.getName().lastIndexOf(StringUtils.DOT));
 
        try (OutputStream out = response.getOutputStream()) {
            response.setContentType(FileTypeUtils.convertHeaderType(suffix));
            response.setHeader("Content-Disposition", "inline; filename=" + URLEncoder.encode(sysFile.getFileName(), "UTF-8"));
            Thumbnails.of(file).size(420, 200).toOutputStream(out);
        } catch (Exception e) {
            log.error("读取文件异常!!! e={}", e.getMessage());
        }
    }
}