1. 程式人生 > >圖片上傳並回顯後端篇

圖片上傳並回顯後端篇

save a13 標簽設置 seek resp nal png mov tin

圖片上傳並回顯後端篇

我們先看一下效果
技術分享圖片

繼上一篇的圖片上傳和回顯,我們來實戰一下圖片上傳的整個過程,今天我們將打通前後端,我們來真實的了解一下,我們上傳的文件,是以什麽樣的形式上傳到服務器,難道也是一張圖片?等下我們來揭曉

我們在實戰開始前呢,我們先做一下準備工作,比如新建一個java web工程,如果你不懂這個的話,那我建議你先學一下Javaweb,可以去我的公眾號找一下這方面的教程。我們就給我們的工程起名為UpImg,我們再給他建一個web包和util包,再把我們以前前端做的圖片回顯的代碼拷到工程裏,我們來看一下項目

技術分享圖片

我們發布一下項目來看一下
技術分享圖片

這樣的話,我們基本的框架就做好了,我們今天就先用form表單來實戰一下圖片的上傳,下一期我們就通過ajax來實現異步圖片上傳,我們先給我們的前端代碼加點料

<form action="upload" method="post" enctype="multipart/form-data">
    <div class="uploadImgBtn" id="uploadImgBtn">
        <input class="uploadImg" type="file" name="file" multiple id="file">
    </div>
    <input type="submit" value="上傳">
</form>

這個樣式我就不再美化了,我們來看一下效果
技術分享圖片


這樣的話,我們前端基本就完成了,我來講解一下部分代碼吧;表單的enctype屬性:

1、默認屬性:application/x-www-form-urlencoded,只處理表單域中的value屬性值,采用這種編碼的方式的表單會將表單域的值處理成url編碼方式

2、multipart/form-data,這種編碼方式的表單會以二進制流的方法來處理表單數據。這種編碼方式會將文件域指定文件的內容也封裝到請求參數裏

3、text/plain,這種方式主要適用於直接通過表單發送郵件的方式

接下來我們講解一下文件上傳的思路,
1、先是表單提交
2、對數據和附件進行二進制編碼
3、servlet中使用二進制流獲取內容

思路我們已經知道了,那我們就開始編碼吧
我們先在util包下新建一個類,我就起名為UpImgUtils,接下來我們就編碼吧

package util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.servlet.http.HttpServletRequest;

/**
* upload Img Utils
*
* @author admin
*
*/
public class UpImgUtils {

    /*
    * 思路 1、從request當中獲取流信息
    *  2、新建一個臨時文件,用輸出流指向這個文件
    *  3、關閉流
    */
    public static void keepFile(HttpServletRequest request) throws IOException {

        // 1、從request當中獲取流信息
        InputStream fileSource = request.getInputStream();

        /*
        * 臨時文件的存儲路徑(我們在webContent下新建一個temp文件夾,發布項目的時候很可能因為temp為空,
        * 沒在tomcat中建立一個文件夾,到時候自己在發布的項目中添加一個即可)
        */
        String tempFileName = request.getServletContext().getRealPath("/") + "temp/tempfile.txt";

        //    2、新建一個臨時文件,用輸出流指向這個文件

        //    建一個文件
        File tempFile = new File( tempFileName );

        //    用輸出流指向這個文件

        FileOutputStream outputStream = new FileOutputStream( tempFile );

        //我們就每次讀寫10K,我們的文件小,這個就已經夠用了
        byte[] b = new byte[1024*10];

        int n = 0 ;

        //讀寫文件,-1標識為空
        while( (n = fileSource.read(b) ) != -1 ) {
            outputStream.write(b, 0, n);
        }

        //    3、關閉流
        fileSource.close();
        outputStream.close();

    }
}

這個類就是用來讀取form表單傳來的字節流,寫到一個臨時文件中,我們就一個servlet來調用一下我們的工具來看看效果。

package web;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import util.UpImgUtils;


public class upload extends HttpServlet {
    private static final long serialVersionUID = 1L;


    public upload() {
        super();
        // TODO Auto-generated constructor stub
    }


    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        UpImgUtils.keepFile(request);
    }


    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

代碼已經寫好,我的項目是java web項目2.5的版本,會自動配置servlet,配置的話,就不再講解。我們來運行看一下效果
技術分享圖片

我們已經看到了,實際上文件上傳就是把文件的二進制流上傳到服務端,這難道就結束了嗎?

那肯定不可能啊,我們上傳的是個圖片,那我們肯定希望還是圖片啊,我們就來重新封裝一個工具類,在封裝之前,我們先看一下臨時文件的格式

技術分享圖片

這是我隨便找的兩個文件,上傳後生成的臨時文件,我們就不實戰封裝兩個文件了,我們就實戰一下封裝一個臨時文件,因此呢我們先把input標簽中的multiple屬性去掉,把我們的前端自動生成input標簽的代碼也先註釋掉,我們先看一下改動的代碼

<script>
    $(document).ready(function(){
        //為外面的盒子綁定一個點擊事件
        $("#uploadImgBtn").click(function(){
            /*
            1、先獲取input標簽
            2、給input標簽綁定change事件
            3、把圖片回顯
             */
//            1、先回去input標簽
            var $input = $("#file");
            console.log($input)
//            2、給input標簽綁定change事件
            $input.on("change" , function(){
                console.log(this)
                //補充說明:因為我們給input標簽設置multiple屬性,因此一次可以上傳多個文件
                //獲取選擇圖片的個數
                var files = this.files;
                var length = files.length;
                console.log("選擇了"+length+"張圖片");
                //3、回顯
                $.each(files,function(key,value){
                    //每次都只會遍歷一個圖片數據
                    var div = document.createElement("div"),
                        img = document.createElement("img");
                    div.className = "pic";

                    var fr = new FileReader();
                    fr.onload = function(){
                        img.src=this.result;
                        div.appendChild(img);
                        document.body.appendChild(div);
                    }
                    fr.readAsDataURL(value);
                })

            })
             //把這下面的註釋掉即可
//            //4、我們把當前input標簽的id屬性remove
//            $input.removeAttr("id");
//            //我們做個標記,再class中再添加一個類名就叫test
//            var newInput = ‘<input class="uploadImg test" type="file" name="file" multiple id="file">‘;
//            $(this).append($(newInput));

        })

    })

