在比較絢麗多彩的網站或者業務邏輯比較豐富的程式設計過程中,圖片的相關操作時必不少的,尤其時圖片的上傳。還沒有徹底擺脫紙質辦公可能需要將紙質的文件備份上傳,網站的建設可能需要上傳用戶頭像、圖片描述等等,這些都需要將圖片從本地上傳到網上(伺服器)。下麵將介紹筆者今天在做圖片上傳過程中所遇到的坑~ 一、業 ...
在比較絢麗多彩的網站或者業務邏輯比較豐富的程式設計過程中,圖片的相關操作時必不少的,尤其時圖片的上傳。還沒有徹底擺脫紙質辦公可能需要將紙質的文件備份上傳,網站的建設可能需要上傳用戶頭像、圖片描述等等,這些都需要將圖片從本地上傳到網上(伺服器)。下麵將介紹筆者今天在做圖片上傳過程中所遇到的坑~
一、業務描述
業務要求是將機器在不斷生產的照片上傳到網上,以便於能在網站上查看。
二、解決思路
由於對圖片這一塊的處理已經比較生疏,所以打算一點一點解決這些業務需求。首先將業務分解為以下幾個部分:
(1)伺服器接收瀏覽器端上傳的圖片。這一點比較好實現,因為伺服器端的開發大多數都是基於B/S架構的,也就是邏輯與瀏覽器端進行開發的。
(2)伺服器接收客戶端上傳的圖片。這一點看似也不難,但是如何正確的發送出數據確是有點難度,也是筆者今天踩坑的地方。
(3)業務邏輯的優化完善。
三、伺服器接收瀏覽器端上傳的圖片
1、新建網頁
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>圖片上傳</title> 6 </head> 7 <body> 8 <form action="/plant/upload.action" enctype="multipart/form-data" 9 method="post"> 10 圖片:<input type="file" name="img"/> <br/> 11 <input type="submit" value="上傳"/> 12 </form> 13 </body> 14 </html>查看代碼
此處需要註意的是 form標簽enctype屬性的添加,還有就是input輸入框中name屬性的設置,這與後臺的代碼相對應。
2、編寫Controller層的代碼
1 @Controller 2 public class UploadController { 3 4 @RequestMapping(value="/upload",method=RequestMethod.POST) 5 @ResponseBody 6 public String uploadImg(@RequestParam("img") MultipartFile img, HttpServletRequest request,HttpServletResponse response) { 7 String contentType = img.getContentType(); // 獲取文件的類型 8 System.out.println("文件類型為:" + contentType); 9 String originalFilename = img.getOriginalFilename(); // 獲取文件的原始名稱 10 // 判斷文件是否為空 11 if(!img.isEmpty()) { 12 File targetImg = new File("F:/img"); 13 // 判斷文件夾是否存在 14 if(!targetImg.exists()) { 15 targetImg.mkdirs(); //級聯創建文件夾 16 } 17 try { 18 // 開始保存圖片 19 FileOutputStream outputStream = new FileOutputStream("F:/img/" + originalFilename); 20 outputStream.write(img.getBytes()); 21 outputStream.flush(); 22 outputStream.close(); 23 } catch (IOException e) { 24 e.printStackTrace(); 25 } 26 } 27 return "SUCCESS"; 28 } 29 }查看代碼
3、Spring配置文件的修改和項目依賴的添加(小坑)
1 <!-- 文件上傳組件 --> 2 <dependency> 3 <groupId>commons-fileupload</groupId> 4 <artifactId>commons-fileupload</artifactId> 5 <version>1.3.1</version> 6 </dependency>查看代碼
1 <!-- 支持文件上傳 --> 2 <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> 3 <!-- 請求編碼格式 --> 4 <property name="defaultEncoding" value="utf-8"></property> 5 <!-- 上傳文件大小(單位:位元組) --> 6 <property name="maxUploadSize" value="50000000"></property> 7 <!-- 緩衝區大小(單位:KB) --> 8 <property name="maxInMemorySize" value="1024"></property> 9 </bean>查看代碼
4、啟動項目,打開瀏覽器顯示相應的圖片上傳的網頁,選擇圖片,點擊上傳,如果不出以外的化本地路徑上應該會看到剛剛上傳的圖片。
四、伺服器接收客戶端上傳的圖片
網上有不少內容關於本部分都是介紹使用HttpURLConnection進行上傳,這中方法一是比較複雜,需要自己手動封裝請求,洋洋灑灑幾十行代碼;二是如果項目比較複雜,用到Session或者Cookie的話,那就真沒轍了~
基於上述原因,本文選擇使用HttpClient進行本地圖片的上傳
1、引入相關的依賴
1 <dependency> 2 <groupId>org.apache.httpcomponents</groupId> 3 <artifactId>httpclient</artifactId> 4 <version>4.5.3</version> 5 </dependency> 6 <dependency> 7 <groupId>org.apache.httpcomponents</groupId> 8 <artifactId>httpmime</artifactId> 9 <version>4.5.3</version> 10 </dependency>查看代碼
2、編寫客戶端程式
1 import java.io.BufferedReader; 2 import java.io.File; 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.InputStreamReader; 6 import java.util.Arrays; 7 8 import org.apache.commons.codec.binary.Base64; 9 import org.apache.commons.lang3.StringUtils; 10 import org.apache.http.HttpEntity; 11 import org.apache.http.client.ClientProtocolException; 12 import org.apache.http.client.methods.CloseableHttpResponse; 13 import org.apache.http.client.methods.HttpPost; 14 import org.apache.http.entity.ContentType; 15 import org.apache.http.entity.mime.MultipartEntityBuilder; 16 import org.apache.http.entity.mime.content.ByteArrayBody; 17 import org.apache.http.entity.mime.content.FileBody; 18 import org.apache.http.entity.mime.content.StringBody; 19 import org.apache.http.impl.client.CloseableHttpClient; 20 import org.apache.http.impl.client.HttpClients; 21 import org.apache.http.util.EntityUtils; 22 23 public class ClientUpload { 24 25 public static void main(String[] args) throws ClientProtocolException, IOException, InterruptedException { 26 String url = "http://localhost:8090/plant/upload.action"; 27 // String basePath = "F:\\img\\"; 28 String path = "G:\\123.jpg"; 29 uploadImage(url, "dfsdfsdfsdf",path); 30 } 31 32 public static String uploadImage(String path, String base64String, String imageFilePath) throws ClientProtocolException, IOException { 33 // 1. 創建上傳需要的元素類型 34 // 1.1 裝載本地上傳圖片的文件 35 File imageFile = new File(imageFilePath); 36 FileBody imageFileBody = new FileBody(imageFile); 37 // 1.2 裝載經過base64編碼的圖片的數據 38 // String imageBase64Data = base64String; 39 // ByteArrayBody byteArrayBody = null; 40 // if (StringUtils.isNotEmpty(imageBase64Data)) { 41 // byte[] byteImage = Base64.decodeBase64(imageBase64Data); 42 // byteArrayBody = new ByteArrayBody(byteImage, "image_name"); 43 // } 44 // 1.3 裝載上傳字元串的對象 45 StringBody name = new StringBody("admin", ContentType.TEXT_PLAIN); 46 // 2. 將所有需要上傳元素打包成HttpEntity對象 47 // HttpEntity reqEntity = MultipartEntityBuilder.create().addPart("name", name).addPart("img", imageFileBody).addPart("file2", byteArrayBody).build(); 48 HttpEntity reqEntity = MultipartEntityBuilder.create().addPart("name", name).addPart("img", imageFileBody).build(); 49 // 3. 創建HttpPost對象,用於包含信息發送post消息 50 HttpPost httpPost = new HttpPost(path); 51 httpPost.setEntity(reqEntity); 52 // 4. 創建HttpClient對象,傳入httpPost執行發送網路請求的動作 53 CloseableHttpClient httpClient = HttpClients.createDefault(); 54 CloseableHttpResponse response = httpClient.execute(httpPost); 55 // 5. 獲取返回的實體內容對象並解析內容 56 HttpEntity resultEntity = response.getEntity(); 57 String responseMessage = ""; 58 try { 59 if (resultEntity != null) { 60 InputStream is = resultEntity.getContent(); 61 BufferedReader br = new BufferedReader(new InputStreamReader(is)); 62 StringBuffer sb = new StringBuffer(); 63 String line = ""; 64 while ((line = br.readLine()) != null) { 65 sb.append(line); 66 } 67 responseMessage = sb.toString(); 68 System.out.println("響應內容為:" + responseMessage); 69 } 70 EntityUtils.consume(resultEntity); 71 } finally { 72 if (null != response) { 73 response.close(); 74 } 75 } 76 return responseMessage; 77 } 78 }查看代碼
3、到此為止,不出意外的話因該能夠在控制台看到令人激動的“SUCCESS”輸出
五、業務邏輯的優化完善
1、由於圖片是在不斷生成的,所以要將圖片不斷地上傳,並且保證上傳地圖片不重覆。
1 public static void main(String[] args) throws ClientProtocolException, IOException, InterruptedException { 2 String url = "http://localhost:8090/plant/upload.action"; 3 String basePath = "F:\\img\\"; 4 // String path = "G:\\123.jpg"; 5 // uploadImage(url, "dfsdfsdfsdf",path); 6 while (true) { 7 File file = new File(basePath); 8 String[] list = file.list(); 9 Arrays.sort(list); 10 for (String str : list) { 11 // 圖片未標記為上傳 12 if (!str.startsWith("Upload")) { 13 uploadImage(url, "chao", basePath + str); // 上傳圖片 14 new File(basePath + str).renameTo(new File(basePath + "Upload_" + str)); // 重命名圖片 15 } 16 } 17 Thread.sleep(1000*60); //等待60秒 18 } 19 }查看代碼
2、服務端的完善
圖片如果想要能夠在開發的網站中瀏覽到,一般業務比較小的話是直接傳至Tomcat伺服器,然後將路徑記錄並寫入資料庫;業務比較龐大的可以現在本地搭建圖片伺服器,採用Nginx或其他技術都是可以做到的,然後也需要將該路徑寫入資料庫進行保存。