commit:微服务工程目录

This commit is contained in:
Jerry
2021-09-28 16:28:10 +08:00
parent 13ba3386dc
commit a6ae0d1a79
1012 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,288 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="Spring" name="Spring">
<configuration />
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/target/generated-sources/annotations" isTestSource="false" generated="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-spring-ui:2.0.8" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger2:2.10.5" level="project" />
<orderEntry type="library" name="Maven: io.swagger:swagger-annotations:1.5.20" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-spi:2.10.5" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-core:2.10.5" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-schema:2.10.5" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger-common:2.10.5" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-spring-web:2.10.5" level="project" />
<orderEntry type="library" name="Maven: io.github.classgraph:classgraph:4.1.7" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml:classmate:1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.30" level="project" />
<orderEntry type="library" name="Maven: io.swagger:swagger-models:1.5.22" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.11.4" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-bean-validators:2.10.5" level="project" />
<orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-starter-gateway:2.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-starter:2.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-rsa:1.0.9.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.bouncycastle:bcpkix-jdk15on:1.59" level="project" />
<orderEntry type="library" name="Maven: org.bouncycastle:bcprov-jdk15on:1.59" level="project" />
<orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-gateway-server:2.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-validation:2.3.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.glassfish:jakarta.el:3.0.3" level="project" />
<orderEntry type="library" name="Maven: io.projectreactor.addons:reactor-extra:3.3.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-webflux:2.3.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-json:2.3.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.4" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.4" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-reactor-netty:2.3.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: io.projectreactor.netty:reactor-netty:0.9.19.RELEASE" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-codec-http:4.1.63.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-codec-http2:4.1.63.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-handler-proxy:4.1.63.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-codec-socks:4.1.63.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-transport-native-epoll:linux-x86_64:4.1.63.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-transport-native-unix-common:4.1.63.Final" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-webflux:5.2.14.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.synchronoss.cloud:nio-multipart-parser:1.1.0" level="project" />
<orderEntry type="library" name="Maven: org.synchronoss.cloud:nio-stream-storage:1.1.3" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-spring-cloud-gateway-adapter:1.8.0" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-api-gateway-adapter-common:1.8.0" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-core:1.8.0" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-reactor-adapter:1.8.0" level="project" />
<orderEntry type="module" module-name="common-redis" />
<orderEntry type="library" name="Maven: org.redisson:redisson:3.15.4" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-common:4.1.63.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-codec:4.1.63.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-buffer:4.1.63.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-transport:4.1.63.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-resolver:4.1.63.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-resolver-dns:4.1.63.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-codec-dns:4.1.63.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-handler:4.1.63.Final" level="project" />
<orderEntry type="library" name="Maven: javax.cache:cache-api:1.1.1" level="project" />
<orderEntry type="library" name="Maven: io.projectreactor:reactor-core:3.3.16.RELEASE" level="project" />
<orderEntry type="library" name="Maven: io.reactivex.rxjava3:rxjava:3.0.12" level="project" />
<orderEntry type="library" name="Maven: org.jboss.marshalling:jboss-marshalling-river:2.0.11.Final" level="project" />
<orderEntry type="library" name="Maven: org.jboss.marshalling:jboss-marshalling:2.0.11.Final" level="project" />
<orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.26" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.11.4" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.11.4" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.11.4" level="project" />
<orderEntry type="library" name="Maven: net.bytebuddy:byte-buddy:1.10.22" level="project" />
<orderEntry type="library" name="Maven: org.jodd:jodd-bean:5.1.6" level="project" />
<orderEntry type="library" name="Maven: org.jodd:jodd-core:5.1.6" level="project" />
<orderEntry type="module" module-name="common-core" />
<orderEntry type="library" name="Maven: com.google.guava:guava:29.0-jre" level="project" />
<orderEntry type="library" name="Maven: com.google.guava:failureaccess:1.0.1" level="project" />
<orderEntry type="library" name="Maven: com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava" level="project" />
<orderEntry type="library" name="Maven: com.google.code.findbugs:jsr305:3.0.2" level="project" />
<orderEntry type="library" name="Maven: org.checkerframework:checker-qual:2.11.1" level="project" />
<orderEntry type="library" name="Maven: com.google.errorprone:error_prone_annotations:2.3.4" level="project" />
<orderEntry type="library" name="Maven: com.google.j2objc:j2objc-annotations:1.3" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.10" level="project" />
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.14" level="project" />
<orderEntry type="library" name="Maven: commons-io:commons-io:2.6" level="project" />
<orderEntry type="library" name="Maven: commons-fileupload:commons-fileupload:1.3.3" level="project" />
<orderEntry type="library" name="Maven: joda-time:joda-time:2.9.9" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-collections4:4.4" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-csv:1.8" level="project" />
<orderEntry type="library" name="Maven: cn.hutool:hutool-all:5.6.4" level="project" />
<orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.9.1" level="project" />
<orderEntry type="library" name="Maven: com.alibaba:fastjson:1.2.76" level="project" />
<orderEntry type="library" name="Maven: com.github.ben-manes.caffeine:caffeine:2.8.8" level="project" />
<orderEntry type="library" name="Maven: cn.jimmyshi:bean-query:1.1.5" level="project" />
<orderEntry type="library" name="Maven: org.hamcrest:hamcrest-all:1.3" level="project" />
<orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.9.3" level="project" />
<orderEntry type="library" name="Maven: commons-collections:commons-collections:3.2.2" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:jcl-over-slf4j:1.7.30" level="project" />
<orderEntry type="library" name="Maven: org.apache.poi:poi-ooxml:3.17" level="project" />
<orderEntry type="library" name="Maven: org.apache.poi:poi:3.17" level="project" />
<orderEntry type="library" name="Maven: org.apache.poi:poi-ooxml-schemas:3.17" level="project" />
<orderEntry type="library" name="Maven: org.apache.xmlbeans:xmlbeans:2.6.0" level="project" />
<orderEntry type="library" name="Maven: stax:stax-api:1.0.1" level="project" />
<orderEntry type="library" name="Maven: com.github.virtuald:curvesapi:1.04" level="project" />
<orderEntry type="library" name="Maven: tk.mybatis:mapper-spring-boot-starter:2.1.5" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.3.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.zaxxer:HikariCP:3.4.5" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-jdbc:5.2.14.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-tx:5.2.14.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.mybatis:mybatis:3.4.6" level="project" />
<orderEntry type="library" name="Maven: org.mybatis:mybatis-spring:1.3.2" level="project" />
<orderEntry type="library" name="Maven: tk.mybatis:mapper-core:1.1.5" level="project" />
<orderEntry type="library" name="Maven: javax.persistence:persistence-api:1.0" level="project" />
<orderEntry type="library" name="Maven: tk.mybatis:mapper-base:1.1.5" level="project" />
<orderEntry type="library" name="Maven: tk.mybatis:mapper-weekend:1.1.5" level="project" />
<orderEntry type="library" name="Maven: tk.mybatis:mapper-spring:1.1.5" level="project" />
<orderEntry type="library" name="Maven: tk.mybatis:mapper-extra:1.1.5" level="project" />
<orderEntry type="library" name="Maven: tk.mybatis:mapper-spring-boot-autoconfigure:2.1.5" level="project" />
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-starter:1.3.0" level="project" />
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.3" level="project" />
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-autoconfigure:2.1.3" level="project" />
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-autoconfigure:1.3.0" level="project" />
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper:5.2.0" level="project" />
<orderEntry type="library" name="Maven: com.github.jsqlparser:jsqlparser:3.2" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery:2.2.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.cloud:spring-cloud-alibaba-commons:2.2.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.nacos:nacos-client:1.4.1" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.nacos:nacos-common:1.4.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpasyncclient:4.1.4" level="project" />
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpcore-nio:4.4.14" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.nacos:nacos-api:1.4.1" level="project" />
<orderEntry type="library" name="Maven: io.prometheus:simpleclient:0.5.0" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.spring:spring-context-support:1.0.10" level="project" />
<orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-commons:2.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-crypto:5.3.9.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-context:2.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-starter-netflix-ribbon:2.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.netflix.ribbon:ribbon:2.3.0" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: com.netflix.ribbon:ribbon-transport:2.3.0" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: io.reactivex:rxnetty-contexts:0.4.9" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: io.reactivex:rxnetty-servo:0.4.9" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: javax.inject:javax.inject:1" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: io.reactivex:rxnetty:0.4.9" level="project" />
<orderEntry type="library" name="Maven: com.netflix.ribbon:ribbon-core:2.3.0" level="project" />
<orderEntry type="library" name="Maven: commons-lang:commons-lang:2.6" level="project" />
<orderEntry type="library" name="Maven: com.netflix.ribbon:ribbon-httpclient:2.3.0" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: com.sun.jersey:jersey-client:1.19.1" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: com.sun.jersey:jersey-core:1.19.1" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: javax.ws.rs:jsr311-api:1.1.1" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: com.sun.jersey.contribs:jersey-apache-client4:1.19.1" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: com.netflix.servo:servo-core:0.12.21" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: com.netflix.netflix-commons:netflix-commons-util:0.3.0" level="project" />
<orderEntry type="library" name="Maven: com.netflix.ribbon:ribbon-loadbalancer:2.3.0" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: com.netflix.netflix-commons:netflix-statistics:0.1.1" level="project" />
<orderEntry type="library" name="Maven: io.reactivex:rxjava:1.3.8" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.cloud:spring-cloud-starter-alibaba-sentinel:2.2.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-transport-simple-http:1.8.0" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-transport-common:1.8.0" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-annotation-aspectj:1.8.0" level="project" />
<orderEntry type="library" name="Maven: org.aspectj:aspectjrt:1.9.6" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.cloud:spring-cloud-circuitbreaker-sentinel:2.2.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-spring-webflux-adapter:1.8.0" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-spring-webmvc-adapter:1.8.0" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-parameter-flow-control:1.8.0" level="project" />
<orderEntry type="library" name="Maven: com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-cluster-server-default:1.8.0" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-cluster-common-default:1.8.0" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-cluster-client-default:1.8.0" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.cloud:spring-cloud-alibaba-sentinel-datasource:2.2.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-datasource-nacos:1.8.0" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.csp:sentinel-datasource-extension:1.8.0" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-freemarker:2.3.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter:2.3.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot:2.3.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.3.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: jakarta.annotation:jakarta.annotation-api:1.3.5" level="project" />
<orderEntry type="library" name="Maven: org.freemarker:freemarker:2.3.31" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context-support:5.2.14.RELEASE" level="project" />
<orderEntry type="library" name="Maven: javax.servlet:javax.servlet-api:4.0.1" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-log4j2:2.3.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-slf4j-impl:2.13.3" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-api:2.13.3" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-core:2.13.3" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-jul:2.13.3" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:jul-to-slf4j:1.7.30" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-aop:2.3.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.2.14.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.aspectj:aspectjweaver:1.9.6" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-cache:2.3.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-configuration-processor:2.3.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-actuator:2.3.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-actuator-autoconfigure:2.3.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-actuator:2.3.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.4" level="project" />
<orderEntry type="library" name="Maven: io.micrometer:micrometer-core:1.5.13" level="project" />
<orderEntry type="library" name="Maven: org.hdrhistogram:HdrHistogram:2.1.12" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.latencyutils:LatencyUtils:2.0.3" level="project" />
<orderEntry type="library" name="Maven: de.codecentric:spring-boot-admin-starter-client:2.3.1" level="project" />
<orderEntry type="library" name="Maven: de.codecentric:spring-boot-admin-client:2.3.1" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-config:2.2.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-starter-openfeign:2.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-openfeign-core:2.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: io.github.openfeign.form:feign-form-spring:3.8.0" level="project" />
<orderEntry type="library" name="Maven: io.github.openfeign.form:feign-form:3.8.0" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-web:5.2.14.RELEASE" level="project" />
<orderEntry type="library" name="Maven: io.github.openfeign:feign-core:10.10.1" level="project" />
<orderEntry type="library" name="Maven: io.github.openfeign:feign-slf4j:10.10.1" level="project" />
<orderEntry type="library" name="Maven: io.github.openfeign:feign-hystrix:10.10.1" level="project" />
<orderEntry type="library" name="Maven: com.netflix.archaius:archaius-core:0.7.6" level="project" />
<orderEntry type="library" name="Maven: io.github.openfeign:feign-httpclient:10.10.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpclient:4.5.13" level="project" />
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpcore:4.4.14" level="project" />
<orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-starter-netflix-hystrix:2.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-netflix-hystrix:2.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-netflix-ribbon:2.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-netflix-archaius:2.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-starter-netflix-archaius:2.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: commons-configuration:commons-configuration:1.8" level="project" />
<orderEntry type="library" name="Maven: com.netflix.hystrix:hystrix-core:1.5.18" level="project" />
<orderEntry type="library" name="Maven: com.netflix.hystrix:hystrix-serialization:1.5.18" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: com.fasterxml.jackson.module:jackson-module-afterburner:2.11.4" level="project" />
<orderEntry type="library" name="Maven: com.netflix.hystrix:hystrix-metrics-event-stream:1.5.18" level="project" />
<orderEntry type="library" name="Maven: com.netflix.hystrix:hystrix-javanica:1.5.18" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.ow2.asm:asm:5.0.4" level="project" />
<orderEntry type="library" name="Maven: io.reactivex:rxjava-reactive-streams:1.2.1" level="project" />
<orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.3" level="project" />
<orderEntry type="library" name="Maven: org.hibernate.validator:hibernate-validator:6.2.0.Final" level="project" />
<orderEntry type="library" name="Maven: jakarta.validation:jakarta.validation-api:2.0.2" level="project" />
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.4.1.Final" level="project" />
<orderEntry type="library" name="Maven: org.mapstruct:mapstruct:1.4.2.Final" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.mapstruct:mapstruct-processor:1.4.2.Final" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.projectlombok:lombok:1.18.20" level="project" />
<orderEntry type="library" name="Maven: org.apache.curator:curator-recipes:4.3.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.curator:curator-framework:4.0.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.curator:curator-client:4.0.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.zookeeper:zookeeper:3.5.3-beta" level="project" />
<orderEntry type="library" name="Maven: commons-cli:commons-cli:1.4" level="project" />
<orderEntry type="library" name="Maven: org.apache.kafka:kafka-clients:2.4.0" level="project" />
<orderEntry type="library" name="Maven: com.github.luben:zstd-jni:1.4.3-1" level="project" />
<orderEntry type="library" name="Maven: org.lz4:lz4-java:1.6.0" level="project" />
<orderEntry type="library" name="Maven: org.xerial.snappy:snappy-java:1.1.7.3" level="project" />
<orderEntry type="library" name="Maven: org.scala-lang:scala-library:2.12.10" level="project" />
<orderEntry type="library" name="Maven: com.lmax:disruptor:3.4.3" level="project" />
<orderEntry type="library" name="Maven: org.springframework.plugin:spring-plugin-core:2.0.0.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.2.14.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.2.14.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.2.14.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.plugin:spring-plugin-metadata:2.0.0.RELEASE" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-starter-test:2.3.10.RELEASE" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test:2.3.10.RELEASE" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test-autoconfigure:2.3.10.RELEASE" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.jayway.jsonpath:json-path:2.4.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: net.minidev:json-smart:2.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: net.minidev:accessors-smart:1.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: jakarta.xml.bind:jakarta.xml.bind-api:2.3.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: jakarta.activation:jakarta.activation-api:1.2.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.assertj:assertj-core:3.16.1" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest:2.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter:5.6.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-api:5.6.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.opentest4j:opentest4j:1.2.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.platform:junit-platform-commons:1.6.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-params:5.6.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-engine:5.6.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.vintage:junit-vintage-engine:5.6.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.apiguardian:apiguardian-api:1.1.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.platform:junit-platform-engine:1.6.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.13.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-core:3.3.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: net.bytebuddy:byte-buddy-agent:1.10.22" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.objenesis:objenesis:2.6" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-junit-jupiter:3.3.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.skyscreamer:jsonassert:1.5.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.vaadin.external.google:android-json:0.0.20131108.vaadin1" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.2.14.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.2.14.RELEASE" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework:spring-test:5.2.14.RELEASE" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.xmlunit:xmlunit-core:2.7.0" level="project" />
</component>
</module>

