首頁 > 軟體

Axios+Spring Boot實現檔案上傳和下載

2022-08-15 10:02:23

本文範例為大家分享了Axios+Spring Boot實現檔案上傳和下載的具體程式碼,供大家參考,具體內容如下

1.所用技術

前端:Vue + Axios

後端:Springboot + SpringMVC

2.單檔案上傳

後端程式碼

只需要使用MultipartFile類配合RequestBody註解即可

@PostMapping("your/path")
public ResultData courseCoverUpload(@RequestBody MultipartFile file){
    /**
    your service
    */
}

前端程式碼

Axios上傳需要設定頭部,使用FormData封裝檔案物件

//file為檔案物件
function upload(file){
    //請求頭設定
    const header={"Content-type":"multipart/form-data"}
    let formData=new FormData();
    //用file作為key沒問題,其他沒試過
    formData.append("file",file);
       //這裡request封裝過,也可以直接使用axios.post()
    request.post(`path`,formData,{headers:header}).then(res=>{
        //your serivce
    })
}

如若使用element-ui的upload元件,可以選擇自定義上傳方法(好處是可以再請求頭中加入token)

<el-upload
      class="upload-demo"
      :auto-upload="false"
      action
      :http-request="uploadFile"
      ref="upload"
      >
          <el-button type="text">點選上傳</el-button>
</el-upload>

上述uploadFile正是上傳時的回撥函數,使用方法如下

function uploadFile(param){
    //param中的file才是真正的檔案體,用於傳入axios上傳方法的引數
    upload( param.file )
},

3.檔案上傳的同時傳輸Json資料

後端程式碼

將@RequestBody換成==@RequestPart==註解,並再註解中加入接收時的識別key即可同時接受檔案和其他Json引數

@PostMapping("up")
public ResultData uploadTest(
    @RequestPart("file") MultipartFile file, 
    @RequestPart("other") Map<String,String> props
    ){
    return ResultData.success().data("file_size",file.getSize()).data("others",props);
}

前端程式碼

function  uploadFile(file_body,other_json){

    //頭資訊不變
    const header={"Content-type":"multipart/form-data"}
    //依舊用FormData作資料封裝
    let form_data=new FormData();
    //此處的key要與後端統一,這裡都使用file
    form_data.append("file",file_body)
    //再封裝其他引數時需要使用Blob,[]不要錯,type一定要加
    form_data.append( "other",new Blob([JSON.stringify(other_json)],{type:"application/json"}))
    //這裡request封裝過,也可以直接使用axios.post()
    request.post(url,form_data,{headers: header}).then(rs=>{
      console.log(rs);
    })
}

4.檔案下載

使用axios下載檔案最噁心之處就在於前後端請求頭還有解析格式要匹配,否則就會出現跨域或者檔案流出錯等問題。

後端程式碼

和返回json資料不同,返回檔案流需要使用HttpServletResponse類的輸出流將檔案流逐一列印出去,這裡選擇用過濾器處理請求,也可以使用Controller

編寫接收前端請求的過濾器

public class FileFilter implements Filter , InputOutputUtil {
    @Override
    public void doFilter(ServletRequest servletRequest,
                         ServletResponse servletResponse,
                         FilterChain filterChain) throws IOException, ServletException {
        /** 本次後端預設前端使用Get請求進行下載,如若get需要傳遞引數可以用getParameter方式獲取
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            System.out.println(request.getParameter("a"));
        */
        //獲取檔案輸出流,這裡是讀取原生的
        File  f= new File("file_path");
        InputStream inpurStream = new FileInputStream(file);
        /** 如果檔案資源在其他伺服器上(比如阿里雲的OSS),可以用以下程式碼獲取檔案流
        URLConnection urlConn = new URL("URL_PATH").openConnection();
        urlConn.connect();
        InputStream inputStream = urlConn.getInputStream();
        */
        
        //輸出方法,放在了自己編寫的InputOutputUtil中
        this.writeFile(servletResponse,"security_key.jpg",inputStream);
    }
}

輔助輸出的介面

public interface InputOutputUtil {
    //輸出檔案時用
    default void writeFile(ServletResponse servletResponse,
                           String fileName,InputStream inputStream) throws IOException {
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        //設定返回的頭資訊
        response.setContentType("application/octet-stream");
        response.setCharacterEncoding("UTF-8");
        response.addHeader("Content-disposition", "attachment;filename=""+fileName+""");
        
        //跨域處理
        response.setHeader("Access-Control-Expose-Headers","Content-Disposition");
        response.setHeader("Access-Control-Allow-Origin","*");
        response.setHeader("Access-Control-Allow-Methods","GET,POST,PUT,DELETE");
        response.setHeader("Access-Control-Allow-Headers","*");
        response.setHeader("Access-Control-Max-Age","false");
        response.setHeader("Access-Control-Allow-Credentials","10");
        
        //獲取輸出流
        ServletOutputStream outputStream=response.getOutputStream();
        //將檔案流逐一放入輸出流中列印給前端
        byte[] bs1=new byte[1024];
        int length;
        while((length=inputStream.read(bs1))!=-1){
            outputStream.write(bs1,0,length);
        }
        //關流操作
        outputStream.close();
        inputStream.close();
    }
}

前端程式碼

使用axios的get方法發起請求

function downloadFile(url,param=null){
    //設定頭資訊
    let config = {responseType:'blob'}
    //如若前端有引數就加入一下
    if (param!=null) config["params"]=param
    //帶著頭資訊和請求引數發起請求
    request.get(url,config).then(res=>{
        //如若成功了,開始拆箱
        //獲取filename,這裡使用的是正規表示式,關聯 輔助輸出介面 的第9行
        let file_name=res.headers["content-disposition"].match(/filename="(S*)"/)[1]
        //data中裝的是檔案體,需要使用Blob流可以下載
        let blob = new Blob([res.data])
        
        //網上最常用的下載方法
        let downloadElement = document.createElement('a')
        let href = window.URL.createObjectURL(blob); //建立下載的連結
        downloadElement.href = href;
        downloadElement.download = file_name; //下載後檔名
        document.body.appendChild(downloadElement);
        downloadElement.click(); //點選下載
        document.body.removeChild(downloadElement); //下載完成移除元素
        window.URL.revokeObjectURL(href); //釋放blob物件
    })
}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com