【Java】檔案上傳及下載、限制檔案大小
阿新 • • 發佈:2018-12-04
1、後端部分
Controller程式碼
// 上傳 @PostMapping("upload") @ResponseBody public Result upload(MultipartFile files, Integer id, String type){ fileService.upload(files, id, type); return success().setRet(0); } // 下載 @GetMapping("download") @ResponseBody public void download(HttpServletResponse response, Integer id){ fileService.download(response, id); }
Service程式碼
@Value("${fileServer.storeDir}") private String storeDir; @Autowired private FileMapper fileMapper; @Override public void upload(MultipartFile file, Integer id, String type) { logger.info("檔案關聯id:{}, 檔名:{}", id, file.getOriginalFilename()); logger.info("檔案字尾名:{}", file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."))); if(!file.isEmpty()){ String dir = getStoreDir(); File tempFile = new File(dir + System.currentTimeMillis() + file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."))); try { file.transferTo(tempFile); FileInfo fileInfo = new FileInfo() .setName(file.getOriginalFilename()) .setPath(tempFile.getAbsolutePath()) .setSize(tempFile.length()) .setTarget(id) .setCreateDate(new Date()) .setMd5(FileUtil.md5(tempFile)) .setType(type); fileMapper.insert(fileInfo); } catch (IOException e) { logger.error(e.getMessage(), e); throw new InternalServerException("file build error"); } } } @Override public void download(HttpServletResponse response, Integer id) { FileInfo fileInfo = fileMapper.findFileById(id); logger.info("下載檔名:{}", fileInfo.getName()); File file = new File(fileInfo.getPath()); if (!FileUtil.isExistingFile(file)) { throw new ResourceNotFoundException("file not found"); } try (OutputStream outputStream = response.getOutputStream(); InputStream inputStream = new FileInputStream(file)) { response.setContentType("application/octet-stream"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileInfo.getName(), "UTF-8")); FileCopyUtils.copy(inputStream, outputStream); } catch (IOException e) { logger.error("下載檔案失敗!",e); throw new RemoteServiceUnavailableException("file download error"); } } private String getStoreDir(){ String dir = storeDir + File.separator ; // String dir = storeDir + File.separator + System.currentTimeMillis() + File.separator; try { FileUtil.mkdir(dir); } catch (IOException e) { logger.error("獲取儲存目錄失敗!",e); throw new InternalServerException("file build error"); } return dir; } private void delFile(String path){ try { FileUtil.delete(path); } catch (IOException e) { logger.error("刪除檔案失敗!",e); throw new InternalServerException("file delete error"); } }
在application.yml配置檔案中設定檔案儲存路徑(這裡假設是本地的E:\ptms中)、以及限制上傳檔案大小(這裡設定為40M)。
# 應用名稱 spring: application: name: ptms resources: static-locations: classpath:/static cache: period: PT1M # 60 SECONDS servlet: multipart: max-file-size: 40Mb max-request-size: 40Mb fileServer: storeDir: E:\ptms
2、前端部分
前端程式碼如下,只看核心的上傳下載即可。上傳的控制元件採用element的el-upload控制元件,下載採用的是window.location.href。同時,在表單驗證完之後,提交表單之前,還做了檔案大小的校驗,採用的是遍歷this.$refs.upload.uploadFiles。
<template>
<div>
<el-form class="mt10 pd10 elForm" :rules="rules" ref="ruleForm" :model="ruleForm" label-width="130px" :label-position="labelPosition">
<el-form-item label="專案名稱:" prop="name" :inline-message="true">
<el-col :span="8">
<el-input placeholder="請輸入專案名稱" v-model="ruleForm.name"></el-input>
</el-col>
</el-form-item>
<el-form-item label="專案版本:" prop="version">
<el-col :span="8">
<el-input placeholder="請輸入專案版本" v-model="ruleForm.version"></el-input>
</el-col>
</el-form-item>
<el-form-item label="產品系列:" prop="productSeriesId">
<el-col :span="8">
<el-select v-model="ruleForm.productSeriesId" placeholder="請選擇產品系列" @change="chooseProductSeries" filterable clearable size="medium">
<el-option v-for="item in productSeries" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-col>
</el-form-item>
<el-form-item label="專案起止:" prop="date1">
<el-date-picker v-model="ruleForm.date1" type="daterange" range-separator="至" start-placeholder="開始日期" end-placeholder="結束日期" value-format="yyyy-MM-dd">
</el-date-picker>
</el-form-item>
<el-form-item label="專案描述:" prop="description">
<el-col :span="8">
<el-input placeholder="請輸入專案描述" v-model="ruleForm.description" type="textarea"></el-input>
</el-col>
</el-form-item>
<el-form-item label="操作備註:" v-if="this.$route.params.id != null">
<el-col :span="8">
<el-input placeholder="請輸入操作備註" v-model="ruleForm.remark" type="textarea"></el-input>
</el-col>
</el-form-item>
<el-form-item label="已上傳附件:" v-if="fileUploaded">
<el-col :span="11">
<template>
<el-table :data="tableData" border>
<el-table-column prop="id" label="檔案id" v-if="false"></el-table-column>
<el-table-column prop="name" label="檔名稱" min-width="180" show-overflow-tooltip>
<template slot-scope="scope">
<a href="javascript:" @click="downloadFile(scope.row.id)" class="aLink">{{scope.row.name}}</a>
</template>
</el-table-column>
<el-table-column prop="size" label="檔案大小" min-width="100" show-overflow-tooltip></el-table-column>
<el-table-column prop="createDate" label="上傳時間" min-width="120" show-overflow-tooltip></el-table-column>
<el-table-column label="操作" min-width="100" show-overflow-tooltip>
<template slot-scope="scope">
<el-button type="text" @click="downloadFile(scope.row.id)">下載</el-button>
<el-button type="text" @click="deleteFile(scope.row.id)">刪除</el-button>
</template>
</el-table-column>
</el-table>
</template>
</el-col>
</el-form-item>
<el-form-item label="附件上傳:">
<el-col :span="8">
<el-upload class="upload-demo" ref="upload" name="files" :data="uploadData" action="/ptms/api/v1/File/upload" multiple
:on-preview="handlePreview" :on-remove="handleRemove" :on-success="handleSuccess" :on-error="handleError" :auto-upload="false">
<el-button slot="trigger" size="small" type="primary">選取檔案</el-button>
<span slot="tip" class="el-upload__tip" style="margin-left: 20px; font-weight: bold">單個檔案大小不超過{{maxFileSize}}}M</span>
</el-upload>
</el-col>
</el-form-item>
<el-form-item>
<template slot-scope="scope">
<el-button type="primary" @click="submit('ruleForm')" class="btn-min-w">提交</el-button>
<el-button @click="cancel()" class="btn-min-w">返回</el-button>
</template>
</el-form-item>
</el-form>
</div>
</template>
<script>
import tableOperation from '@/components/layout/tableOperation'
import * as api from '@/api/ptms'
import {tips} from '../../static/js/global.js'
import moment from 'moment'
export default {
inject:['reload'],
components:{ tableOperation},
data(){
return{
labelPosition: 'right',
ruleForm: {
name:'',
version:'',
description:'',
productSeriesId: '',
date1: [],
createdBy: sessionStorage.getItem("userId"),
actor: sessionStorage.getItem("username"),
remark: '',
},
productSeries: [],
rules: {
name: [
{ required: true, message: '請輸入專案名稱', trigger: 'blur' }
],
},
uploadData:{
id: null,
type: 'project'
},
id: null,
tableData: [{}],
fileUploaded: false,
maxFileSize: 40,
}
},
created() {
// 跳轉頁面獲取資訊
api.projectForm({id: this.$route.params.id})
.then((res)=>{
if(res.ret > -1){
console.log(res.data)
this.productSeries = res.data.productSeries;
if(this.$route.params.id != null){
this.ruleForm.name = res.data.project.name;
this.ruleForm.version = res.data.project.version;
this.ruleForm.description = res.data.project.description;
this.ruleForm.productSeriesId = res.data.project.productSeriesId;
this.ruleForm.createdBy = res.data.project.createdBy;
if(res.data.project.startTime != null){
this.ruleForm.date1.push(new Date(res.data.project.startTime));
}
if(res.data.project.endTime != null){
this.ruleForm.date1.push(new Date(res.data.project.endTime));
}
this.id = this.$route.params.id;
this.showFileList(this.id);
}
}
})
},
methods:{
chooseProductSeries(val){
this.ruleForm.productSeriesId = val;
},
// 新增、修改專案
submit(formName) {
this.$refs[formName].validate((valid) => {
if(valid){
//檔案大小校驗
let flag = true;
this.$refs.upload.uploadFiles.map((item) => {
if(item.size / 1024 / 1024 > this.maxFileSize){
tips(this, item.name + '超過允許檔案大小' + this.maxFileSize + 'M,請重新選擇!', 'warning');
flag = false;
}
});
if(flag){
const id = (typeof (this.$route.params.id) === 'undefined') ? null : this.$route.params.id;
let startTime = null;
let endTime = null;
if(this.ruleForm.date1 != null && this.ruleForm.date1.length > 1){
if(typeof this.ruleForm.date1[0] === 'object'){
startTime = moment(this.ruleForm.date1[0]).format("YYYY-MM-DD");
endTime = moment(this.ruleForm.date1[1]).format("YYYY-MM-DD");
}else{
startTime = this.ruleForm.date1[0];
endTime = this.ruleForm.date1[1];
}
}
api.projectFormAction({id: id, name: this.ruleForm.name, version: this.ruleForm.version, createdBy: this.ruleForm.createdBy,
productSeriesId: this.ruleForm.productSeriesId, description:this.ruleForm.description, startTime: startTime,
endTime:endTime, actor: this.ruleForm.actor, remark: this.ruleForm.remark})
.then((res)=>{
console.log("專案資訊", res.data)
if(res.data === "existed"){
tips(this, '該專案名稱已存在', 'warning');
return;
}
//上傳檔案
if(this.$refs.upload.uploadFiles.length > 0){
this.uploadData.id = res.data;
this.submitUpload();
}else {
tips(this, this.id == null ? '新增成功!' :'修改成功!', 'success');
this.$router.push('/projectList');
}
})
}
}
})
},
// 下載檔案
downloadFile(val){
window.location.href = "/ptms/api/v1/File/download?id=" + val;
},
// 刪除檔案
deleteFile(val){
this.$confirm('確認刪除該附件?', '提示', {
confirmButtonText: '確定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
api.deleteFile({id: val})
.then((res) => {
if(res.ret === 0){
tips(this, '附件刪除成功!', 'success');
this.showFileList(this.id);
// this.reload();
}
})
}).catch(() =>{
// 取消
});
},
// 展示已上傳檔案列表
showFileList(id){
api.getFilesByTarget({target: id, type: this.uploadData.type})
.then((res) => {
if(res.data.files.length > 0){
this.fileUploaded = true;
res.data.files.forEach((item) => {
item.size = (item.size / 1024 ).toFixed(2) + " KB";
item.createDate = moment(item.createDate).format('YYYY-MM-DD HH:mm:ss');
});
this.tableData = res.data.files;
}else {
this.fileUploaded = false;
}
})
},
handleSuccess(response, file, fileList){
console.log("successFile: ", file);
if(response.ret < 0){
console.log("response: ", response);
this.$refs.upload.clearFiles();
tips(this, '上傳失敗!', 'error');
}else {
tips(this, this.id == null ? '新增成功!' :'修改成功!', 'success');
this.$router.push('/projectList');
}
},
handleError(err, file, fileList){
console.log("err: ", err);
console.log("errorFile: ", file);
tips(this, '上傳失敗!', 'error');
},
submitUpload() {
this.$refs.upload.submit();
},
handleRemove(file, fileList) {
console.log(file, fileList);
},
handlePreview(file) {
console.log(file);
},
// 取消返回上一頁
cancel() {
this.$router.back(-1);
}
}
}
</script>
<style lang="scss" scoped>
</style>
3、最終效果如下