溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

基于gitee如何實現(xiàn)上傳下載文件的功能

發(fā)布時間:2023-03-25 09:13:06 來源:億速云 閱讀:152 作者:iii 欄目:軟件技術

本文小編為大家詳細介紹“基于gitee如何實現(xiàn)上傳下載文件的功能”,內(nèi)容詳細,步驟清晰,細節(jié)處理妥當,希望這篇“基于gitee如何實現(xiàn)上傳下載文件的功能”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。

方案的選擇

文件的上傳和下載是我們這個項目的核心功能,也是整合優(yōu)化了一下以前的boot項目來實現(xiàn)這個功能。

對于文件的上傳和下載一般是使用阿里云OSS、華為云OSS這些,很好用而且官方提供了圖形界面,但是這些方式都需要按量儲存收費并且和gitee相似都是去調(diào)用官方接口實現(xiàn)功能,因為我是在學習階段,所以選擇了在gitee搭建了一個倉庫,利用官方的api向倉庫發(fā)起文件的上傳、刪除功能,并且利用數(shù)據(jù)庫儲存的文件地址實現(xiàn)將文件下載到瀏覽器客戶端。

數(shù)據(jù)庫表的設計

數(shù)據(jù)庫的表暫時只用了兩張來實現(xiàn)基本功能,一個是文件表,一個是文件夾表

public class File {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String fileName;
    private String filePath;
    private String fileSize;

    @TableField(fill = FieldFill.INSERT)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date createTime;

    private Long userId;
    private Long folderId;
    //分享次數(shù)
    private Integer shareTimes;
    //文件描述
    private String fileCover;
}
public class Folder {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String folderName;
    private Long fatherId;  //父文件夾id,為0表示沒有最上層文件夾
    private Long userId;
    private String folderCover;
    private Boolean folderPermissions;
    @TableField(fill = FieldFill.INSERT)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date createTime;
}

搭建gitee倉庫

首先打開自己的gitee新建一個倉庫,填寫名稱,勾選初始化倉庫,創(chuàng)建好之后設置為開源

基于gitee如何實現(xiàn)上傳下載文件的功能

倉庫創(chuàng)建好之后打開“個人主頁”—>“個人設置”---->“私人令牌”為自己生成一個新的私人令牌用于調(diào)用官方接口時的認證。

基于gitee如何實現(xiàn)上傳下載文件的功能

生成時不用管選項直接生成,注意保存自己的令牌,因為只會展示一次。

gitee圖床工具類的編寫

這里用的別人寫好的直接copy就行,注意里面的私人令牌、個人空間、倉庫名、默認存儲地址要改成自己的,這個工具類也就是利用這些信息通過HttpUtil工具類向gitee倉庫發(fā)起上傳請求。

package com.ityz.file.util;

import cn.hutool.core.codec.Base64;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @ClassName UploadGiteeImgBedUtil
 * @Author ityz
 * @Date 2022/11/23 16:38
 * @Description Gitee圖床工具類
 */
public class GiteeImgBedUtil {


    /**
     * 碼云私人令牌
     */
    private static final String ACCESS_TOKEN = "0616f0e894e3c264bac45591e34a43bc";  //這里不展示我自己的了,需要你自己補充


    /**
     * 碼云個人空間名
     */
    private static final String OWNER = "procedure-yuan-yanzu";


    /**
     * 上傳指定倉庫
     */
    private static final String REPO = "files";


    /**
     * 默認上傳時指定存放圖片路徑
     */
    public static final String PATH = "files/";

    //API
    /**
     * 新建(POST)、獲取(GET)、刪除(DELETE)文件:()中指的是使用對應的請求方式
     * %s =>倉庫所屬空間地址(企業(yè)、組織或個人的地址path)  (owner)
     * %s => 倉庫路徑(repo)
     * %s => 文件的路徑(path)
     */
    private static final String API_CREATE_POST = "https://gitee.com/api/v5/repos/%s/%s/contents/%s";


    /**
     * 生成創(chuàng)建(獲取、刪除)的指定文件路徑
     * @param originalFilename 原文件名
     * @param path 存儲文件路徑
     * @return
     */
    private static String createUploadFileUrl(String originalFilename,String path){
        String targetPath = path == null ? GiteeImgBedUtil.PATH : path;
        //獲取文件后綴
        String suffix = FileUtil.getFileSuffix(originalFilename);
        //拼接存儲的圖片名稱
        String fileName = System.currentTimeMillis()+"_"+ UUID.randomUUID().toString()+suffix;
        //填充請求路徑
        String url = String.format(GiteeImgBedUtil.API_CREATE_POST,
                GiteeImgBedUtil.OWNER,
                GiteeImgBedUtil.REPO,
                targetPath + fileName);
        return url;
    }

