前言
此工具类以提供一个方便,全面的文件上传下载工具为目的,设计思想遵照Spring的核心要素,通过自动注入与属性配置完成初始化,直接调用Bean里的方法完成对应任务
为了服务器效率:
- 上传与下载将默认采用异步方式处理,通过开启线程池管理异步线程
为了代码简洁:
- 仅实现单文件的上传与下载,多文件的相关操作由调用者重复调用完成
- 未做异常处理,由调用者接收异常并决定是重新执行还是返回错误
为了规范化:
- 实现了配置文件管理Bean,配置信息有两项(可自主扩展)
- threadNumber:线程数
- defaultAddress:文件存储根目录
实现
首先是配置类FileUtilConfig
的书写:
@Data
@Component
@ConfigurationProperties(value = "futil")
public class FileUtilConfig {
private int threadNumber = 10;
private String defaultAddress = "/usr/local/nginx/static/files";
}
相关的yaml
文件为:
futil:
threadNumber: 10
uploadFileAddress: "/usr/local/nginx/static/files"
工具类FileUtil
代码如下:
package com.example.utils;
import com.example.config.FileUtilConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.PostConstruct;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Component
@Slf4j
public class FileUtil {
/***
* 1. 初始化工具类参数
* 2. 文件上传方法(异步上传)
* 3. 文件下载方法(同步下载)
***/
@Autowired
private FileUtilConfig fileUtilConfig;
private ExecutorService SECKILL_ORDER_EXECUTOR;
// 此处必须添加PostConstruct注解,让对属性的读取放在Spring构建完成后
// 否则,由于执行顺序是字段初始化分配(若有初始值则写入,没有则为null)->构造函数执行->自动注入(覆盖初始值)
// 后果:无法在字段初始化时调用get方法
@PostConstruct
public void init() {
this.SECKILL_ORDER_EXECUTOR = Executors.newFixedThreadPool(fileUtilConfig.getThreadNumber());
}
public void upload(MultipartFile file){
SECKILL_ORDER_EXECUTOR.submit(new upload(file));
}
public void download(String fileName, HttpServletResponse response){
new download(fileName, response).run();
}
public class upload implements Runnable {
private MultipartFile file;
public upload(MultipartFile file) {
this.file = file;
}
@Override
public void run() {
try {
//获取文件名
String fileName = file.getOriginalFilename();
//设置文件存储路径
String path = fileUtilConfig.getDefaultAddress()+ '/' + fileName;
File dest = new File(path);
//检测是否存在该目录
if (!dest.getParentFile().exists()){
dest.getParentFile().mkdirs();
}
//写入文件
file.transferTo(dest);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public class download{
private String fileName;
private HttpServletResponse response;
public download(String fileName, HttpServletResponse response) {
this.fileName = fileName;
this.response = response;
}
public void run() {
//设置文件读取路径
String path = fileUtilConfig.getDefaultAddress();
// 设置响应头、以附件形式打开文件
response.setHeader("content-disposition", "attachment; fileName=" + fileName);
response.setContentType("image/jpeg");
int len = 0;
byte[] data = new byte[1024];
try(FileInputStream inputStream = new FileInputStream(new File(path, fileName));
ServletOutputStream outputStream = response.getOutputStream();) {
while ((len = inputStream.read(data)) != -1) {
outputStream.write(data, 0, len);
outputStream.flush();
}
} catch (IOException e) {
log.error("下载文件失败,错误原因:"+ e.toString());
}
}
}
}