從安裝FastDFS開始,斷斷續續折騰了兩天多,終於基本粗糙地實現了這個功能。
遇到了許多bug,記錄一下。
後端:
Controller:
(1)這裏要加上 @CrossOrigin解決跨域問題
(2)我的參數的註解是@RequestParam,而不是@RequestBody,這會導致接下來前端使用axios進行POST請求時,參數傳不到後臺的情況。這個問題在前端解決。
(3)我的設想是前端將圖片文件轉換成base64編碼的字符串,再和圖片名稱一起傳給後臺
(4)我在本地的/home/kimi目錄下新建了image文件夾
@CrossOrigin
@RequestMapping(value = "/uploadbase", method = RequestMethod.POST)
public String uploadBase64(@RequestParam String base64, @RequestParam String filename) throws Exception {
String filePath = "/home/kimi/image/";
FileUtils.base64ToFile(filePath,base64);
MultipartFile multipartFile = FileUtils.fileToMultipart(filePath,filename);
String url = fastDFSClientWrapper.uploadFile(multipartFile);
return url;
}
FileUtils的base64ToFile方法:
public static boolean base64ToFile(String filePath, String base64Data) throws Exception {
String dataPrix = "";
String data = "";
if(base64Data == null || "".equals(base64Data)){
return false;
}else{
String [] d = base64Data.split("base64,");
if(d != null && d.length == 2){
dataPrix = d[0];
data = d[1];
}else{
return false;
}
}
// 因爲BASE64Decoder的jar問題,此處使用spring框架提供的工具包
byte[] bs = Base64Utils.decodeFromString(data);
// 使用apache提供的工具類操作流
org.apache.commons.io.FileUtils.writeByteArrayToFile(new File(filePath), bs);
return true;
}
FileUtils的fileToMultipart方法:
(1)一開始的代碼是File file = new File(filePath);
,調用這個方法時總是給我報“沒有這個文件夾或目錄”/ “XXX是一個文件夾”這樣的錯誤,然後我改成了File file = new File(filePath,filename); file.createNewFile();
,希望可以在filePath下新建名爲filename的文件,這2個參數都是從前端傳進來的。
(2)MultipartFile的構造代碼一開始是MultipartFile multipartFile = new MockMultipartFile(file.getName(), "png", "image/png", inputStream);
,第二個參數本應該是original name,這裏直接寫成了png,contentType也被簡單粗暴地寫成了image/png,這樣導致後來我在調用multipartFile.getOriginalFilename()
方法時,得到的永遠是png,而在調用FilenameUtils.getExtension(multipartFile.getOriginalFilename())
得到的永遠是NULL。於是我改成了MultipartFile multipartFile = new MockMultipartFile(file.getName(), file.getName(), "image/png", inputStream);
。contentType我還沒有詳細瞭解其用法,因此沒有改動。
public static MultipartFile fileToMultipart(String filePath,String filename) {
try {
// File轉換成MutipartFile
File file = new File(filePath,filename);
file.createNewFile();
// if(!file.exists()){
// file.mkdir();
// }
FileInputStream inputStream = new FileInputStream(file);
MultipartFile multipartFile = new MockMultipartFile(file.getName(), file.getName(), "image/png", inputStream);
return multipartFile;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
FastDFSClientWrapper的uploadFile方法:
(1)storePath即是存儲在FastDFS服務器中的位置
public String uploadFile(MultipartFile multipartFile)throws IOException{
StorePath storePath = fastFileStorageClient.uploadFile((InputStream)multipartFile.getInputStream(),multipartFile.getSize(), FilenameUtils.getExtension(multipartFile.getOriginalFilename()),null);
return getResAccessUrl(storePath);
}
前端:
我使用了ElementUI的upload組件,但是我需要返回給後端的是base64字符串,因此我選擇使用http-request來自定義上傳行爲。
(1)在el-upload
節點裏寫上:http-request="httpRequest"
(2)JS代碼:
1)傳入httpRequest的options裏包括頭部、action、file等信息,file裏有圖片的詳細信息,包括uid、name、lastModified、lastModifiedDate等信息。使用let file = options.file
和let filename = file.name
,file即代表圖片文件,filename代表圖片名字。
2)新建一個FileReader對象,使用它的readAsDataURL方法讀取圖像文件,使用let base64Str = this.fileReader.result
獲取讀取到的字符串,這個字符串並不是全都是base64字符串,前面還有data:image之類的一些信息,我們可以使用base64Str.split(',')[1]
,這樣得到的便是base64字符串了。
3)針對上面說過的使用axios進行POST請求時,參數傳不到後臺的問題,我採用了URLSearchParams解決這個問題。
let param = new URLSearchParams()
param.append('base64',base64Str.split(',')[1])
param.append('filename',filename)
在接下來的axios的data裏寫成:data:param
,我一開始寫成:
data:{
param,
}
這樣子後端也接收不到參數。
在這段代碼裏使用了很多Promise的知識,我對這個還不熟練,還要多多學習。
完整代碼:
import axios from 'axios';
export default {
name: "MyInfo",
data() {
return {
imageUrl: '',
fileReader:''
};
},
methods: {
httpRequest(options){
this.fileReader = new FileReader()
let file = options.file
let filename = file.name
console.log(file)
console.log(filename)
if(file){
this.fileReader.readAsDataURL(file)
}
this.fileReader.onload =()=> {
let base64Str = this.fileReader.result
let param = new URLSearchParams()
param.append('base64',base64Str.split(',')[1])
param.append('filename',filename)
let config = {
url: 'http://localhost:8080/uploadbase',
method: 'post',
data:param,
timeout:10000,
}
axios(config)
.then(res=>{
options.onSuccess(res,file)
})
.catch(err=>{
console.log("error")
options.onError(err)
})
}
},
}
}
當不需要傳base64編碼給後臺時,可以把後臺的控制器修改如下,直接用MultipartFile做接收參數即可。
@CrossOrigin
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public String upload(@RequestParam("file")MultipartFile multipartFile) throws IOException {
String fileUrl = fastDFSClientWrapper.uploadFile(multipartFile);
return fileUrl;
}
前端也無需寫http-request方法,直接使用element-ui文檔貼出的方法即可。