Javaweb学习笔记——(二十二)——————文件上传、下载、Javamail
?文件上傳概述
??? ?1.文件上傳的作用
??? ??? ?例如網(wǎng)絡硬盤,就是用來上傳下載文件的。
??? ??? ?在網(wǎng)絡瀏覽器中,時常需要上傳照片
??? ?2.文件上傳對頁面的要求
??? ??? ?上傳文件的要求比較多。需要記住
??? ??? ??? ?1.必須使用表單,而且不能是超鏈接。
??? ??? ??? ?2.表單的method必須是POST,不能是GET;
??? ??? ??? ?3.表單的enctype必須是meltipart/form-data
??? ??? ??? ?4.在表單中添加file表單字段,即<input type="file".../>
?? ??? ? ?? ?<form action="${pageContext.request.contextPath }/FileUploadServlet" method="post" enctype="multipart/form-data">
?? ??? ? ? ??? ?用戶名:<input type="text" name="username"/><br/>
?? ??? ? ? ??? ?文件1:<input type="file" name="file1"/><br/>
?? ??? ? ? ??? ?文件2:<input type="file" name="file2"/><br/>
?? ??? ? ? ??? ?<input type="submit" value="提交"/>
?? ??? ? ? ?</form>
?? ?3.比對文件上傳表單和普通文本表單的區(qū)別
?? ??? ?通過httpWatch查看“文件上傳表單”和“普通文本表單”的區(qū)別
?? ??? ??? ?*文件上傳表單是enctype="multipart/form-data",表示多部件表單數(shù)據(jù);
?? ??? ??? ?*普通文件表單可以不設置enctype屬性:
?? ??? ??? ??? ?**當method="post"時,enctype的默認值為application/x-www-form-urlencoded,表示使用url編碼正文;
?? ??? ??? ??? ?**當method="get"時,enctype的默認值為null,沒有正文,所以就不需要enctype了。
?? ??? ?對普通文本表單的測試:
?? ??? ??? ?<form action="${pageContext.request.contextPath }/FileUploadServlet" method="post">
?? ??? ??? ? ? ??? ?用戶名:<input type="text" name="username"/><br/>
?? ??? ??? ? ? ??? ?文件1:<input type="file" name="file1"/><br/>
?? ??? ??? ? ? ??? ?文件2:<input type="file" name="file2"/><br/>
?? ??? ??? ? ? ??? ?<input type="submit" value="提交"/>
?? ??? ??? ?</form>
?? ??? ??? ?通過httpWatch測試,查看表單的請求數(shù)據(jù)正文,我們發(fā)現(xiàn)請求中只有文件名稱,而沒有文件內容。也就是說,當表單的enctype不是multipart/form
?? ??? ??? ?-data時,請求中不包含文件內容,而只用文件的民粹,這說明普通文本表單中input:file和input:text沒有什么區(qū)別。
?? ??? ?對文件上傳表單的測試
?? ??? ??? ? ? ?<form action="${pageContext.request.contextPath }/FileUploadServlet" method="post" enctype="multipart/form-data">
?? ??? ??? ? ? ??? ?用戶名:<input type="text" name="username"/><br/>
?? ??? ??? ? ? ??? ?文件1:<input type="file" name="file1"/><br/>
?? ??? ??? ? ? ??? ?文件2:<input type="file" name="file2"/><br/>
?? ??? ??? ? ? ??? ?<input type="submit" value="提交"/>
?? ??? ??? ? ? ?</form>
?? ??? ??? ?通過httpWatch測試,查看表單的請求數(shù)據(jù)正文部分,發(fā)現(xiàn)正文部位是由多個部件組成,每個部件對應一個表單字段,每個部件都有自己的頭信息。頭信息下面是空行,空行下面是字段是正文部分。多個部件之間使用隨機生成的分割線隔開。
?? ??? ??? ?文本字段的頭信息中只包含一條頭信息,即Content-Disposition,這個頭信息的值有兩部分,第一部分是固定的,即form-data,第二部分為字段的名稱。在空行后面就是正文部分了,正文部分就是在文本框中填寫的內容。
?? ??? ??? ?文件字段的頭信息中包含了頭信息,Content-Disposition和Content-Type。Content-Disposition中多出了一個filename,它指定的是上傳的文件名稱。而Content-Type指定的是上傳文件的類型。文件字段的正文部分就是文件的內容。
?? ??? ??? ?請注意,因為我們上傳的文件都是普通文本文件,即txt文件,所以在httpWatch中是可以正常顯示的,如果上傳的是exe、mp3等文件,那么在httpWatch中看到的就是亂碼了。
?? ?4.文件上傳對Servlet的要求
?? ??? ?當提交的表單是文件上傳表單時,那么對Servlet也是有要求的。首先我們要肯定一點,文件上傳表單的數(shù)據(jù)也是被封裝到request對象中的。
?? ??? ?request.getParameter(String)方法獲取指定的表單字段字符內容,單文件上傳表單已經(jīng)不再是字符內容,而是字節(jié)內容,所以失效。
?? ??? ?這時可以使用request的getInputStream()方法獲取ServletInputStream對象,它是InputStream的子類,這個ServletInputStream對象對應整個表單的正文部分(從第一個分隔線開始,到最后),這說明我們需要的解析流中的數(shù)據(jù)。當然解析它是很麻煩的一件事情,而Apache已經(jīng)幫我們提供了了解它的工具:commons-fileupload。
?? ??? ?可以嘗試吧request.getInputStream()這個流中的內容打印出來,再對比httpWatch中請求數(shù)據(jù)。
?? ??? ??? ?public void doPost(HttpServletRequest request, HttpServletResponse response)
?? ??? ??? ??? ?throws ServletException, IOException {
?? ??? ??? ??? ?InputStream in = request.getInputStream();
?? ??? ??? ??? ?String s = IOUtils.toString(in);
?? ??? ??? ??? ?System.out.println(s);
?? ??? ??? ?}
?? ??? ??? ?-----------------------------7ddd3370ab2
?? ??? ??? ?Content-Disposition: form-data; name="username"
?? ??? ??? ?hello
?? ??? ??? ?-----------------------------7ddd3370ab2
?? ??? ??? ?Content-Disposition: form-data; name="file1"; filename="a.txt"
?? ??? ??? ?Content-Type: text/plain
?? ??? ??? ?aaa
?? ??? ??? ?-----------------------------7ddd3370ab2
?? ??? ??? ?Content-Disposition: form-data; name="file2"; filename="b.txt"
?? ??? ??? ?Content-Type: text/plain
?? ??? ??? ?bbb
?? ??? ??? ?-----------------------------7ddd3370ab2--
?? ?Commons-fileupload
?? ??? ?為什么使用filleupload:
?? ??? ??? ?上傳文件的要求比較多,需要記一下:
?? ??? ??? ??? ?*必須是POST表單;
?? ??? ??? ??? ?*表單的enctype必須是multipart/form-data;
?? ??? ??? ??? ?*在表單中添加file表單字段,即<input type="file" .../>
?? ??? ?Servlet的要求:
?? ??? ??? ?*不能再使用request.getParameter()來獲取表單數(shù)據(jù);
?? ??? ??? ?*可以使用request.getInputStream()得到所有的表單數(shù)據(jù),而不是一個表單項的數(shù)據(jù);
?? ??? ??? ?*這說明不適用fileupload,我們需要自己來對request.getInputStream()的內容進行解析。
?? ??? ?1.fileupload概述
?? ??? ??? ?fileupload是由apache的commons組件提供的上傳組件。它最主要的工作就是幫我們解析request.getInputStream()。
?? ??? ??? ?fileupload組件需要的jar包有:
?? ??? ??? ??? ?*commons-fileupload.jar,核心包;
?? ??? ??? ??? ?*commons-io.jar,依賴包。
?? ??? ?2.fileupload簡單應用
?? ??? ??? ?fileupload的核心類有:DiskFileItemFactory、ServletFileUpload、FileItem。
?? ??? ??? ?使員工fileupload組件的步驟如下:
?? ??? ??? ??? ?1.創(chuàng)建工廠類DiskFileItemFactory對象:DiskFileItemFactory factory = new DiskFileItemFactory()
?? ??? ??? ??? ?2.使用工廠創(chuàng)建解析器對象:ServetFileUpload fileUpload = new ServletFileUpload(factory);
?? ??? ??? ??? ?3.使用解析器來解析request對象:List<FileItem> list = fileUpload.parseRquest(request);
?? ??? ??? ?隆重介紹FileItem類,它才是我們最終想要的結果。一個FileItem對象對應一個表單項(表單字段)。一個表單中存在文件字段和普通字段,可以使用FileItem類的isFormField()方法來判斷表單字段是否為普通字段,如果不是普通字段,那么就是文件字段了。
?? ??? ??? ??? ?*String getName():獲取文件字段的文件名稱;
?? ??? ??? ??? ?*String getString():獲取字段的內容,如果是文件字段,那么獲取的是文件內容,當然上傳的文件必須是文本文件;
?? ??? ??? ??? ?*String getFieldName():獲取字段名稱,例如:<input type="text" name="username"/>,返回的是username;
?? ??? ??? ??? ?*String getContentType():獲取上傳的文件的類型,例如:text/plain。
?? ??? ??? ??? ?*int getSize():獲取上傳文件的大小;
?? ??? ??? ??? ?*boolean isFormField():判斷當前表單字段是否為普通文本字段,如果返回false,說明是文件字段;
?? ??? ??? ??? ?*InputStream getInputStream():獲取上傳文件對應的輸入流;
?? ??? ??? ??? ?*void write(File):把上傳的文件保存到指定文件中。
?? ??? ?3.簡單上傳示例
?? ??? ??? ?寫一個簡單的上傳示例:
?? ??? ??? ??? ?*表單包含一個用戶名字段,已經(jīng)一個文件字段;
?? ??? ??? ??? ?*Servlet保存上傳的文件到uploads目錄,顯示用戶名,文件名,文件大小,文件類型。
?? ??? ??? ?第一步:
?? ??? ??? ??? ?完成index.jsp,只需要一個表單。注意表單必須是post的,而且enctype必須是mulitpart/form-data的。
?? ??? ??? ??? ? ? ?<form action="${pageContext.request.contextPath }/FileUploadServlet" method="post" enctype="multipart/form-data">
?? ??? ??? ??? ? ? ??? ?用戶名:<input type="text" name="username"/><br/>
?? ??? ??? ??? ? ? ??? ?文件1:<input type="file" name="file1"/><br/>
?? ??? ??? ??? ? ? ??? ?<input type="submit" value="提交"/>
?? ??? ??? ??? ? ? ?</form>
?? ??? ??? ?第二步:
?? ??? ??? ??? ?完成FileUploadServlet
?? ??? ??? ??? ??? ??? ?public void doPost(HttpServletRequest request, HttpServletResponse response)
?? ??? ??? ??? ??? ??? ??? ??? ?throws ServletException, IOException {
?? ??? ??? ??? ??? ??? ??? ?// 因為要使用response打印,所以設置其編碼
?? ??? ??? ??? ??? ??? ??? ?response.setContentType("text/html;charset=utf-8");
?? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ?// 創(chuàng)建工廠
?? ??? ??? ??? ??? ??? ??? ?DiskFileItemFactory dfif = new DiskFileItemFactory();
?? ??? ??? ??? ??? ??? ??? ?// 使用工廠創(chuàng)建解析器對象
?? ??? ??? ??? ??? ??? ??? ?ServletFileUpload fileUpload = new ServletFileUpload(dfif);
?? ??? ??? ??? ??? ??? ??? ?try {
?? ??? ??? ??? ??? ??? ??? ??? ?// 使用解析器對象解析request,得到FileItem列表
?? ??? ??? ??? ??? ??? ??? ??? ?List<FileItem> list = fileUpload.parseRequest(request);
?? ??? ??? ??? ??? ??? ??? ??? ?// 遍歷所有表單項
?? ??? ??? ??? ??? ??? ??? ??? ?for(FileItem fileItem : list) {
?? ??? ??? ??? ??? ??? ??? ??? ??? ?// 如果當前表單項為普通表單項
?? ??? ??? ??? ??? ??? ??? ??? ??? ?if(fileItem.isFormField()) {
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?// 獲取當前表單項的字段名稱
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?String fieldName = fileItem.getFieldName();
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?// 如果當前表單項的字段名為username
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?if(fieldName.equals("username")) {
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?// 打印當前表單項的內容,即用戶在username表單項中輸入的內容
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?response.getWriter().print("用戶名:" + fileItem.getString() + "<br/>");
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ??? ??? ??? ?} else {//如果當前表單項不是普通表單項,說明就是文件字段
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?String name = fileItem.getName();//獲取上傳文件的名稱
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?// 如果上傳的文件名稱為空,即沒有指定上傳文件
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?if(name == null || name.isEmpty()) {
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?continue;
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?// 獲取真實路徑,對應${項目目錄}/uploads,當然,這個目錄必須存在
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?String savepath = this.getServletContext().getRealPath("/uploads");
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?// 通過uploads目錄和文件名稱來創(chuàng)建File對象
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?File file = new File(savepath, name);
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?// 把上傳文件保存到指定位置
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?fileItem.write(file);
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?// 打印上傳文件的名稱
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?response.getWriter().print("上傳文件名:" + name + "<br/>");
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?// 打印上傳文件的大小
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?response.getWriter().print("上傳文件大小:" + fileItem.getSize() + "<br/>");
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?// 打印上傳文件的類型
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?response.getWriter().print("上傳文件類型:" + fileItem.getContentType() + "<br/>");
?? ??? ??? ??? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ??? ?} catch (Exception e) {
?? ??? ??? ??? ??? ??? ??? ??? ?throw new ServletException(e);
?? ??? ??? ??? ??? ??? ??? ?}?
?? ??? ??? ??? ??? ??? ?}
?? ?文件上傳之細節(jié)
?? ??? ?1.把上傳的文件放到WEB-INF目錄下
?? ??? ??? ?如果沒有把用戶上傳的文件存放到WEB-INF目錄下,那么用戶就可以通過瀏覽器直接訪問上傳的文件,這是非常危險的。
?? ??? ??? ?假如說用戶上傳了一個a.jsp文件,然后用戶在通過瀏覽器去訪問這個a.jsp文件,那么就會執(zhí)行a.jsp中的內容,如果在a.jsp中有如下語句:Runtime.getRuntime().exec("shutdown -s -t 1");,那么系統(tǒng)立馬關機
?? ??? ??? ?通常我們會在WEB-INF目錄下創(chuàng)建一個uploads目錄來存放上傳的文件,而在Servlet中找到這個目錄需要使用ServletoContext的getRealPath(String)方法,例如在我的upload1項目中有如下語句:
?? ??? ??? ??? ?ServletContext servletContext = this.getServletContext();
?? ??? ??? ??? ?String savePath = servletContext.getRealPath("/WEB-INF/uploads");
?? ??? ??? ??? ?其中savePath為:F:\tomcat6_1\webapps\upload1\WEB-INF\uploads
?? ??? ?2.文件名稱(完整路徑、文件名稱)
?? ??? ??? ?上傳文件名稱可能是完整路徑:
?? ??? ??? ??? ?IE6獲取的上傳文件名稱是完整路徑,而其他瀏覽器獲取的上傳文件名稱只是文件名稱而已。瀏覽器差異的問題我們還是需要處理一下。
?? ??? ??? ??? ??? ?String name = file1FileItem.getName();
?? ??? ??? ??? ??? ?response.getWriter().print(name);
?? ??? ??? ??? ?使用不同瀏覽器測試,其中IE6就會返回上傳文件的完整路徑,不知道IE6怎么操作,這就給我們帶來了很大的麻煩,就是需要處理一下這個問題。
?? ??? ??? ??? ?處理這一問題也很簡單,無論是否為完整路徑,我們都去截取最后一個“\\”后面的內容就可以了。
?? ??? ??? ??? ??? ?String name = file1FileItem.getName();
?? ??? ??? ??? ??? ?int lastIndex = name.lastIndexOf("\\");//獲取最后一個“\”的位置
?? ??? ??? ??? ??? ?if(lastIndex != -1) {//注意,如果不是完整路徑,那么就不會有“\”的存在。
?? ??? ??? ??? ??? ??? ?name = name.substring(lastIndex + 1);//獲取文件名稱
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?response.getWriter().print(name);
?? ??? ?3.中文亂碼問題
?? ??? ??? ?上傳文件名稱包含中文:
?? ??? ??? ??? ?當上傳文件名稱中包含中文:
?? ??? ??? ??? ??? ?當上傳的誰的名稱中包含中文時,需要設置編碼,commons-fileupload組件為我們提供了兩種設置編碼的方式:
?? ??? ??? ??? ??? ??? ?*request.setCharacterEncoding(Strnig):這種方式是我們最為熟悉的一種;
?? ??? ??? ??? ??? ??? ?*fileUpload.setHeaderEncoding(String):這種方式的優(yōu)先級高于前一種。
?? ??? ??? ??? ?上傳文件的文件內容包含中文:
?? ??? ??? ??? ??? ?通常我們會把用戶上傳的文件保存到uploads目錄下,但是如果用戶上傳了同名文件?,這回出現(xiàn)覆蓋現(xiàn)象。處理這一問題的手段是使用UUID生產(chǎn)唯一名稱,然后再使用“_”連接文件上傳的原始名稱。
?? ??? ??? ??? ??? ?例如用戶上傳的文件是“123.jpg”,在通過處理后,文件名稱為“891b3881395f4175b969256a3f7b6e10_123.jpg”,這種手段不會使文件丟失擴展名,并且因為UUID的唯一性,上傳的文件同名,但是在服務器端是不會出現(xiàn)同名問題的。
?? ??? ??? ??? ??? ??? ?public void doPost(HttpServletRequest request, HttpServletResponse response)
?? ??? ??? ??? ??? ??? ??? ??? ?throws ServletException, IOException {
?? ??? ??? ??? ??? ??? ??? ?request.setCharacterEncoding("utf-8");
?? ??? ??? ??? ??? ??? ??? ?DiskFileItemFactory dfif = new DiskFileItemFactory();
?? ??? ??? ??? ??? ??? ??? ?ServletFileUpload fileUpload = new ServletFileUpload(dfif);
?? ??? ??? ??? ??? ??? ??? ?try {
?? ??? ??? ??? ??? ??? ??? ??? ?List<FileItem> list = fileUpload.parseRequest(request);
?? ??? ??? ??? ??? ??? ??? ??? ?//獲取第二個表單項,因為第一個表單項是username,第二個才是file表單項
?? ??? ??? ??? ??? ??? ??? ??? ?FileItem fileItem = list.get(1);
?? ??? ??? ??? ??? ??? ??? ??? ?String name = fileItem.getName();//獲取文件名稱
?? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ?// 如果客戶端使用的是IE6,那么需要從完整路徑中獲取文件名稱
?? ??? ??? ??? ??? ??? ??? ??? ?int lastIndex = name.lastIndexOf("\\");
?? ??? ??? ??? ??? ??? ??? ??? ?if(lastIndex != -1) {
?? ??? ??? ??? ??? ??? ??? ??? ??? ?name = name.substring(lastIndex + 1);
?? ??? ??? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ?// 獲取上傳文件的保存目錄
?? ??? ??? ??? ??? ??? ??? ??? ?String savepath = this.getServletContext().getRealPath("/WEB-INF/uploads");
?? ??? ??? ??? ??? ??? ??? ??? ?String uuid = CommonUtils.uuid();//生成uuid
?? ??? ??? ??? ??? ??? ??? ??? ?String filename = uuid + "_" + name;//新的文件名稱為uuid + 下劃線 + 原始名稱
?? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ?//創(chuàng)建file對象,下面會把上傳文件保存到這個file指定的路徑
?? ??? ??? ??? ??? ??? ??? ??? ?//savepath,即上傳文件的保存目錄
?? ??? ??? ??? ??? ??? ??? ??? ?//filename,文件名稱
?? ??? ??? ??? ??? ??? ??? ??? ?File file = new File(savepath, filename);
?? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ?// 保存文件
?? ??? ??? ??? ??? ??? ??? ??? ?fileItem.write(file);
?? ??? ??? ??? ??? ??? ??? ?} catch (Exception e) {
?? ??? ??? ??? ??? ??? ??? ??? ?throw new ServletException(e);
?? ??? ??? ??? ??? ??? ??? ?}?
?? ??? ??? ??? ??? ??? ?}
?? ??? ?5.一個目錄不能存放過多的文件(存放目錄打散)
?? ??? ??? ?一個目錄下不應該存放過多的文件,一般一個目錄下存放1000個文件就是上限了,如果在多,那么打開目錄的時候就會出現(xiàn)卡頓現(xiàn)象。
?? ??? ??? ?也就是說,我們需要把上傳的文件放到不同的目錄中。但是也不能為每個上傳的文件設置一個目錄,這種方式會導致目錄過多。所以應該采用某種算法進行“打散”操作。
?? ??? ??? ?打散的方式有很多,例如使用日期進行打散,每天生成一個目錄,也可以使用文件名的首字母來生成目錄,相同首字母的文件放到同一目錄下。
?? ??? ??? ?日期打散算法:如果某一天上傳的文件過多,那么也會出現(xiàn)一個目錄文件過多的情況;
?? ??? ??? ?首字打散算法:如果文件名是中文的,因為中文過多,所有會導致目錄過多的現(xiàn)象。
?? ??? ??? ?這里我們使用hash算法進行打散操作:
?? ??? ??? ??? ?1.獲取文件名稱的hashCode、int hCode = name.hashCode();
?? ??? ??? ??? ?2.獲取hCode的第4位,然后轉換成16進制字符;
?? ??? ??? ??? ?3.獲取hCode的5~8位,然后轉換成16進制字符;
?? ??? ??? ??? ?4.使用這兩個16進制的字符生成目錄鏈。例如第4位字符為“5”
?? ??? ??? ?這種算法的好處是,在uploads目錄下最多生成16個目錄,而每個目錄下最多再生成16個目錄,即256個目錄,所有上傳的文件都放到這256個目錄下。如果每個目錄上限為1000個文件,那么一共可以有256000個文件。
?? ??? ??? ?例如上傳文件名稱為:新建 文本文檔.txt,那么把“新建 文本文檔.txt”的哈希碼獲取到,再獲取哈希碼的低4位,和5~8位。假如第4位為9,5~8位為1,那么文件的保存路徑為uploads/9/1/。
?? ??? ??? ??? ?int hCode = name.hashCode();//獲取文件名的hashCode
?? ??? ??? ??? ?//獲取hCode的低4位,并轉換成16進制字符串
?? ??? ??? ??? ?String dir1 = Integer.toHexString(hCode & 0xF);
?? ??? ??? ??? ?//獲取hCode的低5~8位,并轉換成16進制字符串
?? ??? ??? ??? ?String dir2 = Integer.toHexString(hCode >>> 4 & 0xF);
?? ??? ??? ??? ?//與文件保存目錄連接成完整路徑
?? ??? ??? ??? ?savepath = savepath + "/" + dir1 + "/" + dir2;
?? ??? ??? ??? ?//因為這個路徑可能不存在,所以創(chuàng)建成File對象,再創(chuàng)建目錄鏈,確保目錄在保存文件之前已經(jīng)存在
?? ??? ??? ??? ?new File(savepath).mkdirs();
?? ??? ?6.上傳的單個文件的大小限制
?? ??? ??? ?限制上傳文件的大小很簡單,ServletFileUpload類的setFileSizeMax(long)就可以了。參數(shù)就是上傳文件的上限字節(jié)數(shù),例如servletFileUpload.setFileSizeMax(1024*10)表示上限為10kb。
?? ??? ??? ?一旦上傳的文件超出了上限,那么就會拋出FileUploadBase.FileSizeLimitExceededException異常。我們可以在Servlet中獲取這個異常,然后向頁面輸出“上傳的文件超出限制”。
?? ??? ??? ??? ??? ?public void doPost(HttpServletRequest request, HttpServletResponse response)
?? ??? ??? ??? ??? ??? ??? ?throws ServletException, IOException {
?? ??? ??? ??? ??? ??? ?request.setCharacterEncoding("utf-8");
?? ??? ??? ??? ??? ??? ?DiskFileItemFactory dfif = new DiskFileItemFactory();
?? ??? ??? ??? ??? ??? ?ServletFileUpload fileUpload = new ServletFileUpload(dfif);
?? ??? ??? ??? ??? ??? ?// 設置上傳的單個文件的上限為10KB
?? ??? ??? ??? ??? ??? ?fileUpload.setFileSizeMax(1024 * 10);
?? ??? ??? ??? ??? ??? ?try {
?? ??? ??? ??? ??? ??? ??? ?List<FileItem> list = fileUpload.parseRequest(request);
?? ??? ??? ??? ??? ??? ??? ?//獲取第二個表單項,因為第一個表單項是username,第二個才是file表單項
?? ??? ??? ??? ??? ??? ??? ?FileItem fileItem = list.get(1);
?? ??? ??? ??? ??? ??? ??? ?String name = fileItem.getName();//獲取文件名稱
?? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ?// 如果客戶端使用的是IE6,那么需要從完整路徑中獲取文件名稱
?? ??? ??? ??? ??? ??? ??? ?int lastIndex = name.lastIndexOf("\\");
?? ??? ??? ??? ??? ??? ??? ?if(lastIndex != -1) {
?? ??? ??? ??? ??? ??? ??? ??? ?name = name.substring(lastIndex + 1);
?? ??? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ?// 獲取上傳文件的保存目錄
?? ??? ??? ??? ??? ??? ??? ?String savepath = this.getServletContext().getRealPath("/WEB-INF/uploads");
?? ??? ??? ??? ??? ??? ??? ?String uuid = CommonUtils.uuid();//生成uuid
?? ??? ??? ??? ??? ??? ??? ?String filename = uuid + "_" + name;//新的文件名稱為uuid + 下劃線 + 原始名稱
?? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ?int hCode = name.hashCode();//獲取文件名的hashCode
?? ??? ??? ??? ??? ??? ??? ?//獲取hCode的低4位,并轉換成16進制字符串
?? ??? ??? ??? ??? ??? ??? ?String dir1 = Integer.toHexString(hCode & 0xF);
?? ??? ??? ??? ??? ??? ??? ?//獲取hCode的低5~8位,并轉換成16進制字符串
?? ??? ??? ??? ??? ??? ??? ?String dir2 = Integer.toHexString(hCode >>> 4 & 0xF);
?? ??? ??? ??? ??? ??? ??? ?//與文件保存目錄連接成完整路徑
?? ??? ??? ??? ??? ??? ??? ?savepath = savepath + "/" + dir1 + "/" + dir2;
?? ??? ??? ??? ??? ??? ??? ?//因為這個路徑可能不存在,所以創(chuàng)建成File對象,再創(chuàng)建目錄鏈,確保目錄在保存文件之前已經(jīng)存在
?? ??? ??? ??? ??? ??? ??? ?new File(savepath).mkdirs();
?? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ?//創(chuàng)建file對象,下面會把上傳文件保存到這個file指定的路徑
?? ??? ??? ??? ??? ??? ??? ?//savepath,即上傳文件的保存目錄
?? ??? ??? ??? ??? ??? ??? ?//filename,文件名稱
?? ??? ??? ??? ??? ??? ??? ?File file = new File(savepath, filename);
?? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ?// 保存文件
?? ??? ??? ??? ??? ??? ??? ?fileItem.write(file);
?? ??? ??? ??? ??? ??? ?} catch (Exception e) {
?? ??? ??? ??? ??? ??? ??? ?// 判斷拋出的異常的類型是否為FileUploadBase.FileSizeLimitExceededException
?? ??? ??? ??? ??? ??? ??? ?// 如果是,說明上傳文件時超出了限制。
?? ??? ??? ??? ??? ??? ??? ?if(e instanceof FileUploadBase.FileSizeLimitExceededException) {
?? ??? ??? ??? ??? ??? ??? ??? ?// 在request中保存錯誤信息
?? ??? ??? ??? ??? ??? ??? ??? ?request.setAttribute("msg", "上傳失敗!上傳的文件超出了10KB!");
?? ??? ??? ??? ??? ??? ??? ??? ?// 轉發(fā)到index.jsp頁面中!在index.jsp頁面中需要使用${msg}來顯示錯誤信息
?? ??? ??? ??? ??? ??? ??? ??? ?request.getRequestDispatcher("/index.jsp").forward(request, response);
?? ??? ??? ??? ??? ??? ??? ??? ?return;
?? ??? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ??? ?throw new ServletException(e);
?? ??? ??? ??? ??? ??? ?}?
?? ??? ??? ??? ??? ?}
?? ??? ?
?? ??? ?7.上傳文件的總大小限制
?? ??? ??? ?上傳文件的表單中可能允許上傳多個文件,例如:
?? ??? ??? ??? ?有時我們需要限制一個請求的大小。也就是說這個請求的最大字節(jié)數(shù)(所有表單項之和)實現(xiàn)這一功能也很簡單,只需要調用ServletFileUpload類的setSizeMax(long)方法即可。
?? ??? ??? ??? ?例如fileUpload.setSizeMax(1024*10),顯示整個請求的上限為10kb。當請求大小超出了10kb時,ServletFileUploa類的parseRequest()方法會拋出FileUploadBase.SizeLimitException異常。
?? ??? ?8.緩存大小與臨時目錄
?? ??? ??? ?一種現(xiàn)象:如果上傳一個藍光電影,先把電影保存到電影中,然后再通過內存copy到服務器硬盤上,那么你的內存能吃下嗎?
?? ??? ??? ?所以fileUpload組件不可能吧文件都保留到內存中,fileUpload會判斷文件大小是否超出10kb,如果是,那么就把文件保存到硬盤中,如果沒超過,那么就保存到內存中。
?? ??? ??? ?10kb是fileUpload的默認值,我們可以來設置它。
?? ??? ??? ?當文件保存到硬盤時,fileUpload是吧文件保存到系統(tǒng)臨時目錄,當然你也可以去設置臨時目錄。
?? ??? ??? ??? ?public void doPost(HttpServletRequest request, HttpServletResponse response)
?? ??? ??? ??? ??? ??? ?throws ServletException, IOException {
?? ??? ??? ??? ??? ?request.setCharacterEncoding("utf-8");
?? ??? ??? ??? ??? ?DiskFileItemFactory dfif = new DiskFileItemFactory(1024*20, new File("F:\\temp"));
?? ??? ??? ??? ??? ?ServletFileUpload fileUpload = new ServletFileUpload(dfif);
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?try {
?? ??? ??? ??? ??? ??? ?List<FileItem> list = fileUpload.parseRequest(request);
?? ??? ??? ??? ??? ??? ?FileItem fileItem = list.get(1);
?? ??? ??? ??? ??? ??? ?String name = fileItem.getName();
?? ??? ??? ??? ??? ??? ?String savepath = this.getServletContext().getRealPath("/WEB-INF/uploads");
?? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ?// 保存文件
?? ??? ??? ??? ??? ??? ?fileItem.write(path(savepath, name));
?? ??? ??? ??? ??? ?} catch (Exception e) {
?? ??? ??? ??? ??? ??? ?throw new ServletException(e);
?? ??? ??? ??? ??? ?}?
?? ??? ??? ??? ?}
?? ??? ??? ??? ?
?? ??? ??? ??? ?private File path(String savepath, String filename) {
?? ??? ??? ??? ??? ?// 從完整路徑中獲取文件名稱
?? ??? ??? ??? ??? ?int lastIndex = filename.lastIndexOf("\\");
?? ??? ??? ??? ??? ?if(lastIndex != -1) {
?? ??? ??? ??? ??? ??? ?filename = filename.substring(lastIndex + 1);
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?// 通過文件名稱生成一級、二級目錄
?? ??? ??? ??? ??? ?int hCode = filename.hashCode();
?? ??? ??? ??? ??? ?String dir1 = Integer.toHexString(hCode & 0xF);
?? ??? ??? ??? ??? ?String dir2 = Integer.toHexString(hCode >>> 4 & 0xF);
?? ??? ??? ??? ??? ?savepath = savepath + "/" + dir1 + "/" + dir2;
?? ??? ??? ??? ??? ?// 創(chuàng)建目錄
?? ??? ??? ??? ??? ?new File(savepath).mkdirs();
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?// 給文件名稱添加uuid前綴
?? ??? ??? ??? ??? ?String uuid = CommonUtils.uuid();
?? ??? ??? ??? ??? ?filename = uuid + "_" + filename;
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?// 創(chuàng)建文件完成路徑
?? ??? ??? ??? ??? ?return new File(savepath, filename);
?? ??? ??? ??? ?}
文件下載
?? ?1.通過Servlet下載1
?? ??? ?被下載的資源必須放到WEB-INF目錄下,(只要用戶不能通過瀏覽器直接訪問就ok),然后通過Servlet完成下載,
?? ??? ?在jsp頁面中給出超鏈接,連接到DownloadServlet,并提供要下載的文件名稱。然后DownloadServlet獲取文件的真實路徑,然后把文件寫入到response.getOutputStream()流中。
?? ??? ?download.jsp
?? ??? ??? ? ?<body>
?? ??? ??? ? ? ?This is my JSP page. <br>
?? ??? ??? ? ? ?<a href="<c:url value='/DownloadServlet?path=a.avi'/>">a.avi</a><br/>
?? ??? ??? ? ? ?<a href="<c:url value='/DownloadServlet?path=a.jpg'/>">a.jpg</a><br/>
?? ??? ??? ? ? ?<a href="<c:url value='/DownloadServlet?path=a.txt'/>">a.txt</a><br/>
?? ??? ??? ? ?</body>
?? ??? ?DownloadServlet.java
?? ??? ??? ??? ?public void doGet(HttpServletRequest request, HttpServletResponse response)
?? ??? ??? ??? ??? ??? ?throws ServletException, IOException {
?? ??? ??? ??? ??? ?String filename = request.getParameter("path");
?? ??? ??? ??? ??? ?String filepath = this.getServletContext().getRealPath("/WEB-INF/uploads/" + filename);
?? ??? ??? ??? ??? ?File file = new File(filepath);
?? ??? ??? ??? ??? ?if(!file.exists()) {
?? ??? ??? ??? ??? ??? ?response.getWriter().print("您要下載的文件不存在!");
?? ??? ??? ??? ??? ??? ?return;
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?IOUtils.copy(new FileInputStream(file), response.getOutputStream());
?? ??? ??? ??? ?}
?? ??? ?上面代碼有如下問題:
?? ??? ??? ?*可以下載a.avi,但是在下載框中的文件名稱為DownloadServlet;
?? ??? ??? ?*不能下載a.jpg和a.txt,而是在頁面中顯示他們。
?? ?2.通過Servlet下載2
?? ??? ?下面來處理上一例中的問題,讓下載框中可以顯示正確的文件名稱,已經(jīng)可以下載a.jsp和a.txt文件。
?? ??? ?通過添加content-disposition頭來處理上面問題。當設置了content-disposition頭后,瀏覽器就會彈出下載框。
?? ??? ?而且還可以通過content-disposition頭來指定下載文件的名稱
?? ??? ??? ??? ?String filename = request.getParameter("path");
?? ??? ??? ??? ?String filepath = this.getServletContext().getRealPath("/WEB-INF/uploads/" + filename);
?? ??? ??? ??? ?File file = new File(filepath);
?? ??? ??? ??? ?if(!file.exists()) {
?? ??? ??? ??? ??? ?response.getWriter().print("您要下載的文件不存在!");
?? ??? ??? ??? ??? ?return;
?? ??? ??? ??? ?}
?? ??? ??? ??? ?response.addHeader("content-disposition", "attachment;filename=" + filename);
?? ??? ??? ??? ?IOUtils.copy(new FileInputStream(file), response.getOutputStream());
?? ??? ??? ?雖然上面的代碼已經(jīng)處理txt和jpg等文件的下載問題,并且也處理了下載框中顯示文件名稱的問題,但是如果下載的文件名稱是中文的,那么還是不行的。
?? ?3.通過Serlvet下載3
?? ??? ?下面是處理在下載框中顯示中文的問題
?? ??? ?其實這一問題很簡單,只需要通過URL來編碼中文即可。
?? ??? ??? ?download.jsp
?? ??? ??? ? ? ?<a href="<c:url value='/DownloadServlet?path=這個殺手不太冷.avi'/>">這個殺手不太冷.avi</a><br/>
?? ??? ??? ? ? ?<a href="<c:url value='/DownloadServlet?path=白冰.jpg'/>">白冰.jpg</a><br/>
?? ??? ??? ? ? ?<a href="<c:url value='/DownloadServlet?path=說明文檔.txt'/>">說明文檔.txt</a><br/>
?? ??? ??? ?DownloadServlet.java
?? ??? ??? ??? ?String filename = request.getParameter("path");
?? ??? ??? ??? ?// GET請求中,參數(shù)中包含中文需要自己動手來轉換。
?? ??? ??? ??? ?// 當然如果你使用了“全局編碼過濾器”,那么這里就不用處理了
?? ??? ??? ??? ?filename = new String(filename.getBytes("ISO-8859-1"), "UTF-8");
?? ??? ??? ??? ?
?? ??? ??? ??? ?String filepath = this.getServletContext().getRealPath("/WEB-INF/uploads/" + filename);
?? ??? ??? ??? ?File file = new File(filepath);
?? ??? ??? ??? ?if(!file.exists()) {
?? ??? ??? ??? ??? ?response.getWriter().print("您要下載的文件不存在!");
?? ??? ??? ??? ??? ?return;
?? ??? ??? ??? ?}
?? ??? ??? ??? ?// 所有瀏覽器都會使用本地編碼,即中文操作系統(tǒng)使用GBK
?? ??? ??? ??? ?// 瀏覽器收到這個文件名后,會使用iso-8859-1來解碼
?? ??? ??? ??? ?filename = new String(filename.getBytes("GBK"), "ISO-8859-1");
?? ??? ??? ??? ?response.addHeader("content-disposition", "attachment;filename=" + filename);
?? ??? ??? ??? ?IOUtils.copy(new FileInputStream(file), response.getOutputStream());
JavaMail
?? ?*郵件協(xié)議
?? ?*teinet訪問郵件服務器
?? ?*JavaMail
?? ?郵件協(xié)議
?? ??? ?1.收發(fā)郵件
?? ??? ??? ?發(fā)郵件是從客戶端吧郵件發(fā)送到郵件服務器,收郵件是吧郵件服務器的郵件下載到客戶端。
?? ??? ??? ?在163、126、QQ、sohu、sina等網(wǎng)站注冊的Email賬戶,其實就是在郵件服務器中注冊的。這些網(wǎng)站都有自己的郵件服務器。
?? ??? ?2.郵件協(xié)議概述
?? ??? ??? ?與Http協(xié)議相同,收發(fā)郵件也是需要有傳輸協(xié)議的。
?? ??? ??? ??? ?*SMTP:(Simple Mail Transfer Protocol,簡單郵件傳輸協(xié)議)發(fā)郵件協(xié)議;
?? ??? ??? ??? ?*POP3:(Post Office Protocol Version 3,郵局協(xié)議第3版)收郵件協(xié)議;
?? ??? ??? ??? ?*IMAP:(Internet Message Access Protocol,因特網(wǎng)消息訪問協(xié)議)收發(fā)郵件協(xié)議。
?? ??? ?3.理解郵件收發(fā)過程
?? ??? ??? ?把郵件服務器理解為郵局,如果你需要寄一封信,那么你需要把信封放到信筒中,這樣你的信就會“自動”到達郵局,郵局會把信郵寄到另一個地方的郵局中。然后這封信會被送到收信人的郵箱中。最終收信人需要自己經(jīng)常查看郵箱中是否有新的信件。
?? ??? ??? ?其實每個郵件服務器都有SMTP服務器和POP3服務器構成,其中SMTP服務器負責發(fā)郵件的請求,而POP3負責收郵件的請求。
?? ??? ??? ?當然,有時會使用163的賬戶,向126的賬號發(fā)送郵件。這時郵件是發(fā)送到126的郵件服務器,而對于163的郵件服務器是不會存儲這封郵件的。
?? ??? ?4.郵件服務器名稱
?? ??? ??? ?SMTP服務器的端口號為25,服務器名稱為smtp.xxx.xxx。
?? ??? ??? ?POP3服務器的端口號為110,服務器名稱為pop3.xxx.xxx。
?? ??? ??? ?例如:
?? ??? ??? ??? ?*163:smtp.163.com和pop3.163.com;
?? ??? ??? ??? ?*126:smtp.126.com和pop3.126.com;
?? ??? ??? ??? ?*qq:smtp.qq.com和pop3.qq.com;
?? ??? ??? ??? ?*sohu:smtp.sohu.com和pop3.sohu.com;
?? ??? ??? ??? ?*sina:smtp.sina.com和pop3.sina.com。
?? ?telnet收發(fā)郵件
?? ??? ?1.BASE64加密
?? ??? ??? ?BASE64是一種加密算法,這總加密方式是可逆的。它的作用是使加密后的文本無法通過肉眼識別。java提供了sun.misc.BASE63Encoder這個類,用來對做Base64的加密和解密。
?? ??? ??? ??? ?
?? ??? ??? ??? ?import org.apache.commons.codec.binary.Base64;
?? ??? ??? ??? ?public class Base64Utils {
?? ??? ??? ??? ??? ?public static String encode(String s) {
?? ??? ??? ??? ??? ??? ?return encode(s, "utf-8");
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?public static String decode(String s) {
?? ??? ??? ??? ??? ??? ?return decode(s, "utf-8");
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ?public static String encode(String s, String charset) {
?? ??? ??? ??? ??? ??? ?try {
?? ??? ??? ??? ??? ??? ??? ?byte[] bytes = s.getBytes(charset);
?? ??? ??? ??? ??? ??? ??? ?bytes = Base64.encodeBase64(bytes);
?? ??? ??? ??? ??? ??? ??? ?return new String(bytes, charset);
?? ??? ??? ??? ??? ??? ?} catch (Exception e) {
?? ??? ??? ??? ??? ??? ??? ?throw new RuntimeException(e);
?? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?public static String decode(String s, String charset) {
?? ??? ??? ??? ??? ??? ?try {
?? ??? ??? ??? ??? ??? ??? ?byte[] bytes = s.getBytes(charset);
?? ??? ??? ??? ??? ??? ??? ?bytes = Base64.decodeBase64(bytes);
?? ??? ??? ??? ??? ??? ??? ?return new String(bytes, charset);
?? ??? ??? ??? ??? ??? ?} catch (Exception e) {
?? ??? ??? ??? ??? ??? ??? ?throw new RuntimeException(e);
?? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ?}
?? ??? ?2.telnet發(fā)郵件
?? ??? ??? ?連接163的smtp服務器:telnet smtp.163.com 25;
?? ??? ??? ?連接成功后需要如下步驟才能發(fā)送郵件:
?? ??? ??? ??? ?1.與服務器打招呼:ehlo你的名字
?? ??? ??? ??? ?2.發(fā)出登錄請求:auth-login
?? ??? ??? ??? ?3.輸入加密后的郵箱名:(1451388723@qq.com)aXRjYXN0X2N4ZkAxNjMuY29t
?? ??? ??? ??? ?4.輸入加密后的郵箱密碼:(123456)aXRjYXN0
?? ??? ??? ??? ?5.輸入誰來發(fā)送郵件,即from:mail from:<1451388723@qq.com>
?? ??? ??? ??? ?6.輸入把郵件發(fā)給誰,即to:rcpt to:<475652900@qq.com>
?? ??? ??? ??? ?7.發(fā)送添加數(shù)據(jù)請求:data
?? ??? ??? ??? ?8.開始輸入數(shù)據(jù),數(shù)據(jù)包含:from、to、subject、以及郵件內容,如果輸入結束后,以一個“.”為一行,表示輸入結束;
?? ??? ??? ??? ?
?? ??? ??? ??? ??? ?from:<1451388723@qq.com>
?? ??? ??? ??? ??? ?to:<475652900@qq.com>
?? ??? ??? ??? ??? ?subject: 我愛上你了
?? ??? ??? ??? ??? ?我已經(jīng)深深的愛上你了。
?? ??? ??? ??? ??? ?.
?? ??? ??? ??? ??? ?注意:在標題和郵件正文之間要有一個空行。當要退出時,一定要以一個“.”為單行,表示輸入結束。
?? ??? ??? ??? ?9.最后一步:quit
?? ??? ?3.telnet收郵件
?? ??? ??? ?1.telnet收郵件的步驟
?? ??? ??? ??? ?pop3無需使用Base64加密。
?? ??? ??? ??? ?收郵件連接的服務器是pop3.xxx.com,pop3協(xié)議的默認端口號為110。請注意。這與發(fā)郵件完全不同。如果你在163有郵箱賬號,那么你想使用telnet收郵件,需要連接的服務器是pop3.163.com。
?? ??? ??? ??? ?*連接pop3服務器:telnet.pop3.163.com 110
?? ??? ??? ??? ?*user命令:user 用戶名,例如:user 1451388723@163.com;
?? ??? ??? ??? ?*pass命令:pass 密碼,例如:pass 123456
?? ??? ??? ??? ?*stat命令:stat命令用來查看郵箱中郵件的個數(shù),所有郵件所占的空間;
?? ??? ??? ??? ?*list命令:list命令用來查看所有郵件,或指定郵件的狀態(tài),例如:list 1是查看第一封郵件的大小,list是查看郵件列表,即列出所有郵件的編號,及大小;
?? ??? ??? ??? ?*retr命令:查看指定郵件的內容,例如:retr 1#是查看第一封郵件的內容;
?? ??? ??? ??? ?*dele命令:標記某郵件為刪除,單不是馬上刪除,而是在退出時才會真正的刪除;
?? ??? ??? ??? ?*quit命令:退出。如果在退出之前已經(jīng)使用了dele命令標記了某些郵件,那么會在退出時刪除它們。
?? ?JavaMail
?? ??? ?1.JavaMail概述
?? ??? ??? ?JavaMail是由SUN公司提供的專門針對郵件的api,主要的jar包:mail.jar、activation.jar。
?? ??? ??? ?在使用MyEclipse創(chuàng)建web項目時,需要小心。如果只是在web項目中使用JavaMail是沒有什么問題的,發(fā)布到Tomcat上運行一點問題都沒有。
?? ??? ??? ?但是在web項目中寫測試那就出問題了。
?? ??? ??? ?在MyEclipse中,會自動給web項目導入javax.mail包中的類,但是不全(其實是只有接口,而沒有接口的實現(xiàn)類),所以只靠MyEclipse中的類是不能運行JavaMail項目的,但是如果這時你再去自行導入mail.jar時,就會出現(xiàn)沖突。
?? ??? ??? ?處理方案:到下面路徑中找到javaee.jar文件,把javax.mail刪除。
?? ??? ?2.JavaMail中主要類
?? ??? ??? ?JavaMail中主要類:javax.mail.Session、javax.mail.internet.MimeMessage、javax.mail.Transport。
?? ??? ??? ?Session:表示會話,即客戶端與郵件服務器之間的會話,想要獲得會話需要給出賬戶和密碼,當然還要給出服務器名稱。在郵件服務器中的Session對象,就相當于連接數(shù)據(jù)庫時的Commection對象。
?? ??? ??? ?MimeMessage:表示郵件類,它是Message的子類。它包含郵件的主題(標題)、內容,收件人地址、發(fā)件人地址,還可以設置抄送和暗送,甚至還可以設置附件。
?? ??? ??? ?Transport:用來發(fā)送郵件。它是發(fā)送器。
?? ??? ?3.JavaMail之HelloWorld
?? ??? ??? ?在使用telnet發(fā)郵件時,還需要自己來處理Base64編碼對問題,但是使用Javamail就不必理會這些問題了,都有JavaMail來處理。
?? ??? ??? ?第一步:獲取Session
?? ??? ??? ??? ?Session session = Session。getInstance(Properties prop, Authenticator auth);
?? ??? ??? ??? ?其中prop需要制定兩個鍵值,一個是制定服務器主機名,另一個是指定是否需要認證。
?? ??? ??? ??? ?Properties prop = new Properties();
?? ??? ??? ??? ?prop.setProperty("mail.host", "smtp.qq.com");//設置服務器主機名
?? ??? ??? ??? ?prop.setProperty("mail.smtp.auth", "true");//設置需要認證
?? ??? ??? ??? ?其中Authenticator是一個接口表示認證器,集校驗客戶端的身份。我們需要自己來實現(xiàn)這個接口,實現(xiàn)這個接口需要使用賬戶和密碼。
?? ??? ??? ??? ??? ?Authenticator auth = new Authenticator(){
?? ??? ??? ??? ??? ??? ?public PasswordAuthentication getPasswordAuthentication(){
?? ??? ??? ??? ??? ??? ??? ?return new PasswordAuthentication("1451388723", "123456");//用戶名和密碼
?? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ?通過上面的準備,現(xiàn)在可以獲取Session對象了:
?? ??? ??? ??? ??? ?Session session = Session.getInstance(prop, auth);
?? ??? ??? ?第二步:創(chuàng)建MimeMessage對象
?? ??? ??? ??? ?創(chuàng)建MimeMessage需要使用Session對象來創(chuàng)建:
?? ??? ??? ??? ??? ?MimeMssage msg = new MimeMessage(session);
?? ??? ??? ??? ?然后需要設置發(fā)信人地址、收信人地址、主題,以及郵件正文。
?? ??? ??? ??? ??? ?msg.setFrom(new InternetAddress("1451388723@qq.com"));//設置發(fā)信人
?? ??? ??? ??? ??? ?msg.setRecipients(RecipientType.TO, "1451388723@qq.com", "1451388724@qq.com");//設置多個收信人
?? ??? ??? ??? ??? ?msg.setRecipients(RecipientType.CC, "1451388723@sina.com","1451388724@sina.com");//設置多個抄送
?? ??? ??? ??? ??? ?msg.setRecipients(RecipientType.BCC, "475652900@qq.com");//設置暗送人
?? ??? ??? ??? ??? ?msg.setSubject("這是一封測試郵件");//設置主題(標題)
?? ??? ??? ??? ??? ?msg.setContent("當然是HelloWorld。","text/plain;charset=utf-8");//設置正文
?? ??? ??? ?第三步:發(fā)送郵件:
?? ??? ??? ??? ?Transport.send(msg);//發(fā)送郵件
?? ??? ?4.JavaMail發(fā)送帶有附件的郵件(了解)
?? ??? ??? ?一封郵件可以包含正文、附件N個,所有正文與N個附件都是有郵件的一個部分。
?? ??? ??? ?上面的HelloWorld案例中,只是發(fā)送了帶有正文的郵件,所以在調用setContent()方法時直接設置了正文,如果想要發(fā)送帶有附件郵件,那么需要設置郵件的內容為MimeMultiPart。
?? ??? ??? ??? ?MimeMulitpart parts = new MimeMulitpart();//多部件對象,可以理解為是部件的集合
?? ??? ??? ??? ?msg.setContent(parts);//設置郵件的內容為多部件內容。
?? ??? ??? ??? ?然后我們需要把正文、N個附件創(chuàng)建為“主體部件”對象(MimeBodyPart),添加到MimeMuiltPart中即可。
?? ??? ??? ??? ?MimeBodyPart part1 = new MimeBodyPart();//創(chuàng)建一個部件
?? ??? ??? ??? ?part1.setContent("這是正文部分", "text/html;charset=utf-8");//給部件設置內容
?? ??? ??? ??? ?parts.addBodyPart(part1);//把部件添加到部件集中。
?? ??? ??? ?下面我們創(chuàng)建一個附件:
?? ??? ??? ??? ?MimeBodyPart part2 = new MimeBodyPart();//創(chuàng)建一個部件
?? ??? ??? ??? ?part2.attachFile("d:\\a.jpg");//設置附件
?? ??? ??? ??? ?part2.setFileName("hello.jpg");//設置附件名稱
?? ??? ??? ??? ?part2.addBodyPart(part2);//把附件添加到部件集中
?? ??? ??? ?注意:如果在設置名稱中,文件名稱中包含了中文的話,那么需要使用MimeUitlity類來給中文編碼:
?? ??? ??? ??? ?part2.setFileName(MimeUitlity.encodeText("美女.jpg"));
?? ??? ??? ??? ?
轉載于:https://www.cnblogs.com/changemax/p/10015058.html
總結
以上是生活随笔為你收集整理的Javaweb学习笔记——(二十二)——————文件上传、下载、Javamail的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 需求文件requirements.txt
- 下一篇: 文本监控 :oninput onchan