View File

@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.orange.demo</groupId>
<artifactId>application</artifactId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>gateway</artifactId>
<version>1.0.0</version>
<name>gateway</name>
<packaging>jar</packaging>
<dependencies>
<!-- swagger和knife4j相关集成-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-ui</artifactId>
<version>${knife4j.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${springfox.version}</version>
<exclusions>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>${zz-swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-bean-validators</artifactId>
<version>${springfox.version}</version>
</dependency>
<!-- 网关服务 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
</dependency>
<dependency>
<groupId>com.orange.demo</groupId>
<artifactId>common-redis</artifactId>
<version>1.0.0</version>
</dependency>
<!-- 通用组件依赖 -->
<dependency>
<groupId>com.orange.demo</groupId>
<artifactId>common-core</artifactId>
<version>1.0.0</version>
<exclusions>
<exclusion>
<artifactId>mysql-connector-java</artifactId>
<groupId>mysql</groupId>
</exclusion>
<exclusion>
<artifactId>druid-spring-boot-starter</artifactId>
<groupId>com.alibaba</groupId>
</exclusion>
<exclusion>
<artifactId>spring-boot-starter-web</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,58 @@
package com.orange.demo.gateway;
import com.orange.demo.common.core.util.ApplicationContextHolder;
import com.orange.demo.gateway.filter.AuthenticationPostFilter;
import com.orange.demo.gateway.filter.AuthenticationPreFilter;
import com.orange.demo.gateway.filter.RequestLogFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 网关服务启动类。
*
* @author Jerry
* @date 2020-08-08
*/
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
@SpringCloudApplication
public class GatewayApplication {
@RestController
@RequestMapping("/fallback")
static class FallbackController {
@GetMapping("")
public String fallback() {
return "GATEWAY FALLBACK!!!";
}
}
@Bean
public AuthenticationPreFilter authenticationPreFilter() {
return new AuthenticationPreFilter();
}
@Bean
public AuthenticationPostFilter authenticationPostFilter() {
return new AuthenticationPostFilter();
}
@Bean
public RequestLogFilter requestLogPreFilter() {
return new RequestLogFilter();
}
@Bean
ApplicationContextHolder applicationContextHolder() {
return new ApplicationContextHolder();
}
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}

View File

@@ -0,0 +1,55 @@
package com.orange.demo.gateway.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
import java.util.Set;
/**
* 网关业务配置类。
*
* @author Jerry
* @date 2020-08-08
*/
@Data
@RefreshScope
@Configuration
@ConfigurationProperties(prefix = "application")
public class ApplicationConfig {
/**
* token加密用的密钥该值的长度最少10个字符(过短会报错)。
*/
private String tokenSigningKey;
/**
* 客户端或者浏览器在提交http请求时携带token的header name如 Authorization
*/
private String tokenHeaderKey;
/**
* 令牌Token在被刷新之后服务器Http应答的header name客户端或浏览器需要保存并替换原有的token用于下次发送时携带
*/
private String refreshedTokenHeaderKey;
/**
* 令牌的过期时间,单位毫秒
*/
private Long expiration;
/**
* 授信ip列表没有填写表示全部信任。多个ip之间逗号分隔如: http://10.10.10.1:8080,http://10.10.10.2:8080
*/
private String credentialIpList;
/**
* Session会话和用户权限在Redis中的过期时间(秒)。
* 缺省值是 one day
*/
private int sessionExpiredSeconds = 86400;
/**
* 基于完全等于(equals)判定规则的白名单地址集合过滤效率高于whitelistUrlPattern。
*/
private Set<String> whitelistUrl;
/**
* 基于Ant Pattern模式判定规则的白名单地址集合。如/aa/**。
*/
private Set<String> whitelistUrlPattern;
}

View File

@@ -0,0 +1,39 @@
package com.orange.demo.gateway.config;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;
/**
* 跨域信任配置类。
*
* @author Jerry
* @date 2020-08-08
*/
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsFilter(ApplicationConfig appConfig) {
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource(new PathPatternParser());
CorsConfiguration config = new CorsConfiguration();
if (StringUtils.isNotBlank(appConfig.getCredentialIpList())) {
String[] credentialIpList = StringUtils.split(appConfig.getCredentialIpList(), ",");
if (credentialIpList.length > 0) {
for (String ip : credentialIpList) {
config.addAllowedOrigin(ip);
}
}
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.addExposedHeader(appConfig.getRefreshedTokenHeaderKey());
config.setAllowCredentials(true);
configSource.registerCorsConfiguration("/**", config);
}
return new CorsWebFilter(configSource);
}
}

View File

@@ -0,0 +1,30 @@
package com.orange.demo.gateway.config;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
import java.nio.charset.StandardCharsets;
/**
* Web通用过滤器配置类。
*
* @author Jerry
* @date 2020-08-08
*/
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<Filter> characterEncodingFilterRegistration() {
FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>(
new org.springframework.web.filter.CharacterEncodingFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.addInitParameter("encoding", StandardCharsets.UTF_8.name());
// forceEncoding强制response也被编码另外即使request中已经设置encodingforceEncoding也会重新设置
filterRegistrationBean.addInitParameter("forceEncoding", "true");
filterRegistrationBean.setAsyncSupported(true);
return filterRegistrationBean;
}
}

View File

@@ -0,0 +1,47 @@
package com.orange.demo.gateway.config;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;
import java.util.*;
/**
* Spring Cloud Gateway的Sentinel流控配置类。
*
* @author Jerry
* @date 2020-08-08
*/
@Configuration
public class SentinelConfig {
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public SentinelConfig(
ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// Register the block exception handler for Spring Cloud Gateway.
return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
}

View File

@@ -0,0 +1,52 @@
package com.orange.demo.gateway.config;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
import java.util.ArrayList;
import java.util.List;
/***
* 返回Swagger UI需要读取的资源数据这里是微服务的路由数据。
*
* @author Knife4j Team。
* @date 2020-08-08
*/
@Slf4j
@Component
@Primary
@AllArgsConstructor
public class SwaggerResourceConfig implements SwaggerResourcesProvider {
private final RouteLocator routeLocator;
private final GatewayProperties gatewayProperties;
@Override
public List<SwaggerResource> get() {
List<SwaggerResource> resources = new ArrayList<>();
List<String> routes = new ArrayList<>();
routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
gatewayProperties.getRoutes().stream().filter(routeDefinition -> routes.contains(routeDefinition.getId()))
.forEach(route -> route.getPredicates().stream()
.filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName()))
.forEach(predicateDefinition -> resources.add(swaggerResource(route.getId(),
predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0")
.replace("**", "v2/api-docs")))));
return resources;
}
private SwaggerResource swaggerResource(String name, String location) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion("2.0");
return swaggerResource;
}
}