    private static String createDelFileUrl(String path){
        //填充請求路徑
        String url = String.format(GiteeImgBedUtil.API_CREATE_POST,
                GiteeImgBedUtil.OWNER,
                GiteeImgBedUtil.REPO,
                path);
        return url;
    }

    private static String createGetUrl(String path){
        String targetPath = path == null ? GiteeImgBedUtil.PATH : path;
        //填充請求路徑
        String url = String.format(GiteeImgBedUtil.API_CREATE_POST,
                GiteeImgBedUtil.OWNER,
                GiteeImgBedUtil.REPO,
                targetPath);
        return url;
    }

    /**
     * 獲取創(chuàng)建文件的請求體map集合:access_token、message、content
     * @param multipartFile 文件字節(jié)數(shù)組
     * @return 封裝成map的請求體集合
     */
    private static Map<String,Object> getUploadBodyMap(byte[] multipartFile){
        HashMap<String, Object> bodyMap = new HashMap<>(3);
        bodyMap.put("access_token", GiteeImgBedUtil.ACCESS_TOKEN);
        bodyMap.put("message", "add file!");
        bodyMap.put("content", Base64.encode(multipartFile));
        return bodyMap;
    }

    /**
     * 創(chuàng)建普通攜帶請求體集合內(nèi)容
     * @param map 額外參數(shù)
     * @param message 請求信息
     * @return
     */
    private static Map<String,Object> getCommonBodyMap(HashMap map, String message){
        HashMap<String, Object> bodyMap = new HashMap<>(2);
        bodyMap.put("access_token", GiteeImgBedUtil.ACCESS_TOKEN);
        bodyMap.put("message", message);
        if (map != null){
            bodyMap.putAll(map);
        }
        return bodyMap;
    }

    /**
     * **********封裝好的實際調(diào)用方法*******************
     */

    //超時
    private static int TIMEOUT = 10 * 1000;

    /**
     * 上傳文件
     * @param filename 文件名稱
     * @param path 路徑
     * @param sha 必備參數(shù)from 獲取倉庫具體路徑下的內(nèi)容
     * @return
     */
    public static String uploadFile(String path, String originalFilename, byte[] data){
        String targetURL = GiteeImgBedUtil.createUploadFileUrl(originalFilename,path);
        //請求體封裝
        Map<String, Object> uploadBodyMap = GiteeImgBedUtil.getUploadBodyMap(data);
        return HttpUtil.post(targetURL, uploadBodyMap);
    }


    /**
     * 刪除指定path路徑下的文件
     * @param filename 文件名稱
     * @param path 路徑
     * @param sha 必備參數(shù)from 獲取倉庫具體路徑下的內(nèi)容
     * @return
     */
    public static String deleteFile(String path,String sha){
        String delFileUrl = createDelFileUrl(path);
        HashMap<String, Object> needMap = new HashMap<>(1);
        needMap.put("sha",sha);//添加sha參數(shù)
        return HttpUtil.createRequest(Method.DELETE, delFileUrl)
                .form(getCommonBodyMap(needMap,"del file!"))  //構(gòu)建請求表單
                .timeout(TIMEOUT)
                .execute().body();
    }

    /**
     * 獲取倉庫具體路徑下的內(nèi)容,主要是獲取 sha
     * @param path
     * @return
     */
    public static String getSha(String path){
        String getShaUrl = createDelFileUrl(path);
        return HttpUtil.createRequest(Method.GET, getShaUrl)
                .form(getCommonBodyMap(null, "get sha!"))
                .timeout(TIMEOUT)
                .execute().body();
    }

}

文件上傳接口

文件上傳的過程為前端傳入文件對象和相關信息然后我們向gitee發(fā)起請求將文件傳到倉庫,上傳成功之后在將返回的下載地址和相關信息存入數(shù)據(jù)庫當中。

中間工具類

這里我們先來編寫一個中間工具類來發(fā)起請求和拿到結(jié)果,這個代碼也寫在服務當中的話會顯得代碼太長太復雜所以我單獨拿出來寫。

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.ityz.common.constants.GiteeConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;

