SpringBoot文件上傳控制及Java 獲取和判斷文件頭信息
之前在使用SpringBoot進(jìn)行文件上傳時(shí),遇到了很多問題。于是在翻閱了很多的博文之后,總算將上傳功能進(jìn)行了相應(yīng)的完善,便在這里記錄下來,供自己以后查閱。
首先,是建立一個(gè)標(biāo)準(zhǔn)的SpringBoot 的工程,這里使用的IDE是Intellij Idea,為了方便配置,將默認(rèn)的配置文件替換為了application.yml。

1.在index.html中進(jìn)行文件上傳功能,這里使用的文件上傳方式是ajax,當(dāng)然也可以按照自己的具體要求使用傳統(tǒng)的表單文件上傳。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>上傳測(cè)試</title>
<script type="text/javascript" src="js/jquery-3.2.1.min.js"></script>
</head>
<body>
<input id="file" type="file" name="file"/>
<br/>
<button id="upload" onclick="doUpload()">上傳</button>
<progress id="progressBar" value="0" max="100"></progress>
<script>
function doUpload() {
var fileObj = document.getElementById("file").files[0]; // js 獲取文件對(duì)象
var FileController = "/upload"; // 接收上傳文件的后臺(tái)地址
// FormData 對(duì)象
var form = new FormData();
form.append("file",fileObj);
// XMLHttpRequest 對(duì)象
var xhr = new XMLHttpRequest();
//為請(qǐng)求添加返回處理函數(shù)
xhr.onreadystatechange=function () {
if(this.readyState == 4 && this.status == 200){
var b = this.responseText;
if(b == "success"){
alert("上傳成功!");
}else{
alert("上傳失??!");
}
}
};
xhr.open("post", FileController, true);
//使用進(jìn)度條記錄上傳進(jìn)度
xhr.upload.addEventListener("progress", progressFunction, false);
xhr.send(form);
}
function progressFunction(evt) {
var progressBar = document.getElementById("progressBar");
var percentageDiv = document.getElementById("percentage");
if (evt.lengthComputable) {
progressBar.max = evt.total;
progressBar.value = evt.loaded;
percentageDiv.innerHTML = Math.round(evt.loaded / evt.total * 100) + "%";
}
}
</script>
</body>
</html>
2.在MainController添加文件上傳的API,并返回上傳結(jié)果
@PostMapping("/upload")
@ResponseBody
public String upload(HttpServletRequest request, @RequestParam("file") MultipartFile file) {
String path = "E://upload//";
String fileName = file.getOriginalFilename();
System.out.println(fileName);
File targetFile = new File(path);
if (!targetFile.exists()) {
targetFile.mkdirs();
}
File saveFile=new File(path+fileName);
// 保存
try {
file.transferTo(saveFile);
return "success";
} catch (Exception e) {
e.printStackTrace();
return "fail";
}
}
這時(shí),我們進(jìn)行測(cè)試,就可以發(fā)現(xiàn),文件上傳已經(jīng)完成了。


