Javaweb-文件上傳和郵件發送

来源:https://www.cnblogs.com/twq46/archive/2022/08/03/16547570.html
-Advertisement-
Play Games

1.文件上傳 新建空項目 準備工作 在maven倉庫里下載commons io 和 commons fileupload兩個jar包 實用類介紹 文件上傳註意事項 為保證伺服器安全,上傳文件應該放在外界無法直接訪問的目錄下,比如放在WEB-INF目錄下 為防止文件覆蓋現象發生,要為上傳文件產生一個唯 ...


1.文件上傳

新建空項目

準備工作

在maven倉庫里下載commons io 和 commons fileupload兩個jar包

實用類介紹

文件上傳註意事項

  • 為保證伺服器安全,上傳文件應該放在外界無法直接訪問的目錄下,比如放在WEB-INF目錄下

  • 為防止文件覆蓋現象發生,要為上傳文件產生一個唯一的文件名:可以使用時間戳、uuid、MD5等方式解決文件重名問題

  • 要限制上傳文件的最大值

  • 可以上至上傳文件的類型,在收到上傳文件名時,判斷尾碼名是否合法

需要用到的類詳解

ServletFileUpload負責處理上傳的文件數據,並將表單中每個輸入項封裝成一個FileItem對象,在使用ServletFileUpload對象解析請求時需要DiskFileItemFactory對象,所以,我們需要在進行解析工作前構造好DiskFileItemFactory對象,通過ServletFileUpload對象的構造方法或setFileItemFactory()方法設置ServletFileUpload對象的fileItemFactory屬性。

FileItem類

在HTML頁面中必須有name
<form action="" enctype="multipart/form-data" method="post">
    上傳用戶:<input type="text" name="username"><br>
    <p><input type="file" name="file1"></p>
    <p><input type="file" name="file1"></p>
    <p><input type="submit">   <input type="reset"></p>
</form>

瀏覽器表單的類型如果為multipart/form-data,在伺服器端想要獲取數據就要通過流

常用方法介紹

/*isFormField方法用於判斷FIleItem類對象封裝的數據是一個普通文本表單
還是一個文件表單,如果是普通表單欄位則返回true,否則返回false*/
boolean isFormField();

//getName方法用於獲得文件上傳欄位中的文件名
String getName();

//以流的形式返回上傳文件的數據內容
InputStream getInputStream();

//delete方法用來清空FileItem類對象中存放的主體內容
//如果主體內容被保存在臨時文件中,delete方法將刪除該臨時文件
void delete();

ServletFileUpload類

ServletFileUpload負責處理上傳的文件數據,並將表單中每個輸入項封裝成一個FileItem對象中,使用其parseRequest(HttpServletRequest)方法可以將通過表單中每一個Html標簽提交的數據封裝成一個FileItem對象,然後以List列表的形式返回,使用該方法處理上傳文件簡單易用

代碼編寫

FileServlet代碼
package com.tang.servlet;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;

