Skip to content

oss

这里介绍一下 oss 的使用。

功能介绍

主要包含在 wmeimob-spring-boot-starter-oss jar 中。

支持的平台有:

引入公共依赖:

xml
<dependency>
    <groupId>com.wmeimob.fastboot</groupId>
    <artifactId>wmeimob-spring-boot-starter-oss</artifactId>
</dependency>

公共配置项:

yml
  oss:
    ossType: xxx      # OSS 平台类型
    ossAccessKey: xxx # OSS AccessKey
    ossSecretKey: xxxx # OSS SecretKey
    ossBucketName: xxx # OSS BucketName
    ossEndPoint: oss-xxx.com # OSS EndPoint

阿里云

再引入阿里云依赖:

xml
<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
</dependency>

填写好公共配置项即可。

腾讯云

再引入腾讯云依赖:

xml
<dependency>
    <groupId>com.qcloud</groupId>
    <artifactId>cos_api</artifactId>
</dependency>
<dependency>
    <groupId>com.tencent.cloud</groupId>
    <artifactId>cos-sts-java</artifactId>
</dependency>

除了填写公共配置项外,还需要再填写:

yml
    oss-region: xxx # OSS region
    oss-app-id: xxx # OSS app-id

华为云

再引入华为云依赖:

xml
<dependency>
    <groupId>com.huaweicloud</groupId>
    <artifactId>esdk-obs-java-bundle</artifactId>    
</dependency>

七牛云

暂未遇到有项目在使用,暂时不补充

minio

再引入minio依赖:

xml
<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
</dependency>

本地云存储

如果使用本地云存储,无需引入任何依赖,除了调整公共配置外,还需要再调写:

yml
localDir:     #本地根目录路径
picFileType:  #本地OSS支持的文件类型,默认支持 png|jpg|jpeg|gif|bmp|svg|ico|mp4|webm|ogg|pdf

自定义 spi 扩展

如果使用自定义 spi 扩展,无需引入任何依赖,只需要更改公共配置的 ossType 为自定义 spi 扩展即可。如果上述提供的几种方式不满足的话,可以通过 spi 方式来扩展。此处基于 spring spi 扩展机制来实现。

常见问题

  • 阿里云签名

默认为 V1 签名。由于 V1 签名会被废弃,因而无法使用。现支持 V1,V4 签名切换,参见所有配置属性

  • 文件大小限制

默认 20M。如若不够,可更改。

yml
oss:
    maxFileSize: 20 #最大文件限制(M)
  • 文件后缀限制

文件后缀限制目前只针对阿里云,如果需要上传其他格式,需要添加对应的配置。

默认支持如下格式:

yml
oss:
    content-type:
        - image/png
        - image/bmp
        - image/jpeg
        - image/jpg
        - image/gif
        - video/mp4
        - application/json
        - image/tiff
        - image/webp
        - font/ttf
        - font/otf
  • Handler dispatch failed; nested exception is java.lang.NoSuchMethodError: org.json.JSONObject.toMap()Ljava/util/Map

解决方法如下:

yml
<dependency>
    <groupId>com.qcloud</groupId>
    <artifactId>cos_api</artifactId>
</dependency>

<dependency>
    <groupId>com.tencent.cloud</groupId>
    <artifactId>cos-sts-java</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.json</groupId>
            <artifactId>json</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
</dependency>

主 pom 文件引入如下依赖:

yml
<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20180130</version>
</dependency>
  • 华为云栈溢出

错误如下:

java
Caused by: java.lang.IllegalStateException: Failed to introspect Class [com.wmeimob.spring.boot.oss.service.impl.OssServiceHuaweiyunImpl] from ClassLoader [sun.misc.Launcher$AppClassLoader@42a57993]
	at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:485)
	at org.springframework.util.ReflectionUtils.doWithLocalMethods(ReflectionUtils.java:321)
	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.buildLifecycleMetadata(InitDestroyAnnotationBeanPostProcessor.java:232)
	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.findLifecycleMetadata(InitDestroyAnnotationBeanPostProcessor.java:210)
	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessMergedBeanDefinition(InitDestroyAnnotationBeanPostProcessor.java:149)
	at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessMergedBeanDefinition(CommonAnnotationBeanPostProcessor.java:305)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyMergedBeanDefinitionPostProcessors(AbstractAutowireCapableBeanFactory.java:1116)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594)
	... 72 common frames omitted
