基于阿里云OSS实现图片上传

阿里云OSS

阿里的OSS就是一个文件云存储方案:

1552265269170

简介:

阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。其数据设计持久性不低于99.999999999%,服务设计可用性不低于99.99%。具有与平台无关的RESTful API接口,您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。

您可以使用阿里云提供的API、SDK接口或者OSS迁移工具轻松地将海量数据移入或移出阿里云OSS。数据存储到阿里云OSS以后,您可以选择标准类型(Standard)的阿里云OSS服务作为移动应用、大型网站、图片分享或热点音视频的主要存储方式,也可以选择成本更低、存储期限更长的低频访问类型(Infrequent Access)和归档类型(Archive)的阿里云OSS服务作为不经常访问数据的备份和归档。

2.2.1 开通oss访问

首先登陆阿里云,然后找到对象存储的产品:

1552307302707

点击进入后,开通服务:

1552307241886

随后即可进入管理控制台:

1552307724634

2.2.2.基本概念

OSS中包含一些概念,我们来认识一下:

  • 存储类型(Storage Class)

    OSS提供标准、低频访问、归档三种存储类型,全面覆盖从热到冷的各种数据存储场景。其中标准存储类型提供高可靠、高可用、高性能的对象存储服务,能够支持频繁的数据访问;低频访问存储类型适合长期保存不经常访问的数据(平均每月访问频率1到2次),存储单价低于标准类型;归档存储类型适合需要长期保存(建议半年以上)的归档数据,在三种存储类型中单价最低。详情请参见存储类型介绍

  • 存储空间(Bucket)

    存储空间是您用于存储对象(Object)的容器,所有的对象都必须隶属于某个存储空间。您可以设置和修改存储空间属性用来控制地域、访问权限、生命周期等,这些属性设置直接作用于该存储空间内所有对象,因此您可以通过灵活创建不同的存储空间来完成不同的管理功能。

  • 对象/文件(Object)

    对象是 OSS 存储数据的基本单元,也被称为OSS的文件。对象由元信息(Object Meta),用户数据(Data)和文件名(Key)组成。对象由存储空间内部唯一的Key来标识。对象元信息是一组键值对,表示了对象的一些属性,比如最后修改时间、大小等信息,同时您也可以在元信息中存储一些自定义的信息。

  • 地域(Region)

    地域表示 OSS 的数据中心所在物理位置。您可以根据费用、请求来源等综合选择数据存储的地域。详情请参见OSS已开通的Region

  • 访问域名(Endpoint

    Endpoint 表示OSS对外服务的访问域名。OSS以HTTP RESTful API的形式对外提供服务,当访问不同地域的时候,需要不同的域名。通过内网和外网访问同一个地域所需要的域名也是不同的。具体的内容请参见各个Region对应的Endpoint

  • 访问密钥(AccessKey)

    AccessKey,简称 AK,指的是访问身份验证中用到的AccessKeyId 和AccessKeySecret。OSS通过使用AccessKeyId 和AccessKeySecret对称加密的方法来验证某个请求的发送者身份。AccessKeyId用于标识用户,AccessKeySecret是用户用于加密签名字符串和OSS用来验证签名字符串的密钥,其中AccessKeySecret 必须保密。

以上概念中,跟我们开发中密切相关的有三个:

  • 存储空间(Bucket)
  • 访问域名(Endpoint)
  • 访问密钥(AccessKey):包含了AccessKeyId 和AccessKeySecret。

2.2.3.创建一个bucket

在控制台的右侧,可以看到一个新建Bucket按钮:

1552308905874

点击后,弹出对话框,填写基本信息:

1552309049398

注意点:

  • bucket:存储空间名称,名字只能是字母、数字、中划线
  • 区域:即服务器的地址,这里选择了上海
  • Endpoint:选中区域后,会自动生成一个Endpoint地址,这将是我们访问OSS服务的域名的组成部分
  • 存储类型:默认
  • 读写权限:这里我们选择公共读,否则每次访问都需要额外生成签名并校验,比较麻烦。敏感数据不要请都设置为私有!
  • 日志:不开通

2.2.4.创建AccessKey

有了bucket就可以进行文件上传或下载了。不过,为了安全考虑,我们给阿里云账户开通一个子账户,并设置对OSS的读写权限。

点击屏幕右上角的个人图像,然后点击访问控制:

1552309424324

在跳转的页面中,选择用户,并新建一个用户:

1552309517332

然后填写用户信息:

1552309580867

然后会为你生成用户的AccessKeyID和AccessKeySecret:

1552309726968

妥善保管,不要告诉任何人!

接下来,我们需要给这个用户添加对OSS的控制权限。

进入这个新增的用户详情页面:

1552309892306

点击添加权限,会进入权限选择页面,输入oss进行搜索,然后选择管理对象存储服务(OSS)权限:

1552309962457

2.3.上传文件最佳实践

在控制台的右侧,点击开发者指南按钮,即可查看帮助文档:

1552310900485

然后在弹出的新页面的左侧菜单中找到开发者指南:

1552310990458

可以看到上传文件中,支持多种上传方式,并且因为提供的Rest风格的API,任何语言都可以访问OSS实现上传。

我们可以直接使用java代码来实现把图片上传到OSS,不过这样以来文件会先从客户端浏览器上传到我们的服务端tomcat,然后再上传到OSS,效率较低,如图:

1552311281042

以上方法有三个缺点:

  • 上传慢。先上传到应用服务器,再上传到OSS,网络传送比直传到OSS多了一倍。如果直传到OSS,不通过应用服务器,速度将大大提升,而且OSS采用BGP带宽,能保证各地各运营商的速度。
  • 扩展性差。如果后续用户多了,应用服务器会成为瓶颈。
  • 费用高。需要准备多台应用服务器。由于OSS上传流量是免费的,如果数据直传到OSS,不通过应用服务器,那么将能省下几台应用服务器。

在阿里官方的最佳实践中,推荐了更好的做法:

1552311136676

阿里官方文档中,对于web前端直传又给出了3种不同方案:

  • JavaScript客户端签名直传:客户端通过JavaScript代码完成签名,然后通过表单直传数据到OSS。
  • 服务端签名后直传:客户端上传之前,由服务端完成签名,前端获取签名,然后通过表单直传数据到OSS。
  • 服务端签名直传并设置上传回调:服务端完成签名,并且服务端设置了上传后回调,然后通过表单直传数据到OSS。OSS回调完成后,再将应用服务器响应结果返回给客户端。

各自有一些优缺点。

2.3.1.web前端签名后直传

客户端通过JavaScript代码完成签名,然后通过表单直传数据到OSS。无需访问应用服务器,对应用服务器压力较低。

流程图如下:

image-20200127125730699

  • JavaScript客户端签名直传:
    • 优点:在客户端通过JavaScript代码完成签名,无需过多配置,即可实现直传,非常方便。
    • 问题:客户端通过JavaScript把AccesssKeyID 和AccessKeySecret写在代码里面有泄露的风险

这里我们选择第二种,因为我们并不需要了解用户上传的文件的情况。

2.3.2.服务端签名后直传流程

服务端签名后直传的原理如下:

  1. 用户发送上传Policy请求到应用服务器(我们的微服务)。
  2. 应用服务器返回上传Policy和签名给用户。
  3. 用户直接上传数据到OSS。

流程图:

1552311833528

  • 服务端签名,JavaScript客户端直传:
    • 优点:Web端向服务端请求签名,然后直接上传,不会对服务端产生压力,而且安全可靠
    • 问题:服务端无法实时了解用户上传了多少文件,上传了什么文件

在页面点击上传的按钮,可以看到请求已经发出:

image-20200127132348077

这正是在向服务端申请签名,接下来我们需要在服务端接收请求,生成签名并返回。

我们要做的事情包括:

  • 搭建微服务
  • 在微服务中,提供一个接口,生成文件上传需要的签名
    • 分析接口声明,分析请求方式、请求路径、请求参数、返回值类型
    • 实现业务,生成签名
      • 把一些常量配置到yml文件
      • 编写类,读取这些属性
      • 把OSS客户端注入到spring容器
      • 编写业务,实现签名的生成
      • 解决跨域问题
  • 前端,调用我们的接口,获取签名(已完成)
  • 前端,携带签名,完成上传(已完成)

2.4.搭建授权签名微服务

文件上传并不是商品微服务独有的业务,以后的其它业务也可能用到。而且阿里的AccessKey授权也会在多个地方用到。因此我们把签名授权功能封装到一个独立的微服务中,专门做各种授权功能。

为了方便其它微服务调用,我们依然搭建成聚合工程。

2.4.1.创建父工程

项目坐标

image-20200206191636648

存放目录

image-20200206191651927

pom文件

修改打包方式为POM即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>leyou</artifactId>
<groupId>com.leyou</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>ly-auth</artifactId>
<packaging>pom</packaging>

</project>

2.4.2.实体类模块

项目坐标

image-20200206191824371

存放位置

image-20200206191831294

pom文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ly-auth</artifactId>
<groupId>com.leyou</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>ly-auth-pojo</artifactId>


</project>

2.4.3.API模块

坐标:

image-20200418161726186

存储位置:

image-20200418161751265

pom文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ly-auth</artifactId>
<groupId>com.leyou</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>ly-auth-api</artifactId>

<dependencies>
<dependency>
<groupId>com.leyou</groupId>
<artifactId>ly-auth-pojo</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

2.4.4.业务模块

项目坐标

image-20200206192039899

存放位置

image-20200206192044367

pom文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ly-auth</artifactId>
<groupId>com.leyou</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>ly-auth-service</artifactId>

<dependencies>
<!--eureka起步依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--web起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--阿里云OSS的SDK-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
</dependency>
<!--auth-pojo-->
<dependency>
<groupId>com.leyou</groupId>
<artifactId>ly-auth-pojo</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<!--通用工具-->
<dependency>
<groupId>com.leyou</groupId>
<artifactId>ly-common</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

启动类

ly-auth-servicecom.leyou.auth包下,新建一个启动类:

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.leyou.auth;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication(scanBasePackages = {"com.leyou.auth", "com.leyou.common.advice"})
public class LyAuthApplication {
public static void main(String[] args) {
SpringApplication.run(LyAuthApplication.class, args);
}
}

配置文件

ly-auth-serviceresources目录下,新建一个application.yml文件:

1
2
3
4
5
6
7
8
9
10
11
12
server:
port: 8082
spring:
application:
name: auth-service
eureka:
client:
service-url:
defaultZone: http://ly-registry:10086/eureka
logging:
level:
com.leyou: debug

网关路由

ly-gatewayapplication.yml中,添加对auth-service的路由:

1
2
3
4
5
6
7
8
9
10
11
spring:
# ...
cloud:
# ...
gateway:
# ...
routes:
- id: auth-service # 授权服务
uri: lb://auth-service
predicates:
- Path=/auth/**

2.5.前端请求签名

在品牌新增的表单中,点击图片上传:

image-20200206201955511

发现请求已经发出:

image-20200206201830638

2.5.1.请求分析

请求分析:

  • 请求方式:Get
  • 请求路径:/auth/ali/oss/signature
  • 请求参数:无(如果有登录用户,会携带登录用户信息)
  • 返回值:这个需要参考阿里云的文档介绍

2.5.2.签名返回值

有关签名直传的文档部分:https://help.aliyun.com/document_detail/31927.html?spm=a2c4g.11186623.2.13.34f16e285th61w#concept-qp2-g4y-5db

其中,服务端签名返回给服务端的内容如下:

1
2
3
4
5
6
7
8
{
"accessId":"6MKO******4AUk44",
"host":"http://post-test.oss-cn-hangzhou.aliyuncs.com",
"policy":"eyJleHBpcmF0aW9uIjoiMjAxNS0xMS0wNVQyMDo1Mjoy******Jjdb25kaXRpb25zIjpbWyJjdb250ZW50LWxlbmd0aC1yYW5nZSIsMCwxMDQ4NTc2MDAwXSxbInN0YXJ0cy13aXRoIiwiJGtleSIsInVzZXItZGlyXC8iXV19",
"signature":"VsxOcOudx******z93CLaXPz+4s=",
"expire":1446727949,
"dir":"user-dirs/"
}

详细解释:

  • accessId:用户的AccessKeyId
  • host:申请的阿里OSS的bucket访问地址
  • policy:文件上传的策略,主要包含对上传文件的要求,利用Base64加密后返回,说明文档
  • signature:生成的签名
  • expire:本次签名的过期时间,客户端可以换成签名,在有效期内无需再次签名
  • dir:要上传到bucket中的哪个目录

我们在项目中定义个DTO用来封装这些结果属性:

ly-auth-pojocom.leyou.auth.dto中,添加新的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.leyou.auth.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;


@Data
@AllArgsConstructor(staticName = "of")
@NoArgsConstructor
public class AliOssSignatureDTO {
private String accessId;
private String host;
private String policy;
private String signature;
private long expire;
private String dir;
}

2.5.3.服务端接口声明

根据上面的请求分析,我们可以定义出一个web接口了:

首先是controller,在ly-auth-servicecom.leyou.auth.web包中,新增一个类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.leyou.auth.web;

import com.leyou.auth.dto.AliOssSignatureDTO;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* 阿里的相关授权接口
*
*/
@RestController
@RequestMapping("ali")
public class AliAuthController {
/**
* 申请oss签名
* @return 包含签名、图片验证策略等信息
*/
@GetMapping("/oss/signature")
public ResponseEntity<AliOssSignatureDTO> getAliSignature(){
return ResponseEntity.ok(null);
}

}

2.6.服务端生成签名

根据之前的分析,我们来编写服务端代码,接收前端请求,返回签名结果。这个要参考官方文档中的Demo。

文档地址:https://help.aliyun.com/document_detail/91868.html?spm=a2c4g.11186623.2.16.58cd7eaer5eXWw#concept-ahk-rfz-2fb

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 基本属性
String accessId = "<yourAccessKeyId>"; // 请填写您的AccessKeyId。
String accessKey = "<yourAccessKeySecret>"; // 请填写您的AccessKeySecret。
String endpoint = "oss-cn-hangzhou.aliyuncs.com"; // 请填写您的 endpoint。
String bucket = "bucket-name"; // 请填写您的 bucketname 。
String host = "https://" + bucket + "." + endpoint; // host的格式为 bucketname.endpoint

String dir = "user-dir-prefix/"; // 用户上传文件时指定的前缀。
// OSS客户端
OSS client = new OSSClient(endpoint, accessId, accessKey);
try {
// 过期时间
long expireTime = 30;
long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
Date expiration = new Date(expireEndTime);
// 上传策略条件
PolicyConditions policyConds = new PolicyConditions();
// 文件大小限制
policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
// 文件目录限制
policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
// 对策略加密
String postPolicy = client.generatePostPolicy(expiration, policyConds);
byte[] binaryData = postPolicy.getBytes("utf-8");
String encodedPolicy = BinaryUtil.toBase64String(binaryData);
// 生成签名
String postSignature = client.calculatePostSignature(postPolicy);
// 准备响应结果
Map<String, String> respMap = new LinkedHashMap<String, String>();
respMap.put("accessid", accessId);
respMap.put("policy", encodedPolicy);
respMap.put("signature", postSignature);
respMap.put("dir", dir);
respMap.put("host", host);
respMap.put("expire", String.valueOf(expireEndTime / 1000));
// 把结果转JSON
JSONObject ja1 = JSONObject.fromObject(respMap);
// 写入response
response(request, response, ja1.toString());

} catch (Exception e) {
System.out.println(e.getMessage());
}
}

