怎麼實現檔案的上傳下載功能?以下這篇文章為大家介紹一下基於gitee實作檔案上傳和下載功能的方法,希望對大家有幫助!
檔案的上傳和下載是我們這個專案的核心功能,也是整合優化了一下先前的boot專案來實現這個功能。
對於文件的上傳和下載一般是使用阿里雲OSS、華為雲OSS這些,很好用而且官方提供了圖形界面,但是這些方式都需要按量儲存收費並且和gitee相似都是去呼叫官方介面實作功能,因為我正在學習階段,所以選擇了在gitee搭建了一個倉庫,利用官方的api向倉庫發起文件的上傳、刪除功能,並且利用資料庫儲存的文件地址實現將文件下載到瀏覽器客戶端。
資料庫的表暫時只用了兩張來實現基本功能,一個是文件表,一個是資料夾表
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; //分享次数 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新建一個倉庫,填入名稱,勾選初始化倉庫,建立好之後設定為開源
倉庫創建好之後打開「個人主頁」—>「個人設定」---->「私人令牌」為自己產生一個新的私人令牌用於呼叫官方介面時的認證。
生成時不用管選項直接生成,注意儲存自己的令牌,因為只會展示一次。
這裡用的別人寫好的直接copy就行,注意裡面的私人令牌、個人空間、倉庫名稱、默認儲存位址要改成自己的,這個工具類別也就是利用這些資訊透過HttpUtil工具類別向gitee倉庫發起上傳請求。
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 =>仓库所属空间地址(企业、组织或个人的地址path) (owner) * %s => 仓库路径(repo) * %s => 文件的路径(path) */ private static final String API_CREATE_POST = "https://gitee.com/api/v5/repos/%s/%s/contents/%s"; /** * 生成创建(获取、删除)的指定文件路径 * @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; } /** * 获取创建文件的请求体map集合:access_token、message、content * @param multipartFile 文件字节数组 * @return 封装成map的请求体集合 */ private static Map<string> getUploadBodyMap(byte[] multipartFile){ HashMap<string> bodyMap = new HashMap(3); bodyMap.put("access_token", GiteeImgBedUtil.ACCESS_TOKEN); bodyMap.put("message", "add file!"); bodyMap.put("content", Base64.encode(multipartFile)); return bodyMap; } /** * 创建普通携带请求体集合内容 * @param map 额外参数 * @param message 请求信息 * @return */ private static Map<string> getCommonBodyMap(HashMap map, String message){ HashMap<string> bodyMap = new HashMap(2); bodyMap.put("access_token", GiteeImgBedUtil.ACCESS_TOKEN); bodyMap.put("message", message); if (map != null){ bodyMap.putAll(map); } return bodyMap; } /** * **********封装好的实际调用方法******************* */ //超时 private static int TIMEOUT = 10 * 1000; /** * 上传文件 * @param filename 文件名称 * @param path 路径 * @param sha 必备参数from 获取仓库具体路径下的内容 * @return */ public static String uploadFile(String path, String originalFilename, byte[] data){ String targetURL = GiteeImgBedUtil.createUploadFileUrl(originalFilename,path); //请求体封装 Map<string> uploadBodyMap = GiteeImgBedUtil.getUploadBodyMap(data); return HttpUtil.post(targetURL, uploadBodyMap); } /** * 删除指定path路径下的文件 * @param filename 文件名称 * @param path 路径 * @param sha 必备参数from 获取仓库具体路径下的内容 * @return */ public static String deleteFile(String path,String sha){ String delFileUrl = createDelFileUrl(path); HashMap<string> needMap = new HashMap(1); needMap.put("sha",sha);//添加sha参数 return HttpUtil.createRequest(Method.DELETE, delFileUrl) .form(getCommonBodyMap(needMap,"del file!")) //构建请求表单 .timeout(TIMEOUT) .execute().body(); } /** * 获取仓库具体路径下的内容,主要是获取 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(); } }</string></string></string></string></string></string>
檔案上傳的過程為前端傳入檔案物件和相關資訊然後我們向gitee發起請求將檔案傳送到倉庫,上傳成功之後在將回傳的下載地址和相關資訊存入資料庫當中。
這裡我們先來寫一個中間工具類別來發起請求和拿到結果,這個程式碼也寫在服務當中的話會顯得程式碼太長太複雜所以我單獨拿出來寫。
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()请求已来临..."); //根据文件名生成指定的请求url String originalFilename = multipartFile.getOriginalFilename(); if (originalFilename == null) { log.info("服务器接收文件失败!"); } //Gitee请求:发送上传文件请求 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("上传文件失败!"); } //请求成功:返回下载地址 JSONObject content = JSONUtil.parseObj(jsonObj.getObj(GiteeConstant.RESULT_BODY_CONTENT)); log.info("上传成功,下载地址为:" + content.getStr(GiteeConstant.RESULT_BODY_DOWNLOAD_URL)); return content; } }
controller拿到文件和資訊後調用中間工具類上傳文件,然後從請求頭中拿到用戶id,從返回對象拿到文件資訊存入File類別當中然後使用mybatisplus將物件存入資料庫就行。
@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)); } }</string>
service比較簡單,設定一個儲存時間呼叫mapper存入就行
/** * 上传文件 * * @param file 用于向数据库储存的文件对象 */ @Override public void fileUpload(File file) { file.setCreateTime(new Date()); fileMapper.insert(file); }
我們隨便上傳一個檔案
查看gitee和資料庫是否有對應結果
這裡id為2是因為之前刪除了一條數據,想要從頭開始截斷表就行。
檔案下載最初比較困擾我,有兩種方式,第一種是直接將檔案物件寫入到使用者提供的本機資料夾位址,第二種是將檔案下載到瀏覽器。最後選擇了第二種方式,因為使用者不用設定下載位址而且在瀏覽器下載可以看到下載過程,整個流程是利用下載位址將檔案轉換為檔案流寫入位元組數組,在利用瀏覽器透過下載的方式寫出位元組數組到輸出流。
使用檔案id先從資料庫查到對應位址然後利用位址完成後續作業。
/** * 文件下载接口 * @param fileId 文件id * @param response http响应对象 * @return 下载结果 */ @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(); // 从文件流读取字节到字节数组中 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")); // 注意,这里要设置文件名的编码,否则中文的文件名下载后不显示 // 写出字节数组到输出流 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); } }</string>
這裡需要一個寫一個取得檔案名稱的工具類,不然下載之後瀏覽器不知道檔案類型
/** * 获取url中的文件名(取到最后一个/后面的就是文件名) * @param url 文件地址 * @return */ public static String getFileName(String url) { if(!url.equals("")){ return url.substring(url.lastIndexOf("/")+1); } else return "文件地址错误"; }
发送请求完成下载
/** * 删除文件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请求:发送删除请求 String JSONResult = GiteeImgBedUtil.deleteFile(path, sha); jsonObj = JSONUtil.parseObj(JSONResult); if (jsonObj.getObj(GiteeConstant.RESULT_BODY_COMMIT) == null) { log.info("删除文件失败!"); } log.info("文件路径为:" + path + " 删除成功!"); }
获取文件地址并删除数据库数据
/** * 删除文件 * @param fileId 文件id * @return */ @Override public String delFile(Long fileId) { String url = fileMapper.selectById(fileId).getFilePath(); fileMapper.deleteById(fileId); return url; }
** * 删除文件接口 * @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); } }</string>
发送请求删除文件
查看数据库和gitee仓库
自此完成了文件的上传和下载功能,大家有需要的可以参考。
(学习视频分享:编程基础视频)
以上是怎麼基於gitee實作上傳下載檔案的功能的詳細內容。更多資訊請關注PHP中文網其他相關文章!