此文章是在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>