咱們先看一下效果
html
繼上一篇的圖片上傳和回顯,咱們來實戰一下圖片上傳的整個過程,今天咱們將打通先後端,咱們來真實的瞭解一下,咱們上傳的文件,是以什麼樣的形式上傳到服務器,難道也是一張圖片?等下咱們來揭曉前端
咱們在實戰開始前呢,咱們先作一下準備工做,好比新建一個java web工程,若是你不懂這個的話,那我建議你先學一下Javaweb,能夠去個人公衆號找一下這方面的教程。咱們就給咱們的工程起名爲UpImg,咱們再給他建一個web包和util包,再把咱們之前前端作的圖片回顯的代碼拷到工程裏,咱們來看一下項目java
咱們發佈一下項目來看一下
web
這樣的話,咱們基本的框架就作好了,咱們今天就先用form表單來實戰一下圖片的上傳,下一期咱們就經過ajax來實現異步圖片上傳,咱們先給咱們的前端代碼加點料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屬性:後端
一、默認屬性:application/x-www-form-urlencoded,只處理表單域中的value屬性值,採用這種編碼的方式的表單會將表單域的值處理成url編碼方式tomcat
二、multipart/form-data,這種編碼方式的表單會以二進制流的方法來處理表單數據。這種編碼方式會將文件域指定文件的內容也封裝到請求參數裏服務器
三、text/plain,這種方式主要適用於直接經過表單發送郵件的方式app
接下來咱們講解一下文件上傳的思路,
一、先是表單提交
二、對數據和附件進行二進制編碼
三、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 { /* * 思路 一、從request當中獲取流信息 * 二、新建一個臨時文件,用輸出流指向這個文件 * 三、關閉流 */ public static void keepFile(HttpServletRequest request) throws IOException { // 一、從request當中獲取流信息 InputStream fileSource = request.getInputStream(); /* * 臨時文件的存儲路徑(咱們在webContent下新建一個temp文件夾,發佈項目的時候極可能由於temp爲空, * 沒在tomcat中創建一個文件夾,到時候本身在發佈的項目中添加一個便可) */ String tempFileName = request.getServletContext().getRealPath("/") + "temp/tempfile.txt"; // 二、新建一個臨時文件,用輸出流指向這個文件 // 建一個文件 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); } // 三、關閉流 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(){ /* 一、先獲取input標籤 二、給input標籤綁定change事件 三、把圖片回顯 */ // 一、先回去input標籤 var $input = $("#file"); console.log($input) // 二、給input標籤綁定change事件 $input.on("change" , function(){ console.log(this) //補充說明:由於咱們給input標籤設置multiple屬性,所以一次能夠上傳多個文件 //獲取選擇圖片的個數 var files = this.files; var length = files.length; console.log("選擇了"+length+"張圖片"); //三、回顯 $.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); }) }) //把這下面的註釋掉便可 // //四、咱們把當前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 { /* * 思路 一、從request當中獲取流信息 * 二、新建一個臨時文件,用輸出流指向這個文件 * 三、關閉流 */ public static void keepFile(HttpServletRequest request) throws IOException { // 一、從request當中獲取流信息 InputStream fileSource = request.getInputStream(); /* * 臨時文件的存儲路徑(咱們在webContent下新建一個temp文件夾,發佈項目的時候極可能由於temp爲空, * 沒在tomcat中創建一個文件夾,到時候本身在發佈的項目中添加一個便可) */ String tempFileName = request.getServletContext().getRealPath("/") + "temp/tempfile.txt"; //二、新建一個臨時文件,用輸出流指向這個文件 //建一個文件 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); } //三、關閉流 fileSource.close(); outputStream.close(); //第二部分...................................................... /** * 思路 * 一、獲取文件的名稱,並解決中文亂碼 * 二、獲取文件的內容 * 三、保存文件 */ //第二部分 一、獲取文件的名稱,並解決中文亂碼 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 ); //第二部分 二、獲取文件的內容 //從新定位文件指針到文件頭 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; //第二部分 三、保存文件 //設置保存上傳文件的路徑,咱們好保存到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反回給前端吧,這些代碼就再也不展現,本身實現一下吧。