Commit afc80a49d43fc6a348e811ac2e3c12a67dc5a8eb

Authored by miaoguoxin
0 parents

gateway-service

Showing 57 changed files with 2743 additions and 0 deletions
doc/xtrade-gateway说明.docx 0 → 100644
No preview for this file type
pom.xml 0 → 100644
  1 +++ a/pom.xml
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4 + <modelVersion>4.0.0</modelVersion>
  5 + <parent>
  6 + <groupId>org.springframework.boot</groupId>
  7 + <artifactId>spring-boot-starter-parent</artifactId>
  8 + <version>2.2.5.RELEASE</version>
  9 + <relativePath/> <!-- lookup parent from repository -->
  10 + </parent>
  11 + <groupId>com.diligrp</groupId>
  12 + <artifactId>xtrade-gateway-service</artifactId>
  13 + <version>1.0.0</version>
  14 + <name>gateway-service</name>
  15 + <description>Demo project for Spring Boot</description>
  16 +
  17 + <properties>
  18 + <java.version>11</java.version>
  19 + <spring-cloud.version>Hoxton.SR3</spring-cloud.version>
  20 + <spring-cloud-alibaba.version>2.2.0.RELEASE</spring-cloud-alibaba.version>
  21 + <mybatis-starter.version>2.1.2</mybatis-starter.version>
  22 + </properties>
  23 +
  24 + <dependencies>
  25 + <dependency>
  26 + <groupId>com.diligrp</groupId>
  27 + <artifactId>xtrade-shared-spring-boot-starter</artifactId>
  28 + <version>0.0.1</version>
  29 + </dependency>
  30 + <dependency>
  31 + <groupId>org.springframework.boot</groupId>
  32 + <artifactId>spring-boot-configuration-processor</artifactId>
  33 + <optional>true</optional>
  34 + </dependency>
  35 + <!-- <dependency>
  36 + <groupId>org.springframework.boot</groupId>
  37 + <artifactId>spring-boot-starter-cache</artifactId>
  38 + </dependency>
  39 + <dependency>
  40 + <groupId>net.sf.ehcache</groupId>
  41 + <artifactId>ehcache</artifactId>
  42 + </dependency>-->
  43 + <dependency>
  44 + <groupId>org.mybatis.spring.boot</groupId>
  45 + <artifactId>mybatis-spring-boot-starter</artifactId>
  46 + <version>${mybatis-starter.version}</version>
  47 + </dependency>
  48 + <dependency>
  49 + <groupId>org.reflections</groupId>
  50 + <artifactId>reflections</artifactId>
  51 + <version>0.9.11</version>
  52 + </dependency>
  53 + <dependency>
  54 + <groupId>org.springframework.cloud</groupId>
  55 + <artifactId>spring-cloud-starter-gateway</artifactId>
  56 + </dependency>
  57 + <dependency>
  58 + <groupId>org.projectlombok</groupId>
  59 + <artifactId>lombok</artifactId>
  60 + <optional>true</optional>
  61 + </dependency>
  62 + <dependency>
  63 + <groupId>com.alibaba.cloud</groupId>
  64 + <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  65 + </dependency>
  66 + <dependency>
  67 + <groupId>com.alibaba.cloud</groupId>
  68 + <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  69 + </dependency>
  70 + <dependency>
  71 + <groupId>org.springframework.boot</groupId>
  72 + <artifactId>spring-boot-starter-test</artifactId>
  73 + <scope>test</scope>
  74 + </dependency>
  75 + <dependency>
  76 + <groupId>org.springframework.boot</groupId>
  77 + <artifactId>spring-boot-starter-data-redis</artifactId>
  78 + </dependency>
  79 + <dependency>
  80 + <groupId>org.apache.commons</groupId>
  81 + <artifactId>commons-pool2</artifactId>
  82 + </dependency>
  83 + <dependency>
  84 + <groupId>com.alibaba.nacos</groupId>
  85 + <artifactId>nacos-api</artifactId>
  86 + <version>1.2.0</version>
  87 + </dependency>
  88 + <dependency>
  89 + <groupId>com.alibaba.nacos</groupId>
  90 + <artifactId>nacos-client</artifactId>
  91 + <version>1.2.0</version>
  92 + </dependency>
  93 +
  94 + </dependencies>
  95 +
  96 + <dependencyManagement>
  97 + <dependencies>
  98 + <dependency>
  99 + <groupId>org.springframework.cloud</groupId>
  100 + <artifactId>spring-cloud-dependencies</artifactId>
  101 + <version>${spring-cloud.version}</version>
  102 + <type>pom</type>
  103 + <scope>import</scope>
  104 + </dependency>
  105 + <dependency>
  106 + <groupId>com.alibaba.cloud</groupId>
  107 + <artifactId>spring-cloud-alibaba-dependencies</artifactId>
  108 + <version>${spring-cloud-alibaba.version}</version>
  109 + <type>pom</type>
  110 + <scope>import</scope>
  111 + </dependency>
  112 + </dependencies>
  113 + </dependencyManagement>
  114 +
  115 + <build>
  116 + <plugins>
  117 + <plugin>
  118 + <groupId>org.springframework.boot</groupId>
  119 + <artifactId>spring-boot-maven-plugin</artifactId>
  120 + </plugin>
  121 + <plugin>
  122 + <groupId>org.apache.maven.plugins</groupId>
  123 + <artifactId>maven-compiler-plugin</artifactId>
  124 + <configuration>
  125 + <source>11</source>
  126 + <target>11</target>
  127 + </configuration>
  128 + </plugin>
  129 + </plugins>
  130 + </build>
  131 +
  132 +</project>
