一、介绍

七牛云对象存储 Kodo 是七牛云提供的高可靠、强安全、低成本、可扩展的存储服务。您可通过控制台、API、SDK 等方式简单快速地接入七牛存储服务,实现海量数据的存储和管理。通过 Kodo 可以进行文件的上传、下载和管理。

七牛云对象存储提供高可用和高可靠的对象存储服务,您可以放心的将各种内容存储在云端。利用七牛云对象存储的扩展性和按需付费的优势,可以满足您持续快速增长的存储需求。您也可以搭配使用七牛云的对象存储和融合 CDN服务,实现全球覆盖、快速高效的内容分发。

二、实现步骤

1、准备工作

首先到七牛云注册并登录账号,这里就不介绍注册登录步骤了,注册登录完后进入管理控制台首页,在七牛云官方产品中添加对象存储,如下图

a、弹出侧边添加按钮,我们按要求填写存储空间名称,如:linfen-test,

b、看你自己区域进行选择存储区域,如:华东,

c、再接着选择公开或私有访问,公开对文件访问可以直接:空间域名加存储文件名就可以直接访问下载,私有的话再访问文件时需要携带token和有效时间戳进行访问才能下载文件

创建好bucket存储空间后我们去获取密钥,点击头像去个人中心>选择密钥管理,复制AK和SK这两个密钥后面要用到

2.后端进行项目整合

2.1添加项目依赖

<dependency>
  <groupId>com.qiniu</groupId>
  <artifactId>qiniu-java-sdk</artifactId>
  <version>7.2.28</version>
</dependency>

2.2配置application.yml文件

#七牛云配置
qiniu:
  accessKey: 0CQcXKb0Mjti_WrxZfsdGgmkdngsdYyfffka1dGq
  secretKey: fWGdsfkaoDGspGeeSGvEgVR9JYDFdsjiadddxx9V
  bucketName: linfen-test
  fileDomain: q7omvujlt.bkt.clouddn.com  #文件访问域名前缀(可配置自己的域名)

文件访问前缀,可以到空间管理>空间概览>CDN 测试域名的最下面就是默认配置的域名

2.3创建上传工具类QiniuUtil.java

import com.google.gson.Gson;
import com.qiniu.common.QiniuException;
import com.qiniu.common.Zone;
import com.qiniu.http.Client;
import com.qiniu.http.Response;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;

/**
 * 七牛云工具类
 *@author linfen
 * @since 2020-04-8
 */
@Component
public class QiniuUtil {
    @Value("${qiniu.accessKey}")
    private String accessKey ;
    @Value("${qiniu.secretKey}")
    private String secretKey ;
    @Value("${qiniu.bucketName}")
    private String bucketName ;
    @Value("${qiniu.fileDomain}")
    private String fileDomain;

    public String getAccessKey() {
        return accessKey;
    }

    public String getSecretKey() {
        return secretKey;
    }

    public String getBucketName() {
        return bucketName;
    }

    public String getFileDomain() {
        return fileDomain;
    }

    private UploadManager uploadManager;
    private BucketManager bucketManager;
    private Configuration c;
    private Client client;
    // 密钥配置
    private Auth auth;

    public Client getClient(){
        if (client==null) {
            client=new Client(getConfiguration());
        }
        return client;
    }

    public BucketManager getBucketManager() {
        if (bucketManager == null) {
            bucketManager = new BucketManager(getAuth(), getConfiguration());
        }
        return bucketManager;
    }

    public UploadManager getUploadManager() {
        if (uploadManager == null) {
            uploadManager = new UploadManager(getConfiguration());
        }
        return uploadManager;
    }

    public Configuration getConfiguration() {
        if (c == null) {
            Zone z = Zone.autoZone();
            c = new Configuration(z);
        }
        return c;
    }

    public Auth getAuth() {
        if (auth == null) {
            auth = Auth.create(getAccessKey(), getSecretKey());
        }
        return auth;
    }
    //简单上传模式的凭证
    public String getUpToken() {
        return getAuth().uploadToken(getBucketName());
    }
    //覆盖上传模式的凭证
    public String getUpToken(String fileKey) {
        return getAuth().uploadToken(getBucketName(), fileKey);
    }

    /**
     * 将本地文件上传
     * @param filePath 本地文件路径
     * @param fileKey 上传到七牛后保存的文件路径名称
     * @return
     * @throws IOException
     */
    public DefaultPutRet upload(String filePath, String fileKey) throws IOException {
        Response res  = getUploadManager().put(filePath, fileKey, getUpToken(fileKey));
            // 解析上传成功的结果
            DefaultPutRet putRet = new Gson().fromJson(res.bodyString(), DefaultPutRet.class);
            return putRet;
    }