View File

@@ -0,0 +1,36 @@
package com.orange.demo.gateway.constant;
/**
* 网关业务相关的常量对象。
*
* @author Jerry
* @date 2020-08-08
*/
public final class GatewayConstant {
/**
* 请求进入网关的开始时间。
*/
public static final String START_TIME_ATTRIBUTE = "startTime";
/**
* 登录URL。
*/
public static final String ADMIN_LOGIN_URL = "/admin/upms/login/doLogin";
/**
* 登出URL。
*/
public static final String ADMIN_LOGOUT_URL = "/admin/upms/login/doLogout";
/**
* sessionId的键名称。
*/
public static final String SESSION_ID_KEY_NAME = "sessionId";
/**
* 私有构造函数,明确标识该常量类的作用。
*/
private GatewayConstant() {
}
}

View File

@@ -0,0 +1,231 @@
package com.orange.demo.gateway.filter;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.orange.demo.common.core.constant.ErrorCodeEnum;
import com.orange.demo.common.core.object.ResponseResult;
import com.orange.demo.common.core.object.TokenData;
import com.orange.demo.common.core.util.JwtUtil;
import com.orange.demo.common.core.util.MyCommonUtil;
import com.orange.demo.common.core.util.RedisKeyUtil;
import com.orange.demo.gateway.config.ApplicationConfig;
import com.orange.demo.gateway.constant.GatewayConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.reactivestreams.Publisher;
import org.redisson.api.RBucket;
import org.redisson.api.RSet;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.lang.NonNull;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* 全局后处理过滤器。主要用于将用户的会话信息存到缓存服务器,以及在登出时清除缓存中的会话数据。
*
* @author Jerry
* @date 2020-08-08
*/
@Slf4j
public class AuthenticationPostFilter implements GlobalFilter, Ordered {
@Autowired
private ApplicationConfig appConfig;
@Autowired
private RedissonClient redissonClient;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest originalRequest = exchange.getRequest();
ServerHttpResponse originalResponse = exchange.getResponse();
String refreshedToken =
(String) exchange.getAttributes().get(appConfig.getRefreshedTokenHeaderKey());
if (refreshedToken != null) {
originalResponse.getHeaders().add(appConfig.getRefreshedTokenHeaderKey(), refreshedToken);
}
if (!originalRequest.getURI().getPath().equals(GatewayConstant.ADMIN_LOGIN_URL)
&& !originalRequest.getURI().getPath().equals(GatewayConstant.ADMIN_LOGOUT_URL)) {
return chain.filter(exchange);
}
DataBufferFactory bufferFactory = originalResponse.bufferFactory();
ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
@SuppressWarnings("unchecked")
@Override
public Mono<Void> writeWith(@NonNull Publisher<? extends DataBuffer> bodyData) {
StringBuilder sb = new StringBuilder(128);
sb.append("url: ")
.append(originalRequest.getURI().getPath())
.append(" -- status: ")
.append(getStatusCode());
if (getStatusCode() != HttpStatus.OK) {
log.error(sb.toString());
return super.writeWith(bodyData);
}
if (!(bodyData instanceof Flux)) {
return super.writeWith(bodyData);
}
Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) bodyData;
return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
// 读取完整的服务应答消息体。
String responseBody = readResponseBody(dataBuffers);
originalResponse.getHeaders().setContentType(MediaType.APPLICATION_JSON);
// 先判断body中是否包含数据。
if (StringUtils.isBlank(responseBody)) {
sb.append(" -- Internal Error, no RESPONSE DATA returns !!");
log.error(sb.toString());
String errorMessage = "后台服务没有任何数据返回!";
responseBody = JSON.toJSONString(
ResponseResult.error(ErrorCodeEnum.SERVER_INTERNAL_ERROR, errorMessage));
byte[] uppedContent = new String(responseBody.getBytes(), StandardCharsets.UTF_8).getBytes();
originalResponse.getHeaders().setContentLength(uppedContent.length);
return bufferFactory.wrap(uppedContent);
}
// 处理登录和登出请求。
String result;
try {
result = doProcess(exchange, responseBody);
} catch (Exception e) {
setStatusCode(HttpStatus.BAD_REQUEST);
String errorMsg = "Server Internal Error";
sb.append(errorMsg);
log.error(sb.toString(), e);
result = JSON.toJSONString(
ResponseResult.error(ErrorCodeEnum.SERVER_INTERNAL_ERROR, errorMsg));
}
byte[] uppedContent = new String(result.getBytes(), StandardCharsets.UTF_8).getBytes();
originalResponse.getHeaders().setContentLength(uppedContent.length);
return bufferFactory.wrap(uppedContent);
}));
}
};
return chain.filter(exchange.mutate().response(decoratedResponse).build());
}
/**
* 返回过滤器在在调用链上的优先级。
*
* @return 数值越低,优先级越高。
*/
@Override
public int getOrder() {
// -1 is response write filter, must be called before that
return -2;
}
private String readResponseBody(List<? extends DataBuffer> dataBuffers) {
int dataCount = 0;
for (DataBuffer dataBuffer : dataBuffers) {
dataCount += dataBuffer.readableByteCount();
}
byte[] allBytes = new byte[dataCount];
int offset = 0;
for (DataBuffer dataBuffer : dataBuffers) {
int length = dataBuffer.readableByteCount();
dataBuffer.read(allBytes, offset, length);
DataBufferUtils.release(dataBuffer);
offset += length;
}
return new String(allBytes, StandardCharsets.UTF_8);
}
@SuppressWarnings("unchecked")
private String doProcess(ServerWebExchange exchange, String responseBody) {
// 这个解析出来的就是upms登录或登出接口返回的ResponseResult对象。
ServerHttpRequest originalRequest = exchange.getRequest();
if (originalRequest.getURI().getPath().equals(GatewayConstant.ADMIN_LOGIN_URL)) {
// 处理登录服务的消息体,同时重构该消息体,并最终返回前端。
ResponseResult<JSONObject> result = processLoginResponse(responseBody);
return JSON.toJSONString(result);
}
if (originalRequest.getURI().getPath().equals(GatewayConstant.ADMIN_LOGOUT_URL)) {
ResponseResult<Void> result = JSON.parseObject(responseBody, ResponseResult.class);
if (result.isSuccess()) {
String sessionId = (String) exchange.getAttributes().get(GatewayConstant.SESSION_ID_KEY_NAME);
redissonClient.getBucket(RedisKeyUtil.makeSessionIdKey(sessionId)).deleteAsync();
redissonClient.getSet(RedisKeyUtil.makeSessionPermIdKey(sessionId)).deleteAsync();
}
return responseBody;
}
return null;
}
@SuppressWarnings("unchecked")
private ResponseResult<JSONObject> processLoginResponse(String responseBody) {
ResponseResult<JSONObject> responseResult = JSON.parseObject(responseBody, ResponseResult.class);
if (!responseResult.isSuccess()) {
return responseResult;
}
JSONObject loginData = responseResult.getData();
// 1. 先验证登陆服务器返回的应答数据是否正确
JSONObject tokenData = loginData.getJSONObject(TokenData.REQUEST_ATTRIBUTE_NAME);
ErrorCodeEnum errorCode = ErrorCodeEnum.SERVER_INTERNAL_ERROR;
if (tokenData == null) {
return ResponseResult.error(errorCode, "内部错误,用户登录令牌对象没有正确返回!");
}
Long userId = tokenData.getLong("userId");
if (MyCommonUtil.isBlankOrNull(userId)) {
return ResponseResult.error(errorCode, "内部错误用户Id没有正确返回");
}
Boolean isAdmin = tokenData.getBoolean("isAdmin");
if (isAdmin == null) {
return ResponseResult.error(errorCode, "内部错误,是否为管理员标记没有正确返回!");
}
String showName = tokenData.getString("showName");
if (StringUtils.isBlank(showName)) {
return ResponseResult.error(errorCode, "内部错误,用户显示名没有正确返回!");
}
String loginName = tokenData.getString("loginName");
if (StringUtils.isBlank(loginName)) {
return ResponseResult.error(errorCode, "内部错误,用户登录名没有正确返回!");
}
String sessionId = tokenData.getString("sessionId");
if (StringUtils.isBlank(sessionId)) {
return ResponseResult.error(errorCode, "内部错误SESSION_ID没有正确返回");
}
// 2. 生成sessionId并存放到token中
Map<String, Object> claims = new HashMap<>(1);
claims.put(GatewayConstant.SESSION_ID_KEY_NAME, sessionId);
String token = JwtUtil.generateToken(claims, appConfig.getExpiration(), appConfig.getTokenSigningKey());
// 3. 更新缓存
String sessionIdKey = RedisKeyUtil.makeSessionIdKey(sessionId);
String sessionData = JSON.toJSONString(tokenData, SerializerFeature.WriteNonStringValueAsString);
RBucket<String> bucket = redissonClient.getBucket(sessionIdKey);
bucket.set(sessionData);
bucket.expire(appConfig.getSessionExpiredSeconds(), TimeUnit.SECONDS);
// 3.2 sessionId -> permList 是set结构的缓存
JSONArray permSet = loginData.getJSONArray("permSet");
if (permSet != null) {
String sessionPermKey = RedisKeyUtil.makeSessionPermIdKey(sessionId);
RSet<String> redisPermSet = redissonClient.getSet(sessionPermKey);
redisPermSet.addAll(permSet.stream().map(Object::toString).collect(Collectors.toSet()));
redisPermSet.expire(appConfig.getSessionExpiredSeconds(), TimeUnit.SECONDS);
}
// 4. 构造返回给用户的应答,将加密后的令牌返回给前端。
loginData.put(TokenData.REQUEST_ATTRIBUTE_NAME, token);
// 5. 这里需要移除权限资源集合的数据,验证在后端进行,无需返回给前端。
loginData.remove("permSet");
return ResponseResult.success(loginData);
}
}

