当前位置: 首页 > article >正文

springboot集成七牛云上传文件

大体思路

上传

前端上传MultipartFile file 文件

进行名字空值校验和格式校验,大概就是判断后缀是不是属于jpg.png

生成唯一uuid名称,然后拿着这个文件名和图片文件File调接口

接口参数为

  • 输入流inputstream,将file化流传输
  • 文件名
  • 上传token,由access,secretKey,bucket生成,还可以指定过期时间,其他额外配置,该配置我们单独搞一个配置类注册bean后续注入即可

完事之后拼接url,https(fileAccess)+www.zzz.cn/47.11.11.1(domain)+文件名path丢给前端展示

这里上传失败还可以进行重重

删除

传文件名,bucket,调接口

代码如下

依赖

  <!--        七牛云依赖-->
        <dependency>
            <groupId>com.qiniu</groupId>
            <artifactId>qiniu-java-sdk</artifactId>
            <version>7.2.28</version>
        </dependency>

application.yml格式

# ========================== ↓↓↓↓↓↓ 七牛云配置 ↓↓↓↓↓↓ ==========================
qiniu:
  accessKey: xxxx
  secretKey: xxxx
  # 对象储存
  bucket: xxx # 空间名称
  zone: huanan # 存储区域
  domain: cdn.988.cn # 访问域名
  fileAccess: https://  没有ssl认证就http://

具体实现

service

package com.zww.service;

import com.qiniu.common.QiniuException;
import org.springframework.web.multipart.MultipartFile;

/**
 * @author pangpi
 */
public interface FileService {

    /**
     * 上传图片到OOS
     * @param img 上传的图片文件
     * @return 返回图片的链接路径
     */
    String uploadImg(MultipartFile img);

    String deleteImg(String key) throws QiniuException;
  
}

serviceImpl

package com.zww.service.impl;

import cn.hutool.core.util.ObjUtil;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.UploadManager;
import com.qiniu.util.Auth;
import com.zww.common.exception.ServiceException;
import com.zww.framework.enums.AppHttpCodeEnum;
import com.zww.framework.enums.FileTypeEnum;
import com.zww.service.FileService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author pangpi
 */
@Slf4j
@Service
public class FileServiceImpl implements FileService {


    // @Autowired
    // private ApplicationContext applicationContext;
    @Value("${qiniu.fileUploadType}")
    private String fileUploadType;
    @Value("${qiniu.accessKey}")
    private String accessKey;

    @Value("${qiniu.secretKey}")
    private String secretKey;

    @Value("${qiniu.bucket}")
    private String bucket;

    @Value("${qiniu.domain}")
    private String domain;

    @Value("${qiniu.fileAccess}")
    private String fileAccess;

    // akey和skey在里面定义好了
    @Autowired
    private Auth auth;
    // 地区configuration在里面通过读取application.yml初始化好了
    @Autowired
    private UploadManager uploadManager;
    @Autowired
    private BucketManager bucketManager;



    // 这个方法就是在加工唯一文件名和校验用户上传的是否是图片格式后缀例如jpg,png
    @Override
    public String uploadImg(MultipartFile img) {
        // 判断文件类型,和文件大小
        // 获取原始文件名
        String originalFilename = img.getOriginalFilename();
        if (originalFilename == null) {
            throw new ServiceException("文件名不能为空");
            // throw new ServiceException(AppHttpCodeEnum.FILL_NAME_NOT_NULL.getMsg());
        }
        // 获取文件后缀
        String fileSuffix = getFileSuffix(originalFilename);
        // 判断后缀是否匹配img
        // if (checkImageSuffix(fileSuffix, FileTypeEnum.IMG.getFileType())) {
        if (checkImageSuffix(fileSuffix, "image")) {
            // throw new ServiceException(AppHttpCodeEnum.FILE_TYPE_ERROR.getMsg());
            throw new ServiceException("上传类型格式不为图片jpg,png...");
        }

        // 通过文件获取生成的文件路径
        // 根据日期生成路径   2022-1-15-
        // new一个日期格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-");
        // 通过格式器转换一个时间
        String datePath = sdf.format(new Date());
        // uuid作为文件名
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        // 后缀和文件后缀一致
        int index = originalFilename.lastIndexOf(".");
        // test.jpg -> .jpg
        String fileType = originalFilename.substring(index);
        String filePath = datePath + uuid + fileType;
        // 就是从test.jpg变成了2024-9-1-uuid32142343.jpg
        String url = uploadOss(img, filePath);
        return  url;
    }



