时间:2025-04-22 12:56
人气:
作者:admin
项目的源码地址:

通过 GateWay 进行对各个服务的转发,重定向进行配置信息。从而就简化配置,同时注意存在一个“同源策略” 的问题——》就是一个跨域问题。 CORS 的问题。
重点:注意:我们这里的 GateWay 不是一个 Web 服务,所以所以所以,我们千万千万千万不可以将 Web 相关的依赖的模块导入到 GateWay 当中,不然是会报错的,发生一个冲突。
gateway本身不是一个做 web服务器的,因此不要引入 spring-boot-starter-web,
否则会报告冲突
注意是: spring-boot-starter-web重点

server:
port: 5050 #gateway监听端口
spring:
cloud:
#配置网关
#http://localhost:5050/api/commodity/brand/list
#http://www.hspliving.com/api/commodity/brand/list
gateway:
routes: #配置路由,可以有多个路由
- id: rainbowsealiving_renren_fast_route # 路由id, 由程序员指定,保证唯一
# 当前配置完成的需求说明:
# 如果到网关的请求时 http://localhost:5050/commodity/brand/list ,gateway 通过断言。
# 最终将请求路由转发到 http://localhost:9090/commodity/brand/list = >url=uri+path
uri: lb://renren-fast
predicates:
- Path=/api/** #断言,路径相匹配的进行路由
# - id: member_routh01 # 路由id, 由程序员指定,保证唯一
# # 当前配置完成的需求说明:
# # 如果到网关的请求时 http://localhost:5050/commodity/brand/list ,gateway 通过断言。
# # 最终将请求路由转发到 http://localhost:9090/commodity/brand/list = >url=uri+path
# uri: http://localhost:9090
# predicates:
# - Path=/commodity/brand/list #断言,路径相匹配的进行路由
nacos:
discovery:
server-addr: 127.0.0.1:8848 #配置nacos地址
application:
name: rainbowsealiving-gateway
server:
port: 5050 #gateway监听端口
spring:
cloud:
#配置网关
#http://localhost:5050/api/commodity/brand/list
#http://www.hspliving.com/api/commodity/brand/list
gateway:
routes: #配置路由,可以有多个路由
- id: rainbowsealiving_renren_fast_route # 路由id, 由程序员指定,保证唯一
# 当前配置完成的需求说明:
# 如果到网关的请求时 http://localhost:5050/api/???/??? ,gateway 通过断言。
# 最终将请求路由转发到 http://renren-fast [注册到 nacosd renren-fast 服务ip+端口] = >url=uri+path
uri: lb://renren-fast
predicates:
- Path=/api/** #断言,路径相匹配的进行路由
server:
port: 5050 #gateway监听端口
spring:
cloud:
#配置网关
#http://localhost:5050/api/commodity/brand/list
#http://www.hspliving.com/api/commodity/brand/list
gateway:
routes: #配置路由,可以有多个路由
- id: rainbowsealiving_renren_fast_route # 路由id, 由程序员指定,保证唯一
# 当前配置完成的需求说明:
# 如果到网关的请求时 http://localhost:5050/api/???/??? ,gateway 通过断言。
# 最终将请求路由转发到 http://renren-fast [注册到 nacosd renren-fast 服务ip+端口] = >url=uri+path
uri: lb://renren-fast
predicates:
- Path=/api/** #断言,路径相匹配的进行路由
# - id: member_routh01 # 路由id, 由程序员指定,保证唯一
# # 当前配置完成的需求说明:
# # 如果到网关的请求时 http://localhost:5050/commodity/brand/list ,gateway 通过断言。
# # 最终将请求路由转发到 http://localhost:9090/commodity/brand/list = >url=uri+path
# uri: http://localhost:9090
# predicates:
# - Path=/commodity/brand/list #断言,路径相匹配的进行路由
nacos:
discovery:
server-addr: 127.0.0.1:8848 #配置nacos地址
application:
name: rainbowsealiving-gateway

server:
port: 5050 #gateway监听端口
spring:
cloud:
#配置网关
#http://localhost:5050/api/commodity/brand/list
#http://www.hspliving.com/api/commodity/brand/list
gateway:
routes: #配置路由,可以有多个路由
- id: rainbowsealiving_renren_fast_route # 路由id, 由程序员指定,保证唯一
# 当前配置完成的需求说明:
# 如果到网关的请求时 http://localhost:5050/api/???/??? ,gateway 通过断言。
# 最终将请求路由转发到 http://renren-fast [注册到 nacosd renren-fast 服务ip+端口]/????? = >url=uri+path
# 因为我们要去掉断言到 Path的/api ,所以这里我们需要使用上路径重写。
uri: lb://renren-fast
predicates:
- Path=/api/** #断言,路径相匹配的进行路由
filters:
- RewritePath=/api/(?<segment>.*), /renren-fast/$\{segment}
# - id: member_routh01 # 路由id, 由程序员指定,保证唯一
# # 当前配置完成的需求说明:
# # 如果到网关的请求时 http://localhost:5050/commodity/brand/list ,gateway 通过断言。
# # 最终将请求路由转发到 http://localhost:9090/commodity/brand/list = >url=uri+path
# uri: http://localhost:9090
# predicates:
# - Path=/commodity/brand/list #断言,路径相匹配的进行路由
nacos:
discovery:
server-addr: 127.0.0.1:8848 #配置nacos地址
application:
name: rainbowsealiving-gateway

server:
port: 5050 #gateway监听端口
spring:
cloud:
#配置网关
#http://localhost:5050/api/commodity/brand/list
#http://www.hspliving.com/api/commodity/brand/list
gateway:
routes: #配置路由,可以有多个路由
- id: rainbowsealiving_renren_fast_route # 路由id, 由程序员指定,保证唯一
# 当前配置完成的需求说明:
# 如果到网关的请求时 http://localhost:5050/api/???/??? ,gateway 通过断言。
# 最终将请求路由转发到 http://renren-fast [注册到 nacosd renren-fast 服务ip+端口]/????? = >url=uri+path
# 因为我们要去掉断言到 Path的/api ,所以这里我们需要使用上路径重写。
uri: lb://renren-fast
predicates:
- Path=/api/** #断言,路径相匹配的进行路由
filters:
- RewritePath=/api/(?<segment>.*), /renren-fast/$\{segment}
# - id: member_routh01 # 路由id, 由程序员指定,保证唯一
# # 当前配置完成的需求说明:
# # 如果到网关的请求时 http://localhost:5050/commodity/brand/list ,gateway 通过断言。
# # 最终将请求路由转发到 http://localhost:9090/commodity/brand/list = >url=uri+path
# uri: http://localhost:9090
# predicates:
# - Path=/commodity/brand/list #断言,路径相匹配的进行路由
- id: rainbowSealiving_commodity_route # 路由id, 由程序员指定,保证唯一
# 当前配置完成的需求说明:
# 如果到网关的请求时 http://localhost:5050/api/commodity/???/??? ,gateway 通过断言。
# 最终将请求路由转发到 http://rainbowSealiving-commodity [注册到 nacosd renren-fast 服务ip+端口]/????? = >url=uri+path
# 因为我们要去掉断言到 Path的/api ,所以这里我们需要使用上路径重写。
uri: lb://rainbowSealiving-commodity
predicates:
- Path=/api/commodity/** #断言,路径相匹配的进行路由
filters:
- RewritePath=/api/(?<segment>.*), /renren-fast/$\{segment}
nacos:
discovery:
server-addr: 127.0.0.1:8848 #配置nacos地址
application:
name: rainbowsealiving-gateway
使用之前的 config ,配置的 WEbMvcConfig 不行了,而且 GateWay 不是一个 Web 项目,引入 Web 项目反而会报错。
GateWay 5050 端口访问 ——> 9090 端口跨域问题
9090 ——》阿里云跨域问题

同理,在 config 路径下配置一个跨域处理


package com.rainbowsea.rainbowsealiving.gateway.config;
import org.springframework.context.annotation.Bean;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
public class RainbowsealivingGatewayCorsConfiguration {
@Bean
public CorsWebFilter corsWebFilter(){
System.out.println("enter....");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
//1、配置跨域
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.setAllowCredentials(true);
source.registerCorsConfiguration("/**",corsConfiguration);
return new CorsWebFilter(source);
}
}

同时注意:



server:
port: 5050 #gateway监听端口
spring:
cloud:
#配置网关
#http://localhost:5050/api/commodity/brand/list
#http://www.hspliving.com/api/commodity/brand/list
gateway:
routes: #配置路由,可以有多个路由
# - id: member_routh01 # 路由id, 由程序员指定,保证唯一
# # 当前配置完成的需求说明:
# # 如果到网关的请求时 http://localhost:5050/commodity/brand/list ,gateway 通过断言。
# # 最终将请求路由转发到 http://localhost:9090/commodity/brand/list = >url=uri+path
# uri: http://localhost:9090
# predicates:
# - Path=/commodity/brand/list #断言,路径相匹配的进行路由
- id: raibnowsealiving_service_route # 路由id, 由程序员指定,保证唯一
# 当前配置完成的需求说明:
# 如果到网关的请求时 http://localhost:5050/api/service/???/??? ,gateway 通过断言。
# 最终将请求路由转发到 http://rainbowSealiving-service [注册到 nacosd renren-fast 服务ip+端口]/????? = >url=uri+path
# 因为我们要去掉断言到 Path的/api ,所以这里我们需要使用上路径重写。
uri: lb://raibnowsealiving-service
predicates:
- Path=/api/service/** #断言,路径相匹配的进行路由
filters:
# 也就是通过路径重写,最终的url 就是 http://localhost:7070
- RewritePath=/api/service/(?<segment>.*), /$\{segment}
- id: rainbowSealiving_commodity_route # 路由id, 由程序员指定,保证唯一
# 当前配置完成的需求说明:
# 如果到网关的请求时 http://localhost:5050/api/commodity/list/tree ,gateway 通过断言。
# 最终将请求路由转发到 http://rainbowSealiving-commodity [注册到 nacosd renren-fast 服务ip+端口]/????? = >url=uri+path
# 因为我们要去掉断言到 Path的/api ,所以这里我们需要使用上路径重写。
# 说明: /api/commodity/是一个更加精确的路径,必须将这组路由放在 /api/这里上
# 否则会报错
uri: lb://rainbowSealiving-commodity
predicates:
- Path=/api/commodity/** #断言,路径相匹配的进行路由
filters:
# 也就是通过路径重写,最终的url 就是 http://localhost:9090
- RewritePath=/api/(?<segment>.*), /$\{segment}
- id: rainbowsealiving_renren_fast_route # 路由id, 由程序员指定,保证唯一
# 当前配置完成的需求说明:
# 如果到网关的请求时 http://localhost:5050/api/???/??? ,gateway 通过断言。
# 最终将请求路由转发到 http://renren-fast [注册到 nacosd renren-fast 服务ip+端口]/????? = >url=uri+path
# 因为我们要去掉断言到 Path的/api ,所以这里我们需要使用上路径重写。
uri: lb://renren-fast
predicates:
- Path=/api/** #断言,路径相匹配的进行路由
filters:
# 也就是通过路径重写,最终的url 就是 http://localhost:8090
- RewritePath=/api/(?<segment>.*), /renren-fast/$\{segment}
nacos:
discovery:
server-addr: 127.0.0.1:8848 #配置nacos地址
application:
name: rainbowsealiving-gateway

<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<!--
引入 oss starter 我们引入的 stater 和 文档给的不一样,
请注意观察 artifactId ,小伙伴要和写的保持一致
老师说明: 因为我们在该 pom.xml 文件中有 dependencyManagement 指定了 spring-cloud-aliba
版本 2.1.0.RELEASE 因此这里,我们可以不写 version 而是使用版本仲裁
-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-oss</artifactId>
<!-- <version>2.1.0.RELEASE</version>-->
</dependency>

<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--
引入 oss starter 我们引入的 stater 和 文档给的不一样,
请注意观察 artifactId ,小伙伴要和写的保持一致
老师说明: 因为我们在该 pom.xml 文件中有 dependencyManagement 指定了 spring-cloud-aliba
版本 2.1.0.RELEASE 因此这里,我们可以不写 version 而是使用版本仲裁
-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-oss</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
</dependencies>
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.rainbowsea.RainbowSealiving</groupId>
<artifactId>raibnowsealiving-service</artifactId>
<version>1.0-SNAPSHOT</version>
<name>raibnowsealiving-service</name>
<description>顺平( 家居生活)- 第三方服务模块 OSS</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>2020.0.5</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--
引入 oss starter 我们引入的 stater 和 文档给的不一样,
请注意观察 artifactId ,小伙伴要和写的保持一致
老师说明: 因为我们在该 pom.xml 文件中有 dependencyManagement 指定了 spring-cloud-aliba
版本 2.1.0.RELEASE 因此这里,我们可以不写 version 而是使用版本仲裁
-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-oss</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- 引入公共模块,排除 mybatis-plus -->
<dependency>
<groupId>com.rainbowsea.RainbowSealiving</groupId>
<artifactId>RainbowSealiving-common</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 排除公共模块当中的 mybatis-plus-boot-starter 依赖-->
<exclusions>
<exclusion>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
在 Nacos 配置中心按以前讲解的方式创建命名空间, dataId 和组并将配置信息放在Nacos ,具体如图。




在 resources 下创建一个 bootstrap.properties 用于获取/访问 Nacos 当中的配置信息,也可以用 yml


#注册到 nacos的名字
spring.application.name=rainbowsealiving-service
#指定 nacos的发现注册地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
#指定 nacos的配置地址
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
#要获取的配置文件所在的配置空间
spring.cloud.nacos.config.namespace=73bded0a-1c06-4292-a8ff-e5b177114551
#配置空间的哪一个组,这个组下可以有多个配置文件,通过 ext-config[?]来指定要加载某空间下的某组的第几个文件
spring.cloud.nacos.config.group=dev
#通过 ext-config[?]来指定要加载某空间下的某组的第几个文件
# 和指定 data-id 和是否实时刷新的配置
spring.cloud.nacos.config.ext-config[0].data-id=rainbowsealiving-service.yml
spring.cloud.nacos.config.ext-config[0].group=dev
spring.cloud.nacos.config.ext-config[0].refresh=true
注意这里配置的 pom.xml 的相关的依赖

<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--
引入 oss starter 我们引入的 stater 和 文档给的不一样,
请注意观察 artifactId ,小伙伴要和写的保持一致
老师说明: 因为我们在该 pom.xml 文件中有 dependencyManagement 指定了 spring-cloud-aliba
版本 2.1.0.RELEASE 因此这里,我们可以不写 version 而是使用版本仲裁
-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-oss</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-nacos-config</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
</dependencies>
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.rainbowsea.RainbowSealiving</groupId>
<artifactId>raibnowsealiving-service</artifactId>
<version>1.0-SNAPSHOT</version>
<name>raibnowsealiving-service</name>
<description>顺平( 家居生活)- 第三方服务模块 OSS</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>2020.0.5</spring-cloud.version>
</properties>
<dependencies>
<!--
通过回顾,我们指定,如果该服务需要去拉取nacos配置中心的配置, 需要加入
spring-cloud-starter-alibaba-nacos-config [融汇贯通]
这里,我们使用版本仲裁,来指定version
-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--引入 oss starter 我们引入的stater 和文档给的不一样,
请注意观察artifactId , 小伙伴要和老师写的保持一致
老师说明: 因为我们在该pom.xml文件中有 dependencyManagement 指定了 spring-cloud-alibaba-dependencies
版本 2.1.0.RELEASE, 因此这里,我们可以不写version 而是使用版本仲裁
-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-oss</artifactId>
<!--<version>2.1.0.RELEASE</version>-->
</dependency>
<!-- 引入公共模块,排除 mybatis-plus -->
<dependency>
<groupId>com.rainbowsea.RainbowSealiving</groupId>
<artifactId>RainbowSealiving-common</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 排除公共模块当中的 mybatis-plus-boot-starter 依赖-->
<exclusions>
<exclusion>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!--
1. 这里老师想回顾使用dependencyManagement 在进行版本控制
2. 老韩再强调一下dependencyManagement 用于指定依赖版本,
但是本身并不引入相关依赖
-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<!--
老师解读:
1. type: pom 和 scope import 配合使用
2. 表示 在这个项目的子模块和当前这个模块,
在引入spring-cloud-alibaba相关依赖时 锁定版本为2.1.0.RELEASE
3. 通过 pom + import 解决maven单继承机制
-->
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

通过 @Value 注解的方式,获取到 Nacos 当中的配置,再赋值到对应相等内容上。

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.rainbowsea.common.utils.R;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
@RestController
public class OssServiceController {
// 装配属性
@Resource
OSS ossClient;
@Value("${spring.cloud.alicloud.access-key}")
private String accessId;
@Value("${spring.cloud.alicloud.oss.endpoint}")
private String endpoint;
@Value("${spring.cloud.alicloud.oss.bucket}")
private String bucket;
}
package com.rainbowsea.rainbowsealiving.service.controller;
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.rainbowsea.common.utils.R;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
@RestController
public class OssServiceController {
// 装配属性
@Resource
OSS ossClient;
@Value("${spring.cloud.alicloud.access-key}")
private String accessId;
@Value("${spring.cloud.alicloud.oss.endpoint}")
private String endpoint;
@Value("${spring.cloud.alicloud.oss.bucket}")
private String bucket;
@RequestMapping("/oss/policy")
public R policy() {
String host = "https://" + bucket + "." + endpoint;
// host的 格 式 为 // bucketname.endpoint
// callbackUrl为 上传回调服务器的 URL,请将下面的 IP和 Port配置为您自己的真实信息。暂时不用
// String callbackUrl = "http://88.88.88.88:8888";
// 我们可以将文件按照 年-月-日的形式分目录存放在阿里云[以后优化]
// 得到 dir
// java 基础的日期 -SimpleDateFormat
String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
String dir = format + "/"; //用户上传文件时指定的前缀。
Map<String, String> respMap = null;
try {
long expireTime = 30; // 默认超时时间 30s
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 = ossClient.generatePostPolicy(expiration, policyConds);
byte[] binaryData = postPolicy.getBytes("utf-8");
String encodedPolicy = BinaryUtil.toBase64String(binaryData);
String postSignature = ossClient.calculatePostSignature(postPolicy);
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));
// respMap.put("expire", formatISO8601Date(expiration));
} catch (Exception e) {
// Assert.fail(e.getMessage());
System.out.println(e.getMessage());
}
return R.ok().put("data", respMap);
}
}
用户登录名称 rainbowsealiving-10000@1562236733667461.onaliyun.com
AccessKey ID LTAI5tP4G6hDJqh7FPe1Cahh
AccessKey Secret vl5kaBORH1QADEzKq9NInpRdD8JJeF
LTAI5tP4G6hDJqh7FPe1Cahh
vl5kaBORH1QADEzKq9NInpRdD8JJeF
用户登录名称 rainbowsealiving-10000@1562236733667461.onaliyun.com
AccessKey ID LTAI5tP4G6hDJqh7FPe1Cahh
AccessKey Secret vl5kaBORH1QADEzKq9NInpRdD8JJeF
防止,用户走后端,比如使用 Postman 进行访问,登录时候。
JSR-303 是 JAVA EE 6 中的一项子规范,叫做 Bean Validation,Hibernate Validator 是 Bean Validation 的参考实现



package com.rainbowsea.rainbowsealiving.commodity.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import org.hibernate.validator.constraints.URL;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
/**
* 家居品牌
*
* @author rainbowsea
* @email rainbowsea@gmail.com
* @date 2025-03-08 20:11:04
*/
@Data
@TableName("commodity_brand")
public class BrandEntity implements Serializable {
private static final long serialVersionUID = 2L;
/**
* id
*/
@TableId
private Long id;
/**
* 品牌名
* 1. @NotBlank 表示 name 必须包括一个非空字符
* 2. message = "品牌名不能为空" 是老师指定一个校验消息
* 3. 如果没有指定 message = "品牌名不能为空",就会返回默认的校验信息 key = javax.validation.constion
* 4. 这个默认的消息是在 ValidationMessages_zh_CN.properties 文件配置javax.validation.constran
* 5. @NotBlank 可以用于 CharSequence
*/
@NotBlank(message = "品牌名不能为空")
private String name;
/**
* logo 因为这个 Logo 对应的是图片的 url
* 1.@NotBlank 和 @URL 组合去校验 logo
*/
@NotBlank(message = "logo 不能为空")
@URL(message = "logo 不是一个合法的 URL ")
private String logo;
/**
* 说明
*/
private String description;
/**
* 显示,isshow 后面的 s 是小写
* 1. 这里我们使用的注解是(@NotNull,他可以接收任意类型)
* 2. 如果这里使用 @NotBlank,会报错,因为 @NotBlank 不支持 Integer
* 3. 大家在开发时,需要知道注解可以用在哪些类型上,可以查看注解源码
* 4. 说明: 假如 isshow 规定时 0 / 1,这时我们后面通过自定义约束来解决
* 5. 如果是 String 类型,可以直接使用@Pattern 来进一步校验。
*/
@NotNull(message = "显示状态不能为空")
private Integer isshow;
/**
* 检索首字母 a-z, A-Z
* 因为 firstLetter 是 String 可以直接使用 @Pattern
*/
@NotBlank(message = "检索首字母不能为空")
@Pattern(regexp = "^[a-zA-Z]$",message = "检索首字母必须是 a-z 或者 A-Z")
private String firstLetter;
/**
* 排序
*/
@NotNull(message = "排序值不能为空")
@Min(value = 0,message = "排序值要求大于等于 0 ")
private Integer sort;
}