很多時(shí)候,我們?cè)谶M(jìn)行文件上傳時(shí),特別是向普通用戶開放文件上傳功能時(shí),需要對(duì)上傳文件的格式進(jìn)行控制,以防止黑客將病毒腳本上傳。單純的將文件名的類型進(jìn)行截取的方式非常容易遭到破解,上傳者只需要將病毒改換文件名便可以完成上傳。
這時(shí)候我們可以讀取文件的十六進(jìn)制的文件頭,來判斷文件真正的格式。
因?yàn)槲覀儼l(fā)現(xiàn),在我們讀取文件的二進(jìn)制數(shù)據(jù)并將其轉(zhuǎn)換為十六進(jìn)制時(shí),同類型文件的文件頭數(shù)據(jù)是相同的,即使改變了其后綴,這個(gè)數(shù)據(jù)也不會(huì)改變,例如,png文件的文件頭為“89504E47”。
首先,我們將文件的數(shù)據(jù)進(jìn)行讀取
public class FileUtil {
public static String getFileHeader( MultipartFile file) {
InputStream is = null;
String value = null;
try {
is = file.getInputStream();
byte[] b = new byte[4];
is.read(b, 0, b.length);
value = bytesToHexString(b);
} catch (Exception e) {
} finally {
if (null != is) {
try {
is.close();
} catch (IOException e) {
}
}
}
return value;
}
private static String bytesToHexString(byte[] src) {
StringBuilder builder = new StringBuilder();
if (src == null || src.length <= 0) {
return null;
}
String hv;
for (int i = 0; i < src.length; i++) {
hv = Integer.toHexString(src[i] & 0xFF).toUpperCase();
if (hv.length() < 2) {
builder.append(0);
}
builder.append(hv);
}
System.out.println(builder.toString());
return builder.toString();
}
}
然后在文件上傳的api中進(jìn)行調(diào)用
FileUtil.getFileHeader(file)
這時(shí)候,我們只需要進(jìn)行簡(jiǎn)單的字符串比對(duì),判斷調(diào)用的返回值是否為“89504E47”,就可以知道上傳的是否為png文件。
下面看下 Java 獲取和判斷文件頭信息
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
/**
* 獲取和判斷文件頭信息
*
* @author Sud
*
*/
public class GetTypeByHead {
// 緩存文件頭信息-文件頭信息
public static final HashMap<String, String> mFileTypes = new HashMap<String, String>();
static {
// images
mFileTypes.put("FFD8FF", "jpg");
mFileTypes.put("89504E47", "png");
mFileTypes.put("47494638", "gif");
mFileTypes.put("49492A00", "tif");
mFileTypes.put("424D", "bmp");
//
mFileTypes.put("41433130", "dwg"); // CAD
mFileTypes.put("38425053", "psd");
mFileTypes.put("7B5C727466", "rtf"); // 日記本
mFileTypes.put("3C3F786D6C", "xml");
mFileTypes.put("68746D6C3E", "html");
mFileTypes.put("44656C69766572792D646174653A", "eml"); // 郵件
mFileTypes.put("D0CF11E0", "doc");
mFileTypes.put("5374616E64617264204A", "mdb");
mFileTypes.put("252150532D41646F6265", "ps");
mFileTypes.put("255044462D312E", "pdf");
mFileTypes.put("504B0304", "docx");
mFileTypes.put("52617221", "rar");
mFileTypes.put("57415645", "wav");
mFileTypes.put("41564920", "avi");
mFileTypes.put("2E524D46", "rm");
mFileTypes.put("000001BA", "mpg");
mFileTypes.put("000001B3", "mpg");
mFileTypes.put("6D6F6F76", "mov");
mFileTypes.put("3026B2758E66CF11", "asf");
mFileTypes.put("4D546864", "mid");
mFileTypes.put("1F8B08", "gz");
mFileTypes.put("4D5A9000", "exe/dll");
mFileTypes.put("75736167", "txt");
}
/**
* 根據(jù)文件路徑獲取文件頭信息
*
* @param filePath
* 文件路徑
* @return 文件頭信息
*/
public static String getFileType(String filePath) {
System.out.println(getFileHeader(filePath));
System.out.println(mFileTypes.get(getFileHeader(filePath)));
return mFileTypes.get(getFileHeader(filePath));
}
/**
* 根據(jù)文件路徑獲取文件頭信息
*
* @param filePath
* 文件路徑
* @return 文件頭信息
*/
public static String getFileHeader(String filePath) {
FileInputStream is = null;
String value = null;
try {
is = new FileInputStream(filePath);
byte[] b = new byte[4];
/*
* int read() 從此輸入流中讀取一個(gè)數(shù)據(jù)字節(jié)。 int read(byte[] b) 從此輸入流中將最多 b.length
* 個(gè)字節(jié)的數(shù)據(jù)讀入一個(gè) byte 數(shù)組中。 int read(byte[] b, int off, int len)
* 從此輸入流中將最多 len 個(gè)字節(jié)的數(shù)據(jù)讀入一個(gè) byte 數(shù)組中。
*/
is.read(b, 0, b.length);
value = bytesToHexString(b);
} catch (Exception e) {
} finally {
if (null != is) {
try {
is.close();
} catch (IOException e) {
}
}
}
return value;
}
/**
* 將要讀取文件頭信息的文件的byte數(shù)組轉(zhuǎn)換成string類型表示
*
* @param src
* 要讀取文件頭信息的文件的byte數(shù)組
* @return 文件頭信息
*/
private static String bytesToHexString(byte[] src) {
StringBuilder builder = new StringBuilder();
if (src == null || src.length <= 0) {
return null;
}
String hv;
for (int i = 0; i < src.length; i++) {
// 以十六進(jìn)制(基數(shù) 16)無符號(hào)整數(shù)形式返回一個(gè)整數(shù)參數(shù)的字符串表示形式,并轉(zhuǎn)換為大寫
hv = Integer.toHexString(src[i] & 0xFF).toUpperCase();
if (hv.length() < 2) {
builder.append(0);
}
builder.append(hv);
}
System.out.println(builder.toString());
return builder.toString();
}
public static void main(String[] args) throws Exception {
final String fileType = getFileType("D:\\Ry4S_JAVA.dll");
System.out.println(fileType);
}
}
總結(jié)
以上所述是小編給大家介紹的SpringBoot文件上傳控制及Java 獲取和判斷文件頭信息,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
- 解決springboot MultipartFile文件上傳遇到的問題
- 詳解SpringBoot文件上傳下載和多文件上傳(圖文)
- SpringBoot+Vue.js實(shí)現(xiàn)前后端分離的文件上傳功能
- springboot實(shí)現(xiàn)文件上傳和下載功能
- 詳解SpringBoot下文件上傳與下載的實(shí)現(xiàn)
- springboot 文件上傳大小配置的方法
- SpringBoot+layui實(shí)現(xiàn)文件上傳功能
- springboot實(shí)現(xiàn)單文件和多文件上傳
- SpringBoot實(shí)現(xiàn)文件上傳下載功能小結(jié)
- SpringBoot實(shí)現(xiàn)簡(jiǎn)單文件上傳功能
相關(guān)文章
Java壓縮解壓zip技術(shù)_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
Java解壓縮zip - 多個(gè)文件(包括文件夾),對(duì)多個(gè)文件和文件夾進(jìn)行壓縮,對(duì)復(fù)雜的文件目錄進(jìn)行解壓。壓縮方法使用的是可變參數(shù),可以壓縮1到多個(gè)文件2017-05-05
java面試突擊之sleep和wait有什么區(qū)別詳析
按理來說sleep和wait本身就是八竿子打不著的兩個(gè)東西,但是在實(shí)際使用中大家都喜歡拿他們來做比較,或許是因?yàn)樗鼈兌伎梢宰尵€程處于阻塞狀態(tài),這篇文章主要給大家介紹了關(guān)于java面試突擊之sleep和wait有什么區(qū)別的相關(guān)資料,需要的朋友可以參考下2022-02-02
logback-spring.xml的內(nèi)容格式詳解
這篇文章主要介紹了logback-spring.xml的內(nèi)容格式詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的的朋友參考下吧2023-11-11
Spring5新特性之Reactive響應(yīng)式編程
這篇文章主要介紹了Spring5新特性之Reactive響應(yīng)式編程,響應(yīng)式編程是一種編程范式,通用和專注于數(shù)據(jù)流和變化的,并且是異步的,下文更多詳細(xì)內(nèi)容,需要的小伙伴可以參考一下,希望對(duì)你有所幫助2022-03-03
spring boot 即時(shí)重新啟動(dòng)(熱更替)使用說明
這篇文章主要介紹了spring boot 即時(shí)重新啟動(dòng)(熱更替)的相關(guān)資料,需要的朋友可以參考下2017-12-12
SpringBoot 實(shí)現(xiàn)定時(shí)任務(wù)的方法詳解
這篇文章主要介紹了SpringBoot 實(shí)現(xiàn)定時(shí)任務(wù)的方法詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08
Java調(diào)用微信客服消息實(shí)現(xiàn)發(fā)貨通知的方法詳解
這篇文章主要介紹了Java調(diào)用微信客服消息實(shí)現(xiàn)發(fā)貨通知的方法,結(jié)合實(shí)例形式詳細(xì)分析了java針對(duì)微信接口調(diào)用的原理、調(diào)用方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-08-08

