基于mysql的gateway动态路由_springcloud gateway动态路由实现,mysql存储配置

本文介绍了如何在Spring Cloud Gateway中实现基于MySQL的动态路由配置。通过创建RedisRouteDefinitionRepository,将路由信息存储在Redis中,利用数据库查询获取并更新路由配置。在启动和运行时,使用CommandLineRunner加载数据库中的路由配置到Redis,同时提供了添加、删除和更新路由的API接口。
摘要由CSDN通过智能技术生成

1、mysql数据库表结构

22a7223a741e6450619130424f3b7416.png

2、pom.xml依赖

org.springframework.boot

spring-boot-starter-actuator

org.springframework.cloud

spring-cloud-starter-gateway

org.springframework.cloud

spring-cloud-gateway-webflux

org.springframework.boot

spring-boot-starter-data-redis

3、application.yml添加

#开启端点

management:

endpoints:

web:

exposure:

include: ‘*‘

security:

enabled: false

4、核心配置类,加载路由配置到redis,官网核心包从redis获取路由配置,提高效率

import com.alibaba.fastjson.JSON;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.cloud.gateway.route.RouteDefinition;

import org.springframework.cloud.gateway.route.RouteDefinitionRepository;

import org.springframework.cloud.gateway.support.NotFoundException;

import org.springframework.data.redis.core.RedisTemplate;

import org.springframework.stereotype.Component;

import reactor.core.publisher.Flux;

import reactor.core.publisher.Mono;

import java.util.ArrayList;

import java.util.List;

/**

*将定义好的路由表信息通过此类读写到redis中

*/

@Component

public class RedisRouteDefinitionRepository implements RouteDefinitionRepository {

public static final String GATEWAY_ROUTES = "gateway:routes";

@Autowired

private RedisTemplate redisTemplate;

//请注意,此方法很重要,从redis取路由信息的方法,官方核心包要用,核心路由功能都是从redis取的

@Override

public Flux getRouteDefinitions() {

List routeDefinitions = new ArrayList<>();

redisTemplate.opsForHash().values(GATEWAY_ROUTES).stream().forEach(routeDefinition -> {

routeDefinitions.add(JSON.parseObject(routeDefinition.toString(), RouteDefinition.class));

});

return Flux.fromIterable(routeDefinitions);

}

@Override

public Mono save(Mono route) {

return route

.flatMap(routeDefinition -> {

redisTemplate.opsForHash().put(GATEWAY_ROUTES, routeDefinition.getId(),

JSON.toJSONString(routeDefinition));

return Mono.empty();

});

}

@Override

public Mono delete(Mono routeId) {

return routeId.flatMap(id -> {

if (redisTemplate.opsForHash().hasKey(GATEWAY_ROUTES, id)) {

redisTemplate.opsForHash().delete(GATEWAY_ROUTES, id);

return Mono.empty();

}

return Mono.defer(() -> Mono.error(new NotFoundException("路由文件没有找到: " + routeId)));

});

}

}

5、核心配置类,项目初始化加载数据库的路由配置到redis

import java.net.URI;

import java.util.Arrays;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.CommandLineRunner;

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.context.ApplicationEventPublisher;

import org.springframework.context.ApplicationEventPublisherAware;

import org.springframework.stereotype.Service;

import org.springframework.web.util.UriComponentsBuilder;

import com.alibaba.fastjson.JSON;

import com.smc.gateway.dao.GatewayRouteMapper;

import com.smc.gateway.entity.GatewayRoute;

import com.smc.gateway.repository.RedisRouteDefinitionRepository;

import lombok.extern.slf4j.Slf4j;

import reactor.core.publisher.Mono;

@Slf4j

@Service

public class GatewayServiceHandler implements ApplicationEventPublisherAware, CommandLineRunner{

@Autowired

private RedisRouteDefinitionRepository routeDefinitionWriter;

private ApplicationEventPublisher publisher;

@Override

public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher){

this.publisher = applicationEventPublisher;

}

//自己的获取数据dao

@Autowired

private GatewayRouteMapper gatewayRouteMapper;

@Override

public void run(String... args){

this.loadRouteConfig();

}

public String loadRouteConfig(){

log.info("====开始加载=====网关配置信息=========");

//删除redis里面的路由配置信息

redisTemplate.delete(RedisRouteDefinitionRepository.GATEWAY_ROUTES);

//从数据库拿到基本路由配置

List gatewayRouteList = gatewayRouteMapper.queryAllRoutes();

gatewayRouteList.forEach(gatewayRoute -> {

RouteDefinition definition=handleData(gatewayRoute);

routeDefinitionWriter.save(Mono.just(definition)).subscribe();

});

this.publisher.publishEvent(new RefreshRoutesEvent(this));

log.info("=======网关配置信息===加载完成======");

return "success";

}