... ...
sql/gateway-1.0.0.sql 0 → 100644
  1 +++ a/sql/gateway-1.0.0.sql
  1 +CREATE TABLE `xtrade_gateway`.`t_route`
  2 +(
  3 + `id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT '主键',
  4 + `service_id` varchar(20) NOT NULL COMMENT '服务id名称',
  5 + `url` varchar(100) NOT NULL COMMENT '目标url',
  6 + `description` varchar(100) NOT NULL DEFAULT 1 COMMENT '描述字段',
  7 + `created_time` datetime(0) NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '创建时间',
  8 + `modified_time` datetime(0) NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '更新时间',
  9 + `is_del` smallint(1) NOT NULL DEFAULT 1 COMMENT '1:删除 0:正常',
  10 + PRIMARY KEY (`id`)
  11 +) COMMENT = '路由表';
  12 +
  13 +ALTER TABLE `xtrade_gateway`.`t_route`
  14 + ADD UNIQUE INDEX `uni_service_id`(`service_id`) USING BTREE COMMENT 'service_id唯一索引';
  15 +
  16 +CREATE TABLE `xtrade_gateway`.`t_attr_config`
  17 +(
  18 + `id` bigint(0) NOT NULL COMMENT '主键',
  19 + `service_id` varchar(20) NOT NULL COMMENT '关联的服务id名称',
  20 + `type` smallint(1) NOT NULL COMMENT '1:predicate 2:filter 详见枚举GatewayAttrType',
  21 + `attr_name` varchar(20) NOT NULL COMMENT 'predicate或者filter的名称',
  22 + `attr_args` varchar(100) NULL COMMENT 'predicate或者filter的所属参数,json格式',
  23 + `description` varchar(100) NULL COMMENT '描述字段',
  24 + `sort_order` smallint(2) NOT NULL DEFAULT 0 COMMENT '排序字段',
  25 + `created_time` datetime(0) NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '创建时间',
  26 + `modified_time` datetime(0) NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '更新时间',
  27 + `is_del` smallint(1) NOT NULL DEFAULT 1 COMMENT '1:删除 0:正常',
  28 + PRIMARY KEY (`id`)
  29 +) COMMENT = 'predicate和filter的配置表';
  30 +
  31 +ALTER TABLE `xtrade_gateway`.`t_attr_config`
  32 + MODIFY COLUMN `order` smallint(2) NOT NULL DEFAULT 0 COMMENT '排序字段' AFTER `desc`;
  33 +
  34 +ALTER TABLE `xtrade_gateway`.`t_attr_config`
  35 + ADD UNIQUE INDEX `uni_service_id&attr_name`(`service_id`, `attr_name`) USING BTREE COMMENT 'service_id和attr_name唯一约束';
... ...
src/main/java/com/diligrp/xtrade/gateway/XtradeGatewayApplication.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/XtradeGatewayApplication.java
  1 +package com.diligrp.xtrade.gateway;
  2 +
  3 +import org.mybatis.spring.annotation.MapperScan;
  4 +import org.springframework.boot.SpringApplication;
  5 +import org.springframework.boot.autoconfigure.SpringBootApplication;
  6 +import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
  7 +import org.springframework.cloud.context.config.annotation.RefreshScope;
  8 +
  9 +@SpringBootApplication
  10 +@EnableDiscoveryClient
  11 +@RefreshScope
  12 +@MapperScan(basePackages = {"com.diligrp.xtrade.gateway.repository.dao"})
  13 +public class XtradeGatewayApplication {
  14 +
  15 + public static void main(String[] args) {
  16 + SpringApplication.run(XtradeGatewayApplication.class, args);
  17 + }
  18 +
  19 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/api/Api.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/api/Api.java
  1 +package com.diligrp.xtrade.gateway.api;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import java.io.Serializable;
  6 +
  7 +/**
  8 + * @Auther: miaoguoxin
  9 + * @Date: 2019/3/31 16:24
  10 + * @Description: 只用于网关api缓存的对象
  11 + */
  12 +@Data
  13 +public class Api implements Serializable {
  14 + /**服务名称*/
  15 + private String serviceId;
  16 +
  17 + private String patternUrl;
  18 + //并发量
  19 + private int replenishRate = 2;
  20 + //容量
  21 + private int burstCapacity = 5;
  22 +
  23 + private Integer state;
  24 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/api/ApiManager.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/api/ApiManager.java
  1 +package com.diligrp.xtrade.gateway.api;
  2 +
  3 +import com.diligrp.xtrade.gateway.config.property.AuthPathProperties;
  4 +import org.springframework.beans.factory.annotation.Autowired;
  5 +import org.springframework.http.server.PathContainer;
  6 +import org.springframework.stereotype.Component;
  7 +import org.springframework.web.util.pattern.PathPattern;
  8 +
  9 +import java.util.List;
  10 +import java.util.Optional;
  11 +import java.util.function.Consumer;
  12 +import java.util.function.Function;
  13 +import java.util.function.Predicate;
  14 +
  15 +/**
  16 + * @Auther: miaoguoxin
  17 + * @Date: 2019/3/26 0026 15:37
  18 + * @Description: 管理api动态配置的工具
  19 + */
  20 +@Component
  21 +public class ApiManager {
  22 +
  23 + @Autowired
  24 + private AuthPathProperties authPathProperties;
  25 +
  26 + public boolean isExcludePathMatch(String path) {
  27 + //没有配置排除path的话,表示不拦截任何path
  28 + PathContainer pathContainer = PathContainer.parsePath(path);
  29 + return Optional.ofNullable(authPathProperties.getExcludePathPatterns())
  30 + .map(pathPatterns -> pathPatterns
  31 + .stream()
  32 + .anyMatch(pattern -> pattern.matches(pathContainer)))
  33 + .orElse(true);
  34 + }
  35 +
  36 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/application/TestAggregationApplication.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/application/TestAggregationApplication.java
  1 +package com.diligrp.xtrade.gateway.application;
  2 +
  3 +import com.diligrp.xtrade.gateway.common.annotation.DispatchMapping;
  4 +import com.diligrp.xtrade.gateway.domain.TestRequestDto;
  5 +import com.diligrp.xtrade.gateway.support.dispatch.DispatchContext;
  6 +import com.diligrp.xtrade.gateway.support.dispatch.RequestDispatcher;
  7 +import org.springframework.stereotype.Component;
  8 +import org.springframework.validation.annotation.Validated;
  9 +
  10 +import javax.validation.groups.Default;
  11 +
  12 +/**
  13 + * @Auther: miaoguoxin
  14 + * @Date: 2020/4/15 09:40
  15 + * @Description: 聚合服务应用层
  16 + * {@link RequestDispatcher}
  17 + */
  18 +@Component
  19 +@DispatchMapping
  20 +public class TestAggregationApplication {
  21 +
  22 + @DispatchMapping("/test")
  23 + public String test(DispatchContext<TestRequestDto> dispatchContext){
  24 + return "ffff";
  25 + }
  26 +
  27 + @DispatchMapping("test2")
  28 + public void test2(@Validated(value = Default.class) DispatchContext<TestRequestDto> dispatchContext){
  29 +
  30 + }
  31 +
  32 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/common/annotation/DispatchMapping.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/common/annotation/DispatchMapping.java
  1 +package com.diligrp.xtrade.gateway.common.annotation;
  2 +
  3 +import java.lang.annotation.Documented;
  4 +import java.lang.annotation.ElementType;
  5 +import java.lang.annotation.Retention;
  6 +import java.lang.annotation.RetentionPolicy;
  7 +import java.lang.annotation.Target;
  8 +
  9 +/**
  10 + * @Auther: miaoguoxin
  11 + * @Date: 2020/4/15 09:24
  12 + * @Description: 用于聚合服务映射
  13 + */
  14 +@Target({ElementType.METHOD, ElementType.TYPE})
  15 +@Retention(RetentionPolicy.RUNTIME)
  16 +@Documented
  17 +public @interface DispatchMapping {
  18 + /**
  19 + * 映射路径
  20 + * @param
  21 + * @return
  22 + * @author miaoguoxin
  23 + * @date 2020/4/15
  24 + */
  25 + String value() default "";
  26 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/common/constant/GatewayAttrType.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/common/constant/GatewayAttrType.java
  1 +package com.diligrp.xtrade.gateway.common.constant;
  2 +
  3 +import com.diligrp.xtrade.shared.type.IEnumType;
  4 +
  5 +import java.util.Arrays;
  6 +
  7 +/**
  8 + * @Auther: miaoguoxin
  9 + * @Date: 2018/12/9 20:27
  10 + * @Description: 网关属性类型(类型含义需参见spring cloud gateway官方文档)
  11 + */
  12 +public enum GatewayAttrType implements IEnumType {
  13 + PREDICATE(1,"断言配置"),
  14 + FILTER(2,"过滤器"),
  15 + ;
  16 + /**
  17 + * 编码
  18 + */
  19 + private int value;
  20 +
  21 + private String desc;
  22 +
  23 +
  24 + GatewayAttrType(int value, String desc) {
  25 + this.value = value;
  26 + this.desc=desc;
  27 + }
  28 +
  29 + public int getValue() {
  30 + return value;
  31 + }
  32 +
  33 + /**
  34 + * 获取枚举
  35 + * @param value
  36 + * @return
  37 + */
  38 + public static GatewayAttrType getByValue(int value) {
  39 + return Arrays.stream(values())
  40 + .filter(e -> e.getValue() == value).findFirst()
  41 + .orElse(null);
  42 + }
  43 +
  44 + public String getDesc() {
  45 + return desc;
  46 + }
  47 +
  48 + @Override
  49 + public int getCode() {
  50 + return this.value;
  51 + }
  52 +
  53 + @Override
  54 + public String getName() {
  55 + return this.desc;
  56 + }
  57 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/common/constant/GatewayConst.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/common/constant/GatewayConst.java
  1 +package com.diligrp.xtrade.gateway.common.constant;
  2 +
  3 +import java.util.concurrent.atomic.AtomicBoolean;
  4 +
  5 +/**
  6 + * @Auther: miaoguoxin
  7 + * @Date: 2019/3/25 0025 18:08
  8 + * @Description: 网关所需的一些常量配置
  9 + */
  10 +public class GatewayConst {
  11 + /**用于标记聚合服务mapping是否已经初始化(防止重复加载)*/
  12 + public static final AtomicBoolean HAS_INIT_MAPPING = new AtomicBoolean(false);
  13 + /**请求体缓存Key*/
  14 + public static final String CACHE_REQUEST_BODY_OBJECT_KEY = "cachedRequestBodyObj";
  15 + /**缓存Api配置key*/
  16 + public static final String CACHE_API_OBJECT_KEY = "cachedApiConfigObject";
  17 +
  18 + public static final int CACHE_BODY_FILTER_ORDER = -10;
  19 +
  20 + public static final int AUTH_FILTER_ORDER = -9;
  21 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/common/utils/CacheUtils.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/common/utils/CacheUtils.java
  1 +//package com.diligrp.xtrade.gateway.common.utils;
  2 +//
  3 +//import net.sf.ehcache.Cache;
  4 +//import net.sf.ehcache.CacheManager;
  5 +//import net.sf.ehcache.Element;
  6 +//import org.springframework.beans.factory.annotation.Autowired;
  7 +//import org.springframework.stereotype.Component;
  8 +//
  9 +///**
  10 +// * @Auther: miaoguoxin
  11 +// * @Date: 2020/4/2 13:25
  12 +// * @Description:
  13 +// */
  14 +//@Component
  15 +//public class CacheUtils {
  16 +//
  17 +// private static CacheManager cacheManager;
  18 +//
  19 +// @Autowired
  20 +// public void setCacheManager(CacheManager cacheManager) {
  21 +// CacheUtils.cacheManager = cacheManager;
  22 +// }
  23 +//
  24 +// /**
  25 +// * 获取缓存
  26 +// *
  27 +// * @param cacheName
  28 +// * @param key
  29 +// * @return
  30 +// */
  31 +// public Object getCache(String cacheName, String key) {
  32 +// Cache cache = cacheManager.getCache(cacheName);
  33 +// if (cache == null) {
  34 +// return null;
  35 +// }
  36 +// return cache.get(key).getObjectValue();
  37 +// }
  38 +//
  39 +// /**
  40 +// * 保存缓存--没有则创建一个
  41 +// *
  42 +// * @param cacheName
  43 +// * @param key
  44 +// * @param value
  45 +// */
  46 +// public void putCache(String cacheName, String key, Object value) {
  47 +// Cache cache = cacheManager.getCache(cacheName);
  48 +// if (cache == null) {
  49 +// cacheManager.addCache(cacheName);
  50 +// cache = cacheManager.getCache(cacheName);
  51 +// cache.put(new Element(key, value));
  52 +// }
  53 +// cache.put(new Element(key, value));
  54 +// }
  55 +//
  56 +// /**
  57 +// * 删除缓存
  58 +// * @param cacheName
  59 +// */
  60 +// public void removeCache(String cacheName,String key){
  61 +// Cache cache = cacheManager.getCache(cacheName);
  62 +// if(cache!=null){
  63 +// cache.remove(key);
  64 +// }
  65 +// }
  66 +//
  67 +// /**
  68 +// * 替换缓存
  69 +// * @param cacheName
  70 +// * @param key
  71 +// * @param value
  72 +// */
  73 +// public void replaceCache(String cacheName,String key,String value){
  74 +// Cache cache = cacheManager.getCache(cacheName);
  75 +// if(cache!=null){
  76 +// cache.replace(new Element(key,value));
  77 +// }
  78 +// }
  79 +//}
... ...
src/main/java/com/diligrp/xtrade/gateway/common/utils/PathUtils.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/common/utils/PathUtils.java
  1 +package com.diligrp.xtrade.gateway.common.utils;
  2 +
  3 +import org.springframework.http.server.PathContainer;
  4 +import org.springframework.util.CollectionUtils;
  5 +import org.springframework.web.util.pattern.PathPattern;
  6 +import org.springframework.web.util.pattern.PathPatternParser;
  7 +
  8 +import java.util.List;
  9 +import java.util.Optional;
  10 +import java.util.concurrent.CopyOnWriteArrayList;
  11 +
  12 +/**
  13 + * @Auther: miaoguoxin
  14 + * @Date: 2020/4/15 10:37
  15 + */
  16 +public class PathUtils {
  17 + private static PathPatternParser pathPatternParser = new PathPatternParser();
  18 +
  19 + /**
  20 + * 多个路径拼接成一个标准uri,ex: /test + gateway = /test/gateway
  21 + * @author miaoguoxin
  22 + * @date 2020/4/15
  23 + */
  24 + public static String concatUri(String... paths){
  25 + if (paths==null || paths.length ==0){
  26 + return "";
  27 + }
  28 + StringBuilder sb = new StringBuilder();
  29 + for (String path : paths) {
  30 + sb.append("/").append(path).append("/");
  31 + }
  32 + String s = removeExtraSlashOfUrl(sb.toString());
  33 + if (s.endsWith("/")){
  34 + s= s.substring(0,s.length()-1);
  35 + }
  36 + return s;
  37 + }
  38 +
  39 + /**
  40 + * 去除多余的斜杠
  41 + * @author miaoguoxin
  42 + * @date 2020/4/15
  43 + */
  44 + public static String removeExtraSlashOfUrl(String url) {
  45 + if (url == null || url.length() == 0) {
  46 + return url;
  47 + }
  48 + return url.replaceAll("(?<!(http:|https:))/+", "/");
  49 + }
  50 +
  51 + /**
  52 + * 判断uri是否匹配
  53 + * @author miaoguoxin
  54 + * @date 2020/4/15
  55 + */
  56 + public static boolean isUriMatch(String path, List<PathPattern> pathPatterns){
  57 + PathContainer pathContainer = PathContainer.parsePath(path);
  58 + return Optional.ofNullable(pathPatterns)
  59 + .map(patterns -> patterns
  60 + .stream()
  61 + .anyMatch(pattern -> {
  62 + return pattern.matches(pathContainer);
  63 + }))
  64 + .orElse(true);
  65 + }
  66 +
  67 +
  68 + public static String getMatchUri(String path, List<PathPattern> pathPatterns) {
  69 + PathContainer pathContainer = PathContainer.parsePath(path);
  70 + return Optional.ofNullable(pathPatterns)
  71 + .map(patterns -> {
  72 + PathPattern pathPattern = patterns.stream()
  73 + .filter(p -> p.matches(pathContainer))
  74 + .findFirst().orElse(null);
  75 + if (pathPattern != null) {
  76 + return pathPattern.getPatternString();
  77 + }
  78 + return "";
  79 + }).orElse("");
  80 + }
  81 +
  82 + /**
  83 + * 转换路径格式
  84 + * @author miaoguoxin
  85 + * @date 2020/4/15
  86 + */
  87 + public static List<PathPattern> assemblePath(String[] paths,List<PathPattern> pathPatterns){
  88 + if (paths == null || paths.length == 0){
  89 + return null;
  90 + }
  91 + if (pathPatterns == null){
  92 + pathPatterns = new CopyOnWriteArrayList<>();
  93 + }
  94 + if (!CollectionUtils.isEmpty(pathPatterns)){
  95 + pathPatterns.clear();
  96 + }
  97 + for (String path : paths) {
  98 + PathPattern pathPattern = pathPatternParser.parse(path);
  99 + pathPatterns.add(pathPattern);
  100 + }
  101 + return pathPatterns;
  102 + }
  103 +
  104 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/common/utils/ResponseUtils.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/common/utils/ResponseUtils.java
  1 +package com.diligrp.xtrade.gateway.common.utils;
  2 +
  3 +import com.diligrp.xtrade.shared.domain.Message;
  4 +import com.diligrp.xtrade.shared.util.JsonUtils;
  5 +import org.springframework.http.HttpStatus;
  6 +import org.springframework.http.MediaType;
  7 +import org.springframework.http.server.reactive.ServerHttpResponse;
  8 +import reactor.core.publisher.Flux;
  9 +import reactor.core.publisher.Mono;
  10 +
  11 +import java.nio.charset.StandardCharsets;
  12 +
  13 +/**
  14 + * @Auther: miaoguoxin
  15 + * @Date: 2020/4/14 16:46
  16 + */
  17 +public class ResponseUtils {
  18 +
  19 +
  20 + public static Mono<Void> writeForbidden(ServerHttpResponse response){
  21 + Message message = Message
  22 + .builder()
  23 + .code(HttpStatus.FORBIDDEN.value())
  24 + .message(HttpStatus.FORBIDDEN.toString())
  25 + .build();
  26 + return writeResponse(response,message);
  27 + }
  28 +
  29 + public static Mono<Void> writeResponse(ServerHttpResponse response,Message message){
  30 + String respJson = JsonUtils.toJsonString(message);
  31 + response.getHeaders().setContentLength(
  32 + respJson.getBytes(StandardCharsets.UTF_8).length);
  33 + response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
  34 + return response.writeWith(
  35 + Flux.just(respJson)
  36 + .map(bx -> response.bufferFactory()
  37 + .wrap(bx.getBytes(StandardCharsets.UTF_8))
  38 + )
  39 + );
  40 + }
  41 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/common/utils/ValidateUtils.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/common/utils/ValidateUtils.java
  1 +package com.diligrp.xtrade.gateway.common.utils;
  2 +
  3 +import com.diligrp.xtrade.gateway.exception.GatewayParamNotValidException;
  4 +import org.springframework.beans.factory.annotation.Autowired;
  5 +import org.springframework.stereotype.Component;
  6 +
  7 +import javax.validation.ConstraintViolation;
  8 +import javax.validation.Validation;
  9 +import javax.validation.Validator;
  10 +import javax.validation.groups.Default;
  11 +import java.util.Arrays;
  12 +import java.util.HashSet;
  13 +import java.util.Set;
  14 +
  15 +/**
  16 + * @Auther: miaoguoxin
  17 + * @Date: 2020/4/15 12:44
  18 + * @Description: 用于参数校验的工具类
  19 + */
  20 +@Component
  21 +public class ValidateUtils {
  22 + private static Validator validator;
  23 +
  24 +
  25 + @Autowired
  26 + public void setValidator(Validator validator){
  27 + ValidateUtils.validator = validator;
  28 + }
  29 +
  30 + public static void validate(Object params){
  31 + validate(params, new Class[]{});
  32 + }
  33 +
  34 + public static void validate(Object params, Class... groups) {
  35 + Set<Class> groupSet = new HashSet<>();
  36 + groupSet.add(Default.class);
  37 + if (groups != null && groups.length > 0) {
  38 + groupSet.addAll(Arrays.asList(groups));
  39 + }
  40 + Set<ConstraintViolation<Object>> set = validator.validate(params, groupSet.toArray(new Class[0]));
  41 + if (set != null && !set.isEmpty()) {
  42 + for (ConstraintViolation<Object> violation : set) {
  43 + throw new GatewayParamNotValidException(violation.getMessage());
  44 + }
  45 + }
  46 +
  47 + }
  48 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/config/CacheManagerConfiguration.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/config/CacheManagerConfiguration.java
  1 +//package com.diligrp.xtrade.gateway.config;
  2 +//
  3 +//import net.sf.ehcache.CacheManager;
  4 +//import org.springframework.beans.factory.annotation.Value;
  5 +//import org.springframework.context.annotation.Bean;
  6 +//import org.springframework.context.annotation.Configuration;
  7 +//
  8 +///**
  9 +// * @Auther: miaoguoxin
  10 +// * @Date: 2020/4/2 13:28
  11 +// * @Description:
  12 +// */
  13 +//@Configuration
  14 +//public class CacheManagerConfiguration {
  15 +// @Value("${spring.cache.ehcache.config}")
  16 +// private String ehcaheConfigName;
  17 +//
  18 +// @Bean
  19 +// public CacheManager cacheManager(){
  20 +// String classesPath = getClassesPath();
  21 +// return CacheManager.create(classesPath+ehcaheConfigName);
  22 +// }
  23 +//
  24 +// private static String getClassesPath(){
  25 +// return Thread.currentThread().getContextClassLoader().getResource("").getPath();
  26 +// }
  27 +//
  28 +//}
... ...
src/main/java/com/diligrp/xtrade/gateway/config/ExceptionConfiguration.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/config/ExceptionConfiguration.java
  1 +package com.diligrp.xtrade.gateway.config;
  2 +
  3 +import com.diligrp.xtrade.gateway.exception.GlobalGatewayErrorHandler;
  4 +import org.springframework.beans.factory.ObjectProvider;
  5 +import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
  6 +import org.springframework.context.annotation.Bean;
  7 +import org.springframework.context.annotation.Configuration;
  8 +import org.springframework.context.annotation.Primary;
  9 +import org.springframework.core.Ordered;
  10 +import org.springframework.core.annotation.Order;
  11 +import org.springframework.http.codec.ServerCodecConfigurer;
  12 +import org.springframework.web.reactive.result.view.ViewResolver;
  13 +
  14 +import java.util.Collections;
  15 +import java.util.List;
  16 +
  17 +/**
  18 + * @Auther: miaoguoxin
  19 + * @Date: 2018/12/12 21:53
  20 + * @Description: 全局异常处理配置
  21 + */
  22 +@Configuration
  23 +public class ExceptionConfiguration {
  24 + @Primary
  25 + @Bean
  26 + @Order(Ordered.HIGHEST_PRECEDENCE)
  27 + public ErrorWebExceptionHandler errorWebExceptionHandler(ObjectProvider<List<ViewResolver>> viewResolversProvider,
  28 + ServerCodecConfigurer serverCodecConfigurer) {
  29 + GlobalGatewayErrorHandler jsonExceptionHandler = new GlobalGatewayErrorHandler();
  30 + jsonExceptionHandler.setViewResolvers(viewResolversProvider.getIfAvailable(Collections::emptyList));
  31 + jsonExceptionHandler.setMessageWriters(serverCodecConfigurer.getWriters());
  32 + jsonExceptionHandler.setMessageReaders(serverCodecConfigurer.getReaders());
  33 + return jsonExceptionHandler;
  34 + }
  35 +
  36 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/config/GatewayResourceLoaderConfiguration.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/config/GatewayResourceLoaderConfiguration.java
  1 +package com.diligrp.xtrade.gateway.config;
  2 +
  3 +import com.alibaba.cloud.nacos.NacosConfigProperties;
  4 +import com.alibaba.nacos.api.NacosFactory;
  5 +import com.alibaba.nacos.api.PropertyKeyConst;
  6 +import com.alibaba.nacos.api.config.ConfigService;
  7 +import com.alibaba.nacos.api.exception.NacosException;
  8 +import com.diligrp.xtrade.gateway.exception.GatewayServiceException;
  9 +import com.diligrp.xtrade.gateway.route.DynamicRouteLoaderIntf;
  10 +import com.diligrp.xtrade.gateway.route.impl.CloudRouteResourceLoader;
  11 +import com.diligrp.xtrade.gateway.route.impl.MysqlRouteResourceLoader;
  12 +import org.apache.logging.log4j.util.Strings;
  13 +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  14 +import org.springframework.context.annotation.Bean;
  15 +import org.springframework.context.annotation.Configuration;
  16 +import org.springframework.core.env.Environment;
  17 +
  18 +import java.util.Properties;
  19 +
  20 +/**
  21 + * @Auther: miaoguoxin
  22 + * @Date: 2020/4/10 13:20
  23 + * @Description: 路由资源加载器配置
  24 + */
  25 +@Configuration(proxyBeanMethods = false)
  26 +public class GatewayResourceLoaderConfiguration {
  27 +
  28 + @Bean
  29 + public ConfigService configService(Environment environment,NacosConfigProperties configProperties){
  30 + String username = environment.getProperty("spring.cloud.nacos.config.username");
  31 + String password = environment.getProperty("spring.cloud.nacos.config.password");
  32 + Properties properties = new Properties();
  33 + properties.put(PropertyKeyConst.NAMESPACE, configProperties.getNamespace());
  34 + if (Strings.isNotBlank(username)) {
  35 + properties.put(PropertyKeyConst.USERNAME, username);
  36 + properties.put(PropertyKeyConst.PASSWORD, password);
  37 + }
  38 + properties.put(PropertyKeyConst.SERVER_ADDR, configProperties.getServerAddr());
  39 + ConfigService configService;
  40 + try {
  41 + configService = NacosFactory.createConfigService(properties);
  42 + } catch (NacosException e) {
  43 + throw new GatewayServiceException("init nacos configService failed", e);
  44 + }
  45 + return configService;
  46 + }
  47 +
  48 + @Bean(name = "cloudRouteResourceLoader")
  49 + @ConditionalOnProperty(prefix = "xtrade",name = "gateway-loader",havingValue = "cloud",matchIfMissing = true)
  50 + public DynamicRouteLoaderIntf cloudRouteResourceLoader(){
  51 + return new CloudRouteResourceLoader();
  52 + }
  53 +
  54 +
  55 + @Bean(name = "mysqlRouteResourceLoader")
  56 + @ConditionalOnProperty(prefix = "xtrade",name = "gateway-loader",havingValue = "mysql")
  57 + public DynamicRouteLoaderIntf mysqlRouteResourceLoader(){
  58 + return new MysqlRouteResourceLoader();
  59 + }
  60 +
  61 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/config/property/AuthPathProperties.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/config/property/AuthPathProperties.java
  1 +package com.diligrp.xtrade.gateway.config.property;
  2 +
  3 +import com.diligrp.xtrade.gateway.common.utils.PathUtils;
  4 +import lombok.Data;
  5 +import org.springframework.boot.context.properties.ConfigurationProperties;
  6 +import org.springframework.stereotype.Component;
  7 +import org.springframework.util.CollectionUtils;
  8 +import org.springframework.web.util.pattern.PathPattern;
  9 +import org.springframework.web.util.pattern.PathPatternParser;
  10 +
  11 +import java.util.ArrayList;
  12 +import java.util.List;
  13 +import java.util.concurrent.CopyOnWriteArrayList;
  14 +
  15 +/**
  16 + * @Auther: miaoguoxin
  17 + * @Date: 2020/4/13 15:17
  18 + */
  19 +@Component
  20 +@ConfigurationProperties(prefix = "xtrade.auth")
  21 +@Data
  22 +public class AuthPathProperties {
  23 + /**不需要校验权限的path*/
  24 + private String[] excludePaths;
  25 + /**转换path格式*/
  26 + private List<PathPattern> excludePathPatterns;
  27 +
  28 +
  29 + /**
  30 + * 属性配置刷新的时候会从这里进入
  31 + * @author miaoguoxin
  32 + * @date 2020/4/13
  33 + */
  34 + public void setExcludePaths(String[] excludePaths) {
  35 + this.excludePaths = excludePaths;
  36 + this.excludePathPatterns = PathUtils.assemblePath(this.excludePaths,this.excludePathPatterns);
  37 + }
  38 +
  39 +
  40 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/config/property/DispatchProperties.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/config/property/DispatchProperties.java
  1 +package com.diligrp.xtrade.gateway.config.property;
  2 +
  3 +import lombok.Data;
  4 +import org.springframework.boot.context.properties.ConfigurationProperties;
  5 +import org.springframework.stereotype.Component;
  6 +
  7 +/**
  8 + * @Auther: miaoguoxin
  9 + * @Date: 2020/4/15 17:35
  10 + */
  11 +@Component
  12 +@ConfigurationProperties(prefix = "xtrade")
  13 +@Data
  14 +public class DispatchProperties {
  15 + /** 扫描包路径 */
  16 + private String[] aggregationScanPackages;
  17 +
  18 + public DispatchProperties(String[] aggregationScanPackages) {
  19 + this.aggregationScanPackages = aggregationScanPackages;
  20 + }
  21 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/controller/TestController.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/controller/TestController.java
  1 +package com.diligrp.xtrade.gateway.controller;
  2 +
  3 +import com.diligrp.xtrade.shared.domain.Message;
  4 +import com.google.common.collect.Lists;
  5 +import org.springframework.beans.factory.annotation.Autowired;
  6 +import org.springframework.beans.factory.annotation.Value;
  7 +import org.springframework.cloud.context.config.annotation.RefreshScope;
  8 +import org.springframework.cloud.gateway.config.GatewayProperties;
  9 +import org.springframework.cloud.gateway.route.RouteDefinition;
  10 +import org.springframework.http.server.PathContainer;
  11 +import org.springframework.web.bind.annotation.GetMapping;
  12 +import org.springframework.web.bind.annotation.RequestMapping;
  13 +import org.springframework.web.bind.annotation.RestController;
  14 +import org.springframework.web.util.pattern.PathPattern;
  15 +import org.springframework.web.util.pattern.PathPatternParser;
  16 +
  17 +import java.util.ArrayList;
  18 +import java.util.List;
  19 +import java.util.Optional;
  20 +
  21 +/**
  22 + * @Auther: miaoguoxin
  23 + * @Date: 2020/4/10 16:01
  24 + * @Description:
  25 + */
  26 +@RestController
  27 +@RequestMapping("/test")
  28 +@RefreshScope
  29 +public class TestController {
  30 + private static PathPatternParser pathPatternParser = new PathPatternParser();
  31 + @Autowired
  32 + private GatewayProperties gatewayProperties;
  33 + @Value("${ribbon.ServerListRefreshInterval}")
  34 + private String interval;
  35 +
  36 + @GetMapping("/gateway")
  37 + public Message<List<RouteDefinition>> test() {
  38 + List<RouteDefinition> routes = gatewayProperties.getRoutes();
  39 + return Message.builder().success(routes);
  40 + //throw new RuntimeException("gfdg");
  41 + }
  42 +
  43 + @GetMapping("/test_dynamic")
  44 + public Message<String> test1() {
  45 + return Message.builder().success(interval);
  46 + }
  47 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/domain/TestRequestDto.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/domain/TestRequestDto.java
  1 +package com.diligrp.xtrade.gateway.domain;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import javax.validation.constraints.NotBlank;
  6 +
  7 +/**
  8 + * @Auther: miaoguoxin
  9 + * @Date: 2020/4/15 15:56
  10 + */
  11 +@Data
  12 +public class TestRequestDto {
  13 + @NotBlank(message = "{request.username.not.blank}")
  14 + private String username;
  15 +
  16 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/exception/GatewayParamNotValidException.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/exception/GatewayParamNotValidException.java
  1 +package com.diligrp.xtrade.gateway.exception;
  2 +
  3 +/**
  4 + * @Auther: miaoguoxin
  5 + * @Date: 2020/4/15 13:34
  6 + * @Description: 用于聚合服务操作参数校验失败
  7 + */
  8 +public class GatewayParamNotValidException extends RuntimeException {
  9 +
  10 + public GatewayParamNotValidException(String message) {
  11 + super(message);
  12 + }
  13 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/exception/GatewayServiceException.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/exception/GatewayServiceException.java
  1 +package com.diligrp.xtrade.gateway.exception;
  2 +
  3 +import lombok.Getter;
  4 +
  5 +/**
  6 + * @Auther: miaoguoxin
  7 + * @Date: 2020/4/10 11:28
  8 + * @Description:
  9 + */
  10 +@Getter
  11 +public class GatewayServiceException extends RuntimeException {
  12 + private Object[] args;
  13 +
  14 + public GatewayServiceException() {
  15 + }
  16 +
  17 + public GatewayServiceException(String message) {
  18 + super(message);
  19 + }
  20 +
  21 + public GatewayServiceException(String message, Object[] args) {
  22 + super(message);
  23 + this.args = args;
  24 + }
  25 +
  26 + public GatewayServiceException(String message, Throwable cause, Object[] args) {
  27 + super(message, cause);
  28 + this.args = args;
  29 + }
  30 +
  31 + public GatewayServiceException(Throwable cause, Object[] args) {
  32 + super(cause);
  33 + this.args = args;
  34 + }
  35 +
  36 + public GatewayServiceException(String message, Throwable cause) {
  37 + super(message, cause);
  38 + }
  39 +
  40 + public GatewayServiceException(Throwable cause) {
  41 + super(cause);
  42 + }
  43 +
  44 +
  45 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/exception/GlobalGatewayErrorHandler.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/exception/GlobalGatewayErrorHandler.java
  1 +package com.diligrp.xtrade.gateway.exception;
  2 +
  3 +import com.alibaba.fastjson.JSON;
  4 +import com.diligrp.xtrade.shared.domain.Message;
  5 +import lombok.extern.slf4j.Slf4j;
  6 +import org.springframework.beans.factory.annotation.Autowired;
  7 +import org.springframework.boot.web.reactive.error.ErrorAttributes;
  8 +import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
  9 +import org.springframework.cloud.gateway.support.NotFoundException;
  10 +import org.springframework.http.HttpStatus;
  11 +import org.springframework.http.MediaType;
  12 +import org.springframework.http.codec.HttpMessageReader;
  13 +import org.springframework.http.codec.HttpMessageWriter;
  14 +import org.springframework.http.server.reactive.ServerHttpRequest;
  15 +import org.springframework.util.Assert;
  16 +import org.springframework.web.reactive.function.BodyInserters;
  17 +import org.springframework.web.reactive.function.server.RequestPredicates;
  18 +import org.springframework.web.reactive.function.server.RouterFunctions;
  19 +import org.springframework.web.reactive.function.server.ServerRequest;
  20 +import org.springframework.web.reactive.function.server.ServerResponse;
  21 +import org.springframework.web.reactive.result.view.ViewResolver;
  22 +import org.springframework.web.server.ResponseStatusException;
  23 +import org.springframework.web.server.ServerWebExchange;
  24 +import reactor.core.publisher.Mono;
  25 +
  26 +import java.util.Collections;
  27 +import java.util.HashMap;
  28 +import java.util.List;
  29 +import java.util.Map;
  30 +
  31 +/**
  32 + * @Auther: miaoguoxin
  33 + * @Date: 2020/04/13 10:55
  34 + * @Description: 处理网关本身抛出的异常
  35 + */
  36 +@Slf4j
  37 +public class GlobalGatewayErrorHandler implements ErrorWebExceptionHandler {
  38 + @Autowired
  39 + private ErrorAttributes errorAttributes;
  40 + /**
  41 + * MessageReader
  42 + */
  43 + private List<HttpMessageReader<?>> messageReaders = Collections.emptyList();
  44 +
  45 + /**
  46 + * MessageWriter
  47 + */
  48 + private List<HttpMessageWriter<?>> messageWriters = Collections.emptyList();
  49 +
  50 + /**
  51 + * ViewResolvers
  52 + */
  53 + private List<ViewResolver> viewResolvers = Collections.emptyList();
  54 +
  55 + /**
  56 + * 存储处理异常后的信息
  57 + */
  58 + private ThreadLocal<Map<String, Object>> exceptionHandlerResult = new ThreadLocal<>();
  59 +
  60 + /**
  61 + * 参考AbstractErrorWebExceptionHandler
  62 + */
  63 + public void setViewResolvers(List<ViewResolver> viewResolvers) {
  64 + this.viewResolvers = viewResolvers;
  65 + }
  66 +
  67 + /**
  68 + * 参考AbstractErrorWebExceptionHandler
  69 + */
  70 + public void setMessageWriters(List<HttpMessageWriter<?>> messageWriters) {
  71 + Assert.notNull(messageWriters, "'messageWriters' must not be null");
  72 + this.messageWriters = messageWriters;
  73 + }
  74 +
  75 + /**
  76 + * 参考AbstractErrorWebExceptionHandler
  77 + */
  78 + public void setMessageReaders(List<HttpMessageReader<?>> messageReaders) {
  79 + Assert.notNull(messageReaders, "'messageReaders' must not be null");
  80 + this.messageReaders = messageReaders;
  81 + }
  82 +
  83 +
  84 + @Override
  85 + public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
  86 + ServerHttpRequest request = exchange.getRequest();
  87 + // Map<String, Object> result = this.getHttpResult(httpStatus);
  88 + //参考AbstractErrorWebExceptionHandler
  89 + if (exchange.getResponse().isCommitted()) {
  90 + return Mono.error(ex);
  91 + }
  92 + errorAttributes.storeErrorInformation(ex,exchange);
  93 + ServerRequest newRequest = ServerRequest.create(exchange, this.messageReaders);
  94 + return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse).route(newRequest)
  95 + .switchIfEmpty(Mono.error(ex))
  96 + .flatMap((handler) -> handler.handle(newRequest))
  97 + .flatMap((response) -> write(exchange, response));
  98 + }
  99 +
  100 + private HttpStatus getHttpStatus(Throwable ex) {
  101 + HttpStatus httpStatus;
  102 + if (ex instanceof NotFoundException) {
  103 + httpStatus = HttpStatus.NOT_FOUND;
  104 + } else if (ex instanceof ResponseStatusException) {
  105 + ResponseStatusException responseStatusException = (ResponseStatusException) ex;
  106 + httpStatus = responseStatusException.getStatus();
  107 + } else {
  108 + httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
  109 + }
  110 + return httpStatus;
  111 + }
  112 +
  113 + private Map<String, Object> getHttpResult(HttpStatus httpStatus) {
  114 + Message apiResult= Message.builder()
  115 + .code(httpStatus.value())
  116 + .message(httpStatus.toString())
  117 + .build();
  118 + Map<String,Object> result=new HashMap<>();
  119 + result.put("httpStatus",httpStatus);
  120 + result.put("body", JSON.toJSONString(apiResult));
  121 + return result;
  122 + }
  123 +
  124 + /**
  125 + * 参考DefaultErrorWebExceptionHandler
  126 + */
  127 + private Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
  128 + Map<String, Object> errorAttrs = errorAttributes.getErrorAttributes(request, true);
  129 + String msg = String.format("%s %s",
  130 + errorAttrs.get("path"), errorAttrs.get("error"));
  131 + Message message = Message.builder()
  132 + .code((int)errorAttrs.get("status"))
  133 + .message(msg)
  134 + .build();
  135 + if (message.getCode().equals(500)){
  136 + log.error("[全局异常处理]异常请求路径:{},记录异常信息:{}", errorAttrs.get("path"),errorAttributes.getError(request));
  137 + }
  138 + return ServerResponse.status(HttpStatus.OK)
  139 + .contentType(MediaType.APPLICATION_JSON)
  140 + .body(BodyInserters.fromValue(message));
  141 + }
  142 +
  143 + /**
  144 + * 参考AbstractErrorWebExceptionHandler
  145 + */
  146 + private Mono<? extends Void> write(ServerWebExchange exchange,
  147 + ServerResponse response) {
  148 + exchange.getResponse().getHeaders()
  149 + .setContentType(response.headers().getContentType());
  150 + return response.writeTo(exchange, new ResponseContext());
  151 + }
  152 +
  153 +
  154 + /**
  155 + * 参考AbstractErrorWebExceptionHandler
  156 + */
  157 + private class ResponseContext implements ServerResponse.Context {
  158 +
  159 + @Override
  160 + public List<HttpMessageWriter<?>> messageWriters() {
  161 + return GlobalGatewayErrorHandler.this.messageWriters;
  162 + }
  163 +
  164 + @Override
  165 + public List<ViewResolver> viewResolvers() {
  166 + return GlobalGatewayErrorHandler.this.viewResolvers;
  167 + }
  168 +
  169 + }
  170 +
  171 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/filters/factory/DispatchGatewayFilterFactory.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/filters/factory/DispatchGatewayFilterFactory.java
  1 +package com.diligrp.xtrade.gateway.filters.factory;
  2 +
  3 +import com.diligrp.xtrade.gateway.common.utils.ResponseUtils;
  4 +import com.diligrp.xtrade.gateway.support.dispatch.RequestDispatcher;
  5 +import com.diligrp.xtrade.shared.domain.Message;
  6 +import lombok.Data;
  7 +import org.reactivestreams.Publisher;
  8 +import org.springframework.beans.factory.annotation.Autowired;
  9 +import org.springframework.cloud.gateway.filter.GatewayFilter;
  10 +import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
  11 +import org.springframework.core.io.buffer.DataBuffer;
  12 +import org.springframework.http.HttpHeaders;
  13 +import org.springframework.http.MediaType;
  14 +import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
  15 +import org.springframework.stereotype.Component;
  16 +import reactor.core.publisher.Mono;
  17 +
  18 +import static com.diligrp.xtrade.gateway.common.constant.GatewayConst.CACHE_REQUEST_BODY_OBJECT_KEY;
  19 +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR;
  20 +
  21 +/**
  22 + * @Auther: miaoguoxin
  23 + * @Date: 2020/4/15 14:18
  24 + * @Description: 分发过滤器filter,用来做网关本身的逻辑操作
  25 + */
  26 +@Component
  27 +public class DispatchGatewayFilterFactory extends AbstractGatewayFilterFactory<DispatchGatewayFilterFactory.Config> {
  28 + @Autowired
  29 + private RequestDispatcher requestDispatcher;
  30 +
  31 + public DispatchGatewayFilterFactory() {
  32 + super(Config.class);
  33 + }
  34 +
  35 + @Override
  36 + public GatewayFilter apply(Config config) {
  37 + return (exchange, chain) -> {
  38 + String rawPath = exchange.getRequest().getURI().getRawPath();
  39 + String paramsJson = exchange.getAttribute(CACHE_REQUEST_BODY_OBJECT_KEY);
  40 + Message message = requestDispatcher.executeMethod(rawPath, paramsJson,exchange);
  41 + //throw new RuntimeException("gggg");
  42 + return ResponseUtils.writeResponse(
  43 + new ServerHttpResponseDecorator(exchange.getResponse()) {
  44 + @Override
  45 + public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
  46 + //这里需要设置响应content-Type,不然后面的过滤器拿不到这个值会报错
  47 + exchange.getAttributes().put(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR, MediaType.APPLICATION_JSON_VALUE);
  48 + String originalResponseContentType = exchange
  49 + .getAttribute(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR);
  50 + HttpHeaders httpHeaders = exchange.getResponse().getHeaders();
  51 + httpHeaders.add(HttpHeaders.CONTENT_TYPE, originalResponseContentType);
  52 + return super.writeWith(body);
  53 + }
  54 + }, message);
  55 + };
  56 + }
  57 +
  58 + @Data
  59 + public static class Config {
  60 + private String keyResolverName;
  61 + }
  62 +
  63 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/filters/global/AuthGlobalFilter.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/filters/global/AuthGlobalFilter.java
  1 +package com.diligrp.xtrade.gateway.filters.global;
  2 +
  3 +import com.diligrp.xtrade.gateway.api.ApiManager;
  4 +import com.diligrp.xtrade.gateway.common.utils.ResponseUtils;
  5 +import com.diligrp.xtrade.shared.domain.Message;
  6 +import com.diligrp.xtrade.shared.util.JsonUtils;
  7 +import lombok.extern.slf4j.Slf4j;
  8 +import org.springframework.beans.factory.annotation.Autowired;
  9 +import org.springframework.cloud.gateway.filter.GatewayFilterChain;
  10 +import org.springframework.cloud.gateway.filter.GlobalFilter;
  11 +import org.springframework.core.Ordered;
  12 +import org.springframework.core.io.buffer.PooledDataBuffer;
  13 +import org.springframework.http.HttpStatus;
  14 +import org.springframework.http.MediaType;
  15 +import org.springframework.http.server.reactive.ServerHttpRequest;
  16 +import org.springframework.http.server.reactive.ServerHttpResponse;
  17 +import org.springframework.stereotype.Component;
  18 +import org.springframework.web.server.ServerWebExchange;
  19 +import reactor.core.Disposable;
  20 +import reactor.core.publisher.Flux;
  21 +import reactor.core.publisher.Mono;
  22 +
  23 +import java.nio.charset.Charset;
  24 +import java.nio.charset.StandardCharsets;
  25 +import java.util.Map;
  26 +
  27 +import static com.diligrp.xtrade.gateway.common.constant.GatewayConst.AUTH_FILTER_ORDER;
  28 +import static com.diligrp.xtrade.gateway.common.constant.GatewayConst.CACHE_REQUEST_BODY_OBJECT_KEY;
  29 +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR;
  30 +
  31 +/**
  32 + * @Auther: miaoguoxin
  33 + * @Date: 2020/4/2 13:50
  34 + * @Description: 用于权限操作
  35 + */
  36 +@Component
  37 +@Slf4j
  38 +public class AuthGlobalFilter implements GlobalFilter, Ordered {
  39 + @Autowired
  40 + private ApiManager apiManager;
  41 + @Override
  42 + public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  43 + String rawPath = exchange.getRequest().getURI().getRawPath();
  44 + ServerHttpResponse response = exchange.getResponse();
  45 + //排除在外的Uri跳过权限
  46 + if (apiManager.isExcludePathMatch(rawPath)){
  47 + return chain.filter(exchange);
  48 + }
  49 + return ResponseUtils.writeForbidden(response);
  50 + }
  51 +
  52 + @Override
  53 + public int getOrder() {
  54 + return AUTH_FILTER_ORDER;
  55 + }
  56 +
  57 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/filters/global/CacheRequestBodyGlobalFilter.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/filters/global/CacheRequestBodyGlobalFilter.java
  1 +package com.diligrp.xtrade.gateway.filters.global;
  2 +
  3 +import lombok.extern.slf4j.Slf4j;
  4 +import org.springframework.cloud.gateway.filter.GatewayFilterChain;
  5 +import org.springframework.cloud.gateway.filter.GlobalFilter;
  6 +import org.springframework.cloud.gateway.filter.factory.rewrite.CachedBodyOutputMessage;
  7 +import org.springframework.cloud.gateway.filter.factory.rewrite.ModifyRequestBodyGatewayFilterFactory;
  8 +import org.springframework.cloud.gateway.support.BodyInserterContext;
  9 +import org.springframework.core.Ordered;
  10 +import org.springframework.core.io.buffer.DataBuffer;
  11 +import org.springframework.http.HttpHeaders;
  12 +import org.springframework.http.ReactiveHttpOutputMessage;
  13 +import org.springframework.http.codec.HttpMessageReader;
  14 +import org.springframework.http.server.reactive.ServerHttpRequest;
  15 +import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
  16 +import org.springframework.stereotype.Component;
  17 +import org.springframework.web.reactive.function.BodyInserter;
  18 +import org.springframework.web.reactive.function.BodyInserters;
  19 +import org.springframework.web.reactive.function.server.HandlerStrategies;
  20 +import org.springframework.web.reactive.function.server.ServerRequest;
  21 +import org.springframework.web.server.ServerWebExchange;
  22 +import reactor.core.publisher.Flux;
  23 +import reactor.core.publisher.Mono;
  24 +
  25 +import java.util.List;
  26 +
  27 +import static com.diligrp.xtrade.gateway.common.constant.GatewayConst.CACHE_BODY_FILTER_ORDER;
  28 +import static com.diligrp.xtrade.gateway.common.constant.GatewayConst.CACHE_REQUEST_BODY_OBJECT_KEY;
  29 +
  30 +/**
  31 + * @Auther: miaoguoxin
  32 + * @Date: 2020/4/13 11:49
  33 + * @Description: 缓存请求body的过滤器,参考
  34 + * {@link ModifyRequestBodyGatewayFilterFactory}
  35 + */
  36 +@Component
  37 +@Slf4j
  38 +public class CacheRequestBodyGlobalFilter implements GlobalFilter, Ordered {
  39 + private static final List<HttpMessageReader<?>> messageReaders = HandlerStrategies
  40 + .withDefaults().messageReaders();
  41 +
  42 + @Override
  43 + public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  44 + ServerRequest serverRequest = ServerRequest.create(exchange,
  45 + messageReaders);
  46 + Mono<String> modifiedBody = serverRequest.bodyToMono(String.class)
  47 + .flatMap(body -> {
  48 + exchange.getAttributes().put(CACHE_REQUEST_BODY_OBJECT_KEY, body);
  49 + return Mono.just(body);
  50 + });
  51 +
  52 + BodyInserter<Mono<String>, ReactiveHttpOutputMessage> bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
  53 + HttpHeaders headers = new HttpHeaders();
  54 + headers.putAll(exchange.getRequest().getHeaders());
  55 + //由bodyInserter重新设置content-length
  56 + headers.remove(HttpHeaders.CONTENT_LENGTH);
  57 +
  58 + CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(
  59 + exchange, headers);
  60 + return bodyInserter.insert(outputMessage, new BodyInserterContext())
  61 + // .log("modify_request", Level.INFO)
  62 + .then(Mono.defer(() -> {
  63 + ServerHttpRequest decorator = this.decorate(exchange, headers,
  64 + outputMessage);
  65 + return chain.filter(exchange.mutate().request(decorator).build());
  66 + }));
  67 + }
  68 +
  69 + private ServerHttpRequestDecorator decorate(ServerWebExchange exchange, HttpHeaders headers,
  70 + CachedBodyOutputMessage outputMessage) {
  71 + return new ServerHttpRequestDecorator(exchange.getRequest()) {
  72 + @Override
  73 + public HttpHeaders getHeaders() {
  74 + long contentLength = headers.getContentLength();
  75 + HttpHeaders httpHeaders = new HttpHeaders();
  76 + httpHeaders.putAll(headers);
  77 + if (contentLength > 0) {
  78 + httpHeaders.setContentLength(contentLength);
  79 + } else {
  80 + httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
  81 + }
  82 + return httpHeaders;
  83 + }
  84 +
  85 + @Override
  86 + public Flux<DataBuffer> getBody() {
  87 + return outputMessage.getBody();
  88 + }
  89 + };
  90 + }
  91 +
  92 + @Override
  93 + public int getOrder() {
  94 + return CACHE_BODY_FILTER_ORDER;
  95 + }
  96 +
  97 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/filters/global/ResponseReadBodyGlobalFilter.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/filters/global/ResponseReadBodyGlobalFilter.java
  1 +package com.diligrp.xtrade.gateway.filters.global;
  2 +
  3 +import lombok.extern.slf4j.Slf4j;
  4 +import org.reactivestreams.Publisher;
  5 +import org.springframework.cloud.gateway.filter.GatewayFilterChain;
  6 +import org.springframework.cloud.gateway.filter.GlobalFilter;
  7 +import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
  8 +import org.springframework.core.Ordered;
  9 +import org.springframework.core.io.buffer.DataBuffer;
  10 +import org.springframework.http.HttpHeaders;
  11 +import org.springframework.http.HttpStatus;
  12 +import org.springframework.http.MediaType;
  13 +import org.springframework.http.ReactiveHttpOutputMessage;
  14 +import org.springframework.http.codec.HttpMessageReader;
  15 +import org.springframework.http.server.reactive.ServerHttpRequest;
  16 +import org.springframework.http.server.reactive.ServerHttpResponse;
  17 +import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
  18 +import org.springframework.stereotype.Component;
  19 +import org.springframework.web.reactive.function.client.ClientResponse;
  20 +import org.springframework.web.reactive.function.server.HandlerStrategies;
  21 +import org.springframework.web.server.ServerWebExchange;
  22 +import reactor.core.publisher.Flux;
  23 +import reactor.core.publisher.Mono;
  24 +
  25 +import java.nio.charset.StandardCharsets;
  26 +import java.util.List;
  27 +import java.util.Objects;
  28 +import java.util.function.BiFunction;
  29 +
  30 +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR;
  31 +
  32 +/**
  33 + * @auther: miaoguoxin
  34 + * @date: 2018/12/26 21:26
  35 + * @description: 读取响应体过滤器
  36 + */
  37 +@Component
  38 +@Slf4j
  39 +public class ResponseReadBodyGlobalFilter implements GlobalFilter, Ordered {
  40 +
  41 + private final List<HttpMessageReader<?>> messageReaders;
  42 +
  43 + public ResponseReadBodyGlobalFilter() {
  44 + messageReaders = HandlerStrategies.withDefaults().messageReaders();
  45 + }
  46 +
  47 + @Override
  48 + public Mono<Void> filter(ServerWebExchange exchange,
  49 + GatewayFilterChain chain) {
  50 + long startTime = System.currentTimeMillis();
  51 + //重写原始响应
  52 + BodyHandlerServerHttpResponseDecorator responseDecorator = new BodyHandlerServerHttpResponseDecorator(
  53 + initBodyHandler(exchange, startTime), exchange.getResponse());
  54 + return chain.filter(exchange.mutate().response(responseDecorator).build());
  55 + }
  56 +
  57 + @Override
  58 + public int getOrder() {
  59 + //需要在NettyWriteResponseFilter之前执行
  60 + return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1;
  61 + }
  62 +
  63 + /**
  64 + * 响应body处理,添加响应的打印
  65 + *
  66 + * @param exchange
  67 + * @param startTime
  68 + * @return
  69 + */
  70 + private BodyHandlerServerHttpResponseDecorator.BodyHandlerFunction initBodyHandler(ServerWebExchange exchange, long startTime) {
  71 + return (resp, body) -> {
  72 + ServerHttpRequest request = exchange.getRequest();
  73 + //拦截
  74 + String trace = request.getHeaders().getFirst("trace");
  75 +
  76 + MediaType originalResponseContentType = MediaType.parseMediaType(Objects.requireNonNull(exchange.getAttribute(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR)));
  77 + HttpHeaders httpHeaders = new HttpHeaders();
  78 + httpHeaders.setContentType(originalResponseContentType);
  79 +
  80 + ClientResponse clientResponse = this.prepareClientResponse( exchange.getResponse().getStatusCode(),body, httpHeaders);
  81 + Mono<String> bodyMono = clientResponse.bodyToMono(String.class);
  82 + return bodyMono.flatMap(respBody -> {
  83 + //打印返回响应日志
  84 + log.debug("[Trace:{}]-gateway response:ct=[{}], status=[{}],headers=[{}],body=[{}]",
  85 + trace, System.currentTimeMillis() - startTime, resp.getStatusCode(), resp.getHeaders(), respBody);
  86 +// String errRespString = this.getErrRespString(resp.getStatusCode());
  87 +// if (!Strings.isNullOrEmpty(errRespString)) {
  88 +// resp.setStatusCode(HttpStatus.OK);
  89 +// respBody = errRespString;
  90 +// }
  91 + HttpHeaders headers = resp.getHeaders();
  92 + //特别声明:响应体改变必须设置contentLength,且长度要保持一致,(经过测试,如果过短则会截断,过长则会导致超时。)
  93 + headers.setContentLength(respBody.getBytes(StandardCharsets.UTF_8).length);
  94 + return resp.writeWith(Flux.just(respBody).map(bx -> resp.bufferFactory().wrap(bx.getBytes())));
  95 + }).then();
  96 + };
  97 + }
  98 +
  99 +
  100 +
  101 + private ClientResponse prepareClientResponse(HttpStatus httpStatus, Publisher<? extends DataBuffer> body,
  102 + HttpHeaders httpHeaders) {
  103 + ClientResponse.Builder builder;
  104 + builder = ClientResponse.create(httpStatus, messageReaders);
  105 + return builder.headers(headers -> headers.putAll(httpHeaders))
  106 + .body(Flux.from(body)).build();
  107 + }
  108 +
  109 +
  110 + protected static class BodyHandlerServerHttpResponseDecorator extends ServerHttpResponseDecorator{
  111 +
  112 + interface BodyHandlerFunction extends BiFunction<ServerHttpResponse, Publisher<? extends DataBuffer>, Mono<Void>> {
  113 +
  114 + }
  115 +
  116 + /**
  117 + * body 处理拦截器
  118 + */
  119 + private BodyHandlerServerHttpResponseDecorator.BodyHandlerFunction bodyHandler = initDefaultBodyHandler();
  120 + /**
  121 + * 构造函数
  122 + *
  123 + * @param bodyHandler
  124 + * @param delegate
  125 + */
  126 + public BodyHandlerServerHttpResponseDecorator(BodyHandlerServerHttpResponseDecorator.BodyHandlerFunction bodyHandler, ServerHttpResponse delegate) {
  127 + super(delegate);
  128 + if (bodyHandler != null) {
  129 + this.bodyHandler = bodyHandler;
  130 + }
  131 + }
  132 +
  133 + @Override
  134 + public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
  135 + //body 拦截处理器处理响应
  136 + return bodyHandler.apply(getDelegate(), body);
  137 + }
  138 +
  139 + @Override
  140 + public Mono<Void> writeAndFlushWith(
  141 + Publisher<? extends Publisher<? extends DataBuffer>> body) {
  142 + return writeWith(Flux.from(body).flatMapSequential(p -> p));
  143 + }
  144 +
  145 +
  146 + /**
  147 + * 默认body拦截处理器
  148 + *
  149 + * @return
  150 + */
  151 + private BodyHandlerServerHttpResponseDecorator.BodyHandlerFunction initDefaultBodyHandler() {
  152 + return ReactiveHttpOutputMessage::writeWith;
  153 + }
  154 + }
  155 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/filters/web/ReactiveContextWebFilter.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/filters/web/ReactiveContextWebFilter.java
  1 +package com.diligrp.xtrade.gateway.filters.web;
  2 +
  3 +import com.diligrp.xtrade.gateway.support.context.ReactiveExchangeContextHolder;
  4 +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
  5 +import org.springframework.http.server.reactive.ServerHttpRequest;
  6 +import org.springframework.stereotype.Component;
  7 +import org.springframework.web.server.ServerWebExchange;
  8 +import org.springframework.web.server.WebFilter;
  9 +import org.springframework.web.server.WebFilterChain;
  10 +import reactor.core.publisher.Mono;
  11 +import reactor.core.publisher.SignalType;
  12 +
  13 +/**
  14 + * @Auther: miaoguoxin
  15 + * @Date: 2020/4/16 09:17
  16 + * @Description: 操作reactive request和response上下文的过滤器
  17 + */
  18 +@Component
  19 +@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
  20 +public class ReactiveContextWebFilter implements WebFilter {
  21 + @Override
  22 + public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
  23 + ServerHttpRequest request = exchange.getRequest();
  24 + String path = request.getURI().getRawPath();
  25 + if (path.contains("favicon.ico")) {
  26 + return exchange.getResponse().setComplete();
  27 + }
  28 + ReactiveExchangeContextHolder.put(exchange);
  29 + return chain.filter(exchange).doFinally(signalType -> {
  30 + ReactiveExchangeContextHolder.remove();
  31 + });
  32 + }
  33 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/predicates/ReadBodyRoutePredicateFactory.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/predicates/ReadBodyRoutePredicateFactory.java
  1 +package com.diligrp.xtrade.gateway.predicates;
  2 +
  3 +import com.diligrp.xtrade.gateway.filters.global.CacheRequestBodyGlobalFilter;
  4 +import lombok.Data;
  5 +import lombok.extern.slf4j.Slf4j;
  6 +import org.springframework.cloud.gateway.handler.AsyncPredicate;
  7 +import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
  8 +import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
  9 +import org.springframework.http.HttpHeaders;
  10 +import org.springframework.http.codec.HttpMessageReader;
  11 +import org.springframework.http.server.reactive.ServerHttpRequest;
  12 +import org.springframework.stereotype.Component;
  13 +import org.springframework.web.reactive.function.server.HandlerStrategies;
  14 +import org.springframework.web.reactive.function.server.ServerRequest;
  15 +import org.springframework.web.server.ServerWebExchange;
  16 +import reactor.core.Disposable;
  17 +import reactor.core.publisher.Mono;
  18 +
  19 +import java.time.Duration;
  20 +import java.util.List;
  21 +import java.util.function.Consumer;
  22 +import java.util.function.Function;
  23 +import java.util.function.Predicate;
  24 +
  25 +import static com.diligrp.xtrade.gateway.common.constant.GatewayConst.CACHE_REQUEST_BODY_OBJECT_KEY;
  26 +
  27 +
  28 +/**
  29 + * @Auther: miaoguoxin
  30 + * @Date: 2019/3/25 0025 10:47
  31 + * @Description: 缓存请求体数据predicate
  32 + * {@link CacheRequestBodyGlobalFilter}
  33 + */
  34 +@Slf4j
  35 +//@Component
  36 +@Deprecated
  37 +public class ReadBodyRoutePredicateFactory extends AbstractRoutePredicateFactory<ReadBodyRoutePredicateFactory.Config> {
  38 + private static final List<HttpMessageReader<?>> messageReaders = HandlerStrategies
  39 + .withDefaults().messageReaders();
  40 +
  41 + public ReadBodyRoutePredicateFactory() {
  42 + super(Config.class);
  43 + }
  44 +
  45 +
  46 + @Override
  47 + public Predicate<ServerWebExchange> apply(Config config) {
  48 + throw new UnsupportedOperationException(
  49 + "ReadBodyRoutePredicateFactory is only async.");
  50 + }
  51 +
  52 + public AsyncPredicate<ServerWebExchange> applyAsync(Config config) {
  53 + return exchange -> {
  54 + ServerHttpRequest request = exchange.getRequest();
  55 + HttpHeaders headers = request.getHeaders();
  56 + log.info("请求headers:{}",headers);
  57 + String rawPath = request.getURI().getRawPath();
  58 + //兼容没有content-type的情况
  59 + String contentTypeStr = headers.getFirst("Content-Type");
  60 + if (contentTypeStr == null) {
  61 + log.warn("consider your Content-Type empty?---" + rawPath);
  62 + return Mono.just(Boolean.TRUE);
  63 + }
  64 + //文件上传直接跳过
  65 + if (contentTypeStr.startsWith("multipart/form-data")) {
  66 + return Mono.just(Boolean.TRUE);
  67 + }
  68 + // String cachedBody = exchange.getAttribute(CACHE_REQUEST_BODY_OBJECT_KEY);
  69 +// BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
  70 +// //因为请求体可能是null,这里自定义个缓存输出
  71 +// CustomCacheBodyOutputMessage outputMessage = new CustomCacheBodyOutputMessage(exchange, headers);
  72 + return ServerWebExchangeUtils.cacheRequestBodyAndRequest(exchange,
  73 + (serverHttpRequest) -> ServerRequest
  74 + .create(exchange.mutate().request(serverHttpRequest)
  75 + .build(), messageReaders)
  76 + .bodyToMono(String.class)
  77 + .doOnNext(new Consumer<String>() {
  78 + @Override
  79 + public void accept(String objectValue) {
  80 + exchange.getAttributes().put(CACHE_REQUEST_BODY_OBJECT_KEY, objectValue);
  81 + }
  82 + })
  83 + .map(objectValue -> Boolean.TRUE));
  84 + };
  85 + }
  86 +
  87 + @Data
  88 + public static class Config {
  89 + //需要跳过的uri
  90 + private String shouldSkipUri;
  91 +
  92 + }
  93 +
  94 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/repository/GatewayRepository.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/repository/GatewayRepository.java
  1 +package com.diligrp.xtrade.gateway.repository;
  2 +
  3 +import com.diligrp.xtrade.gateway.common.constant.GatewayAttrType;
  4 +import com.diligrp.xtrade.gateway.exception.GatewayServiceException;
  5 +import com.diligrp.xtrade.gateway.repository.dao.AttrConfigDao;
  6 +import com.diligrp.xtrade.gateway.repository.dao.RouteDao;
  7 +import com.diligrp.xtrade.gateway.repository.entity.GatewayAttrConfig;
  8 +import com.diligrp.xtrade.gateway.repository.entity.GatewayConfig;
  9 +import com.diligrp.xtrade.shared.util.JsonUtils;
  10 +import com.diligrp.xtrade.shared.util.ReflectUtils;
  11 +import com.fasterxml.jackson.core.type.TypeReference;
  12 +import com.google.common.base.Strings;
  13 +import org.springframework.beans.factory.annotation.Autowired;
  14 +import org.springframework.cloud.gateway.filter.FilterDefinition;
  15 +import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
  16 +import org.springframework.cloud.gateway.route.RouteDefinition;
  17 +import org.springframework.stereotype.Repository;
  18 +import org.springframework.util.CollectionUtils;
  19 +import org.springframework.web.util.UriComponentsBuilder;
  20 +import reactor.core.publisher.Mono;
  21 +
  22 +import java.lang.reflect.InvocationTargetException;
  23 +import java.net.URI;
  24 +import java.net.URISyntaxException;
  25 +import java.util.ArrayList;
  26 +import java.util.Comparator;
  27 +import java.util.LinkedHashMap;
  28 +import java.util.List;
  29 +import java.util.Map;
  30 +import java.util.stream.Collectors;
  31 +
  32 +/**
  33 + * @Auther: miaoguoxin
  34 + * @Date: 2020/4/10 14:46
  35 + */
  36 +@Repository
  37 +public class GatewayRepository implements IGatewayRepository {
  38 + @Autowired
  39 + private RouteDao routeDao;
  40 + @Autowired
  41 + private AttrConfigDao attrConfigDao;
  42 +
  43 + @Override
  44 + public List<RouteDefinition> getAll() {
  45 + List<GatewayConfig> gatewayConfigs = routeDao.findAllForLoad();
  46 + List<GatewayAttrConfig> allAttrConfigs = attrConfigDao.findAllForLoad();
  47 + Map<String , List<GatewayAttrConfig>> attrMap = allAttrConfigs.stream()
  48 + .collect(Collectors.groupingBy(GatewayAttrConfig::getServiceId));
  49 + gatewayConfigs.forEach(config->{
  50 + List<GatewayAttrConfig> attrConfigs = attrMap.get(config.getServiceId());
  51 + if (!CollectionUtils.isEmpty(attrConfigs)){
  52 + attrConfigs.sort(Comparator.comparing(GatewayAttrConfig::getSortOrder));
  53 + config.setAttrConfigs(attrConfigs);
  54 + }
  55 + });
  56 + return gatewayConfigs.stream()
  57 + .map(this::generateRouteDefinition)
  58 + .collect(Collectors.toList());
  59 + }
  60 +
  61 + private RouteDefinition generateRouteDefinition(GatewayConfig gatewayConfig) {
  62 + RouteDefinition definition = new RouteDefinition();
  63 + definition.setId(gatewayConfig.getServiceId());
  64 + try {
  65 + //必须要加上协议头才能访问
  66 + URI uri;
  67 + if (gatewayConfig.getUrl().startsWith("lb")) {
  68 + uri = new URI(gatewayConfig.getUrl());
  69 + } else {
  70 + uri = UriComponentsBuilder.fromHttpUrl(gatewayConfig.getUrl()).build().toUri();
  71 + }
  72 + definition.setUri(uri);
  73 + } catch (URISyntaxException e) {
  74 + throw new GatewayServiceException("get url failed",e);
  75 + }
  76 + //设置predicate和filter
  77 + this.setPredicatesAndFilters(gatewayConfig, definition);
  78 + return definition;
  79 + }
  80 +
  81 + private void setPredicatesAndFilters(GatewayConfig gatewayConfig, RouteDefinition definition) {
  82 + List<GatewayAttrConfig> gatewayAttrConfigs = gatewayConfig.getAttrConfigs();
  83 + if (gatewayAttrConfigs.isEmpty()) {
  84 + throw new GatewayServiceException("gateway attrs can not allow empty, please check");
  85 + }
  86 + List<PredicateDefinition> predicateDefinitions = new ArrayList<>();
  87 + List<FilterDefinition> filterDefinitions = new ArrayList<>();
  88 + for (GatewayAttrConfig gatewayAttrConfig : gatewayAttrConfigs) {
  89 + if (GatewayAttrType.PREDICATE.getValue() == gatewayAttrConfig.getType()) {
  90 + predicateDefinitions.add(this.generatePredicateOrFilter(gatewayAttrConfig,PredicateDefinition.class));
  91 + } else {
  92 + filterDefinitions.add(this.generatePredicateOrFilter(gatewayAttrConfig,FilterDefinition.class));
  93 + }
  94 + }
  95 + definition.setPredicates(predicateDefinitions);
  96 + definition.setFilters(filterDefinitions);
  97 + }
  98 +
  99 +
  100 + private <T> T generatePredicateOrFilter(GatewayAttrConfig gatewayAttrConfig,Class<T> clazz) {
  101 + T target;
  102 + try {
  103 + target = clazz.getDeclaredConstructor().newInstance();
  104 + //设置predicate或者filter的名称
  105 + ReflectUtils.invokeMethod(
  106 + target,
  107 + "setName",
  108 + new Class[]{String.class},
  109 + new Object[]{gatewayAttrConfig.getAttrName()});
  110 + //设置predicate或者filter的参数
  111 + if (!Strings.isNullOrEmpty(gatewayAttrConfig.getAttrArgs())) {
  112 + Map<String, String> args = JsonUtils.fromJsonString(
  113 + gatewayAttrConfig.getAttrArgs(),
  114 + new TypeReference<LinkedHashMap<String, String>>() {});
  115 + ReflectUtils.invokeMethod(
  116 + target,
  117 + "setArgs",
  118 + new Class[]{Map.class},
  119 + new Object[]{args}
  120 + );
  121 + }
  122 + } catch (IllegalAccessException
  123 + | InvocationTargetException
  124 + | InstantiationException
  125 + |NoSuchMethodException e) {
  126 + throw new GatewayServiceException("init gateway resource failed",
  127 + e,
  128 + new Object[]{JsonUtils.toJsonString(gatewayAttrConfig)});
  129 + }
  130 + return target;
  131 + }
  132 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/repository/IGatewayRepository.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/repository/IGatewayRepository.java
  1 +package com.diligrp.xtrade.gateway.repository;
  2 +
  3 +import org.springframework.cloud.gateway.route.RouteDefinition;
  4 +
  5 +import java.util.List;
  6 +
  7 +/**
  8 + * @Auther: miaoguoxin
  9 + * @Date: 2020/4/10 14:39
  10 + */
  11 +public interface IGatewayRepository {
  12 + /**
  13 + * 获取所有路由资源配置
  14 + * @param
  15 + * @return
  16 + * @author miaoguoxin
  17 + * @date 2020/4/10
  18 + */
  19 + List<RouteDefinition> getAll();
  20 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/repository/dao/AttrConfigDao.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/repository/dao/AttrConfigDao.java
  1 +package com.diligrp.xtrade.gateway.repository.dao;
  2 +
  3 +import com.diligrp.xtrade.gateway.repository.entity.GatewayAttrConfig;
  4 +
  5 +import java.util.List;
  6 +
  7 +/**
  8 + * @Auther: miaoguoxin
  9 + * @Date: 2020/4/10 15:06
  10 + * @Description: t_attr_config mapper
  11 + */
  12 +public interface AttrConfigDao {
  13 +
  14 + List<GatewayAttrConfig> findAllForLoad();
  15 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/repository/dao/RouteDao.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/repository/dao/RouteDao.java
  1 +package com.diligrp.xtrade.gateway.repository.dao;
  2 +
  3 +import com.diligrp.xtrade.gateway.repository.entity.GatewayConfig;
  4 +
  5 +import java.util.List;
  6 +
  7 +/**
  8 + * @Auther: miaoguoxin
  9 + * @Date: 2020/4/10 14:51
  10 + * @Description: t_router mapper
  11 + */
  12 +public interface RouteDao {
  13 +
  14 + List<GatewayConfig> findAllForLoad();
  15 +
  16 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/repository/entity/GatewayAttrConfig.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/repository/entity/GatewayAttrConfig.java
  1 +package com.diligrp.xtrade.gateway.repository.entity;
  2 +
  3 +import com.diligrp.xtrade.gateway.common.constant.GatewayAttrType;
  4 +import com.diligrp.xtrade.shared.domain.BaseDo;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +
  8 +/**
  9 + * @Auther: miaoguoxin
  10 + * @Date: 2018/12/12 0012 17:43
  11 + * @Description: 网关断言和过滤器配置实体
  12 + */
  13 +@EqualsAndHashCode(callSuper = true)
  14 +@Data
  15 +public class GatewayAttrConfig extends BaseDo{
  16 + /**服务id名称*/
  17 + private String serviceId;
  18 + /**类型 {@link GatewayAttrType}*/
  19 + private Integer type;
  20 + /**predicate或者filter的名称*/
  21 + private String attrName;
  22 + /** predicate或者filter所需的参数 json格式*/
  23 + private String attrArgs;
  24 + /**描述*/
  25 + private String description;
  26 + /**排序*/
  27 + private Integer sortOrder;
  28 + /**1:删除 0:正常*/
  29 + private Integer isDel;
  30 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/repository/entity/GatewayConfig.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/repository/entity/GatewayConfig.java
  1 +package com.diligrp.xtrade.gateway.repository.entity;
  2 +
  3 +import com.diligrp.xtrade.shared.domain.BaseDo;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +
  7 +import java.util.List;
  8 +
  9 +/**
  10 + * @Auther: miaoguoxin
  11 + * @Date: 2018/12/11 0011 14:53
  12 + * @Description: 路由配置实体
  13 + */
  14 +@EqualsAndHashCode(callSuper = true)
  15 +@Data
  16 +public class GatewayConfig extends BaseDo {
  17 + /**服务id名称*/
  18 + private String serviceId;
  19 + /**路由url*/
  20 + private String url;
  21 + /** 1:删除 0:正常*/
  22 + private Integer isDel;
  23 + /**描述*/
  24 + private String description;
  25 + /**包含predicate和filter*/
  26 + private List<GatewayAttrConfig> attrConfigs;
  27 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/route/DynamicRouteLoaderIntf.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/route/DynamicRouteLoaderIntf.java
  1 +package com.diligrp.xtrade.gateway.route;
  2 +
  3 +/**
  4 + * @Auther: miaoguoxin
  5 + * @Date: 2020/4/2 14:01
  6 + */
  7 +public interface DynamicRouteLoaderIntf {
  8 +
  9 + void init();
  10 +
  11 + void refreshApis();
  12 +
  13 + void refreshRoutes();
  14 +
  15 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/route/GatewayResourcesLoader.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/route/GatewayResourcesLoader.java
  1 +package com.diligrp.xtrade.gateway.route;
  2 +
  3 +import org.springframework.beans.factory.annotation.Autowired;
  4 +import org.springframework.boot.ApplicationArguments;
  5 +import org.springframework.boot.ApplicationRunner;
  6 +import org.springframework.stereotype.Component;
  7 +
  8 +/**
  9 + * @Auther: miaoguoxin
  10 + * @Date: 2020/4/2 14:00
  11 + * @Description: 初始化网关所需资源的入口
  12 + */
  13 +@Component
  14 +public class GatewayResourcesLoader implements ApplicationRunner {
  15 + @Autowired
  16 + private DynamicRouteLoaderIntf dynamicRouteLoader;
  17 +
  18 + @Override
  19 + public void run(ApplicationArguments args) throws Exception {
  20 + dynamicRouteLoader.init();
  21 + }
  22 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/route/impl/CloudRouteResourceLoader.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/route/impl/CloudRouteResourceLoader.java
  1 +package com.diligrp.xtrade.gateway.route.impl;
  2 +
  3 +import com.alibaba.nacos.api.config.ConfigService;
  4 +import com.alibaba.nacos.api.config.listener.Listener;
  5 +import com.alibaba.nacos.api.exception.NacosException;
  6 +import com.diligrp.xtrade.gateway.config.GatewayResourceLoaderConfiguration;
  7 +import com.diligrp.xtrade.gateway.exception.GatewayServiceException;
  8 +import com.diligrp.xtrade.gateway.route.DynamicRouteLoaderIntf;
  9 +import lombok.extern.slf4j.Slf4j;
  10 +import org.springframework.beans.factory.annotation.Autowired;
  11 +import org.springframework.beans.factory.annotation.Value;
  12 +import org.springframework.cloud.gateway.config.GatewayProperties;
  13 +import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
  14 +import org.springframework.cloud.gateway.route.RouteDefinition;
  15 +import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
  16 +import org.springframework.context.ApplicationContext;
  17 +import reactor.core.publisher.Mono;
  18 +
  19 +import javax.annotation.Resource;
  20 +import java.util.List;
  21 +import java.util.Timer;
  22 +import java.util.TimerTask;
  23 +import java.util.concurrent.Executor;
  24 +import java.util.concurrent.atomic.AtomicBoolean;
  25 +
  26 +/**
  27 + * @Auther: miaoguoxin
  28 + * @Date: 2020/4/2 14:02
  29 + * @Description: 从云端配置中心加载
  30 + * {@link GatewayResourceLoaderConfiguration} 配置
  31 + */
  32 +@Slf4j
  33 +public class CloudRouteResourceLoader implements DynamicRouteLoaderIntf {
  34 + /**标记当前gatewayproties的hash值,用于判断配置是否更新过*/
  35 + private static int gatewayPropertiesHash;
  36 + /**防止重复初始化的标记*/
  37 + private static AtomicBoolean hasInit = new AtomicBoolean(false);
  38 +
  39 + private final static String GROUP = "DEFAULT_GROUP";
  40 + private final static String ROUTE_CONFIG_NAME = "route.properties";
  41 +
  42 +
  43 + @Value("${spring.application.name}")
  44 + private String applicationName;
  45 + @Value("${spring.profiles.active}")
  46 + private String activeProfile;
  47 + @Value("${spring.cloud.nacos.config.file-extension}")
  48 + private String fileType;
  49 + @Autowired
  50 + private ApplicationContext applicationContext;
  51 + @Resource
  52 + private RouteDefinitionWriter routeDefinitionWriter;
  53 + @Autowired
  54 + private ConfigService configService;
  55 + @Autowired
  56 + private GatewayProperties gatewayProperties;
  57 +
  58 + @Override
  59 + public void init() {
  60 + if (hasInit.compareAndSet(false, true)) {
  61 + this.loadRoutes();
  62 + //用来判断routes是否改变过,避免无效刷新
  63 + gatewayPropertiesHash = gatewayProperties.getRoutes().hashCode();
  64 + }
  65 + }
  66 +
  67 + @Override
  68 + public void refreshApis() {
  69 +
  70 + }
  71 +
  72 + @Override
  73 + public void refreshRoutes() {
  74 + this.notifyRefreshRoutes();
  75 + }
  76 +
  77 +
  78 + /**
  79 + * 通过nacos配置中心监听配置变化,
  80 + * 完成路由资源装载
  81 + * @author miaoguoxin
  82 + * @date 2020/4/10
  83 + */
  84 + private void loadRoutes() {
  85 + //只有放到标准的配置文件下,才能够成功刷新配置
  86 + String configFile = String.format("%s-%s.%s", applicationName, activeProfile, fileType);
  87 + try {
  88 + configService.getConfigAndSignListener(
  89 + ROUTE_CONFIG_NAME,
  90 + GROUP,
  91 + 5000,
  92 + new Listener() {
  93 + @Override
  94 + public void receiveConfigInfo(String configInfo) {
  95 + Timer timer = new Timer(true);
  96 + TimerTask task = new TimerTask() {
  97 + @Override
  98 + public void run() {
  99 + notifyRefreshRoutes();
  100 + }
  101 + };
  102 + //由于属性刷新有延迟,这里延长点时间
  103 + timer.schedule(task, 5000);
  104 + }
  105 +
  106 + @Override
  107 + public Executor getExecutor() {
  108 + return null;
  109 + }
  110 + });
  111 + } catch (NacosException e) {
  112 + throw new GatewayServiceException("load route resource failed", e);
  113 + }
  114 + }
  115 +
  116 +
  117 + private void notifyRefreshRoutes() {
  118 + synchronized (CloudRouteResourceLoader.this){
  119 + if (gatewayPropertiesHash == gatewayProperties.getRoutes().hashCode()) {
  120 + return;
  121 + }
  122 + List<RouteDefinition> routes = gatewayProperties.getRoutes();
  123 + routes.forEach(definition ->
  124 + routeDefinitionWriter.save(Mono.just(definition)).subscribe());
  125 + applicationContext.publishEvent(new RefreshRoutesEvent(this));
  126 + gatewayPropertiesHash = gatewayProperties.getRoutes().hashCode();
  127 + log.info("refresh route success");
  128 + }
  129 + }
  130 +
  131 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/route/impl/MysqlRouteResourceLoader.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/route/impl/MysqlRouteResourceLoader.java
  1 +package com.diligrp.xtrade.gateway.route.impl;
  2 +
  3 +import com.diligrp.xtrade.gateway.config.GatewayResourceLoaderConfiguration;
  4 +import com.diligrp.xtrade.gateway.repository.IGatewayRepository;
  5 +import com.diligrp.xtrade.gateway.route.DynamicRouteLoaderIntf;
  6 +import lombok.extern.slf4j.Slf4j;
  7 +import org.springframework.beans.factory.annotation.Autowired;
  8 +import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
  9 +import org.springframework.cloud.gateway.route.RouteDefinition;
  10 +import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
  11 +import org.springframework.context.ApplicationContext;
  12 +import reactor.core.publisher.Mono;
  13 +
  14 +import javax.annotation.Resource;
  15 +import java.util.List;
  16 +
  17 +/**
  18 + * @Auther: miaoguoxin
  19 + * @Date: 2020/4/10 13:18
  20 + * @Description: 从数据库加载
  21 + * 通过 {@link GatewayResourceLoaderConfiguration} 配置
  22 + */
  23 +@Slf4j
  24 +public class MysqlRouteResourceLoader implements DynamicRouteLoaderIntf {
  25 + @Autowired
  26 + private ApplicationContext applicationContext;
  27 + @Autowired
  28 + private IGatewayRepository gatewayRepository;
  29 + @Resource
  30 + private RouteDefinitionWriter routeDefinitionWriter;
  31 +
  32 +
  33 + public MysqlRouteResourceLoader() {
  34 +
  35 + }
  36 +
  37 + @Override
  38 + public void init() {
  39 + this.refreshRoutes();
  40 + }
  41 +
  42 + @Override
  43 + public void refreshApis(){
  44 +
  45 + }
  46 +
  47 + @Override
  48 + public void refreshRoutes() {
  49 + List<RouteDefinition> routeDefinitions = gatewayRepository.getAll();
  50 + routeDefinitions.forEach(definition ->
  51 + routeDefinitionWriter.save(Mono.just(definition)).subscribe());
  52 + applicationContext.publishEvent(new RefreshRoutesEvent(this));
  53 + log.info("route resources load success");
  54 + }
  55 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/support/context/ReactiveExchangeContextHolder.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/support/context/ReactiveExchangeContextHolder.java
  1 +package com.diligrp.xtrade.gateway.support.context;
  2 +
  3 +import org.springframework.web.server.ServerWebExchange;
  4 +
  5 +/**
  6 + * @Auther: miaoguoxin
  7 + * @Date: 2020/4/16 09:09
  8 + * @Description: 保存 ServerWebExchange 变量
  9 + */
  10 +public class ReactiveExchangeContextHolder {
  11 + /**让该变量可以在父子线程间传递*/
  12 + private static final ThreadLocal<ServerWebExchange> REQUEST_THREAD_LOCAL = new InheritableThreadLocal<>();
  13 +
  14 + public static void put(ServerWebExchange exchange){
  15 + REQUEST_THREAD_LOCAL.set(exchange);
  16 + }
  17 +
  18 + public static ServerWebExchange get(){
  19 + return REQUEST_THREAD_LOCAL.get();
  20 + }
  21 +
  22 + public static void remove(){
  23 + REQUEST_THREAD_LOCAL.remove();
  24 + }
  25 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/support/context/ReactiveRequestBeanProcessor.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/support/context/ReactiveRequestBeanProcessor.java
  1 +package com.diligrp.xtrade.gateway.support.context;
  2 +
  3 +import org.springframework.beans.BeansException;
  4 +import org.springframework.beans.factory.ObjectFactory;
  5 +import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
  6 +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
  7 +import org.springframework.http.server.reactive.ServerHttpRequest;
  8 +import org.springframework.http.server.reactive.ServerHttpResponse;
  9 +import org.springframework.stereotype.Component;
  10 +
  11 +import java.io.Serializable;
  12 +
  13 +/**
  14 + * @Auther: miaoguoxin
  15 + * @Date: 2020/4/16 09:13
  16 + * @Description:
  17 + */
  18 +@Component
  19 +public class ReactiveRequestBeanProcessor implements BeanFactoryPostProcessor {
  20 +
  21 + @Override
  22 + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
  23 + beanFactory.registerResolvableDependency(ServerHttpRequest.class,new ReactiveRequestObjectFactory());
  24 + beanFactory.registerResolvableDependency(ServerHttpResponse.class,new ReactiveResponseObjectFactory());
  25 + }
  26 +
  27 + private static class ReactiveRequestObjectFactory implements ObjectFactory<ServerHttpRequest>, Serializable {
  28 +
  29 + @Override
  30 + public ServerHttpRequest getObject() throws BeansException {
  31 + return ReactiveExchangeContextHolder.get().getRequest();
  32 + }
  33 + }
  34 +
  35 + private static class ReactiveResponseObjectFactory implements ObjectFactory<ServerHttpResponse>, Serializable {
  36 +
  37 + @Override
  38 + public ServerHttpResponse getObject() throws BeansException {
  39 + return ReactiveExchangeContextHolder.get().getResponse();
  40 + }
  41 + }
  42 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/support/dispatch/DispatchContext.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/support/dispatch/DispatchContext.java
  1 +package com.diligrp.xtrade.gateway.support.dispatch;
  2 +
  3 +import lombok.Getter;
  4 +import org.springframework.http.server.reactive.ServerHttpRequest;
  5 +import org.springframework.http.server.reactive.ServerHttpResponse;
  6 +
  7 +/**
  8 + * @Auther: miaoguoxin
  9 + * @Date: 2020/4/16 09:20
  10 + */
  11 +@Getter
  12 +public class DispatchContext<T> {
  13 + private ServerHttpRequest request;
  14 + private ServerHttpResponse response;
  15 + /**请求参数*/
  16 + private T param;
  17 +
  18 + public DispatchContext(ServerHttpRequest request, ServerHttpResponse response, T param) {
  19 + this.request = request;
  20 + this.response = response;
  21 + this.param = param;
  22 + }
  23 +
  24 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/support/dispatch/MappingMetaInfo.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/support/dispatch/MappingMetaInfo.java
  1 +package com.diligrp.xtrade.gateway.support.dispatch;
  2 +
  3 +import lombok.Getter;
  4 +import org.springframework.validation.annotation.Validated;
  5 +
  6 +import java.lang.reflect.Method;
  7 +
  8 +/**
  9 + * @Auther: miaoguoxin
  10 + * @Date: 2020/4/15 09:57
  11 + */
  12 +@Getter
  13 +public class MappingMetaInfo {
  14 + /**方法所属的bean class*/
  15 + private Class<?> targetClass;
  16 + /** 需要执行的方法 */
  17 + private Method targetMethod;
  18 + /***/
  19 + private Validated validated;
  20 + /**泛化参数类型 {@link DispatchContext#getParam()}*/
  21 + private Class<?> parameterType;
  22 +
  23 + public MappingMetaInfo(Class<?> targetBean, Method targetMethod) {
  24 + this.targetClass = targetBean;
  25 + this.targetMethod = targetMethod;
  26 + }
  27 +
  28 + public MappingMetaInfo(Class<?> targetClass, Method targetMethod, Validated validated, Class<?> parameterType) {
  29 + this.targetClass = targetClass;
  30 + this.targetMethod = targetMethod;
  31 + this.validated = validated;
  32 + this.parameterType = parameterType;
  33 + }
  34 +
  35 + @Override
  36 + public String toString() {
  37 + return "MappingInfo{" +
  38 + "targetBean=" + targetClass.getName() +
  39 + ", targetMethod=" + targetMethod.getName() +
  40 + '}';
  41 + }
  42 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/support/dispatch/MappingRegister.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/support/dispatch/MappingRegister.java
  1 +package com.diligrp.xtrade.gateway.support.dispatch;
  2 +
  3 +import com.diligrp.xtrade.gateway.XtradeGatewayApplication;
  4 +import com.diligrp.xtrade.gateway.common.annotation.DispatchMapping;
  5 +import com.diligrp.xtrade.gateway.common.constant.GatewayConst;
  6 +import com.diligrp.xtrade.gateway.common.utils.PathUtils;
  7 +import com.diligrp.xtrade.gateway.config.property.DispatchProperties;
  8 +import lombok.extern.slf4j.Slf4j;
  9 +import org.reflections.Reflections;
  10 +import org.reflections.scanners.FieldAnnotationsScanner;
  11 +import org.reflections.scanners.MethodAnnotationsScanner;
  12 +import org.reflections.scanners.SubTypesScanner;
  13 +import org.reflections.util.ConfigurationBuilder;
  14 +import org.springframework.beans.factory.annotation.Autowired;
  15 +import org.springframework.boot.SpringApplication;
  16 +import org.springframework.context.ApplicationContext;
  17 +import org.springframework.context.ApplicationListener;
  18 +import org.springframework.context.event.ContextRefreshedEvent;
  19 +import org.springframework.stereotype.Component;
  20 +import org.springframework.validation.annotation.Validated;
  21 +
  22 +import java.lang.annotation.Annotation;
  23 +import java.lang.reflect.Method;
  24 +import java.lang.reflect.ParameterizedType;
  25 +import java.lang.reflect.Type;
  26 +import java.util.Set;
  27 +
  28 +/**
  29 + * @Auther: miaoguoxin
  30 + * @Date: 2020/4/15 09:29
  31 + * @Description: 注册聚合服务方法映射
  32 + */
  33 +@Component
  34 +@Slf4j
  35 +public class MappingRegister implements ApplicationListener<ContextRefreshedEvent> {
  36 + @Autowired
  37 + private ApplicationContext applicationContext;
  38 + @Autowired
  39 + private DispatchProperties dispatchProperties;
  40 +
  41 + @Override
  42 + public void onApplicationEvent(ContextRefreshedEvent event) {
  43 + if (GatewayConst.HAS_INIT_MAPPING.compareAndSet(false, true)) {
  44 + String[] scanPackages = this.getScanPackages();
  45 + Reflections reflections = new Reflections(new ConfigurationBuilder()
  46 + .forPackages(scanPackages)
  47 + .addScanners(new SubTypesScanner())
  48 + .addScanners(new MethodAnnotationsScanner())
  49 + .addScanners(new FieldAnnotationsScanner()));
  50 + try {
  51 +
  52 + Set<Method> methodMappings = reflections.getMethodsAnnotatedWith(DispatchMapping.class);
  53 + for (Method method : methodMappings) {
  54 + //只扫描参数为DispatchContext的方法
  55 + Class<?>[] parameterTypes = method.getParameterTypes();
  56 + if (parameterTypes.length != 1 || !DispatchContext.class.isAssignableFrom(parameterTypes[0])) {
  57 + continue;
  58 + }
  59 + DispatchMapping methodAnnotation = method.getAnnotation(DispatchMapping.class);
  60 + String methodPath = methodAnnotation.value();
  61 + String classUriPath = "";
  62 + //这里meta信息只传入bean的class,在dispatch中再获取真实的bean,为了能够多例bean使用
  63 + Class<?> declaringClass = method.getDeclaringClass();
  64 + if (declaringClass.isAnnotationPresent(DispatchMapping.class)) {
  65 + DispatchMapping classAnnotation = declaringClass.getAnnotation(DispatchMapping.class);
  66 + classUriPath = classAnnotation.value();
  67 + }
  68 + String uri = PathUtils.concatUri(classUriPath, methodPath);
  69 + //获取泛型参数类型
  70 + Class<?> parameterType = getParameterType(method);
  71 + //dispatch的时候判断校验参数
  72 + Validated validated = getValidateAnnotation(method);
  73 + MappingMetaInfo mappingMetaInfo = new MappingMetaInfo(declaringClass, method, validated, parameterType);
  74 + RequestDispatcher.addMapping(uri, mappingMetaInfo);
  75 + log.info("register aggregation mapping 【{}】", uri);
  76 + }
  77 + } catch (Exception e) {
  78 + log.error("register mappingMetaInfo error:{}",e);
  79 + //发生异常直接退出,防止后续无法调用服务
  80 + int exit = SpringApplication.exit(applicationContext, () -> 0);
  81 + System.exit(exit);
  82 + }
  83 + }
  84 + }
  85 +
  86 + private static Class<?> getParameterType(Method method) throws ClassNotFoundException {
  87 + Type[] genericParameterTypes = method.getGenericParameterTypes();
  88 + if (genericParameterTypes.length == 1 && genericParameterTypes[0] instanceof ParameterizedType) {
  89 + ParameterizedType type = (ParameterizedType) genericParameterTypes[0];
  90 + Type[] params = type.getActualTypeArguments();
  91 + return Class.forName(params[0].getTypeName());
  92 + }
  93 + return null;
  94 + }
  95 +
  96 + private static Validated getValidateAnnotation(Method method){
  97 + Annotation[][] parameterAnnotations = method.getParameterAnnotations();
  98 + for (Annotation[] parameterAnnotation : parameterAnnotations) {
  99 + for (Annotation annotation : parameterAnnotation) {
  100 + if (Validated.class == annotation.annotationType()){
  101 + return (Validated)annotation;
  102 + }
  103 + }
  104 + }
  105 + return null;
  106 + }
  107 +
  108 +
  109 + private String[] getScanPackages() {
  110 + String[] scanPackages = dispatchProperties.getAggregationScanPackages();
  111 + if (scanPackages == null || scanPackages.length == 0) {
  112 + return new String[]{XtradeGatewayApplication.class.getPackageName()};
  113 + }
  114 + return scanPackages;
  115 + }
  116 +
  117 +}
... ...
src/main/java/com/diligrp/xtrade/gateway/support/dispatch/RequestDispatcher.java 0 → 100644
  1 +++ a/src/main/java/com/diligrp/xtrade/gateway/support/dispatch/RequestDispatcher.java
  1 +package com.diligrp.xtrade.gateway.support.dispatch;
  2 +
  3 +import com.diligrp.xtrade.gateway.application.TestAggregationApplication;
  4 +import com.diligrp.xtrade.gateway.common.utils.PathUtils;
  5 +import com.diligrp.xtrade.gateway.common.utils.ValidateUtils;
  6 +import com.diligrp.xtrade.gateway.domain.TestRequestDto;
  7 +import com.diligrp.xtrade.gateway.exception.GatewayParamNotValidException;
  8 +import com.diligrp.xtrade.gateway.exception.GatewayServiceException;
  9 +import com.diligrp.xtrade.gateway.filters.factory.DispatchGatewayFilterFactory;
  10 +import com.diligrp.xtrade.gateway.route.DynamicRouteLoaderIntf;
  11 +import com.diligrp.xtrade.gateway.route.impl.MysqlRouteResourceLoader;
  12 +import com.diligrp.xtrade.shared.domain.Message;
  13 +import com.diligrp.xtrade.shared.type.SystemCode;
  14 +import com.diligrp.xtrade.shared.util.JsonUtils;
  15 +import com.google.common.base.Strings;
  16 +import lombok.extern.slf4j.Slf4j;
  17 +import org.bouncycastle.util.Arrays;
  18 +import org.springframework.beans.factory.annotation.Autowired;
  19 +import org.springframework.cloud.gateway.support.NotFoundException;
  20 +import org.springframework.context.ApplicationContext;
  21 +import org.springframework.stereotype.Component;
  22 +import org.springframework.validation.annotation.Validated;
  23 +import org.springframework.web.server.ResponseStatusException;
  24 +import org.springframework.web.server.ServerWebExchange;
  25 +import org.springframework.web.server.ServerWebInputException;
  26 +import org.springframework.web.util.pattern.PathPattern;
  27 +
  28 +import java.lang.reflect.InvocationTargetException;
  29 +import java.lang.reflect.Method;
  30 +import java.lang.reflect.ParameterizedType;
  31 +import java.lang.reflect.Type;
  32 +import java.util.List;
  33 +import java.util.Map;
  34 +import java.util.Optional;
  35 +import java.util.concurrent.ConcurrentHashMap;
  36 +import java.util.concurrent.CopyOnWriteArrayList;
  37 +import java.util.concurrent.atomic.AtomicBoolean;
  38 +
  39 +/**
  40 + * @Auther: miaoguoxin
  41 + * @Date: 2020/4/15 09:29
  42 + * @Description: 映射分发器, 用于聚合服务执行对应方法
  43 + * {@link DispatchGatewayFilterFactory}
  44 + */
  45 +@Component
  46 +@Slf4j
  47 +public class RequestDispatcher {
  48 + /**
  49 + * key: uri value:{@link MappingMetaInfo}
  50 + */
  51 + private static final Map<String, MappingMetaInfo> MAPPING_INFO_MAP = new ConcurrentHashMap<>();
  52 +
  53 + private static final List<PathPattern> PATH_PATTERNS = new CopyOnWriteArrayList<>();
  54 +
  55 + private static AtomicBoolean hasInit = new AtomicBoolean(false);
  56 +
  57 + @Autowired
  58 + private ApplicationContext applicationContext;
  59 +
  60 + /**
  61 + * 执行对应方法
  62 + *
  63 + * @author miaoguoxin
  64 + * @date 2020/4/15
  65 + */
  66 + public Message executeMethod(String uri, String paramsJson, ServerWebExchange exchange) {
  67 + try {
  68 + if (hasInit.compareAndSet(false, true)) {
  69 + String[] paths = MAPPING_INFO_MAP.keySet().toArray(new String[0]);
  70 + PATH_PATTERNS.addAll(PathUtils.assemblePath(paths, PATH_PATTERNS));
  71 + }
  72 + String matchUri = PathUtils.getMatchUri(uri, PATH_PATTERNS);
  73 + if (Strings.isNullOrEmpty(matchUri)) {
  74 + throw NotFoundException.create(true, String.format("%s not found", uri));
  75 + }
  76 + //分发逻辑
  77 + Object resultData = this.beginDispatch(matchUri, paramsJson,exchange);
  78 + return Message.builder().success(resultData);
  79 + } catch (Throwable e) {
  80 + return handleException(e);
  81 + }
  82 + }
  83 +
  84 + /**
  85 + * 注册mapping信息
  86 + * @param
  87 + * @return
  88 + * @author miaoguoxin
  89 + * @date 2020/4/16
  90 + */
  91 + public static void addMapping(String uri, MappingMetaInfo mappingMetaInfo) {
  92 + Optional.ofNullable(MAPPING_INFO_MAP.put(uri, mappingMetaInfo))
  93 + .ifPresent(info -> {
  94 + throw new GatewayServiceException(
  95 + String.format("mapping:【%s】 duplicate:【%s】", uri, info.toString()));
  96 + });
  97 +
  98 + }
  99 +
  100 + /**
  101 + * 执行分发操作,参数为DispatchContext
  102 + *
  103 + * @author miaoguoxin
  104 + * @date 2020/4/15
  105 + */
  106 + private Object beginDispatch(String matchUri, String paramsJson, ServerWebExchange exchange) throws Throwable {
  107 + MappingMetaInfo mappingMetaInfo = MAPPING_INFO_MAP.get(matchUri);
  108 + Object targetBean = applicationContext.getBean(mappingMetaInfo.getTargetClass());
  109 + Method targetMethod = mappingMetaInfo.getTargetMethod();
  110 + Class<?> parameterType = mappingMetaInfo.getParameterType();
  111 + Object paramData = null;
  112 + if (parameterType != null){
  113 + paramData = JsonUtils.fromJsonString(paramsJson, parameterType);
  114 + Validated validated = mappingMetaInfo.getValidated();
  115 + if (validated != null){
  116 + ValidateUtils.validate(paramData,validated.value());
  117 + }
  118 + }
  119 +
  120 + DispatchContext dispatchContext = new DispatchContext(
  121 + exchange.getRequest(),
  122 + exchange.getResponse(),
  123 + paramData);
  124 + return this.call(targetMethod, targetBean, dispatchContext);
  125 + }
  126 +
  127 + public Object call(Method method, Object target, Object params) throws Throwable {
  128 + try {
  129 + return method.invoke(target, params);
  130 + } catch (InvocationTargetException tex) {
  131 + throw tex.getCause() == null ? tex : tex.getCause();
  132 + }
  133 + }
  134 +
  135 + private static Message handleException(Throwable ex) {
  136 + if (ex instanceof ResponseStatusException) {
  137 + int statusCode = ((ResponseStatusException) ex).getStatus().value();
  138 + log.error("aggregation dispatch {}:{}", statusCode, ex.getMessage());
  139 + return Message.builder()
  140 + .code(statusCode)
  141 + .message(ex.getMessage())
  142 + .build();
  143 + } else if (ex instanceof GatewayParamNotValidException) {
  144 + return Message.builder()
  145 + .code(SystemCode.ILLEGAL_PARAMS.getCode())
  146 + .message(ex.getMessage())
  147 + .build();
  148 + } else {
  149 + log.error("aggregation dispatch error:{}", ex);
  150 + return Message.builder()
  151 + .code(SystemCode.SERVER_ERROR.getCode())
  152 + .message(SystemCode.SERVER_ERROR.getName())
  153 + .build();
  154 + }
  155 + }
  156 +
  157 +
  158 +}
... ...
src/main/resources/ValidationMessages.properties 0 → 100644
  1 +++ a/src/main/resources/ValidationMessages.properties
  1 +
  2 +
... ...
src/main/resources/ValidationMessages_zh_CN.properties 0 → 100644
  1 +++ a/src/main/resources/ValidationMessages_zh_CN.properties
  1 +request.username.not.blank=\u767B\u5F55\u7528\u6237\u8D26\u53F7\u4E0D\u80FD\u4E3A\u7A7A
  2 +request.password.not.blank=\u767B\u5F55\u7528\u6237\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A
  3 +request.date_interval={beginDateField}\u548C{endDateField}\u95F4\u9694\u6709\u8BEF
... ...
src/main/resources/banner2.txt 0 → 100644
  1 +++ a/src/main/resources/banner2.txt
  1 +${AnsiColor.YELLOW}
  2 + ┏┓   ┏┓+ +
  3 +    ┏┛┻━━━┛┻┓ + +
  4 +    ┃       ┃  
  5 +    ┃   ━   ┃ ++ + + +
  6 +    ████━████ ┃+
  7 +    ┃       ┃ +
  8 +    ┃   ┻   ┃
  9 +    ┃       ┃ + +
  10 +    ┗━┓   ┏━┛
  11 +      ┃   ┃           
  12 +      ┃   ┃ + + + +
  13 +      ┃   ┃    Codes are far away from bugs with the animal protecting   
  14 +      ┃   ┃ +     神兽保佑,代码无bug  
  15 +      ┃   ┃
  16 +      ┃   ┃  +         
  17 +      ┃    ┗━━━┓ + +
  18 +      ┃        ┣┓
  19 +      ┃        ┏┛
  20 +      ┗┓┓┏━┳┓┏┛ + + + +
  21 +       ┃┫┫ ┃┫┫
  22 +       ┗┻┛ ┗┻┛+ + + +
  23 + Spring Boot :${spring-boot.version} 此代码已经开光!
... ...
src/main/resources/bootstrap-dev.yml 0 → 100644
  1 +++ a/src/main/resources/bootstrap-dev.yml
  1 +spring:
  2 + cloud:
  3 + nacos:
  4 + discovery:
  5 + username: nacos
  6 + password: microtest
  7 + server-addr: apitest.51shiban.com:80/n
  8 + namespace: c86d8673-4d0a-469f-8bb8-1434c57c236c
  9 + config:
  10 + username: nacos
  11 + password: microtest
  12 + server-addr: apitest.51shiban.com:80/n
  13 + namespace: c86d8673-4d0a-469f-8bb8-1434c57c236c
... ...
src/main/resources/bootstrap-gateway-tempalte.yml 0 → 100644
  1 +++ a/src/main/resources/bootstrap-gateway-tempalte.yml
  1 +spring:
  2 + cloud:
  3 + gateway:
  4 + routes:
  5 + - id: micro-goods
  6 + uri: lb://micro-goods
  7 + predicates:
  8 + - Path=/goods/**
  9 + - ReadBody=s
  10 + filters:
  11 + - StripPrefix=1
... ...
src/main/resources/bootstrap.yml 0 → 100644
  1 +++ a/src/main/resources/bootstrap.yml
  1 +server:
  2 + port: 8888
  3 +spring:
  4 + application:
  5 + name: xtrade-gateway-service
  6 + profiles:
  7 + active: dev
  8 + cloud:
  9 + nacos:
  10 + config:
  11 + file-extension: properties
  12 + context-path: /nacos
  13 + extension-configs:
  14 + - dataId: route.properties
  15 + refresh: true
  16 + - dataId: common.properties
  17 + refresh: false
  18 + banner:
  19 + location: banner2.txt
  20 +mybatis:
  21 + mapper-locations: classpath:/mapper/*.xml
  22 + config-location: classpath:/mybatis-config.xml
  23 +xtrade:
  24 + json:
  25 + format: false
  26 + gateway-loader: cloud
  27 + aggregation-scan-packages: com.diligrp.xtrade.gateway.application
... ...
src/main/resources/ehcache.xml 0 → 100644
  1 +++ a/src/main/resources/ehcache.xml
  1 +<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
  2 +
  3 + <diskStore path="java.io.tmpdir"/>
  4 +
  5 + <!--defaultCache:echcache的默认缓存策略 -->
  6 + <defaultCache
  7 + maxElementsInMemory="100000"
  8 + eternal="false"
  9 + timeToIdleSeconds="120"
  10 + timeToLiveSeconds="120"
  11 + maxElementsOnDisk="100000"
  12 + diskExpiryThreadIntervalSeconds="120"
  13 + memoryStoreEvictionPolicy="LRU">
  14 + <persistence strategy="localTempSwap"/>
  15 + </defaultCache>
  16 + <cache name="permissions"
  17 + maxElementsInMemory="10000"
  18 + eternal="false"
  19 + timeToIdleSeconds="120"
  20 + timeToLiveSeconds="7200"
  21 + maxElementsOnDisk="10000"
  22 + diskExpiryThreadIntervalSeconds="120"
  23 + memoryStoreEvictionPolicy="LRU">
  24 + <persistence strategy="localTempSwap"/>
  25 + </cache>
  26 +</ehcache>
... ...
src/main/resources/mapper/AttrConfigDao.xml 0 → 100644
  1 +++ a/src/main/resources/mapper/AttrConfigDao.xml
  1 +<?xml version="1.0" encoding="UTF-8" ?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
  3 +<mapper namespace="com.diligrp.xtrade.gateway.repository.dao.AttrConfigDao">
  4 + <resultMap id="Base_Result_Map" type="com.diligrp.xtrade.gateway.repository.entity.GatewayAttrConfig">
  5 + <id property="id" column="id"/>
  6 + <result property="serviceId" column="service_id"/>
  7 + <result property="type" column="type"/>
  8 + <result property="attrName" column="attr_name"/>
  9 + <result property="attrArgs" column="attr_args"/>
  10 + <result property="description" column="description"/>
  11 + <result property="sortOrder" column="sort_order"/>
  12 + <result property="isDel" column="is_del"/>
  13 + <result property="modifiedTime" column="modified_time"/>
  14 + <result property="createdTime" column="created_time"/>
  15 + </resultMap>
  16 +
  17 + <select id="findAllForLoad" resultMap="Base_Result_Map">
  18 + SELECT service_id,
  19 + type,
  20 + attr_name,
  21 + attr_args,
  22 + sort_order
  23 + FROM t_attr_config
  24 + WHERE is_del = 0
  25 + </select>
  26 +</mapper>
... ...
src/main/resources/mapper/RouteDao.xml 0 → 100644
  1 +++ a/src/main/resources/mapper/RouteDao.xml
  1 +<?xml version="1.0" encoding="UTF-8" ?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
  3 +<mapper namespace="com.diligrp.xtrade.gateway.repository.dao.RouteDao">
  4 + <resultMap id="Base_Result_Map" type="com.diligrp.xtrade.gateway.repository.entity.GatewayConfig">
  5 + <id property="id" column="id"/>
  6 + <result property="url" column="url"/>
  7 + <result property="serviceId" column="service_id"/>
  8 + <result property="createdTime" column="created_time"/>
  9 + <result property="modifiedTime" column="modified_time"/>
  10 + <result property="description" column="description"/>
  11 + <result property="isDel" column="is_del"/>
  12 + </resultMap>
  13 +
  14 + <select id="findAllForLoad" resultMap="Base_Result_Map">
  15 + SELECT
  16 + url,service_id
  17 + FROM
  18 + t_route
  19 + WHERE
  20 + is_del=0
  21 + </select>
  22 +</mapper>
... ...
src/main/resources/mybatis-config.xml 0 → 100644
  1 +++ a/src/main/resources/mybatis-config.xml
  1 +<?xml version="1.0" encoding="UTF-8" ?>
  2 +<!DOCTYPE configuration
  3 + PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4 + "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5 +
  6 +<configuration>
  7 +<settings>
  8 + <!-- 只设置需要的,其他使用默认值
  9 + 开启二级缓存,相当于关闭一级缓存,防止分布式一级缓存无法共享 -->
  10 + <setting name="cacheEnabled" value="true"/>
  11 + <!-- 在null时也调用 setter,适应于返回Map,3.2版本以上可用 -->
  12 + <setting name="callSettersOnNulls" value="true"/>
  13 + <!-- 打印sql语句 调试使用-->
  14 + <!-- <setting name="logImpl" value="STDOUT_LOGGING" />-->
  15 + </settings>
  16 + <!-- <plugins>
  17 + <plugin interceptor="com.simida.infrastructure.common.page.PageHelper"/>
  18 + </plugins>-->
  19 +</configuration>
0 20 \ No newline at end of file
... ...
src/test/java/com/diligrp/xtrade/gateway/XtradeGatewayApplicationTests.java 0 → 100644
  1 +++ a/src/test/java/com/diligrp/xtrade/gateway/XtradeGatewayApplicationTests.java
  1 +package com.diligrp.xtrade.gateway;
  2 +
  3 +import org.junit.jupiter.api.Test;
  4 +import org.springframework.boot.test.context.SpringBootTest;
  5 +
  6 +@SpringBootTest
  7 +class XtradeGatewayApplicationTests {
  8 +
  9 + @Test
  10 + void contextLoads() {
  11 + }
  12 +
  13 +}
... ...