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; | 
				
			||||
 | 
				
			||||
import com.gitee.sop.gatewaycommon.bean.ServiceRouteRepository; | 
				
			||||
import com.gitee.sop.gatewaycommon.manager.RouteRepository; | 
				
			||||
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.cloud.gateway.event.PredicateArgsEvent; | 
				
			||||
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.RouteDefinitionRepository; | 
				
			||||
import org.springframework.cloud.gateway.support.NotFoundException; | 
				
			||||
import org.springframework.cloud.gateway.support.ConfigurationUtils; | 
				
			||||
import org.springframework.context.ApplicationEventPublisher; | 
				
			||||
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 java.util.Collections; | 
				
			||||
import java.util.HashSet; | 
				
			||||
import java.util.Map; | 
				
			||||
import java.util.Set; | 
				
			||||
import java.util.concurrent.ConcurrentHashMap; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * 动态更新路由 | 
				
			||||
 * 路由存储管理,负责动态更新路由 | 
				
			||||
 * | 
				
			||||
 * @author thc | 
				
			||||
 */ | 
				
			||||
@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 | 
				
			||||
    private RouteDefinitionRepository routeDefinitionRepository; | 
				
			||||
    private Validator validator; | 
				
			||||
 | 
				
			||||
    private ApplicationEventPublisher publisher; | 
				
			||||
 | 
				
			||||
    /** 根据ID获取路由 */ | 
				
			||||
    private BeanFactory beanFactory; | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * 根据ID获取路由 | 
				
			||||
     */ | 
				
			||||
    @Override | 
				
			||||
    public RouteDefinition get(String id) { | 
				
			||||
        return routeDefinitionRepository.getRouteDefinitions() | 
				
			||||
        return getRouteDefinitions() | 
				
			||||
                .filter(routeDefinition -> { | 
				
			||||
                    return routeDefinition.getId().equals(id); | 
				
			||||
                }).blockFirst(); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** 增加路由 */ | 
				
			||||
    /** | 
				
			||||
     * 增加路由 | 
				
			||||
     */ | 
				
			||||
    @Override | 
				
			||||
    public String add(RouteDefinition definition) { | 
				
			||||
        routeDefinitionRepository.save(Mono.just(definition)).subscribe(); | 
				
			||||
    public String add(GatewayServiceRouteInfo serviceRouteInfo, RouteDefinition definition) { | 
				
			||||
        super.save(Mono.just(definition)).subscribe(); | 
				
			||||
        serviceRouteRepository.saveRouteDefinition(serviceRouteInfo, definition); | 
				
			||||
        this.initPredicateDefinition(definition); | 
				
			||||
        this.publisher.publishEvent(new RefreshRoutesEvent(this)); | 
				
			||||
        return "success"; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** 更新路由 */ | 
				
			||||
    @Override | 
				
			||||
    public String update(RouteDefinition definition) { | 
				
			||||
        log.info("更新route,id:{}", definition.getId()); | 
				
			||||
        try { | 
				
			||||
            this.routeDefinitionRepository.delete(Mono.just(definition.getId())); | 
				
			||||
        } catch (Exception e) { | 
				
			||||
            return "update fail,not find route  routeId: " + definition.getId(); | 
				
			||||
    protected void initPredicateDefinition(RouteDefinition definition) { | 
				
			||||
        for (PredicateDefinition predicate : definition.getPredicates()) { | 
				
			||||
            Map<String, String> args = predicate.getArgs(); | 
				
			||||
            if (!args.isEmpty()) { | 
				
			||||
                RoutePredicateFactory<NameVersionRoutePredicateFactory.Config> factory = new NameVersionRoutePredicateFactory(); | 
				
			||||
                Map<String, Object> properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory); | 
				
			||||
                Object config = factory.newConfig(); | 
				
			||||
                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 | 
				
			||||
    public void delete(String id) { | 
				
			||||
        this.routeDefinitionRepository.delete(Mono.just(id)) | 
				
			||||
                .then(Mono.defer(() -> Mono.just(ResponseEntity.ok().build()))) | 
				
			||||
                .onErrorResume(t -> t instanceof NotFoundException, t -> Mono.just(ResponseEntity.notFound().build())); | 
				
			||||
        super.delete(Mono.just(id)); | 
				
			||||
        this.publisher.publishEvent(new PredicateArgsEvent(this, id, Collections.emptyMap())); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    @Override | 
				
			||||
    public void deleteAll(GatewayServiceRouteInfo serviceRouteInfo) { | 
				
			||||
        serviceRouteRepository.deleteAll(serviceRouteInfo, routeDefinition -> { | 
				
			||||
            this.delete(routeDefinition.getId()); | 
				
			||||
        }); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    @Override | 
				
			||||
    public void setApplicationEventPublisher(ApplicationEventPublisher 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