2.6.1.配置属性

在刚刚的Demo中,有许多是值或者与服务器环境有关,需要定义到配置文件中,在application.yaml中添加下面的属性:

1
2
3
4
5
6
7
8
9
ly:
oss:
accessKeyId: LTAI4FhtSrGpB2mq4N36XbGb
accessKeySecret: OEavFEiAyGm7OsGYff5TClHx88KJ28
host: http://ly-images.oss-cn-shanghai.aliyuncs.com # 访问oss的bucket的域名
endpoint: oss-cn-shanghai.aliyuncs.com # 你选择的oss服务器的地址
dir: "heima01" # 保存到bucket的某个子目录
expireTime: 1200000 # 过期时间,单位是ms
maxFileSize: 5242880 #文件大小限制,这里是5M

然后,通过一个类来加载这些属性,在ly-auth-servicecom.leyou.auth.config中定义类:

1
2
3
4
5
6
7
8
9
10
11
12
@Data
@Component
@ConfigurationProperties("ly.oss")
public class OSSProperties {
private String accessKeyId;
private String accessKeySecret;
private String host;
private String endpoint;
private String dir;
private long expireTime;
private long maxFileSize;
}

2.6.2.配置OSS客户端

OSS上传需要使用阿里提供的客户端API,其中核心是一个名为OSS的接口:

image-20200206224145079

我们在ly-auth-servicecom.leyou.auth.config定义一个配置类,将OSS注入到Spring容器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.leyou.auth.config;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class OSSConfig {

@Bean
public OSS ossClient(OSSProperties prop){
return new OSSClientBuilder()
.build(prop.getEndpoint(), prop.getAccessKeyId(), prop.getAccessKeySecret());
}
}

2.6.3.service

定义业务代码,改造阿里提供的Demo,将结果封装为DTO返回.

ly-auth-servicecom.leyou.auth.service中定义Service接口:

1
2
3
4
5
6
7
8
9
10
11
12
package com.leyou.auth.service;

import com.leyou.auth.dto.AliOssSignatureDTO;


public interface AliAuthService {

/**
* 生成OSS的文件签名
*/
AliOssSignatureDTO getSignature();
}

ly-auth-servicecom.leyou.auth.service.impl中定义Service的实现类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package com.leyou.auth.service;

import com.aliyun.oss.OSS;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.leyou.auth.config.OSSProperties;
import com.leyou.auth.dto.AliOssSignatureDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Date;


@Slf4j
@Service
public class AliAuthServiceImpl implements AliAuthService{

private OSSProperties prop;

private OSS client;

public AliAuthServiceImpl(OSSProperties ossProperties, OSS client) {
this.prop = ossProperties;
this.client = client;
}

public AliOssSignatureDTO getSignature() {
try {
// 1.计算过期时间
long expireTime = prop.getExpireTime();
long expireEndTime = System.currentTimeMillis() + expireTime;
Date expiration = new Date(expireEndTime);

// 2.设置上传策略
PolicyConditions policyConds = new PolicyConditions();
// 2.1.文件大小限制
policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, prop.getMaxFileSize());
// 2.2.上传目录
policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, prop.getDir());
// 2.3.生成策略
String postPolicy = client.generatePostPolicy(expiration, policyConds);
// 2.4.编码
byte[] binaryData = postPolicy.getBytes("utf-8");
String encodedPolicy = BinaryUtil.toBase64String(binaryData);
// 3.生成签名
String postSignature = client.calculatePostSignature(postPolicy);

// 4.封装要返回的结果
return AliOssSignatureDTO.of(prop.getAccessKeyId(), prop.getHost(), encodedPolicy, postSignature, expireEndTime, prop.getDir());
} catch (Exception e) {
log.error("上传文件失败,原因:{}", e.getMessage(), e);
throw new RuntimeException("文件上传失败!", e);
}
}
}

