init commit
This commit is contained in:
parent
51c5f2a5f6
commit
3fe3f891da
59
.gitignore
vendored
59
.gitignore
vendored
@ -1,26 +1,41 @@
|
||||
# ---> Java
|
||||
# Compiled class file
|
||||
*.class
|
||||
HELP.md
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
replay_pid*
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
## IDEA maven
|
||||
/.flattened-pom.xml
|
||||
/**/flattened-pom.xml
|
||||
admin-application/.flattened-pom.xml
|
||||
admin-application/logs/
|
||||
admin-client/.flattened-pom.xml
|
||||
admin-core/.flattened-pom.xml
|
||||
admin-model/.flattened-pom.xml
|
||||
|
82
Dockerfile
Normal file
82
Dockerfile
Normal file
@ -0,0 +1,82 @@
|
||||
FROM openjdk:8
|
||||
|
||||
ARG JAR_FILE="./target/*.jar"
|
||||
ARG APP_NAME="bi-gateway"
|
||||
ARG SERVER_PORT=80
|
||||
ARG PROFILES="dev"
|
||||
ARG SPRING_CLOUD_SENTINEL_ENABLED="false"
|
||||
ARG SPRING_CLOUD_SENTINEL_EAGER="false"
|
||||
|
||||
# license配置
|
||||
ARG LICENSE_PATH="/opt/license/verifyinfo"
|
||||
ARG LICENSE_REDIS_HOST="10.0.5.17:6679"
|
||||
ARG LICENSE_REDIS_PWD="Do1admin@hr123"
|
||||
ARG LICENSE_IP="10.0.5.17"
|
||||
ARG NACOS_USERNAME="nacos"
|
||||
ARG NACOS_PASSWORD="nacos"
|
||||
|
||||
# 内存配置
|
||||
ENV JAVA_OPTS "-Xmx2048m -Xss256k"
|
||||
#启动环境配置
|
||||
ENV PROFILES $PROFILES
|
||||
#工作路径
|
||||
ENV WORK_PATH "/home"
|
||||
#日志路径
|
||||
ENV LOG_FILE "logs/app.log"
|
||||
#服务端口
|
||||
ENV SERVER_PORT $SERVER_PORT
|
||||
# NACOS 配置
|
||||
ENV NACOS_SERVER $NACOS_SERVER
|
||||
ENV NACOS_NAMESPACE $NACOS_NAMESPACE
|
||||
ENV NACOS_USERNAME $NACOS_USERNAME
|
||||
ENV NACOS_PASSWORD $NACOS_PASSWORD
|
||||
|
||||
ENV LICENSE_PATH $LICENSE_PATH
|
||||
|
||||
ENV LICENSE_REDIS_HOST $LICENSE_REDIS_HOST
|
||||
|
||||
ENV LICENSE_REDIS_PWD $LICENSE_REDIS_PWD
|
||||
|
||||
ENV LICENSE_IP $LICENSE_IP
|
||||
ENV LOGGIN_FILE $LOGGIN_FILE
|
||||
|
||||
# Sentinel配置
|
||||
ENV SPRING_CLOUD_SENTINEL_ENABLED $SPRING_CLOUD_SENTINEL_ENABLED
|
||||
ENV SPRING_CLOUD_SENTINEL_EAGER $SPRING_CLOUD_SENTINEL_EAGER
|
||||
ENV SPRING_CLOUD_SENTINEL_TRANSPORT_PORT $SPRING_CLOUD_SENTINEL_TRANSPORT_PORT
|
||||
ENV SPRING_CLOUD_SENTINEL_TRANSPORT_DASHBOARD $SPRING_CLOUD_SENTINEL_TRANSPORT_DASHBOARD
|
||||
|
||||
#设置时区
|
||||
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||
|
||||
VOLUME /tmp
|
||||
|
||||
EXPOSE ${SERVER_PORT}
|
||||
|
||||
#WITH_SKYWALKING# ADD skywalking-agent.tar.gz /lib/
|
||||
COPY ${JAR_FILE} ${WORK_PATH}/app.jar
|
||||
RUN sh -c 'touch ${WORK_PATH}/app.jar'
|
||||
|
||||
#ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom --server.port=$SERVER_PORT -Dapollo.meta=$APOLLO_META -Dapp.id=$APOLLO_ID -Dspring.profiles.active=$PROFILES -jar $WORK_PATH/app.jar " ]
|
||||
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom \
|
||||
-Dserver.port=$SERVER_PORT \
|
||||
-Dspring.cloud.nacos.config.server-addr=$NACOS_SERVER \
|
||||
-Dspring.cloud.nacos.config.namespace=$NACOS_NAMESPACE \
|
||||
-Dspring.cloud.nacos.config.username=$NACOS_USERNAME \
|
||||
-Dspring.cloud.nacos.config.password=$NACOS_PASSWORD \
|
||||
-Dspring.cloud.nacos.discovery.server-addr=$NACOS_SERVER \
|
||||
-Dspring.cloud.nacos.discovery.username=$NACOS_USERNAME \
|
||||
-Dspring.cloud.nacos.discovery.password=$NACOS_PASSWORD \
|
||||
-Dspring.cloud.nacos.discovery.namespace=$NACOS_NAMESPACE \
|
||||
-Dspring.profiles.active=$PROFILES \
|
||||
-Ddo1.license=$LICENSE_PATH \
|
||||
-Dredis.host=$LICENSE_REDIS_HOST \
|
||||
-Dredis.pwd=$LICENSE_REDIS_PWD \
|
||||
-Dlicense.ip=$LICENSE_IP \
|
||||
-Dlogging.file=$LOGGIN_FILE \
|
||||
-Dspring.cloud.sentinel.enabled=$SPRING_CLOUD_SENTINEL_ENABLED \
|
||||
-Dspring.cloud.sentinel.eager=$SPRING_CLOUD_SENTINEL_EAGER \
|
||||
-Dspring.cloud.sentinel.transport.port=$SPRING_CLOUD_SENTINEL_TRANSPORT_PORT \
|
||||
-Dspring.cloud.sentinel.transport.dashboard=$SPRING_CLOUD_SENTINEL_TRANSPORT_DASHBOARD \
|
||||
-Duser.timezone=GMT+08 -jar $WORK_PATH/app.jar" ]
|
||||
|
118
Jenkinsfile
vendored
Normal file
118
Jenkinsfile
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
pipeline {
|
||||
agent {
|
||||
node {
|
||||
label labelName
|
||||
}
|
||||
|
||||
}
|
||||
stages {
|
||||
stage('初始化') {
|
||||
steps {
|
||||
script {
|
||||
|
||||
echo """ ==== 构建信息 ====
|
||||
应 用 名:$serverName
|
||||
分 支:$gitBranch
|
||||
gitkey:$gitkey
|
||||
harborkey: $harborkey
|
||||
镜像版本:$DOCKER_TAG """
|
||||
echo """ $params"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('编译') {
|
||||
steps {
|
||||
script {
|
||||
container(labelName) {
|
||||
dir(serverName) {
|
||||
checkout([
|
||||
$class: 'GitSCM',
|
||||
branches: [[name: "*/$gitBranch"]],
|
||||
doGenerateSubmoduleConfigurations: false,
|
||||
extensions: [[$class: 'CloneOption', depth: 1, noTags: false, reference: '', shallow: true]],
|
||||
submoduleCfg: [],
|
||||
userRemoteConfigs: [[url: gitPath, credentialsId: gitkey]],
|
||||
])
|
||||
/** 打印基础信息 **/
|
||||
sh " echo 打印基础信息 "
|
||||
sh " pwd "
|
||||
sh " ls "
|
||||
sh " mvn clean install -e -Dmaven.test.skip=true "
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('镜像打包') {
|
||||
steps {
|
||||
script {
|
||||
container(labelName) {
|
||||
dir(serverName) {
|
||||
withCredentials([usernamePassword(passwordVariable: 'DOCKER_PASSWORD', usernameVariable: 'DOCKER_USERNAME', credentialsId: "harborkey",)]) {
|
||||
sh 'echo "$DOCKER_PASSWORD" | docker login $DOCKER_REGISTRY -u "$DOCKER_USERNAME" --password-stdin'
|
||||
sh """
|
||||
cd admin-application
|
||||
docker build -t $DOCKER_IMAGE --build-arg JAR_FILE=$filepath --build-arg APP_NAME=$serverName .
|
||||
docker push $DOCKER_IMAGE
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('发布服务') {
|
||||
steps {
|
||||
container(labelName) {
|
||||
script{
|
||||
//查询服务是否已经创建,如果已经创建再次发布只更新镜像
|
||||
def result = ""
|
||||
def global_config = true
|
||||
def license = true
|
||||
def harborkey = true
|
||||
//服务是否已经部署
|
||||
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE'){
|
||||
result = sh(returnStdout: true, script: "kubectl get deployment $serverName -n $namespace ").trim()
|
||||
}
|
||||
if(result==""){
|
||||
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE'){
|
||||
sh "helm delete $serverName -n $namespace "
|
||||
}
|
||||
sh "helm repo update "
|
||||
sh "helm install --set image.repository=$DOCKER_REGISTRY,image.tag=$DOCKER_TAG,nameOverride=$serverName $serverName do1-chart/base-server --version=$CHART_VERSION -n $namespace "
|
||||
}else{
|
||||
sh "kubectl set image deploy $serverName *=$DOCKER_IMAGE -n $namespace"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
environment {
|
||||
dockerFile = "Dockerfile"
|
||||
filepath = " ./target/**.jar "
|
||||
labelName = "maven"
|
||||
DOCKER_REGISTRY="$DOCKER_REGISTRY/$namespace/$serverName".replaceAll("//","/")
|
||||
DOCKER_IMAGE="$DOCKER_REGISTRY:$DOCKER_TAG".replaceAll("//","/")
|
||||
CHART_VERSION = "1.1.0"
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 说明: 参数初始化脚本,默认情况下是注释的,如果需要新增参数可以通过可视化界面添加也可以通过此脚本添加,一般用来初始化和调整顺序,注意,使用此代码片段添加参数,参数会在第一次构建生效,且会覆相同的参数值,以代码片段中的参数配置重新添加,意思就是如果初始化后,下面代码 parameters 没有 注释,那么每次运行后之前添加或修改的参数都会被下面的参数和默认值替换
|
||||
parameters {
|
||||
string(name: 'gitBranch', defaultValue: 'dev', description: '选择需要发布的分支')
|
||||
string(name: 'gitPath', defaultValue: 'https://git.qiweioa.cn/bi-system/bi-admin.git', description: 'git 仓库地址')
|
||||
string(name: 'serverName', defaultValue: 'bi-admin-dev', description: 'KubeSphere服务名')
|
||||
string(name: 'namespace', defaultValue: 'bi-dev', description: '需要发布的k8s命名空间,每个项目都应该有一个命名空间,且在集群中唯一')
|
||||
string(name: 'gitkey', defaultValue: 'denghuizhi', description: 'git仓库访问凭证配置在流水线访问凭证中,gitkey为全局的配置在Jenkins中,不需要手动创建,模版中的值由主流程传递过来')
|
||||
string(name: 'harborkey', defaultValue: 'harborkey', description: '镜像仓库访问凭证,harborkey 为默认值,镜像仓库地址发生变更时需要修改此参数,自定义凭证需要在流水线凭证中创建')
|
||||
string(name: 'DOCKER_REGISTRY', defaultValue: 'harbor.uat.do1.com.cn:6001/do1cloud/', description: '镜像仓库,默认值 harbor.uat.do1.com.cn/do1cloud/ 为公司全局镜像仓库,如有需要可以自行更改,如果使用了其他镜像仓库地址,需要修改dockerkey的值')
|
||||
string(name: 'DOCKER_TAG', defaultValue: 'dev', description: '镜像版本')
|
||||
}
|
||||
}
|
18
README.md
18
README.md
@ -1,2 +1,18 @@
|
||||
# bi-gateway
|
||||
## 默认访问路径
|
||||
- http://网关IP:端口/{nacos服务名}/{RequestMapping的路径},如下图
|
||||
```shell
|
||||
http://127.0.0.1/saas-dubbo-all-application/acc/user?id=2&test=aba
|
||||
```
|
||||
## 打印access log
|
||||
```jvm
|
||||
-Dreactor.netty.http.server.accessLogEnabled=true
|
||||
```
|
||||
|
||||
## 参考资料
|
||||
- [基础入门](https://spring.io/guides/gs/gateway/) 官方gateway使用示例
|
||||
- [gateway官方文档](https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the-discoveryclient-route-definition-locator)
|
||||
12.4节 The DiscoveryClient Route Definition Locator
|
||||
- [核心重要接口](https://blog.csdn.net/u010647035/article/details/84480626) RouteLocator、RouteDefinitionRouteLocator、DiscoveryClient、DiscoveryClientRouteDefinitionLocator
|
||||
、重要配置类DiscoveryLocatorProperties、GatewayDiscoveryClientAutoConfiguration以及不同厂家的DiscoveryClient实现配置、RouteRefreshListener
|
||||
- [路由转发过程](https://zhuanlan.zhihu.com/p/449990867) 通过handler利用RouteLocator的getRoutes实现路由转发
|
||||
- [gateway性能优化](https://blog.csdn.net/weixin_42161936/article/details/123395773) 面向ISV的架构
|
3
buildDocker.sh
Normal file
3
buildDocker.sh
Normal file
@ -0,0 +1,3 @@
|
||||
docker build -t harbor.uat.do1.com.cn:6001/do1cloud/bi-release/bi-gateway-release:0.5.0 .
|
||||
docker login -u admin -p Harbor12345 harbor.uat.do1.com.cn:6001
|
||||
docker push harbor.uat.do1.com.cn:6001/do1cloud/bi-release/bi-gateway-release:0.5.0
|
176
pom.xml
Normal file
176
pom.xml
Normal file
@ -0,0 +1,176 @@
|
||||
<?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>cn.com.do1.do1cloud.bi</groupId>
|
||||
<artifactId>bi-denpendencies</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<groupId>cn.com.do1.do1cloud.bi</groupId>
|
||||
<artifactId>bi-gateway</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<dqdp.license.version>2.1.0-SNAPSHOT</dqdp.license.version>
|
||||
<spring-boot-maven-plugin.version>2.1.1.RELEASE</spring-boot-maven-plugin.version>
|
||||
<project.parent.artifactId.version>2.2.1-SNAPSHOT</project.parent.artifactId.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||
<version>3.0.8</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</exclusion>
|
||||
|
||||
<exclusion>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.tomcat.embed</groupId>
|
||||
<artifactId>tomcat-embed-core</artifactId>
|
||||
</exclusion>
|
||||
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/io.projectreactor.netty/reactor-netty-http -->
|
||||
<dependency>
|
||||
<groupId>io.projectreactor.netty</groupId>
|
||||
<artifactId>reactor-netty-http</artifactId>
|
||||
<version>1.0.29</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor.netty</groupId>
|
||||
<artifactId>reactor-netty-core</artifactId>
|
||||
<version>1.0.29</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-core</artifactId>
|
||||
<version>3.4.27</version>
|
||||
</dependency>
|
||||
<!--客户端负载均衡loadbalancer-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||
<version>4.0.2</version>
|
||||
</dependency>
|
||||
<!--客户端依赖-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
<!--配置中心依赖-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-boot-starter</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-bootstrap</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.com.do1.do1cloud.bi</groupId>
|
||||
<artifactId>bi-model</artifactId>
|
||||
<version>${parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.janino</groupId>
|
||||
<artifactId>janino</artifactId>
|
||||
<version>3.0.16</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-compiler</artifactId>
|
||||
<groupId>org.codehaus.janino</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.janino</groupId>
|
||||
<artifactId>commons-compiler</artifactId>
|
||||
<version>3.0.16</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.logstash.logback</groupId>
|
||||
<artifactId>logstash-logback-encoder</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-datasource-nacos</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<!--spring-cloud-alibaba 版本控制-->
|
||||
<dependency>
|
||||
<groupId>cn.com.do1.do1cloud.bi</groupId>
|
||||
<artifactId>bi-denpendencies</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>${spring-boot-maven-plugin.version}</version>
|
||||
<configuration>
|
||||
<fork>true</fork>
|
||||
<mainClass>cn.com.do1.component.bi.gateway.GatewayApplication</mainClass>
|
||||
<layoutFactory implementation="cn.com.do1.license.boot.DqdpLayoutFactory">
|
||||
<licenseJar>dqdp-license-${dqdp.license.version}.jar</licenseJar>
|
||||
</layoutFactory>
|
||||
</configuration>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.com.do1</groupId>
|
||||
<artifactId>dqdp-license</artifactId>
|
||||
<version>${dqdp.license.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@ -0,0 +1,18 @@
|
||||
package cn.com.do1.component.bi.gateway;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.cloud.gateway.discovery.GatewayDiscoveryClientAutoConfiguration;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@SpringBootApplication(exclude = GatewayDiscoveryClientAutoConfiguration.class)
|
||||
@RestController
|
||||
@EnableDiscoveryClient
|
||||
public class GatewayApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(GatewayApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package cn.com.do1.component.bi.gateway.config.DynamicRoute;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@RefreshScope
|
||||
@Data
|
||||
@Getter
|
||||
@Setter
|
||||
@ConfigurationProperties(prefix = "dynamic-routes")
|
||||
public class DynamicRouteConfig {
|
||||
private List<RouteInfo> routeInfos;
|
||||
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package cn.com.do1.component.bi.gateway.config.DynamicRoute;
|
||||
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 动态路由转换器
|
||||
*/
|
||||
public class DynamicRouteConfigConverter {
|
||||
|
||||
|
||||
private final static Map<String, List<String>> instanceToTenantIds=new HashMap<>();
|
||||
|
||||
private final static Map<String, List<String>> tenantIdToInstances=new HashMap<>();
|
||||
|
||||
public static Map<String, List<String>> getTenantIdToInstances(){
|
||||
return tenantIdToInstances;
|
||||
}
|
||||
public static Map<String, List<String>> getInstanceToTenantIds(){
|
||||
return instanceToTenantIds;
|
||||
}
|
||||
|
||||
|
||||
public static Map<String, List<String>> convertToInstanceToTenantIds(List<RouteInfo> routeInfos){
|
||||
for (RouteInfo routeInfo:routeInfos){
|
||||
DynamicRouteConfigConverter.instanceToTenantIds.putAll(routeInfo.getInstanceToTenantIds());
|
||||
}
|
||||
return instanceToTenantIds;
|
||||
}
|
||||
|
||||
|
||||
public static Map<String, List<String>> convertToTenantIdToInstances(List<RouteInfo> routeInfos){
|
||||
routeInfos.stream().forEach(routeInfo -> {
|
||||
if (ObjectUtil.isNotEmpty(routeInfo.getInstanceToTenantIds())){
|
||||
routeInfo.getInstanceToTenantIds().entrySet().stream().forEach(entry -> entry.getValue().stream().forEach(tenantId -> {
|
||||
String instanceTenantIdKey = routeInfo.getId() + tenantId;
|
||||
List<String> instances = tenantIdToInstances.getOrDefault(instanceTenantIdKey, new ArrayList<String>());
|
||||
instances.add( entry.getKey());
|
||||
tenantIdToInstances.put(instanceTenantIdKey,instances);
|
||||
}));
|
||||
}
|
||||
|
||||
});
|
||||
return tenantIdToInstances;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
package cn.com.do1.component.bi.gateway.config.DynamicRoute;
|
||||
|
||||
import cn.com.do1.component.bi.gateway.filter.ReqDecryptFilter;
|
||||
import cn.com.do1.component.bi.gateway.filter.RespEncryptFilter;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilter;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||
import org.springframework.cloud.gateway.route.Route;
|
||||
import org.springframework.cloud.gateway.route.RouteLocator;
|
||||
import org.springframework.cloud.gateway.route.builder.GatewayFilterSpec;
|
||||
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
|
||||
import org.springframework.cloud.gateway.route.builder.UriSpec;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpCookie;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR;
|
||||
|
||||
@Configuration
|
||||
public class GatewayConfig {
|
||||
|
||||
@Autowired
|
||||
private DynamicRouteConfig dynamicRouteConfig;
|
||||
|
||||
@Bean
|
||||
public RouteLocator headerRoutes(RouteLocatorBuilder builder){
|
||||
RouteLocatorBuilder.Builder routes = builder.routes();
|
||||
List<RouteInfo> routeInfos = dynamicRouteConfig.getRouteInfos();
|
||||
if (ObjectUtil.isNotEmpty(routeInfos)){
|
||||
DynamicRouteConfigConverter.convertToTenantIdToInstances(routeInfos);
|
||||
for (RouteInfo routeInfo:routeInfos){
|
||||
routes.route(routeInfo.getId(), r ->{
|
||||
return r.path(routeInfo.getPredicatesPaths().get(0))
|
||||
.filters(new Function<GatewayFilterSpec, UriSpec>() {
|
||||
@Override
|
||||
public UriSpec apply(GatewayFilterSpec gatewayFilterSpec) {
|
||||
Map<String, String> rewritePathMap = routeInfo.getRewritePathMap();
|
||||
if (ObjectUtil.isNotEmpty(rewritePathMap)) {
|
||||
gatewayFilterSpec.rewritePath(rewritePathMap.get("regexp"),rewritePathMap.get("replacement"));
|
||||
}
|
||||
return gatewayFilterSpec.filter(new HeaderToPathGatewayFilter(routeInfo.getId()))
|
||||
.filter(new ReqDecryptFilter(-25))
|
||||
.filter(new RespEncryptFilter(-23));
|
||||
}
|
||||
}).uri(routeInfo.getDefaultUri());
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
return routes.build();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 租户路由过滤器
|
||||
*/
|
||||
public class HeaderToPathGatewayFilter implements GatewayFilter{
|
||||
private String routeInfoId;
|
||||
|
||||
public HeaderToPathGatewayFilter(String routeInfoId) {
|
||||
this.routeInfoId = routeInfoId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||
List<HttpCookie> tenantIdCookies = exchange.getRequest().getCookies().get("tenantId");
|
||||
if (ObjectUtil.isNotEmpty(tenantIdCookies)){
|
||||
String tenantId = tenantIdCookies.get(0).getValue();
|
||||
if (ObjectUtil.isEmpty(tenantId)){
|
||||
Map<String, List<String>> tenantIdToInstances = DynamicRouteConfigConverter.getTenantIdToInstances();
|
||||
String instanceTenantIdKey =routeInfoId + tenantId;
|
||||
if (tenantIdToInstances.containsKey(instanceTenantIdKey)) {
|
||||
List<String> targetUris = tenantIdToInstances.get(instanceTenantIdKey);
|
||||
int asInt = new Random().ints(0, targetUris.size()).findFirst().getAsInt();
|
||||
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
|
||||
Route newRoute = Route.async().asyncPredicate(route.getPredicate()).filters(route.getFilters()).id(route.getId())
|
||||
.order(route.getOrder()).uri(targetUris.get(asInt)).build();
|
||||
exchange.getAttributes().put(GATEWAY_ROUTE_ATTR,newRoute);
|
||||
}
|
||||
}
|
||||
}
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
package cn.com.do1.component.bi.gateway.config.DynamicRoute;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 路由信息配置
|
||||
*/
|
||||
public class RouteInfo {
|
||||
/**
|
||||
* 路由规则id
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 服务实例对应租户id
|
||||
*/
|
||||
private Map<String, List<String>> instanceToTenantIds;
|
||||
|
||||
/**
|
||||
* 默认路由规则
|
||||
*/
|
||||
private String defaultUri;
|
||||
|
||||
/**
|
||||
* 断言请求路径
|
||||
*/
|
||||
private List<String> predicatesPaths;
|
||||
|
||||
/**
|
||||
* 过滤器重写路径匹配
|
||||
*/
|
||||
private Map<String,String> rewritePathMap;
|
||||
private Map<String,String> filters;
|
||||
|
||||
public Map<String, String> getRewritePathMap() {
|
||||
return rewritePathMap;
|
||||
}
|
||||
|
||||
public void setRewritePathMap(Map<String, String> rewritePathMap) {
|
||||
this.rewritePathMap = rewritePathMap;
|
||||
}
|
||||
|
||||
public List<String> getPredicatesPaths() {
|
||||
return predicatesPaths;
|
||||
}
|
||||
|
||||
public void setPredicatesPaths(List<String> predicatesPaths) {
|
||||
this.predicatesPaths = predicatesPaths;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getInstanceToTenantIds() {
|
||||
return instanceToTenantIds;
|
||||
}
|
||||
|
||||
public void setInstanceToTenantIds(Map<String, List<String>> instanceToTenantIds) {
|
||||
this.instanceToTenantIds = instanceToTenantIds;
|
||||
}
|
||||
|
||||
public String getDefaultUri() {
|
||||
return defaultUri;
|
||||
}
|
||||
|
||||
public void setDefaultUri(String defaultUri) {
|
||||
this.defaultUri = defaultUri;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
RouteInfo routeInfo = new RouteInfo();
|
||||
routeInfo.setId("bi-system");
|
||||
List<String> strings = new ArrayList<>();
|
||||
strings.add("1");
|
||||
strings.add("3");
|
||||
strings.add("4");
|
||||
List<String> strings1 = new ArrayList<>();
|
||||
strings1.add("2");
|
||||
List<String> predicatesPaths = new ArrayList<>();
|
||||
predicatesPaths.add("/system/**");
|
||||
Map<String, List<String>> stringListHashMap = new HashMap<>();
|
||||
stringListHashMap.put("lb://bi-system-1",strings);
|
||||
stringListHashMap.put("lb://bi-system-2",strings1);
|
||||
routeInfo.setInstanceToTenantIds(stringListHashMap);
|
||||
routeInfo.setDefaultUri("lb://bi-system");
|
||||
routeInfo.setPredicatesPaths(predicatesPaths);
|
||||
Map<String, String> stringStringHashMap = new HashMap<>();
|
||||
|
||||
stringStringHashMap.put("'/' + serviceId.replace('bi-', '') + '/(?<remaining>.*)'","'/${remaining}'");
|
||||
routeInfo.setRewritePathMap(stringStringHashMap);
|
||||
List<RouteInfo> routeInfos = new ArrayList<>();
|
||||
routeInfos.add(routeInfo);
|
||||
String s = JSON.toJSONString(routeInfos);
|
||||
|
||||
List<RouteInfo> routeInfos1 = JSON.parseArray(s, RouteInfo.class);
|
||||
System.out.println(s);
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package cn.com.do1.component.bi.gateway.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cloud.gateway.config.GatewayProperties;
|
||||
import org.springframework.cloud.gateway.route.RouteLocator;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.stereotype.Component;
|
||||
import springfox.documentation.swagger.web.SwaggerResource;
|
||||
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 网关的swagger的配置类
|
||||
*/
|
||||
@Component
|
||||
@Primary
|
||||
public class GatewaySwaggerResourcesProvider implements SwaggerResourcesProvider {
|
||||
/**
|
||||
* swagger3默认的url后缀
|
||||
*/
|
||||
private static final String SWAGGER2URL = "/v3/api-docs";
|
||||
/**
|
||||
* 网关路由
|
||||
*/
|
||||
@Autowired
|
||||
private RouteLocator routeLocator;
|
||||
|
||||
@Autowired
|
||||
private GatewayProperties gatewayProperties;
|
||||
/**
|
||||
* 网关应用名称
|
||||
*/
|
||||
@Value("${spring.application.name}")
|
||||
private String self;
|
||||
|
||||
@Override
|
||||
public List<SwaggerResource> get() {
|
||||
List<SwaggerResource> resources = new ArrayList<>();
|
||||
List<String> routeHosts = new ArrayList<>();
|
||||
// 获取所有可用的host:serviceId
|
||||
routeLocator.getRoutes().filter(route -> route.getUri().getHost() != null)
|
||||
.filter(route -> !self.equals(route.getUri().getHost()))
|
||||
.subscribe(route -> routeHosts.add(route.getUri().getHost()));
|
||||
// 记录已经添加过的server
|
||||
Set<String> dealed = new HashSet<>();
|
||||
routeHosts.forEach(instance -> {
|
||||
// 拼接url
|
||||
String url = "/" + instance.toLowerCase().split("-")[1] + SWAGGER2URL;
|
||||
if (!dealed.contains(url)) {
|
||||
dealed.add(url);
|
||||
SwaggerResource swaggerResource = new SwaggerResource();
|
||||
swaggerResource.setUrl(url);
|
||||
swaggerResource.setName(instance);
|
||||
resources.add(swaggerResource);
|
||||
}
|
||||
});
|
||||
return resources;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package cn.com.do1.component.bi.gateway.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@RefreshScope
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "encrypt-decrypt")
|
||||
public class ReqDecryptAndRespEncryptConfig {
|
||||
/**
|
||||
* 开启req的body解密,true开启
|
||||
*/
|
||||
private Boolean reqDecrypt = false;
|
||||
/**
|
||||
* 是否开启Response加密,true开启
|
||||
*/
|
||||
private Boolean respEncrypt = false;
|
||||
/**
|
||||
* 加解密白名单,白名单内url不处理
|
||||
*/
|
||||
private List<String> whiteUrl = new ArrayList<>();
|
||||
/**
|
||||
* rsa加密公钥
|
||||
*/
|
||||
private String rsaPublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9Z3S1r2wPogXFY2UH2vzBgzUEdvXDq6j0DHnJ5YU5pF" +
|
||||
"Ipgnz+G1Uf+5a5VzDcANrCT/GVqZAKPwbQM776eDv/xy1i4sS7wsI9m6pKQ3HSAJl1knT36qfKthMd6VdOQLAZuf9pH3ccbpO3GiJNWAfee/nJ" +
|
||||
"egPK0Xle4Fl114vaiQIDAQAB";
|
||||
/**
|
||||
* rsa加密私钥
|
||||
*/
|
||||
private String rsaPrivateKey = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAL1ndLWvbA+iBcVj" +
|
||||
"ZQfa/MGDNQR29cOrqPQMecnlhTmkUimCfP4bVR/7lrlXMNwA2sJP8ZWpkAo/BtAz" +
|
||||
"vvp4O//HLWLixLvCwj2bqkpDcdIAmXWSdPfqp8q2Ex3pV05AsBm5/2kfdxxuk7ca" +
|
||||
"Ik1YB957+cl6A8rReV7gWXXXi9qJAgMBAAECgYBJpwp2gHHoHlxaJs2p4Vl6stgS" +
|
||||
"FWR6o60+wf82KL/G64RbyfdrJRvUJRS2nBZO5zIqb8YFKfvuUBYJLqYsZkcGA58H" +
|
||||
"rxIt18bwdtbF3NEgPNLfnMhisD4KcMeBWySe+OlITiFY2IVMtCHAGT/lhSphkTru" +
|
||||
"UoRc4VfmFRLBy3g/hQJBAN0HeuFQS2zXeAItc6E7YoInTQb01Fm4Ax1pmViQQCke" +
|
||||
"Z6+Qe15jvktlppYJ0DM96lSPpDcBDJeMqM9vu5anBo8CQQDbXwo1VEkE+cROU+Cc" +
|
||||
"0YqvxDFJonp9iDza2ZzO1ilo0lLZWKYdG41gFDdSACwCNFq39X769c+eCV2b5iH6" +
|
||||
"J9lnAkEAvrrarZ1lSMnydCaWljYxflC9plgU+krQ3UunmQX5Z8ImBRjvbHcz2cog" +
|
||||
"424abG1sTYYaVaChJhGqBj7LqGf/PwJBAIlo18Ed4XsvZEpX+drg2klM0D66epWF" +
|
||||
"L/E53CInPdr9241vHOYgqwaiwyAnIWnkF2shaH+UV487eJo9pczHB0MCQQCwqgF6" +
|
||||
"rs6IyoFb/acqVm0mH5o6ROPthW5CobjoO7R3YcKQ1Mr5iHZcYKOPTnibLOlclEsH" +
|
||||
"CrPUk5sdCSkjd9NP";
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package cn.com.do1.component.bi.gateway.ctl;
|
||||
|
||||
import cn.com.do1.component.bi.gateway.config.ReqDecryptAndRespEncryptConfig;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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("/env")
|
||||
public class GatewayController {
|
||||
@Autowired
|
||||
private ReqDecryptAndRespEncryptConfig reqDecryptAndRespEncryptConfig;
|
||||
|
||||
@GetMapping("secret")
|
||||
public ResponseEntity<String> secret() {
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("code",0);
|
||||
JSONObject sonJson = new JSONObject();
|
||||
if(reqDecryptAndRespEncryptConfig.getReqDecrypt() || reqDecryptAndRespEncryptConfig.getRespEncrypt()){
|
||||
sonJson.put("reqDecrypt",reqDecryptAndRespEncryptConfig.getReqDecrypt());
|
||||
sonJson.put("respEncrypt",reqDecryptAndRespEncryptConfig.getRespEncrypt());
|
||||
sonJson.put("publicKey", reqDecryptAndRespEncryptConfig.getRsaPublicKey());
|
||||
sonJson.put("privateKey", reqDecryptAndRespEncryptConfig.getRsaPrivateKey());
|
||||
}
|
||||
json.put("data",sonJson);
|
||||
return ResponseEntity.ok(json.toString());
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
package cn.com.do1.component.bi.gateway.filter;
|
||||
|
||||
import cn.com.do1.component.bi.gateway.config.ReqDecryptAndRespEncryptConfig;
|
||||
import cn.com.do1.component.bi.gateway.util.SpringContextUtils;
|
||||
import cn.com.do1.component.bi.gateway.util.encrypt.AESEncryptUtil;
|
||||
import cn.com.do1.component.bi.gateway.util.encrypt.RSAEncryptUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilter;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||
import org.springframework.cloud.gateway.filter.factory.rewrite.CachedBodyOutputMessage;
|
||||
import org.springframework.cloud.gateway.support.BodyInserterContext;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
|
||||
import org.springframework.web.reactive.function.BodyInserter;
|
||||
import org.springframework.web.reactive.function.BodyInserters;
|
||||
import org.springframework.web.reactive.function.server.HandlerStrategies;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@DependsOn("reqDecryptAndRespEncryptConfig")
|
||||
public class ReqDecryptFilter implements GatewayFilter, Ordered {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ReqDecryptFilter.class);
|
||||
|
||||
private int order;
|
||||
|
||||
private static ReqDecryptAndRespEncryptConfig reqDecryptAndRespEncryptConfig = null;
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||
if(reqDecryptAndRespEncryptConfig == null){
|
||||
reqDecryptAndRespEncryptConfig = SpringContextUtils.getBean("reqDecryptAndRespEncryptConfig");
|
||||
}
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
if(!reqDecryptAndRespEncryptConfig.getReqDecrypt()){
|
||||
//关闭解密
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
if(reqDecryptAndRespEncryptConfig.getWhiteUrl().size()>0){
|
||||
for(String url : reqDecryptAndRespEncryptConfig.getWhiteUrl()){
|
||||
if(request.getURI().getPath().startsWith(url)){
|
||||
//白名单url直接跳过
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
}
|
||||
}
|
||||
HttpMethod requestMethod = request.getMethod();
|
||||
if (!HttpMethod.POST.equals(requestMethod) && !HttpMethod.PUT.equals(requestMethod)) {
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
// 获取请求的Content-Type
|
||||
String contentType = request.getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
|
||||
if (!MediaType.APPLICATION_JSON_VALUE.equals(contentType)) {
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
return readBody(exchange, chain);
|
||||
}
|
||||
ServerHttpRequestDecorator decorate(ServerWebExchange exchange, HttpHeaders headers, CachedBodyOutputMessage outputMessage) {
|
||||
return new ServerHttpRequestDecorator(exchange.getRequest()) {
|
||||
public HttpHeaders getHeaders() {
|
||||
long contentLength = headers.getContentLength();
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.putAll(super.getHeaders());
|
||||
if (contentLength > 0L) {
|
||||
httpHeaders.setContentLength(contentLength);
|
||||
} else {
|
||||
httpHeaders.set("Transfer-Encoding", "chunked");
|
||||
}
|
||||
return httpHeaders;
|
||||
}
|
||||
public Flux<DataBuffer> getBody() {
|
||||
return outputMessage.getBody();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private Mono<Void> returnMononew(GatewayFilterChain chain,ServerWebExchange exchange){
|
||||
return chain.filter(exchange).then(Mono.fromRunnable(()->{
|
||||
}));
|
||||
}
|
||||
private Mono<Void> readBody(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||
//重新构造request,参考ModifyRequestBodyGatewayFilterFactory
|
||||
ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
|
||||
//重点
|
||||
Mono<String> modifiedBody = serverRequest.bodyToMono(String.class).flatMap(body -> {
|
||||
String newBody = decryptAES(body);
|
||||
return Mono.just(newBody);
|
||||
});
|
||||
BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.putAll(exchange.getRequest().getHeaders());
|
||||
//猜测这个就是之前报400错误的元凶,之前修改了body但是没有重新写content length
|
||||
headers.remove("Content-Length");
|
||||
CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);
|
||||
return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {
|
||||
ServerHttpRequest decorator = this.decorate(exchange, headers, outputMessage);
|
||||
return returnMononew(chain, exchange.mutate().request(decorator).build());
|
||||
}));
|
||||
}
|
||||
private String decryptAES(String encryptedText) {
|
||||
// 解密逻辑
|
||||
JSONObject param = JSONObject.parseObject(encryptedText);
|
||||
if(param.containsKey("encrypted") && param.containsKey("requestData")){
|
||||
try {
|
||||
String clientKey = RSAEncryptUtil.decryptByPrivateKey(param.getString("encrypted"),reqDecryptAndRespEncryptConfig.getRsaPrivateKey());
|
||||
return AESEncryptUtil.decrypt(param.getString("requestData"), clientKey);
|
||||
} catch (Exception e) {
|
||||
logger.error("解密接口出现问题",e);
|
||||
}
|
||||
}else{
|
||||
logger.debug("需要解密内容为空");
|
||||
}
|
||||
return encryptedText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return this.order;
|
||||
}
|
||||
|
||||
|
||||
public ReqDecryptFilter(int order){
|
||||
this.order = order;
|
||||
}
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
package cn.com.do1.component.bi.gateway.filter;
|
||||
|
||||
import cn.com.do1.component.bi.gateway.config.ReqDecryptAndRespEncryptConfig;
|
||||
import cn.com.do1.component.bi.gateway.util.RandomStringUtils;
|
||||
import cn.com.do1.component.bi.gateway.util.SpringContextUtils;
|
||||
import cn.com.do1.component.bi.gateway.util.encrypt.AESEncryptUtil;
|
||||
import cn.com.do1.component.bi.gateway.util.encrypt.RSAEncryptUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilter;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class RespEncryptFilter implements GatewayFilter, Ordered {
|
||||
private static final Logger logger = LoggerFactory.getLogger(RespEncryptFilter.class);
|
||||
|
||||
private int order;
|
||||
private static ReqDecryptAndRespEncryptConfig reqDecryptAndRespEncryptConfig = null;
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
if(reqDecryptAndRespEncryptConfig == null){
|
||||
reqDecryptAndRespEncryptConfig = SpringContextUtils.getBean("reqDecryptAndRespEncryptConfig");
|
||||
}
|
||||
if(!reqDecryptAndRespEncryptConfig.getRespEncrypt()){
|
||||
//关闭解密
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
if(reqDecryptAndRespEncryptConfig.getWhiteUrl().size()>0){
|
||||
for(String url : reqDecryptAndRespEncryptConfig.getWhiteUrl()){
|
||||
if(request.getURI().getPath().startsWith(url)){
|
||||
//白名单url直接跳过
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
}
|
||||
}
|
||||
ServerHttpResponse originalResponse = exchange.getResponse();
|
||||
originalResponse.getHeaders().setContentType(MediaType.APPLICATION_JSON);
|
||||
DataBufferFactory bufferFactory = originalResponse.bufferFactory();
|
||||
ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
|
||||
@Override
|
||||
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
|
||||
if (getStatusCode().equals(HttpStatus.OK) && body instanceof Flux) {
|
||||
Flux<? extends DataBuffer> fluxBody = Flux.from(body);
|
||||
return super.writeWith(fluxBody.buffer().map(dataBuffer -> {
|
||||
DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
|
||||
DataBuffer join = dataBufferFactory.join(dataBuffer);
|
||||
byte[] content = new byte[join.readableByteCount()];
|
||||
join.read(content);
|
||||
//释放掉内存
|
||||
DataBufferUtils.release(join);
|
||||
// 正常返回的数据
|
||||
String rootData = new String(content, StandardCharsets.UTF_8);
|
||||
logger.debug("--------"+request.getURI().getPath()+";"+rootData);
|
||||
JSONObject result = JSONObject.parseObject(rootData);
|
||||
if(!result.containsKey("code")){
|
||||
return bufferFactory.wrap(rootData.getBytes());
|
||||
}
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("code", result.getInteger("code"));
|
||||
json.put("message", result.getString("message"));
|
||||
json.put("traceId", result.getString("traceId"));
|
||||
try {
|
||||
String data = result.getString("data");
|
||||
if(result.containsKey("code") && 0 == result.getInteger("code") && StringUtils.hasLength(data)){
|
||||
String aesKey = RandomStringUtils.generateRandomString(16);
|
||||
String key = RSAEncryptUtil.encryptByPublicKeyToBase64(aesKey.getBytes(),reqDecryptAndRespEncryptConfig.getRsaPublicKey());
|
||||
String encryptData = AESEncryptUtil.encrypt(data,aesKey);
|
||||
JSONObject sonJson = new JSONObject();
|
||||
sonJson.put("encrypted", key);
|
||||
sonJson.put("responseData", encryptData);
|
||||
json.put("data",sonJson);
|
||||
}else{
|
||||
json.put("data", null);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("加密response失败",e);
|
||||
}
|
||||
// 加密后的数据返回给客户端
|
||||
byte[] uppedContent = json.toJSONString().getBytes(StandardCharsets.UTF_8);
|
||||
originalResponse.getHeaders().setContentLength(uppedContent.length);
|
||||
return bufferFactory.wrap(uppedContent);
|
||||
}));
|
||||
}
|
||||
return super.writeWith(body);
|
||||
}
|
||||
};
|
||||
return chain.filter(exchange.mutate().response(decoratedResponse).build());
|
||||
}
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return this.order;
|
||||
}
|
||||
|
||||
public RespEncryptFilter(int order){
|
||||
this.order = order;
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package cn.com.do1.component.bi.gateway.util;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class RandomStringUtils {
|
||||
|
||||
private static final String CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
|
||||
public static String generateRandomString(int length) {
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
Random random = new Random();
|
||||
for (int i = 0; i < length; i++) {
|
||||
int index = random.nextInt(CHARACTERS.length());
|
||||
sb.append(CHARACTERS.charAt(index));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package cn.com.do1.component.bi.gateway.util;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class SpringContextUtils implements ApplicationContextAware {
|
||||
private static ApplicationContext applicationContext;
|
||||
|
||||
public SpringContextUtils() {
|
||||
}
|
||||
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
SpringContextUtils.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
public static ApplicationContext getContext() {
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
public static <T> T getBean(String name) {
|
||||
return (T) applicationContext.getBean(name);
|
||||
}
|
||||
|
||||
public static <T> T getBean(Class<T> clazz) {
|
||||
return applicationContext.getBean(clazz);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package cn.com.do1.component.bi.gateway.util.encrypt;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.IOException;
|
||||
import java.util.Base64;
|
||||
|
||||
@Slf4j
|
||||
public class AESEncryptUtil {
|
||||
|
||||
public AESEncryptUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
* @param input
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public static String encrypt(String input, String key) {
|
||||
|
||||
String result = null;
|
||||
try {
|
||||
byte[] crypted = null;
|
||||
SecretKeySpec skey = new SecretKeySpec(key.getBytes(), "AES");
|
||||
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, skey);
|
||||
crypted = cipher.doFinal(input.getBytes("UTF-8"));
|
||||
result = encryptBASE64(crypted);
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.toString());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public static void main(String[] args) throws Exception {
|
||||
String key = "niaze7pp0zho1mgp";
|
||||
String str = encrypt("{\"type\":2,\"pageSize\":50,\"currPage\":1}",key);
|
||||
System.out.println(str);
|
||||
System.out.println(decrypt(str,key));
|
||||
}
|
||||
/**
|
||||
* 解密
|
||||
* @param input
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public static String decrypt(String input, String key) {
|
||||
String result = null;
|
||||
try {
|
||||
byte[] output = null;
|
||||
SecretKeySpec skey = new SecretKeySpec(key.getBytes(), "AES");
|
||||
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
||||
cipher.init(Cipher.DECRYPT_MODE, skey);
|
||||
output = cipher.doFinal(decryptBASE64(input));
|
||||
result = new String(output, "UTF-8");
|
||||
} catch (Exception e) {
|
||||
log.info(e.toString());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static byte[] decryptBASE64(String key) throws IOException {
|
||||
return Base64.getDecoder().decode(key);
|
||||
}
|
||||
|
||||
public static String encryptBASE64(byte[] key) {
|
||||
return Base64.getEncoder().encodeToString(key);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
package cn.com.do1.component.bi.gateway.util.encrypt;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.Key;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class RSAEncryptUtil {
|
||||
private static final Logger logger = LoggerFactory.getLogger(RSAEncryptUtil.class);
|
||||
public RSAEncryptUtil() {
|
||||
}
|
||||
|
||||
public static String encryptBASE64(byte[] key) {
|
||||
return Base64.getEncoder().encodeToString(key);
|
||||
}
|
||||
|
||||
public static byte[] decryptBASE64(String key) {
|
||||
return Base64.getDecoder().decode(key);
|
||||
}
|
||||
|
||||
public static Map<String, Object> initKey() throws Exception {
|
||||
Map<String, Object> keyMap = new HashMap(2);
|
||||
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGen.initialize(1024);
|
||||
KeyPair keyPair = keyPairGen.generateKeyPair();
|
||||
RSAPublicKey publicKey = (RSAPublicKey)keyPair.getPublic();
|
||||
RSAPrivateKey privateKey = (RSAPrivateKey)keyPair.getPrivate();
|
||||
keyMap.put("RSAPublicKey", publicKey);
|
||||
keyMap.put("RSAPrivateKey", privateKey);
|
||||
return keyMap;
|
||||
}
|
||||
|
||||
public static String getPrivateKey(Map<String, Object> keyMap) {
|
||||
Key key = (Key)keyMap.get("RSAPrivateKey");
|
||||
return encryptBASE64(key.getEncoded());
|
||||
}
|
||||
|
||||
public static String getPublicKey(Map<String, Object> keyMap) {
|
||||
Key key = (Key)keyMap.get("RSAPublicKey");
|
||||
return encryptBASE64(key.getEncoded());
|
||||
}
|
||||
|
||||
public static byte[] decryptByPublicKey(byte[] data, String key) throws Exception {
|
||||
byte[] keyBytes = decryptBASE64(key);
|
||||
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
Key publicKey = keyFactory.generatePublic(x509KeySpec);
|
||||
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
||||
cipher.init(2, publicKey);
|
||||
return cipher.doFinal(data);
|
||||
}
|
||||
|
||||
public static String decryptByPrivateKey(String data, String key) throws Exception {
|
||||
byte[] keyBytes = decryptBASE64(key);
|
||||
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
|
||||
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
||||
cipher.init(2, privateKey);
|
||||
//当长度过长的时候,需要分割后解密 128个字节
|
||||
return new String(getMaxResultDecrypt(data, cipher));
|
||||
}
|
||||
|
||||
private static byte[] getMaxResultDecrypt(String data, Cipher cipher) throws IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
|
||||
byte[] inputArray = decryptBASE64(data);
|
||||
int inputLength = inputArray.length;
|
||||
// 最大解密字节数,超出最大字节数需要分组加密
|
||||
int MAX_ENCRYPT_BLOCK = 128;
|
||||
// 标识
|
||||
int offSet = 0;
|
||||
byte[] resultBytes = {};
|
||||
byte[] cache = {};
|
||||
while (inputLength - offSet > 0) {
|
||||
if (inputLength - offSet > MAX_ENCRYPT_BLOCK) {
|
||||
cache = cipher.doFinal(inputArray, offSet, MAX_ENCRYPT_BLOCK);
|
||||
offSet += MAX_ENCRYPT_BLOCK;
|
||||
} else {
|
||||
cache = cipher.doFinal(inputArray, offSet, inputLength - offSet);
|
||||
offSet = inputLength;
|
||||
}
|
||||
resultBytes = Arrays.copyOf(resultBytes, resultBytes.length + cache.length);
|
||||
System.arraycopy(cache, 0, resultBytes, resultBytes.length - cache.length, cache.length);
|
||||
}
|
||||
return resultBytes;
|
||||
}
|
||||
|
||||
public static byte[] encryptByPublicKey(byte[] data, String key) throws Exception {
|
||||
byte[] keyBytes = decryptBASE64(key);
|
||||
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
Key publicKey = keyFactory.generatePublic(x509KeySpec);
|
||||
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
||||
cipher.init(1, publicKey);
|
||||
return cipher.doFinal(data);
|
||||
}
|
||||
|
||||
public static byte[] encryptByPrivateKey(byte[] data, String key) throws Exception {
|
||||
byte[] keyBytes = decryptBASE64(key);
|
||||
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
|
||||
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
||||
cipher.init(1, privateKey);
|
||||
return cipher.doFinal(data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Map<String, Object> keyMap = initKey();
|
||||
String publicKey = getPublicKey(keyMap);
|
||||
String privateKey = getPrivateKey(keyMap);
|
||||
System.out.println("公钥: \n\r" + publicKey);
|
||||
String str = encryptByPublicKeyToBase64("crkXipxtMn5I4KXwwLMkeA==".getBytes(),publicKey);
|
||||
System.out.println("公钥加密后: \n\r" + str);
|
||||
System.out.println("私钥: \n\r" + privateKey);
|
||||
//System.out.println("私钥解密后: \n\r" + decryptByPrivateKey(str.getBytes(),privateKey));
|
||||
}
|
||||
|
||||
public static String encryptByPublicKeyToBase64(byte[] data, String key) throws Exception {
|
||||
byte[] keyBytes = decryptBASE64(key);
|
||||
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
Key publicKey = keyFactory.generatePublic(x509KeySpec);
|
||||
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
||||
cipher.init(1, publicKey);
|
||||
return Base64.getEncoder().encodeToString(cipher.doFinal(data));
|
||||
}
|
||||
}
|
32
src/main/resources/bootstrap-dev.yml
Normal file
32
src/main/resources/bootstrap-dev.yml
Normal file
@ -0,0 +1,32 @@
|
||||
server:
|
||||
port: 80
|
||||
spring:
|
||||
application:
|
||||
name: bi-gateway
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 192.168.83.10:32610
|
||||
namespace: bi-system
|
||||
config:
|
||||
server-addr: 192.168.83.10:32610
|
||||
file-extension: yml
|
||||
namespace: bi-system
|
||||
group: DEFAULT_GROUP
|
||||
# 配置组,优先级从上至下递增,最下方的优先级最高
|
||||
shared-configs:
|
||||
- data-id: global.yml
|
||||
- data-id: bi-gateway.yml
|
||||
|
||||
gateway:
|
||||
discovery:
|
||||
locator:
|
||||
enabled: true
|
||||
lower-case-service-id: true #小写的服务名称
|
||||
predicates[0]:
|
||||
name: Path
|
||||
args[pattern]: "'/'+ serviceId.replace('bi-', '') +'/**'"
|
||||
filters[0]:
|
||||
name: CustomRewritePath
|
||||
args[regexp]: "'/' + serviceId.replace('bi-', '') + '/(?<remaining>.*)'"
|
||||
args[replacement]: "'/${remaining}'"
|
42
src/main/resources/bootstrap-home.yml
Normal file
42
src/main/resources/bootstrap-home.yml
Normal file
@ -0,0 +1,42 @@
|
||||
server:
|
||||
port: 80
|
||||
spring:
|
||||
application:
|
||||
name: saas-cpn-gateway
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 127.0.0.1:8848
|
||||
config:
|
||||
server-addr: 127.0.0.1:8848
|
||||
file-extension: properties
|
||||
namespace: public
|
||||
group: DEFAULT_GROUP
|
||||
extension-configs[0]:
|
||||
data-id: redis.properties
|
||||
group: DEFAULT_GROUP
|
||||
refresh: true
|
||||
extension-configs[1]:
|
||||
data-id: global.properties
|
||||
group: DEFAULT_GROUP
|
||||
refresh: true
|
||||
gateway:
|
||||
discovery:
|
||||
locator:
|
||||
enabled: true
|
||||
lower-case-service-id: true #小写的服务名称
|
||||
predicates[0]:
|
||||
name: Path
|
||||
args[pattern]: "'/'+serviceId+'/**'"
|
||||
filters[0]:
|
||||
name: CustomRewritePath
|
||||
args[regexp]: "'/' + serviceId + '/?(?<remaining>.*)'"
|
||||
args[replacement]: "'/${remaining}'"
|
||||
routes:
|
||||
- id: default_to_all
|
||||
uri: lb://saas-dubbo-all-application
|
||||
order: 10
|
||||
predicates:
|
||||
- Path=/**
|
||||
filters:
|
||||
- RewritePath=/saas-dubbo-[-\w]+/, /
|
32
src/main/resources/bootstrap-local.yml
Normal file
32
src/main/resources/bootstrap-local.yml
Normal file
@ -0,0 +1,32 @@
|
||||
server:
|
||||
port: 80
|
||||
spring:
|
||||
application:
|
||||
name: bi-gateway
|
||||
# profiles:
|
||||
# active: local #启动环境 dev:开发环境 local:本地环境 prod:prod环境
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 192.168.83.10:32610
|
||||
namespace: bi-system-local
|
||||
config:
|
||||
server-addr: 192.168.83.10:32610
|
||||
file-extension: yml
|
||||
namespace: bi-system-local
|
||||
group: DEFAULT_GROUP
|
||||
# 配置组,优先级从上至下递增,最下方的优先级最高
|
||||
shared-configs:
|
||||
- data-id: bi-gateway.yml
|
||||
gateway:
|
||||
discovery:
|
||||
locator:
|
||||
enabled: true
|
||||
lower-case-service-id: true #小写的服务名称
|
||||
predicates[0]:
|
||||
name: Path
|
||||
args[pattern]: "'/'+ serviceId.replace('bi-', '') +'/**'"
|
||||
filters[0]:
|
||||
name: CustomRewritePath
|
||||
args[regexp]: "'/' + serviceId.replace('bi-', '') + '/(?<remaining>.*)'"
|
||||
args[replacement]: "'/${remaining}'"
|
27
src/main/resources/bootstrap-qa.yml
Normal file
27
src/main/resources/bootstrap-qa.yml
Normal file
@ -0,0 +1,27 @@
|
||||
server:
|
||||
port: 80
|
||||
spring:
|
||||
application:
|
||||
name: bi-gateway
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 192.168.83.10:32610
|
||||
namespace: bi-system
|
||||
config:
|
||||
server-addr: 192.168.83.10:32610
|
||||
file-extension: yml
|
||||
namespace: bi-system
|
||||
group: DEFAULT_GROUP
|
||||
gateway:
|
||||
discovery:
|
||||
locator:
|
||||
enabled: true
|
||||
lower-case-service-id: true #小写的服务名称
|
||||
predicates[0]:
|
||||
name: Path
|
||||
args[pattern]: "'/'+ serviceId.replace('bi-', '') +'/**'"
|
||||
filters[0]:
|
||||
name: CustomRewritePath
|
||||
args[regexp]: "'/' + serviceId.replace('bi-', '') + '/(?<remaining>.*)'"
|
||||
args[replacement]: "'/${remaining}'"
|
49
src/main/resources/bootstrap-sentinel.yml
Normal file
49
src/main/resources/bootstrap-sentinel.yml
Normal file
@ -0,0 +1,49 @@
|
||||
spring:
|
||||
cloud:
|
||||
sentinel:
|
||||
enabled: false # sentinel开关
|
||||
eager: false
|
||||
transport:
|
||||
port: 8089
|
||||
dashboard: http://127.0.0.1:8858 # Sentinel控制台地址
|
||||
datasource:
|
||||
# 流控规则
|
||||
flow:
|
||||
nacos:
|
||||
server-addr: ${spring.cloud.nacos.discovery.server-addr}
|
||||
dataId: ${spring.application.name}-flow-rules
|
||||
namespace: sentinel
|
||||
file-extension: json
|
||||
rule-type: flow
|
||||
# 降级规则
|
||||
degrade:
|
||||
nacos:
|
||||
server-addr: ${spring.cloud.nacos.discovery.server-addr}
|
||||
dataId: ${spring.application.name}-degrade-rules
|
||||
namespace: sentinel
|
||||
file-extension: json
|
||||
rule-type: degrade
|
||||
# 热点规则
|
||||
param-flow:
|
||||
nacos:
|
||||
server-addr: ${spring.cloud.nacos.discovery.server-addr}
|
||||
dataId: ${spring.application.name}-param-flow-rules
|
||||
namespace: sentinel
|
||||
file-extension: json
|
||||
rule-type: param-flow
|
||||
# 系统规则
|
||||
system:
|
||||
nacos:
|
||||
server-addr: ${spring.cloud.nacos.discovery.server-addr}
|
||||
dataId: ${spring.application.name}-system-rules
|
||||
namespace: sentinel
|
||||
file-extension: json
|
||||
rule-type: system
|
||||
# 授权规则
|
||||
authority:
|
||||
nacos:
|
||||
server-addr: ${spring.cloud.nacos.discovery.server-addr}
|
||||
dataId: ${spring.application.name}-authority-rules
|
||||
namespace: sentinel
|
||||
file-extension: json
|
||||
rule-type: authority
|
27
src/main/resources/bootstrap-uat.yml
Normal file
27
src/main/resources/bootstrap-uat.yml
Normal file
@ -0,0 +1,27 @@
|
||||
server:
|
||||
port: 80
|
||||
spring:
|
||||
application:
|
||||
name: bi-gateway
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 192.168.83.10:32610
|
||||
namespace: bi-system
|
||||
config:
|
||||
server-addr: 192.168.83.10:32610
|
||||
file-extension: yml
|
||||
namespace: bi-system
|
||||
group: DEFAULT_GROUP
|
||||
gateway:
|
||||
discovery:
|
||||
locator:
|
||||
enabled: true
|
||||
lower-case-service-id: true #小写的服务名称
|
||||
predicates[0]:
|
||||
name: Path
|
||||
args[pattern]: "'/'+ serviceId.replace('bi-', '') +'/**'"
|
||||
filters[0]:
|
||||
name: CustomRewritePath
|
||||
args[regexp]: "'/' + serviceId.replace('bi-', '') + '/(?<remaining>.*)'"
|
||||
args[replacement]: "'/${remaining}'"
|
43
src/main/resources/bootstrap-ybg.yml
Normal file
43
src/main/resources/bootstrap-ybg.yml
Normal file
@ -0,0 +1,43 @@
|
||||
server:
|
||||
port: 80
|
||||
spring:
|
||||
application:
|
||||
name: saas-cpn-gateway
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 192.168.83.219:8848
|
||||
namespace: ybg
|
||||
config:
|
||||
server-addr: 192.168.83.219:8848
|
||||
file-extension: properties
|
||||
namespace: ybg
|
||||
group: DEFAULT_GROUP
|
||||
extension-configs[0]:
|
||||
data-id: redis.properties
|
||||
group: DEFAULT_GROUP
|
||||
refresh: true
|
||||
extension-configs[1]:
|
||||
data-id: global.properties
|
||||
group: DEFAULT_GROUP
|
||||
refresh: true
|
||||
gateway:
|
||||
discovery:
|
||||
locator:
|
||||
enabled: true
|
||||
lower-case-service-id: true #小写的服务名称
|
||||
predicates[0]:
|
||||
name: Path
|
||||
args[pattern]: "'/'+serviceId+'/**'"
|
||||
filters[0]:
|
||||
name: CustomRewritePath
|
||||
args[regexp]: "'/' + serviceId + '/?(?<remaining>.*)'"
|
||||
args[replacement]: "'/${remaining}'"
|
||||
routes:
|
||||
- id: default_to_all
|
||||
uri: lb://wxqyh
|
||||
order: 10
|
||||
predicates:
|
||||
- Path=/**
|
||||
filters:
|
||||
- RewritePath=/saas-dubbo-[-\w]+/, /
|
34
src/main/resources/bootstrap.yml
Normal file
34
src/main/resources/bootstrap.yml
Normal file
@ -0,0 +1,34 @@
|
||||
server:
|
||||
port: 80
|
||||
spring:
|
||||
application:
|
||||
name: bi-gateway
|
||||
profiles:
|
||||
active: local #启动环境 dev:开发环境 local:本地环境 prod:prod环境
|
||||
include: sentinel
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 192.168.83.10:32610
|
||||
namespace: bi-system
|
||||
config:
|
||||
server-addr: 192.168.83.10:32610
|
||||
file-extension: yml
|
||||
namespace: bi-system
|
||||
group: DEFAULT_GROUP
|
||||
# 配置组,优先级从上至下递增,最下方的优先级最高
|
||||
shared-configs:
|
||||
- data-id: global.yml
|
||||
- data-id: bi-gateway.yml
|
||||
gateway:
|
||||
discovery:
|
||||
locator:
|
||||
enabled: true
|
||||
lower-case-service-id: true #小写的服务名称
|
||||
predicates[0]:
|
||||
name: Path
|
||||
args[pattern]: "'/'+ serviceId.replace('bi-', '') +'/**'"
|
||||
filters[0]:
|
||||
name: CustomRewritePath
|
||||
args[regexp]: "'/' + serviceId.replace('bi-', '') + '/(?<remaining>.*)'"
|
||||
args[replacement]: "'/${remaining}'"
|
78
src/main/resources/logback-logstash.xml
Normal file
78
src/main/resources/logback-logstash.xml
Normal file
@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<springProperty scope="context" name="application" source="spring.application.name"/>
|
||||
<springProperty scope="context" name="profile" source="spring.profiles.active"/>
|
||||
|
||||
<springProperty scope="context" name="logStashEnable" source="logging.logstash.enable" defaultValue="false"/>
|
||||
<springProperty scope="context" name="logStashHost" source="logging.logstash.host"/>
|
||||
<springProperty scope="context" name="logStashPort" source="logging.logstash.port"/>
|
||||
<springProperty scope="context" name="LOG_HOME" source="logging.file" defaultValue="./logs"/>
|
||||
|
||||
|
||||
<property name="LOG_PATTERN"
|
||||
value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%level %thread] [%X{traceId}-%X{spanId}] %logger{50} - %msg %n" />
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
<!-- 按照每天生成日志文件 -->
|
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!--日志文件输出的文件名-->
|
||||
<FileNamePattern>${LOG_HOME}/${application}.log.%d{yyyy-MM-dd}.%i</FileNamePattern>
|
||||
<timeBasedFileNamingAndTriggeringPolicy
|
||||
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<!-- or whenever the file size reaches 10MB -->
|
||||
<maxFileSize>1024MB</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
<!--日志文件保留天数-->
|
||||
<MaxHistory>30</MaxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
<if condition='property("logStashEnable").contains("true")'>
|
||||
<then>
|
||||
<!-- Appender to log to file in a JSON format -->
|
||||
<appender name="logStash" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
|
||||
<destination>${logStashHost}:${logStashPort}</destination>
|
||||
<encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder"/>
|
||||
</appender>
|
||||
</then>
|
||||
</if>
|
||||
|
||||
<!-- 开发、测试环境 -->
|
||||
<springProfile name="dev,test,local,poc,qa">
|
||||
<logger name="org.springframework.web" level="INFO"/>
|
||||
<logger name="org.springboot.sample" level="INFO" />
|
||||
<logger name="cn.com.do1.component" level="INFO"/>
|
||||
<logger name="com.alibaba.nacos.client.naming" level="ERROR" />
|
||||
<logger name="cn.com.do1.component" level="DEBUG"/>
|
||||
</springProfile>
|
||||
|
||||
<!-- 生产环境 -->
|
||||
<springProfile name="prod">
|
||||
<logger name="org.springframework.web" level="ERROR"/>
|
||||
<logger name="org.springboot.sample" level="ERROR" />
|
||||
<logger name="com.alibaba.nacos.client.naming" level="ERROR" />
|
||||
<logger name="cn.com.do1.component" level="ERROR" />
|
||||
</springProfile>
|
||||
|
||||
<!-- 日志输出级别 -->
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="FILE"/>
|
||||
<if condition='property("logStashEnable").contains("true")'>
|
||||
<then>
|
||||
<appender-ref ref="logStash"/>
|
||||
</then>
|
||||
</if>
|
||||
</root>
|
||||
|
||||
</configuration>
|
Loading…
x
Reference in New Issue
Block a user