標籤:
在使用servlet上傳的時候,因為request裡面有時候既包含了參數資訊還有檔案資訊,取出來的時候就會很麻煩,所以我們可以根據request取出參數的原理,相當於自訂一個request來實現我們的檔案上傳和其他參數取出的分離.
一.關聯關係和依賴關係
介紹這個問題之前,需要先理解幾個概念
Class A{ private B b;}
用下面代碼解釋就是A中的方法需要B類的作為參數參與
Class A{ public void f(B b);}
說到這就想起了裝飾者模式,兩者都可以說是裝飾者模式的一種實現吧.下面要做的也是利用裝飾者模式來解決.
二.具體實現1.HttpServletRequest
從類的結構圖,可以看出來HttpServletRequest實現了兩個介面,這裡我們重點看HttpServletRequestWrapper.
尋找API會發現HttpServletRequestWrapper裡面管理著HttpServletRequest裡面鎖調用的方法,因此我們只要自訂一個類,繼承HttpServletRequestWrapper,然後利用自訂的類來建立req就可以實現自訂的request了.
2.自訂MultipartRequestWrapper
自訂前需要引入兩個上傳組件包
自訂前需要注意:上傳資料可能有多值現象,比如checkbox,這樣的就是一個數組.另外之前的檔案上傳使用的是傳統的方法traditional API,這裡換成Streaming API,相比傳統的方式,這種方式更加迅速.
import org.apache.commons.fileupload.FileItemIterator;import org.apache.commons.fileupload.FileItemStream;import org.apache.commons.fileupload.FileUploadException;import org.apache.commons.fileupload.servlet.ServletFileUpload;import org.apache.commons.fileupload.util.Streams;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequestWrapper;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.util.Arrays;import java.util.HashMap;import java.util.Map;/** * Created by nl101 on 2016/3/8. */public class MultipartRequestWrapper extends HttpServletRequestWrapper { //儲存參數的集合 private Map<String,String[]> params = new HashMap<>(); private static String PATH = "E:\\temp\\"; //設定上傳路徑 public MultipartRequestWrapper(HttpServletRequest request) { super(request); setParams(request);//對request進行解析,並存入map中 } /** * 通過StreamingAPI的方式上傳檔案 */ private void setParams(HttpServletRequest request){ //擷取上傳檔案類型 if (ServletFileUpload.isMultipartContent(request)){ //建立ServletFileUpload執行個體 ServletFileUpload fileUpload = new ServletFileUpload(); try { //解析request請求 返回FileItemStream的iterator執行個體 FileItemIterator iter = fileUpload.getItemIterator(request); InputStream is = null;//輸出資料流 //迭代取出 while (iter.hasNext()){ FileItemStream item = iter.next();//擷取檔案流 String name = item.getFieldName();//返回表單中標籤的name值 is = item.openStream();//得到對應表單的輸出資料流 if (item.isFormField()){//如果是非檔案域,設定進入map,這裡要注意多值處理 setFormParam(name,is);//如果不是檔案上傳,處理 }else { if (is.available()>0){//如果輸出資料流的內容大於0 String fname = item.getName();//擷取檔案名稱 Streams.copy(is,new FileOutputStream(PATH+fname),true);//拷貝內容到上傳路徑 params.put(name,new String[]{fname});//把檔案名稱設定進request中 } } } } catch (FileUploadException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }else { params = request.getParameterMap();//如果不是檔案上傳請求,則直接設定map } } /** * 處理非上傳的表單 * @param name * @param is */ private void setFormParam(String name, InputStream is) { try { if (params.containsKey(name)){//判斷當前值name是否已經儲存過 String[] values = params.get(name);//取出已經儲存過的值 values = Arrays.copyOf(values,values.length+1);//把當前數組擴大 values[values.length-1] = Streams.asString(is);//增加新值 params.put(name,values);//重新添加到map中 }else { params.put(name,new String[]{Streams.asString(is)});//直接存入參數中 } } catch (IOException e) { e.printStackTrace(); } } /** * 返回參數map集合,自訂後上傳檔案,上傳成功則返迴文件名 * @return */ @Override public Map<String,String[]> getParameterMap() { return params; } /** * 從請求中取出參數 * @param name * @return */ @Override public String getParameter(String name) { String[] values = params.get(name); if(values!=null) { return values[0]; } return null; } /** * 從請求中取出多個參數值,如checkbox的值 * @param name * @return */ @Override public String[] getParameterValues(String name) { String[] values = params.get(name); if(values!=null) { return values; } return null; }}
3.使用自訂的request
使用就很簡單了,直接在處理上傳的Servlet中來再次封裝下req即可
import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;/** * Created by nl101 on 2016/3/9. */public class UploadServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req = new MultipartRequestWrapper(req);//重新封裝 req.getParameter("username");//接著就可以像往常一樣處理請求了 req.getParameter("file");//接著就可以像往常一樣處理請求了 }}
別忘記配置WEB.xml檔案
<servlet> <servlet-name>UploadServlet</servlet-name> <servlet-class>com.servlet.UploadServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>UploadServlet</servlet-name> <url-pattern>/upload.do</url-pattern> </servlet-mapping>
4,jsp測試
<%@ page contentType="text/html;charset=UTF-8" language="java" %><html> <head> <title>上傳測試</title> </head> <body> <form action="upload.do" method="post" enctype="multipart/form-data"> <table border="1"> <tr> <td>使用者名稱:<input name="username" type="text"></td> </tr> <tr> <td>上傳:<input type="file" name="file"></td> </tr> <tr> <td><input type="submit" value="上傳"></td> </tr> </table> </form> </body></html>
這樣點擊上傳,就可以完成上傳了,而且我們的處理還是像往常一樣通過req.getParameter(“username”),這樣用起來省心太多了.
Servlet基於HttpServletRequestWrapper的檔案上傳