配置迁移到表
This commit is contained in:
@@ -118,12 +118,13 @@ public class LbGoodsController {
|
|||||||
@Operation(
|
@Operation(
|
||||||
summary = "从 hxrd 第三方同步货品",
|
summary = "从 hxrd 第三方同步货品",
|
||||||
description =
|
description =
|
||||||
"分页调用 GET /api/order/goods(每页 limit=20,自动计算 S/T/N 签名),"
|
"分页调用 GET /api/order/goods(自动计算 S/T/N 签名),"
|
||||||
+ "解析 data.list 后 upsert 到 lb_goods;需配置 hxr.admin.goods-api-token、goods-api-app-str;"
|
+ "解析 data.list 后 upsert 到 lb_goods;"
|
||||||
+ "token 可选,传入时替代配置中的 goods-api-token")
|
+ "token、URL、appStr 等从 lb_third_integration_config 按 tenantId 读取;"
|
||||||
|
+ "token 可选,传入时覆盖库中 goodsApiToken")
|
||||||
public ResponseEntity<Map<String, Object>> syncFromHxr(
|
public ResponseEntity<Map<String, Object>> syncFromHxr(
|
||||||
@Parameter(description = "租户 id", required = true) @RequestParam String tenantId,
|
@Parameter(description = "租户 id", required = true) @RequestParam String tenantId,
|
||||||
@Parameter(description = "hxrd 接口请求头 token;未传时使用 hxr.admin.goods-api-token")
|
@Parameter(description = "hxrd 接口请求头 token;未传时使用 lb_third_integration_config 中的 goodsApiToken")
|
||||||
@RequestParam(required = false)
|
@RequestParam(required = false)
|
||||||
String token) {
|
String token) {
|
||||||
Map<String, Object> result = lbGoodsService.syncFromHxrGoods(tenantId, token);
|
Map<String, Object> result = lbGoodsService.syncFromHxrGoods(tenantId, token);
|
||||||
|
|||||||
13
src/main/java/com/rj/dto/hxr/HxrGoodsApiContext.java
Normal file
13
src/main/java/com/rj/dto/hxr/HxrGoodsApiContext.java
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package com.rj.dto.hxr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用 hxrd 货品/抢购 API 所需的运行时配置(由 {@code lb_third_integration_config} 解析而来)。
|
||||||
|
*/
|
||||||
|
public record HxrGoodsApiContext(
|
||||||
|
String goodsApiBaseUrl,
|
||||||
|
int pageLimit,
|
||||||
|
String origin,
|
||||||
|
String referer,
|
||||||
|
String token,
|
||||||
|
String appStr) {
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
|||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||||
import com.rj.config.HxrAdminProperties;
|
import com.rj.config.HxrAdminProperties;
|
||||||
|
import com.rj.dto.hxr.HxrGoodsApiContext;
|
||||||
import com.rj.dto.hxr.HxrLbGoodsSelectResponse;
|
import com.rj.dto.hxr.HxrLbGoodsSelectResponse;
|
||||||
import com.rj.util.HxrGoodsSignUtil;
|
import com.rj.util.HxrGoodsSignUtil;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@@ -49,7 +50,7 @@ public class HxrAdminGoodsService {
|
|||||||
private final HxrAdminProperties properties;
|
private final HxrAdminProperties properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页拉取货品列表。
|
* 分页拉取货品列表(使用 {@code hxr.admin} 配置文件,兼容旧调用)。
|
||||||
*
|
*
|
||||||
* @param page 页码,从 1 开始
|
* @param page 页码,从 1 开始
|
||||||
* @param token 可选;非空时作为请求头 token,否则使用 {@code hxr.admin.goods-api-token}
|
* @param token 可选;非空时作为请求头 token,否则使用 {@code hxr.admin.goods-api-token}
|
||||||
@@ -65,11 +66,45 @@ public class HxrAdminGoodsService {
|
|||||||
log.warn("hxr.admin 未配置 goods-api-app-str,跳过 /api/order/goods");
|
log.warn("hxr.admin 未配置 goods-api-app-str,跳过 /api/order/goods");
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
HxrGoodsApiContext ctx = new HxrGoodsApiContext(
|
||||||
|
stripQuery(properties.getGoodsApiUrl()),
|
||||||
|
GOODS_PAGE_SIZE,
|
||||||
|
properties.getGoodsApiOrigin(),
|
||||||
|
properties.getGoodsApiReferer(),
|
||||||
|
resolvedToken,
|
||||||
|
appStr.trim());
|
||||||
|
return fetchGoodsPage(page, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页拉取货品列表(使用租户 {@code lb_third_integration_config} 解析出的运行时配置)。
|
||||||
|
*/
|
||||||
|
public Optional<HxrLbGoodsSelectResponse> fetchGoodsPage(int page, HxrGoodsApiContext ctx) throws Exception {
|
||||||
|
if (ctx == null) {
|
||||||
|
log.warn("货品 API 配置为空,跳过 /api/order/goods");
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
String resolvedToken = ctx.token();
|
||||||
|
if (resolvedToken == null || resolvedToken.isBlank()) {
|
||||||
|
log.warn("未提供 token,跳过 /api/order/goods");
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
String appStr = ctx.appStr();
|
||||||
|
if (appStr == null || appStr.isBlank()) {
|
||||||
|
log.warn("未配置 goodsApiAppStr,跳过 /api/order/goods");
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
String goodsApiBaseUrl = ctx.goodsApiBaseUrl();
|
||||||
|
if (goodsApiBaseUrl == null || goodsApiBaseUrl.isBlank()) {
|
||||||
|
log.warn("未配置 goodsApiBaseUrl,跳过 /api/order/goods");
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
int pageLimit = ctx.pageLimit() > 0 ? ctx.pageLimit() : GOODS_PAGE_SIZE;
|
||||||
int safePage = Math.max(1, page);
|
int safePage = Math.max(1, page);
|
||||||
String uri = UriComponentsBuilder.fromUriString(properties.getGoodsApiUrl())
|
String uri = UriComponentsBuilder.fromUriString(goodsApiBaseUrl)
|
||||||
.replaceQueryParam("page", safePage)
|
.replaceQueryParam("page", safePage)
|
||||||
.replaceQueryParam("limit", GOODS_PAGE_SIZE)
|
.replaceQueryParam("limit", pageLimit)
|
||||||
.build()
|
.build()
|
||||||
.encode()
|
.encode()
|
||||||
.toUriString();
|
.toUriString();
|
||||||
@@ -78,7 +113,7 @@ public class HxrAdminGoodsService {
|
|||||||
String noncestr = randomNoncestr();
|
String noncestr = randomNoncestr();
|
||||||
Map<String, Object> signParams = new LinkedHashMap<>();
|
Map<String, Object> signParams = new LinkedHashMap<>();
|
||||||
signParams.put("page", safePage);
|
signParams.put("page", safePage);
|
||||||
signParams.put("limit", GOODS_PAGE_SIZE);
|
signParams.put("limit", pageLimit);
|
||||||
signParams.put("timestamp", timestamp);
|
signParams.put("timestamp", timestamp);
|
||||||
signParams.put("noncestr", noncestr);
|
signParams.put("noncestr", noncestr);
|
||||||
String sign = HxrGoodsSignUtil.computeSign(signParams, appStr.trim());
|
String sign = HxrGoodsSignUtil.computeSign(signParams, appStr.trim());
|
||||||
@@ -93,8 +128,8 @@ public class HxrAdminGoodsService {
|
|||||||
.timeout(Duration.ofSeconds(120))
|
.timeout(Duration.ofSeconds(120))
|
||||||
.header("Accept", "application/json,*/*")
|
.header("Accept", "application/json,*/*")
|
||||||
.header("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
|
.header("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
|
||||||
.header("Origin", properties.getGoodsApiOrigin())
|
.header("Origin", ctx.origin())
|
||||||
.header("Referer", properties.getGoodsApiReferer())
|
.header("Referer", ctx.referer())
|
||||||
.header("User-Agent", USER_AGENT)
|
.header("User-Agent", USER_AGENT)
|
||||||
.header("token", resolvedToken)
|
.header("token", resolvedToken)
|
||||||
.header("S", sign)
|
.header("S", sign)
|
||||||
@@ -136,6 +171,15 @@ public class HxrAdminGoodsService {
|
|||||||
return Optional.of(body);
|
return Optional.of(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 从完整 URL 中去掉 query,供配置文件回退路径使用。 */
|
||||||
|
private static String stripQuery(String url) {
|
||||||
|
if (url == null || url.isBlank()) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
int q = url.indexOf('?');
|
||||||
|
return q >= 0 ? url.substring(0, q) : url;
|
||||||
|
}
|
||||||
|
|
||||||
/** 优先使用入参 token,否则回退到配置 {@code goods-api-token}。 */
|
/** 优先使用入参 token,否则回退到配置 {@code goods-api-token}。 */
|
||||||
private String resolveToken(String token) {
|
private String resolveToken(String token) {
|
||||||
if (token != null && !token.isBlank()) {
|
if (token != null && !token.isBlank()) {
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ package com.rj.service;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
import com.rj.dto.LbThirdIntegrationCredentialUpdateRequest;
|
import com.rj.dto.LbThirdIntegrationCredentialUpdateRequest;
|
||||||
|
import com.rj.dto.hxr.HxrGoodsApiContext;
|
||||||
import com.rj.entity.LbThirdIntegrationConfig;
|
import com.rj.entity.LbThirdIntegrationConfig;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 租户第三方集成配置服务
|
* 租户第三方集成配置服务
|
||||||
@@ -35,4 +37,9 @@ public interface ILbThirdIntegrationConfigService extends IService<LbThirdIntegr
|
|||||||
*/
|
*/
|
||||||
Map<String, Object> updateCredentialByTenantId(
|
Map<String, Object> updateCredentialByTenantId(
|
||||||
String tenantId, LbThirdIntegrationCredentialUpdateRequest request);
|
String tenantId, LbThirdIntegrationCredentialUpdateRequest request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按租户 id 解析货品 API 运行时配置(含解密凭证);{@code tokenOverride} 非空时优先于库中 token。
|
||||||
|
*/
|
||||||
|
Optional<HxrGoodsApiContext> resolveGoodsApiContext(String tenantId, String tokenOverride);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.rj.service.impl;
|
|||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.rj.dto.hxr.HxrGoodsApiContext;
|
||||||
import com.rj.dto.hxr.HxrLbGoodsPageData;
|
import com.rj.dto.hxr.HxrLbGoodsPageData;
|
||||||
import com.rj.dto.hxr.HxrLbGoodsSelectResponse;
|
import com.rj.dto.hxr.HxrLbGoodsSelectResponse;
|
||||||
import com.rj.entity.LbGoods;
|
import com.rj.entity.LbGoods;
|
||||||
@@ -10,6 +11,7 @@ import com.rj.mapper.LbGoodsMapper;
|
|||||||
import com.rj.service.HxrAdminBuyService;
|
import com.rj.service.HxrAdminBuyService;
|
||||||
import com.rj.service.HxrAdminGoodsService;
|
import com.rj.service.HxrAdminGoodsService;
|
||||||
import com.rj.service.ILbGoodsService;
|
import com.rj.service.ILbGoodsService;
|
||||||
|
import com.rj.service.ILbThirdIntegrationConfigService;
|
||||||
import com.rj.tenant.TenantContextHolder;
|
import com.rj.tenant.TenantContextHolder;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -40,6 +42,8 @@ public class LbGoodsServiceImpl extends ServiceImpl<LbGoodsMapper, LbGoods> impl
|
|||||||
|
|
||||||
private final HxrAdminBuyService hxrAdminBuyService;
|
private final HxrAdminBuyService hxrAdminBuyService;
|
||||||
|
|
||||||
|
private final ILbThirdIntegrationConfigService lbThirdIntegrationConfigService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Object> add(LbGoods entity) {
|
public Map<String, Object> add(LbGoods entity) {
|
||||||
Map<String, Object> result = new HashMap<>();
|
Map<String, Object> result = new HashMap<>();
|
||||||
@@ -260,6 +264,17 @@ public class LbGoodsServiceImpl extends ServiceImpl<LbGoodsMapper, LbGoods> impl
|
|||||||
}
|
}
|
||||||
|
|
||||||
String tid = tenantId.trim();
|
String tid = tenantId.trim();
|
||||||
|
Optional<HxrGoodsApiContext> apiContextOpt =
|
||||||
|
lbThirdIntegrationConfigService.resolveGoodsApiContext(tid, token);
|
||||||
|
if (apiContextOpt.isEmpty()) {
|
||||||
|
result.put("success", false);
|
||||||
|
result.put("message",
|
||||||
|
"未找到该租户的第三方集成配置,或配置未启用、URL/凭证不完整(请检查 lb_third_integration_config)");
|
||||||
|
result.put("synced", 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
HxrGoodsApiContext apiContext = apiContextOpt.get();
|
||||||
|
|
||||||
String previousTenantId = TenantContextHolder.getTenantId();
|
String previousTenantId = TenantContextHolder.getTenantId();
|
||||||
TenantContextHolder.setTenantId(tid);
|
TenantContextHolder.setTenantId(tid);
|
||||||
try {
|
try {
|
||||||
@@ -268,11 +283,12 @@ public class LbGoodsServiceImpl extends ServiceImpl<LbGoodsMapper, LbGoods> impl
|
|||||||
int totalSynced = 0;
|
int totalSynced = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
Optional<HxrLbGoodsSelectResponse> opt =
|
Optional<HxrLbGoodsSelectResponse> opt =
|
||||||
hxrAdminGoodsService.fetchGoodsPage(page, token);
|
hxrAdminGoodsService.fetchGoodsPage(page, apiContext);
|
||||||
if (opt.isEmpty()) {
|
if (opt.isEmpty()) {
|
||||||
if (page == 1) {
|
if (page == 1) {
|
||||||
result.put("success", false);
|
result.put("success", false);
|
||||||
result.put("message", "未拉取到货品(请检查 hxr.admin.goods-api-token、goods-api-app-str 或网络)");
|
result.put("message",
|
||||||
|
"未拉取到货品(请检查 lb_third_integration_config 中 token、appStr、URL 或网络)");
|
||||||
result.put("synced", 0);
|
result.put("synced", 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|||||||
import com.rj.common.LbThirdIntegrationConstants;
|
import com.rj.common.LbThirdIntegrationConstants;
|
||||||
import com.rj.common.PasswordUtil;
|
import com.rj.common.PasswordUtil;
|
||||||
import com.rj.dto.LbThirdIntegrationCredentialUpdateRequest;
|
import com.rj.dto.LbThirdIntegrationCredentialUpdateRequest;
|
||||||
|
import com.rj.dto.hxr.HxrGoodsApiContext;
|
||||||
import com.rj.entity.LbThirdIntegrationConfig;
|
import com.rj.entity.LbThirdIntegrationConfig;
|
||||||
import com.rj.mapper.LbThirdIntegrationConfigMapper;
|
import com.rj.mapper.LbThirdIntegrationConfigMapper;
|
||||||
import com.rj.service.ILbThirdIntegrationConfigService;
|
import com.rj.service.ILbThirdIntegrationConfigService;
|
||||||
|
import com.rj.util.LbThirdIntegrationConfigUtil;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
@@ -18,6 +20,7 @@ import java.time.LocalDateTime;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -306,6 +309,40 @@ public class LbThirdIntegrationConfigServiceImpl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<HxrGoodsApiContext> resolveGoodsApiContext(String tenantId, String tokenOverride) {
|
||||||
|
if (!StringUtils.hasText(tenantId)) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
LbThirdIntegrationConfig config = getByTenantIdOrNull(tenantId.trim());
|
||||||
|
if (config == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
if (config.getEnabled() == null || config.getEnabled() != 1) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
String token = StringUtils.hasText(tokenOverride)
|
||||||
|
? tokenOverride.trim()
|
||||||
|
: decryptFromBytes(config.getGoodsApiTokenCipher());
|
||||||
|
String appStr = decryptFromBytes(config.getGoodsApiAppStrCipher());
|
||||||
|
if (!StringUtils.hasText(token) || !StringUtils.hasText(appStr)) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return Optional.of(new HxrGoodsApiContext(
|
||||||
|
LbThirdIntegrationConfigUtil.resolveGoodsApiBaseUrl(config),
|
||||||
|
LbThirdIntegrationConfigUtil.resolveGoodsPageLimit(config),
|
||||||
|
LbThirdIntegrationConfigUtil.resolveGoodsApiOrigin(config),
|
||||||
|
LbThirdIntegrationConfigUtil.resolveGoodsApiReferer(config),
|
||||||
|
token.trim(),
|
||||||
|
appStr.trim()));
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private LbThirdIntegrationConfig getByTenantIdOrNull(String tenantId) {
|
private LbThirdIntegrationConfig getByTenantIdOrNull(String tenantId) {
|
||||||
return this.getOne(new LambdaQueryWrapper<LbThirdIntegrationConfig>()
|
return this.getOne(new LambdaQueryWrapper<LbThirdIntegrationConfig>()
|
||||||
.eq(LbThirdIntegrationConfig::getTenantId, tenantId)
|
.eq(LbThirdIntegrationConfig::getTenantId, tenantId)
|
||||||
|
|||||||
64
src/main/java/com/rj/util/LbThirdIntegrationConfigUtil.java
Normal file
64
src/main/java/com/rj/util/LbThirdIntegrationConfigUtil.java
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package com.rj.util;
|
||||||
|
|
||||||
|
import com.rj.common.LbThirdIntegrationConstants;
|
||||||
|
import com.rj.entity.LbThirdIntegrationConfig;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 {@link LbThirdIntegrationConfig} 解析第三方 API 地址与请求头。
|
||||||
|
*/
|
||||||
|
public final class LbThirdIntegrationConfigUtil {
|
||||||
|
|
||||||
|
private LbThirdIntegrationConfigUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String resolveGoodsApiBaseUrl(LbThirdIntegrationConfig config) {
|
||||||
|
String base = trimTrailingSlash(requireText(config.getAdminBaseUrl(), "adminBaseUrl"));
|
||||||
|
String path = config.getGoodsApiPath();
|
||||||
|
if (!StringUtils.hasText(path)) {
|
||||||
|
path = LbThirdIntegrationConstants.DEFAULT_GOODS_API_PATH;
|
||||||
|
}
|
||||||
|
path = path.trim();
|
||||||
|
if (!path.startsWith("/")) {
|
||||||
|
path = "/" + path;
|
||||||
|
}
|
||||||
|
return base + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String resolveGoodsApiOrigin(LbThirdIntegrationConfig config) {
|
||||||
|
if (StringUtils.hasText(config.getGoodsApiOrigin())) {
|
||||||
|
return config.getGoodsApiOrigin().trim();
|
||||||
|
}
|
||||||
|
return trimTrailingSlash(requireText(config.getWebBaseUrl(), "webBaseUrl"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String resolveGoodsApiReferer(LbThirdIntegrationConfig config) {
|
||||||
|
if (StringUtils.hasText(config.getGoodsApiReferer())) {
|
||||||
|
return config.getGoodsApiReferer().trim();
|
||||||
|
}
|
||||||
|
return trimTrailingSlash(requireText(config.getWebBaseUrl(), "webBaseUrl")) + "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int resolveGoodsPageLimit(LbThirdIntegrationConfig config) {
|
||||||
|
Integer limit = config.getGoodsPageLimit();
|
||||||
|
if (limit == null || limit < 1) {
|
||||||
|
return LbThirdIntegrationConstants.DEFAULT_GOODS_PAGE_LIMIT;
|
||||||
|
}
|
||||||
|
return limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String requireText(String value, String fieldName) {
|
||||||
|
if (!StringUtils.hasText(value)) {
|
||||||
|
throw new IllegalStateException(fieldName + " 未配置");
|
||||||
|
}
|
||||||
|
return value.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String trimTrailingSlash(String url) {
|
||||||
|
String trimmed = url.trim();
|
||||||
|
while (trimmed.endsWith("/")) {
|
||||||
|
trimmed = trimmed.substring(0, trimmed.length() - 1);
|
||||||
|
}
|
||||||
|
return trimmed;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user