1、mysql数据库表结构
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