public void saveRoute(GatewayRoute gatewayRoute){

RouteDefinition definition=handleData(gatewayRoute);

routeDefinitionWriter.save(Mono.just(definition)).subscribe();

this.publisher.publishEvent(new RefreshRoutesEvent(this));

}

public void update(GatewayRoute gatewayRoute){

RouteDefinition definition=handleData(gatewayRoute);

try {

this.routeDefinitionWriter.delete(Mono.just(definition.getId()));

routeDefinitionWriter.save(Mono.just(definition)).subscribe();

this.publisher.publishEvent(new RefreshRoutesEvent(this));

} catch (Exception e) {

e.printStackTrace();

}

}

public void deleteRoute(String routeId){

routeDefinitionWriter.delete(Mono.just(routeId)).subscribe();

this.publisher.publishEvent(new RefreshRoutesEvent(this));

}

/**

* 路由数据转换公共方法

* @param gatewayRoute

* @return

*/

private RouteDefinition handleData(GatewayRoute gatewayRoute){

RouteDefinition definition = new RouteDefinition();

Map predicateParams = new HashMap<>(8);

PredicateDefinition predicate = new PredicateDefinition();

FilterDefinition filterDefinition = new FilterDefinition();

Map filterParams = new HashMap<>(8);

URI uri = null;

if(gatewayRoute.getUri().startsWith("http")){

//http地址

uri = UriComponentsBuilder.fromHttpUrl(gatewayRoute.getUri()).build().toUri();

}else{

//注册中心

uri = UriComponentsBuilder.fromUriString("lb://"+gatewayRoute.getUri()).build().toUri();

}

definition.setId(gatewayRoute.getServiceId());

// 名称是固定的,spring gateway会根据名称找对应的PredicateFactory

predicate.setName("Path");

predicateParams.put("pattern",gatewayRoute.getPredicates());

predicate.setArgs(predicateParams);

// 名称是固定的, 路径去前缀

filterDefinition.setName("StripPrefix");

filterParams.put("_genkey_0", gatewayRoute.getFilters().toString());

filterDefinition.setArgs(filterParams);

definition.setPredicates(Arrays.asList(predicate));

definition.setFilters(Arrays.asList(filterDefinition));

definition.setUri(uri);

definition.setOrder(Integer.parseInt(gatewayRoute.getGOrder()));

return definition;

}

}

6、自定义controller层;

直接在数据库添加路由配置信息;

前端页面增、删、改路由配置信息,并刷新redis使配置信息立即生效;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.PostMapping;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import org.springframework.beans.BeanUtils;

import com.smc.gateway.dto.GatewayRouteDto;

import com.smc.gateway.route.GatewayRouteService;

import com.smc.gateway.route.GatewayServiceHandler;

@RestController

@RequestMapping("/route")

public class RouteController{

@Autowired

private GatewayServiceHandler gatewayServiceHandler;

@Autowired

private GatewayRouteService gatewayRouteService;

/**

* 刷新路由配置

*

* @param gwdefinition

* @return

*/

@GetMapping("/refresh")

public String refresh() throws Exception {

return this.gatewayServiceHandler.loadRouteConfig();

}

/**

* 增加路由记录

*

* @param gwdefinition

* @return

*/

@PostMapping("/add")

public String add(@RequestBody GatewayRouteDto gatewayRouteDto) throws Exception {

gatewayRouteService.add(gatewayRouteDto);

GatewayRoute gatewayRoute=new GatewayRoute();

BeanUtils.copyProperties(gatewayRouteDto, gatewayRoute);

gatewayServiceHandler.saveRoute(gatewayRoute);

return "success";

}

@PostMapping("/update")

public String update(@RequestBody GatewayRouteDto gatewayRouteDto) throws Exception {

gatewayRouteService.update(gatewayRouteDto);

GatewayRoute gatewayRoute=new GatewayRoute();

BeanUtils.copyProperties(gatewayRouteDto, gatewayRoute);

gatewayServiceHandler.update(gatewayRoute);

return "success";

}

@GetMapping("/delete")

public String delete(@PathVariable String id) throws Exception {

gatewayRouteService.delete(id);

gatewayServiceHandler.deleteRoute(id);

return "success";

}

}