View File

@@ -0,0 +1,188 @@
package com.orange.demo.gateway.filter;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.orange.demo.common.core.constant.ErrorCodeEnum;
import com.orange.demo.common.core.object.ResponseResult;
import com.orange.demo.common.core.object.TokenData;
import com.orange.demo.common.core.util.JwtUtil;
import com.orange.demo.common.core.util.RedisKeyUtil;
import com.orange.demo.common.core.util.IpUtil;
import com.orange.demo.gateway.config.ApplicationConfig;
import com.orange.demo.gateway.constant.GatewayConstant;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
/**
* 全局前处理过滤器。主要用于用户操作权限验证。
*
* @author Jerry
* @date 2020-08-08
*/
@Slf4j
public class AuthenticationPreFilter implements GlobalFilter, Ordered {
@Autowired
private ApplicationConfig appConfig;
@Autowired
private RedissonClient redissonClient;
/**
* Ant Pattern模式的白名单地址匹配器。
*/
private final AntPathMatcher antMatcher = new AntPathMatcher();
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
String url = request.getURI().getPath();
// 判断是否为白名单请求,以及一些内置不需要验证的请求。(登录请求也包含其中)。
if (this.shouldNotFilter(url)) {
return chain.filter(exchange);
}
String token = this.getTokenFromRequest(request);
Claims c = JwtUtil.parseToken(token, appConfig.getTokenSigningKey());
if (JwtUtil.isNullOrExpired(c)) {
log.warn("EXPIRED request [{}] from REMOTE-IP [{}].", url, IpUtil.getRemoteIpAddress(request));
response.setStatusCode(HttpStatus.UNAUTHORIZED);
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
byte[] responseBody = JSON.toJSONString(ResponseResult.error(ErrorCodeEnum.UNAUTHORIZED_LOGIN,
"用户登录已过期或尚未登录,请重新登录!")).getBytes(StandardCharsets.UTF_8);
return response.writeWith(Flux.just(response.bufferFactory().wrap(responseBody)));
}
// 这里判断是否需要定时刷新token
if (JwtUtil.needToRefresh(c)) {
exchange.getAttributes().put(appConfig.getRefreshedTokenHeaderKey(),
JwtUtil.generateToken(c, appConfig.getExpiration(), appConfig.getTokenSigningKey()));
}
// 先基于sessionId获取userInfo
String sessionId = (String) c.get(GatewayConstant.SESSION_ID_KEY_NAME);
String sessionIdKey = RedisKeyUtil.makeSessionIdKey(sessionId);
RBucket<String> sessionData = redissonClient.getBucket(sessionIdKey);
JSONObject tokenData = null;
if (sessionData.isExists()) {
tokenData = JSON.parseObject(sessionData.get());
}
if (tokenData == null) {
log.warn("UNAUTHORIZED request [{}] from REMOTE-IP [{}] because no sessionId exists in redis.",
url, IpUtil.getRemoteIpAddress(request));
response.setStatusCode(HttpStatus.UNAUTHORIZED);
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
byte[] responseBody = JSON.toJSONString(ResponseResult.error(ErrorCodeEnum.UNAUTHORIZED_LOGIN,
"用户会话已失效,请重新登录!")).getBytes(StandardCharsets.UTF_8);
return response.writeWith(Flux.just(response.bufferFactory().wrap(responseBody)));
}
String userId = tokenData.getString("userId");
if (StringUtils.isBlank(userId)) {
log.warn("UNAUTHORIZED request [{}] from REMOTE-IP [{}] because userId is empty in redis.",
url, IpUtil.getRemoteIpAddress(request));
response.setStatusCode(HttpStatus.UNAUTHORIZED);
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
byte[] responseBody = JSON.toJSONString(ResponseResult.error(ErrorCodeEnum.UNAUTHORIZED_LOGIN,
"用户登录验证信息已过期,请重新登录!")).getBytes(StandardCharsets.UTF_8);
return response.writeWith(Flux.just(response.bufferFactory().wrap(responseBody)));
}
String showName = tokenData.getString("showName");
// 因为http header中不支持中文传输所以需要编码。
try {
showName = URLEncoder.encode(showName, StandardCharsets.UTF_8.name());
tokenData.put("showName", showName);
} catch (UnsupportedEncodingException e) {
log.error("Failed to call AuthenticationPreFilter.filter.", e);
}
boolean isAdmin = tokenData.getBoolean("isAdmin");
if (Boolean.FALSE.equals(isAdmin) && !this.hasPermission(redissonClient, sessionId, url)) {
log.warn("FORBIDDEN request [{}] from REMOTE-IP [{}] for USER [{} -- {}] no perm!",
url, IpUtil.getRemoteIpAddress(request), userId, showName);
response.setStatusCode(HttpStatus.FORBIDDEN);
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
byte[] responseBody = JSON.toJSONString(ResponseResult.error(ErrorCodeEnum.NO_OPERATION_PERMISSION,
"用户对该URL没有访问权限请核对")).getBytes(StandardCharsets.UTF_8);
return response.writeWith(Flux.just(response.bufferFactory().wrap(responseBody)));
}
// 将session中关联的用户信息添加到当前的Request中。转发后业务服务可以根据需要自定读取。
tokenData.put("sessionId", sessionId);
exchange.getAttributes().put(GatewayConstant.SESSION_ID_KEY_NAME, sessionId);
ServerHttpRequest mutableReq = exchange.getRequest().mutate().header(
TokenData.REQUEST_ATTRIBUTE_NAME, tokenData.toJSONString()).build();
ServerWebExchange mutableExchange = exchange.mutate().request(mutableReq).build();
return chain.filter(mutableExchange);
}
/**
* 返回过滤器在在调用链上的优先级。
*
* @return 数值越低,优先级越高。
*/
@Override
public int getOrder() {
return HIGHEST_PRECEDENCE + 10000;
}
private String getTokenFromRequest(ServerHttpRequest request) {
String token = request.getHeaders().getFirst(appConfig.getTokenHeaderKey());
if (StringUtils.isBlank(token)) {
token = request.getQueryParams().getFirst(appConfig.getTokenHeaderKey());
}
return token;
}
private boolean hasPermission(RedissonClient redissonClient, String sessionId, String url) {
// 对于退出登录操作,不需要进行权限验证,仅仅确认是已经登录的合法用户即可。
if (url.equals(GatewayConstant.ADMIN_LOGOUT_URL)) {
return true;
}
String permKey = RedisKeyUtil.makeSessionPermIdKey(sessionId);
return redissonClient.getSet(permKey).contains(url);
}
/**
* 判断当前请求的url是否为配置中的白名单地址。以及一些内置的不需要登录即可访问的url。
* @param url 请求的url。
* @return 是返回true否则false。
*/
private boolean shouldNotFilter(String url) {
// 这里过滤和swagger相关的url
if (url.endsWith("/v2/api-docs") || url.endsWith("/v2/api-docs-ext")) {
return true;
}
if (url.equals(GatewayConstant.ADMIN_LOGIN_URL)) {
return true;
}
// 先过滤直接匹配的白名单url。
if (CollectionUtils.isNotEmpty(appConfig.getWhitelistUrl())) {
if (appConfig.getWhitelistUrl().contains(url)) {
return true;
}
}
// 过滤ant pattern模式的白名单url。
if (CollectionUtils.isNotEmpty(appConfig.getWhitelistUrlPattern())) {
for (String urlPattern : appConfig.getWhitelistUrlPattern()) {
if (antMatcher.match(urlPattern, url)) {
return true;
}
}
}
return false;
}
}