    /**
     * 上传二进制数据
     * @param data
     * @param fileKey
     * @return
     * @throws IOException
     */
    public DefaultPutRet upload(byte[] data, String fileKey) throws IOException {
        Response res = getUploadManager().put(data, fileKey, getUpToken(fileKey));
            // 解析上传成功的结果
            DefaultPutRet putRet = new Gson().fromJson(res.bodyString(), DefaultPutRet.class);
            return  putRet;
    }

    /**
     * 上传输入流
     * @param inputStream
     * @param fileKey
     * @return
     * @throws IOException
     */
    public DefaultPutRet upload(InputStream inputStream, String fileKey) throws IOException {
        Response res = getUploadManager().put(inputStream, fileKey, getUpToken(fileKey),null,null);
            // 解析上传成功的结果
            DefaultPutRet putRet = new Gson().fromJson(res.bodyString(), DefaultPutRet.class);
            return putRet ;

    }

    /**
     * 删除文件
     * @param fileKey
     * @return
     * @throws QiniuException
     */
    public boolean delete(String fileKey) throws QiniuException {
        Response response = bucketManager.delete(this.getBucketName(), fileKey);
        return response.statusCode == 200 ? true:false;
    }

    /**
     * 获取公共空间文件
     * @param fileKey
     * @return
     */
    public String getFile(String fileKey) throws Exception{
        String encodedFileName = URLEncoder.encode(fileKey, "utf-8").replace("+", "%20");
        String url = String.format("%s/%s", fileDomain, encodedFileName);
        return url;
    }

    /**
     * 获取私有空间文件
     * @param fileKey
     * @return
     */
    public String getPrivateFile(String fileKey) throws Exception{
        String encodedFileName = URLEncoder.encode(fileKey, "utf-8").replace("+", "%20");
        String publicUrl = String.format("%s/%s", fileDomain, encodedFileName);
        Auth auth = Auth.create(accessKey, secretKey);
        long expireInSeconds = 3600;//1小时,可以自定义链接过期时间
        String finalUrl = auth.privateDownloadUrl(publicUrl, expireInSeconds);
        return finalUrl;
    }

}

2.4创建控制类QiNiuController.java

import cn.hutool.core.date.DateUtil;
import cn.linfenw.log.annotation.SysOperaLog;
import cn.linfenw.modules.sys.util.QiniuUtil;
import com.alibaba.fastjson.JSON;
import com.qiniu.storage.model.DefaultPutRet;
import cn.linfenw.common.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;


/**
 * 七牛云工具类
 * @author linfen
 * @since 2020-04-8
 */
@Slf4j
@RestController
@RequestMapping("/qiniu")
public class QiNiuController {

    @Autowired
    private QiniuUtil qiniuUtil;

    /**
     * 七牛云文件上传
     *
     * @param file 文件
     * @return
     */
    @RequestMapping("/upload")
    @ResponseBody
    public R upload(MultipartFile[] file) {
        if (file.length <= 0) {
            return R.error("上传文件不能为空");
        }
        if (file[0].isEmpty()) {
            return R.error("上传文件不能为空");
        }
        try {
            BufferedInputStream fileInputStream = (BufferedInputStream) file[0].getInputStream();
            String originalFilename = file[0].getOriginalFilename();
            String fileExtend = originalFilename.substring(originalFilename.lastIndexOf("."));
            String yyyyMMddHHmmss = DateUtil.format(new Date(), "yyyyMMddHHmmss");
            //默认不指定key的情况下,以文件内容的hash值作为文件名
            String fileKey = UUID.randomUUID().toString().replace("-", "") + "-" + yyyyMMddHHmmss + fileExtend;
            Map<String, Object> map = new HashMap<>();
            DefaultPutRet uploadInfo = qiniuUtil.upload(fileInputStream, fileKey);
            map.put("fileName", uploadInfo.key);
            map.put("originName", originalFilename);
            map.put("size", file[0].getSize());
            //七牛云文件私有下载地址(看自己七牛云公开还是私有配置)
            map.put("url", "/linfen/qiniu/private/file/" + uploadInfo.key);
//            map.put("url", "/linfen/qiniu/file/" + uploadInfo.key);//七牛云公开下载地址
            log.info("文件:" + JSON.toJSONString(map));
            return R.ok(map);
        } catch (Exception e) {
            e.printStackTrace();
            return R.error("上传失败");
        }
    }

