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

java 复制代码
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

java 复制代码
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));
    }

}

初始化配置类

java 复制代码
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 然后调用方法

java 复制代码
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作为参数,不过得

控制台输出

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

相关推荐
IT毕设实战小研7 分钟前
基于大数据的跨国外派人员适应满意度与留存影响因素可视化分析
android·java·大数据·python·django·课程设计
letisgo510 分钟前
JAVA 高级进阶10篇《消息队列实战:RocketMQ/Kafka选型与“不丢不重有序“三连解》
java·面试·kafka·消息队列·rocketmq
2401_8504811715 分钟前
UVA101
java
平头哥AI21 分钟前
Day 21 _ error 是个普通值_errors.New 与 fmt.Errorf 造出来,沿调用栈抛到 main 接住
后端·学习·golang·go
Lyyaoo.25 分钟前
【回溯】【中等】全排列
java·数据结构·算法
xixingzhe225 分钟前
spring boot对接Dify
java·spring boot·dify
数据狐(Datafox)27 分钟前
京东商品详情API接口解析(附 JSON 样例)
java·开发语言·json
写后端的胖头鱼29 分钟前
一文讲懂JVM与调优
jvm·后端·算法·架构·jvm调优
步行cgn30 分钟前
Spring Boot 指定数据来源详解
spring boot·后端·python
Wang's Blog32 分钟前
Java框架快速入门: Spring Security+OAuth2之深度定制UserDetailsService与密码无缝升级
java·开发语言·spring