View File

@@ -0,0 +1,60 @@
package com.orange.demo.gateway.filter;
import com.orange.demo.common.core.constant.ApplicationConstant;
import com.orange.demo.common.core.util.MyCommonUtil;
import com.orange.demo.gateway.constant.GatewayConstant;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* 链路日志前置过虑器。
* 为整个链路生成唯一的traceId并存储在Request Head中。
*
* @author Jerry
* @date 2020-08-08
*/
@Slf4j
public class RequestLogFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("开始请求app={gateway}, url={}", exchange.getRequest().getURI().getPath());
final String traceId = MyCommonUtil.generateUuid();
// 分别记录traceId和执行开始时间。
exchange.getAttributes().put(GatewayConstant.START_TIME_ATTRIBUTE, System.currentTimeMillis());
ServerHttpRequest mutableReq = exchange.getRequest().mutate().header(
ApplicationConstant.HTTP_HEADER_TRACE_ID, traceId).build();
ServerWebExchange mutableExchange = exchange.mutate().request(mutableReq).build();
ServerHttpResponse response = mutableExchange.getResponse();
response.beforeCommit(() -> {
response.getHeaders().set(ApplicationConstant.HTTP_HEADER_TRACE_ID, traceId);
return Mono.empty();
});
return chain.filter(mutableExchange).then(Mono.fromRunnable(() -> {
Long startTime = exchange.getAttribute(GatewayConstant.START_TIME_ATTRIBUTE);
MDC.put(ApplicationConstant.HTTP_HEADER_TRACE_ID, traceId);
long elapse = 0;
if (startTime != null) {
elapse = System.currentTimeMillis() - startTime;
}
log.info("请求完成, app={gateway}, url={}elapse={}", exchange.getRequest().getURI().getPath(), elapse);
}));
}
/**
* 返回过滤器在在调用链上的优先级。
*
* @return 数值越低,优先级越高。
*/
@Override
public int getOrder() {
return HIGHEST_PRECEDENCE + 9900;
}
}

View File

@@ -0,0 +1,53 @@
package com.orange.demo.gateway.handler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.*;
import java.util.Optional;
/**
* Swagger的资源请求处理器。
*
* @author Knife4j Team。
* @date 2020-08-08
*/
@RestController
public class SwaggerHandler {
@Autowired(required = false)
private SecurityConfiguration securityConfiguration;
@Autowired(required = false)
private UiConfiguration uiConfiguration;
private final SwaggerResourcesProvider swaggerResources;
@Autowired
public SwaggerHandler(SwaggerResourcesProvider swaggerResources) {
this.swaggerResources = swaggerResources;
}
@GetMapping("/swagger-resources/configuration/security")
public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {
return Mono.just(new ResponseEntity<>(
Optional.ofNullable(securityConfiguration)
.orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK));
}
@GetMapping("/swagger-resources/configuration/ui")
public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {
return Mono.just(new ResponseEntity<>(
Optional.ofNullable(uiConfiguration)
.orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
}
@GetMapping("/swagger-resources")
public Mono<ResponseEntity> swaggerResources() {
return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
}
}

View File

@@ -0,0 +1,19 @@
spring:
application:
name: gateway
profiles:
active: dev
cloud:
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848
file-extension: yaml
# 共享配置文件,排序越高后,优先级越高。
shared-configs:
- data-id: application-dev.yaml
group: DEFAULT_GROUP
refresh: true
main:
allow-bean-definition-overriding: true

View File

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!-- 本项目全部使用log4j2性能上有很大提升 -->
<!--monitorInterval="60" 自动检测配置文件更改时间 单位为秒 最小值为5 -->
<!--Configuration后面的status这个用于设置log4j2自身内部的信息输出可以不设置当设置成trace时你会看到log4j2内部各种详细输出。 -->
<configuration monitorInterval="20" status="OFF">
<!--日志变量 -->
<properties>
<!-- 日志主目录 ,需要保存到文件时请自己配置-->
<property name="LOG_HOME">./zzlogs/gateway</property>
<!-- 日志备份目录 -->
<property name="BACKUP_HOME">./zzlogs/gateway/backup</property>
<!-- 日志输出级别 -->
<property name="OUTPUT_LOG_LEVEL">info</property>
<!-- 日志输出格式 -->
<property name="LOG_PATTERN">
<!-- 输出格式%d{HH:mm:ss}时间24小时制 -->
<!-- %-5p日志级别 5位左对齐 [%t]线程名 [%c]类名 -->
<!--%l输出日志事件的发生位置相当于%c.%M(%F:%L)的组合包括类全名、方法、文件名以及在代码中的行数。例如test.TestLog4j.main(TestLog4j.java:10)。 -->
<!-- 另一种输出风格<PatternLayout pattern="级别%-5p [%d{YYYY-MM-dd HH:mm:ss}] [%t] 位置[%l] - 信息:%msg%n" /> -->
<!-- [%-5p][%d{yy-MM-dd HH:mm:ss}][%t]==>%m==>%c==>%L%n -->
[%-5p] [%d{YYYY-MM-dd HH:mm:ss}] [%t] ==> %msg%n
</property>
<property name="LOG_PATTERN_EX">
<!-- 下面注释中 %X{PtxId}, SpanId: %X{PspanId} 为PinPoint 中的traceid -->
[%-5p] [%d{YYYY-MM-dd HH:mm:ss}] T:[%X{traceId}] [%t] ==> [TxId: %X{PtxId}, SpanId: %X{PspanId}] %msg%n
</property>
<!-- 日志保留天数 -->
<property name="EVERY_FILE_COUNT">31</property>
<!-- 日志切割的最小单位 -->
<property name="EVERY_FILE_SIZE">20M</property>
</properties>
<appenders>
<!--Kafka输出 -->
<Kafka name="kafka_log" topic="zz-log-topic" syncSend="false" ignoreExceptions="false">
<PatternLayout pattern="${LOG_PATTERN_EX}"/>
<Property name="bootstrap.servers">localhost:9092</Property>
<Property name="max.block.ms">10000</Property>
</Kafka>
<!--控制台输出 -->
<console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="${LOG_PATTERN}"/>
</console>
<!--每次大小超过size则这size大小的日志会自动进行压缩作为存档 -->
<rollingFile name="file_log" fileName="${LOG_HOME}/gateway.log"
filePattern="${LOG_HOME}/gateway-%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout charset="UTF-8" pattern="${LOG_PATTERN_EX}"/>
<!-- 日志切割的最小单位 -->
<SizeBasedTriggeringPolicy size="${EVERY_FILE_SIZE}"/>
<!-- 默认的日志文件数量 -->
<DefaultRolloverStrategy max="${EVERY_FILE_COUNT}"/>
</rollingFile>
</appenders>
<!-- 然后定义logger只有定义了logger并引入的appenderappender才会生效 -->
<!-- 这里我们把输出到控制台appender的日志级别设置为DEBUG便于调试。但是输出文件我们缺省为INFO两者均可随时修改。-->
<Loggers>
<Root level="${OUTPUT_LOG_LEVEL}">
<AppenderRef ref="console"/>
</Root>
<Logger name="springfox.documentation" additivity="false" level="error">
<AppenderRef ref="console"/>
</Logger>
<!-- AsyncLogger 是基于Disruptor的全量异步队列性能极高队列默认大小4096。-->
<!-- 队列默认值可通过JVM参数设置参考博客https://www.jianshu.com/p/82469047acbf -->
<AsyncLogger name="com.orange.demo" additivity="false" level="info">
<AppenderRef ref="console"/>
<AppenderRef ref="kafka_log"/>
<AppenderRef ref="file_log"/>
</AsyncLogger>
</Loggers>
</configuration>