/**
* 保存
* 说明:
* 1. @Validated 注解的作用就是启用 BrandEntity 字段校验
* 2. 注解如果没有写 @Validated 这个校验规则不生效
* 3. BindingResult result: springboot 会将校验的错误放入到 result
* 4. 程序员可以通过 BindingResult result 将校验得到错误取出,然后进行相应处理
*/
@RequestMapping("/save")
//@RequiresPermissions("commodity:brand:save")
public R save(@Validated @RequestBody BrandEntity brand, BindingResult result){
// 先创建一个 Map,用于收集校验错误
Map<String,String> map = new HashMap<>();
if (result.hasErrors()) { // 如果有校验错误
// 遍历 result ,将错误信息收集到 map
result.getFieldErrors().forEach((item) ->{
// 得到 field
String field = item.getField();
// 得到校验错误信息
String message = item.getDefaultMessage();
// 放入 map
map.put(field,message);
});
return R.error(400,"品牌表单数据不合法").put("data",map);
} else { // 如果没有校验错误,入库
brandService.save(brand);
return R.ok();
}
}


我们可以使用@ControllerAdvice 统一管理异常/错误

package com.rainbowsea.rainbowsealiving.commodity.exception;
import com.rainbowsea.common.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;
import java.util.Map;
/**
* 说明:
* @ResponseBody : 表示以 json 格式返回数据
* @Slf4j 可以输出日志,便于数据
* @ControllerAdvice(basePackages = "com.rainbowsea.rainbowsealiving.commodity.controller")
* 表示统一接管 com.rainbowsea.rainbowsealiving.commodity.controller 这个路径包下的
* 抛出了的数据校验的异常,就由 @ExceptionHandler(value = MethodArgumentNotValidException.class)
* 处理
*/
@Slf4j
@ResponseBody
@ControllerAdvice(basePackages = "com.rainbowsea.rainbowsealiving.commodity.controller")
public class RainbowSealivingExceptionControllerAdvice {
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public R handleValidException(MethodArgumentNotValidException e) {
log.error(" 数据校验出现问题{},异常类型:{}",e.getMessage(),e.getClass());
BindingResult bindingResult = e.getBindingResult();
Map<String, String> errorMap = new HashMap<>();
bindingResult.getFieldErrors().forEach((fieldError) -> {
errorMap.put(fieldError.getField(), fieldError.getDefaultMessage());
});
return R.error(400, " 方法参数异常").put("data", errorMap);
}
/**
*
这里再写一个处理 Throwable类型的异常的方法,没有精确匹配到的异常,走这里
*/
@ExceptionHandler(value = Throwable.class)
public R handleException(Throwable throwable){
return R.error(40000," 系统未知错误");
}
}


/**
* 保存
* 说明:
* 1. @Validated 注解的作用就是启用 BrandEntity 字段校验
* 2. 注解如果没有写 @Validated 这个校验规则不生效
* 3. BindingResult result: springboot 会将校验的错误放入到 result
* 4. 程序员可以通过 BindingResult result 将校验得到错误取出,然后进行相应处理
* 5.如果使用@ControllerAdvice统一接管异常,就不用单独封装返回异常信息了,将其注释
* 6.异常会统一抛出给@ControllerAdvice类
*/
@RequestMapping("/save")
//@RequiresPermissions("commodity:brand:save")
public R save(@Validated @RequestBody BrandEntity brand, BindingResult result){
// 先创建一个 Map,用于收集校验错误
//Map<String,String> map = new HashMap<>();
//
//if (result.hasErrors()) { // 如果有校验错误
// // 遍历 result ,将错误信息收集到 map
// result.getFieldErrors().forEach((item) ->{
// // 得到 field
// String field = item.getField();
// // 得到校验错误信息
// String message = item.getDefaultMessage();
// // 放入 map
// map.put(field,message);
// });
//
// return R.error(400,"品牌表单数据不合法").put("data",map);
/
【从0到1构建一个ClaudeAgent】协作-Agent团队