feat(integration): 添加 ZT-Scenic 集成服务模块

- 新增 FeignConfig、IntegrationProperties 等基础配置类
- 实现自定义 FeignErrorDecoder 和 IntegrationException
- 添加 CommonResponse 和 PageResponse 等通用响应模型
- 定义多个 Feign 客户端接口,用于调用 ZT-Scenic 服务
- 实现 DefaultConfigIntegrationService 和 ScenicConfigIntegrationService 服务类
- 添加 ScenicIntegrationExample 示例类,展示如何使用集成服务
This commit is contained in:
2025-08-26 13:36:06 +08:00
parent e694aac928
commit 32feaa9692
37 changed files with 1181 additions and 2 deletions

View File

@@ -0,0 +1,32 @@
package com.ycwl.basic.integration.common.config;
import com.ycwl.basic.integration.common.exception.FeignErrorDecoder;
import feign.RequestInterceptor;
import feign.codec.ErrorDecoder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Slf4j
@Configuration
@RequiredArgsConstructor
public class FeignConfig {
private final FeignErrorDecoder feignErrorDecoder;
@Bean
public ErrorDecoder errorDecoder() {
return feignErrorDecoder;
}
@Bean
public RequestInterceptor requestInterceptor() {
return template -> {
template.header("Accept", "application/json");
template.header("Content-Type", "application/json");
// 可以在这里添加统一的鉴权头
// template.header("Authorization", "Bearer " + getToken());
};
}
}

View File

@@ -0,0 +1,43 @@
package com.ycwl.basic.integration.common.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
@Data
@Component
@RefreshScope
@ConfigurationProperties(prefix = "integration")
public class IntegrationProperties {
/**
* 景区服务配置
*/
private ScenicConfig scenic = new ScenicConfig();
@Data
public static class ScenicConfig {
/**
* 是否启用景区服务集成
*/
private boolean enabled = true;
/**
* 服务名称
*/
private String serviceName = "zt-scenic";
/**
* 超时配置(毫秒)
*/
private int connectTimeout = 5000;
private int readTimeout = 10000;
/**
* 重试配置
*/
private boolean retryEnabled = false;
private int maxRetries = 3;
}
}

View File

@@ -0,0 +1,60 @@
package com.ycwl.basic.integration.common.exception;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ycwl.basic.integration.common.response.CommonResponse;
import feign.Response;
import feign.codec.ErrorDecoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@Slf4j
@Component
public class FeignErrorDecoder implements ErrorDecoder {
private final ErrorDecoder defaultDecoder = new Default();
private final ObjectMapper objectMapper = new ObjectMapper();
@Override
public Exception decode(String methodKey, Response response) {
log.warn("Feign调用失败, methodKey: {}, status: {}, reason: {}",
methodKey, response.status(), response.reason());
try {
if (response.body() != null) {
String body = new String(response.body().asInputStream().readAllBytes(), StandardCharsets.UTF_8);
log.warn("响应内容: {}", body);
try {
CommonResponse<?> errorResponse = objectMapper.readValue(body, CommonResponse.class);
if (errorResponse.getCode() != null && !errorResponse.getCode().equals(200)) {
return new IntegrationException(
errorResponse.getCode(),
errorResponse.getMessage() != null ? errorResponse.getMessage() : "服务调用失败",
extractServiceName(methodKey)
);
}
} catch (Exception e) {
log.warn("解析错误响应失败", e);
}
}
} catch (IOException e) {
log.error("读取响应体失败", e);
}
return new IntegrationException(
response.status(),
String.format("服务调用失败: %s", response.reason()),
extractServiceName(methodKey)
);
}
private String extractServiceName(String methodKey) {
if (methodKey != null && methodKey.contains("#")) {
return methodKey.substring(0, methodKey.indexOf("#"));
}
return "unknown";
}
}

View File

@@ -0,0 +1,33 @@
package com.ycwl.basic.integration.common.exception;
import lombok.Getter;
@Getter
public class IntegrationException extends RuntimeException {
private final Integer code;
private final String serviceName;
public IntegrationException(Integer code, String message) {
super(message);
this.code = code;
this.serviceName = null;
}
public IntegrationException(Integer code, String message, String serviceName) {
super(message);
this.code = code;
this.serviceName = serviceName;
}
public IntegrationException(Integer code, String message, Throwable cause) {
super(message, cause);
this.code = code;
this.serviceName = null;
}
public IntegrationException(Integer code, String message, String serviceName, Throwable cause) {
super(message, cause);
this.code = code;
this.serviceName = serviceName;
}
}

