此文章是在Spring Boot 文件上传与下载的基础上修改的
一、配置文件
在application-dev.yml文件中添加如下代码
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
default-property-inclusion: non_null
## MULTIPART (MultipartProperties)
# 开启 multipart 上传功能
servlet:
multipart:
enabled: true
# 文件写入磁盘的阈值
file-size-threshold: 2KB
# 最大文件大小
max-file-size: 200MB
# 最大请求大小
max-request-size: 215MB
## 文件存储所需参数
# 所有通过 REST APIs 上传的文件都将存储在此目录下
file:
upload-dir: ./uploads
创建FileProperties文件
/**
* @author yejiajun
* @date 2019/8/13 15:46
* Version 1.0.0
*/
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "file")
public class FileProperties {
private String uploadDir;
public String getUploadDir() {
return uploadDir;
}
public void setUploadDir(String uploadDir) {
this.uploadDir = uploadDir;
}
}
在启动类中添加配置
@EnableConfigurationProperties({
FileProperties.class
})
public class TrainBooststrap {
public static void main(String[] args) {
new SpringApplicationBuilder(TrainBooststrap.class).web(true).run(args); }
}
二、创建响应类
import lombok.Data;
/**
* @author yejiajun
* @date 2019/8/13 15:54
* Version 1.0.0
*/
@Data
public class UploadFileResponse {
private String fileName;
private String fileDownloadUri;
private String fileType;
private long size;
public UploadFileResponse(String fileName, String fileDownloadUri, String fileType, long size) {
this.fileName = fileName;
this.fileDownloadUri = fileDownloadUri;
this.fileType = fileType;
this.size = size;
}
}
三、创建异常对象
/**
* @author yejiajun
* @date 2019/8/13 15:55
* Version 1.0.0
*/
public class FileException extends RuntimeException{
public FileException(String message) {
super(message);
}
public FileException(String message, Throwable cause) {
super(message, cause);
}
}
四、提供文件服务
import org.springframework.core.io.Resource;
import org.springframework.web.multipart.MultipartFile;
/**
* @author yejiajun
* @date 2019/8/19 10:40
* Version 1.0.0
*/
public interface FileService {
/**
* 存储文件到系统
*
* @param file 文件
* @return 文件名
*/
String storeFile(MultipartFile file);
/**
* 加载文件
* @param fileName 文件名
* @return 文件
*/
Resource loadFileAsResource(String fileName);
}
实现这个接口
import com.capol.train.server.exception.FileException;
import com.capol.train.server.property.FileProperties;
import com.capol.train.server.server.FileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
/**
* @author yejiajun
* @date 2019/8/1215:07
* Version 1.0.0
*/
@Service
public class FileServiceImpl implements FileService {
/**
* 文件在本地存储的地址
*/
private final Path fileStorageLocation;
@Autowired
public FileServiceImpl(FileProperties fileProperties) {
this.fileStorageLocation = Paths.get(fileProperties.getUploadDir()).toAbsolutePath().normalize();
try {
Files.createDirectories(this.fileStorageLocation);
} catch (Exception ex) {
throw new FileException("Could not create the directory where the uploaded files will be stored.", ex);
}
}
/**
* 存储文件到系统
*
* @param file 文件
* @return 文件名
*/
@Override
public String storeFile(MultipartFile file) {
// Normalize FileNoticeDTO name
String fileName = StringUtils.cleanPath(file.getOriginalFilename());
try {
// Check if the FileNoticeDTO's name contains invalid characters
if(fileName.contains("..")) {
throw new FileException("Sorry! Filename contains invalid path sequence " + fileName);
}
// Copy FileNoticeDTO to the target location (Replacing existing FileNoticeDTO with the same name)
Path targetLocation = this.fileStorageLocation.resolve(fileName);
Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);
return fileName;
} catch (IOException ex) {
throw new FileException("Could not store FileNoticeDTO " + fileName + ". Please try again!", ex);
}
}
/**
* 加载文件
* @param fileName 文件名
* @return 文件
*/
@Override
public Resource loadFileAsResource(String fileName) {
try {
Path filePath = this.fileStorageLocation.resolve(fileName).normalize();
Resource resource = new UrlResource(filePath.toUri());
if(resource.exists()) {
return resource;
} else {
throw new FileException("File not found " + fileName);
}
} catch (MalformedURLException ex) {
throw new FileException("File not found " + fileName, ex);
}
}
}
五、创建controller提供服务
import com.capol.train.server.response.UploadFileResponse;
import com.capol.train.server.server.FileService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author yejiajun
* @date 2019/8/12 15:07
* Version 1.0.0
*/
@RestController
public class FileController {
private static final Logger logger = LoggerFactory.getLogger(FileController.class);
@Autowired
private FileService fileService;
@PostMapping("/uploadFile")
public UploadFileResponse uploadFile(@RequestParam("file") MultipartFile file) {
String fileName = fileService.storeFile(file);
String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()
.path("/downloadFile/")
.path(fileName)
.toUriString();
//因为我这个项目是分布式的,ip地址不稳定,所以我把前面ip地址给截掉 了,如果是单机可以不用下的语句
fileDownloadUri = fileDownloadUri.substring(fileDownloadUri.indexOf("/downloadFile/"));
return new UploadFileResponse(fileName, fileDownloadUri,
file.getContentType(), file.getSize());
}
@PostMapping("/uploadMultipleFiles")
public List<UploadFileResponse> uploadMultipleFiles(@RequestParam("files") MultipartFile[] files) {
return Arrays.stream(files)
.map(this::uploadFile)
.collect(Collectors.toList());
}
@GetMapping("/downloadFile/{fileName:.+}")
public void downloadFile(@PathVariable String fileName, HttpServletResponse response) {
InputStream inputStream = null;
OutputStream out = null;
response.setContentType("application/x-msdownload");
try {
Resource resource = fileService.loadFileAsResource(fileName);
inputStream = resource.getInputStream();
//1.设置文件ContentType类型
response.setContentType("application/octet-stream;charset=UTF-8");
out = response.getOutputStream();
//2.转码
fileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
int b = 0;
byte[] buffer = new byte[2048];
while (b != -1) {
b = inputStream.read(buffer);
if (b != -1) {
out.write(buffer, 0, b);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
inputStream.close();
out.close();
out.flush();
} catch (IOException e) {
}
}
}
}
六、测试
下载就是直接那个下载地址就可以了。
七、前端
<el-form-item label="附件">
<el-upload
class="upload-demo"
<!-- 填自己的controller接口-->
:action= "baseUrl+'/api/train/uploadFile?token='+token"
:file-list="publicFileList"
:on-change="publicHandleChange"
:on-success="publicUploadSuccess"
:limit="1">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">(必传)</div>
</el-upload>
</el-form-item>
<script>
export default {
name: 'documentation',
data() {
return {
baseUrl: '1',
token: '1',
},
components: {},
mounted() {
const _that = this;
_that.baseUrl = process.env.BASE_API_ROOT;
_that.token = _that.getToken();
},
methods: {
pudownload(row){
//前缀加后缀token,地址就按自己的来
window.location.href = this.baseUrl + '/api/train' + row.url + '?token=' + this.token
},
}
</script>