圖片上傳並回顯後端篇
圖片上傳並回顯後端篇
我們先看一下效果
繼上一篇的圖片上傳和回顯,我們來實戰一下圖片上傳的整個過程,今天我們將打通前後端,我們來真實的了解一下,我們上傳的文件,是以什麽樣的形式上傳到服務器,難道也是一張圖片?等下我們來揭曉
我們在實戰開始前呢,我們先做一下準備工作,比如新建一個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異步篇
圖片上傳並回顯後端篇