View File

@@ -0,0 +1,40 @@
package com.ycwl.basic.integration.common.response;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class CommonResponse<T> {
private Integer code;
private String message;
private T data;
public static <T> CommonResponse<T> success() {
return new CommonResponse<>(200, "OK", null);
}
public static <T> CommonResponse<T> success(T data) {
return new CommonResponse<>(200, "OK", data);
}
public static <T> CommonResponse<T> success(String message, T data) {
return new CommonResponse<>(200, message, data);
}
public static <T> CommonResponse<T> error(Integer code, String message) {
return new CommonResponse<>(code, message, null);
}
public static <T> CommonResponse<T> error(String message) {
return new CommonResponse<>(5000, message, null);
}
public boolean isSuccess() {
return code != null && code == 200;
}
}

View File

@@ -0,0 +1,17 @@
package com.ycwl.basic.integration.common.response;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageResponse<T> {
private List<T> list;
private Long total;
private Integer page;
private Integer pageSize;
}

View File

@@ -0,0 +1,28 @@
package com.ycwl.basic.integration.scenic.client;
import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.scenic.dto.config.DefaultConfigDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@FeignClient(name = "zt-scenic", path = "/api/scenic/default-config")
public interface DefaultConfigClient {
@GetMapping("/")
CommonResponse<List<DefaultConfigDTO>> listDefaultConfigs();
@GetMapping("/{configKey}")
CommonResponse<DefaultConfigDTO> getDefaultConfig(@PathVariable("configKey") String configKey);
@PostMapping("/")
CommonResponse<DefaultConfigDTO> createDefaultConfig(@RequestBody DefaultConfigDTO request);
@PutMapping("/{configKey}")
CommonResponse<DefaultConfigDTO> updateDefaultConfig(@PathVariable("configKey") String configKey,
@RequestBody DefaultConfigDTO request);
@DeleteMapping("/{configKey}")
CommonResponse<Void> deleteDefaultConfig(@PathVariable("configKey") String configKey);
}

View File

@@ -0,0 +1,44 @@
package com.ycwl.basic.integration.scenic.client;
import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.scenic.dto.config.*;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@FeignClient(name = "zt-scenic", path = "/api/scenic/config/v2")
public interface ScenicConfigV2Client {
@GetMapping("/{scenicId}")
CommonResponse<List<ScenicConfigV2DTO>> listConfigs(@PathVariable("scenicId") Long scenicId);
@GetMapping("/{scenicId}/key/{configKey}")
CommonResponse<ScenicConfigV2DTO> getConfigByKey(@PathVariable("scenicId") Long scenicId,
@PathVariable("configKey") String configKey);
@GetMapping("/{scenicId}/keys")
CommonResponse<Map<String, Object>> getFlatConfigs(@PathVariable("scenicId") Long scenicId);
@PostMapping("/{scenicId}")
CommonResponse<ScenicConfigV2DTO> createConfig(@PathVariable("scenicId") Long scenicId,
@RequestBody CreateConfigRequest request);
@PutMapping("/{scenicId}/{id}")
CommonResponse<ScenicConfigV2DTO> updateConfig(@PathVariable("scenicId") Long scenicId,
@PathVariable("id") String id,
@RequestBody UpdateConfigRequest request);
@DeleteMapping("/{scenicId}/{id}")
CommonResponse<Void> deleteConfig(@PathVariable("scenicId") Long scenicId,
@PathVariable("id") String id);
@PostMapping("/{scenicId}/batch")
CommonResponse<BatchUpdateResponse> batchUpdateConfigs(@PathVariable("scenicId") Long scenicId,
@RequestBody BatchConfigRequest request);
@PostMapping("/{scenicId}/batchFlatUpdate")
CommonResponse<BatchUpdateResponse> batchFlatUpdateConfigs(@PathVariable("scenicId") Long scenicId,
@RequestBody Map<String, Object> configs);
}

View File

@@ -0,0 +1,15 @@
package com.ycwl.basic.integration.scenic.client;
import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.scenic.dto.config.ConfigWithDefaultResponse;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name = "zt-scenic", path = "/api/scenic/config-with-default")
public interface ScenicConfigWithDefaultClient {
@GetMapping("/{scenicId}/{configKey}")
CommonResponse<ConfigWithDefaultResponse> getConfigWithDefault(@PathVariable("scenicId") Long scenicId,
@PathVariable("configKey") String configKey);
}

View File

@@ -0,0 +1,40 @@
package com.ycwl.basic.integration.scenic.client;
import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.scenic.dto.meta.*;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigDTO;
import com.ycwl.basic.integration.scenic.dto.scenic.UpdateScenicRequest;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@FeignClient(name = "zt-scenic", path = "/api/scenic/meta")
public interface ScenicMetaClient {
@GetMapping("/{scenicId}/fields/enabled")
CommonResponse<EnabledFieldsResponse> getEnabledFields(@PathVariable("scenicId") Long scenicId);
@GetMapping("/fields/all")
CommonResponse<List<FieldConfigDTO>> getAllFields();
@GetMapping("/fields/{fieldKey}")
CommonResponse<FieldConfigDTO> getFieldConfig(@PathVariable("fieldKey") String fieldKey);
@PostMapping("/{scenicId}/fields/{fieldKey}/enabled")
CommonResponse<Void> setFieldEnabled(@PathVariable("scenicId") Long scenicId,
@PathVariable("fieldKey") String fieldKey,
@RequestBody SetFieldEnabledRequest request);
@PostMapping("/{scenicId}/fields/batch-enabled")
CommonResponse<Void> batchSetFieldEnabled(@PathVariable("scenicId") Long scenicId,
@RequestBody BatchSetFieldEnabledRequest request);
@GetMapping("/{scenicId}/with-config")
CommonResponse<ScenicV2WithConfigDTO> getScenicWithConfigEnhanced(@PathVariable("scenicId") Long scenicId);
@PutMapping("/{scenicId}/config")
CommonResponse<Void> updateConfigEnhanced(@PathVariable("scenicId") Long scenicId,
@RequestBody Map<String, Object> configs);
}

View File

@@ -0,0 +1,39 @@
package com.ycwl.basic.integration.scenic.client;
import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.scenic.dto.filter.ScenicFilterPageResponse;
import com.ycwl.basic.integration.scenic.dto.filter.ScenicFilterRequest;
import com.ycwl.basic.integration.scenic.dto.scenic.CreateScenicRequest;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigDTO;
import com.ycwl.basic.integration.scenic.dto.scenic.UpdateScenicRequest;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@FeignClient(name = "zt-scenic", path = "/api/scenic/v2")
public interface ScenicV2Client {
@GetMapping("/{scenicId}")
CommonResponse<ScenicV2DTO> getScenic(@PathVariable("scenicId") Long scenicId);
@GetMapping("/{scenicId}/with-config")
CommonResponse<ScenicV2WithConfigDTO> getScenicWithConfig(@PathVariable("scenicId") Long scenicId);
@GetMapping("/{scenicId}/flat")
CommonResponse<Map<String, Object>> getScenicFlatConfig(@PathVariable("scenicId") Long scenicId);
@PostMapping("/")
CommonResponse<ScenicV2DTO> createScenic(@RequestBody CreateScenicRequest request);
@PutMapping("/{scenicId}")
CommonResponse<ScenicV2DTO> updateScenic(@PathVariable("scenicId") Long scenicId,
@RequestBody UpdateScenicRequest request);
@DeleteMapping("/{scenicId}")
CommonResponse<Void> deleteScenic(@PathVariable("scenicId") Long scenicId);
@PostMapping("/filter")
CommonResponse<ScenicFilterPageResponse> filterScenics(@RequestBody ScenicFilterRequest request);
}

View File

@@ -0,0 +1,15 @@
package com.ycwl.basic.integration.scenic.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Slf4j
@Configuration
@ConfigurationProperties(prefix = "integration.scenic")
public class ScenicIntegrationConfig {
public ScenicIntegrationConfig() {
log.info("ZT-Scenic集成配置初始化完成");
}
}

View File

@@ -0,0 +1,26 @@
package com.ycwl.basic.integration.scenic.dto.config;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import java.util.List;
@Data
public class BatchConfigRequest {
@JsonProperty("configs")
@NotEmpty(message = "配置列表不能为空")
@Valid
private List<BatchConfigItem> configs;
@Data
public static class BatchConfigItem {
@JsonProperty("configKey")
@NotEmpty(message = "配置键不能为空")
private String configKey;
@JsonProperty("configValue")
private String configValue;
}
}

View File

@@ -0,0 +1,16 @@
package com.ycwl.basic.integration.scenic.dto.config;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class BatchUpdateResponse {
@JsonProperty("updatedCount")
private Integer updatedCount;
@JsonProperty("createdCount")
private Integer createdCount;
@JsonProperty("message")
private String message;
}

View File

@@ -0,0 +1,16 @@
package com.ycwl.basic.integration.scenic.dto.config;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class ConfigWithDefaultResponse {
@JsonProperty("configKey")
private String configKey;
@JsonProperty("configValue")
private String configValue;
@JsonProperty("source")
private String source;
}

View File

@@ -0,0 +1,23 @@
package com.ycwl.basic.integration.scenic.dto.config;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
@Data
public class CreateConfigRequest {
@JsonProperty("configKey")
@NotBlank(message = "配置键不能为空")
private String configKey;
@JsonProperty("configValue")
private String configValue;
@JsonProperty("configType")
@NotBlank(message = "配置类型不能为空")
private String configType;
@JsonProperty("description")
private String description;
}

View File

@@ -0,0 +1,19 @@
package com.ycwl.basic.integration.scenic.dto.config;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class DefaultConfigDTO {
@JsonProperty("configKey")
private String configKey;
@JsonProperty("configValue")
private String configValue;
@JsonProperty("configType")
private String configType;
@JsonProperty("description")
private String description;
}

View File

@@ -0,0 +1,36 @@
package com.ycwl.basic.integration.scenic.dto.config;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class ScenicConfigV2DTO {
@JsonProperty("id")
private String id;
@JsonProperty("scenicID")
@JsonAlias({"scenicId", "scenicID"})
private String scenicId;
@JsonProperty("configKey")
private String configKey;
@JsonProperty("configValue")
private String configValue;
@JsonProperty("configType")
private String configType;
@JsonProperty("description")
private String description;
@JsonProperty("isActive")
private Integer isActive;
@JsonProperty("createTime")
private Long createTime;
@JsonProperty("updateTime")
private Long updateTime;
}

View File

@@ -0,0 +1,16 @@
package com.ycwl.basic.integration.scenic.dto.config;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class UpdateConfigRequest {
@JsonProperty("configKey")
private String configKey;
@JsonProperty("configValue")
private String configValue;
@JsonProperty("description")
private String description;
}

View File

@@ -0,0 +1,20 @@
package com.ycwl.basic.integration.scenic.dto.filter;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
@Data
public class FilterCondition {
@JsonProperty("configKey")
@NotBlank(message = "配置键不能为空")
private String configKey;
@JsonProperty("configValue")
@NotBlank(message = "配置值不能为空")
private String configValue;
@JsonProperty("operator")
private String operator = "eq";
}

View File

@@ -0,0 +1,30 @@
package com.ycwl.basic.integration.scenic.dto.filter;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
@Data
public class ScenicFilterPageResponse {
@JsonProperty("list")
private List<ScenicFilterItem> list;
@JsonProperty("total")
private Long total;
@JsonProperty("page")
private Integer page;
@JsonProperty("pageSize")
private Integer pageSize;
@Data
public static class ScenicFilterItem {
@JsonProperty("id")
private String id;
@JsonProperty("name")
private String name;
}
}

View File

@@ -0,0 +1,22 @@
package com.ycwl.basic.integration.scenic.dto.filter;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import java.util.List;
@Data
public class ScenicFilterRequest {
@JsonProperty("filters")
@NotEmpty(message = "筛选条件不能为空")
@Valid
private List<FilterCondition> filters;
@JsonProperty("page")
private Integer page = 1;
@JsonProperty("pageSize")
private Integer pageSize = 20;
}

View File

@@ -0,0 +1,26 @@
package com.ycwl.basic.integration.scenic.dto.meta;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import java.util.List;
@Data
public class BatchSetFieldEnabledRequest {
@JsonProperty("fields")
@NotEmpty(message = "字段列表不能为空")
@Valid
private List<FieldEnabledItem> fields;
@Data
public static class FieldEnabledItem {
@JsonProperty("fieldKey")
@NotEmpty(message = "字段键不能为空")
private String fieldKey;
@JsonProperty("enabled")
private Boolean enabled;
}
}

View File

@@ -0,0 +1,12 @@
package com.ycwl.basic.integration.scenic.dto.meta;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
@Data
public class EnabledFieldsResponse {
@JsonProperty("enabledFields")
private List<String> enabledFields;
}

View File

@@ -0,0 +1,22 @@
package com.ycwl.basic.integration.scenic.dto.meta;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class FieldConfigDTO {
@JsonProperty("fieldKey")
private String fieldKey;
@JsonProperty("fieldName")
private String fieldName;
@JsonProperty("fieldType")
private String fieldType;
@JsonProperty("description")
private String description;
@JsonProperty("enabled")
private Boolean enabled;
}