    /**
     * 七牛云私有文件下载
     *
     * @param filename 文件名
     * @return
     */
    @RequestMapping("/private/file/{filename}")
    public void privateDownload(@PathVariable("filename") String filename, HttpServletResponse response) {
        if (filename.isEmpty()) {
            return;
        }

        try {
            String privateFile = qiniuUtil.getPrivateFile(filename);
            log.info("文件下载地址:" + privateFile);
            response.sendRedirect(privateFile);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 七牛云文件下载
     *
     * @param filename 文件名
     * @return
     */
    @RequestMapping("/file/{filename}")
    public void download(@PathVariable("filename") String filename, HttpServletResponse response) {
        if (filename.isEmpty()) {
            return;
        }

        try {
            String privateFile = qiniuUtil.getFile(filename);
            log.info("文件下载地址:" + privateFile);
            response.sendRedirect(privateFile);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 七牛云删除文件
     *
     * @param filename 文件名
     * @return
     */
    @SysOperaLog(descrption = "删除七牛云文件")
    @PreAuthorize("hasAuthority('sys:qiniu:delete')")
    @RequestMapping("/delete/file/{filename}")
    public R deleteFile(@PathVariable("filename") String filename, HttpServletResponse response) {
        if (filename.isEmpty()) {
            return R.error("未知文件");
        }

        try {
            boolean result = qiniuUtil.delete(filename);
            if (result)
                return R.ok("文件删除成功");
            else
                return R.error("文件删除失败");
        } catch (Exception e) {
            e.printStackTrace();
            return R.error("文件删除失败");
        }
    }
}

 

3.Vue实现代码实现qiniuOss.vue

项目添加element的上传组件,前后端分离的项目需要携带token信息可以再headers中添加要携带的信息,代码如下

<template>
  <div class="app-container">
    <el-form
      ref="dataForm"
      :model="dataForm"
    >
      <el-form-item label="上传文件" prop="title" :label-width="formLabelWidth">
        <el-upload
          drag
          action="/linfen/qiniu/upload"
          :before-upload="handleUploadPreview"
          :on-success="handleUploadSuccess"
          :on-error="handleUploadError"
          :limit="1"
          :headers="uploadHeaders"
          multiple>
          <i class="el-icon-upload"></i>
          <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
          <div class="el-upload__tip" slot="tip">文件不得超过25M</div>
        </el-upload>
      </el-form-item>

      <el-form-item label="原文件名" prop="originName" :label-width="formLabelWidth">
        <el-input  :disabled="true" v-model="dataForm.originName" placeholder="请输入原文件名"/>
      </el-form-item>

      <el-form-item label="大小" prop="fileSize" :label-width="formLabelWidth">
        <el-input  :disabled="true" v-model="dataForm.fileSize" placeholder="请输入文件大小" />
      </el-form-item>

      <el-form-item label="下载地址" prop="url" :label-width="formLabelWidth">
        <el-input :disabled="true" v-model="dataForm.url" placeholder="请输入下载地址" />
        <el-link :underline="false" type="primary" :href="dataForm.url">下载</el-link>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
  import { getToken } from '@/utils/auth'

  export default {
    data() {
      return {
        formLabelWidth: '120px',
        uploadHeaders:{},
        dataForm: {
          fileSize: '',
          type: '',
          downloads: '',
        },
      }
    },
    created() {
      this.uploadHeaders={//设置授权的Token
        'Authorization': 'Bearer ' + getToken(),
      }
    },
    methods: {
      clipboardSuccess() {
        this.$message({
          message: '复制成功',
          type: 'success',
          duration: 1500
        })
      },
      handleUploadPreview(file) {//文件上传进行大小判断
        console.log(file);
        const isLt2M = file.size / 1024 / 1024 < 25;
        if (!isLt2M) {
          this.$message.error('上传文件大小不能超过 25MB!');
        }
        return isLt2M;
      },
      handleUploadSuccess(res, file) {//处理成功后的设置
        if (res.code === 200) {
          this.$message.success('上传成功')
          this.dataForm.url = res.data.url
          this.dataForm.fileSize = res.data.size
          this.dataForm.originName = res.data.originName
          console.log(JSON.stringify(this.dataForm))

        } else {
          this.$message.success(res.msg)
        }
      },
      handleUploadError(err, file) {
        this.$message.error("失败" + err)
      },

    }
  }
</script>

三、运行效果

最终运行效果如下:

Logo

前往低代码交流专区

更多推荐