springboot整合oss(签名生成版)

本文详细介绍了如何使用阿里云OSS服务创建存储空间,并设置跨域资源共享。通过Java SpringBoot项目,配置yaml、编写配置类和服务层代码,实现了服务端签名生成,使得前端能够直接向OSS上传文件,并在上传成功后触发回调。此外,还提供了前端上传图片的示例代码,展示了整个流程。
摘要由CSDN通过智能技术生成

Oss图片上传(签名生成版)

参考开源项目:macrozheng/mall

一、创建oss

1.OSS

阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。OSS可用于图片、音视频、日志等海量文件的存储。各种终端设备、Web网站程序、移动应用可以直接向OSS写入或读取数据。

2.OSS中的相关概念

  • Endpoint:访问域名,通过该域名可以访问OSS服务的API,进行文件上传、下载等操作。
  • Bucket:存储空间,是存储对象的容器,所有存储对象都必须隶属于某个存储空间。
  • Object:对象,对象是 OSS 存储数据的基本单元,也被称为 OSS 的文件。
  • AccessKey:访问密钥,指的是访问身份验证中用到的 AccessKeyId 和 AccessKeySecret。

3.OSS的相关设置

开通OSS服务
  • 登录阿里云官网;
  • 将鼠标移至产品标签页,单击对象存储 OSS,打开OSS 产品详情页面;
  • 在OSS产品详情页,单击立即开通。
创建存储空间
  • 点击网页右上角控制台按钮进入控制台

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传qfimg-7YhDpK09-1612705644935)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20210115140806196.png)]

  • 选择我的云产品中的对象存储OSS
    在这里插入图片描述

  • 点击左侧存储空间的加号新建存储空间

  • 新建存储空间并设置读写权限为公共读

在这里插入图片描述

跨域资源共享(CORS)的设置

由于浏览器处于安全考虑,不允许跨域资源访问,所以我们要设置OSS的跨域资源共享。

  • 选择一个存储空间,打开其权限管理

  • 点击跨越设置的设置按钮

在这里插入图片描述

  • 点击创建规则

在这里插入图片描述

  • 进行跨域规则设置

在这里插入图片描述

4.服务端签名后前端直传的相关说明

流程示例图

在这里插入图片描述

流程介绍
  1. Web前端请求应用服务器,获取上传所需参数(如OSS的accessKeyId、policy、callback等参数)
  2. 应用服务器返回相关参数
  3. Web前端直接向OSS服务发起上传文件请求
  4. 等上传完成后OSS服务会回调应用服务器的回调接口
  5. 应用服务器返回响应给OSS服务
  6. OSS服务将应用服务器回调接口的内容返回给Web前端

二、代码编写

1.新键springboot项目

2.导入依赖

<!--oss依赖-->
<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>2.5.0</version>
</dependency>
<!--Hutool工具集-->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.4.0</version>
</dependency>
<!--swagger-->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>
<!--lombok懒人插件-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

3.配置yaml

aliyun:
  oss:
    endpoint: oss-cn-shenzhen.aliyuncs.com # oss对外服务的访问域名
    accessKeyId:  # 访问身份验证中用到用户标识
    accessKeySecret:  # 用户用于加密签名字符串和oss用来验证签名字符串的密钥
    bucketName:  # oss的存储空间
    policy:
      expire: 300 # 签名有效期(S)
    maxSize: 10 # 上传文件大小(M)
    callback: http://127.0.0.1:8080/aliyun/oss/callback # 文件上传成功后的回调地址
    dir:
      prefix: mall/images/ # 上传文件夹路径前缀

