前言:
Web開發中圖片上傳的功能很常見, 本篇博客來講述下springmvc如何實現圖片上傳的功能. 主要講述依賴包引入, 配置項, 本地存儲和雲存儲方案(阿里雲的OSS服務).
鋪墊:
文件上傳是很基礎的東西, 沒有高深的理論背景. 因此這邊不再具體闡述和"科普", ^_^.
對於javaer而言, 實現文件上傳功能需要用到commons-fileupload和commons-io組件.
Ok, Let's Go!
頁面編寫:
文件上傳的form表單非常的簡單:
<form action="/test/upload_file" method="post" enctype="multipart/form-data"> 文件名: <input type="file" name="upfile"/> <br/> <input type="submit" value="提交" /> </form>
唯一需要注意的是, 表單enctype為multipart/form-data, 而不是默認的application/x-www-form-urlencoded.
springmvc配置:
需要引入依賴的commons-fileupload和commons-io組件.
則在maven工程的pom.xml中, 添加入如下依賴項:
<!-- 上傳文件的支持 --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency>
編寫相應的Controller類進行文件上傳的處理:
@Controller @RequestMapping(value = "/test") public class TestFileUploadController { @RequestMapping(value="/upload_file", method=RequestMethod.POST) public ModelAndView uploadFile(@RequestParam("upfile") MultipartFile upfile) { ModelAndView mav = new ModelAndView(); // TODO // save upfile return mav; } }
好想非常的簡單, 然而當滿懷信心去嘗試運行的時候, 結果卻如下的錯誤信息.
Expected MultipartHttpServletRequest: is a MultipartResolver configured?
正如錯誤體所所指示的, 需要添加一個MultipartResolver實例於SpringMVC中即可.
<!-- 對上傳文件的支持 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 上傳文件大小為10M --> <property name="maxUploadSize" value="10485760" /> </bean>
再次運行, 基本上就沒問題了.
本地保存:
對於本地存儲而言, 關鍵還是如何獲取webapp的根目錄.
方法一: 配置系統屬性
配置web.xml, 通過注冊listener設置目錄於系統屬性中.
<context-param> <param-name>webAppRootKey</param-name> <param-value>app.yourweb.com</param-value> </context-param> <!-- 添加對webapp根路徑的快速訪問支持 --> <listener> <listener-class>org.springframework.web.util.WebAppRootListener</listener-class> </listener>
然后通過如下Java代碼獲取到:
String realPath = System.getProperty("app.yourweb.com");
方法二: 借助ServletContext來獲取webapp根目錄
HttpServletRequest request = ...; request.getSession().getServletContext().getRealPath("/");
這兩種方式都可以, 那種簡潔就使用那種.
OSS存儲:
使用雲存儲服務來保存文件, 是種被推薦的做法, 現在也越來越流行. 淘寶這么多圖片, 一個圖片文件系統, 輕輕松松的簡化開發的工作量.
參考官方文檔: OSS Java API手冊.
OSS中, bucket全局唯一, 這個需要注意, OSSClient是線程安全的.
• OSSClient的實例化和基礎配置:
String accessKeyId = "your accessKeyId"; String accessKeySecret = "your accessKeySecret"; String bucketName = "your bucketName"; String endpoint = "your endpoint"; ClientConfiguration conf = new ClientConfiguration(); conf.setMaxConnections(10); // 設置HTTP最大連接數為10 conf.setConnectionTimeout(2000); // 設置TCP連接超時為5000毫秒 conf.setMaxErrorRetry(3); // 設置最大的重試次數為3 conf.setSocketTimeout(5000); // 設置Socket傳輸數據超時的時間為2000毫秒 // *) 進行OSS客戶端的實例化 OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret, conf);
• 上傳文件代碼(摘自官網):
public void putObject(String bucketName, String key, String filePath) throws FileNotFoundException { // 初始化OSSClient OSSClient client = ...; // 獲取指定文件的輸入流 File file = new File(filePath); InputStream content = new FileInputStream(file); // 創建上傳Object的Metadata ObjectMetadata meta = new ObjectMetadata(); // 必須設置ContentLength meta.setContentLength(file.length()); // 上傳Object. PutObjectResult result = client.putObject(bucketName, key, content, meta); // 打印ETag System.out.println(result.getETag()); }
• 生成Url代碼(摘自官網):
String bucketName = "your-bucket-name"; String key = "your-object-key"; // 設置URL過期時間為1小時 Date expiration = new Date(new Date().getTime() + 3600 * 1000); // 生成URL URL url = client.generatePresignedUrl(bucketName, key, expiration);
這個是帶時效的url.
當然也可以自己拼接生成如下url:
String endpoint = ...; String bucketName = ...; String key = ...; String url = endpoint + "/" + bucketName + "/" + key;
下面這種, 更簡單直接一點.
OSS的操作看似非常簡單, 但真正自己去實踐的時候, 難免遇到一些坑.
比如如下錯誤:
The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.
這個問題的本質是, 阿里雲的雲存儲是有機房概念的, 每個bucket在構建時會屬於某一個機房.
endpoint默認為杭州, 若你的bucket屬於其他區域, 而endpoint又沒有設置一致, 就會報如上錯誤.
比如筆者的bucket屬於上海, 則默認把endpoint設為http://oss-cn-shanghai.aliyuncs.com, 既OK.
具體可參見: OSS使用SDK訪問bucket提示endpoint錯誤.
• 圖片上傳
對於圖片上傳, 除了在ObjectMetaData中設置文件大小以外, 還需要配置ContentType, 這個尤顯得重要.
對於MIME類型, 這邊也貼個鏈接: MIME類型大全.
總結:
文件本地存儲, 並非什么難事, 主要還是體驗一下OSS. 本文對springmvc文件上傳做了簡單的介紹, 權當學習筆記.
公眾號&游戲站點:
個人微信公眾號: 木目的H5游戲世界
個人游戲作品集站點(尚在建設中...): www.mmxfgame.com, 也可直接ip訪問: http://120.26.221.54/.