Java實現上傳圖片功能


以本產品的上傳商品圖片為例,它包含了”上傳圖片后的預覽”、”清空預覽圖片”、”保存圖片"三個部分。上傳圖片后,先將圖片文件臨時存放到session中,如果需要保存圖片,再從session中獲取到文件並保存到服務器。

1、 上傳圖片預覽

上傳圖片預覽實現了上傳圖片,並且在頁面顯示圖片,此時還沒有在服務器完成修改操作:

(1)   上傳圖片HTML代碼。

<div class="commodityPicture layui-upload">
      <div class="layui-upload-list">
      <p class='explain'>支持100k大小的<br />jpg、png、jpeg格<br />式圖片</p>
      <img class="imgStyle" id="commImage">
 </div>
      <button type="button" class="layui-btn layui-btn-sm" id="uploadImage">上傳商品圖片</button>
      <button type="button" class="layui-btn layui-btn-sm" id="cleanImage">清空商品圖片</button>
 </div>

(2)   上傳圖片js代碼。

使用到了Layui框架的upload模塊。upload.render函數設置請求后端的url、允許的圖片類型、圖片大小等信息:

//上傳商品圖片
	var uploadCommImage = upload.render({
		elem: '#uploadImage',
		url: commPictureUpload_url,
		accept: 'images',
		acceptMime: 'image/jpg, image/jpeg, image/png',
		exts: 'jpg|jpeg|png',
		size: 100,
		before: function (obj) {
			//預讀本地文件示例,不支持ie8
			obj.preview(function (index, file, result) {
				$('#commImage').attr('src', result);		//圖片鏈接(base64
			});
		},
		done: function (res) {
			bDesertLastOperation = false;
			$("input[name='lastOperationToPicture']").val(LAST_OPERATION_TO_PICTURE_Upload);
			if (res.ERROR == "EC_NoError") {		//上傳成功
				var msg = res.msg == "" ? "上傳圖片成功" : res.msg;
				return layer.msg(msg);
			} else {		//上傳失敗
				var msg = res.msg == "" ? "上傳圖片失敗" : res.msg;
				return layer.msg(msg);
			}
		},
		error: function (index, upload) {
			//演示失敗狀態,並實現重傳
			var demoText = $('#hintText');
			demoText.html('<span style="color: #FF5722;">上傳失敗</span><a class="layui-btn layui-btn-xs demo-reload">重試</a>');
			demoText.find('.demo-reload').on('click', function () {
				uploadCommImage.upload();
			});
		}
	});

(3)   后端接收前端傳遞的圖片。

使用了Spring的MultipartFile來接收上傳的圖片文件:

/** 上傳圖片到D:/nbr/pic/private_db/companyX/tempXXXXXX.jpg(png/jpeg),臨時保存之。
	 * 此時,還未確定圖片的名字,所以命名帶有temp字眼。這個臨時文件的路徑和MultipartFile對象被保存在會話中,給后面的操作使用
	 * 之后,用戶可能創建、修改、刪除商品,這個臨時文件將會被處理,比如重命名為138.jpg,對應商品F_ID=138 */
	@RequestMapping(value = "/uploadPictureEx", method = RequestMethod.POST)
	@ResponseBody
	public Map<String, Object> uploadPictureEx(@ModelAttribute("SpringWeb") Commodity commodity, ModelMap model, HttpServletRequest req, @RequestParam("file") MultipartFile file) {
		if (!canCallCurrentAction(req.getSession(), BaseAction.EnumUserScope.STAFF.getIndex())) {
			logger.debug("無權訪問本Action");
			return null;
		}

(4)   清空session中的商品圖片信息。

上傳的圖片文件還有它應存放的位置信息我們是把它們存放在session當中的,所以如果之前有上傳過,需要先清空:

// 清空會話,確保session不受污染
		req.getSession().removeAttribute(EnumSession.SESSION_CommodityPictureDestination.getName());
		req.getSession().removeAttribute(EnumSession.SESSION_PictureFILE.getName());

(5)   檢查文件的類型、大小。

String fileName = file.getOriginalFilename();
				String picType = "image/" + fileName.substring(fileName.lastIndexOf(".") + 1);
				if (!picType.equals(JPEGType) && !picType.equals(PNGType) && !picType.equals(JPGType)) {
					logger.error("商品圖片的類型不對。當前類型為:" + picType);

					map.put(BaseAction.JSON_ERROR_KEY, EnumErrorCode.EC_OtherError.toString());
					map.put(KEY_HTMLTable_Parameter_msg, "商品圖片的類型必須是.jpg/.jpeg/.png格式");
					break;
				}

				Long size = file.getSize();
				ErrorInfo ecOut = new ErrorInfo();
				ConfigGeneral commodityLogoVolumeMax = (ConfigGeneral) CacheManager.getCache(company.getDbName(), EnumCacheType.ECT_ConfigGeneral).read1(BaseCache.CommodityLogoVolumeMax, getStaffFromSession(req.getSession()).getID(), ecOut,
						company.getDbName());
				if (size <= 0 || size > Long.parseLong(commodityLogoVolumeMax.getValue())) {
					logger.error("商品圖片大小不能超過100K。當前size=" + size);

					map.put(KEY_HTMLTable_Parameter_msg, "商品圖片大小不能超過100K");

(6)   檢查磁盤的空間大小。

/** 檢查磁盤空間是否足夠和存儲路徑是否存在 */
	public static boolean checkDiskSpaceAndCreateFolder(Map<String, Object> params, String path) {
		File diskPath = new File(Disk);
		if (!diskPath.exists()) {
			logger.error("該路徑不存在:" + diskPath);
			params.put(BaseAction.KEY_HTMLTable_Parameter_msg, "服務器錯誤");
			params.put(BaseAction.JSON_ERROR_KEY, EnumErrorCode.EC_OtherError.toString());
			return false;
		}
		ErrorInfo ecOut = new ErrorInfo();
		BxConfigGeneral extraDiskSpaceSize = (BxConfigGeneral) CacheManager.getCache(BaseAction.DBName_Public, EnumCacheType.ECT_BXConfigGeneral).read1(BaseCache.EXTRA_DISK_SPACE_SIZE, BaseBO.SYSTEM, ecOut, BaseAction.DBName_Public);

		long minUsablePatitionSpace = 1;
		logger.info("磁盤可用空間為:" + diskPath.getUsableSpace() / (1024 * 1024 * 1024) + "GB");
		if (diskPath.getUsableSpace() - Integer.valueOf(extraDiskSpaceSize.getValue()) < minUsablePatitionSpace) {
			logger.error("磁盤空間不足!");
			params.put(BaseAction.KEY_HTMLTable_Parameter_msg, "服務器錯誤");
			params.put(BaseAction.JSON_ERROR_KEY, EnumErrorCode.EC_OtherError.toString());
			return false;
		}
		// 判斷文件夾是否存在,如果不存在,創建相應的文件夾,String1傳回來DBName
		File uploadDir = new File(path);
		if (!uploadDir.exists()) {
			uploadDir.mkdirs();
		}
		return true;
	}

(7)   設置圖片的存放位置。

String path = BaseAction.CommodityPictureDir;
logger.info("商品圖片上傳路徑:" + path);

(8)   定義圖片的臨時名稱。

根據文件的類型定義文件的臨時名稱pictureName,如temp12345.jpg:

// 判斷是jpg還是png類型,上傳名稱。如果多個線程在這里寫,會存在隱患:出現相同的臨時圖片文件,不同的商品引用相同的圖片
				String pictureName = "";
				if (picType.contains(JPGType)) {
					pictureName = "temp" + System.currentTimeMillis() % 1000000 + ".jpg";
				} else if (picType.contains(PNGType)) {
					pictureName = "temp" + System.currentTimeMillis() % 1000000 + ".png";
				} else {
					pictureName = "temp" + System.currentTimeMillis() % 1000000 + ".jpeg";
				}

(9)   根據存放位置構建File對象。

File commodityPictureDestination = new File(path + "/" + company.getDbName() + "/" + pictureName);

(10) 將圖片信息保存在session中。

req.getSession().setAttribute(EnumSession.SESSION_CommodityPictureDestination.getName(), commodityPictureDestination);
req.getSession().setAttribute(EnumSession.SESSION_PictureFILE.getName(), file);

(11) 前端效果圖。

11.前端效果圖

2、    保存圖片
(1)    更新數據庫圖片位置信息。
從session中獲取圖片文件位置信息,設置商品對象圖片位置,最后更新數據庫對應商品的圖片位置字段:

		Commodity commodity = (Commodity) baseModel;
		// ... 截取參數和handleCreateEx()中類似。
		File dest = (File) req.getSession().getAttribute(EnumSession.SESSION_CommodityPictureDestination.getName());

		// 處理商品圖片字段
		int lastOperationToPicture = commodity.getLastOperationToPicture();
		switch (lastOperationToPicture) {
		case LAST_OPERATION_TO_PICTURE_Upload:
			if (dest != null) {
				StringBuilder filePath = new StringBuilder(dest.getPath().replaceAll("\\\\", "/"));// filePath一定形如d:/nbr/pic/nbr_MYJ/18.jpg
				for (int i = 0; i < DIR.length(); i++) {
					filePath.setCharAt(i, Character.toLowerCase(filePath.charAt(i)));// 確保下面的替換真正替換到東西
				}
				logger.debug("filePath=" + filePath.toString());
				String commPictureDir = filePath.toString().replaceAll(DIR, "/p");
				commodity.setPicture(commPictureDir);
			}
			break;
		case LAST_OPERATION_TO_PICTURE_None:
			commodity.setPicture(FLAG_WillNotUpdatePictureInSP);
			break;
		case LAST_OPERATION_TO_PICTURE_Clear:

(2)    從session中拿到MultipartFile file文件對象。

// 上傳圖片(如果有)
MultipartFile file = (MultipartFile) req.getSession().getAttribute(EnumSession.SESSION_PictureFILE.getName());
if (dest != null && file != null) {
	renameCommodityPicture(req, dbName, bmFromDB, dest, file, ec);
	}

(3)    判斷磁盤是否已經有該圖片文件,如果有則刪除。

			// 現在傳入的文件是否已經存在,如果有刪除該文件
			do {
				File file5 = new File(BaseAction.CommodityPictureDir + dbName + "/" + bm.getID() + ".jpg");
				if (file5.exists()) {
					file5.delete();
					break;
				}
				file5 = new File(BaseAction.CommodityPictureDir + dbName + "/" + bm.getID() + ".jpeg");
				if (file5.exists()) {
					file5.delete();
					break;
				}
				file5 = new File(BaseAction.CommodityPictureDir + dbName + "/" + bm.getID() + ".png");
				if (file5.exists()) {
					file5.delete();
					break;
				}
			} while (false);

(4)    將上傳的圖片保存到磁盤中。

file.transferTo(dest);

(5)    重命名文件名稱。
此時的文件名還是臨時文件名temp12345.jpg,根據商品ID將臨時文件重命名:

			String commodityPicturePath = BaseAction.CommodityPictureDir + dbName + "/" + bm.getID() + commodityPictureType;
			File companyBusinessLicensePictureDestination1 = new File(commodityPicturePath);
			dest.renameTo(companyBusinessLicensePictureDestination1);

(6)    清空session中的圖片信息。
最后清空掉session中的圖片信息,釋放內存:

// 上傳圖片成功刪除對應session
			req.getSession().removeAttribute(EnumSession.SESSION_CommodityPictureDestination.getName());
			req.getSession().removeAttribute(EnumSession.SESSION_PictureFILE.getName());

3、清空圖片
(1)    清空圖片js代碼。

//清除商品圖片
	$("#cleanImage").click(function () {
		$.ajax({
			url: commPictureDelete_url,
			type: method_post,
			async: true,
			dataType: "json",
			data: {},
			success: function succFunction (data) {		//此接口后端不會返回錯誤碼
				$('.explain').show();
				$('#commImage').attr('src', ' ');
				bDesertLastOperation = false;
				$("input[name='lastOperationToPicture']").val(LAST_OPERATION_TO_PICTURE_Clear);
			},
			error: function (XMLHttpRequest, textStatus, errorThrown) {
				layer.msg(XMLHttpRequest.status + ":" + XMLHttpRequest.statusText);
				layer.msg("清空商品圖片失敗");
			}
		})
	})

(2)    清空圖片后端代碼,清空session中的圖片信息。

		logger.info("清空商品圖片的session");
		session.removeAttribute(EnumSession.SESSION_CommodityPictureDestination.getName());
		session.removeAttribute(EnumSession.SESSION_PictureFILE.getName());

(3)    更新數據庫圖片信息。
清空圖片后,如果要保存修改,后端就將商品圖片設置為空,並更新數據庫。

		case LAST_OPERATION_TO_PICTURE_Clear:
		case LAST_OPERATION_TO_PICTURE_None:
		default:
			commodity.setPicture("");
			break;
		}

		List<List<BaseModel>> bmFromDB = null;
		DataSourceContextHolder.setDbName(dbName);
		bmFromDB = commodityBO.createObjectEx(getStaffFromSession(req.getSession()).getID(), iUseCaseID, baseModel);

(4)    配置虛擬映射路徑。
    如果在tomcat服務器上部署,並且想把代碼和上傳的圖片分離開,那么需要配置tomcat虛擬映射路徑才能訪問到圖片。在pom.xml文件中配置了tomcat虛擬映射路徑:

<!-- tomcat虛擬映射路徑 -->
		<!-- 更改公司的營業執照路徑時需要同時更改config.sql中的CompanyBusinessLicensePictureDir的路徑 -->
		<!-- 更改商品的圖片路徑時需要同時更改config.sql中的CommodityLogoDir的路徑 -->
		<staticContextPath>/p</staticContextPath> 
		<staticContextDocbase>D:/nbr/pic</staticContextDocbase>
		<contextReloadable>false</contextReloadable>
		<useTestClasspath>true</useTestClasspath>

新建p.xml,配置映射,path 為虛擬目錄 docBase 為實際目錄:

<Context crossContext="true" reloadable="true" debug="0" workDir="D:/nbr/pic/" docBase="D:/nbr/pic/" path="/p"/>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM