JeecgBoot 2.3 里程碑版本发布,支持微服务和单体自由切换、提供新行编辑表格JVXETable

This commit is contained in:
zhangdaiscott
2020-09-13 18:23:23 +08:00
parent c5f055d004
commit 024272eb7c
533 changed files with 187550 additions and 36942 deletions

View File

@ -0,0 +1,7 @@
# 服务化改造手册
~~~
注意 :启动服务跨域问题处理
1、需要将common 模块的 WebMvcConfiguration corsFilter 注掉 后面做成注解切换
2、org.jeecg.config.shiro.filters.JwtFilter类的 65行跨域代码注释掉
~~~

View File

@ -0,0 +1,81 @@
<?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>
<artifactId>jeecg-cloud-module</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>2.3.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jeecg-cloud-gateway</artifactId>
<properties>
<swagger2.version>2.9.2</swagger2.version>
</properties>
<dependencies>
<!-- spring-cloud-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 熔断、降级 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 限流Redis实现 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<!--springboot2.X默认使用lettuce连接池需要引入commons-pool2-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--server-api-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<!-- Swagger API文档 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger2.version}</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>

View File

@ -0,0 +1,16 @@
package org.jeecg;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
@EnableDiscoveryClient
public class JeecgGatewayApplication {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(JeecgGatewayApplication.class, args);
String userName = applicationContext.getEnvironment().getProperty("jeecg.test");
System.err.println("user name :" +userName);
}
}

View File

@ -0,0 +1,31 @@
package org.jeecg.config;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.handler.HystrixFallbackHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
/**
* @author scott
* @date 2020/05/26
* 路由配置信息
*/
@Slf4j
@Configuration
@AllArgsConstructor
public class GatewayRoutersConfiguration {
private final HystrixFallbackHandler hystrixFallbackHandler;
@Bean
public RouterFunction routerFunction() {
return RouterFunctions.route(
RequestPredicates.path("/fallback").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), hystrixFallbackHandler);
}
}

View File

@ -0,0 +1,49 @@
package org.jeecg.filter;
import lombok.extern.slf4j.Slf4j;
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.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Arrays;
import java.util.stream.Collectors;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.addOriginalRequestUrl;
/**
*
*/
@Slf4j
@Component
public class GlobalAccessTokenFilter implements GlobalFilter, Ordered {
public final static String X_ACCESS_TOKEN = "X-Access-Token";
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String url = exchange.getRequest().getURI().getPath();
log.info(" access url : "+ url);
// 1. 重写StripPrefix(获取真实的URL)
addOriginalRequestUrl(exchange, exchange.getRequest().getURI());
String rawPath = exchange.getRequest().getURI().getRawPath();
String newPath = "/" + Arrays.stream(StringUtils.tokenizeToStringArray(rawPath, "/")).skip(1L).collect(Collectors.joining("/"));
ServerHttpRequest newRequest = exchange.getRequest().mutate().path(newPath).build();
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, newRequest.getURI());
//将现在的request添加当前身份
ServerHttpRequest mutableReq = exchange.getRequest().mutate().header("Authorization-UserName", "").build();
ServerWebExchange mutableExchange = exchange.mutate().request(mutableReq).build();
return chain.filter(mutableExchange);
}
@Override
public int getOrder() {
return 0;
}
}

View File

@ -0,0 +1,34 @@
package org.jeecg.handler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import java.util.Optional;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR;
/**
* @author scott
* @date 2020/05/26
* Hystrix 降级处理
*/
@Slf4j
@Component
public class HystrixFallbackHandler implements HandlerFunction<ServerResponse> {
@Override
public Mono<ServerResponse> handle(ServerRequest serverRequest) {
Optional<Object> originalUris = serverRequest.attribute(GATEWAY_ORIGINAL_REQUEST_URL_ATTR);
originalUris.ifPresent(originalUri -> log.error("网关执行请求:{}失败,hystrix服务降级处理", originalUri));
return ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR.value())
.header("Content-Type","text/plain; charset=utf-8").body(BodyInserters.fromObject("服务异常"));
}
}

View File

@ -0,0 +1,65 @@
package org.jeecg.handler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.stereotype.Component;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
import java.util.*;
/**
* 聚合各个服务的swagger接口
*/
@Component
public class MySwaggerResourceProvider implements SwaggerResourcesProvider {
/**
* swagger2默认的url后缀
*/
private static final String SWAGGER2URL = "/v2/api-docs";
/**
* 网关路由
*/
private final RouteLocator routeLocator;
/**
* 网关应用名称
*/
@Value("${spring.application.name}")
private String self;
@Autowired
public MySwaggerResourceProvider(RouteLocator routeLocator) {
this.routeLocator = routeLocator;
}
@Override
public List<SwaggerResource> get() {
List<SwaggerResource> resources = new ArrayList<>();
List<String> routeHosts = new ArrayList<>();
// 获取所有可用的hostserviceId
routeLocator.getRoutes().filter(route -> route.getUri().getHost() != null)
.filter(route -> !self.equals(route.getUri().getHost()))
.subscribe(route -> routeHosts.add(route.getUri().getHost()));
// 记录已经添加过的server存在同一个应用注册了多个服务在eureka上
Set<String> dealed = new HashSet<>();
routeHosts.forEach(instance -> {
// 拼接url
String url = "/" + instance.toLowerCase() + SWAGGER2URL;
if (!dealed.contains(url)) {
dealed.add(url);
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setUrl(url);
swaggerResource.setName(instance);
//Swagger排除监控
if(instance.indexOf("jeecg-cloud-monitor")==-1){
resources.add(swaggerResource);
}
}
});
return resources;
}
}

View File

@ -0,0 +1,39 @@
package org.jeecg.handler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.swagger.web.*;
import java.util.List;
/**
* swagger聚合接口三个接口都是 doc.html需要访问的接口
*/
@RestController
@RequestMapping("/swagger-resources")
public class SwaggerResourceController {
private MySwaggerResourceProvider swaggerResourceProvider;
@Autowired
public SwaggerResourceController(MySwaggerResourceProvider swaggerResourceProvider) {
this.swaggerResourceProvider = swaggerResourceProvider;
}
@RequestMapping(value = "/configuration/security")
public ResponseEntity<SecurityConfiguration> securityConfiguration() {
return new ResponseEntity<>(SecurityConfigurationBuilder.builder().build(), HttpStatus.OK);
}
@RequestMapping(value = "/configuration/ui")
public ResponseEntity<UiConfiguration> uiConfiguration() {
return new ResponseEntity<>(UiConfigurationBuilder.builder().build(), HttpStatus.OK);
}
@RequestMapping
public ResponseEntity<List<SwaggerResource>> swaggerResources() {
return new ResponseEntity<>(swaggerResourceProvider.get(), HttpStatus.OK);
}
}

View File

@ -0,0 +1,39 @@
spring:
redis:
host: 127.0.0.1
password: ''
port: 6379
cloud:
gateway:
discovery:
locator:
enabled: true
globalcors:
cors-configurations:
'[/**]':
allowCredentials: true
allowedOrigins: "*"
allowedMethods: "*"
allowedHeaders: "*"
routes:
- id: jeecg-demo
uri: lb://jeecg-demo
predicates:
- Path=/test/**,/api/**
- id: jeecg-system
uri: lb://jeecg-system
predicates:
- Path=/sys/**,/webSocketApi/**,/online/**,/message/**
- id: jeecg-system-websocket
uri: lb:ws://jeecg-system
predicates:
- Path=/websocket/**
- id: jeecg-demo-websocket
uri: lb:ws://jeecg-demo
predicates:
- Path=/vxeSocket/**
management:
endpoints:
web:
exposure:
include: '*'

View File

@ -0,0 +1,11 @@
server:
port: 9999
spring:
application:
name: jeecg-cloud-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
profiles:
active: dev

View File

@ -0,0 +1,20 @@
<?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>
<artifactId>jeecg-boot-parent</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>2.3.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jeecg-cloud-module</artifactId>
<packaging>pom</packaging>
<modules>
<module>jeecg-cloud-gateway</module>
</modules>
</project>