SpringBoot+Vue+ElementUI實現頭像上傳功能

從安裝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.filelet 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文檔貼出的方法即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章