View File

@@ -0,0 +1,13 @@
package com.ycwl.basic.integration.scenic.dto.meta;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import jakarta.validation.constraints.NotNull;
@Data
public class SetFieldEnabledRequest {
@JsonProperty("enabled")
@NotNull(message = "enabled状态不能为空")
private Boolean enabled;
}

View File

@@ -0,0 +1,21 @@
package com.ycwl.basic.integration.scenic.dto.scenic;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
@Data
public class CreateScenicRequest {
@JsonProperty("name")
@NotBlank(message = "景区名称不能为空")
private String name;
@JsonProperty("mpId")
@NotNull(message = "小程序ID不能为空")
private Integer mpId;
@JsonProperty("status")
private Integer status = 1;
}

View File

@@ -0,0 +1,25 @@
package com.ycwl.basic.integration.scenic.dto.scenic;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class ScenicV2DTO {
@JsonProperty("id")
private String id;
@JsonProperty("name")
private String name;
@JsonProperty("mpId")
private Integer mpId;
@JsonProperty("status")
private Integer status;
@JsonProperty("createTime")
private Long createTime;
@JsonProperty("updateTime")
private Long updateTime;
}

View File

@@ -0,0 +1,14 @@
package com.ycwl.basic.integration.scenic.dto.scenic;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Map;
@Data
@EqualsAndHashCode(callSuper = true)
public class ScenicV2WithConfigDTO extends ScenicV2DTO {
@JsonProperty("config")
private Map<String, Object> config;
}

View File

@@ -0,0 +1,16 @@
package com.ycwl.basic.integration.scenic.dto.scenic;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class UpdateScenicRequest {
@JsonProperty("name")
private String name;
@JsonProperty("mpId")
private Integer mpId;
@JsonProperty("status")
private Integer status;
}

View File

@@ -0,0 +1,78 @@
package com.ycwl.basic.integration.scenic.example;
import com.ycwl.basic.integration.scenic.dto.config.CreateConfigRequest;
import com.ycwl.basic.integration.scenic.dto.filter.FilterCondition;
import com.ycwl.basic.integration.scenic.dto.filter.ScenicFilterRequest;
import com.ycwl.basic.integration.scenic.dto.scenic.CreateScenicRequest;
import com.ycwl.basic.integration.scenic.service.ScenicConfigIntegrationService;
import com.ycwl.basic.integration.scenic.service.ScenicIntegrationService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.Collections;
/**
* ZT-Scenic集成服务使用示例
* 仅供参考,实际使用时根据业务需要调用相应的服务方法
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class ScenicIntegrationExample {
private final ScenicIntegrationService scenicIntegrationService;
private final ScenicConfigIntegrationService scenicConfigIntegrationService;
/**
* 示例:创建景区并设置配置
*/
public void createScenicWithConfig() {
try {
// 1. 创建景区
CreateScenicRequest createRequest = new CreateScenicRequest();
createRequest.setName("测试景区");
createRequest.setMpId(1001);
var scenic = scenicIntegrationService.createScenic(createRequest);
log.info("创建景区成功: {}", scenic.getName());
// 2. 为景区添加配置
CreateConfigRequest configRequest = new CreateConfigRequest();
configRequest.setConfigKey("tour_time");
configRequest.setConfigValue("120");
configRequest.setConfigType("int");
configRequest.setDescription("游览时长");
var config = scenicConfigIntegrationService.createConfig(
Long.valueOf(scenic.getId()), configRequest);
log.info("创建配置成功: {} = {}", config.getConfigKey(), config.getConfigValue());
} catch (Exception e) {
log.error("创建景区和配置失败", e);
}
}
/**
* 示例:筛选景区
*/
public void filterScenics() {
try {
FilterCondition condition = new FilterCondition();
condition.setConfigKey("tour_time");
condition.setConfigValue("120");
condition.setOperator("gte");
ScenicFilterRequest filterRequest = new ScenicFilterRequest();
filterRequest.setFilters(Collections.singletonList(condition));
filterRequest.setPage(1);
filterRequest.setPageSize(10);
var result = scenicIntegrationService.filterScenics(filterRequest);
log.info("筛选到 {} 个景区", result.getTotal());
} catch (Exception e) {
log.error("筛选景区失败", e);
}
}
}

View File

@@ -0,0 +1,60 @@
package com.ycwl.basic.integration.scenic.service;
import com.ycwl.basic.integration.common.exception.IntegrationException;
import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.scenic.client.DefaultConfigClient;
import com.ycwl.basic.integration.scenic.dto.config.DefaultConfigDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
@Slf4j
@Service
@RequiredArgsConstructor
public class DefaultConfigIntegrationService {
private final DefaultConfigClient defaultConfigClient;
public List<DefaultConfigDTO> listDefaultConfigs() {
log.info("获取默认配置列表");
CommonResponse<List<DefaultConfigDTO>> response = defaultConfigClient.listDefaultConfigs();
return handleResponse(response, "获取默认配置列表失败");
}
public DefaultConfigDTO getDefaultConfig(String configKey) {
log.info("获取指定默认配置, configKey: {}", configKey);
CommonResponse<DefaultConfigDTO> response = defaultConfigClient.getDefaultConfig(configKey);
return handleResponse(response, "获取指定默认配置失败");
}
public DefaultConfigDTO createDefaultConfig(DefaultConfigDTO request) {
log.info("创建默认配置, configKey: {}", request.getConfigKey());
CommonResponse<DefaultConfigDTO> response = defaultConfigClient.createDefaultConfig(request);
return handleResponse(response, "创建默认配置失败");
}
public DefaultConfigDTO updateDefaultConfig(String configKey, DefaultConfigDTO request) {
log.info("更新默认配置, configKey: {}", configKey);
CommonResponse<DefaultConfigDTO> response = defaultConfigClient.updateDefaultConfig(configKey, request);
return handleResponse(response, "更新默认配置失败");
}
public void deleteDefaultConfig(String configKey) {
log.info("删除默认配置, configKey: {}", configKey);
CommonResponse<Void> response = defaultConfigClient.deleteDefaultConfig(configKey);
handleResponse(response, "删除默认配置失败");
}
private <T> T handleResponse(CommonResponse<T> response, String errorMessage) {
if (response == null || !response.isSuccess()) {
String msg = response != null && response.getMessage() != null
? response.getMessage()
: errorMessage;
Integer code = response != null ? response.getCode() : 5000;
throw new IntegrationException(code, msg, "zt-scenic");
}
return response.getData();
}
}

View File

@@ -0,0 +1,87 @@
package com.ycwl.basic.integration.scenic.service;
import com.ycwl.basic.integration.common.exception.IntegrationException;
import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.scenic.client.ScenicConfigV2Client;
import com.ycwl.basic.integration.scenic.client.ScenicConfigWithDefaultClient;
import com.ycwl.basic.integration.scenic.dto.config.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
@Slf4j
@Service
@RequiredArgsConstructor
public class ScenicConfigIntegrationService {
private final ScenicConfigV2Client scenicConfigV2Client;
private final ScenicConfigWithDefaultClient scenicConfigWithDefaultClient;
public List<ScenicConfigV2DTO> listConfigs(Long scenicId) {
log.info("获取景区配置列表, scenicId: {}", scenicId);
CommonResponse<List<ScenicConfigV2DTO>> response = scenicConfigV2Client.listConfigs(scenicId);
return handleResponse(response, "获取景区配置列表失败");
}
public ScenicConfigV2DTO getConfigByKey(Long scenicId, String configKey) {
log.info("根据键获取景区配置, scenicId: {}, configKey: {}", scenicId, configKey);
CommonResponse<ScenicConfigV2DTO> response = scenicConfigV2Client.getConfigByKey(scenicId, configKey);
return handleResponse(response, "根据键获取景区配置失败");
}
public Map<String, Object> getFlatConfigs(Long scenicId) {
log.info("获取景区扁平化配置, scenicId: {}", scenicId);
CommonResponse<Map<String, Object>> response = scenicConfigV2Client.getFlatConfigs(scenicId);
return handleResponse(response, "获取景区扁平化配置失败");
}
public ScenicConfigV2DTO createConfig(Long scenicId, CreateConfigRequest request) {
log.info("创建景区配置, scenicId: {}, configKey: {}", scenicId, request.getConfigKey());
CommonResponse<ScenicConfigV2DTO> response = scenicConfigV2Client.createConfig(scenicId, request);
return handleResponse(response, "创建景区配置失败");
}
public ScenicConfigV2DTO updateConfig(Long scenicId, String id, UpdateConfigRequest request) {
log.info("更新景区配置, scenicId: {}, id: {}", scenicId, id);
CommonResponse<ScenicConfigV2DTO> response = scenicConfigV2Client.updateConfig(scenicId, id, request);
return handleResponse(response, "更新景区配置失败");
}
public void deleteConfig(Long scenicId, String id) {
log.info("删除景区配置, scenicId: {}, id: {}", scenicId, id);
CommonResponse<Void> response = scenicConfigV2Client.deleteConfig(scenicId, id);
handleResponse(response, "删除景区配置失败");
}
public BatchUpdateResponse batchUpdateConfigs(Long scenicId, BatchConfigRequest request) {
log.info("批量更新景区配置, scenicId: {}, configs count: {}", scenicId, request.getConfigs().size());
CommonResponse<BatchUpdateResponse> response = scenicConfigV2Client.batchUpdateConfigs(scenicId, request);
return handleResponse(response, "批量更新景区配置失败");
}
public BatchUpdateResponse batchFlatUpdateConfigs(Long scenicId, Map<String, Object> configs) {
log.info("扁平化批量更新景区配置, scenicId: {}, configs count: {}", scenicId, configs.size());
CommonResponse<BatchUpdateResponse> response = scenicConfigV2Client.batchFlatUpdateConfigs(scenicId, configs);
return handleResponse(response, "扁平化批量更新景区配置失败");
}
public ConfigWithDefaultResponse getConfigWithDefault(Long scenicId, String configKey) {
log.info("获取带默认值的配置, scenicId: {}, configKey: {}", scenicId, configKey);
CommonResponse<ConfigWithDefaultResponse> response = scenicConfigWithDefaultClient.getConfigWithDefault(scenicId, configKey);
return handleResponse(response, "获取带默认值的配置失败");
}
private <T> T handleResponse(CommonResponse<T> response, String errorMessage) {
if (response == null || !response.isSuccess()) {
String msg = response != null && response.getMessage() != null
? response.getMessage()
: errorMessage;
Integer code = response != null ? response.getCode() : 5000;
throw new IntegrationException(code, msg, "zt-scenic");
}
return response.getData();
}
}

