1. Defina el modelo de enrutamiento
import lombok.Data;
import java.util.LinkedHashMap;
import java.util.List;
/**
* 路由模型
*
* @author 向振华
* @date 2021/02/04 10:26
*/
@Data
public class RouteDefinitionDTO {
/**
* 路由的Id
*/
private String id;
/**
* 路由断言集合配置
*/
private List<PredicateDefinitionDTO> predicates;
/**
* 路由过滤器集合配置
*/
private List<FilterDefinitionDTO> filters;
/**
* 路由规则转发的目标uri
*/
private String uri;
/**
* 路由执行的顺序
*/
private Integer order;
@Data
public static class PredicateDefinitionDTO {
/**
* 断言名称
*/
private String name;
/**
* 断言规则
*/
private LinkedHashMap<String, String> args;
}
@Data
public static class FilterDefinitionDTO {
/**
* 过滤器名称
*/
private String name;
/**
* 路由规则
*/
private LinkedHashMap<String, String> args;
}
}
2. Definir el enrutamiento y modificar el controlador
import com.bzcst.bop.gateway.entity.RouteDefinitionDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import java.util.List;
/**
* @author 向振华
* @date 2021/02/04 10:26
*/
@RestController
@RequestMapping("/route")
public class DynamicRouteController {
@Autowired
private DynamicRouteService dynamicRouteService;
/**
* 获取路由
*/
@GetMapping
public Flux<RouteDefinition> get() {
return dynamicRouteService.get();
}
/**
* 更新路由
*/
@PutMapping
public void update(@RequestBody List<RouteDefinitionDTO> dto) {
dynamicRouteService.updateRoutes(dto);
}
/**
* 删除路由
*/
@DeleteMapping("/{id}")
public void delete(@PathVariable String id) {
dynamicRouteService.delete(id);
}
}
3. Defina el servicio para manejar el enrutamiento dinámico y guárdelo en la memoria local.
import com.bzcst.bop.gateway.entity.RouteDefinitionDTO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import javax.annotation.Resource;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
/**
* 动态路由服务
*
* @author 向振华
* @date 2021/02/04 10:26
*/
@Service
public class DynamicRouteService implements ApplicationEventPublisherAware {
@Resource
private RouteDefinitionLocator routeDefinitionLocator;
@Resource
private RouteDefinitionWriter routeDefinitionWriter;
private ApplicationEventPublisher publisher;
/**
* 获取路由
*
* @return
*/
public Flux<RouteDefinition> get() {
return routeDefinitionLocator.getRouteDefinitions();
}
/**
* 更新路由
*
* @param dtos
*/
public void updateRoutes(List<RouteDefinitionDTO> dtos) {
if (CollectionUtils.isEmpty(dtos)) {
return;
}
for (RouteDefinitionDTO dto : dtos) {
RouteDefinition routeDefinition = convertRouteDefinition(dto);
update(routeDefinition);
}
}
/**
* 更新路由
*
* @param definition
*/
public void update(RouteDefinition definition) {
delete(definition.getId());
save(definition);
}
/**
* 删除路由
*
* @param id
*/
public void delete(String id) {
try {
routeDefinitionWriter.delete(Mono.just(id)).subscribe();
} catch (Exception ignored) {
}
this.publisher.publishEvent(new RefreshRoutesEvent(this));
}
/**
* 保存路由
*
* @param definition
*/
public void save(RouteDefinition definition) {
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
}
/**
* 参数转换成路由对象
*
* @param dto
* @return
*/
private RouteDefinition convertRouteDefinition(RouteDefinitionDTO dto) {
RouteDefinition definition = new RouteDefinition();
// 设置id
definition.setId(dto.getId());
// 设置order
definition.setOrder(dto.getOrder());
// 设置断言
List<PredicateDefinition> pdList = new ArrayList<>();
List<RouteDefinitionDTO.PredicateDefinitionDTO> predicateDefinitionDTOList = dto.getPredicates();
for (RouteDefinitionDTO.PredicateDefinitionDTO gpDefinition : predicateDefinitionDTOList) {
PredicateDefinition predicate = new PredicateDefinition();
predicate.setArgs(gpDefinition.getArgs());
predicate.setName(gpDefinition.getName());
pdList.add(predicate);
}
definition.setPredicates(pdList);
// 设置过滤器
List<FilterDefinition> filters = new ArrayList<>();
List<RouteDefinitionDTO.FilterDefinitionDTO> gatewayFilters = dto.getFilters();
for (RouteDefinitionDTO.FilterDefinitionDTO filterDefinition : gatewayFilters) {
FilterDefinition filter = new FilterDefinition();
filter.setName(filterDefinition.getName());
filter.setArgs(filterDefinition.getArgs());
filters.add(filter);
}
definition.setFilters(filters);
// 设置uri
URI uri = null;
String uriStr = dto.getUri();
if (StringUtils.isNotBlank(uriStr)) {
String http = "http";
if (uriStr.startsWith(http)) {
uri = UriComponentsBuilder.fromHttpUrl(dto.getUri()).build().toUri();
} else {
uri = URI.create(dto.getUri());
}
}
definition.setUri(uri);
return definition;
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
}
4. Utilice
Habrá un problema aquí. Modificar una ruta existente en el archivo de configuración local agregará una nueva ruta. Mi solución es eliminar la configuración de enrutamiento local y usar la configuración de enrutamiento dinámico.
La interfaz de enrutamiento debe estar bien controlada por motivos de seguridad, puede estar cifrada y firmada, o modificada por otros servicios, y luego usar redis para actualizar regularmente, actualizar dinámicamente, etc.
Adjuntar parámetro json
[
{
"id":"xxx服务",
"predicates":[
{
"name":"Path",
"args":{
"_genkey_0":"/xxx/**"
}
}
],
"filters":[
{
"name":"Login",
"args":{
}
},
{
"name":"FileSize",
"args":{
"_genkey_0":"10485760",
"_genkey_1":"/*/x/z;/*/h/a"
}
}
],
"uri":"lb://xxx",
"order":0
}
]