正文
依赖管理
<!-- bootstrap最高级启动配置读取 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<version>3.1.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.ctrip.framework.apollo/apollo-client -->
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-openapi</artifactId>
<version>2.1.0</version>
</dependency>
application.properties
# Apollo
app.id=MORE-USER-USE
apollo.cache-dir=./ManyUser/apollo/cache
apollo.bootstrap.enabled=true
#apollo.bootstrap.namespaces=application.properties
apollo.meta=http://localhost:8080
apollo.bootstrap.eagerLoad.enabled=true
apollo.config-service=http://localhost:8080
env=DEV
apollo.use.admin.token=809d168da6f3baa39c02c1d376a0cc9cec852fa0fa8c6e2cff9b33e276d3738a
apollo.use.portal.url=http://localhost:8070
apollo-env.properties
dev.meta=http://localhost:8080
启动类 加入 @EnableApolloConfig
/**
* @description: 启动类
* @author: GuoTong
* @createTime: 2023-06-21 20:31
* @since JDK 1.8 OR 11
**/
@SpringBootApplication
@EnableApolloConfig
public class AppStartClass {
public static void main(String[] args) {
SpringApplication.run(AppStartClass.class, args);
}
}
常规配置中心集成使用
package com.gton.user.config;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
import com.gton.user.io.Resp;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* @description: Apollo同时还增加了几个新的Annotation来简化在Spring环境中的使用。
* @author: GuoTong
* @createTime: 2023-06-24 12:30
* @since JDK 1.8 OR 11
**/
@Component
@Slf4j
public class MyApolloConfig {
/**
* ApolloJsonValue annotated on fields example, the default value is specified as empty list - []
* <br />
* jsonBeanProperty=[{"someString":"hello","someInt":100},{"someString":"world!","someInt":200}]
*/
@ApolloJsonValue("${jsonBeanProperty:[]}")
private List<Resp> anotherJsonBeans = new ArrayList<>();
@Value("${batch:100}")
private String batch;
//config change listener for namespace application
@ApolloConfigChangeListener(value = "application")
private void apolloChange(ConfigChangeEvent changeEvent) {
//update injected value of batch if it is changed in Apollo
if (changeEvent.isChanged("batch")) {
batch = changeEvent.getChange("batch").getNewValue();
}
log.info(changeEvent.getNamespace() + "变化的key=>" + changeEvent.changedKeys() + ";==1");
}
@ApolloConfigChangeListener(value = "order")
private void someOnChange(ConfigChangeEvent changeEvent) {
//update injected value of batch if it is changed in Apollo
if (changeEvent.isChanged("anotherJsonBeans")) {
log.info(changeEvent.getChange("anotherJsonBeans").getOldValue());
log.error(changeEvent.getChange("anotherJsonBeans").getNewValue());
}
log.info(anotherJsonBeans.toString());
log.info(changeEvent.getNamespace() + "变化的key=>" + changeEvent.changedKeys() + ";==1");
}
}
Apollo 的开放平台使用
package com.gton.user.handler;
import com.ctrip.framework.apollo.openapi.client.ApolloOpenApiClient;
import com.ctrip.framework.apollo.openapi.dto.NamespaceReleaseDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenAppNamespaceDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenItemDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenPageDTO;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.ClassPathResource;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Properties;
/**
* @description: Apollo开放平台操作
* @author: GuoTong
* @createTime: 2023-06-24 14:10
* @since JDK 1.8 OR 11
**/
public class ApolloOpenApiOperator {
private ApolloOpenApiClient apolloOpenApiClient;
private static ApolloOpenApiOperator apolloOpenApiOperator = null;
public static ApolloOpenApiOperator getApolloOpenApiOperator() throws IOException {
if (apolloOpenApiOperator == null) {
synchronized (ApolloOpenApiOperator.class) {
if (apolloOpenApiOperator == null) {
return new ApolloOpenApiOperator();
}
}
}
return apolloOpenApiOperator;
}
public ApolloOpenApiOperator(ApolloOpenApiClient apolloOpenApiClient) {
this.apolloOpenApiClient = apolloOpenApiClient;
}
public ApolloOpenApiOperator() throws IOException {
initApolloOpenApiOperator();
}
private void initApolloOpenApiOperator() throws IOException {
// 获取配置文件
ClassPathResource classPathResource = new ClassPathResource("application.properties");
InputStream inputStream = classPathResource.getInputStream();
// 使用properties加载
Properties properties = new Properties();
properties.load(inputStream);
String token = properties.getProperty("apollo.use.admin.token");
String portalUrl = properties.getProperty("apollo.use.portal.url");
if (StringUtils.isNotEmpty(token)) {
this.apolloOpenApiClient = ApolloOpenApiClient
.newBuilder().
withConnectTimeout(60000).
withToken(token).
withPortalUrl(portalUrl).
withReadTimeout(60000)
.build();
}
}
public ApolloOpenApiClient getApolloOpenApiClient() {
return this.apolloOpenApiClient;
}
/**
* Description: 创建NamSpace
*
* @param openAppNamespaceKey
* @author: GuoTong
* @date: 2023-06-24 15:04:44
* @return:void
*/
public void crateNameSpace(OpenAppNamespaceKey openAppNamespaceKey) {
OpenAppNamespaceDTO openAppNamespaceDTO = new OpenAppNamespaceDTO();
openAppNamespaceDTO.setAppId(openAppNamespaceKey.getAppId());
openAppNamespaceDTO.setName(openAppNamespaceKey.getSpaceName());
openAppNamespaceDTO.setComment(openAppNamespaceKey.getSpaceDesc());
openAppNamespaceDTO.setPublic(openAppNamespaceKey.spaceIsPub);
apolloOpenApiClient.createAppNamespace(openAppNamespaceDTO);
}
/**
* Description: 下发Apollo
*
* @param doIssueApolloKey
* @author: GuoTong
* @date: 2023-06-24 14:35:52
* @return:void
*/
public void doIssueApollo(DoIssueApolloKey doIssueApolloKey) {
OpenItemDTO openItemDTO = new OpenItemDTO();
openItemDTO.setKey(doIssueApolloKey.getKey());
openItemDTO.setValue(doIssueApolloKey.getValue());
openItemDTO.setComment(doIssueApolloKey.getDesc());
openItemDTO.setType(doIssueApolloKey.handlerValueType(doIssueApolloKey.getValueType()));
openItemDTO.setDataChangeCreatedBy(doIssueApolloKey.getOperator());
if (doIssueApolloKey.isModifiedOrInsert()) {
openItemDTO.setDataChangeLastModifiedBy(doIssueApolloKey.getOperator());
}
// 下发到Apollo
apolloOpenApiClient.createOrUpdateItem(
doIssueApolloKey.getAppId(),
doIssueApolloKey.getEnv(),
doIssueApolloKey.getClusterName(),
doIssueApolloKey.getNamespaceName(),
openItemDTO
);
}
/**
* Description: 发布整个NameSpace;推荐下发完成之后统一调一次,不要多次的下发操作,每一次下发都调用
*
* @param publishApolloKey
* @author: GuoTong
* @date: 2023-06-24 14:56:43
* @return:void
*/
public void executorPublish(PublishApolloKey publishApolloKey) {
// apollo下发的数据执行发布
NamespaceReleaseDTO namespaceReleaseDTO = new NamespaceReleaseDTO();
//配置版本名称
namespaceReleaseDTO.setReleaseTitle(publishApolloKey.getReleaseTitle());
// 发布说明
namespaceReleaseDTO.setReleaseComment(publishApolloKey.getReleaseDescription());
// 操作员
namespaceReleaseDTO.setReleasedBy(publishApolloKey.getReleaseOperator());
apolloOpenApiClient.publishNamespace(publishApolloKey.getAppId(),
publishApolloKey.getEnv(),
publishApolloKey.getClusterName(),
publishApolloKey.getNamespaceName(), namespaceReleaseDTO);
}
/**
* Description: 移除Apollo的配置
* String appId, String env, String clusterName, String namespaceName, String key,
* String operator
*
* @param removeKeys
* @author: GuoTong
* @date: 2023-06-24 15:27:07
* @return:void
*/
public void executorRemove(DoIssueApolloKey removeKeys) {
apolloOpenApiClient.removeItem(removeKeys.getAppId(),
removeKeys.getEnv(),
removeKeys.getClusterName(),
removeKeys.getNamespaceName(), removeKeys.getKey(), removeKeys.getOperator());
}
/**
* queryApolloKey many
*
* @param baseApolloKey
* @author: GuoTong
* @date: 2023-06-24 14:56:43
* @return:void
*/
public List<OpenItemDTO> queryApolloKey(BaseApolloKey baseApolloKey, int page, int size) {
if (page <= 1) {
page = 0;
}
if (size <= 0) {
size = 10;
}
OpenPageDTO<OpenItemDTO> itemsByNamespace = apolloOpenApiClient.findItemsByNamespace(baseApolloKey.getAppId(),
baseApolloKey.getEnv(),
baseApolloKey.getClusterName(),
baseApolloKey.getNamespaceName(), page, size);
List<OpenItemDTO> content = itemsByNamespace.getContent();
return content;
}
/**
* queryApolloKey one
*
* @param baseApolloKey
* @author: GuoTong
* @date: 2023-06-24 14:56:43
* @return:void
*/
public OpenItemDTO queryApolloKeyOne(DoIssueApolloKey baseApolloKey) {
OpenItemDTO itemsByNamespace = apolloOpenApiClient.getItem(baseApolloKey.getAppId(),
baseApolloKey.getEnv(),
baseApolloKey.getClusterName(),
baseApolloKey.getNamespaceName(), baseApolloKey.getKey());
return itemsByNamespace;
}
@Data
public static class OpenAppNamespaceKey {
private String appId;
private String spaceName;
private String spaceDesc;
private boolean spaceIsPub = false;
// 默认值 DEV
private String env = "DEV";
private String clusterName;
private String namespaceName;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class DoIssueApolloKey extends BaseApolloKey {
private String key;
private String value;
// 默认值 Apollo
private String operator = "Apollo";
private String desc;
private String valueType;
// 是否是修改
private boolean modifiedOrInsert;
/**
* Description: 查询 Portal web的前端得出
*
* @author: GuoTong
* @date: 2023-06-24 14:46:42
* <select class="form-control ng-valid ng-valid-valdr ng-not-empty ng-dirty ng-touched ng-valid-parse" name="type" ng-model="item.type" ng-change="changeType()">
* <option value="0" class="ng-binding">String</option>
* <option value="1" class="ng-binding">Number</option>
* <option value="2" class="ng-binding">Boolean</option>
* <option value="3" class="ng-binding">JSON</option>
* </select>
*/
public int handlerValueType(String valueType) {
switch (valueType) {
case "String":
return 0;
case "Number":
return 1;
case "Boolean":
return 2;
case "JSON":
return 3;
}
// 未匹配就默认使用String的值
return 0;
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class BaseApolloKey {
protected String appId;
// 默认值 DEV
protected String env = "DEV";
// 默认值 default
protected String clusterName = "default";
protected String namespaceName;
}
@Data
public static class PublishApolloKey extends BaseApolloKey {
// 发布时候的标题
private String releaseTitle;
// 发布时候的操作员
private String releaseOperator;
// 发布时候的DESC
private String releaseDescription;
}
}
配合Controller使用
package com.gton.user.controller;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ctrip.framework.apollo.openapi.dto.OpenItemDTO;
import com.gton.user.annotation.SwaggerScanClass;
import com.gton.user.handler.ApolloOpenApiOperator;
import com.gton.user.io.Resp;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* 多租户表(apollo)表控制层
*
* @author 郭童
* @since 2023-06-22 16:28:10
*/
@RestController
@RequestMapping("apollo")
@SwaggerScanClass
public class ApolloOperatorController {
/**
* 分页查询数据 namespaceName
*
* @param
* @return 所有数据
*/
@PostMapping("/queryLimit")
@ApiOperation("查询Apollo配置")
public Resp<List<OpenItemDTO>> queryPage(
@RequestParam("appId") String appId,
@RequestParam("clusterName") String clusterName,
@RequestParam("env") String env,
@RequestParam("namespaceName") String namespaceName
) throws IOException {
ApolloOpenApiOperator apolloOpenApiOperator = ApolloOpenApiOperator.getApolloOpenApiOperator();
ApolloOpenApiOperator.BaseApolloKey baseApolloKey = new ApolloOpenApiOperator.BaseApolloKey();
baseApolloKey.setAppId(appId);
baseApolloKey.setClusterName(clusterName);
baseApolloKey.setEnv(env);
baseApolloKey.setNamespaceName(namespaceName);
List<OpenItemDTO> openItemDTOS = apolloOpenApiOperator.queryApolloKey(baseApolloKey, 0, 10);
return Resp.Ok(openItemDTOS);
}
/**
* 通过主键查询单条数据
*
* @param key apollo-key
* @return 单条数据
*/
@GetMapping("/queryOne/{key}")
public Resp<OpenItemDTO> selectOne(@PathVariable("key") String key,
@RequestParam("appId") String appId,
@RequestParam("clusterName") String clusterName,
@RequestParam("env") String env,
@RequestParam("namespaceName") String namespaceName) throws IOException {
ApolloOpenApiOperator apolloOpenApiOperator = ApolloOpenApiOperator.getApolloOpenApiOperator();
ApolloOpenApiOperator.DoIssueApolloKey baseApolloKey = new ApolloOpenApiOperator.DoIssueApolloKey();
baseApolloKey.setAppId(appId);
baseApolloKey.setEnv(env);
baseApolloKey.setNamespaceName(namespaceName);
baseApolloKey.setClusterName(clusterName);
baseApolloKey.setKey(key);
OpenItemDTO openItemDTO = apolloOpenApiOperator.queryApolloKeyOne(baseApolloKey);
return Resp.Ok(openItemDTO);
}
/**
* 新增数据 到Apollo
*
* @param doIssueApolloKey 实体对象
* @return 新增结果
*/
@PostMapping("/save")
public Resp<String> insert(@RequestBody Map<String, String> doIssueApolloKey) throws IOException {
String json = JSON.toJSONString(doIssueApolloKey);
ApolloOpenApiOperator.DoIssueApolloKey doIssueApolloData = JSONObject.parseObject(json, ApolloOpenApiOperator.DoIssueApolloKey.class);
ApolloOpenApiOperator apolloOpenApiOperator = ApolloOpenApiOperator.getApolloOpenApiOperator();
doIssueApolloData.setModifiedOrInsert(false);
apolloOpenApiOperator.doIssueApollo(doIssueApolloData);
return Resp.Ok(doIssueApolloData.getKey());
}
/**
* 修改数据
*
* @param doIssueApolloKey 实体对象
* @return 修改结果
*/
@PutMapping("/update")
public Resp<String> update(@RequestBody Map<String, String> doIssueApolloKey) throws IOException {
String json = JSON.toJSONString(doIssueApolloKey);
ApolloOpenApiOperator.DoIssueApolloKey doIssueApolloData = JSONObject.parseObject(json, ApolloOpenApiOperator.DoIssueApolloKey.class);
ApolloOpenApiOperator apolloOpenApiOperator = ApolloOpenApiOperator.getApolloOpenApiOperator();
doIssueApolloData.setModifiedOrInsert(true);
apolloOpenApiOperator.doIssueApollo(doIssueApolloData);
return Resp.Ok(doIssueApolloData.getKey());
}
/**
* Description: 移出Apollo已下发数据
*
* @param key
* @param appId
* @param clusterName
* @param env
* @param namespaceName
* @author: GuoTong
* @date: 2023-06-24 15:42:24
* @return:com.gton.user.io.Resp<java.lang.String>
*/
@GetMapping("/dels")
public Resp<String> delete(@RequestParam("key") String key,
@RequestParam("appId") String appId,
@RequestParam("clusterName") String clusterName,
@RequestParam("env") String env,
@RequestParam("namespaceName") String namespaceName) throws IOException {
ApolloOpenApiOperator apolloOpenApiOperator = ApolloOpenApiOperator.getApolloOpenApiOperator();
ApolloOpenApiOperator.DoIssueApolloKey removeKeys = new ApolloOpenApiOperator.DoIssueApolloKey();
removeKeys.setAppId(appId);
removeKeys.setEnv(env);
removeKeys.setNamespaceName(namespaceName);
removeKeys.setClusterName(clusterName);
removeKeys.setKey(key);
apolloOpenApiOperator.executorRemove(removeKeys);
return Resp.Ok(removeKeys.getKey());
}
}