/**
 * gitee文件操作api
 */
@Slf4j
public class GiteeApi {
    /**
     * 上傳文件api
     * @param multipartFile 前端傳入的文件對象
     * @param folder 文件所存文件夾名稱
     * @return gitee的api上傳返回值的json對象
     * @throws IOException
     */
    public static JSONObject upload(MultipartFile multipartFile,String folder) throws IOException {
        log.info("uploadFile()請求已來臨...");
        //根據(jù)文件名生成指定的請求url
        String originalFilename = multipartFile.getOriginalFilename();
        if (originalFilename == null) {
            log.info("服務器接收文件失敗!");
        }
        //Gitee請求:發(fā)送上傳文件請求
        String JSONResult = GiteeImgBedUtil.uploadFile(folder, originalFilename, multipartFile.getBytes());
        //解析響應JSON字符串
        //上傳txt文件時會出問題,沒解決
        JSONObject jsonObj = JSONUtil.parseObj(JSONResult);
        //請求失敗
        if (jsonObj.getObj(GiteeConstant.RESULT_BODY_COMMIT) == null) {
            log.info("上傳文件失?。?quot;);
        }
        //請求成功:返回下載地址
        JSONObject content = JSONUtil.parseObj(jsonObj.getObj(GiteeConstant.RESULT_BODY_CONTENT));
        log.info("上傳成功,下載地址為:" + content.getStr(GiteeConstant.RESULT_BODY_DOWNLOAD_URL));
        return content;
    }
}

Controller

controller拿到文件和信息后調(diào)用中間工具類上傳文件,然后從請求頭中拿到用戶id,從返回對象中拿到文件信息存入File類當中然后使用mybatisplus將對象存入數(shù)據(jù)庫就行。

@RestController
@Slf4j
@RequestMapping("/file")
public class FileController {
    @Autowired
    private FileService fileService;
    @Autowired
    private HttpServletRequest request;

    /**
     * 文件上傳接口
     * @param multipartFile 上傳的文件對象
     * @param fileCover 文件的描述信息
     * @param folderId 文件所屬的文件夾id
     * @return 用戶文件地址
     * @throws IOException
     */
    @PostMapping("/upload")
    public Result<String> uploadFile(@RequestParam("file") MultipartFile multipartFile
            , @RequestParam("fileCover") String fileCover
            , @RequestParam("folderId") Long folderId) throws IOException {
        JSONObject content = GiteeApi.upload(multipartFile, "test/");
        //獲取userId
        Long userId = Long.valueOf(TokenUtil.parseToken(request.getHeader("token")));
        File file = new File();
        file.setFileCover(fileCover);
        file.setUserId(userId);
        file.setFolderId(folderId);
        file.setFileName(content.getStr(GiteeConstant.RESULT_BODY_NAME));;
        file.setFileSize(content.getStr(GiteeConstant.RESULT_BODY_SIZE));
        file.setFilePath(content.getStr(GiteeConstant.RESULT_BODY_DOWNLOAD_URL));
        fileService.fileUpload(file);
        return new Result<>(ResultCode.SUCCESS,ResultCode.UP_FILE_SUCCESS,content.getStr(GiteeConstant.RESULT_BODY_DOWNLOAD_URL));
    }
}

service比較簡單,設置一個儲存時間調(diào)用mapper存入就行

/**
     * 上傳文件
     *
     * @param file 用于向數(shù)據(jù)庫儲存的文件對象
     */
    @Override
    public void fileUpload(File file) {
        file.setCreateTime(new Date());
        fileMapper.insert(file);
    }

接口測試

我們隨便上傳一個文件

基于gitee如何實現(xiàn)上傳下載文件的功能

查看gitee和數(shù)據(jù)庫是否有相應結(jié)果

基于gitee如何實現(xiàn)上傳下載文件的功能

這里id為2是因為之前刪除了一條數(shù)據(jù),想要從頭開始截斷表就行。

文件下載接口

文件下載最初比較困擾我,有兩種方式,第一種是直接將文件對象寫入到用戶提供的本地文件夾地址,第二種是將文件下載到瀏覽器。最終選擇了第二種方式,因為用戶不用設置下載地址而且在瀏覽器下載可以看到下載過程,整個流程是利用下載地址將文件轉(zhuǎn)換為文件流寫入字節(jié)數(shù)組,在利用瀏覽器通過下載的方式寫出字節(jié)數(shù)組到輸出流。

controller

使用文件id先從數(shù)據(jù)庫查到相應地址然后利用地址完成后續(xù)操作。

/**
     * 文件下載接口
     * @param fileId 文件id
     * @param response http響應對象
     * @return 下載結(jié)果
     */
    @GetMapping("/download")
    public Result<String> download(Long fileId,HttpServletResponse response) {
        try {
            String downloadUrl = fileService.downloadFile(fileId);
            URL url = new URL(downloadUrl);
            URLConnection conn = url.openConnection();
            InputStream bis = conn.getInputStream();
            byte[] bytes = new byte[bis.available()];
            OutputStream os = response.getOutputStream();
            // 從文件流讀取字節(jié)到字節(jié)數(shù)組中
            while (bis.read(bytes) != -1) {
                // 重置 response
                response.reset();
                // 設置 response 的下載響應頭
                response.setContentType("application/x-download");
                response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(FileUtil.getFileName(downloadUrl), "UTF-8"));  // 注意,這里要設置文件名的編碼,否則中文的文件名下載后不顯示
                // 寫出字節(jié)數(shù)組到輸出流
                os.write(bytes);
                // 刷新輸出流
                os.flush();
            }
            return new Result<>(ResultCode.SUCCESS,ResultCode.DOWN_FILE_SUCCESS);
        }catch (Exception e){
            e.printStackTrace();
            return new Result<>(ResultCode.FAIL,ResultCode.DOWN_FILE_FAIL);
        }
    }