4.config配置类

  • swagger配置

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import springfox.documentation.builders.PathSelectors;
    import springfox.documentation.builders.RequestHandlerSelectors;
    import springfox.documentation.spi.DocumentationType;
    import springfox.documentation.spring.web.plugins.Docket;
    import springfox.documentation.swagger2.annotations.EnableSwagger2;
    
    /**
     * Swagger API文档相关配置
     * Created by macro on 2018/4/26.
     */
    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {
    
        @Bean //配置docket以配置Swagger具体参数
        public Docket docket1() {
            return new Docket(DocumentationType.SWAGGER_2)
                    .groupName("Auth(auth)")
                    .select()// 通过.select()方法,去配置扫描接口,RequestHandlerSelectors配置如何扫描接口
                    .apis(RequestHandlerSelectors.basePackage("cn.kgc.controller"))
                    .paths(PathSelectors.any())
                    .build();
        }
    
    }
    
  • oss配置类

    import com.aliyun.oss.OSSClient;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * OSS对象存储相关配置
     * Created by macro on 2018/5/17.
     */
    @Configuration
    public class OssConfig {
        @Value("${aliyun.oss.endpoint}")
        private String ALIYUN_OSS_ENDPOINT;
        @Value("${aliyun.oss.accessKeyId}")
        private String ALIYUN_OSS_ACCESSKEYID;
        @Value("${aliyun.oss.accessKeySecret}")
        private String ALIYUN_OSS_ACCESSKEYSECRET;
        @Bean
        public OSSClient ossClient(){
            return new OSSClient(ALIYUN_OSS_ENDPOINT,ALIYUN_OSS_ACCESSKEYID,ALIYUN_OSS_ACCESSKEYSECRET);
        }
    }
    
  • 跨域配置

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
    import org.springframework.web.filter.CorsFilter;
    
    /**
     * 全局跨域配置
     * Created by macro on 2019/7/27.
     */
    @Configuration
    public class GlobalCorsConfig {
    
        /**
         * 允许跨域调用的过滤器
         */
        @Bean
        public CorsFilter corsFilter() {
            CorsConfiguration config = new CorsConfiguration();
            //允许所有域名进行跨域调用
            config.addAllowedOriginPattern("*");
            //允许跨越发送cookie
            config.setAllowCredentials(true);
            //放行全部原始头信息
            config.addAllowedHeader("*");
            //允许所有请求方法跨域调用
            config.addAllowedMethod("*");
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**", config);
            return new CorsFilter(source);
        }
    }
    

5.创建dto

  • import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    import lombok.EqualsAndHashCode;
    
    /**
     * 获取OSS上传文件授权返回结果
     * Created by macro on 2018/5/17.
     */
    @Data
    @EqualsAndHashCode(callSuper = false)
    public class OssPolicyResult {
        @ApiModelProperty("访问身份验证中用到用户标识")
        private String accessKeyId;
        @ApiModelProperty("用户表单上传的策略,经过base64编码过的字符串")
        private String policy;
        @ApiModelProperty("对policy签名后的字符串")
        private String signature;
        @ApiModelProperty("上传文件夹路径前缀")
        private String dir;
        @ApiModelProperty("oss对外服务的访问域名")
        private String host;
        @ApiModelProperty("上传成功后的回调设置")
        private String callback;
    }
    
  • import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    import lombok.EqualsAndHashCode;
    
    /**
     * oss上传文件的回调结果
     * Created by macro on 2018/5/17.
     */
    @Data
    @EqualsAndHashCode(callSuper = false)
    public class OssCallbackResult {
        @ApiModelProperty("文件名称")
        private String filename;
        @ApiModelProperty("文件大小")
        private String size;
        @ApiModelProperty("文件的mimeType")
        private String mimeType;
        @ApiModelProperty("图片文件的宽")
        private String width;
        @ApiModelProperty("图片文件的高")
        private String height;
    }
    
  • import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    import lombok.EqualsAndHashCode;
    
    /**
     * oss上传成功后的回调参数
     * Created by macro on 2018/5/17.
     */
    @Data
    @EqualsAndHashCode(callSuper = false)
    public class OssCallbackParam {
        @ApiModelProperty("请求的回调地址")
        private String callbackUrl;
        @ApiModelProperty("回调是传入request中的参数")
        private String callbackBody;
        @ApiModelProperty("回调时传入参数的格式,比如表单提交形式")
        private String callbackBodyType;
    }
    

