文件模块初步完成
This commit is contained in:
@ -0,0 +1,35 @@
|
||||
package com.greenorange.promotion.service.file;
|
||||
|
||||
import com.greenorange.promotion.model.dto.fileInfo.UploadFileRequest;
|
||||
import com.greenorange.promotion.model.entity.FileInfo;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author 35880
|
||||
* @description 针对表【file_info(文件上传列表)】的数据库操作Service
|
||||
* @createDate 2025-05-06 17:02:05
|
||||
*/
|
||||
public interface FileInfoService extends IService<FileInfo> {
|
||||
|
||||
|
||||
/**
|
||||
* 校验文件
|
||||
*/
|
||||
void validFile(MultipartFile multipartFile);
|
||||
|
||||
|
||||
/**
|
||||
* 获取文件保存路径
|
||||
*/
|
||||
String uploadFile(MultipartFile multipartFile, UploadFileRequest uploadFileRequest);
|
||||
|
||||
|
||||
/**
|
||||
* 文件下载
|
||||
*/
|
||||
void downloadFile(String filename, HttpServletResponse response) throws IOException;
|
||||
}
|
@ -0,0 +1,162 @@
|
||||
package com.greenorange.promotion.service.file.impl;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.greenorange.promotion.common.ErrorCode;
|
||||
import com.greenorange.promotion.exception.BusinessException;
|
||||
import com.greenorange.promotion.exception.ThrowUtils;
|
||||
import com.greenorange.promotion.model.dto.fileInfo.FileInfoAddRequest;
|
||||
import com.greenorange.promotion.model.dto.fileInfo.UploadFileRequest;
|
||||
import com.greenorange.promotion.model.entity.FileInfo;
|
||||
import com.greenorange.promotion.model.enums.FileUploadBizEnum;
|
||||
import com.greenorange.promotion.service.common.CommonService;
|
||||
import com.greenorange.promotion.service.file.FileInfoService;
|
||||
import com.greenorange.promotion.mapper.FileInfoMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @author 35880
|
||||
* @description 针对表【file_info(文件上传列表)】的数据库操作Service实现
|
||||
* @createDate 2025-05-06 17:02:05
|
||||
*/
|
||||
@Service
|
||||
public class FileInfoServiceImpl extends ServiceImpl<FileInfoMapper, FileInfo>
|
||||
implements FileInfoService{
|
||||
|
||||
@Resource
|
||||
private CommonService commonService;
|
||||
|
||||
|
||||
// 上传文件的服务器存储目录
|
||||
private static final String UPLOAD_DIR = "D:/qingcheng/image/";
|
||||
|
||||
|
||||
// 优化:设置一个合理的缓冲区大小
|
||||
private static final int BUFFER_SIZE = 8192; // 8 KB
|
||||
|
||||
|
||||
/**
|
||||
* 校验文件
|
||||
*/
|
||||
@Override
|
||||
public void validFile(MultipartFile multipartFile) {
|
||||
// 文件大小
|
||||
long fileSize = multipartFile.getSize();
|
||||
// 文件后缀
|
||||
String fileSuffix = FileUtil.getSuffix(multipartFile.getOriginalFilename());
|
||||
final long LIMIT = 20 * 1024 * 1024L;
|
||||
ThrowUtils.throwIf(fileSize > LIMIT, ErrorCode.PARAMS_ERROR, "文件大小不能超过20MB");
|
||||
ThrowUtils.throwIf(!Arrays.asList("jpeg", "jpg", "svg", "png", "webp", "JPG").contains(fileSuffix),ErrorCode.PARAMS_ERROR, "文件类型错误");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取文件保存路径
|
||||
*/
|
||||
@Override
|
||||
public String uploadFile(MultipartFile multipartFile, UploadFileRequest uploadFileRequest) {
|
||||
// 获取业务名称
|
||||
String biz = uploadFileRequest.getBiz();
|
||||
// 获取文件名
|
||||
String fileName = multipartFile.getOriginalFilename();
|
||||
// 获取文件类型
|
||||
String fileType = FileUtil.getSuffix(fileName);
|
||||
// 获取文件路径
|
||||
// 获取view值
|
||||
String view = RandomStringUtils.random(8);
|
||||
// 获取文件路径
|
||||
String filePath = String.format("%s/%s", biz, fileName);
|
||||
// 获取文件大小
|
||||
Double fileSize = multipartFile.getSize() / 1024.0;
|
||||
// 保存文件
|
||||
FileInfoAddRequest fileInfoAddRequest = FileInfoAddRequest.builder()
|
||||
.name(fileName)
|
||||
.type(fileType)
|
||||
.path(filePath)
|
||||
.size(fileSize)
|
||||
.fileView(view)
|
||||
.biz(biz)
|
||||
.build();
|
||||
FileInfo fileInfo = commonService.copyProperties(fileInfoAddRequest, FileInfo.class);
|
||||
this.save(fileInfo);
|
||||
// 创建上传目录,如果不存在
|
||||
File file = new File(UPLOAD_DIR + filePath);
|
||||
if (!file.getParentFile().exists()) {
|
||||
file.getParentFile().mkdirs();// 如果路径不存在则创建
|
||||
}
|
||||
// 将文件上传到目标位置
|
||||
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file), BUFFER_SIZE)) {
|
||||
bos.write(multipartFile.getBytes());
|
||||
} catch (IOException e) {
|
||||
throw new BusinessException(ErrorCode.OPERATION_ERROR, "文件上传失败,失败原因:" + e.getMessage());
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 文件下载
|
||||
* @param filename 业务名称/view值
|
||||
* @param response
|
||||
*/
|
||||
@Override
|
||||
public void downloadFile(String filename, HttpServletResponse response) throws IOException{
|
||||
ThrowUtils.throwIf(!filename.contains("/"), ErrorCode.PARAMS_ERROR);
|
||||
String[] split = filename.split("/");
|
||||
FileUploadBizEnum fileUploadBizEnum = FileUploadBizEnum.getEnumByValue(split[0]);
|
||||
ThrowUtils.throwIf(fileUploadBizEnum == null, ErrorCode.PARAMS_ERROR, "业务类型错误");
|
||||
LambdaQueryWrapper<FileInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
lambdaQueryWrapper.eq(FileInfo::getFileView, split[1]);
|
||||
FileInfo fileInfo = this.getOne(lambdaQueryWrapper);
|
||||
ThrowUtils.throwIf(fileInfo == null, ErrorCode.NOT_FOUND_ERROR, "文件不存在");
|
||||
|
||||
File file = new File(UPLOAD_DIR + fileInfo.getPath());
|
||||
// // 设置response的Header
|
||||
response.setContentType("application/octet-stream");
|
||||
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), StandardCharsets.UTF_8));
|
||||
response.setContentLengthLong(file.length()); // 使用 setContentLengthLong 适应大文件
|
||||
|
||||
// 设置缓存相关的 HTTP 头
|
||||
long lastModified = file.lastModified();
|
||||
response.setDateHeader("Last-Modified", lastModified); // 文件最后修改时间
|
||||
response.setHeader("Cache-Control", "public, max-age=86400"); // 缓存一天(24小时)
|
||||
response.setHeader("ETag", String.valueOf(lastModified)); // 使用文件最后修改时间作为 ETag
|
||||
|
||||
// 检查浏览器缓存是否有效
|
||||
String ifNoneMatch = response.getHeader("If-None-Match");
|
||||
if (ifNoneMatch != null && ifNoneMatch.equals(String.valueOf(lastModified))) {
|
||||
// 如果 ETag 匹配,表示文件没有变化,返回 304 Not Modified
|
||||
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
|
||||
return;
|
||||
}
|
||||
// 使用 BufferedInputStream 和 BufferedOutputStream 提高性能
|
||||
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file), BUFFER_SIZE);
|
||||
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream(), BUFFER_SIZE)) {
|
||||
byte[] buffer = new byte[BUFFER_SIZE];
|
||||
int bytesRead;
|
||||
// 从文件中读取数据并写入响应输出流
|
||||
while ((bytesRead = bis.read(buffer)) != -1) {
|
||||
bos.write(buffer, 0, bytesRead);
|
||||
}
|
||||
bos.flush(); // 确保所有数据都已写入响应
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user