這里需要一個編寫獲取文件名的工具類,不然下載之后瀏覽器不知道文件類型

/**
     * 獲取url中的文件名(取到最后一個/后面的就是文件名)
     * @param url 文件地址
     * @return
     */
    public static String getFileName(String url) {
        if(!url.equals("")){
        return url.substring(url.lastIndexOf("/")+1);
        }
        else return "文件地址錯誤";
    }

接口測試

發(fā)送請求完成下載

基于gitee如何實現(xiàn)上傳下載文件的功能

文件刪除接口

中間工具類

/**
     * 刪除文件api
     * @param url 文件地址
     */
    public static void del(String url){
        if (!url.equals("") && !url.contains("master/")) {
            log.info("url:" + url + " 無法解析路徑!");
        }
        String path = url.substring(url.indexOf("master/") + 7);
        log.info("解析取得待刪除路徑:" + path);
        String shaResult = GiteeImgBedUtil.getSha(path);
        JSONObject jsonObj = JSONUtil.parseObj(shaResult);
        String sha = jsonObj.getStr(GiteeConstant.RESULT_BODY_SHA);
        //3、Gitee請求:發(fā)送刪除請求
        String JSONResult = GiteeImgBedUtil.deleteFile(path, sha);
        jsonObj = JSONUtil.parseObj(JSONResult);
        if (jsonObj.getObj(GiteeConstant.RESULT_BODY_COMMIT) == null) {
            log.info("刪除文件失?。?quot;);
        }
        log.info("文件路徑為:" + path + " 刪除成功!");
    }

service

獲取文件地址并刪除數(shù)據(jù)庫數(shù)據(jù)

/**
     * 刪除文件
     * @param fileId 文件id
     * @return
     */
    @Override
    public String delFile(Long fileId) {
        String url = fileMapper.selectById(fileId).getFilePath();
        fileMapper.deleteById(fileId);
        return url;
    }

controller

**
     * 刪除文件接口
     * @param fileId 前端傳入的文件id
     * @return
     */
    @GetMapping("/del")
    public Result<String> delFile(Long fileId) {
        try {
            String url = fileService.delFile(fileId);
            GiteeApi.del(url);
            return new Result<>(ResultCode.SUCCESS,ResultCode.DEL_FILE_SUCCESS);
        }
        catch (Exception e){
            e.printStackTrace();
            return new Result<>(ResultCode.FAIL,ResultCode.DEL_FILE_FAIL);
        }
    }

接口測試

發(fā)送請求刪除文件

基于gitee如何實現(xiàn)上傳下載文件的功能

查看數(shù)據(jù)庫和gitee倉庫

基于gitee如何實現(xiàn)上傳下載文件的功能

讀到這里,這篇“基于gitee如何實現(xiàn)上傳下載文件的功能”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內(nèi)容的文章,歡迎關注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI