SpringCloud Gateway动态路由

553 阅读1分钟

说明 动态路由配置免去了每新增路由跳转都需要重启网关的工作,如下则是保存到MongoDB的步骤 相关pom.xml文件配置

<dependencies>
		<!--GateWay ⽹关-->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-gateway</artifactId>
		</dependency>
		<!--引⼊webflux-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-webflux</artifactId>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-mongodb</artifactId>
		</dependency>
	</dependencies>

application.yml配置

spring:
  application:
    name: api-gateway
  data:
    mongodb:
      uri: mongodb://username:password@192.168.8.11:27017/databaseName

mongo相关类

#定义路由实体
@Getter
@Setter
public class Router {

    /** 路由ID */
    @Id
    private String id;
    /** 路由谓词 */
    private List<PredicateDefinition> predicates = new ArrayList<>();
    /** 过滤器 */
    private List<FilterDefinition> filters = new ArrayList<>();
    /** 跳转地址uri */
    private String uri;
    /** 路由顺序 */
    private int order;
}
#定义service
public interface RouterService {

    List<Router> listAll();

    void add(Router router);

    void modifyById(Router router);

    void removeById(String id);
}
@Service
public class RouterServiceImpl implements RouterService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Override
    public List<Router> listAll() {
        return mongoTemplate.findAll(Router.class);
    }

    @Override
    public void add(Router router) {
        mongoTemplate.save(router);
    }

    @Override
    public void modifyById(Router router) {
        mongoTemplate.save(router);
    }

    @Override
    public void removeById(String id) {
        Query query = Query.query(Criteria.where("id").is(id));
        mongoTemplate.remove(query,Router.class);
    }
}

实现路由保存接口 RouteDefinitionRepository

@Service
public class MongoRouteDefinitionRepository implements RouteDefinitionRepository {

    @Autowired
    private RouterService routerService;

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        List<Router> routers = routerService.listAll();
        List<RouteDefinition> routeDefinitions = new ArrayList<>();
        for (Router router : routers) {
            RouteDefinition routeDefinition = new RouteDefinition();
            routeDefinition.setId(router.getId());
            routeDefinition.setFilters(router.getFilters());
            routeDefinition.setPredicates(router.getPredicates());
            routeDefinition.setUri(URI.create(router.getUri()));
            routeDefinition.setOrder(router.getOrder());
            routeDefinitions.add(routeDefinition);
        }
        return Flux.fromIterable(routeDefinitions);
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return route.flatMap(routeDefinition -> {
            Router router = new Router();
            router.setId(routeDefinition.getId());
            router.setFilters(routeDefinition.getFilters());
            router.setPredicates(routeDefinition.getPredicates());
            router.setUri(routeDefinition.getUri().toString());
            router.setOrder(routeDefinition.getOrder());
            routerService.add(router);
            return Mono.empty();
        });
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return routeId.flatMap(id -> {
            routerService.removeById(id);
            return Mono.empty();
        });
    }
}

实现网关路由接口 ApplicationEventPublisherAware

@Service
public class GatewayDynamicRouteService implements ApplicationEventPublisherAware {

    @Autowired
    private MongoRouteDefinitionRepository mongoRouteDefinitionRepository;
    private ApplicationEventPublisher applicationEventPublisher;

    private void notifyChanged() {
        applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
    }


    /**
     * 增加路由
     *
     * @param routeDefinition
     * @return
     */
    public int add(RouteDefinition routeDefinition) {
        mongoRouteDefinitionRepository.save(Mono.just(routeDefinition)).subscribe();
        notifyChanged();
        return 1;
    }

    /**
     * 更新
     *
     * @param routeDefinition
     * @return
     */
    public int update(RouteDefinition routeDefinition) {
        mongoRouteDefinitionRepository.delete(Mono.just(routeDefinition.getId()));
        mongoRouteDefinitionRepository.save(Mono.just(routeDefinition)).subscribe();
        notifyChanged();
        return 1;
    }

    /**
     * 删除路由
     */
    public int delete(String id) {
        mongoRouteDefinitionRepository.delete(Mono.just(id)).subscribe();
        notifyChanged();
        return 1;
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
}

控制类编写

@RestController
@RequestMapping("/gateway/route")
public class GatewayDynamicRouteController {

    @Resource
    private GatewayDynamicRouteService gatewayDynamicRouteService;

    @PostMapping("/add")
    public ResponseMessage create(@RequestBody RouteDefinition entity) {
        int result = gatewayDynamicRouteService.add(entity);
        return ResponseMessage.success(new HashMap<String, Object>(){{
            put("result", result);
        }});
    }

    @PostMapping("/update")
    public ResponseMessage update(@RequestBody RouteDefinition entity) {
        int result = gatewayDynamicRouteService.update(entity);
        return ResponseMessage.success(new HashMap<String, Object>(){{
            put("result", result);
        }});
    }

    @GetMapping("/delete/{id}")
    public ResponseMessage delete(@PathVariable String id) {
        int result = gatewayDynamicRouteService.delete(id);
        return ResponseMessage.success(new HashMap<String, Object>(){{
            put("result", result);
        }});
    }
}
  • 注意需要把yml中定义的路由配置删除掉 测试接口 具体配置规则,需要看官方文档
#postman调用
{
    "id":"blog",
    "predicates":[
        {
            "name": "Path",
            "args":{
                "pattern" : "/user/**"
            }
        }
    ],
    "filters" : [ 
        {
            "name" : "StripPrefix",
            "args" : {
                "_genkey_0" : "1"
            }
        }
    ],
    "uri": "https://blog.csdn.net",
    "order": 0
}