public class FileServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //判斷上傳的文件是普通表單還是帶文件的表單
        if(!ServletFileUpload.isMultipartContent(req)){
            return;//終止方法運行,說明這是一個普通表單,直接返回
        }

        //創建上傳文件的保存路徑,建議在WEB-INF路徑下,安全,用戶無法直接訪問上傳的文件
        String uploadPath = this.getServletContext().getRealPath("WEB-INF/upload");
        File uploadFile = new File(uploadPath);
        if(!uploadFile.exists()){//若文件不存在
            uploadFile.mkdir();//創建這個目錄
        }

        //緩存,臨時文件
        //臨時路徑,假如文件超過了預期的大小,我們就把他放到一個臨時文件中,過幾天自動刪除,或則提醒用戶轉存為永久
        String tmpPath = this.getServletContext().getRealPath("WEB-INF/tmp");
        File file = new File(tmpPath);
        if(!file.exists()){//若文件不存在
            file.mkdir();//創建這個臨時目錄
        }

        /*處理上傳的文件,一般都需要通過流來獲取,我們可以使用req.getInputStream(),原生態的文件上
        * 傳流獲取,十分麻煩,但是我們都是建議使用Apache的文件上傳組件來實現,common-fileupload,他需要依賴於commons-io組件*/

        try {
            //1.創建DiskFileItemFactory對象,處理文件上傳路徑或者大小限制的;
            DiskFileItemFactory factory = getDiskFileItemFactory(file);
            //2、獲取ServletFileUpload
            ServletFileUpload upload = getServletFileUpload(factory);
            //3、處理上傳文件。
            String msg = uploadParseRequest(upload,req,uploadPath);
            //Servlet請求轉發消息
            req.setAttribute("msg",msg);
            req.getRequestDispatcher("/info.jsp").forward(req,resp);
        }catch (FileUploadException e) {
            e.printStackTrace();
        }

   }


    public static DiskFileItemFactory getDiskFileItemFactory(File file){
        //1、創建DiskFileItemFactory對象,處理文件上傳路徑或限制文件大小.
        DiskFileItemFactory factory = new DiskFileItemFactory();
        //通過這個工廠設置一個緩衝區,當上傳的文件大小大於緩衝區的時候,將它放到臨時文件中;
        //這裡不設置的話也有預設的。
        factory.setSizeThreshold(1024 * 1024);//緩衝區大小為1M.
        factory.setRepository(file);
        return factory;
    }


    public static ServletFileUpload getServletFileUpload(DiskFileItemFactory factory){
        //2、獲取ServletFileUpload。
        ServletFileUpload upload = new ServletFileUpload(factory);
        //監聽文件上傳進度。
        upload.setProgressListener(new ProgressListener() {
            public void update(long pBytesRead, long lpContentLenght, int i) {
                //pBytesRead:已讀取到的文件大小。
                //pContentLenght:文件大小。
                System.out.println("總大小:"+lpContentLenght+"已上傳:"+pBytesRead);//在這裡還可以加進度。
            }
        });
        //處理亂碼問題.
        upload.setHeaderEncoding("UTF-8");
        //設置單個文件的最大值.
        upload.setFileSizeMax(1024 * 1024 * 10);
        //設置總共能夠上傳文件的大小.
        //1024 = 1kb * 1024 = 1M * 10 = 10M
        upload.setSizeMax(1024 * 1024 * 10);
        return upload;
    }


    public static String uploadParseRequest(ServletFileUpload upload,HttpServletRequest req,String uploadPath) throws IOException, FileUploadException {
        String msg = "";
        //3、處理上傳文件。
        //把前端的請求解析,封裝成一個FileItem對象,需要從ServletFileUpLoad對象中獲取
        List<FileItem> fileItems = upload.parseRequest(req);
        for (FileItem fileItem : fileItems) {
            if (fileItem.isFormField()) { //判斷是普通表單還是帶文件的表單。
                //getFieldName指的是前端表單控制項的name。
                String name = fileItem.getFieldName();
                String value = fileItem.getString("UTF-8");//處理亂碼。
                System.out.println(name + ":" + value);

            }else {//判斷它是帶文件的表單。

                //======================處理文件=======================//

                //拿到文件的名字
                String uploadFileName = fileItem.getName();
                System.out.println("上傳的文件名:" + uploadFileName);
                //可能存在文件不合法的情況
                if (uploadFileName.trim().equals("") || uploadFileName == null) {
                    continue;
                }
                //獲得上傳的文件名,例如/img/girl/ooa.jpg,只需要ooa,其前面的後面的都不需要。
                String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/") + 1);
                //獲得文件的尾碼名。
                String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1);

                    /*
                    如果文件尾碼名fileExtName不是我們所需要的。
                    就直接return,不處理,告訴用戶文件類型不對。
                    */
                    /*可以使用UUID(唯一識別的通用碼),保證文件名唯一。
                    UUID.randomUUID,隨機生一個唯一識別的通用碼。
                    網路傳輸中的東西,都需要序列化。
                    pojo,實體類,如果想要在多個電腦運行,傳輸--->需要把對象都序列化了。
                    JNI=java Native Interface
                    implements Serializable :標記介面,JVM--->java棧 本地方法棧 native-->c++ */
                String uuidPath= UUID.randomUUID().toString();
                System.out.println("文件信息【文件名:"+fileName+"文件類型:"+fileExtName+"】");
                //======================存放地址=======================//
                //存到哪?uploadPath
                //文件真實存在的路徑 realPath
                String realPath = uploadPath+"/"+uuidPath;
                //給每一個文件創建一個對應的文件夾
                File realPathFile = new File(realPath);
                if(!realPathFile.exists()){
                    realPathFile.mkdir();
                }
                //======================文件傳輸=======================//
                //獲得文件上傳的流
                InputStream inputStream = fileItem.getInputStream();

                //創建一個文件輸出流
                FileOutputStream fos = new FileOutputStream(realPath + "/" + fileName);

                //創建一個緩衝區
                byte[] buffer = new byte[1024 * 1024];

                //判斷是否讀取完畢
                int len = 0;

                //如果大於0,說明還存在數據
                while ((len=inputStream.read(buffer))>0){
                    fos.write(buffer,0,len);
                }

                //關閉流
                fos.close();
                inputStream.close();

                msg = "文件上傳成功!";
                fileItem.delete();//上傳成功,清除臨時文件
            }
        }
        return msg;
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>FileServlet</servlet-name>
        <servlet-class>com.tang.servlet.FileServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>FileServlet</servlet-name>
        <url-pattern>/upload.do</url-pattern>
    </servlet-mapping>
</web-app>

index.jsp

<%--
  Created by IntelliJ IDEA.
  User: twq
  Date: 2022/8/3
  Time: 17:10
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%--通過表單上傳文件
    get:上傳文件大小有限制
    post:上傳文件大小沒有限制
