parent
7d22c92122
commit
f94009e2c4
@ -0,0 +1,22 @@ |
|||||||
|
package com.gitee.sop.bookweb.config; |
||||||
|
|
||||||
|
import com.gitee.sop.servercommon.configuration.AlipayServiceConfiguration; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
|
||||||
|
/** |
||||||
|
* 使用支付宝开放平台功能 |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
@Configuration |
||||||
|
public class OpenServiceConfig extends AlipayServiceConfiguration { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 使用淘宝开放平台功能 |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
//@Configuration
|
||||||
|
//public class OpenServiceConfig extends TaobaoServiceConfiguration {
|
||||||
|
//
|
||||||
|
//}
|
@ -0,0 +1,40 @@ |
|||||||
|
package com.gitee.sop.bookweb.controller; |
||||||
|
|
||||||
|
import com.gitee.sop.bookweb.consumer.StoryServiceConsumer; |
||||||
|
import com.gitee.sop.servercommon.annotation.ApiMapping; |
||||||
|
import com.gitee.sop.story.api.domain.Story; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.web.bind.annotation.RestController; |
||||||
|
|
||||||
|
import java.util.Arrays; |
||||||
|
|
||||||
|
/** |
||||||
|
* 支付宝服务端,假设签名验证通过后,到达这里进行具体的业务处理。 |
||||||
|
* 这里演示如何接受业务参数。 |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
@RestController |
||||||
|
public class AlipayBookController { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
StoryServiceConsumer storyServiceConsumer; |
||||||
|
|
||||||
|
@ApiMapping(value = "alipay.book.get") |
||||||
|
public Story getBook() { |
||||||
|
Story story = new Story(); |
||||||
|
story.setId(1); |
||||||
|
story.setName("白雪公主(alipay.book.get)"); |
||||||
|
return story; |
||||||
|
} |
||||||
|
|
||||||
|
// 调用story服务
|
||||||
|
@ApiMapping(value = "alipay.book.story.get") |
||||||
|
public Object getBook2() { |
||||||
|
Story story = new Story(); |
||||||
|
story.setId(1); |
||||||
|
story.setName("白雪公主(alipay.book.story.get)"); |
||||||
|
Story story2 = storyServiceConsumer.getStory(1); |
||||||
|
return Arrays.asList(story, story2); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,6 +0,0 @@ |
|||||||
server.port=3333 |
|
||||||
spring.application.name=book-service |
|
||||||
eureka.host=localhost |
|
||||||
eureka.port=1111 |
|
||||||
eureka.client.serviceUrl.defaultZone=http://${eureka.host}:${eureka.port}/eureka/ |
|
||||||
|
|
@ -0,0 +1,9 @@ |
|||||||
|
server: |
||||||
|
port: 3333 |
||||||
|
|
||||||
|
eureka: |
||||||
|
port: 1111 |
||||||
|
host: localhost |
||||||
|
client: |
||||||
|
serviceUrl: |
||||||
|
defaultZone: http://${eureka.host}:${eureka.port}/eureka/ |
@ -0,0 +1,7 @@ |
|||||||
|
spring: |
||||||
|
application: |
||||||
|
name: book-service |
||||||
|
|
||||||
|
cloud: |
||||||
|
zookeeper: |
||||||
|
connect-string: localhost:2181 |
@ -0,0 +1,38 @@ |
|||||||
|
package com.gitee.sop.gatewaycommon.bean; |
||||||
|
|
||||||
|
import java.util.Collections; |
||||||
|
import java.util.HashSet; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Set; |
||||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||||
|
import java.util.function.Consumer; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
public abstract class ServiceRouteRepository<R, E> { |
||||||
|
/** |
||||||
|
* key:serviceId |
||||||
|
*/ |
||||||
|
private Map<String, Set<E>> serviceRouteMap = new ConcurrentHashMap<>(); |
||||||
|
|
||||||
|
public abstract String getServiceId(R r); |
||||||
|
|
||||||
|
public void saveRouteDefinition(R serviceRouteInfo, E definition) { |
||||||
|
String serverId = getServiceId(serviceRouteInfo); |
||||||
|
Set<E> routeDefinitionSet = serviceRouteMap.putIfAbsent(serverId, new HashSet<>(16)); |
||||||
|
if (routeDefinitionSet == null) { |
||||||
|
routeDefinitionSet = serviceRouteMap.get(serverId); |
||||||
|
} |
||||||
|
routeDefinitionSet.add(definition); |
||||||
|
} |
||||||
|
|
||||||
|
public synchronized void deleteAll(R serviceRouteInfo, Consumer<E> consumer) { |
||||||
|
String serverId = getServiceId(serviceRouteInfo); |
||||||
|
Set<E> definitionSet = serviceRouteMap.getOrDefault(serverId, Collections.emptySet()); |
||||||
|
for (E routeDefinition : definitionSet) { |
||||||
|
consumer.accept(routeDefinition); |
||||||
|
} |
||||||
|
definitionSet.clear(); |
||||||
|
} |
||||||
|
} |
@ -1,74 +1,123 @@ |
|||||||
package com.gitee.sop.gatewaycommon.gateway.route; |
package com.gitee.sop.gatewaycommon.gateway.route; |
||||||
|
|
||||||
|
import com.gitee.sop.gatewaycommon.bean.ServiceRouteRepository; |
||||||
import com.gitee.sop.gatewaycommon.manager.RouteRepository; |
import com.gitee.sop.gatewaycommon.manager.RouteRepository; |
||||||
import lombok.extern.slf4j.Slf4j; |
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.beans.BeansException; |
||||||
|
import org.springframework.beans.factory.BeanFactory; |
||||||
|
import org.springframework.beans.factory.BeanFactoryAware; |
||||||
import org.springframework.beans.factory.annotation.Autowired; |
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.cloud.gateway.event.PredicateArgsEvent; |
||||||
import org.springframework.cloud.gateway.event.RefreshRoutesEvent; |
import org.springframework.cloud.gateway.event.RefreshRoutesEvent; |
||||||
|
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition; |
||||||
|
import org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory; |
||||||
|
import org.springframework.cloud.gateway.route.InMemoryRouteDefinitionRepository; |
||||||
import org.springframework.cloud.gateway.route.RouteDefinition; |
import org.springframework.cloud.gateway.route.RouteDefinition; |
||||||
import org.springframework.cloud.gateway.route.RouteDefinitionRepository; |
import org.springframework.cloud.gateway.support.ConfigurationUtils; |
||||||
import org.springframework.cloud.gateway.support.NotFoundException; |
|
||||||
import org.springframework.context.ApplicationEventPublisher; |
import org.springframework.context.ApplicationEventPublisher; |
||||||
import org.springframework.context.ApplicationEventPublisherAware; |
import org.springframework.context.ApplicationEventPublisherAware; |
||||||
import org.springframework.http.ResponseEntity; |
import org.springframework.core.convert.ConversionService; |
||||||
|
import org.springframework.expression.spel.standard.SpelExpressionParser; |
||||||
|
import org.springframework.validation.Validator; |
||||||
import reactor.core.publisher.Mono; |
import reactor.core.publisher.Mono; |
||||||
|
|
||||||
|
import java.util.Collections; |
||||||
|
import java.util.HashSet; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Set; |
||||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||||
|
|
||||||
/** |
/** |
||||||
* 动态更新路由 |
* 路由存储管理,负责动态更新路由 |
||||||
|
* |
||||||
* @author thc |
* @author thc |
||||||
*/ |
*/ |
||||||
@Slf4j |
@Slf4j |
||||||
public class GatewayRouteRepository implements ApplicationEventPublisherAware, RouteRepository<RouteDefinition> { |
public class GatewayRouteRepository extends InMemoryRouteDefinitionRepository |
||||||
|
implements ApplicationEventPublisherAware, |
||||||
|
BeanFactoryAware, |
||||||
|
RouteRepository<GatewayServiceRouteInfo, RouteDefinition> { |
||||||
|
|
||||||
|
private final SpelExpressionParser parser = new SpelExpressionParser(); |
||||||
|
|
||||||
|
private ServiceRouteRepository<GatewayServiceRouteInfo, RouteDefinition> serviceRouteRepository = new ServiceRouteRepository<GatewayServiceRouteInfo, RouteDefinition>() { |
||||||
|
@Override |
||||||
|
public String getServiceId(GatewayServiceRouteInfo serviceRouteInfo) { |
||||||
|
return serviceRouteInfo.getAppName(); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ConversionService conversionService; |
||||||
|
|
||||||
@Autowired |
@Autowired |
||||||
private RouteDefinitionRepository routeDefinitionRepository; |
private Validator validator; |
||||||
|
|
||||||
private ApplicationEventPublisher publisher; |
private ApplicationEventPublisher publisher; |
||||||
|
|
||||||
/** 根据ID获取路由 */ |
private BeanFactory beanFactory; |
||||||
|
|
||||||
|
/** |
||||||
|
* 根据ID获取路由 |
||||||
|
*/ |
||||||
@Override |
@Override |
||||||
public RouteDefinition get(String id) { |
public RouteDefinition get(String id) { |
||||||
return routeDefinitionRepository.getRouteDefinitions() |
return getRouteDefinitions() |
||||||
.filter(routeDefinition -> { |
.filter(routeDefinition -> { |
||||||
return routeDefinition.getId().equals(id); |
return routeDefinition.getId().equals(id); |
||||||
}).blockFirst(); |
}).blockFirst(); |
||||||
} |
} |
||||||
|
|
||||||
/** 增加路由 */ |
/** |
||||||
|
* 增加路由 |
||||||
|
*/ |
||||||
@Override |
@Override |
||||||
public String add(RouteDefinition definition) { |
public String add(GatewayServiceRouteInfo serviceRouteInfo, RouteDefinition definition) { |
||||||
routeDefinitionRepository.save(Mono.just(definition)).subscribe(); |
super.save(Mono.just(definition)).subscribe(); |
||||||
|
serviceRouteRepository.saveRouteDefinition(serviceRouteInfo, definition); |
||||||
|
this.initPredicateDefinition(definition); |
||||||
this.publisher.publishEvent(new RefreshRoutesEvent(this)); |
this.publisher.publishEvent(new RefreshRoutesEvent(this)); |
||||||
return "success"; |
return "success"; |
||||||
} |
} |
||||||
|
|
||||||
/** 更新路由 */ |
protected void initPredicateDefinition(RouteDefinition definition) { |
||||||
@Override |
for (PredicateDefinition predicate : definition.getPredicates()) { |
||||||
public String update(RouteDefinition definition) { |
Map<String, String> args = predicate.getArgs(); |
||||||
log.info("更新route,id:{}", definition.getId()); |
if (!args.isEmpty()) { |
||||||
try { |
RoutePredicateFactory<NameVersionRoutePredicateFactory.Config> factory = new NameVersionRoutePredicateFactory(); |
||||||
this.routeDefinitionRepository.delete(Mono.just(definition.getId())); |
Map<String, Object> properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory); |
||||||
} catch (Exception e) { |
Object config = factory.newConfig(); |
||||||
return "update fail,not find route routeId: " + definition.getId(); |
ConfigurationUtils.bind(config, properties, factory.shortcutFieldPrefix(), predicate.getName(), |
||||||
|
validator, conversionService); |
||||||
|
this.publisher.publishEvent(new PredicateArgsEvent(this, definition.getId(), properties)); |
||||||
} |
} |
||||||
try { |
|
||||||
routeDefinitionRepository.save(Mono.just(definition)).subscribe(); |
|
||||||
this.publisher.publishEvent(new RefreshRoutesEvent(this)); |
|
||||||
return "success"; |
|
||||||
} catch (Exception e) { |
|
||||||
return "update route fail"; |
|
||||||
} |
} |
||||||
|
|
||||||
} |
} |
||||||
|
|
||||||
/** 删除路由 */ |
/** |
||||||
|
* 删除路由 |
||||||
|
*/ |
||||||
@Override |
@Override |
||||||
public void delete(String id) { |
public void delete(String id) { |
||||||
this.routeDefinitionRepository.delete(Mono.just(id)) |
super.delete(Mono.just(id)); |
||||||
.then(Mono.defer(() -> Mono.just(ResponseEntity.ok().build()))) |
this.publisher.publishEvent(new PredicateArgsEvent(this, id, Collections.emptyMap())); |
||||||
.onErrorResume(t -> t instanceof NotFoundException, t -> Mono.just(ResponseEntity.notFound().build())); |
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void deleteAll(GatewayServiceRouteInfo serviceRouteInfo) { |
||||||
|
serviceRouteRepository.deleteAll(serviceRouteInfo, routeDefinition -> { |
||||||
|
this.delete(routeDefinition.getId()); |
||||||
|
}); |
||||||
} |
} |
||||||
|
|
||||||
@Override |
@Override |
||||||
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { |
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { |
||||||
this.publisher = applicationEventPublisher; |
this.publisher = applicationEventPublisher; |
||||||
} |
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setBeanFactory(BeanFactory beanFactory) throws BeansException { |
||||||
|
this.beanFactory = beanFactory; |
||||||
|
} |
||||||
} |
} |
@ -0,0 +1,23 @@ |
|||||||
|
package com.gitee.sop.gatewaycommon.util; |
||||||
|
|
||||||
|
import org.springframework.cloud.gateway.route.Route; |
||||||
|
|
||||||
|
import java.net.URI; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
public class RoutePathUtil { |
||||||
|
|
||||||
|
public static final String REGEX = "\\#"; |
||||||
|
|
||||||
|
public static String findPath(String uri) { |
||||||
|
// #后面是对应的path
|
||||||
|
String[] uriArr = uri.split(REGEX); |
||||||
|
if (uriArr.length == 2) { |
||||||
|
return uriArr[1]; |
||||||
|
} else { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1,41 +0,0 @@ |
|||||||
package com.gitee.sop.gatewaycommon.zuul.filter; |
|
||||||
|
|
||||||
import com.gitee.sop.gatewaycommon.message.ErrorEnum; |
|
||||||
import com.netflix.zuul.context.RequestContext; |
|
||||||
import com.netflix.zuul.exception.ZuulException; |
|
||||||
import org.apache.commons.lang.StringUtils; |
|
||||||
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; |
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author tanghc |
|
||||||
*/ |
|
||||||
public class PreTokenFilter extends BaseZuulFilter { |
|
||||||
|
|
||||||
@Override |
|
||||||
protected FilterType getFilterType() { |
|
||||||
return FilterType.PRE; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected int getFilterOrder() { |
|
||||||
return FilterConstants.PRE_DECORATION_FILTER_ORDER + 1; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected Object doRun(RequestContext ctx) throws ZuulException { |
|
||||||
Object serviceId = ctx.get(FilterConstants.SERVICE_ID_KEY); |
|
||||||
log.info("serviceId:{}", serviceId); |
|
||||||
HttpServletRequest request = ctx.getRequest(); |
|
||||||
|
|
||||||
log.info("send {} request to {}", request.getMethod(), request.getRequestURL().toString()); |
|
||||||
|
|
||||||
String accessToken = request.getParameter("access_token"); |
|
||||||
if (StringUtils.isBlank(accessToken)) { |
|
||||||
throw ErrorEnum.AOP_INVALID_APP_AUTH_TOKEN.getErrorMeta().getException(); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,45 @@ |
|||||||
|
package com.gitee.sop.gateway.config; |
||||||
|
|
||||||
|
import com.gitee.sop.gatewaycommon.bean.ApiContext; |
||||||
|
import com.gitee.sop.gatewaycommon.zuul.configuration.AlipayZuulConfiguration; |
||||||
|
import com.gitee.sop.gatewaycommon.zuul.configuration.TaobaoZuulConfiguration; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
|
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* 使用Spring Cloud Zuul,推荐使用 |
||||||
|
* |
||||||
|
* 注意:下面两个只能使用一个 |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* 开通支付宝开放平台能力 |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
@Configuration |
||||||
|
public class ZuulConfig extends AlipayZuulConfiguration { |
||||||
|
|
||||||
|
{ |
||||||
|
Map<String, String> appSecretStore = new HashMap(); |
||||||
|
appSecretStore.put("alipay_test", "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlyb9aUBaljQP/vjmBFe1mF8HsWSvyfC2NTlpT/V9E+sBxTr8TSkbzJCeeeOEm4LCaVXL0Qz63MZoT24v7AIXTuMdj4jyiM/WJ4tjrWAgnmohNOegfntTto16C3l234vXz4ryWZMR/7W+MXy5B92wPGQEJ0LKFwNEoLspDEWZ7RdE53VH7w6y6sIZUfK+YkXWSwehfKPKlx+lDw3zRJ3/yvMF+U+BAdW/MfECe1GuBnCFKnlMRh3UKczWyXWkL6ItOpYHHJi/jx85op5BWDje2pY9QowzfN94+0DB3T7UvZeweu3zlP6diwAJDzLaFQX8ULfWhY+wfKxIRgs9NoiSAQIDAQAB"); |
||||||
|
ApiContext.getApiConfig().addAppSecret(appSecretStore); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 开通支付宝开放平台能力 |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
//@Configuration
|
||||||
|
//public class ZuulConfig extends TaobaoZuulConfiguration {
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// Map<String, String> appSecretStore = new HashMap();
|
||||||
|
// appSecretStore.put("taobao_test", "G9w0BAQEFAAOCAQ8AMIIBCgKCA");
|
||||||
|
// ApiContext.getApiConfig().addAppSecret(appSecretStore);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
@ -1,7 +0,0 @@ |
|||||||
server.port=2222 |
|
||||||
spring.application.name=story-service |
|
||||||
|
|
||||||
eureka.host=localhost |
|
||||||
eureka.port=1111 |
|
||||||
eureka.client.serviceUrl.defaultZone=http://${eureka.host}:${eureka.port}/eureka/ |
|
||||||
|
|
@ -0,0 +1,9 @@ |
|||||||
|
server: |
||||||
|
port: 2222 |
||||||
|
|
||||||
|
eureka: |
||||||
|
port: 1111 |
||||||
|
host: localhost |
||||||
|
client: |
||||||
|
serviceUrl: |
||||||
|
defaultZone: http://${eureka.host}:${eureka.port}/eureka/ |
Loading…
Reference in new issue