6.service层

import cn.kgc.beans.dto.OssCallbackResult;
import cn.kgc.beans.dto.OssPolicyResult;

import javax.servlet.http.HttpServletRequest;

/**
 * Oss对象存储管理Service
 * Created by macro on 2018/5/17.
 */
public interface OssService {
    /**
     * oss上传策略生成
     */
    OssPolicyResult policy();
    /**
     * oss上传成功回调
     */
    OssCallbackResult callback(HttpServletRequest request);
}
import cn.hutool.json.JSONUtil;
import cn.kgc.beans.dto.OssCallbackParam;
import cn.kgc.beans.dto.OssCallbackResult;
import cn.kgc.beans.dto.OssPolicyResult;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * oss上传管理Service实现类
 * Created by macro on 2018/5/17.
 */
@Service
public class OssServiceImpl implements OssService {

	private static final Logger LOGGER = LoggerFactory.getLogger(cn.kgc.service.OssServiceImpl.class);
	@Value("${aliyun.oss.policy.expire}")
	private              int    ALIYUN_OSS_EXPIRE;
	@Value("${aliyun.oss.maxSize}")
	private              int    ALIYUN_OSS_MAX_SIZE;
	@Value("${aliyun.oss.callback}")
	private              String ALIYUN_OSS_CALLBACK;
	@Value("${aliyun.oss.bucketName}")
	private              String ALIYUN_OSS_BUCKET_NAME;
	@Value("${aliyun.oss.endpoint}")
	private              String ALIYUN_OSS_ENDPOINT;
	@Value("${aliyun.oss.dir.prefix}")
	private              String ALIYUN_OSS_DIR_PREFIX;

	@Autowired
	private OSSClient ossClient;

	/**
	 * 签名生成
	 */
	@Override
	public OssPolicyResult policy() {
		OssPolicyResult result = new OssPolicyResult();
		// 存储目录
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
		String dir = ALIYUN_OSS_DIR_PREFIX+sdf.format(new Date());
		// 签名有效期
		long expireEndTime = System.currentTimeMillis() + ALIYUN_OSS_EXPIRE * 1000;
		Date expiration = new Date(expireEndTime);
		// 文件大小
		long maxSize = ALIYUN_OSS_MAX_SIZE * 1024 * 1024;
		// 回调
		OssCallbackParam callback = new OssCallbackParam();
		callback.setCallbackUrl(ALIYUN_OSS_CALLBACK);
		callback.setCallbackBody("filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}");
		callback.setCallbackBodyType("application/x-www-form-urlencoded");
		// 提交节点
		String action = "http://" + ALIYUN_OSS_BUCKET_NAME + "." + ALIYUN_OSS_ENDPOINT;
		try {
			PolicyConditions policyConds = new PolicyConditions();
			policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, maxSize);
			policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
			String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
			byte[] binaryData = postPolicy.getBytes("utf-8");
			String policy = BinaryUtil.toBase64String(binaryData);
			String signature = ossClient.calculatePostSignature(postPolicy);
			String callbackData = BinaryUtil.toBase64String(JSONUtil.parse(callback).toString().getBytes("utf-8"));
			// 返回结果
			result.setAccessKeyId(ossClient.getCredentialsProvider().getCredentials().getAccessKeyId());
			result.setPolicy(policy);
			result.setSignature(signature);
			result.setDir(dir);
			result.setCallback(callbackData);
			result.setHost(action);
		} catch (Exception e) {
			LOGGER.error("签名生成失败", e);
		}
		return result;
	}

	@Override
	public OssCallbackResult callback(HttpServletRequest request) {
		OssCallbackResult result= new OssCallbackResult();
		String filename = request.getParameter("filename");
		filename = "http://".concat(ALIYUN_OSS_BUCKET_NAME).concat(".").concat(ALIYUN_OSS_ENDPOINT).concat("/").concat(filename);
		result.setFilename(filename);
		result.setSize(request.getParameter("size"));
		result.setMimeType(request.getParameter("mimeType"));
		result.setWidth(request.getParameter("width"));
		result.setHeight(request.getParameter("height"));
		return result;
	}

}