7、自定义service层,增、删、改、查数据库路由配置信息

import java.util.Date;

import org.springframework.beans.BeanUtils;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import com.smc.gateway.dao.GatewayRouteMapper;

import com.smc.gateway.dto.GatewayRouteDto;

import com.smc.gateway.entity.GatewayRoute;

@Service

public class GatewayRouteService {

@Autowired

private GatewayRouteMapper gatewayRouteMapper;

public Integer add(GatewayRouteDto gatewayRouteDto) {

GatewayRoute gatewayRoute = new GatewayRoute();

BeanUtils.copyProperties(gatewayRouteDto, gatewayRoute);

gatewayRoute.setCreateDate(new Date());

gatewayRoute.setCreatorId("");

return gatewayRouteMapper.insertSelective(gatewayRoute);

}

public Integer update(GatewayRouteDto gatewayRouteDto) {

GatewayRoute gatewayRoute = new GatewayRoute();

BeanUtils.copyProperties(gatewayRouteDto, gatewayRoute);

gatewayRoute.setUpdateDate(new Date());

gatewayRoute.setUpdateId("");

return gatewayRouteMapper.updateByPrimaryKeySelective(gatewayRoute);

}

public Integer delete(String id) {

return gatewayRouteMapper.deleteByPrimaryKey(Long.parseLong(id));

}

}

8、前端参数dto

import lombok.AllArgsConstructor;

import lombok.Builder;

import lombok.Data;

import lombok.NoArgsConstructor;

@Data

@Builder

@NoArgsConstructor

@AllArgsConstructor

public class GatewayRouteDto {

private Long id;

private String serviceId;

private String uri;

private String predicates;

private String filters;

private String order;

private String remarks;

}

9、数据库实体

import java.util.Date;

import lombok.AllArgsConstructor;

import lombok.Builder;

import lombok.Data;

import lombok.NoArgsConstructor;

/**

* Created by Mybatis Generator on 2019/06/17

*/

@Data

@Builder

@NoArgsConstructor

@AllArgsConstructor

public class GatewayRoute {

private Long id;

private String serviceId;

private String uri;

private String predicates;

private String filters;

private String order;

private String creatorId;

private Date createDate;

private String updateId;

private Date updateDate;

private String remarks;

private String delFlag;

}

10、访问地址

查看路由配置信息  http://localhost:18080/actuator/gateway/routes

手动刷新路由配置信息  http://localhost:18080/route/refresh

1、mysql数据库表结构

22a7223a741e6450619130424f3b7416.png

2、pom.xml依赖

org.springframework.boot

spring-boot-starter-actuator

org.springframework.cloud

spring-cloud-starter-gateway

org.springframework.cloud

spring-cloud-gateway-webflux

org.springframework.boot

spring-boot-starter-data-redis

3、application.yml添加

#开启端点

management:

endpoints:

web:

exposure:

include: ‘*‘

security:

enabled: false

4、核心配置类,加载路由配置到redis,官网核心包从redis获取路由配置,提高效率

import com.alibaba.fastjson.JSON;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.cloud.gateway.route.RouteDefinition;

import org.springframework.cloud.gateway.route.RouteDefinitionRepository;

import org.springframework.cloud.gateway.support.NotFoundException;

import org.springframework.data.redis.core.RedisTemplate;

import org.springframework.stereotype.Component;

import reactor.core.publisher.Flux;

import reactor.core.publisher.Mono;

import java.util.ArrayList;

import java.util.List;

/**

*将定义好的路由表信息通过此类读写到redis中

*/

@Component

public class RedisRouteDefinitionRepository implements RouteDefinitionRepository {

public static final String GATEWAY_ROUTES = "gateway:routes";

@Autowired

private RedisTemplate redisTemplate;

//请注意,此方法很重要,从redis取路由信息的方法,官方核心包要用,核心路由功能都是从redis取的

@Override

public Flux getRouteDefinitions() {

List routeDefinitions = new ArrayList<>();

redisTemplate.opsForHash().values(GATEWAY_ROUTES).stream().forEach(routeDefinition -> {

routeDefinitions.add(JSON.parseObject(routeDefinition.toString(), RouteDefinition.class));

});

return Flux.fromIterable(routeDefinitions);

}

@Override

public Mono save(Mono route) {

return route

.flatMap(routeDefinition -> {

redisTemplate.opsForHash().put(GATEWAY_ROUTES, routeDefinition.getId(),

JSON.toJSONString(routeDefinition));

return Mono.empty();

});

}

@Override

public Mono delete(Mono routeId) {

return routeId.flatMap(id -> {

if (redisTemplate.opsForHash().hasKey(GATEWAY_ROUTES, id)) {

redisTemplate.opsForHash().delete(GATEWAY_ROUTES, id);

return Mono.empty();

}

return Mono.defer(() -> Mono.error(new NotFoundException("路由文件没有找到: " + routeId)));

});

}

}

5、核心配置类,项目初始化加载数据库的路由配置到redis

import java.net.URI;

import java.util.Arrays;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.CommandLineRunner;

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.context.ApplicationEventPublisher;

import org.springframework.context.ApplicationEventPublisherAware;

import org.springframework.stereotype.Service;

import org.springframework.web.util.UriComponentsBuilder;

import com.alibaba.fastjson.JSON;

import com.smc.gateway.dao.GatewayRouteMapper;

import com.smc.gateway.entity.GatewayRoute;

import com.smc.gateway.repository.RedisRouteDefinitionRepository;

import lombok.extern.slf4j.Slf4j;

import reactor.core.publisher.Mono;

@Slf4j

@Service

public class GatewayServiceHandler implements ApplicationEventPublisherAware, CommandLineRunner{

@Autowired

private RedisRouteDefinitionRepository routeDefinitionWriter;

private ApplicationEventPublisher publisher;

@Override

public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher){

this.publisher = applicationEventPublisher;

}

//自己的获取数据dao

@Autowired

private GatewayRouteMapper gatewayRouteMapper;

@Override

public void run(String... args){

this.loadRouteConfig();

}

public String loadRouteConfig(){

log.info("====开始加载=====网关配置信息=========");

//删除redis里面的路由配置信息

redisTemplate.delete(RedisRouteDefinitionRepository.GATEWAY_ROUTES);

//从数据库拿到基本路由配置

List gatewayRouteList = gatewayRouteMapper.queryAllRoutes();

gatewayRouteList.forEach(gatewayRoute -> {

RouteDefinition definition=handleData(gatewayRoute);

routeDefinitionWriter.save(Mono.just(definition)).subscribe();

});

this.publisher.publishEvent(new RefreshRoutesEvent(this));

log.info("=======网关配置信息===加载完成======");

return "success";

}

public void saveRoute(GatewayRoute gatewayRoute){

RouteDefinition definition=handleData(gatewayRoute);

routeDefinitionWriter.save(Mono.just(definition)).subscribe();

this.publisher.publishEvent(new RefreshRoutesEvent(this));

}

public void update(GatewayRoute gatewayRoute){

RouteDefinition definition=handleData(gatewayRoute);

try {

this.routeDefinitionWriter.delete(Mono.just(definition.getId()));

routeDefinitionWriter.save(Mono.just(definition)).subscribe();

this.publisher.publishEvent(new RefreshRoutesEvent(this));

} catch (Exception e) {

e.printStackTrace();

}

}

public void deleteRoute(String routeId){

routeDefinitionWriter.delete(Mono.just(routeId)).subscribe();

this.publisher.publishEvent(new RefreshRoutesEvent(this));

}

/**

* 路由数据转换公共方法

* @param gatewayRoute

* @return

*/

private RouteDefinition handleData(GatewayRoute gatewayRoute){

RouteDefinition definition = new RouteDefinition();

Map predicateParams = new HashMap<>(8);

PredicateDefinition predicate = new PredicateDefinition();

FilterDefinition filterDefinition = new FilterDefinition();

Map filterParams = new HashMap<>(8);

URI uri = null;

if(gatewayRoute.getUri().startsWith("http")){

//http地址

uri = UriComponentsBuilder.fromHttpUrl(gatewayRoute.getUri()).build().toUri();

}else{

//注册中心

uri = UriComponentsBuilder.fromUriString("lb://"+gatewayRoute.getUri()).build().toUri();

}

definition.setId(gatewayRoute.getServiceId());

// 名称是固定的,spring gateway会根据名称找对应的PredicateFactory

predicate.setName("Path");

predicateParams.put("pattern",gatewayRoute.getPredicates());

predicate.setArgs(predicateParams);

// 名称是固定的, 路径去前缀

filterDefinition.setName("StripPrefix");

filterParams.put("_genkey_0", gatewayRoute.getFilters().toString());

filterDefinition.setArgs(filterParams);

definition.setPredicates(Arrays.asList(predicate));

definition.setFilters(Arrays.asList(filterDefinition));

definition.setUri(uri);

definition.setOrder(Integer.parseInt(gatewayRoute.getGOrder()));

return definition;

}

}

6、自定义controller层;

直接在数据库添加路由配置信息;

前端页面增、删、改路由配置信息,并刷新redis使配置信息立即生效;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.PostMapping;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import org.springframework.beans.BeanUtils;

import com.smc.gateway.dto.GatewayRouteDto;

import com.smc.gateway.route.GatewayRouteService;

import com.smc.gateway.route.GatewayServiceHandler;

@RestController

@RequestMapping("/route")

public class RouteController{

@Autowired

private GatewayServiceHandler gatewayServiceHandler;

@Autowired

private GatewayRouteService gatewayRouteService;

/**

* 刷新路由配置

*

* @param gwdefinition

* @return

*/

@GetMapping("/refresh")

public String refresh() throws Exception {

return this.gatewayServiceHandler.loadRouteConfig();

}

/**

* 增加路由记录

*

* @param gwdefinition

* @return

*/

@PostMapping("/add")

public String add(@RequestBody GatewayRouteDto gatewayRouteDto) throws Exception {

gatewayRouteService.add(gatewayRouteDto);

GatewayRoute gatewayRoute=new GatewayRoute();

BeanUtils.copyProperties(gatewayRouteDto, gatewayRoute);

gatewayServiceHandler.saveRoute(gatewayRoute);

return "success";

}

@PostMapping("/update")

public String update(@RequestBody GatewayRouteDto gatewayRouteDto) throws Exception {

gatewayRouteService.update(gatewayRouteDto);

GatewayRoute gatewayRoute=new GatewayRoute();

BeanUtils.copyProperties(gatewayRouteDto, gatewayRoute);

gatewayServiceHandler.update(gatewayRoute);

return "success";

}

@GetMapping("/delete")

public String delete(@PathVariable String id) throws Exception {

gatewayRouteService.delete(id);

gatewayServiceHandler.deleteRoute(id);

return "success";

}

}

7、自定义service层,增、删、改、查数据库路由配置信息

import java.util.Date;

import org.springframework.beans.BeanUtils;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import com.smc.gateway.dao.GatewayRouteMapper;

import com.smc.gateway.dto.GatewayRouteDto;

import com.smc.gateway.entity.GatewayRoute;

@Service

public class GatewayRouteService {

@Autowired

private GatewayRouteMapper gatewayRouteMapper;

public Integer add(GatewayRouteDto gatewayRouteDto) {

GatewayRoute gatewayRoute = new GatewayRoute();

BeanUtils.copyProperties(gatewayRouteDto, gatewayRoute);

gatewayRoute.setCreateDate(new Date());

gatewayRoute.setCreatorId("");

return gatewayRouteMapper.insertSelective(gatewayRoute);

}

public Integer update(GatewayRouteDto gatewayRouteDto) {

GatewayRoute gatewayRoute = new GatewayRoute();

BeanUtils.copyProperties(gatewayRouteDto, gatewayRoute);

gatewayRoute.setUpdateDate(new Date());

gatewayRoute.setUpdateId("");

return gatewayRouteMapper.updateByPrimaryKeySelective(gatewayRoute);

}

public Integer delete(String id) {

return gatewayRouteMapper.deleteByPrimaryKey(Long.parseLong(id));

}

}

8、前端参数dto

import lombok.AllArgsConstructor;

import lombok.Builder;

import lombok.Data;

import lombok.NoArgsConstructor;

@Data

@Builder

@NoArgsConstructor

@AllArgsConstructor

public class GatewayRouteDto {

private Long id;

private String serviceId;

private String uri;

private String predicates;

private String filters;

private String order;

private String remarks;

}

9、数据库实体

import java.util.Date;

import lombok.AllArgsConstructor;

import lombok.Builder;

import lombok.Data;

import lombok.NoArgsConstructor;

/**

* Created by Mybatis Generator on 2019/06/17

*/

@Data

@Builder

@NoArgsConstructor

@AllArgsConstructor

public class GatewayRoute {

private Long id;

private String serviceId;

private String uri;

private String predicates;

private String filters;

private String order;

private String creatorId;

private Date createDate;

private String updateId;

private Date updateDate;

private String remarks;

private String delFlag;

}

10、访问地址

查看路由配置信息  http://localhost:18080/actuator/gateway/routes

手动刷新路由配置信息  http://localhost:18080/route/refresh

转自:https://blog.csdn.net/qq_42714869/article/details/92794911

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值