Merge appactive module into main branch of 2.2.x. (#2758)
* feature: initial appactive module * feature:appactive core logic * feature:add appactive relevant examples * fix: add appactive module in pom.xml * fix: Reformat code * feature: add AppactivePredicate * refactor: delete duplicate codes and reformat them * feature: using PredicateBasedRule default filter logic * feature: deleted useless filed in AppactiveRule * refactor: polish the code * feat(appactive):doc init * refactor: add rules and polish codes * refactor: modified package name * refactor: delete useless files * feature: add readme-zh.md * refactor: polish readme docs * fix: fix appactive docs error * refactor: polish code and docs * refactor: adjust service type name * refactor: delete useless files Co-authored-by: 就砺 <jiuli.qk@alibaba-inc.com>pull/2765/head
@ -0,0 +1,88 @@
|
||||
# sh baseline.sh 2 or sh baseline.sh 2 NACOS appactiveDemoNamespaceId
|
||||
# sh baseline.sh 3
|
||||
|
||||
type=$1
|
||||
channel=$2
|
||||
tenant=$3
|
||||
if [ ! -n "$channel" ] ;then
|
||||
channel="FILE"
|
||||
fi
|
||||
echo "channel: ${channel}"
|
||||
|
||||
|
||||
if [ `expr $type % 2` == 0 ]
|
||||
then
|
||||
if [ $channel = "FILE" ]
|
||||
then
|
||||
for file in $(ls ../data/); do
|
||||
if [[ "$file" == *"path-address"* ]]; then
|
||||
echo "continue"
|
||||
continue
|
||||
fi
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") 应用 ${file} 基线推送中";
|
||||
cp -f ./rule/idSource.json "../data/$file/"
|
||||
cp -f ./rule/transformerBetween.json "../data/$file/idTransformer.json"
|
||||
cp -f ./rule/idUnitMapping.json "../data/$file/"
|
||||
cp -f ./rule/dbProperty.json "../data/$file/mysql-product"
|
||||
arr=(${file//-/ })
|
||||
unitFlag=${arr[1]}
|
||||
echo "{\"unitFlag\":\"${unitFlag}\"}" > "../data/$file/machine.json"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") 应用 ${file} 基线推送完成"
|
||||
done
|
||||
elif [ $channel = "NACOS" ]
|
||||
then
|
||||
dataIdPrefix="appactive.dataId."
|
||||
groupId="appactive.groupId"
|
||||
|
||||
idSourceRule=$(cat ./rule/idSource.json)
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") idSourceRule 推送结果: " \
|
||||
&& curl -X POST "127.0.0.1:8848/nacos/v1/cs/configs" \
|
||||
-d "tenant=${tenant}&dataId=${dataIdPrefix}idSourceRulePath&group=${groupId}&content=${idSourceRule}" \
|
||||
&& echo ""
|
||||
|
||||
idTransformerRule=$(cat ./rule/transformerBetween.json)
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") idTransformerRule 推送结果: " \
|
||||
&& curl -X POST "127.0.0.1:8848/nacos/v1/cs/configs" \
|
||||
-d "tenant=${tenant}&dataId=${dataIdPrefix}transformerRulePath&group=${groupId}&content=${idTransformerRule}" \
|
||||
&& echo ""
|
||||
|
||||
idUnitMappingRule=$(cat ./rule/idUnitMapping.json)
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") idUnitMappingRule 推送结果: " \
|
||||
&& curl -X POST "127.0.0.1:8848/nacos/v1/cs/configs" \
|
||||
-d "tenant=${tenant}&dataId=${dataIdPrefix}trafficRouteRulePath&group=${groupId}&content=${idUnitMappingRule}" \
|
||||
&& echo ""
|
||||
|
||||
forbiddenRule=$(cat ./rule/forbiddenRuleEmpty.json)
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") forbiddenRule 推送结果: " \
|
||||
&& curl -X POST "127.0.0.1:8848/nacos/v1/cs/configs" \
|
||||
-d "tenant=${tenant}&dataId=${dataIdPrefix}forbiddenRulePath&group=${groupId}&content=${forbiddenRule}" \
|
||||
&& echo ""
|
||||
|
||||
dataScopeRule=$(cat ./rule/dbProperty.json)
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") dataScopeRule 推送结果: " \
|
||||
&& curl -X POST "127.0.0.1:8848/nacos/v1/cs/configs" \
|
||||
-d "tenant=${tenant}&dataId=${dataIdPrefix}dataScopeRuleDirectoryPath_mysql-product&group=${groupId}&content=${dataScopeRule}" \
|
||||
&& echo ""
|
||||
else
|
||||
echo "unsupported channel: ${channel}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ `expr $type % 3` == 0 ]
|
||||
then
|
||||
idSource=$(cat ./rule/idSource.json)
|
||||
idTransformer=$(cat ./rule/idTransformer.json)
|
||||
idUnitMapping=$(cat ./rule/idUnitMapping.json)
|
||||
|
||||
gatewayRule="{\"idSource\" : $idSource, \"idTransformer\" : $idTransformer, \"idUnitMapping\" : $idUnitMapping}"
|
||||
data="{\"key\" : \"459236fc-ed71-4bc4-b46c-69fc60d31f18_test1122\", \"value\" : $gatewayRule}"
|
||||
echo $data
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") gateway 基线推送结果: " && curl --header "Content-Type: application/json" \
|
||||
--request POST \
|
||||
--data "$data" \
|
||||
127.0.0.1:8090/set
|
||||
fi
|
||||
|
||||
|
||||
|
@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>appactive-example-common</artifactId>
|
||||
<name>Spring Cloud Starter Alibaba Appactive Example - Common Service</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>5.3.18</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<version>5.1.0.Final</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.msha</groupId>
|
||||
<artifactId>client-spi-metainfo</artifactId>
|
||||
<version>0.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-appactive</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2013-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.common;
|
||||
|
||||
/**
|
||||
* @author ChengPu raozihao
|
||||
* @description
|
||||
* @date 2022/8/15
|
||||
*/
|
||||
public final class Constants {
|
||||
|
||||
/**
|
||||
* center flag.
|
||||
*/
|
||||
public static final String CENTER_FLAG = "center";
|
||||
|
||||
private Constants() {
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.common;
|
||||
|
||||
/**
|
||||
* @author raozihao, mageekchiu
|
||||
* @author <a href="mailto:zihaorao@gmail.com">Steve</a>
|
||||
*/
|
||||
public enum RPCType {
|
||||
|
||||
/**
|
||||
* Spring Cloud.
|
||||
*/
|
||||
SpringCloud
|
||||
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.common.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
/**
|
||||
* @author ChengPu raozihao
|
||||
* @description
|
||||
* @date 2022/8/15
|
||||
*/
|
||||
@Entity
|
||||
public class Product implements Serializable {
|
||||
|
||||
@Id
|
||||
@Column(nullable = false, columnDefinition = "char(100)")
|
||||
private String id;
|
||||
|
||||
@Column(nullable = false, columnDefinition = "char(100)")
|
||||
private String name;
|
||||
|
||||
@Column(nullable = false, columnDefinition = "char(100)")
|
||||
private String img;
|
||||
|
||||
@Column(nullable = false, columnDefinition = "varchar(2000)")
|
||||
private String description;
|
||||
|
||||
private int price;
|
||||
|
||||
private int number;
|
||||
|
||||
public Product() {
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getImg() {
|
||||
return img;
|
||||
}
|
||||
|
||||
public void setImg(String img) {
|
||||
this.img = img;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public int getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public void setPrice(int price) {
|
||||
this.price = price;
|
||||
}
|
||||
|
||||
public int getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public void setNumber(int number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Product{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", img='"
|
||||
+ img + '\'' + ", description='" + description + '\'' + ", price=" + price
|
||||
+ ", number=" + number + '}';
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.common.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ResultHolder<T> implements Serializable {
|
||||
|
||||
List<Node> chain = new ArrayList<>();
|
||||
|
||||
private T result;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public ResultHolder() {
|
||||
|
||||
}
|
||||
|
||||
public ResultHolder(T result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public T getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(T result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public List<Node> getChain() {
|
||||
return chain;
|
||||
}
|
||||
|
||||
public void setChain(List<Node> chain) {
|
||||
this.chain = chain;
|
||||
}
|
||||
|
||||
public void addChain(String app, String unitFlag) {
|
||||
chain.add(new Node(app, unitFlag));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ResultHolder{" + "result=" + result + ", chain=" + chain + '}';
|
||||
}
|
||||
|
||||
static class Node implements Serializable {
|
||||
|
||||
private String app;
|
||||
|
||||
private String unitFlag;
|
||||
|
||||
Node() {
|
||||
}
|
||||
|
||||
Node(String app, String unitFlag) {
|
||||
this.app = app;
|
||||
this.unitFlag = unitFlag;
|
||||
}
|
||||
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(String app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public String getUnitFlag() {
|
||||
return unitFlag;
|
||||
}
|
||||
|
||||
public void setUnitFlag(String unitFlag) {
|
||||
this.unitFlag = unitFlag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Node{" + "app='" + app + '\'' + ", unitFlag='" + unitFlag + '\''
|
||||
+ '}';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.common.filter;
|
||||
|
||||
import com.alibaba.cloud.example.common.entity.ResultHolder;
|
||||
import io.appactive.support.log.LogUtil;
|
||||
import io.appactive.support.sys.JvmPropertyUtil;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.AfterReturning;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
public class ChainAspect {
|
||||
|
||||
private static final Logger logger = LogUtil.getLogger();
|
||||
|
||||
/**
|
||||
* Add tag information in result.
|
||||
* @param joinPoint joinPoint
|
||||
* @param result result
|
||||
*/
|
||||
@AfterReturning(
|
||||
pointcut = "execution(* com.alibaba.cloud.example.frontend.service.*.*(..)) || "
|
||||
+ "execution(* com.alibaba.cloud.example.product.service.*.*(..)) || "
|
||||
+ "execution(* com.alibaba.cloud.example.storage.service.*.*(..)) || "
|
||||
+ "execution(* com.alibaba.cloud.example.common.service.*.*(..))",
|
||||
returning = "result")
|
||||
public void afterRunning(JoinPoint joinPoint, Object result) {
|
||||
if (result instanceof ResultHolder) {
|
||||
ResultHolder resultHolder = (ResultHolder) result;
|
||||
resultHolder.addChain(JvmPropertyUtil.getJvmAndEnvValue("appactive.app"),
|
||||
JvmPropertyUtil.getJvmAndEnvValue("appactive.unit"));
|
||||
logger.info("ChainAspect: " + resultHolder);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.common.service;
|
||||
|
||||
import com.alibaba.cloud.example.common.entity.ResultHolder;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
@Service
|
||||
public class OrderDAO {
|
||||
|
||||
@Autowired
|
||||
private OrderService orderService;
|
||||
|
||||
public ResultHolder<String> buy(String rId, String pId, Integer number) {
|
||||
return orderService.buy(rId, pId, number);
|
||||
}
|
||||
|
||||
@FeignClient(name = "storage")
|
||||
public interface OrderService {
|
||||
|
||||
@GetMapping("/buy/")
|
||||
ResultHolder<String> buy(@RequestParam(name = "rId") String rId,
|
||||
@RequestParam(name = "id") String id,
|
||||
@RequestParam(name = "number") Integer number);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.common.service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.alibaba.cloud.example.common.RPCType;
|
||||
import com.alibaba.cloud.example.common.entity.Product;
|
||||
import com.alibaba.cloud.example.common.entity.ResultHolder;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@Service
|
||||
public class ProductDAO {
|
||||
|
||||
@Autowired(required = false)
|
||||
RestTemplate restTemplate;
|
||||
|
||||
@Autowired
|
||||
private ProductService productService;
|
||||
|
||||
public ResultHolder<List<Product>> list() {
|
||||
return productService.list();
|
||||
}
|
||||
|
||||
public ResultHolder<Product> detail(String rId, String pId) {
|
||||
return productService.detail(rId, pId);
|
||||
}
|
||||
|
||||
public ResultHolder<Product> detailHidden(String pId) {
|
||||
return productService.detailHidden(pId);
|
||||
}
|
||||
|
||||
public ResultHolder<String> buy(String rId, String pId, Integer number) {
|
||||
return productService.buy(RPCType.SpringCloud.name(), rId, pId, number);
|
||||
}
|
||||
|
||||
public ResultHolder<List<Product>> listTemplate() {
|
||||
if (restTemplate != null) {
|
||||
return restTemplate.getForObject("http://product/list", ResultHolder.class);
|
||||
}
|
||||
return productService.list();
|
||||
}
|
||||
|
||||
public ResultHolder<Product> detailTemplate(String rId, String pId) {
|
||||
if (restTemplate != null) {
|
||||
Map<String, String> params = new HashMap<>(2);
|
||||
params.put("rId", rId);
|
||||
params.put("pId", pId);
|
||||
return restTemplate.getForObject("http://product/detail", ResultHolder.class,
|
||||
params);
|
||||
}
|
||||
return productService.detail(rId, pId);
|
||||
}
|
||||
|
||||
@FeignClient(name = "product")
|
||||
public interface ProductService {
|
||||
|
||||
@RequestMapping("/list/")
|
||||
ResultHolder<List<Product>> list();
|
||||
|
||||
@RequestMapping("/detail/")
|
||||
ResultHolder<Product> detail(@RequestParam(name = "rId") String rId,
|
||||
@RequestParam(name = "pId") String pId);
|
||||
|
||||
@RequestMapping("/detailHidden/")
|
||||
ResultHolder<Product> detailHidden(@RequestParam(name = "pId") String pId);
|
||||
|
||||
@RequestMapping("/buy/")
|
||||
ResultHolder<String> buy(@RequestParam(name = "rpcType") String rpcType,
|
||||
@RequestParam(name = "rId") String rId,
|
||||
@RequestParam(name = "pId") String pId,
|
||||
@RequestParam(name = "number") Integer number);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.common.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.cloud.example.common.entity.Product;
|
||||
import com.alibaba.cloud.example.common.entity.ResultHolder;
|
||||
|
||||
public interface ProductServiceNormal {
|
||||
|
||||
ResultHolder<List<Product>> list();
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.common.service;
|
||||
|
||||
import com.alibaba.cloud.example.common.entity.Product;
|
||||
import com.alibaba.cloud.example.common.entity.ResultHolder;
|
||||
|
||||
public interface ProductServiceUnit {
|
||||
|
||||
ResultHolder<Product> detail(String rId, String pId);
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.common.service;
|
||||
|
||||
import com.alibaba.cloud.example.common.entity.Product;
|
||||
import com.alibaba.cloud.example.common.entity.ResultHolder;
|
||||
|
||||
public interface ProductServiceUnitHidden {
|
||||
|
||||
ResultHolder<Product> detail(String pId);
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
version: "3"
|
||||
services:
|
||||
nacos:
|
||||
container_name: nacos
|
||||
hostname: nacos
|
||||
image: nacos/nacos-server:2.0.3
|
||||
environment:
|
||||
- PREFER_HOST_MODE=hostname
|
||||
- MODE=standalone
|
||||
ports:
|
||||
- "8848:8848"
|
||||
- "9848:9848"
|
||||
- "9849:9849"
|
||||
|
||||
mysql:
|
||||
container_name: mysql
|
||||
hostname: mysql
|
||||
image: mysql:5.7
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: root
|
||||
MYSQL_DATABASE: product
|
||||
ports:
|
||||
- "3306:3306"
|
||||
command: [
|
||||
--character-set-server=utf8mb4,
|
||||
--collation-server=utf8mb4_unicode_ci
|
||||
]
|
@ -0,0 +1,86 @@
|
||||
channel=$1
|
||||
tenant=$2
|
||||
waitTime=$3
|
||||
if [ ! -n "$channel" ] ;then
|
||||
channel="FILE"
|
||||
fi
|
||||
if [ ! -n "$waitTime" ] ;then
|
||||
waitTime=3
|
||||
fi
|
||||
echo "channel: ${channel}"
|
||||
dataIdPrefix="appactive.dataId."
|
||||
groupId="appactive.groupId"
|
||||
|
||||
forbiddenFile="forbiddenRule.json"
|
||||
forbiddenFileEmpty="forbiddenRuleEmpty.json"
|
||||
idUnitMappingNextFile="idUnitMappingNext.json"
|
||||
|
||||
if [ $channel = "FILE" ]
|
||||
then
|
||||
for file in $(ls ../data/); do
|
||||
if [[ "$file" == *"path-address"* ]]; then
|
||||
echo "continue"
|
||||
continue
|
||||
fi
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") 应用 ${file} 禁写规则推送中)"
|
||||
cp -f ./rule/$forbiddenFile "../data/$file/forbiddenRule.json"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") 应用 ${file} 禁写规则推送完成"
|
||||
done
|
||||
elif [ $channel = "NACOS" ]
|
||||
then
|
||||
forbiddenRule=$(cat ./rule/forbiddenRule.json)
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") forbiddenRule 推送结果: " \
|
||||
&& curl -X POST "127.0.0.1:8848/nacos/v1/cs/configs" \
|
||||
-d "tenant=${tenant}&dataId=${dataIdPrefix}forbiddenRulePath&group=${groupId}&content=${forbiddenRule}" \
|
||||
&& echo ""
|
||||
else
|
||||
echo "unsupported channel: ${channel}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
idSource=$(cat ./rule/idSource.json)
|
||||
idTransformer=$(cat ./rule/idTransformer.json)
|
||||
idUnitMapping=$(cat ./rule/$idUnitMappingNextFile)
|
||||
|
||||
gatewayRule="{\"idSource\" : $idSource, \"idTransformer\" : $idTransformer, \"idUnitMapping\" : $idUnitMapping}"
|
||||
data="{\"key\" : \"459236fc-ed71-4bc4-b46c-69fc60d31f18_test1122\", \"value\" : $gatewayRule}"
|
||||
echo $data
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") gateway 新规则推送结果: " && curl --header "Content-Type: application/json" \
|
||||
--request POST \
|
||||
--data "$data" \
|
||||
127.0.0.1:8090/set
|
||||
|
||||
echo "等待数据追平......"
|
||||
sleep "${waitTime}s"
|
||||
echo "数据已经追平,下发新规则......"
|
||||
|
||||
if [ $channel = "FILE" ]
|
||||
then
|
||||
for file in $(ls ../data/); do
|
||||
if [[ "$file" == *"path-address"* ]]; then
|
||||
echo "continue"
|
||||
continue
|
||||
fi
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") 应用 ${file} 新规则推送中"
|
||||
cp -f ./rule/$idUnitMappingNextFile "../data/$file/idUnitMapping.json"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") 应用 ${file} 新规则推送完成"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") 应用 ${file} 清除禁写规则推送中)"
|
||||
cp -f ./rule/$forbiddenFileEmpty "../data/$file/forbiddenRule.json"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") 应用 ${file} 清除禁写规则推送完成"
|
||||
done
|
||||
elif [ $channel = "NACOS" ]
|
||||
then
|
||||
idUnitMappingRule=$(cat ./rule/idUnitMappingNext.json)
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") idUnitMappingRule 推送结果: " \
|
||||
&& curl -X POST "127.0.0.1:8848/nacos/v1/cs/configs" \
|
||||
-d "tenant=${tenant}&dataId=${dataIdPrefix}trafficRouteRulePath&group=${groupId}&content=${idUnitMappingRule}" \
|
||||
&& echo ""
|
||||
forbiddenRule=$(cat ./rule/forbiddenRuleEmpty.json)
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") forbiddenRule 推送结果: " \
|
||||
&& curl -X POST "127.0.0.1:8848/nacos/v1/cs/configs" \
|
||||
-d "tenant=${tenant}&dataId=${dataIdPrefix}forbiddenRulePath&group=${groupId}&content=${forbiddenRule}" \
|
||||
&& echo ""
|
||||
else
|
||||
echo "unsupported channel: ${channel}"
|
||||
exit 1
|
||||
fi
|
@ -0,0 +1,19 @@
|
||||
FROM openjdk:8-jdk-alpine
|
||||
|
||||
WORKDIR /app
|
||||
COPY target/frontend-0.2.1.jar /app
|
||||
# 设置文件夹操作权限
|
||||
RUN chown -R root:root /app/* && \
|
||||
chmod a+rw -R /app/*
|
||||
#EXPOSE 8088
|
||||
USER root:root
|
||||
|
||||
ARG UNITFLAG=default
|
||||
|
||||
ENV TZ=Asia/Shanghai \
|
||||
UNITFLAG=$UNITFLAG \
|
||||
LANG="en_US.UTF-8"
|
||||
|
||||
ENTRYPOINT ["sh", "-c"]
|
||||
CMD ["java -jar /app/frontend-0.2.1.jar"]
|
||||
#CMD ["sleep 10m"]
|
@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>frontend</artifactId>
|
||||
<name>Spring Cloud Starter Alibaba Appactive Example - Frontend Service</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<maven.deploy.skip>true</maven.deploy.skip>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>appactive-example-common</artifactId>
|
||||
<version>${revision}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.frontend;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
|
||||
@ComponentScan(basePackages = { "com.alibaba.cloud.example" })
|
||||
@EnableDiscoveryClient
|
||||
@EnableFeignClients(basePackages = { "com.alibaba.cloud.example" })
|
||||
public class FrontendApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(FrontendApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.frontend.controller;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import com.alibaba.cloud.example.common.RPCType;
|
||||
import com.alibaba.cloud.example.common.entity.Product;
|
||||
import com.alibaba.cloud.example.common.entity.ResultHolder;
|
||||
import com.alibaba.cloud.example.common.service.ProductDAO;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import io.appactive.java.api.base.AppContextClient;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.CookieValue;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller("/")
|
||||
public class FrontController {
|
||||
|
||||
@Resource
|
||||
private ProductDAO productDAO;
|
||||
|
||||
@Value("${spring.application.name}")
|
||||
private String appName;
|
||||
|
||||
@Autowired
|
||||
private Environment env;
|
||||
|
||||
private Map<String, String[]> metaData;
|
||||
|
||||
@RequestMapping("/")
|
||||
public String index() {
|
||||
return "redirect:/listProduct";
|
||||
}
|
||||
|
||||
@RequestMapping("/echo")
|
||||
@ResponseBody
|
||||
public ResultHolder<String> echo(@RequestParam(required = false,
|
||||
defaultValue = "echo content") String content) {
|
||||
return new ResultHolder<>(appName + " : " + content);
|
||||
}
|
||||
|
||||
@RequestMapping("/check")
|
||||
@ResponseBody
|
||||
public String check() {
|
||||
return "OK From " + appName;
|
||||
}
|
||||
|
||||
@RequestMapping("/show")
|
||||
@ResponseBody
|
||||
public String show() {
|
||||
return "routerId: " + AppContextClient.getRouteId();
|
||||
}
|
||||
|
||||
@ModelAttribute("metaData")
|
||||
public Map<String, String[]> getMetaData() {
|
||||
return metaData;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void parseMetaData() {
|
||||
String unitList = env.getProperty("io.appactive.demo.unitlist");
|
||||
String appList = env.getProperty("io.appactive.demo.applist");
|
||||
metaData = new HashMap<>(2);
|
||||
metaData.put("unitList", unitList.split(","));
|
||||
metaData.put("appList", appList.split(","));
|
||||
}
|
||||
|
||||
@RequestMapping("/meta")
|
||||
@ResponseBody
|
||||
public ResultHolder<Object> meta() {
|
||||
return new ResultHolder<>(metaData);
|
||||
}
|
||||
|
||||
@GetMapping("/listProduct")
|
||||
public String listProduct(
|
||||
@CookieValue(value = "rpc_type", required = false,
|
||||
defaultValue = "Dubbo") RPCType rpcType,
|
||||
@RequestParam(required = false, defaultValue = "feign") String call,
|
||||
Model model) {
|
||||
// normal
|
||||
ResultHolder<List<Product>> resultHolder = (call.equals("feign")
|
||||
? productDAO.list() : productDAO.listTemplate());
|
||||
|
||||
model.addAttribute("result", JSON.toJSONString(resultHolder.getResult()));
|
||||
model.addAttribute("products", resultHolder.getResult());
|
||||
model.addAttribute("chain", JSON.toJSONString(resultHolder.getChain()));
|
||||
model.addAttribute("current", "listProduct");
|
||||
return "index.html";
|
||||
}
|
||||
|
||||
@GetMapping("/detailProduct")
|
||||
public String detailProduct(
|
||||
@CookieValue(value = "rpc_type", required = false,
|
||||
defaultValue = "Dubbo") RPCType rpcType,
|
||||
@RequestParam(required = false, defaultValue = "12") String id,
|
||||
@RequestParam(required = false, defaultValue = "false") Boolean hidden,
|
||||
@RequestParam(required = false, defaultValue = "feign") String call,
|
||||
Model model) {
|
||||
// unit
|
||||
ResultHolder<Product> resultHolder = getProductResultHolder(rpcType, id, hidden,
|
||||
call);
|
||||
|
||||
model.addAttribute("result", JSON.toJSONString(resultHolder.getResult()));
|
||||
model.addAttribute("product", resultHolder.getResult());
|
||||
model.addAttribute("chain", JSON.toJSONString(resultHolder.getChain()));
|
||||
model.addAttribute("current", "detailProduct");
|
||||
return "detail.html";
|
||||
}
|
||||
|
||||
private ResultHolder<Product> getProductResultHolder(RPCType rpcType, String id,
|
||||
Boolean hidden, String call) {
|
||||
ResultHolder<Product> resultHolder;
|
||||
resultHolder = hidden ? productDAO.detailHidden(id)
|
||||
: (call.equals("feign")
|
||||
? productDAO.detail(AppContextClient.getRouteId(), id)
|
||||
: productDAO.detailTemplate(AppContextClient.getRouteId(), id));
|
||||
return resultHolder;
|
||||
}
|
||||
|
||||
@RequestMapping("/buyProduct")
|
||||
public String buyProduct(
|
||||
@CookieValue(value = "rpc_type", required = false,
|
||||
defaultValue = "Dubbo") RPCType rpcType,
|
||||
@RequestParam(required = false, defaultValue = "12") String pId,
|
||||
@RequestParam(required = false, defaultValue = "1") Integer number,
|
||||
@RequestParam(required = false, defaultValue = "feign") String call,
|
||||
Model model) {
|
||||
// unit
|
||||
ResultHolder<String> resultHolder = productDAO.buy(AppContextClient.getRouteId(),
|
||||
pId, number);
|
||||
|
||||
ResultHolder<Product> productHolder = getProductResultHolder(rpcType, pId, false,
|
||||
call);
|
||||
|
||||
model.addAttribute("result", JSON.toJSONString(resultHolder.getResult()));
|
||||
model.addAttribute("msg", resultHolder.getResult());
|
||||
model.addAttribute("product", productHolder.getResult());
|
||||
model.addAttribute("chain", JSON.toJSONString(resultHolder.getChain()));
|
||||
model.addAttribute("current", "buyProduct");
|
||||
return "buy.html";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.frontend.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
// @Component
|
||||
public class ChainFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response,
|
||||
FilterChain chain) throws IOException, ServletException {
|
||||
HttpServletResponse res = (HttpServletResponse) response;
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
server.port=8089
|
||||
spring.application.name=frontend
|
||||
|
||||
appactive.unit=center
|
||||
appactive.app=frontend
|
||||
io.appactive.demo.unitlist=center,unit
|
||||
io.appactive.demo.applist=frontend,product,storage
|
||||
spring.thymeleaf.mode=LEGACYHTML5
|
||||
spring.thymeleaf.encoding=UTF-8
|
||||
spring.thymeleaf.servlet.content-type=text/html
|
||||
spring.thymeleaf.suffix=.html
|
||||
spring.thymeleaf.cache=false
|
||||
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
|
||||
feign.client.config.default.connectTimeout=8000
|
||||
feign.client.config.default.readTimeout=8000
|
||||
spring.cloud.appactive.filter.general-path=/*
|
||||
product.ribbon.NFLoadBalancerRuleClassName=com.alibaba.cloud.appactive.consumer.AppactiveRule
|
||||
|
After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 20 KiB |
@ -0,0 +1,69 @@
|
||||
<!--
|
||||
~ Copyright 2013-2019 the original author or authors.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
|
||||
<head th:replace="header.html :: commonHead">
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
$(window).on('load', function () {
|
||||
$('#resultModal').modal('show');
|
||||
});
|
||||
</script>
|
||||
<header th:replace="header.html :: pageHeader"></header>
|
||||
<div class="container" id="welcome-page">
|
||||
<div class="modal" id="resultModal" role="dialog" tabindex="-1">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">购买结果</h5>
|
||||
<button aria-label="Close" class="close" data-dismiss="modal" type="button">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p th:text="${msg}"></p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" data-dismiss="modal" type="button">关闭</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row align-items-center m-auto">
|
||||
<div class="col m-auto">
|
||||
<div class="card m-auto" style="width: 8rem; align-self: center">
|
||||
<img class="card-img-top" th:src="${product.img}" width="90%">
|
||||
<div class="card-body" th:id="${product.id}">
|
||||
<h5 class="card-title" style="text-align: center" th:text="${product.name}"></h5>
|
||||
<p class="card-text" style="text-align: center" th:text="${product.description}"></p>
|
||||
<p class="card-text">
|
||||
<span>价格: </span><span class="badge text-bg-success" th:text="${product.price}"></span>
|
||||
<span>库存: </span><span class="badge text-bg-info" th:text="${product.number}"></span>
|
||||
<a class="btn btn-primary" style="text-align: center"
|
||||
th:href="@{'/buyProduct?pId=' + ${product.id}}">
|
||||
购买
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<header th:replace="header.html :: pageTraffic"></header>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,41 @@
|
||||
<!--
|
||||
~ Copyright 2013-2019 the original author or authors.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
|
||||
<head th:replace="header.html :: commonHead"></head>
|
||||
<body>
|
||||
<header th:replace="header.html :: pageHeader"></header>
|
||||
<div class="container" id="welcome-page">
|
||||
<div class="row align-items-center m-auto">
|
||||
<div class="col m-auto">
|
||||
<div class="card m-auto" style="width: 8rem; align-self: center">
|
||||
<img class="card-img-top" th:src="${product.img}" width="90%">
|
||||
<div class="card-body" th:id="${product.id}">
|
||||
<h5 class="card-title" style="text-align: center" th:text="${product.name}"></h5>
|
||||
<p class="card-text" style="text-align: center" th:text="${product.description}"></p>
|
||||
<p class="card-text">
|
||||
<span>价格: </span><span class="badge text-bg-success" th:text="${product.price}"></span>
|
||||
<span>库存: </span><span class="badge text-bg-info" th:text="${product.number}"></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<header th:replace="header.html :: pageTraffic"></header>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,258 @@
|
||||
<!--
|
||||
~ Copyright 2013-2019 the original author or authors.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
|
||||
<head th:fragment="commonHead">
|
||||
<meta charset="UTF-8">
|
||||
<title>Appactive Demo</title>
|
||||
|
||||
<link href="/css/bootstrap.min.css" rel="stylesheet">
|
||||
<script src="/js/jquery-3.2.1.slim.min.js"></script>
|
||||
<script src="/js/popper.min.js"></script>
|
||||
<script src="/js/bootstrap.min.js"></script>
|
||||
|
||||
<meta content="width=device-width, initial-scale=1.0, shrink-to-fit=no" name="viewport">
|
||||
<meta content="ie=edge" http-equiv="X-UA-Compatible">
|
||||
|
||||
<style>
|
||||
ul li.active > a {
|
||||
color: #00CED1 !important;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.card-body .card-body-badge {
|
||||
position: absolute;
|
||||
display: none;
|
||||
top: -10px;
|
||||
left: -30px;
|
||||
padding: 5px;
|
||||
background: #00CC66;
|
||||
color: white;
|
||||
transform: rotate(-20deg);
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
window.onload = function () {
|
||||
setMenu();
|
||||
hideGateway();
|
||||
refresh(undefined, undefined);
|
||||
drawArrow();
|
||||
};
|
||||
|
||||
// function drawArrow() {
|
||||
// let activeColor = "#00CC66";
|
||||
//
|
||||
// let chainNode = $("#chain");
|
||||
// let chain = JSON.parse(chainNode.val());
|
||||
// let num = chain.length;
|
||||
//
|
||||
// $("#center-gateway").css({backgroundColor: activeColor});
|
||||
//
|
||||
// chain.forEach((val)=>{
|
||||
// let elem = $("#" + val.unitFlag + "-" + val.app);
|
||||
// elem.css({backgroundColor: activeColor});
|
||||
// });
|
||||
// }
|
||||
|
||||
function drawArrow() {
|
||||
let activeColor = "#FFCC66";
|
||||
activeColor = "#00CC66";
|
||||
|
||||
let interval = 700;
|
||||
|
||||
let chainNode = $("#chain");
|
||||
let chain = JSON.parse(chainNode.val());
|
||||
let num = chain.length;
|
||||
|
||||
lightUp({"unitFlag": "center", "app": "gateway"}, activeColor, 0);
|
||||
for (let i = 0; i < num; i++) {
|
||||
(function (i) {
|
||||
setTimeout(function () {
|
||||
let val = chain[i];
|
||||
lightUp(val, activeColor, num - i)
|
||||
}, interval * (num - i))
|
||||
})(i)
|
||||
}
|
||||
}
|
||||
|
||||
function lightUp(val, activeColor, i) {
|
||||
let id = val.unitFlag + "-" + val.app;
|
||||
console.log(id)
|
||||
let elem = $("#" + id);
|
||||
elem.css({backgroundColor: activeColor});
|
||||
|
||||
let id1 = val.unitFlag + "T" + val.app
|
||||
let elem1 = $("#" + id1);
|
||||
elem1.text("第 " + (i) + " 跳");
|
||||
elem1.show();
|
||||
}
|
||||
|
||||
function hideGateway() {
|
||||
let host = window.location.host;
|
||||
if ("demo.appactive.io" !== host) {
|
||||
$("#domainArea").hide();
|
||||
}
|
||||
}
|
||||
|
||||
function setMenu() {
|
||||
let currentNode = $("#current");
|
||||
let current = currentNode.val();
|
||||
let elem = $("#" + current);
|
||||
elem.addClass("active");
|
||||
}
|
||||
|
||||
function refresh(routerIdNew, rpcTypeNew) {
|
||||
let routerId = routerIdNew === undefined ? getRouterId() : routerIdNew;
|
||||
let rpcType = rpcTypeNew === undefined ? getRpcType() : rpcTypeNew;
|
||||
let element = document.getElementById("routerId");
|
||||
element.value = routerId;
|
||||
element = document.getElementById("rpcType");
|
||||
element.value = rpcType;
|
||||
document.cookie = ("rpc_type=" + rpcType + "; path=/");
|
||||
document.cookie = ("r_id=" + routerId + "; path=/");
|
||||
}
|
||||
|
||||
function setMeta() {
|
||||
let element = document.getElementById("routerId");
|
||||
let routerId = element.value;
|
||||
let element1 = document.getElementById("rpcType");
|
||||
let rpcType = element1.value;
|
||||
console.log(routerId + "," + rpcType)
|
||||
// 整个网站生效 用 /
|
||||
refresh(routerId, rpcType);
|
||||
}
|
||||
|
||||
function getRouterId() {
|
||||
let routerId = getQuery("r_id")
|
||||
if (routerId === undefined) {
|
||||
routerId = getCookie("r_id")
|
||||
}
|
||||
if (routerId === undefined) {
|
||||
routerId = 24
|
||||
}
|
||||
return routerId;
|
||||
}
|
||||
|
||||
function getRpcType() {
|
||||
let rpcType = getQuery("rpc_type")
|
||||
if (rpcType === undefined) {
|
||||
rpcType = getCookie("rpc_type")
|
||||
}
|
||||
if (rpcType === undefined) {
|
||||
rpcType = "SpringCloud"
|
||||
}
|
||||
return rpcType;
|
||||
}
|
||||
|
||||
function getCookie(cname) {
|
||||
let name = cname + "=";
|
||||
let ca = document.cookie.split(';');
|
||||
for (let i = 0; i < ca.length; i++) {
|
||||
let c = ca[i].trim();
|
||||
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getQuery(variable) {
|
||||
let query = window.location.search.substring(1);
|
||||
let vars = query.split("&");
|
||||
for (let i = 0; i < vars.length; i++) {
|
||||
let pair = vars[i].split("=");
|
||||
if (pair[0] === variable) {
|
||||
return pair[1];
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<header th:fragment="pageHeader">
|
||||
<nav class="navbar navbar-light" style="background-color: #e3f2fd;">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand" href="#">Appactive Demo</a>
|
||||
</div>
|
||||
<ul class="nav">
|
||||
<li id="listProduct"><a class="nav-link" th:href="@{'/listProduct'}">列表(普通服务)</a></li>
|
||||
<li id="detailProduct"><a class="nav-link" th:href="@{'/detailProduct'}">详情(单元服务)</a></li>
|
||||
<li id="buyProduct"><a class="nav-link" th:href="@{'/buyProduct'}">下单(中心服务)</a></li>
|
||||
<select class="form-control" id="rpcType" name="rpcType" onchange="setMeta()" style="width:150px">
|
||||
<option value="SpringCloud">SpringCloud</option>
|
||||
</select>
|
||||
<li><input class="form-control" id="routerId" onblur="setMeta()" onchange="setMeta()" placeholder="路由ID"
|
||||
type="text"></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<input hidden id="result" th:value="${result}"/>
|
||||
<input hidden id="chain" th:value="${chain}"/>
|
||||
<input hidden id="current" th:value="${current}"/>
|
||||
<br>
|
||||
</header>
|
||||
|
||||
<header th:fragment="pageTraffic">
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<hr>
|
||||
</div>
|
||||
<div class="col-auto">绿色格子-流量路径</div>
|
||||
<div class="col">
|
||||
<hr>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container m-auto">
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="row">
|
||||
<div class="col-md-4" id="domainArea">
|
||||
<div class="card" style="width: 8rem">
|
||||
<img class="card-img-top" src="/img/gateway.png">
|
||||
<div class="card-body" id="center-gateway">
|
||||
<h5 class="card-title" style="text-align: center">center</h5>
|
||||
<h5 class="card-title" style="text-align: center">gateway</h5>
|
||||
<div class="card-body-badge" id="centerTgateway"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<div class="row" th:each="unit: ${metaData.unitList}">
|
||||
<div class="col-md-4" th:each="app: ${metaData.appList}">
|
||||
<div class="card" style="width: 8rem">
|
||||
<img class="card-img-top" th:src="'/img/' + ${app} + '.png'">
|
||||
<div class="card-body" th:id="@{${unit} + '-' + ${app}}">
|
||||
<h5 class="card-title" style="text-align: center" th:text="${unit}"></h5>
|
||||
<h5 class="card-title" style="text-align: center" th:text="${app}"></h5>
|
||||
<div class="card-body-badge" th:id="@{${unit} + 'T' + ${app}}"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,39 @@
|
||||
<!--
|
||||
~ Copyright 2013-2019 the original author or authors.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
|
||||
<head th:replace="header.html :: commonHead"></head>
|
||||
<body>
|
||||
<header th:replace="header.html :: pageHeader"></header>
|
||||
<div class="container" id="welcome-page">
|
||||
<div class="row">
|
||||
<div class="col-md-3" th:each="product: ${products}">
|
||||
<div class="card" style="width: 8rem">
|
||||
<img class="card-img-top" th:src="${product.img}">
|
||||
<div class="card-body" th:id="${product.id}">
|
||||
<h5 class="card-title" style="text-align: center">
|
||||
<a th:href="@{'/detailProduct?id=' + ${product.id}}" th:text="${product.name}"></a>
|
||||
</h5>
|
||||
<p class="card-text" style="text-align: center" th:text="${product.description}"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<header th:replace="header.html :: pageTraffic"></header>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,18 @@
|
||||
FROM openjdk:8-jdk-alpine
|
||||
|
||||
WORKDIR /app
|
||||
COPY target/product-0.2.1.jar /app
|
||||
# 设置文件夹操作权限
|
||||
RUN chown -R root:root /app/* && \
|
||||
chmod a+rw -R /app/*
|
||||
#EXPOSE 8089
|
||||
USER root:root
|
||||
|
||||
ARG UNITFLAG=default
|
||||
|
||||
ENV TZ=Asia/Shanghai \
|
||||
UNITFLAG=$UNITFLAG \
|
||||
LANG="en_US.UTF-8"
|
||||
|
||||
ENTRYPOINT ["sh", "-c"]
|
||||
CMD ["java -jar /app/product-0.2.1.jar"]
|
@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>product</artifactId>
|
||||
<name>Spring Cloud Starter Alibaba Appactive Example - Product Service</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<maven.deploy.skip>true</maven.deploy.skip>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>appactive-example-common</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.40</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.product;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.cloud.example.common.RPCType;
|
||||
import com.alibaba.cloud.example.common.entity.Product;
|
||||
import com.alibaba.cloud.example.common.entity.ResultHolder;
|
||||
import com.alibaba.cloud.example.common.service.OrderDAO;
|
||||
import com.alibaba.cloud.example.common.service.ProductServiceNormal;
|
||||
import com.alibaba.cloud.example.common.service.ProductServiceUnit;
|
||||
import com.alibaba.cloud.example.common.service.ProductServiceUnitHidden;
|
||||
import io.appactive.java.api.base.AppContextClient;
|
||||
import io.appactive.support.log.LogUtil;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@SpringBootApplication
|
||||
@ComponentScan(basePackages = { "com.alibaba.cloud.example" })
|
||||
@EntityScan("com.alibaba.cloud.example.*")
|
||||
@Controller
|
||||
@RequestMapping("/")
|
||||
@EnableDiscoveryClient
|
||||
@EnableFeignClients(basePackages = { "com.alibaba.cloud.example" })
|
||||
public class ProductApplication {
|
||||
|
||||
private static final Logger logger = LogUtil.getLogger();
|
||||
|
||||
@Autowired
|
||||
OrderDAO orderDAO;
|
||||
|
||||
@Value("${spring.application.name}")
|
||||
private String appName;
|
||||
|
||||
@Autowired
|
||||
private ProductServiceNormal productServiceNormal;
|
||||
|
||||
@Autowired
|
||||
private ProductServiceUnit productServiceUnit;
|
||||
|
||||
@Autowired
|
||||
private ProductServiceUnitHidden productServiceUnitHidden;
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ProductApplication.class, args);
|
||||
}
|
||||
|
||||
@RequestMapping("/echo")
|
||||
@ResponseBody
|
||||
public String echo(
|
||||
@RequestParam(required = false, defaultValue = "jack") String user) {
|
||||
String s = String.valueOf(user);
|
||||
return String.format("%s get %s", s, productServiceNormal.list().toString());
|
||||
}
|
||||
|
||||
@RequestMapping("/list")
|
||||
@ResponseBody
|
||||
public ResultHolder<List<Product>> list() {
|
||||
return productServiceNormal.list();
|
||||
}
|
||||
|
||||
@RequestMapping("/detailHidden")
|
||||
@ResponseBody
|
||||
public ResultHolder<Product> detailHidden(
|
||||
@RequestParam(required = false, defaultValue = "12") String pId) {
|
||||
// unit
|
||||
logger.info("detailHidden, routerId: {}, pId: {}", AppContextClient.getRouteId(),
|
||||
pId);
|
||||
return productServiceUnitHidden.detail(pId);
|
||||
}
|
||||
|
||||
@RequestMapping("/detail")
|
||||
@ResponseBody
|
||||
public ResultHolder<Product> detail(
|
||||
@RequestParam(required = false, defaultValue = "12") String rId,
|
||||
@RequestParam(required = false, defaultValue = "12") String pId) {
|
||||
// unit
|
||||
logger.info("detail, routerId: {}, pId: {}", AppContextClient.getRouteId(), pId);
|
||||
return productServiceUnit.detail(rId, pId);
|
||||
}
|
||||
|
||||
@RequestMapping("/buy")
|
||||
@ResponseBody
|
||||
public ResultHolder<String> buy(
|
||||
@RequestParam(required = false, defaultValue = "Dubbo") RPCType rpcType,
|
||||
@RequestParam(required = false, defaultValue = "12") String rId,
|
||||
@RequestParam(required = false, defaultValue = "12") String pId,
|
||||
@RequestParam(required = false, defaultValue = "5") Integer number) {
|
||||
logger.info("buy, routerId: {}, rpcType: {}", AppContextClient.getRouteId(),
|
||||
rpcType);
|
||||
return orderDAO.buy(rId, pId, number);
|
||||
|
||||
}
|
||||
|
||||
@RequestMapping("/check")
|
||||
@ResponseBody
|
||||
public String check() {
|
||||
return "OK From " + appName;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.product.init;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import com.alibaba.cloud.example.common.entity.Product;
|
||||
import com.alibaba.cloud.example.product.repository.ProductRepository;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import static com.alibaba.cloud.example.common.Constants.CENTER_FLAG;
|
||||
|
||||
@Component
|
||||
public class InitData implements ApplicationRunner {
|
||||
|
||||
@Resource
|
||||
ProductRepository productRepository;
|
||||
|
||||
@Value("${appactive.unit}")
|
||||
private String unit;
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) throws Exception {
|
||||
|
||||
if (!CENTER_FLAG.equals(unit)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Product> products = new ArrayList<>(4);
|
||||
Product p1 = new Product();
|
||||
p1.setId("12");
|
||||
p1.setName("书包");
|
||||
p1.setImg("/img/backpack.png");
|
||||
p1.setDescription("好用的书包");
|
||||
p1.setPrice(300);
|
||||
p1.setNumber(10);
|
||||
products.add(p1);
|
||||
|
||||
Product p2 = new Product();
|
||||
p2.setId("14");
|
||||
p2.setName("球拍");
|
||||
p2.setImg("/img/badminton.png");
|
||||
p2.setDescription("好用的球拍");
|
||||
p2.setPrice(200);
|
||||
p2.setNumber(20);
|
||||
products.add(p2);
|
||||
|
||||
Product p3 = new Product();
|
||||
p3.setId("16");
|
||||
p3.setName("键盘");
|
||||
p3.setImg("/img/keyboard.png");
|
||||
p3.setDescription("好用的键盘");
|
||||
p3.setPrice(800);
|
||||
p3.setNumber(50);
|
||||
products.add(p3);
|
||||
|
||||
Product p4 = new Product();
|
||||
p4.setId("18");
|
||||
p4.setName("茶杯");
|
||||
p4.setImg("/img/cup.png");
|
||||
p4.setDescription("好用的茶杯");
|
||||
p4.setPrice(100);
|
||||
p4.setNumber(60);
|
||||
products.add(p4);
|
||||
|
||||
try {
|
||||
productRepository.deleteAll();
|
||||
productRepository.saveAll(products);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.product.repository;
|
||||
|
||||
import com.alibaba.cloud.example.common.entity.Product;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface ProductRepository extends JpaRepository<Product, String> {
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.product.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.cloud.example.common.entity.Product;
|
||||
import com.alibaba.cloud.example.common.entity.ResultHolder;
|
||||
import com.alibaba.cloud.example.common.service.ProductServiceNormal;
|
||||
import com.alibaba.cloud.example.product.repository.ProductRepository;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class ProductServiceNormalImpl implements ProductServiceNormal {
|
||||
|
||||
@Autowired
|
||||
ProductRepository productRepository;
|
||||
|
||||
@Value("${appactive.unit}")
|
||||
private String unit;
|
||||
|
||||
@Override
|
||||
public ResultHolder<List<Product>> list() {
|
||||
return new ResultHolder<>(productRepository.findAll());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.product.service;
|
||||
|
||||
import com.alibaba.cloud.example.common.entity.Product;
|
||||
import com.alibaba.cloud.example.common.entity.ResultHolder;
|
||||
import com.alibaba.cloud.example.common.service.ProductServiceUnitHidden;
|
||||
import com.alibaba.cloud.example.product.repository.ProductRepository;
|
||||
import io.appactive.java.api.base.AppContextClient;
|
||||
import io.appactive.support.log.LogUtil;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class ProductServiceUnitHiddenImpl implements ProductServiceUnitHidden {
|
||||
|
||||
private static final Logger logger = LogUtil.getLogger();
|
||||
|
||||
@Autowired
|
||||
ProductRepository productRepository;
|
||||
|
||||
@Value("${appactive.unit}")
|
||||
private String unit;
|
||||
|
||||
@Override
|
||||
public ResultHolder<Product> detail(String pId) {
|
||||
String rId = AppContextClient.getRouteId();
|
||||
logger.info("detail: " + pId + ",rId " + rId);
|
||||
return new ResultHolder<>(productRepository.findById(pId).orElse(new Product()));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.product.service;
|
||||
|
||||
import com.alibaba.cloud.example.common.entity.Product;
|
||||
import com.alibaba.cloud.example.common.entity.ResultHolder;
|
||||
import com.alibaba.cloud.example.common.service.ProductServiceUnit;
|
||||
import com.alibaba.cloud.example.product.repository.ProductRepository;
|
||||
import io.appactive.support.log.LogUtil;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class ProductServiceUnitImpl implements ProductServiceUnit {
|
||||
|
||||
private static final Logger logger = LogUtil.getLogger();
|
||||
|
||||
@Autowired
|
||||
ProductRepository productRepository;
|
||||
|
||||
@Value("${appactive.unit}")
|
||||
private String unit;
|
||||
|
||||
@Override
|
||||
public ResultHolder<Product> detail(String rId, String pId) {
|
||||
// unit
|
||||
return new ResultHolder<>(productRepository.findById(pId).orElse(new Product()));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
server.port=8087
|
||||
spring.application.name=product
|
||||
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/product?characterEncoding=utf8&useSSL=false&serverTimezone=GMT
|
||||
spring.datasource.username=root
|
||||
spring.datasource.password=root
|
||||
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
|
||||
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
|
||||
spring.jpa.hibernate.ddl-auto=update
|
||||
spring.jpa.show-sql=false
|
||||
appactive.unit=center
|
||||
appactive.app=product
|
||||
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
|
||||
feign.client.config.default.connectTimeout=5000
|
||||
feign.client.config.default.readTimeout=5000
|
||||
spring.cloud.appactive.filter.core-path=/detailHidden/*,/detail/*
|
||||
spring.cloud.appactive.filter.global-path=/buy/*
|
||||
spring.cloud.appactive.filter.general-path=/*
|
||||
|
||||
storage.ribbon.NFLoadBalancerRuleClassName=com.alibaba.cloud.appactive.consumer.AppactiveRule
|
||||
|
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 20 KiB |
@ -0,0 +1,27 @@
|
||||
<!--
|
||||
~ Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
|
||||
<head th:replace="header.html :: commonHead"></head>
|
||||
<body>
|
||||
<header th:replace="header.html :: pageHeader"></header>
|
||||
|
||||
<div id="welcome-page">
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,27 @@
|
||||
<!--
|
||||
~ Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
|
||||
<head th:replace="header.html :: commonHead"></head>
|
||||
<body>
|
||||
<header th:replace="header.html :: pageHeader"></header>
|
||||
|
||||
<div id="welcome-page">
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,195 @@
|
||||
<!--
|
||||
~ Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
|
||||
<head th:fragment="commonHead">
|
||||
<meta charset="UTF-8">
|
||||
<title>AppActive Demo</title>
|
||||
|
||||
<link href="/css/bootstrap.min.css" rel="stylesheet">
|
||||
<script src="/js/jquery-3.2.1.slim.min.js"></script>
|
||||
<script src="/js/popper.min.js"></script>
|
||||
<script src="/js/bootstrap.min.js"></script>
|
||||
|
||||
<meta content="width=device-width, initial-scale=1.0, shrink-to-fit=no" name="viewport">
|
||||
<meta content="ie=edge" http-equiv="X-UA-Compatible">
|
||||
|
||||
<script>
|
||||
window.onload = function () {
|
||||
setMenu();
|
||||
hideGateway();
|
||||
refresh();
|
||||
drawArrow();
|
||||
};
|
||||
|
||||
// function drawArrow() {
|
||||
// let activeColor = "#00CC66";
|
||||
//
|
||||
// let chainNode = $("#chain");
|
||||
// let chain = JSON.parse(chainNode.val());
|
||||
// let num = chain.length;
|
||||
//
|
||||
// $("#center-gateway").css({backgroundColor: activeColor});
|
||||
//
|
||||
// chain.forEach((val)=>{
|
||||
// let elem = $("#" + val.unitFlag + "-" + val.app);
|
||||
// elem.css({backgroundColor: activeColor});
|
||||
// });
|
||||
// }
|
||||
|
||||
function drawArrow() {
|
||||
let activeColor = "#FFCC66";
|
||||
activeColor = "#00CC66";
|
||||
|
||||
let interval = 700;
|
||||
|
||||
let chainNode = $("#chain");
|
||||
let chain = JSON.parse(chainNode.val());
|
||||
let num = chain.length;
|
||||
|
||||
$("#center-gateway").css({backgroundColor: activeColor});
|
||||
for (let i = 0; i < num; i++) {
|
||||
(function (i) {
|
||||
setTimeout(function () {
|
||||
let val = chain[i];
|
||||
lightUp(val, activeColor)
|
||||
}, interval * (num - i))
|
||||
})(i)
|
||||
}
|
||||
}
|
||||
|
||||
function lightUp(val, activeColor) {
|
||||
let id = val.unitFlag + "-" + val.app
|
||||
console.log(id)
|
||||
let elem = $("#" + id);
|
||||
elem.css({backgroundColor: activeColor});
|
||||
}
|
||||
|
||||
function hideGateway() {
|
||||
let host = window.location.host;
|
||||
if ("demo.appactive.io" !== host) {
|
||||
$("#domainArea").hide();
|
||||
}
|
||||
}
|
||||
|
||||
function setMenu() {
|
||||
let currentNode = $("#current");
|
||||
let current = currentNode.val();
|
||||
let elem = $("#" + current);
|
||||
elem.addClass("active");
|
||||
}
|
||||
|
||||
function refresh(routerIdNew) {
|
||||
let routerId = routerIdNew === undefined ? getRouterId() : routerIdNew;
|
||||
// let element = document.getElementById("routerId");
|
||||
// element.value = routerId;
|
||||
document.cookie = "r_id=" + routerId + "; path=/";
|
||||
}
|
||||
|
||||
function setRouterId() {
|
||||
let element = document.getElementById("r_id");
|
||||
let routerId = element.value;
|
||||
// 整个网站生效 用 /
|
||||
refresh(routerId);
|
||||
}
|
||||
|
||||
function getRouterId() {
|
||||
let routerId = getQuery("r_id")
|
||||
if (routerId === undefined) {
|
||||
routerId = getCookie("r_id")
|
||||
}
|
||||
if (routerId === undefined) {
|
||||
routerId = 24
|
||||
}
|
||||
return routerId;
|
||||
}
|
||||
|
||||
function getCookie(cname) {
|
||||
let name = cname + "=";
|
||||
let ca = document.cookie.split(';');
|
||||
for (let i = 0; i < ca.length; i++) {
|
||||
let c = ca[i].trim();
|
||||
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getQuery(variable) {
|
||||
let query = window.location.search.substring(1);
|
||||
let vars = query.split("&");
|
||||
for (let i = 0; i < vars.length; i++) {
|
||||
let pair = vars[i].split("=");
|
||||
if (pair[0] === variable) {
|
||||
return pair[1];
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<header th:fragment="pageHeader">
|
||||
<div class="container">
|
||||
<nav class="navbar navbar-light" style="background-color: #e3f2fd;">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand" href="#">App-Active Demo</a>
|
||||
</div>
|
||||
<ul class="nav navbar-nav">
|
||||
<li id="listProduct"><a class="nav-link" th:href="@{'/listProduct'}">列表</a></li>
|
||||
<li id="detailProduct"><a class="nav-link" th:href="@{'/detailProduct'}">详情</a></li>
|
||||
<li id="buyProduct"><a class="nav-link" th:href="@{'/buyProduct'}">下单</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="row">
|
||||
<div class="col-md-4" id="domainArea">
|
||||
<div class="card" style="width: 8rem">
|
||||
<img class="card-img-top" src="/img/gateway.png">
|
||||
<div class="card-body" id="center-gateway">
|
||||
<h5 class="card-title" style="text-align: center">center</h5>
|
||||
<h5 class="card-title" style="text-align: center">gateway</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<div class="row" th:each="unit: ${metaData.unitList}">
|
||||
<div class="col-md-4" th:each="app: ${metaData.appList}">
|
||||
<div class="card" style="width: 8rem">
|
||||
<img class="card-img-top" th:src="'/img/' + ${app} + '.png'">
|
||||
<div class="card-body" th:id="@{${unit} + '-' + ${app}}">
|
||||
<h5 class="card-title" style="text-align: center" th:text="${unit}"></h5>
|
||||
<h5 class="card-title" style="text-align: center" th:text="${app}"></h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input hidden id="result" th:value="${result}"/>
|
||||
<input hidden id="chain" th:value="${chain}"/>
|
||||
<input hidden id="current" th:value="${current}"/>
|
||||
</header>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,27 @@
|
||||
<!--
|
||||
~ Copyright 1999-2022 Alibaba Group Holding Ltd.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
|
||||
<head th:replace="header.html :: commonHead"></head>
|
||||
<body>
|
||||
<header th:replace="header.html :: pageHeader"></header>
|
||||
|
||||
<div id="welcome-page">
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,216 @@
|
||||
# AppActive Example
|
||||
|
||||
## Introduction
|
||||
|
||||
[![vTlxsA.jpg](https://s1.ax1x.com/2022/09/04/vTlxsA.jpg)](https://imgse.com/i/vTlxsA)
|
||||
|
||||
The overall structure of this demo is shown above.
|
||||
|
||||
Note:
|
||||
|
||||
- The registry Nacos and database MySQL that the application depends on are not shown in the figure.
|
||||
- The demo uses Nacos as a command channel
|
||||
|
||||
### Core Concept
|
||||
|
||||
concept
|
||||
|
||||
The idea of multi-activity in different places is analogous to that eggs in daily life should not be placed in one basket. By splitting and deploying business applications in units, the impact of a unit's failure is limited to a specific unit. In the application multi-activity scheme based on AppActive, applications can be divided into three categories: global business, core business and shared business according to application attributes, which can be classified into two types of units: center unit and general unit. Units are generally used to refer to server room.
|
||||
|
||||
3 types applications:
|
||||
- Global application: business applications (such as inventory, amount, etc.) with strong consistency cannot be split between multiple activities in different places, and they need to read and write services in the center unit.
|
||||
- Core application: an application that is divided into units, an application that reads and writes in a specific unit according to the preset multi-active rules and request information.
|
||||
- General application: It belongs to the business on the non-core link of the system, has low requirements on data consistency, and is not divided into units.
|
||||
|
||||
2 types units:
|
||||
|
||||
- Center unit: also known as the center server room, can carry three types of global, core and general services, and generally has higher hardware configuration than the normal unit in the server room.
|
||||
- Normal unit: other non-central units, used to carry services other than non-global services, can also be called general server rooms.
|
||||
|
||||
There are three applications in demo, according to the distance (call link) of the end user from near and far:
|
||||
|
||||
- frontend: frontend application, accept user requests, and return after requesting actual data.
|
||||
- product: product application, providing three services:
|
||||
- product List: General Service
|
||||
- product Details: Unit Service
|
||||
- product order: central service, relying on inventory application
|
||||
- storage: storage application, it provide create orders service for users.
|
||||
|
||||
The applications are deployed in each of the center and normal unit.
|
||||
|
||||
The green grid in the figure represents the call link of the request.
|
||||
|
||||
## Instructions for use
|
||||
|
||||
### Quick start
|
||||
Before starting the example for demonstration, let's take a look at how Spring Cloud applications use the remote multi-active capabilities provided by AppActive.
|
||||
**Note, this chapter is only for your understanding of the access method. The access work has been completed in this examples, and you do not need to modify it.**
|
||||
|
||||
1. First, modify the pom.xml file to add the following maven dependencies based on the latest `spring-cloud-alibaba-dependencies` added to the provider and consumer.
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-appactive</artifactId>
|
||||
</dependency>
|
||||
|
||||
2. Configure offload policies for specific interfaces in the `application.properties` configuration file of the Provider application. The suffix `core-path` is used to configure core services, `global-path` is used to configure global services, and `general-path` is used to configure general services. For example, the product application distribution strategy in the demo is configured as follows
|
||||
|
||||
spring.cloud.appactive.filter.core-path=/detailHidden/*,/detail/*
|
||||
spring.cloud.appactive.filter.global-path=/buy/*
|
||||
spring.cloud.appactive.filter.general-path=/*
|
||||
|
||||
3. In the `application.properties` of the Consumer application, configure the client load balancing as the load balancing algorithm provided by AppActive. The configuration method is as follows. Note that `[service-name]` needs to be replaced with the specific service name to be consumed.
|
||||
|
||||
[service-name].ribbon.NFLoadBalancerRuleClassName =com.alibaba.cloud.appactive.consumer.AppactiveRule
|
||||
|
||||
|
||||
### Presentation preparation
|
||||
|
||||
1. Start Nacos, MySQL, and push multi-active rules to Nacos:
|
||||
|
||||
- In the `appactive-example` directory, execute: `docker-compose -f component-quickstart.yml up -d` to start Nacos, MySQL.
|
||||
- Execute the following command: `curl -X POST 'http://127.0.0.1:8848/nacos/v1/console/namespaces' -d 'customNamespaceId=appactiveDemoNamespaceId&namespaceName=appactiveDemoNamespaceName&namespaceDesc=appactiveDemoNamespaceDesc'` Create a demo named in Nacos configuration center Space appactiveDemoNamespaceId.
|
||||
- Execute the following command: `sh baseline.sh 2 NACOS appactiveDemoNamespaceId` to push the multi-active rule to the namespace. The multi-live rules are described as follows:
|
||||
- `appactive.dataId.idSourceRulePath`: Describes how to extract routing tokens from http traffic
|
||||
- `appactive.dataId.transformerRulePath`: Describes how to parse routing tokens
|
||||
- `appactive.dataId.trafficRouteRulePath`: Describes the mapping between routing labels and units
|
||||
- `appactive.dataId.dataScopeRuleDirectoryPath_mysql-product`: Properties that describe the database
|
||||
|
||||
|
||||
2. Start five sets of applications, the startup parameters are:
|
||||
|
||||
- frontend
|
||||
```
|
||||
-Dappactive.channelTypeEnum=NACOS
|
||||
-Dappactive.namespaceId=appactiveDemoNamespaceId
|
||||
-Dappactive.unit=unit
|
||||
-Dappactive.app=frontend
|
||||
-Dio.appactive.demo.unitlist=center,unit
|
||||
-Dio.appactive.demo.applist=frontend,product,storage
|
||||
-Dserver.port=8875
|
||||
```
|
||||
- product
|
||||
```
|
||||
-Dappactive.channelTypeEnum=NACOS
|
||||
-Dappactive.namespaceId=appactiveDemoNamespaceId
|
||||
-Dappactive.unit=center
|
||||
-Dappactive.app=product
|
||||
-Dspring.datasource.url=jdbc:mysql://127.0.0.1:3306/product?characterEncoding=utf8&useSSL=false&serverTimezone=GMT&activeInstanceId=mysql&activeDbName=product
|
||||
-Dserver.port=8883
|
||||
```
|
||||
```
|
||||
-Dappactive.channelTypeEnum=NACOS
|
||||
-Dappactive.namespaceId=appactiveDemoNamespaceId
|
||||
-Dappactive.unit=unit
|
||||
-Dappactive.app=product
|
||||
-Dspring.datasource.url=jdbc:mysql://127.0.0.1:3306/product?characterEncoding=utf8&useSSL=false&serverTimezone=GMT&activeInstanceId=mysql&activeDbName=product
|
||||
-Dserver.port=8873
|
||||
```
|
||||
- storage
|
||||
```
|
||||
-Dappactive.channelTypeEnum=NACOS
|
||||
-Dappactive.namespaceId=appactiveDemoNamespaceId
|
||||
-Dappactive.unit=center
|
||||
-Dappactive.app=storage
|
||||
-Dspring.datasource.url=jdbc:mysql://127.0.0.1:3306/product?characterEncoding=utf8&useSSL=false&serverTimezone=GMT
|
||||
-Dserver.port=8881
|
||||
```
|
||||
```
|
||||
-Dappactive.channelTypeEnum=NACOS
|
||||
-Dappactive.namespaceId=appactiveDemoNamespaceId
|
||||
-Dappactive.unit=unit
|
||||
-Dappactive.app=storage
|
||||
-Dspring.datasource.url=jdbc:mysql://127.0.0.1:3306/product?characterEncoding=utf8&useSSL=false&serverTimezone=GMT
|
||||
-Dserver.port=8871
|
||||
```
|
||||
|
||||
## Demonstration process
|
||||
|
||||
1. Demonstration of general service calls belonging to the normal unit. Typing: `http://127.0.0.1:8079/listProduct` address in the browser, it can be seen that the request is sent to the product through the frontend application.
|
||||
|
||||
[![vTlxsA.jpg](https://s1.ax1x.com/2022/09/04/vTlxsA.jpg)](https://imgse.com/i/vTlxsA)
|
||||
|
||||
Since `/listProduct` in the above path matches the `/*` path rule in the product application, which corresponds to the normal unit, frontend does not have a tendency in the product address list obtained from the registry, and will randomly select an address for request sending. So requesting the above path multiple times will see the request switch back and forth between the normal and center units of the product.
|
||||
|
||||
2. Demonstration of core service calls belonging to the different unit by request information. Typing: `http://127.0.0.1:8079/detailProduct` in the browser, because the `/detailProduct` in the above path matches the `/detail/*` path rule in the product application, corresponding to the normal(unit) unit, it will be based on the request The specific value of the variable in the Header, Cookie or request parameter is used to determine the downstream unit type of the request, because the following flow switching rules are configured in advance (for details, see the content of the idUnitMapping.json file in the rule directory):
|
||||
```
|
||||
{
|
||||
"itemType": "UnitRuleItem",
|
||||
"items": [
|
||||
{
|
||||
"name": "unit",
|
||||
"conditions": [
|
||||
{
|
||||
"@userIdBetween": [
|
||||
"0~1999"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "center",
|
||||
"conditions": [
|
||||
{
|
||||
"@userIdBetween": [
|
||||
"2000~9999"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
The above rules mean that requests with user IDs of 0 ~ 1999 will be sent to the noraml(unit) in the downstream provider, and requests with user IDs of 2000 ~ 9999 will be sent to the center unit of the downstream provider.
|
||||
As shown in the figure below, a request with a user ID of 1999 is simulated. It can be seen that the request is sent to the normal unit of product in the downstream through the frontend.
|
||||
|
||||
[![1xnI7.jpg](https://s1.328888.xyz/2022/09/05/1xnI7.jpg)](https://imgloc.com/i/1xnI7)
|
||||
|
||||
As shown in the figure below, a request with a user ID of 2000 is simulated. It can be seen that the request is sent to the center unit node of the product in the downstream through the frontend.
|
||||
|
||||
[![1xAHk.jpg](https://s1.328888.xyz/2022/09/05/1xAHk.jpg)](https://imgloc.com/i/1xAHk)
|
||||
|
||||
3. Demonstration of global service invocation belonging to the center unit. Typing: `http://127.0.0.1:8079/buyProduct` path in the browser, because the `/buyProduct` in the above path matches the `/buy/*` path rule in the product and storage applications, corresponding to the center unit, it will directly send the request to the downstream center unit node.
|
||||
|
||||
[![1s4Oi.jpg](https://s1.328888.xyz/2022/09/04/1s4Oi.jpg)](https://imgloc.com/i/1s4Oi)
|
||||
|
||||
4. Cut flow demo. The main things to do when cutting flow are as follows:
|
||||
- Build new mapping relationship rules and write prohibition rules (manually).
|
||||
- Push the write prohibition rules to the application.
|
||||
- Push the new mapping relationship rules to the application after waiting for the data to equalize.
|
||||
The streaming rule demonstrated next will send requests with user IDs 0 ~ 2999 to the normal(called unit) unit in the downstream provider, and requests with user IDs 3000 ~ 9999 will be sent to the center(called center) unit in the downstream provider. For specific rules, see idUnitMappingNext.json:
|
||||
```
|
||||
{
|
||||
"itemType": "UnitRuleItem",
|
||||
"items": [
|
||||
{
|
||||
"name": "unit",
|
||||
"conditions": [
|
||||
{
|
||||
"@userIdBetween": [
|
||||
"0~2999"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "center",
|
||||
"conditions": [
|
||||
{
|
||||
"@userIdBetween": [
|
||||
"3000~9999"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
As shown in the figure below, a request with a user ID of 2999 is simulated. It can be seen that the request is sent to the unit node of the product in the downstream through the frontend, and the flow switching rule takes effect.
|
||||
[![1xUnd.jpg](https://s1.328888.xyz/2022/09/05/1xUnd.jpg)](https://imgloc.com/i/1xUnd)
|
||||
|
||||
As shown in the figure below, a request with a user ID of 3000 is simulated. It can be seen that the request is sent to the center unit node of the product in the downstream through the frontend, and the cut flow rule takes effect.
|
||||
[![1xpgr.jpg](https://s1.328888.xyz/2022/09/05/1xpgr.jpg)](https://imgloc.com/i/1xpgr)
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1 @@
|
||||
{}
|
@ -0,0 +1,15 @@
|
||||
{
|
||||
"itemType": "ForbiddenRuleItem",
|
||||
"items": [
|
||||
{
|
||||
"name": "between",
|
||||
"conditions": [
|
||||
{
|
||||
"@userIdBetween": [
|
||||
"2000~2999"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
{
|
||||
"itemType": "ForbiddenRuleItem",
|
||||
"items": []
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
{
|
||||
"source": "arg,header,cookie",
|
||||
"tokenKey": "r_id"
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"id": "userIdBetween",
|
||||
"mod": "10000"
|
||||
}
|
||||
]
|
||||
|
@ -0,0 +1,25 @@
|
||||
{
|
||||
"itemType": "UnitRuleItem",
|
||||
"items": [
|
||||
{
|
||||
"name": "unit",
|
||||
"conditions": [
|
||||
{
|
||||
"@userIdBetween": [
|
||||
"0~1999"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "center",
|
||||
"conditions": [
|
||||
{
|
||||
"@userIdBetween": [
|
||||
"2000~9999"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
{
|
||||
"itemType": "UnitRuleItem",
|
||||
"items": [
|
||||
{
|
||||
"name": "unit",
|
||||
"conditions": [
|
||||
{
|
||||
"@userIdBetween": [
|
||||
"0~2999"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "center",
|
||||
"conditions": [
|
||||
{
|
||||
"@userIdBetween": [
|
||||
"3000~9999"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
{
|
||||
"id": "userIdBetween",
|
||||
"mod": "10000"
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
FROM openjdk:8-jdk-alpine
|
||||
|
||||
WORKDIR /app
|
||||
COPY target/storage-0.2.1.jar /app
|
||||
# 设置文件夹操作权限
|
||||
RUN chown -R root:root /app/* && \
|
||||
chmod a+rw -R /app/*
|
||||
#EXPOSE 8090
|
||||
USER root:root
|
||||
|
||||
ARG UNITFLAG=default
|
||||
|
||||
ENV TZ=Asia/Shanghai \
|
||||
UNITFLAG=$UNITFLAG \
|
||||
LANG="en_US.UTF-8"
|
||||
|
||||
ENTRYPOINT ["sh", "-c"]
|
||||
CMD ["java -jar /app/storage-0.2.1.jar"]
|
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>storage</artifactId>
|
||||
<name>Spring Cloud Starter Alibaba Appactive Example - Storage Service</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<maven.deploy.skip>true</maven.deploy.skip>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>appactive-example-common</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.40</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.msha</groupId>
|
||||
<artifactId>client-bridge-db-mysql</artifactId>
|
||||
<version>0.2.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.storage;
|
||||
|
||||
import com.alibaba.cloud.example.common.entity.ResultHolder;
|
||||
import com.alibaba.cloud.example.storage.service.OrderServiceImpl;
|
||||
import io.appactive.java.api.base.AppContextClient;
|
||||
import io.appactive.support.log.LogUtil;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@SpringBootApplication
|
||||
@EntityScan("com.alibaba.cloud.example.*")
|
||||
@ComponentScan(basePackages = { "com.alibaba.cloud.example" })
|
||||
@RestController("/")
|
||||
@EnableDiscoveryClient
|
||||
@EnableFeignClients(basePackages = { "com.alibaba.cloud.example" })
|
||||
public class StorageApplication {
|
||||
|
||||
private static final Logger logger = LogUtil.getLogger();
|
||||
|
||||
@Autowired
|
||||
OrderServiceImpl orderService;
|
||||
|
||||
@Value("${spring.application.name}")
|
||||
private String appName;
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(StorageApplication.class, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* buy1 is just for bypassing center service protection.
|
||||
* @param rId rId
|
||||
* @param id id
|
||||
* @param number number
|
||||
* @return resultHolder resultHolder
|
||||
*/
|
||||
@RequestMapping({ "/buy", "/buy1" })
|
||||
@ResponseBody
|
||||
public ResultHolder<String> buy(
|
||||
@RequestParam(required = false, defaultValue = "jack") String rId,
|
||||
@RequestParam(required = false, defaultValue = "12") String id,
|
||||
@RequestParam(required = false, defaultValue = "1") Integer number) {
|
||||
String routerId = AppContextClient.getRouteId();
|
||||
logger.info("buy, routerId: {}, pid: {}, number: {}", routerId, id, number);
|
||||
ResultHolder<String> resultHolder = orderService.buy(rId, id, number);
|
||||
resultHolder
|
||||
.setResult(String.format("routerId %s bought %d of item %s, result: %s",
|
||||
routerId, number, id, resultHolder.getResult()));
|
||||
return resultHolder;
|
||||
}
|
||||
|
||||
@RequestMapping("/check")
|
||||
@ResponseBody
|
||||
public String check() {
|
||||
return "OK From " + appName;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.storage.repository;
|
||||
|
||||
import com.alibaba.cloud.example.common.entity.Product;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface ProductRepository extends JpaRepository<Product, String> {
|
||||
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.storage.service;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.alibaba.cloud.example.common.entity.Product;
|
||||
import com.alibaba.cloud.example.common.entity.ResultHolder;
|
||||
import com.alibaba.cloud.example.common.service.OrderDAO;
|
||||
import com.alibaba.cloud.example.storage.repository.ProductRepository;
|
||||
import io.appactive.support.log.LogUtil;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class OrderServiceImpl implements OrderDAO.OrderService {
|
||||
|
||||
private static final Logger logger = LogUtil.getLogger();
|
||||
|
||||
@Autowired
|
||||
ProductRepository repository;
|
||||
|
||||
@Value("${appactive.unit}")
|
||||
private String unit;
|
||||
|
||||
@Override
|
||||
public ResultHolder<String> buy(String rId, String pId, Integer number) {
|
||||
String result = null;
|
||||
try {
|
||||
Optional<Product> op = repository.findById(pId);
|
||||
if (op.isPresent()) {
|
||||
// todo 扣库存,应该强校验
|
||||
Product p = op.get();
|
||||
int oldNum = p.getNumber();
|
||||
int left = oldNum - number;
|
||||
if (left >= 0) {
|
||||
p.setNumber(left);
|
||||
p = repository.save(p);
|
||||
if (p.getNumber() + number != oldNum) {
|
||||
result = "storage not consist";
|
||||
}
|
||||
else {
|
||||
result = "success";
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = "sold out";
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = "no such product";
|
||||
}
|
||||
}
|
||||
catch (Throwable e) {
|
||||
result = e.getCause().getCause().getMessage();
|
||||
}
|
||||
return new ResultHolder<>(result);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
server.port=8085
|
||||
spring.application.name=storage
|
||||
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/product?characterEncoding=utf8&useSSL=false&serverTimezone=GMT
|
||||
spring.datasource.username=root
|
||||
spring.datasource.password=root
|
||||
#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
|
||||
spring.datasource.driver-class-name=io.appactive.db.mysql.driver.Driver
|
||||
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
|
||||
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
|
||||
spring.jpa.hibernate.ddl-auto=update
|
||||
spring.jpa.show-sql=false
|
||||
appactive.unit=center
|
||||
appactive.app=storage
|
||||
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
|
||||
spring.cloud.appactive.filter.global-path=/buy/*
|
||||
spring.cloud.appactive.filter.general-path=/*
|
@ -1,68 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<parent>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>nacos-discovery-example</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>nacos-discovery-example</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
<artifactId>nacos-discovery-consumer-example</artifactId>
|
||||
<name>Spring Cloud Starter Alibaba Nacos Discovery Consumer Example</name>
|
||||
<description>Example demonstrating how to use nacos discovery</description>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>nacos-discovery-consumer-example</artifactId>
|
||||
<name>Spring Cloud Starter Alibaba Nacos Discovery Consumer Example</name>
|
||||
<description>Example demonstrating how to use nacos discovery</description>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-appactive</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>${maven-deploy-plugin.version}</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>${maven-deploy-plugin.version}</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
@ -0,0 +1,33 @@
|
||||
HELP.md
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-starters</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>spring-cloud-starter-alibaba-appactive</artifactId>
|
||||
<name>Spring Cloud Starter Alibaba Appactive</name>
|
||||
|
||||
<properties>
|
||||
<appactive.version>0.2.1</appactive.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.msha</groupId>
|
||||
<artifactId>appactive-java-api</artifactId>
|
||||
<version>${appactive.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.msha</groupId>
|
||||
<artifactId>client-rule</artifactId>
|
||||
<version>${appactive.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.msha</groupId>
|
||||
<artifactId>client-bridge-rpc-base</artifactId>
|
||||
<version>${appactive.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-openfeign-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
<artifactId>feign-java8</artifactId>
|
||||
<version>9.5.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.msha</groupId>
|
||||
<artifactId>client-bridge-servlet</artifactId>
|
||||
<version>0.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>4.0.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<version>2.4.0</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>31.1-jre</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>2.0.11</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.appactive;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author ChengPu raozihao
|
||||
* @description
|
||||
* @date 2022/8/15
|
||||
*/
|
||||
@ConfigurationProperties("spring.cloud.appactive.filter")
|
||||
public class AppactiveProperties {
|
||||
|
||||
private String[] corePath;
|
||||
|
||||
private String[] globalPath;
|
||||
|
||||
private String[] generalPath;
|
||||
|
||||
@Autowired
|
||||
private Environment environment;
|
||||
|
||||
public String[] getCorePath() {
|
||||
return corePath;
|
||||
}
|
||||
|
||||
void setCorePath(String[] corePath) {
|
||||
this.corePath = corePath;
|
||||
}
|
||||
|
||||
public String[] getGlobalPath() {
|
||||
return globalPath;
|
||||
}
|
||||
|
||||
void setGlobalPath(String[] globalPath) {
|
||||
this.globalPath = globalPath;
|
||||
}
|
||||
|
||||
public String[] getGeneralPath() {
|
||||
return generalPath;
|
||||
}
|
||||
|
||||
void setGeneralPath(String[] generalPath) {
|
||||
this.generalPath = generalPath;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
this.overrideFromEnv(environment);
|
||||
}
|
||||
|
||||
public void overrideFromEnv(Environment env) {
|
||||
|
||||
if (StringUtils.isEmpty(this.getCorePath())) {
|
||||
String coreValue = env
|
||||
.resolvePlaceholders("${spring.cloud.appactive.filter.core-path:}");
|
||||
String[] cores = coreValue.split(",");
|
||||
this.setCorePath(cores);
|
||||
}
|
||||
if (StringUtils.isEmpty(this.getGlobalPath())) {
|
||||
String globalValue = env
|
||||
.resolvePlaceholders("${spring.cloud.appactive.filter.global-path:}");
|
||||
String[] globals = globalValue.split(",");
|
||||
this.setGlobalPath(globals);
|
||||
}
|
||||
if (StringUtils.isEmpty(this.getGeneralPath())) {
|
||||
String generalValue = env.resolvePlaceholders(
|
||||
"${spring.cloud.appactive.filter.general-path:}");
|
||||
String[] generals = generalValue.split(",");
|
||||
this.setGeneralPath(generals);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.appactive.common;
|
||||
|
||||
/**
|
||||
* @author raozihao, mageekchiu
|
||||
* @author <a href="mailto:zihaorao@gmail.com">Steve</a>
|
||||
*/
|
||||
public class ServiceMeta implements Comparable<ServiceMeta> {
|
||||
|
||||
private String uriPrefix;
|
||||
|
||||
private String ra;
|
||||
|
||||
public ServiceMeta() {
|
||||
}
|
||||
|
||||
public ServiceMeta(String uriPrefix, String ra) {
|
||||
this.uriPrefix = uriPrefix;
|
||||
this.ra = ra;
|
||||
}
|
||||
|
||||
public String getUriPrefix() {
|
||||
return uriPrefix;
|
||||
}
|
||||
|
||||
public void setUriPrefix(String uriPrefix) {
|
||||
this.uriPrefix = uriPrefix;
|
||||
}
|
||||
|
||||
public String getRa() {
|
||||
return ra;
|
||||
}
|
||||
|
||||
public void setRa(String ra) {
|
||||
this.ra = ra;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServiceMeta{" + "uriPrefix='" + uriPrefix + '\'' + ", ra=" + ra + '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ServiceMeta o) {
|
||||
int pre = this.uriPrefix.compareTo(o.getUriPrefix());
|
||||
return pre == 0 ? this.ra.compareTo(o.getRa()) : pre;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.appactive.common;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author raozihao, mageekchiu
|
||||
* @author <a href="mailto:zihaorao@gmail.com">Steve</a>
|
||||
*/
|
||||
public class ServiceMetaObject {
|
||||
|
||||
private List<ServiceMeta> serviceMetaList;
|
||||
|
||||
/**
|
||||
* string of serviceMetaList.
|
||||
*/
|
||||
private String meta;
|
||||
|
||||
private String md5OfList;
|
||||
|
||||
public ServiceMetaObject(List<ServiceMeta> serviceMetaList, String md5OfList) {
|
||||
this.serviceMetaList = serviceMetaList;
|
||||
this.md5OfList = md5OfList;
|
||||
}
|
||||
|
||||
public ServiceMetaObject() {
|
||||
}
|
||||
|
||||
public List<ServiceMeta> getServiceMetaList() {
|
||||
return serviceMetaList;
|
||||
}
|
||||
|
||||
public void setServiceMetaList(List<ServiceMeta> serviceMetaList) {
|
||||
this.serviceMetaList = serviceMetaList;
|
||||
}
|
||||
|
||||
public String getMd5OfList() {
|
||||
return md5OfList;
|
||||
}
|
||||
|
||||
public void setMd5OfList(String md5OfList) {
|
||||
this.md5OfList = md5OfList;
|
||||
}
|
||||
|
||||
public String getMeta() {
|
||||
return meta;
|
||||
}
|
||||
|
||||
public void setMeta(String meta) {
|
||||
this.meta = meta;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServiceMetaObject{" + "serviceMetaList=" + serviceMetaList
|
||||
+ ", md5OfList='" + md5OfList + '\'' + '}';
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.appactive.common;
|
||||
|
||||
/**
|
||||
* @author raozihao, mageekchiu
|
||||
* @author <a href="mailto:zihaorao@gmail.com">Steve</a>
|
||||
*/
|
||||
public final class UriContext {
|
||||
|
||||
private UriContext() {
|
||||
}
|
||||
|
||||
private static final ThreadLocal<String> URI_INFO = new ThreadLocal<String>();
|
||||
|
||||
public static void clearContext() {
|
||||
URI_INFO.remove();
|
||||
}
|
||||
|
||||
public static String getUriPath() {
|
||||
return URI_INFO.get();
|
||||
}
|
||||
|
||||
public static void setUriPath(String targetUnit) {
|
||||
URI_INFO.set(targetUnit);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.appactive.config;
|
||||
|
||||
import com.alibaba.cloud.appactive.AppactiveProperties;
|
||||
import com.alibaba.cloud.appactive.provider.CoreServiceFilter;
|
||||
import com.alibaba.cloud.appactive.provider.GlobalServiceFilter;
|
||||
import io.appactive.servlet.RequestFilter;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author ChengPu raozihao
|
||||
* @description
|
||||
* @date 2022/8/15
|
||||
*/
|
||||
@Configuration
|
||||
public class FilterAutoConfiguration {
|
||||
|
||||
@Autowired
|
||||
private AppactiveProperties appactiveProperties;
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<GlobalServiceFilter> appActiveCenterServiceFilter() {
|
||||
if (appactiveProperties.getGlobalPath() == null) {
|
||||
return null;
|
||||
}
|
||||
FilterRegistrationBean<GlobalServiceFilter> filterRegistrationBean = new FilterRegistrationBean<>();
|
||||
GlobalServiceFilter reqResFilter = new GlobalServiceFilter();
|
||||
filterRegistrationBean.setFilter(reqResFilter);
|
||||
filterRegistrationBean.addUrlPatterns(appactiveProperties.getGlobalPath());
|
||||
return filterRegistrationBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<CoreServiceFilter> appActiveUnitServiceFilter() {
|
||||
if (appactiveProperties.getCorePath() == null) {
|
||||
return null;
|
||||
}
|
||||
FilterRegistrationBean<CoreServiceFilter> filterRegistrationBean = new FilterRegistrationBean<>();
|
||||
CoreServiceFilter reqResFilter = new CoreServiceFilter();
|
||||
filterRegistrationBean.setFilter(reqResFilter);
|
||||
filterRegistrationBean.addUrlPatterns(appactiveProperties.getCorePath());
|
||||
return filterRegistrationBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<RequestFilter> appActiveNormalServiceFilter() {
|
||||
if (appactiveProperties.getGeneralPath() == null) {
|
||||
return null;
|
||||
}
|
||||
FilterRegistrationBean<RequestFilter> filterRegistrationBean = new FilterRegistrationBean<>();
|
||||
RequestFilter reqResFilter = new RequestFilter();
|
||||
filterRegistrationBean.setFilter(reqResFilter);
|
||||
filterRegistrationBean.addUrlPatterns(appactiveProperties.getGeneralPath());
|
||||
return filterRegistrationBean;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.appactive.config;
|
||||
|
||||
import com.alibaba.cloud.appactive.AppactiveProperties;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author ChengPu raozihao
|
||||
* @description
|
||||
* @date 2022/8/15
|
||||
*/
|
||||
@Configuration
|
||||
public class FilterPropertiesAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public AppactiveProperties appactiveProperties() {
|
||||
return new AppactiveProperties();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.appactive.constant;
|
||||
|
||||
/**
|
||||
* @author raozihao, mageekchiu
|
||||
* @author <a href="mailto:zihaorao@gmail.com">Steve</a>
|
||||
*/
|
||||
public final class Constants {
|
||||
|
||||
/**
|
||||
* Router Id header key.
|
||||
*/
|
||||
public static final String ROUTER_ID_HEADER_KEY = "appactive-router-id";
|
||||
|
||||
private Constants() {
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.appactive.consumer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.alibaba.cloud.appactive.common.ServiceMeta;
|
||||
import com.alibaba.cloud.appactive.common.UriContext;
|
||||
import com.alibaba.cloud.nacos.ribbon.NacosServer;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.netflix.client.config.IClientConfig;
|
||||
import com.netflix.loadbalancer.AbstractServerPredicate;
|
||||
import com.netflix.loadbalancer.IRule;
|
||||
import com.netflix.loadbalancer.PredicateKey;
|
||||
import io.appactive.java.api.base.AppContextClient;
|
||||
import io.appactive.java.api.base.constants.AppactiveConstant;
|
||||
import io.appactive.java.api.base.constants.ResourceActiveType;
|
||||
import io.appactive.java.api.rule.traffic.TrafficRouteRuleService;
|
||||
import io.appactive.java.api.utils.lang.StringUtils;
|
||||
import io.appactive.rule.ClientRuleService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
|
||||
/**
|
||||
* @author ChengPu raozihao
|
||||
* @description
|
||||
* @date 2022/8/20
|
||||
*/
|
||||
public class AppactivePredicate extends AbstractServerPredicate {
|
||||
|
||||
private static final Logger logger = LoggerFactory
|
||||
.getLogger(AppactivePredicate.class);
|
||||
|
||||
private final TrafficRouteRuleService trafficRouteRuleService = ClientRuleService
|
||||
.getTrafficRouteRuleService();
|
||||
|
||||
private final AntPathMatcher antPathMatcher = new AntPathMatcher();
|
||||
|
||||
public AppactivePredicate(IRule rule, IClientConfig clientConfig) {
|
||||
super(rule, clientConfig);
|
||||
}
|
||||
|
||||
public AppactivePredicate(IRule rule) {
|
||||
super(rule);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(PredicateKey predicateKey) {
|
||||
// Just support Nacos Registry now, if it's a NacosServer, return true directly.
|
||||
if (!(predicateKey.getServer() instanceof NacosServer)) {
|
||||
return true;
|
||||
}
|
||||
NacosServer server = (NacosServer) predicateKey.getServer();
|
||||
|
||||
// uriPath of the request.
|
||||
String uriPath = UriContext.getUriPath();
|
||||
Map<String, String> metadata = server.getMetadata();
|
||||
// zone
|
||||
String unitType = metadata.get("ut");
|
||||
String svcMeta = metadata.get("svc_meta");
|
||||
String version = metadata.get("svc_meta_v");
|
||||
if (unitType == null || svcMeta == null || version == null) {
|
||||
return true;
|
||||
}
|
||||
String serviceType = null;
|
||||
List<ServiceMeta> serviceMetas = JSONObject.parseArray(svcMeta,
|
||||
ServiceMeta.class);
|
||||
Map<String, String> matchingPatterns = new HashMap<>();
|
||||
for (ServiceMeta sm : serviceMetas) {
|
||||
if (antPathMatcher.match(sm.getUriPrefix(), uriPath)) {
|
||||
matchingPatterns.put(sm.getUriPrefix(), sm.getRa());
|
||||
}
|
||||
}
|
||||
Comparator<String> patternComparator = antPathMatcher
|
||||
.getPatternComparator(uriPath);
|
||||
if (!matchingPatterns.isEmpty()) {
|
||||
List<String> urls = new ArrayList<>(matchingPatterns.keySet());
|
||||
urls.sort(patternComparator);
|
||||
serviceType = matchingPatterns.get(urls.get(0));
|
||||
}
|
||||
|
||||
if (!StringUtils.isBlank(serviceType) && ResourceActiveType.CENTER_RESOURCE_TYPE
|
||||
.equalsIgnoreCase(serviceType)) {
|
||||
return AppactiveConstant.CENTER_FLAG.equalsIgnoreCase(unitType);
|
||||
}
|
||||
else if (!StringUtils.isBlank(serviceType)
|
||||
&& ResourceActiveType.UNIT_RESOURCE_TYPE.equalsIgnoreCase(serviceType)) {
|
||||
// routeId of the request.
|
||||
String routeId = AppContextClient.getRouteId();
|
||||
if (routeId == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// targetUnit setting by users, such as unit0,unit1,...,unitn.
|
||||
String targetUnitByRouteId = trafficRouteRuleService
|
||||
.getUnitByRouteId(routeId);
|
||||
return !StringUtils.isBlank(targetUnitByRouteId)
|
||||
&& targetUnitByRouteId.equalsIgnoreCase(unitType);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.appactive.consumer;
|
||||
|
||||
import com.netflix.loadbalancer.AbstractServerPredicate;
|
||||
import com.netflix.loadbalancer.CompositePredicate;
|
||||
import com.netflix.loadbalancer.ILoadBalancer;
|
||||
import com.netflix.loadbalancer.PredicateBasedRule;
|
||||
|
||||
/**
|
||||
* @description
|
||||
* @author ChengPu raozihao
|
||||
* @date 2022/8/21
|
||||
*/
|
||||
public class AppactiveRule extends PredicateBasedRule {
|
||||
|
||||
private AbstractServerPredicate predicate;
|
||||
|
||||
public AppactiveRule() {
|
||||
super();
|
||||
predicate = CompositePredicate.withPredicate(new AppactivePredicate(this, null))
|
||||
.addFallbackPredicate(AbstractServerPredicate.alwaysTrue()).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoadBalancer(ILoadBalancer lb) {
|
||||
super.setLoadBalancer(lb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractServerPredicate getPredicate() {
|
||||
return predicate;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.appactive.consumer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import feign.RequestInterceptor;
|
||||
import feign.codec.Decoder;
|
||||
import feign.optionals.OptionalDecoder;
|
||||
import io.appactive.support.lang.CollectionUtils;
|
||||
import io.appactive.support.log.LogUtil;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
||||
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
|
||||
import org.springframework.cloud.openfeign.support.SpringDecoder;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* @author raozihao, mageekchiu
|
||||
* @author <a href="mailto:zihaorao@gmail.com">Steve</a>
|
||||
*/
|
||||
@Configuration
|
||||
public class ConsumerAutoConfig {
|
||||
|
||||
private static final Logger logger = LogUtil.getLogger();
|
||||
|
||||
@Autowired
|
||||
ApplicationContext context;
|
||||
|
||||
@Autowired(required = false)
|
||||
RestTemplate restTemplate;
|
||||
|
||||
@Autowired
|
||||
private ObjectFactory<HttpMessageConverters> messageConverters;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Decoder appActiveFeignDecoder() {
|
||||
return new OptionalDecoder(
|
||||
new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BeanPostProcessor feignDecoderPostProcessor() {
|
||||
return new FeignDecoderPostProcessor(context);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RequestInterceptor routerIdTransmissionRequestInterceptor() {
|
||||
return new RouterIdTransmissionRequestInterceptor();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
if (restTemplate != null) {
|
||||
List<ClientHttpRequestInterceptor> interceptors = restTemplate
|
||||
.getInterceptors();
|
||||
if (CollectionUtils.isEmpty(interceptors)) {
|
||||
interceptors = new ArrayList<>();
|
||||
}
|
||||
interceptors.add(new ReqResInterceptor());
|
||||
logger.info(
|
||||
"ConsumerAutoConfig adding interceptor for restTemplate[{}]......",
|
||||
restTemplate.getClass());
|
||||
restTemplate.setInterceptors(interceptors);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.appactive.consumer;
|
||||
|
||||
import feign.codec.Decoder;
|
||||
import io.appactive.support.log.LogUtil;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* @author raozihao, mageekchiu
|
||||
* @author <a href="mailto:zihaorao@gmail.com">Steve</a>
|
||||
*/
|
||||
public class FeignDecoderPostProcessor implements BeanPostProcessor {
|
||||
|
||||
private static final Logger logger = LogUtil.getLogger();
|
||||
|
||||
final ApplicationContext context;
|
||||
|
||||
public FeignDecoderPostProcessor(ApplicationContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
// there does`t have to be a Decoder(when using default), so we added a default
|
||||
if (bean instanceof Decoder) {
|
||||
if ("appActiveFeignDecoder".equals(beanName)) {
|
||||
logger.info(
|
||||
"FeignDecoderPostProcessor replacing defaultDecoder {} ......",
|
||||
beanName);
|
||||
}
|
||||
else {
|
||||
logger.info(
|
||||
"FeignDecoderPostProcessor replacing customizedDecoder {} ......",
|
||||
beanName);
|
||||
}
|
||||
Decoder decoder = (Decoder) bean;
|
||||
// wrap original decoder
|
||||
return new ResponseInterceptor(decoder);
|
||||
|
||||
/// another way
|
||||
// Object proxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(),
|
||||
// bean.getClass().getInterfaces(),
|
||||
// (proxy1, method, args) -> {
|
||||
// String result = (String) method.invoke(bean, args);
|
||||
// return result.toUpperCase();
|
||||
// });
|
||||
// return proxy;
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.appactive.consumer;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.alibaba.cloud.appactive.common.UriContext;
|
||||
import com.alibaba.cloud.appactive.constant.Constants;
|
||||
import io.appactive.java.api.base.AppContextClient;
|
||||
import io.appactive.support.log.LogUtil;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
|
||||
/**
|
||||
* @author raozihao, mageekchiu
|
||||
* @author <a href="mailto:zihaorao@gmail.com">Steve</a>
|
||||
*/
|
||||
public class ReqResInterceptor implements ClientHttpRequestInterceptor {
|
||||
|
||||
private static final Logger logger = LogUtil.getLogger();
|
||||
|
||||
@Override
|
||||
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
|
||||
ClientHttpRequestExecution execution) throws IOException {
|
||||
|
||||
request.getHeaders().add(Constants.ROUTER_ID_HEADER_KEY,
|
||||
AppContextClient.getRouteId());
|
||||
UriContext.setUriPath(request.getURI().getPath());
|
||||
|
||||
ClientHttpResponse response = execution.execute(request, body);
|
||||
|
||||
logger.info("ReqResInterceptor uri {} for request {} got cleared",
|
||||
UriContext.getUriPath(), request.getURI());
|
||||
UriContext.clearContext();
|
||||
return response;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.appactive.consumer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Objects;
|
||||
|
||||
import com.alibaba.cloud.appactive.common.UriContext;
|
||||
import feign.FeignException;
|
||||
import feign.Response;
|
||||
import feign.codec.Decoder;
|
||||
import io.appactive.support.log.LogUtil;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
/**
|
||||
* @author raozihao, mageekchiu
|
||||
* @author <a href="mailto:zihaorao@gmail.com">Steve</a>
|
||||
*/
|
||||
public class ResponseInterceptor implements Decoder {
|
||||
|
||||
private static final Logger logger = LogUtil.getLogger();
|
||||
|
||||
final Decoder delegate;
|
||||
|
||||
public ResponseInterceptor(Decoder delegate) {
|
||||
Objects.requireNonNull(delegate, "Decoder must not be null. ");
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object decode(Response response, Type type)
|
||||
throws IOException, FeignException {
|
||||
Object object = delegate.decode(response, type);
|
||||
logger.info("ResponseInterceptor uri {} for request {} got cleared by {}",
|
||||
UriContext.getUriPath(), response.request().url(), delegate.getClass());
|
||||
UriContext.clearContext();
|
||||
return object;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.appactive.consumer;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.alibaba.cloud.appactive.common.UriContext;
|
||||
import com.alibaba.cloud.appactive.constant.Constants;
|
||||
import feign.RequestInterceptor;
|
||||
import feign.RequestTemplate;
|
||||
import io.appactive.java.api.base.AppContextClient;
|
||||
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
/**
|
||||
* @author raozihao, mageekchiu
|
||||
* @author <a href="mailto:zihaorao@gmail.com">Steve</a>
|
||||
*/
|
||||
public class RouterIdTransmissionRequestInterceptor implements RequestInterceptor {
|
||||
|
||||
@Override
|
||||
public void apply(RequestTemplate requestTemplate) {
|
||||
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
|
||||
.getRequestAttributes();
|
||||
if (requestAttributes == null) {
|
||||
return;
|
||||
}
|
||||
HttpServletRequest request = requestAttributes.getRequest();
|
||||
if (request == null) {
|
||||
return;
|
||||
}
|
||||
requestTemplate.header(Constants.ROUTER_ID_HEADER_KEY,
|
||||
AppContextClient.getRouteId());
|
||||
// store uri for routing filter
|
||||
UriContext.setUriPath(requestTemplate.url());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.appactive.consumer;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.netflix.loadbalancer.Server;
|
||||
|
||||
/**
|
||||
* @author raozihao, mageekchiu
|
||||
* @author <a href="mailto:zihaorao@gmail.com">Steve</a>
|
||||
*/
|
||||
public interface ServerMeta {
|
||||
|
||||
Map<String, String> getMetaMap(Server server);
|
||||
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.appactive.provider;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.alibaba.cloud.appactive.constant.Constants;
|
||||
import io.appactive.java.api.base.AppContextClient;
|
||||
import io.appactive.java.api.base.constants.AppactiveConstant;
|
||||
import io.appactive.java.api.bridge.servlet.ServletService;
|
||||
import io.appactive.java.api.rule.TrafficMachineService;
|
||||
import io.appactive.java.api.rule.machine.AbstractMachineUnitRuleService;
|
||||
import io.appactive.java.api.rule.traffic.TrafficRouteRuleService;
|
||||
import io.appactive.java.api.utils.lang.StringUtils;
|
||||
import io.appactive.rule.ClientRuleService;
|
||||
import io.appactive.support.log.LogUtil;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
/**
|
||||
* @author raozihao, mageekchiu
|
||||
* @author <a href="mailto:zihaorao@gmail.com">Steve</a>
|
||||
*/
|
||||
public class CoreServiceFilter implements Filter {
|
||||
|
||||
private final TrafficRouteRuleService trafficRouteRuleService = ClientRuleService
|
||||
.getTrafficRouteRuleService();
|
||||
|
||||
private final AbstractMachineUnitRuleService machineUnitRuleService = ClientRuleService
|
||||
.getMachineUnitRuleService();
|
||||
|
||||
private final TrafficMachineService trafficMachineService = new TrafficMachineService(
|
||||
trafficRouteRuleService, machineUnitRuleService);
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response,
|
||||
FilterChain chain) throws IOException, ServletException {
|
||||
if (!(request instanceof HttpServletRequest
|
||||
&& response instanceof HttpServletResponse)) {
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
String routerId = ServletService.getRouteIdFromHeader(httpRequest,
|
||||
Constants.ROUTER_ID_HEADER_KEY);
|
||||
if (StringUtils.isBlank(routerId)) {
|
||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN,
|
||||
"no routerId provided for this request");
|
||||
}
|
||||
if (!trafficMachineService.isInCurrentUnit(routerId)) {
|
||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN,
|
||||
"routerId " + routerId + " does not belong in core : "
|
||||
+ machineUnitRuleService.getCurrentUnit());
|
||||
}
|
||||
AppContextClient.setUnitContext(routerId);
|
||||
LogUtil.info(AppactiveConstant.PROJECT_NAME + "-routerIdFilter-doFilter-header:"
|
||||
+ AppContextClient.getRouteId());
|
||||
chain.doFilter(request, response);
|
||||
clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
|
||||
private void clear() {
|
||||
AppContextClient.clearUnitContext();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.appactive.provider;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
/**
|
||||
* @author raozihao, mageekchiu
|
||||
* @author <a href="mailto:zihaorao@gmail.com">Steve</a>
|
||||
*/
|
||||
public class GeneralServiceFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response,
|
||||
FilterChain chain) throws IOException, ServletException {
|
||||
// todo
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
|
||||
}
|