2.6.4.补全controller

我们给ly-auth-servicecom.leyou.auth.web包中的AliAuthController补全业务,调用AliAuthService

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.leyou.auth.web;

import com.leyou.auth.dto.AliOssSignatureDTO;
import com.leyou.auth.service.AliAuthService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* 阿里的相关授权接口
*
*
*/
@RestController
@RequestMapping("ali")
public class AliAuthController {

private AliAuthService aliAuthService;

public AliAuthController(AliAuthService aliAuthService) {
this.aliAuthService = aliAuthService;
}

/**
* 申请oss签名
*
* @return 包含签名、图片验证策略等信息
*/
@GetMapping("/oss/signature")
public ResponseEntity<AliOssSignatureDTO> getAliSignature() {
return ResponseEntity.ok(aliAuthService.getSignature());
}

}

2.7.启动测试

启动ly-auth-service,并重启ly-auth-gateway,然后测试上传功能。

发现签名正确返回了:

image-20200206233442420

结果:

image-20200206233516457

但是上传失败了,返回了403的状态码:

image-20200206233554422

控制台也报错了:

image-20200206233646040

这是跨域问题。

2.8.解决跨域问题

我们在manage.leyou.com访问aliyuncs.com是跨域访问,需要设置跨域许可。

在阿里OSS的控制台看到这样的信息:

image-20200206233916516

我们点击设置,进入设置页面:

image-20200206233947861

点击创建规则,进入跨域请求填写表单:

image-20200206234147957

填写完成后,再次测试