JavaWeb開發中重新認識檔案上傳
阿新 • • 發佈:2019-01-03
檔案上傳功能在很多軟體中都是必備的功能之一,所以,檔案上傳也就不顯得那麼有技術含量了,但是如果要把這個功能做好甚至完美,可不是三兩下就能搞定的,其中包含的諸多細節盡在不言中。我們來看一下,做一個上傳功能需要考慮什麼,以apk檔案上傳為例:
1、上傳的檔案的型別(選擇檔案時對檔案格式做限制)
2、上傳的檔案的大小(設定檔案上傳的最大範圍)3、上傳的檔案的名稱(這裡包括加密後的名稱和realName)
4、刪除檔案(必須考慮是否能真正刪除)5、修改時能否回顯檔案
6、修改後儲存檔案應該怎麼對檔案進行處理
7、單獨複製檔案絕對路徑能否下載
8、檔案的相對路徑生成
雖然總結出了八條需要考慮的點,但應該還是存在欠缺的地方的。常用的上傳方式有兩種:非同步上傳和同步上傳,現在好像非同步上傳用的比較多一些,下面先以同步上傳方式來說說吧:
同步上傳就是先僅僅選擇一個檔案,填完其它內容後再統一提交到後臺,在後臺做檔案上傳的邏輯處理並儲存一個完整內容。一般來說,我們在資料庫中都會用一個欄位(URL)來儲存檔案的相對路徑,但是這個最終儲存到資料庫裡的URL是要在後臺生成的,因此,提交表單時將檔案同請求一起傳送到後臺即可。下面以app版本管理功能為例講解。
app版本新增頁面:
JSP程式碼:
通過觀察程式碼可以發現,path屬性的名稱與這個實體物件的屬性相對應且名稱相同,提交表單時會自動把這些屬性的值存到modelAttribute中傳到後臺,我們不可以直接選擇檔案後就直接得到相對路徑存到modelAttribute中,只有經過後臺處理後才可以進行儲存,所以,在頁面中檔案只是一個獨立的檔案而已,path的值可以不填甚至不要這個屬性,但是name屬性是必須要用到的,這是用於後臺識別檔案的唯一標識。這就好比採摘水果,傳統售賣摘下來就可以拿去賣了,因為客戶需要的只是普通水果,而果汁飲料需要採摘下來再加工後做成飲料產品才能滿足客戶需求。<form:form id="inputForm" modelAttribute="safeFireAppVersion" action="${ctx}/safe/fire/safeFireAppVersion/save" method="post" class="form-horizontal" enctype="multipart/form-data"> <form:hidden path="id"/> <sys:message content="${message}"/> <div class="control-group"> <label class="control-label">版本號:</label> <div class="controls"> <form:input path="code" htmlEscape="false" maxlength="16" class="input-xlarge required"/> <span class="help-inline"><font color="red">*</font> </span> </div> </div> <div class="control-group"> <label class="control-label">版本數:</label> <div class="controls"> <form:input path="codenum" htmlEscape="false" maxlength="3" class="input-xlarge required" onkeyup="this.value=this.value.replace(/\D/g,'')" onafterpaste="this.value=this.value.replace(/\D/g,'')" /> <span class="help-inline"><font color="red">*</font> </span> </div> </div> <div class="control-group"> <label class="control-label">檔案:</label> <div class="controls"> <form:input path="" type="file" name="apkFile" accept=".apk"/> <br/>${safeFireAppVersion.realName } </div> </div> <div class="control-group"> <label class="control-label">備註:</label> <div class="controls"> <form:textarea path="remarks" htmlEscape="false" rows="4" maxlength="255" class="input-xxlarge "/> </div> </div> <div class="form-actions"> <shiro:hasPermission name="safe:fire:safeFireAppVersion:edit"><input id="btnSubmit" class="btn btn-primary" type="submit" value="保 存"/> </shiro:hasPermission> <input id="btnCancel" class="btn" type="button" value="返 回" onclick="history.go(-1)"/> </div> </form:form>
表單提交的方式為POST,我們只要在後臺利用Springmvc的@RequestParam註解就可以對前臺傳送過來的檔案進行接收了。後臺程式碼如下:
@RequiresPermissions("safe:fire:safeFireAppVersion:edit")
@RequestMapping(value = "save")
public String save(@RequestParam("apkFile") MultipartFile apkFile, SafeFireAppVersion safeFireAppVersion, Model model, RedirectAttributes redirectAttributes) throws Exception {
if (!beanValidator(model, safeFireAppVersion)) {
return form(safeFireAppVersion, model);
}
if (!apkFile.isEmpty()) { // 判斷檔案是否為空
String oldPath = null;
if(!safeFireAppVersion.getIsNewRecord()){ // 判斷是否是新記錄,不是的話就是修改中的儲存
SafeFireAppVersion old = safeFireAppVersionService.get(safeFireAppVersion); // 獲取原先的檔案
FileUtils.delFileByPath(old.getUrl()); // 刪除原檔案
oldPath = old.getUrl(); // 獲取原先的檔案的路徑,用於保留之前的uuid,換了檔案還是用之前的uuid作為加密後的檔名
}
String filePath = UploadUtils.appVersionUpload(FireConstant.UPLOAD_VERSION_PATH, apkFile, oldPath); // 開始檔案上傳
safeFireAppVersion.setUrl(filePath);
safeFireAppVersion.setRealName(apkFile.getOriginalFilename()); // 真實名稱
}
safeFireAppVersionService.save(safeFireAppVersion);
addMessage(redirectAttributes, "儲存滅火器APP版本資訊成功");
return "redirect:" + Global.getAdminPath() + "/safe/fire/safeFireAppVersion/?repage";
}