7.controller层

import cn.kgc.beans.dto.OssCallbackResult;
import cn.kgc.beans.dto.OssPolicyResult;
import cn.kgc.service.OssService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;

/**
 * Oss对象存储管理Controller
 * Created by macro on 2021/1/14.
 */
@Controller
@Api(tags = "OssController", description = "Oss管理")
@RequestMapping("/aliyun/oss")
public class OssController {
    @Autowired
    private OssService ossService;

    @ApiOperation(value = "oss上传签名生成")
    @RequestMapping(value = "/policy", method = RequestMethod.GET)
    @ResponseBody
    public OssPolicyResult policy() {
        OssPolicyResult result = ossService.policy();

        return result;
    }

    @ApiOperation(value = "oss上传成功回调")
    @RequestMapping(value = "/callback", method = RequestMethod.POST)
    @ResponseBody
    public OssCallbackResult callback(HttpServletRequest request) {
        OssCallbackResult ossCallbackResult = ossService.callback(request);
        return ossCallbackResult;
    }

    public static void main(String[] args) {
        System.out.println(aa());
    }
    public static int aa(){
        try{
            return 5/0;
        } catch(Exception e){
            return 2*3;
        } finally {
            return 3;
        }
    }
}

8.前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>oss</title>
</head>
<script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
<body>
<script>
    var accessKeyId = "";
    var policy = "";
    var signature = "";
    var dir = "";
    var host = "";
    var callback = "";
//访问后台接口拿到签名
  function uploadPhoto() {
    $.ajax({
      url:"http://localhost:8080/aliyun/oss/policy",
      type:"get",
      success: function(data) {
          accessKeyId = data.accessKeyId;
          policy = data.policy;
          signature = data.signature;
          dir = data.dir;
          host = data.host;
      },
      error:function(data) {
        alert("签名生成失败")
      }
    });
    $("#photoFile").click();
  }

  /**
   * 上传图片到oss服务器
   */
  function upload() {
    if ($("#photoFile").val() == '') {
      return;
    }
    var formData = new FormData();
      formData.append('policy', policy);
      formData.append('signature', signature);
      formData.append('key', dir+'/${filename}');
      formData.append('ossaccessKeyId', accessKeyId);
      formData.append('dir', dir);
      formData.append('host', host);
    formData.append('file', document.getElementById('photoFile').files[0]);


    $.ajax({
      url:"http://likaifeng.oss-cn-shenzhen.aliyuncs.com/",
      type:"post",
      data: formData,
      contentType: false,
      processData: false,
      success: function(data) {
          console.log()
          var file=$("#photoFile").val()
          //正则表达式获取文件名,带后缀
          var filename=file.replace(/.*(\/|\\)/, "");
          //正则表达式获取后缀
          var fileExt=(/[.]/.exec(filename)) ? /[^.]+$/.exec(filename.toLowerCase()) : '';
          $("#preview_photo").attr("src","http://likaifeng.oss-cn-shenzhen.aliyuncs.com/"+dir+"/"+filename);
      },
      error:function(data) {
        alert("上传失败")
      }
    });
  }
</script>
<button onclick="uploadPhoto()">选择图片</button>
<input type="file" id="photoFile" style="display: none;" onchange="upload()">
<img id="preview_photo" src="">

</body>
</html>

9.测试

上传图片前

在这里插入图片描述

上传图片后。成功上传
在这里插入图片描述
首先访问policy拿到签名

携带签名上传图片到oss服务器

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值