View File

@@ -0,0 +1,77 @@
package com.ycwl.basic.integration.scenic.service;
import com.ycwl.basic.integration.common.exception.IntegrationException;
import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.scenic.client.ScenicV2Client;
import com.ycwl.basic.integration.scenic.dto.filter.ScenicFilterPageResponse;
import com.ycwl.basic.integration.scenic.dto.filter.ScenicFilterRequest;
import com.ycwl.basic.integration.scenic.dto.scenic.CreateScenicRequest;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigDTO;
import com.ycwl.basic.integration.scenic.dto.scenic.UpdateScenicRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Map;
@Slf4j
@Service
@RequiredArgsConstructor
public class ScenicIntegrationService {
private final ScenicV2Client scenicV2Client;
public ScenicV2DTO getScenic(Long scenicId) {
log.info("获取景区信息, scenicId: {}", scenicId);
CommonResponse<ScenicV2DTO> response = scenicV2Client.getScenic(scenicId);
return handleResponse(response, "获取景区信息失败");
}
public ScenicV2WithConfigDTO getScenicWithConfig(Long scenicId) {
log.info("获取景区配置信息, scenicId: {}", scenicId);
CommonResponse<ScenicV2WithConfigDTO> response = scenicV2Client.getScenicWithConfig(scenicId);
return handleResponse(response, "获取景区配置信息失败");
}
public Map<String, Object> getScenicFlatConfig(Long scenicId) {
log.info("获取景区扁平化配置, scenicId: {}", scenicId);
CommonResponse<Map<String, Object>> response = scenicV2Client.getScenicFlatConfig(scenicId);
return handleResponse(response, "获取景区扁平化配置失败");
}
public ScenicV2DTO createScenic(CreateScenicRequest request) {
log.info("创建景区, name: {}", request.getName());
CommonResponse<ScenicV2DTO> response = scenicV2Client.createScenic(request);
return handleResponse(response, "创建景区失败");
}
public ScenicV2DTO updateScenic(Long scenicId, UpdateScenicRequest request) {
log.info("更新景区信息, scenicId: {}", scenicId);
CommonResponse<ScenicV2DTO> response = scenicV2Client.updateScenic(scenicId, request);
return handleResponse(response, "更新景区信息失败");
}
public void deleteScenic(Long scenicId) {
log.info("删除景区, scenicId: {}", scenicId);
CommonResponse<Void> response = scenicV2Client.deleteScenic(scenicId);
handleResponse(response, "删除景区失败");
}
public ScenicFilterPageResponse filterScenics(ScenicFilterRequest request) {
log.info("筛选景区, filters: {}", request.getFilters().size());
CommonResponse<ScenicFilterPageResponse> response = scenicV2Client.filterScenics(request);
return handleResponse(response, "筛选景区失败");
}
private <T> T handleResponse(CommonResponse<T> response, String errorMessage) {
if (response == null || !response.isSuccess()) {
String msg = response != null && response.getMessage() != null
? response.getMessage()
: errorMessage;
Integer code = response != null ? response.getCode() : 5000;
throw new IntegrationException(code, msg, "zt-scenic");
}
return response.getData();
}
}