Caused by: java.lang.StackOverflowError: null
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(Unknown Source)
	at java.lang.ClassLoader.loadClass(Unknown Source)
	at java.lang.ClassLoader.loadClass(Unknown Source)
	at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
	at java.lang.ClassLoader.loadClass(Unknown Source)
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(Unknown Source)
	at java.security.SecureClassLoader.defineClass(Unknown Source)
	at java.net.URLClassLoader.defineClass(Unknown Source)
	at java.net.URLClassLoader.access$100(Unknown Source)
	at java.net.URLClassLoader$1.run(Unknown Source)
	at java.net.URLClassLoader$1.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(Unknown Source)
	at java.lang.ClassLoader.loadClass(Unknown Source)
	at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
	at java.lang.ClassLoader.loadClass(Unknown Source)
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(Unknown Source)
	at java.security.SecureClassLoader.defineClass(Unknown Source)
	at java.net.URLClassLoader.defineClass(Unknown Source)
	at java.net.URLClassLoader.access$100(Unknown Source)
	at java.net.URLClassLoader$1.run(Unknown Source)
	at java.net.URLClassLoader$1.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(Unknown Source)
	at java.lang.ClassLoader.loadClass(Unknown Source)
	at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
	at java.lang.ClassLoader.loadClass(Unknown Source)
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(Unknown Source)
	at java.security.SecureClassLoader.defineClass(Unknown Source)
	at java.net.URLClassLoader.defineClass(Unknown Source)
	at java.net.URLClassLoader.access$100(Unknown Source)
	at java.net.URLClassLoader$1.run(Unknown Source)
	at java.net.URLClassLoader$1.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)

解决方法如下:

java
jvm 启动参数增大栈空间
-Xss512K

所有配置属性

txt
/**
* OSS类型 (pic:本地OSS qiniu:七牛  aliyun:阿里云  qcloud:腾讯云, huawei:华为云)
*/
ossType;
/**
* 是否开启自定义 cdn 域名
*/
enableCustomCdn;
/**
* CDN域名
*/
cdnDomain;
/**
* OSS绑定的域名
*/
ossDomain;
/**
* OSS AccessKey
*/
ossAccessKey;
/**
* OSS SecretKey
*/
ossSecretKey;
/**
* OSS BucketName
*/
ossBucketName;
/**
* EndPoint (EndPoint)
*/
ossEndPoint;
/**
* AppId (腾讯云AppId)
*/
ossAppId;
/**
* 所属地区 (阿里云/腾讯云)
*/
ossRegion;
/**
* Url有效时间
*/
expire;
/**
* 上传目录(OSS服务的上传路径)
*/
dir;
/**
* 最大文件限制(M)
*/
maxFileSize;
/**
* 是否为https(已过期,使用 enableHttps 代替)
*/
isHttps;
/**
* 是否为https
*/
enabledHttps;
/**
* 本地根目录路径(临时文件|服务器图片上传路径)
*/
localDir;
/**
* 本地OSS支持的文件类型(png|jpg|jpeg|gif|bmp|svg|ico|mp4|webm|ogg|pdf)
*/
picFileType = "png|jpg|jpeg|gif|bmp|svg|ico|mp4|webm|ogg|pdf";
/**
* 上传支持的 contentType 列表
*/
contentType;
/**
* 签名版本(适用于阿里云,默认 V1。支持 V1,V4。当使用 V4 时,ossRegion 属性必填。)
*/
signVersion = "V1";

与标品的集成

java
@Api(tags = {"云存储"})
@RestController
@RequestMapping("/api/oss")
public class OssController {
    
    @Resource
    private OssService ossService;
    
    @ApiOperation(value = "云存储信息")
    @GetMapping("/info")
    public JsonResult<Map<String, Object>> info() {
        return JsonResult.ok(this.ossService.ossPolicy());
    }
}
java
public enum OssType {
    Aliyun,
    Qcloud,
    Qiniu,
    Pic,
    Huawei,
    Custom;
}

前端直接通过该接口便可以获取到具体的云存储通道。如下是各个渠道 map 参数说明:

txt
accessid=xx     #访问id
policy=xx       #policy
signature=xx    #签名
dir=xx/         #上传目录
host=xx         #host
expire=xx       #过期时间毫秒
cdnDomain=xx    #cdn域名
type=xx         #类型
txt
 credentials: {
    "tmpSecretId": "xxx",
    "tmpSecretKey": "xx=",
    "sessionToken": "xxx"
}                   #凭证对象
dir=xx/             #上传目录
expiration=xx       #过期时间,例如:2024-02-29T09:15:53Z
startTime=xx        #开始时间,整形
expiredTime=xx      #过期时间,整形
bucket=xx           #桶名称
region=xx           #区域
cdnDomain=xx        #cdn域名
type=xx             #类型
txt
access_key_id=xx    #访问id
policy=xx           #policy
signature=xx        #签名
server=xx           #host
dir=xx/             #上传目录
cdnDomain=xx        #cdn域名
type=xx             #类型
txt
暂未提供

安全

跨域

当作为静态资源存储时,我们需要为其设置跨域规则,例如:

yaml
http://localhost:* #本地开发
https://xxx        #部署后的域名

防盗链

而防盗链设置则可以不让 oss 流量外泄,我们可以这样去设置,例如:

yaml
*.console.aliyun.com # 阿里云域名
*servicewechat.com   # 微信小程序域名
*.xxx                # 业务部署后的域名
http://localhost:*   # 本地开发