    // 传入文件名然后调接口
    @Override
    public String deleteImg(String key) throws QiniuException {
        // 由于bucketManager注入了spring,且初始化了a,skey,和地区,所以可以直接传bucket调用
        // 如果有重传需求则三次重传
        Response response = bucketManager.delete(this.bucket, key);
        int retry = 0;
        while (response.needRetry() && retry++ < 3) {
            response = bucketManager.delete(this.bucket, key);
        }
        return response.statusCode == 200 ? "删除成功!" : "删除失败!";
    }

    /**
     * @param file     文件
     * @param filePath 文件路径
     * @return 文件访问url
     */
    // 如果你有别的oos,那么这里会动态获取bean并且上传
    // OosUploadService oosUploadService = applicationContext.getBean(fileUploadType + "_oos", OosUploadService.class);
    // if (ObjUtil.isNotEmpty(oosUploadService)) {
    //     return oosUploadService.uploadOss(file, filePath);
    // } else {
    //     log.error("对象存储 {} 不存在,请联系管理员",fileUploadType);
    //     throw new ServiceException(AppHttpCodeEnum.SYSTEM_ERROR.getMsg());
    // }
    // 这里直接使用qiniu_oss了,上传成功后返回字符串
    private String uploadOss(MultipartFile file, String filePath) {
        // 这里的getUploadToken()是获取上传凭证,由
        // Access Key: 访问密钥
        // Secret Key: 秘密密钥 和 存储空间名 bucket所生成
        // 同时还设置了令牌过期时间sxpire
        // 这两个密钥用于身份验证和权限控制,确保只有授权的用户可以访问或操作资源
        // 获取文件输入流
        try {
            // 将文件转为输入流,后面流给七牛云
            InputStream inputStream = file.getInputStream();
            try {
                //上传ing...
                Response response = this.uploadManager.put(inputStream, filePath, getUploadToken(), null, null);
                // 如果上一步执行没问题则说明上传完毕,此时给链接前端展示即可
                int retry = 0;
                // 如果有重传需求则三次重传
                while (response.needRetry() && retry < 3) {
                    response = this.uploadManager.put(inputStream, filePath, getUploadToken(), null, null);
                    retry++;
                }
                if (response.statusCode == 200) {
                    return fileAccess + domain + "/" + filePath;
                }
                return "上传失败";
            } catch (QiniuException e) {
                // 如果上传失败,捕获QiniuException并打印错误信息。
                System.err.println(e.response.toString());
                throw new RuntimeException(e);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取上传凭证
     */
    private String getUploadToken() {
        return this.auth.uploadToken(bucket, null, 3600, null);
    }

    /**
     * 输入文件名,获取文件的后缀
     *
     * @param fileName 文件名
     * @return 文件后缀
     */
    private String getFileSuffix(String fileName) {
        // 拆分文件和后缀
        String[] split = fileName.split("\\.");
        if (split.length <= 1) {
            throw new ServiceException(AppHttpCodeEnum.FILL_NAME_NOT_SUFFIX.getMsg());
        }
        return split[split.length - 1];
    }

    /**
     * 根据传入的后缀和文件类型,判断其后缀是否正常
     *
     * @param imgSuffix 文件类型
     * @return 是否满足后缀要求
     */
    private boolean checkImageSuffix(String imgSuffix, String fileType) {
        // 暂时使用set进行判断,后续有需要改为数据库动态存储不同文件类型下的文件后缀
        Map<String, Set<String>> fileTypeSuffixMap = new HashMap<>();
        // 每个文件类型存储多个后缀格式用set存放,最后放入map
        Set<String> imageSuffixName = new HashSet<>();
        imageSuffixName.add("jpg");
        imageSuffixName.add("jpeg");
        imageSuffixName.add("jpe");
        imageSuffixName.add("png");
        imageSuffixName.add("svg");
        imageSuffixName.add("webp");
        fileTypeSuffixMap.put(FileTypeEnum.IMG.getFileType(), imageSuffixName);

        Set<String> excelSuffixName = new HashSet<>();
        excelSuffixName.add("xlsx");
        excelSuffixName.add("xls");
        fileTypeSuffixMap.put(FileTypeEnum.EXCEL.getFileType(), excelSuffixName);

        Set<String> htmlSuffixName = new HashSet<>();
        htmlSuffixName.add("html");
        fileTypeSuffixMap.put(FileTypeEnum.HTML.getFileType(), htmlSuffixName);

        Set<String> mp3SuffixName = new HashSet<>();
        mp3SuffixName.add("mp3");
        fileTypeSuffixMap.put(FileTypeEnum.MP3.getFileType(), mp3SuffixName);

        Set<String> lrcSuffixName = new HashSet<>();
        lrcSuffixName.add("lrc");
        fileTypeSuffixMap.put(FileTypeEnum.LRC.getFileType(), lrcSuffixName);

        if (ObjUtil.isEmpty(fileTypeSuffixMap.get(fileType))) {
            log.error("没有这样一个类型: {} 存放在类型map中", fileType);
            return true;
        }
        return !(fileTypeSuffixMap.get(fileType).contains(imgSuffix));
    }

}

初始化配置类

package com.zww.framework.config;

import com.google.gson.Gson;
import com.qiniu.common.Zone;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.UploadManager;
import com.qiniu.util.Auth;
import com.zww.common.exception.GlobalException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class QiniuConfig {

    @Value("${qiniu.accessKey}")
    private String accessKey;

    @Value("${qiniu.secretKey}")
    private String secretKey;

    @Value("${qiniu.zone}")
    private String zone;

    /**
     * 配置空间的存储区域
     */
    @Bean
    public com.qiniu.storage.Configuration qiNiuConfig() {
        switch (zone) {
            case "huadong":
                return new com.qiniu.storage.Configuration(Zone.huadong());
            case "huabei":
                return new com.qiniu.storage.Configuration(Zone.huabei());
            case "huanan":
                return new com.qiniu.storage.Configuration(Zone.huanan());
            case "beimei":
                return new com.qiniu.storage.Configuration(Zone.beimei());
            default:
                throw new GlobalException("存储区域配置错误");
        }
    }

    /**
     * 构建一个七牛上传工具实例
     */
    @Bean
    public UploadManager uploadManager() {
        return new UploadManager(qiNiuConfig());
    }

    /**
     * 认证信息实例
     */
    @Bean
    public Auth auth() {
        return Auth.create(accessKey, secretKey);
    }

    /**
     * 构建七牛空间管理实例
     */
    @Bean
    public BucketManager bucketManager() {
        return new BucketManager(auth(), qiNiuConfig());
    }

    @Bean
    public Gson gson() {
        return new Gson();
    }

}

测试代码

将本地图片File 对象转为multipartFile 然后调用方法

package com.zww;

import com.qiniu.common.QiniuException;
import com.zww.service.FileService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

@RunWith(SpringRunner.class)
@SpringBootTest
public class QiniuTest {

    @Autowired
    private FileService fileService;
    public static MultipartFile convert(File file) throws IOException {
        InputStream inputStream = new FileInputStream(file);
        return new MockMultipartFile("file", file.getName(), "image/jpeg", inputStream);
    }

    @Test
    public void testUpload() throws IOException {
        File file = new File("电脑图片链接xxxxx");
        MultipartFile multipartFile = convert(file);
        String result = fileService.uploadImg(multipartFile);
        System.out.println("访问地址: " + result);
    }

    @Test
    public void testDelete() throws QiniuException {
        String result = fileService.deleteImg("helloworld");
        System.out.println(result);
    }

}
使用File作为参数,不过得

image-20240831171250604

控制台输出

image-20240831171305444

当然你也可以上传其他文件类型例如视频,文本,压缩包,这里不过多赘述,原理大差不差,前端传好参数,后端参数好好填入就行,配置文件别写错


http://www.kler.cn/a/290655.html

相关文章:

  • Spring框架之适配器模式 (Adapter Pattern)
  • Oracle OCP认证考试考点详解082系列16
  • 【考研数学:高数2】数列极限
  • C 语言标准库 - <errno.h>
  • C++20 概念与约束(1)—— SFINAE
  • echarts-gl 3D柱状图配置
  • Python画笔案例-030 实现打点之斜正方
  • MATLAB 中的对数计算
  • torch、torchvision、torchtext版本兼容问题
  • ubuntu 22.04安装NVIDIA驱动和CUDA
  • 传统CV算法——基于 SIFT 特征点检测与匹配实现全景图像拼接
  • Java实现根据某个字段对集合进行去重并手动选择被保留的对象
  • vuex 基础使用
  • 网页版修改本地数据器:重新布局,引入 highlight.js高亮显示代码
  • 鸿蒙Next-拉起支付宝的三种方式——教程
  • 【Linux】理解Linux中的软链接与硬链接
  • 传统CV算法——背景建模算法介绍
  • 架构基础 -- 打点系统之FastAPI、python、grafana、prometheus实现
  • Unity数据持久化 之 文件操作(增删查改)
  • 【赵渝强老师】大数据生态圈中的组件
  • 8 自研rgbd相机基于rk3566之sensor图像解析与AWB算法原理
  • SQL语言的规则和规范
  • 盘点成都产业园前十,寻找你的理想创业地!
  • Pencils Protocol生态新进展,即将上线 Vault 产品
  • Python的list和numpy的array有什么区别?
  • 2024自动化测试面试真题(附答案)!