View File

@@ -0,0 +1,76 @@
package com.ycwl.basic.integration.scenic.service;
import com.ycwl.basic.integration.common.exception.IntegrationException;
import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.scenic.client.ScenicMetaClient;
import com.ycwl.basic.integration.scenic.dto.meta.*;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
@Slf4j
@Service
@RequiredArgsConstructor
public class ScenicMetaIntegrationService {
private final ScenicMetaClient scenicMetaClient;
public EnabledFieldsResponse getEnabledFields(Long scenicId) {
log.info("获取启用的字段, scenicId: {}", scenicId);
CommonResponse<EnabledFieldsResponse> response = scenicMetaClient.getEnabledFields(scenicId);
return handleResponse(response, "获取启用的字段失败");
}
public List<FieldConfigDTO> getAllFields() {
log.info("获取所有字段配置");
CommonResponse<List<FieldConfigDTO>> response = scenicMetaClient.getAllFields();
return handleResponse(response, "获取所有字段配置失败");
}
public FieldConfigDTO getFieldConfig(String fieldKey) {
log.info("获取字段配置, fieldKey: {}", fieldKey);
CommonResponse<FieldConfigDTO> response = scenicMetaClient.getFieldConfig(fieldKey);
return handleResponse(response, "获取字段配置失败");
}
public void setFieldEnabled(Long scenicId, String fieldKey, Boolean enabled) {
log.info("设置字段启用状态, scenicId: {}, fieldKey: {}, enabled: {}", scenicId, fieldKey, enabled);
SetFieldEnabledRequest request = new SetFieldEnabledRequest();
request.setEnabled(enabled);
CommonResponse<Void> response = scenicMetaClient.setFieldEnabled(scenicId, fieldKey, request);
handleResponse(response, "设置字段启用状态失败");
}
public void batchSetFieldEnabled(Long scenicId, BatchSetFieldEnabledRequest request) {
log.info("批量设置字段启用状态, scenicId: {}, fields count: {}", scenicId, request.getFields().size());
CommonResponse<Void> response = scenicMetaClient.batchSetFieldEnabled(scenicId, request);
handleResponse(response, "批量设置字段启用状态失败");
}
public ScenicV2WithConfigDTO getScenicWithConfigEnhanced(Long scenicId) {
log.info("获取景区与配置(增强版), scenicId: {}", scenicId);
CommonResponse<ScenicV2WithConfigDTO> response = scenicMetaClient.getScenicWithConfigEnhanced(scenicId);
return handleResponse(response, "获取景区与配置(增强版)失败");
}
public void updateConfigEnhanced(Long scenicId, Map<String, Object> configs) {
log.info("更新配置(增强版), scenicId: {}, configs count: {}", scenicId, configs.size());
CommonResponse<Void> response = scenicMetaClient.updateConfigEnhanced(scenicId, configs);
handleResponse(response, "更新配置(增强版)失败");
}
private <T> T handleResponse(CommonResponse<T> response, String errorMessage) {
if (response == null || !response.isSuccess()) {
String msg = response != null && response.getMessage() != null
? response.getMessage()
: errorMessage;
Integer code = response != null ? response.getCode() : 5000;
throw new IntegrationException(code, msg, "zt-scenic");
}
return response.getData();
}
}

View File

@@ -3,4 +3,21 @@ server:
spring: spring:
application: application:
name: zt name: zt
# Feign配置(简化版,基于Nacos服务发现)
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 10000
loggerLevel: full
decode404: true
okhttp:
enabled: true
# 开发环境日志配置
logging:
level:
com.ycwl.basic.integration.scenic.client: DEBUG

View File

@@ -3,4 +3,9 @@ server:
spring: spring:
application: application:
name: zt name: zt
# 生产环境日志级别
logging:
level:
com.ycwl.basic.integration.scenic.client: WARN