</script>

我們來看一下一個文件的時候,臨時文件的格式
技術分享圖片

我們來分析一下,第二行的filename是我們需要的,這是文件的名稱,我們已經看到中文名稱亂碼,一會編碼的時候,我們需要解決一下;第4行有一個空行,到第5行的時候才到我們的正文部分;我們的正文結束的時候會有一個空格;既然知道了這些,我們就去完善一下我們的工具類吧

package util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;

import javax.servlet.http.HttpServletRequest;

/**
* upload Img Utils
*
* @author admin
*
*/
public class UpImgUtils {

    /*
    * 思路 1、從request當中獲取流信息
    *  2、新建一個臨時文件,用輸出流指向這個文件
    *  3、關閉流
    */
    public static void keepFile(HttpServletRequest request) throws IOException {

    // 1、從request當中獲取流信息
    InputStream fileSource = request.getInputStream();

    /*
    * 臨時文件的存儲路徑(我們在webContent下新建一個temp文件夾,發布項目的時候很可能因為temp為空,
    * 沒在tomcat中建立一個文件夾,到時候自己在發布的項目中添加一個即可)
    */
    String tempFileName = request.getServletContext().getRealPath("/") + "temp/tempfile.txt";

    //2、新建一個臨時文件,用輸出流指向這個文件

    //建一個文件
    File tempFile = new File( tempFileName );

    //用輸出流指向這個文件

    FileOutputStream outputStream = new FileOutputStream( tempFile );

    //我們就每次讀寫10K,我們的文件小,這個就已經夠用了
    byte[] b = new byte[1024*10];

    int n = 0 ;

    //讀寫文件,-1標識為空
    while( (n = fileSource.read(b) ) != -1 ) {
        outputStream.write(b, 0, n);
    }

    //3、關閉流
    fileSource.close();
    outputStream.close();

    //第二部分......................................................
    /**
    * 思路
    * 1、獲取文件的名稱,並解決中文亂碼
    * 2、獲取文件的內容
    * 3、保存文件
    */

    //第二部分 1、獲取文件的名稱,並解決中文亂碼

    RandomAccessFile randomFile = new RandomAccessFile(tempFile,"r");
    randomFile.readLine();//先讀取一行
    String str = randomFile.readLine();//讀取第二行
    int beginIndex = str.lastIndexOf("filename=\"") + 10;//定位到文件名開始的地方
    int endIndex = str.lastIndexOf("\"");//定位到文件名結尾的地方

    String filename = str.substring(beginIndex, endIndex);

    //判斷文件名是全路徑名還是只是文件名(google和火狐是只是文件名,微軟系列是全路徑名)
    endIndex = filename.lastIndexOf("\\") + 1;
    if( endIndex > -1 ) {
        filename = filename.substring(endIndex);
    }
    //經過上面的這幾步,我們就已經獲取到了文件名,我們還需要解決一下中文名亂碼的問題

    //解決上傳文件中文名字亂碼
    filename = new String(filename.getBytes("ISO-8859-1"), "UTF-8");

    System.out.println("filename: " + filename );

    //第二部分 2、獲取文件的內容
    //重新定位文件指針到文件頭
    randomFile.seek(0);
    long startPosition = 0L;//正文開始的位置
    int i = 1;
    while( ( n = randomFile.readByte() ) != -1 && i <=4 ) {
        if( n == ‘\n‘) {
            startPosition = randomFile.getFilePointer();
            i++;
        }
    }
    //
    startPosition = randomFile.getFilePointer() - 1 ;

    //獲取文件內容,結束位置
    randomFile.seek(randomFile.length() );//指針定位到尾部
    long endPosition = randomFile.getFilePointer();
    int j = 1;
    while( endPosition >= 0 && j <=2 ) {
        endPosition--;
        randomFile.seek(endPosition);
        if(randomFile.readByte() == ‘\n‘ ) {
            j++;
        }
    }

    endPosition = endPosition - 1;

    //第二部分 3、保存文件
    //設置保存上傳文件的路徑,我們好保存到temp中
    String realPath = request.getServletContext().getRealPath("/") + "temp";
    File fileupload = new File( realPath );

    File saveFile = new File(realPath,filename);
    RandomAccessFile randomAccessFile = new RandomAccessFile(saveFile,"rw");
    //
    //從臨時文件當中讀取文件內容(根據起止位置獲取)
    randomFile.seek(startPosition);
    while(startPosition < endPosition ) {
        randomAccessFile.write(randomFile.readByte());
        startPosition = randomFile.getFilePointer();
    }
    //
    //關閉輸入輸出流、刪除臨時文件
    randomAccessFile.close();
    randomFile.close();
    //tempFile.delete();

    }
}

我們來看一下效果
技術分享圖片
這樣的話,我們的上傳圖片也已經上傳成功了,我們來把上傳圖片的url反回給前端吧,這些代碼就不再展示,自己實現一下吧。

如何用input標簽上傳多個圖片並回顯
圖片上傳並回顯Ajax異步篇

圖片上傳並回顯後端篇