--%>
<%--${pageContext.request.contextPath}獲取伺服器路徑--%>
<form action="${pageContext.request.contextPath}/upload.do" enctype="multipart/form-data" method="post">
    上傳用戶:<input type="text" name="username"><br>
    <p><input type="file" name="file1"></p>
    <p><input type="file" name="file1"></p>
    <p><input type="submit">   <input type="reset"></p>
</form>
</body>
</html>

info.jsp


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
${msg}
</body>
</html>

運行結果圖

2.郵件發送

電子郵件

  • 要在網路上實現郵件功能,必須要有專門的郵件伺服器。

  • 這些郵件伺服器類似於現實生活中的郵局,它主要負責接收用戶投遞過來的郵件,並把郵件投遞到郵件接收者的電子郵箱中。

  • SMTP伺服器地址:一般是 smtp.xxx.com,比如163郵箱是smtp.163.com,qq郵箱是smtp.qq.com。

  • 電子郵箱(E-Mail地址)的獲得需要在郵件伺服器上進行申請。比如我們要使用QQ郵箱,就需要開通郵箱功能。

傳輸協議

SMTP協議

  • 我們通常把處理用戶smtp請求(郵件發送請求)的伺服器稱之為SMTP伺服器(郵件發送伺服器)。

POP3協議

  • 我們通常把處理用戶pop3請求(郵件接收請求)的伺服器稱之為POP3伺服器(郵件接收伺服器)。

郵件收發送原理圖


原理圖的描述:

  • 大Twq通過smtp協議連接到smtp伺服器,然後發送一封郵件給網易的郵件伺服器.

  • 網易分析發現需要去QQ的郵件伺服器,通過smtp協議將郵件轉投給QQ的smtp伺服器.

  • QQ將接收到的郵件存儲在[email protected]這個郵件賬號的空間中.

  • 小Twq通過Pop3協議連接到Pop3伺服器收取郵件.

  • [email protected]這個郵件賬號的空間中取出郵件.

  • Pop3伺服器將取出來的郵件送到小Twq手中.

註意:有可能你收件人地址,發件人地址等信息都正確了,控制台也列印了正確的信息,但是在收件箱就是收不到信息。這是因為可能收件箱伺服器拒收了你發的郵件(比如認為你的郵件是廣告),這時候可能在垃圾箱里能找到,可能找不到。解決辦法是重覆的郵件內容不要多次發送,或者更換收件箱試試。
8月4號繼續更新


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • vuex狀態管理 概述 vuex主要由state,mutations,actions,getters四部分構成(modules本文暫不闡述) state 全局狀態,只讀 組件讀取state方式 根組件上引入並掛載store對象,其他組件在計算屬性通過$store獲取狀態 可以在計算屬性上使用mapS ...
  • 封裝了一個基於vue的公用SvgIcon組件庫,只需要降svg文件放入指定文件夾,就可以通過文件名綁定到SvgIcon組件上使用該文件。 ...
  • 1. 表格標簽 1.1主要作用 顯示和展示數據美觀、良好。 1.2基本語法 <table> <tr> <td>單元格內的文字</td> ... </tr> ... </table> <table></table>用來定義表格的標簽 <tr></tr>標簽用於定義表格中的行,必須鑲嵌在<table>< ...
  • 在設計網頁的時候常常遇到這種情況:一個元素使用的樣式與另一個元素完全相同,但又添加了額外的樣式。 通常會在 HTML 中給元素定義兩個 class,一個通用樣式,一個特殊樣式。 普通CSS的實現 接下來以警告框為例進行講,解4種類型 | 類型 | 說明 | | | | | info | 信息!請註意 ...
  • 如果你有玩過 🎮 《王者榮耀》、《陰陽師》 等手游,一定註意到過它的啟動動畫、皮膚立繪卡片等場景,經常採用靜態底圖加局部液態流動效果的簡單動畫,本文使用前端開發技術,結合 SVG 和 CSS 來實現類似的液化流動效果。本文包含的知識點主要包括:mask-image 遮罩、feTurbulence ... ...
  • 一個工作薄中快速新建多個數據表 一、建立數據源數表 將所有數據統一錄入到本數據源表中,併進行統一排列數據。 註意:這裡的序號很重要,是對應後面工作表格獲取數據的來源,具體見公式設置。 二、建立一個表格模板 ① 將自己需要的表格進行製作及調整格式。 註意:做好表格列印格式調整。 ② 表格做好讀取表格名 ...
  • 1.用戶定義 在前面的案例中,我們的登錄用戶是基於配置文件來配置的(本質是基於記憶體),但是在實際開發中,這種方式肯定是不可取的,在實際項目中,用戶信息肯定要存入資料庫之中。 Spring Security支持多種用戶定義方式,接下來我們就逐個來看一下這些定義方式。通過前面的介紹(參見3小節),大家對 ...
  • 目錄 一.簡介 二.效果演示 三.源碼下載 四.猜你喜歡 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 基礎 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 轉場 零基礎 O ...
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...