整合營銷服務(wù)商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          JavaWeb實現(xiàn)文件上傳與下載

          . 增強HttpServletResponse對象

          1. 實現(xiàn)一個增強的HttpServletResponse類,需要繼承javax.servlet.http.HttpServletRequestWrapper類,通過重寫自己需要增強的方法來實現(xiàn)(這種模式就叫做裝飾者模式),使用該增強類在加上過濾器就可以實現(xiàn)無編碼轉(zhuǎn)換處理代碼。

          public class MyRequest extends HttpServletRequestWrapper{
          	private HttpServletRequest req;
          	public MyRequest(HttpServletRequest request) {
          		super(request);
          		req=request;
          	}
          	@Override
          	public String getParameter(String name) {
          		//解決編碼問題,無論是post還是get請求,都不需要在業(yè)務(wù)代碼中對編碼再處理
          		String method=req.getMethod();
          		if("get".equalsIgnoreCase(method)){
          			try {
          				String str=req.getParameter(name);
          				byte[] b=str.getBytes("iso8859-1");
          				String newStr=new String(b, "utf-8");
          				return newStr;
          			} catch (UnsupportedEncodingException e) {
          				// TODO Auto-generated catch block
          				e.printStackTrace();
          			}
          		}else if("post".equalsIgnoreCase(method)){
          			try {
          				req.setCharacterEncoding("utf-8");
          			} catch (UnsupportedEncodingException e) {
          				// TODO Auto-generated catch block
          				e.printStackTrace();
          			}
          		}
          		//絕對不能刪除此行代碼,因為此行代碼返回的就是編碼之后的數(shù)據(jù)
          		return super.getParameter(name);
          	}
          }
          

          在過濾器中應(yīng)用

          public class FilterTest4 implements Filter {
          	@Override
          	public void init(FilterConfig filterConfig) throws ServletException {}
          	@Override
          	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
          			throws IOException, ServletException {
          		//生成增強的HttpServletRequest對象
          		HttpServletRequest req=(HttpServletRequest) request;
          		MyRequest myReq=new MyRequest(req);
          		//將增強的HttpServletRequest對象傳入過濾器執(zhí)行鏈中,在后面?zhèn)魅氲膔equest對象都會是增強的HttpServletRequest對象
          		chain.doFilter(myReq, response);
          		
          	}
          	@Override
          	public void destroy() {}
          }
          

          2. 文件上傳原理過程

          1. JavaWeb中實現(xiàn)文件上傳:

          • 客戶端:HTML頁面需要一個<form>表單,且必須設(shè)置表單的enctype屬性值為"multipart/form-data",以及method屬性值為"post"(因為get方式不支持大量數(shù)據(jù)提交);表單里有一個<input type="file" name="">的標簽,且name屬性值必須指定。
          <html>
           <head>
           <title>My JSP 'upload.jsp' starting page</title>
          	<meta http-equiv="pragma" content="no-cache">
          	<meta http-equiv="cache-control" content="no-cache">
          	<meta http-equiv="expires" content="0"> 
          	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
          	<meta http-equiv="description" content="This is my page">
           </head>
           
           <body>
           <form action="" method="post" enctype="multipart/form-data">
           <input type="text" name="name">
           	請選擇文件:<input type="file" name="upload">
           	<input type="submit" value="上傳">
           </form>
           </body>
          </html>
          
          • 服務(wù)端:主要進行IO讀寫操作。必須導(dǎo)入commons-fileupload和commons-io兩個jar包,可以通過請求request對象的getInputStream獲得一個流來讀取請求中的文件數(shù)據(jù),但是如果客戶端上傳多個文件時,就會很麻煩,所以提供了commons-fileupload和commons-io兩個jar包來更方便的實現(xiàn)文件上傳。
          import java.io.FileOutputStream;
          import java.io.IOException;
          import java.io.InputStream;
          import java.io.OutputStream;
          import java.util.List;
          import javax.servlet.ServletException;
          import javax.servlet.http.HttpServlet;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          import org.apache.commons.fileupload.FileItem;
          import org.apache.commons.fileupload.FileUploadException;
          import org.apache.commons.fileupload.disk.DiskFileItemFactory;
          import org.apache.commons.fileupload.servlet.ServletFileUpload;
          public class UploadServlet extends HttpServlet{
          	@Override
          	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          		/**
          		 * 1. 創(chuàng)建磁盤文件項工廠類 DiskFileItemFactory
          		 * 2. 創(chuàng)建核心解析Request類 ServletFileUpload
          		 * 3. 開始解析Request對象中的數(shù)據(jù),并返回一個List集合
          		 * 4. List中包含表單中提交的內(nèi)容
          		 * 5. 遍歷集合,獲取內(nèi)容
          		 */
          		DiskFileItemFactory fac=new DiskFileItemFactory();
          		
          		ServletFileUpload upload=new ServletFileUpload(fac);
          		upload.setHeaderEncoding("utf-8");//防止中文的文件名亂碼
          		try {
          			List<FileItem> fileItems = upload.parseRequest(req);
          			for(FileItem item:fileItems){
          				//有可能是普通文本項,比如<input type="text">標簽提交上來的字符串
          				//也有可能是<input type="submit" value="上傳">上傳的文件
          				//文件項與普通項有不同的API來處理
          				//首先判斷是普通文本項還是文件項,
          				if(item.isFormField()){
          					//true表示普通文本項
          					//獲取文本項的name屬性值
          					String name=item.getFieldName();
          					//獲取對應(yīng)的文本
          					String value=item.getString("utf-8");//防止中文亂碼
          					System.out.println(name+":"+value);
          				}else{
          					//false表示文件項
          					//先獲取文件名稱
          					String name=item.getName();
          					//獲取文件項的輸入流
          					InputStream in=item.getInputStream();
          					//獲取服務(wù)器端文件存儲的目標磁盤路徑
          					String path=getServletContext().getRealPath("/upload");
          					System.out.println(path);
          					//獲取輸出流,輸出到本地文件中
          					OutputStream out=new FileOutputStream(path+"/"+name);
          					//寫入數(shù)據(jù)
          					int len=0;
          					byte[] b=new byte[1024];
          					while((len=in.read(b))!=-1){
          						out.write(b,0,len);
          					}
          					in.close();
          					out.close();
          					
          				}
          			}
          		} catch (FileUploadException e) {
          			// TODO Auto-generated catch block
          			e.printStackTrace();
          		}
          	}
          }
          

          注意:在文件上傳時,會將form表單的屬性enctype屬性值為"multipart/form-data",當提交到服務(wù)端后,無法使用 req.getParameter(name) 方法來獲取到內(nèi)容,只有通過上面的方法來獲取文本項。

          2. 文件上傳相關(guān)核心類:

          • DiskFileItemFactory:相關(guān)API如下
          • public DiskFileItemFactory():無參構(gòu)造器
          • public DiskFileItemFactory(int sizeThreshold, File repository):構(gòu)造器,sizeThreshold設(shè)置緩沖區(qū)大小,默認10240 byte;repository表示如果過緩沖區(qū)空間小于上傳文件空間,那么會生成臨時文件,repository就是指定該臨時文件的保存路徑,如果過未上傳完成就中斷,繼續(xù)上傳時就可以通過這個臨時文件來繼續(xù)上傳。
          • public void setSizeThreshold(int sizeThreshold):設(shè)置緩沖區(qū)大小
          • public void setRepository(File repository):指定該臨時文件的保存路徑
          //改進上面的文件上傳代碼,添加一個臨時文件
          public class UploadServlet extends HttpServlet{
          	@Override
          	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          		DiskFileItemFactory fac=new DiskFileItemFactory();
          		fac.setSizeThreshold(1024*1024);//設(shè)置緩沖區(qū)為1mb
          		//設(shè)置臨時文件的本地磁盤存儲路徑
          		File repository=new File(getServletContext().getRealPath("/temp"));
          		fac.setRepository(repository);
          		ServletFileUpload upload=new ServletFileUpload(fac);
          		upload.setHeaderEncoding("utf-8");//防止中文的文件名亂碼
          		try {
          			List<FileItem> fileItems = upload.parseRequest(req);
          			for(FileItem item:fileItems){
          				if(item.isFormField()){
          					String name=item.getFieldName();
          					String value=item.getString();
          					String value=item.getString("utf-8");//防止中文亂碼
          					System.out.println(name+":"+value);
          				}else{
          					String name=item.getName();
          					InputStream in=item.getInputStream();
          					String path=getServletContext().getRealPath("/upload");
          					System.out.println(path);
          					OutputStream out=new FileOutputStream(path+"/"+name);
          					int len=0;
          					byte[] b=new byte[1024];
          					while((len=in.read(b))!=-1){
          						out.write(b,0,len);
          					}
          					in.close();
          					out.close();
          					
          				}
          			}
          		} catch (FileUploadException e) {
          			// TODO Auto-generated catch block
          			e.printStackTrace();
          		}
          	}
          }
          
          • ServletFileUpload:相關(guān)API如下
          • public static final boolean isMultipartContent( HttpServletRequest request) :判斷表單提交上來的數(shù)據(jù)內(nèi)容是否是multipart類型的數(shù)據(jù),即 form表單的 enctype="multipart/form-data",是則返回true,否則返回false
          • public List /* FileItem */ parseRequest(HttpServletRequest request):解析request對象,返回一個泛型為FileItem 的List集合
          • public void setFileSizeMax(long fileSizeMax):設(shè)置單個文件的空間大小的最大值
          • public void setSizeMax(long sizeMax):設(shè)置所有文件空間大小之和的最大值
          • public void setHeaderEncoding(String encoding):解決上傳文件名的亂碼問題
          • public void setProgressListener(ProgressListener pListener):上傳時的進度條。
          • FileItem:封裝表單中提交的數(shù)據(jù)
          • boolean isFormField():判斷當前FileItem對象是表單中提交的文本數(shù)據(jù)項,還是文件數(shù)據(jù)項
          • String getFieldName():獲取文本項類型FileItem對象的name屬性值,即相當于表單中的 <input type="text" name="name">
          • String getString( String encoding ):獲取文本項類型FileItem對象的value值,可以指定編碼格式,也可以省略encoding不寫
          • String getName():應(yīng)用于文件項類型的FileItem對象,用于獲取文件的名稱,包括后綴名
          • InputStream getInputStream():獲取輸入流
          • void delete():刪除臨時緩存文件(在輸入以及輸出流關(guān)閉后執(zhí)行)

          3. 實現(xiàn)多文件上傳(需要js技術(shù)):主要是更改jsp頁面,通過js代碼來添加多個文件進行上傳,服務(wù)器代碼無需更改

          <%@ page language="java" import="java.util.*" pageEncoding="UTF-8" contentType="text/html; charset=utf-8"%>
          <%
          String path = request.getContextPath();
          String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
          %>
          <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
          <html>
           <head>
           <base href="<%=basePath%>">
           <title>My JSP 'upload.jsp' starting page</title>
          	<meta http-equiv="pragma" content="no-cache">
          	<meta http-equiv="cache-control" content="no-cache">
          	<meta http-equiv="expires" content="0"> 
          	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
          	<meta http-equiv="description" content="This is my page">
           </head>
           
           <body>
           <script type="text/javascript">
           	function run(){
           		var div=document.getElementById("divId");
           		 div.innerHTML+=
           		 "<div><input type='file' name='upload'><input type='button' value='刪除' onclick='del(this)'></div>"
           	}
           	function del(presentNode){
           		var div=document.getElementById("divId");
           		div.removeChild(presentNode.parentNode);
           	}
           </script>
           <div>
           	多文件上傳<br/>
           <form action="/Servlet/upload" method="post" enctype="multipart/form-data">
           	<input type="button" value="添加" onclick="run()"><br/>
           	<div id="divId">
           	
           	</div>
           	
           	<input type="submit" value="上傳">
           </form>
           </div>
           </body>
          </html>
          

          4. 關(guān)于文件上傳的一些問題:

          • 文件重名可能會產(chǎn)生覆蓋效果,可以在處理文件名時生成一個唯一的文件名
          • 如果所有的文件都儲存在一個文件夾中,會導(dǎo)致文件夾下文件過多,可以一個用戶一個文件夾,或者利用算法目錄分離等方法。

          3. 文件下載

          1. 傳統(tǒng)文件下載方式有超鏈接下載或者后臺程序下載兩種方式。通過超鏈接下載時,如果瀏覽器可以解析,那么就會直接打開,如果不能解析,就會彈出下載框;而后臺程序下載就必須通過兩個響應(yīng)頭和一個文件的輸入流。

          2. 后臺程序下載:

          • 兩個響應(yīng)頭:
          • Content-Type:其值有比如 text/html;charset=utf-8
          • Content-Disposition:其值為 attachment;filename=文件名 以附件形式打開
          • 流:需要獲取文件的輸入流,然后通過response對象的輸出流輸出到客戶端。

          單的 ASP.NET 頁面看上去就像普通的 HTML 頁面。


          Hello RUNOOB.COM

          在開始學(xué)習(xí) ASP.NET 之前,我們先來構(gòu)建一個簡單的 HTML 頁面,該頁面將在瀏覽器中顯示 "Hello RUNOOB.COM":

          Hello RUNOOB.COM!


          用 HTML 編寫的 Hello RUNOOB.COM

          下面的代碼將以 HTML 頁面的形式顯示實例:

          <html>

          <body bgcolor="yellow">

          <center>

          <h2>Hello RUNOOB.COM!</h2>

          </center>

          </body>

          </html>

          如果您想親自嘗試一下,請保存上面的代碼到一個名為 "firstpage.htm" 的文件中,并創(chuàng)建一個到該文件的鏈接:firstpage.htm。


          用 ASP.NET 編寫的 Hello RUNOOB.COM

          轉(zhuǎn)換 HTML 頁面為 ASP.NET 頁面最簡單的方法是,直接復(fù)制一個 HTML 文件,并把新文件的擴展名改成 .aspx

          下面的代碼將以 ASP.NET 頁面的形式顯示實例:

          <html>

          <body bgcolor="yellow">

          <center>

          <h2>Hello RUNOOB.COM!</h2>

          </center>

          </body>

          </html>

          如果您想親自嘗試一下,請保存上面的代碼到一個名為 "firstpage.aspx" 的文件中,并創(chuàng)建一個到該文件的鏈接:firstpage.aspx。


          它是如何工作的?

          從根本上講,ASP.NET 頁面與 HTML 是完全相同的。

          HTML 頁面的擴展名是 .htm。如果瀏覽器向服務(wù)器請求一個 HTML 頁面,服務(wù)器可以不進行任何修改,就直接發(fā)送頁面給瀏覽器。

          ASP.NET 頁面的擴展名是 .aspx。如果瀏覽器向服務(wù)器請求個 ASP.NET 頁面,服務(wù)器在將結(jié)果發(fā)回給瀏覽器之前,需要先處理頁面中的可執(zhí)行代碼。

          上面的 ASP.NET 頁面不包含任何可執(zhí)行的代碼,所以沒有執(zhí)行任何東西。在下面的實例中,我們將添加一些可執(zhí)行的代碼到頁面中,以便演示靜態(tài) HTML 頁面和動態(tài) ASP 頁面的不同之處。


          經(jīng)典 ASP

          Active Server Pages (ASP) 已經(jīng)流行很多年了。通過 ASP,可以在 HTML 頁面中放置可執(zhí)行代碼。

          之前的 ASP 版本(在 ASP.NET 之前)通常被稱為經(jīng)典 ASP。

          ASP.NET 不完全兼容經(jīng)典 ASP,但是只需要經(jīng)過少量的修改,大部分經(jīng)典 ASP 頁面就可以作為 ASP.NET 頁面良好地運行。

          如果您想學(xué)習(xí)更多關(guān)于經(jīng)典 ASP 的知識,請訪問我們的 ASP 教程。


          用經(jīng)典 ASP 編寫的動態(tài)頁面

          為了演示 ASP 是如何顯示包含動態(tài)內(nèi)容的頁面,我們將向上面的實例中添加一些可執(zhí)行的代碼(紅色字體標識):

          <html>

          <body bgcolor="yellow">

          <center>

          <h2>Hello RUNOOB.COM!</h2>

          <p><%Response.Write(now())%></p>

          </center>

          </body>

          </html>

          <% --%> 標簽內(nèi)的代碼是在服務(wù)器上執(zhí)行的。

          Response.Write 是用來向 HTML 輸出流中寫東西的 ASP 代碼。

          Now() 是一個返回服務(wù)器當前日期和時間的函數(shù)。

          如果您想親自嘗試一下,請保存上面的代碼到一個名為 "dynpage.asp" 的文件中,并創(chuàng)建一個到該文件的鏈接:dynpage.asp。


          用 ASP .NET 編寫的動態(tài)頁面

          下面的代碼將以 ASP.NET 頁面的形式顯示實例:

          <html>

          <body bgcolor="yellow">

          <center>

          <h2>Hello RUNOOB.COM!</h2>

          <p><%Response.Write(now())%></p>

          </center>

          </body>

          </html>

          如果您想親自嘗試一下,請保存上面的代碼到一個名為 "dynpage.aspx" 的文件中,并創(chuàng)建一個到該文件的鏈接:dynpage.aspx。


          ASP.NET 對比經(jīng)典 ASP

          上面的實例無法演示 ASP.NET 與經(jīng)典 ASP 之間任何的不同之處。

          正如最后的兩個實例中,您看不出 ASP 頁面和 ASP.NET 頁面兩者之間的不同之處。

          在下一章中,您將看到服務(wù)器控件是如何讓 ASP.NET 比經(jīng)典 ASP 更強大的。

          )CSS 標準盒子模型(Box Model)

          在網(wǎng)頁中所有HTML元素可以看作盒子,在CSS中,"box model"術(shù)語是用來設(shè)計和布局時使用的;CSS盒模型本質(zhì)上是一個盒子,封裝周圍的HTML元素包括:外邊距(margin)邊框(border)內(nèi)邊距(padding)實際內(nèi)容(content)四個屬性,所以布局時每個元素所占的總寬高是這4個屬性的總和;比如寬度:總元素的寬度=寬度+左填充+右填充+左邊框+右邊框+左邊距+右邊距

          1.1Margin(外邊距)清除邊框外的區(qū)域,外邊距是透明的

          1.2Border(邊框)圍繞在內(nèi)邊距和內(nèi)容外的邊框

          1.3Padding(內(nèi)邊距)清除內(nèi)容周圍的區(qū)域,內(nèi)邊距是透明的

          1.4Content(內(nèi)容)盒子里填充的內(nèi)容比如文本,圖像等

          標準盒子模型

          寬度為100px的div

          根據(jù)盒子模型得出該元素的總寬度為:100+(20+20)+(15+15)+(15+15)(由里至外)因此如果想在此div中放置一個寬度為100px的元素,此元素的總寬度必須小于等于100px

          2)DIV+CSS布局

          Div+CSS布局就是將網(wǎng)頁內(nèi)容用<div>分割為塊,之后使用css設(shè)置每個塊的大小,位置等

          DIV+CSS布局最重要的是靈活運用float(浮動)屬性,其值:1)left 2)right 3)both

          clear屬性作用是清除浮動,其值為:1)left 2)right 3)both

          d2向右浮動 float:right

          因為div是塊級元素,如果都沒有脫離文檔流div就會按照從上到下的順序放置

          d2設(shè)置為右浮動其他兩個div位置的變化:

          1)d1沒有脫離文檔流會占據(jù)一行,所以d2只能浮動到d1下面的右面如上圖所示

          2)d2脫離文檔流,d3自動填充到d2的位置

          d1,d2全部設(shè)置為右浮動

          1)當d1,d2都設(shè)置為右浮動時:因為css中d1在d2上面先設(shè)置,因此d1在右側(cè),如果d2在d1上面先設(shè)置樣式,則d2在右側(cè),d1在左側(cè),自己測試不再截圖

          2)當d1,d2都設(shè)置為右浮動時:d3就會跑到上圖中d2的位置

          3)如果3個div都設(shè)置左或右浮動,當3個width加一起<=100%就會在第一行顯示(d1,d2,d3)

           <style type="text/css">
                #d1 {
                margin: 0px;
                background-color: red;
                padding: 0px;
                width: 50%;
                height: 100px;
                float:right; 
              }
              #d2 {
                margin: 0px;
                background-color: yellow;
                padding: 0px;
                width: 50%;
                height: 100px;
                float:right; 
              }
              #d3 {
                margin: 0px;
                background-color: green;
                padding: 0px;
                width: 50%;
                height: 100px;
              }
            </style>

          d2清除左浮動,d3設(shè)置為右浮動

          當d2清除了左浮動,d3設(shè)置為右浮動,就會如上圖所示;如果d2清除的是右浮動,d2就會在d1上面,d3就會定位在d1下面的右面,自己測試不再截圖

          當d2清除了左浮動,如果想要d2緊挨著d1(與d1在一行上),可以通過position脫離文檔流設(shè)置其上下左右屬性使其定位在d1右側(cè),自己測試

          <!DOCTYPE html
            PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
          <html xmlns="http://www.w3.org/1999/xhtml">
          <head>
            <title>div+CSS布局</title>
            <style type="text/css">
                #d1 {
                margin: 0px;
                background-color: red;
                padding: 0px;
                width: 30%;
                height: 100px;
                float:left; 
              }
              #d2 {
                margin: 0px;
                background-color: yellow;
                padding: 0px;
                width: 40%;
                height: 100px;
                clear: left;     
              }
              #d3 {
                margin: 0px;
                background-color: green;
                padding: 0px;
                width: 30%;
                height: 100px; 
                float: right; 
              }
            </style>
          </head>
          <body>
              <div id="d1"><span style="font-size: 50px;">d1</span></div>
              <div id="d2"><span style="font-size: 50px;">d2</span></div>
              <div id="d3"><span style="font-size: 50px;">d3</span></div>
            </body>
          </html>

          DIV+CSS布局綜合運用position+上下左右屬性與float屬性為網(wǎng)頁進行布局

          注意:瀏覽器的兼容性問題,特別是使用IE內(nèi)核的瀏覽器對W3C的規(guī)范不怎么遵守


          主站蜘蛛池模板: 人妖在线精品一区二区三区| 亚洲成AV人片一区二区密柚| 夜夜高潮夜夜爽夜夜爱爱一区| 日韩精品乱码AV一区二区| 日韩电影一区二区三区| 亚洲一区二区三区在线网站| 好吊妞视频一区二区| 亚洲人成网站18禁止一区| 亚欧色一区W666天堂| 国产成人久久一区二区不卡三区| 国产一区二区三区四| 好湿好大硬得深一点动态图91精品福利一区二区 | 亚洲一区二区三区高清不卡| 精品无人乱码一区二区三区| 亚洲日本中文字幕一区二区三区 | 久久精品动漫一区二区三区| 亚洲性无码一区二区三区| 国产成人精品一区在线| 亚洲av乱码一区二区三区| 一区五十路在线中出| 精品一区二区三区在线播放视频| 国产一区二区三区免费看| 久久无码人妻一区二区三区| 国产伦精品一区二区三区免.费| 性无码免费一区二区三区在线| 成人精品一区二区三区电影| 国产一区二区三区不卡观| 日本一区二区三区在线看| 水蜜桃av无码一区二区| 一区二区三区杨幂在线观看| 国产成人久久精品区一区二区| 久久久久国产一区二区| 精品国产一区二区三区香蕉事| 国产一区二区精品久久| 无码国产精品一区二区高潮 | 国产成人精品第一区二区| 高清国产精品人妻一区二区 | 一区二区三区四区视频在线| 日本国产一区二区三区在线观看| 国产精品一区二区av| 一区二区三区伦理高清|