- 创建第三方的模块
- 给第三方服务模块, 进行配置
- 服务端签名后直传OSS
- 网关配置
由于之后可能要调用很多的第三方服务, 因此直接创建一个模块专门用于第三方服务的调用
勾选上 远程调用的功能 . 注册中心和配置中心的依赖 , 直接用common的
gulimall-third-party 模块中, 添加如下的依赖
com.atguigu.gulimall
gulimall-common
0.0.1-SNAPSHOT
com.alibaba.cloud
spring-cloud-starter-alicloud-oss
另外在dependencyManagement 节点中 ,添加如下
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
com.alibaba.cloud
spring-cloud-alibaba-dependencies
2.1.0.RELEASE
pom
import
删除common中的 对象存储的依赖, 以免其他的服务要配置对象存储的配置.
在命名空间中, 新建一个命名空间为third-party , 用于第三方服务 新建一个配置
spring:
cloud:
alicloud:
access-key: 666666
secret-key: 7777777
oss:
endpoint: oss-cn-shanghai.aliyuncs.com
gulimall-third-party 模块中, 新建一个bootstrap.properties 配置文件 内容如下, 主要是配置nacos中对应的相关信息 .
spring.application.name=gulimall-third-party
# 配置中心的地址 nacos的地址
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
# gulimall-third-party 第三方服务的命名空间
spring.cloud.nacos.config.namespace=7e5ca2a6-9dea-4569-89c3-30fd11080753
# nacos 配置的 data-id 即配置的文件名
spring.cloud.nacos.config.ext-config[0].data-id=oss.yml
# nacos 配置的 分组
spring.cloud.nacos.config.ext-config[0].group=DEFAULT_GROUP
# nacos 配置的 是否设置动态刷新
spring.cloud.nacos.config.ext-config[0].refresh=true
新建立一个application.yml文件 内容如下 ,用于配置注册中心的地址和应用名称, 服务端口
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 #nacos注册中心的地址
application:
name: gulimall-third-party
server:
port: 30000
由于此第三方的服务不需要连接数据库 , 因此要把common中的mybatis的依赖排除
com.atguigu.gulimall
gulimall-common
0.0.1-SNAPSHOT
com.baomidou
mybatis-plus-boot-starter
在主启动类上加上 服务注册与发现的注解 启动项目报错如下
Caused by: java.lang.NoClassDefFoundError: org/springframework/boot/context/properties/ConfigurationPropertiesBean
at org.springframework.cloud.context.properties.ConfigurationPropertiesBeans.postProcessBeforeInitialization(ConfigurationPropertiesBeans.java:94) ~[spring-cloud-context-2.2.5.RELEASE.jar:2.2.5.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:414) ~[spring-beans-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1770) ~[spring-beans-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593) ~[spring-beans-5.1.9.RELEASE.jar:5.1.9.RELEASE]
... 26 common frames omitted
Caused by: java.lang.ClassNotFoundException: org.springframework.boot.context.properties.ConfigurationPropertiesBean
at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_161]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_161]
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338) ~[na:1.8.0_161]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_161]
... 30 common frames omitted
报错原因: 主要原因是Spring cloud 的版本不对. 需要换成 Greenwich.SR3
可以看到成功的启动了.
在nacos的服务列表中 也可以看得到
在gulimall-third-party 模块的测试类中 , 进行文件上传的测试
@SpringBootTest
class GulimallThirdPartyApplicationTests {
@Autowired
OSSClient ossClient ;
@Test
void upload() throws FileNotFoundException {
// 上传文件流。
InputStream inputStream = new FileInputStream("C:\\Users\\tao\\Desktop\\天气之子壁纸\\1082262.png");
ossClient.putObject("gulimall-.....", "666.png", inputStream);
// 关闭OSSClient。
ossClient.shutdown();
System.out.println("上传完成!!! ");
}
}
可以看到上传成功. 在阿里云的控制台中, 也能看得到
上面上传是用的nacos中的oss的配置
服务端签名后直传 可以参考阿里云官方的文档 https://help.aliyun.com/document_detail/31926.html?spm=a2c4g.11186623.6.1684.4c1d7eaeavWjxO 流程如下图 参考如下链接文章的示例代码 https://help.aliyun.com/document_detail/91868.html?spm=a2c4g.11186623.2.15.68306e28yXTsV2#concept-ahk-rfz-2fb
示例代码中, 红色框的代码是用于处理跨域的, 但是在谷粒商城中, 跨域是在网关层统一处理的, 不需要的, 因此可以去掉此处的代码, 只需返回一个map.
服务端签名的改造接口如下. 主要是一些配置信息, 通过nacos中获取. 另外是建立一个文件夹用于每天建立一个文件夹存放文件, 避免一个文件夹文件太多. 注意 : 注入的是OSS 接口.
package com.atguigu.gulimall.thirdparty.controller;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.atguigu.common.utils.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 类名称:OssController
* 类描述: 文件上传
*
* @author: https://javaweixin6.blog.csdn.net/
* 创建时间:2020/10/1 21:49
* Version 1.0
*/
@RestController
public class OssController {
@Autowired
OSS ossClient;
@Value("${spring.cloud.alicloud.oss.endpoint}")
private String endpoint ;
@Value("${spring.cloud.alicloud.oss.bucket}")
private String bucket ;
@Value("${spring.cloud.alicloud.access-key}")
private String accessId;
@RequestMapping("/oss/policy")
public R policy() {
// host的格式为 bucketname.endpoint 用于拼接图片的访问地址
String host = "https://" + bucket + "." + endpoint;
// 用户上传文件时指定的前缀。 此处定义每天建立一个文件夹
String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
String dir = format+"/";
Map respMap = null ;
try {
long expireTime = 30;
long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
Date expiration = new Date(expireEndTime);
// PostObject请求最大可支持的文件大小为5 GB,即CONTENT_LENGTH_RANGE为5*1024*1024*1024。
PolicyConditions policyConds = new PolicyConditions();
policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
byte[] binaryData = postPolicy.getBytes("utf-8");
String encodedPolicy = BinaryUtil.toBase64String(binaryData);
String postSignature = ossClient.calculatePostSignature(postPolicy);
respMap = new LinkedHashMap();
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));
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
ossClient.shutdown();
}
return R.ok().put("data",respMap);
}
}
将该模块启动后, 访问http://localhost:30000/oss/policy
可以看到通过该接口, 返回了签名相关的数据
所有的请求发给网关88端口, 那么希望按照http://localhost:88/api/thirdparty
开头的请求, 例如http://localhost:88/api/thirdparty/oss/policy
, 都能够映射到第三方服务的模块上.
修改网关的配置如下. 增加一个上传文件的配置 完整的如下. 其中
- id 为third_party_route , 用于给第三方服务的路由起个id
- uri 代表要跳转到哪个服务中去, 指定了要跳转到应用名称为gulimall-third-party 服务中去
- predicates 配置的是
/api/thirdparty/**
代表只要是以/api/thirdparty/
开头的请求, 都会跳转到gulimall-third-party 服务中去. - filters 配置的是
RewritePath=/api/thirdparty/(?/?.*), /$\{segment}
代表对路径的截取替换. 例如请求的是http://localhost:88/api/thirdparty/oss/policy
, 实际请求的是http://localhost:30000/oss/policy
, 其中http://localhost:30000
已经根据应用的名称去替换了. 那么要截取的就是去掉api/thirdparty
, 所以写成了/api/thirdparty/(?/?.*), /$\{segment}
spring:
cloud:
gateway:
routes:
- id: product_route
uri: lb://gulimall-product
predicates:
- Path=/api/product/**
filters:
- RewritePath=/api/(?/?.*), /$\{segment}
- id: third_party_route
uri: lb://gulimall-third-party
predicates:
- Path=/api/thirdparty/**
filters:
- RewritePath=/api/thirdparty/(?/?.*), /$\{segment}
- id: admin_route
uri: lb://renren-fast
predicates:
- Path=/api/**
filters:
- RewritePath=/api/(?/?.*), /renren-fast/$\{segment}
开启网关和第三方模块的服务 浏览器访问
http://localhost:88/api/thirdparty/oss/policy
可以看到成功的返回了数据. 代表网关成功的进行了路由配置