From 3493a783410a400af65fba10ce26c386894a6bce Mon Sep 17 00:00:00 2001 From: ZuoZuo <68836346+Mrz-sakura@users.noreply.github.com> Date: Mon, 13 Apr 2026 14:47:50 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=90=AF=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/endpoint/EndpointRestController.java | 94 ++++---- .../gateway/filter/AuthGlobalFilter.java | 151 ++++++++----- rc-gateway/src/main/resources/bootstrap.yml | 10 +- .../app/party3rd/AliYunRestController.java | 117 +++++++--- .../app/oss/LocalDiskFileRestController.java | 49 +++++ .../adapter/app/oss/OssRestController.java | 191 ++++++++++++---- .../external-application/pom.xml | 28 ++- .../app/oss/LocalDiskStorageProperties.java | 47 ++++ .../app/oss/LocalDiskStorageService.java | 204 ++++++++++++++++++ .../app/oss/TencentCosProperties.java | 130 +++++++++++ .../app/oss/TencentCosStorageService.java | 190 ++++++++++++++++ .../oss/impl/OssServiceClientServiceImpl.java | 121 +++++++---- .../RedisServiceFallbackConfiguration.java | 181 ++++++++++++++++ .../src/main/resources/application.yml | 6 +- .../service/LiveMicrophoneServiceImpl.java | 22 +- .../repository/LiveMicrophoneGatewayImpl.java | 35 +-- .../other-application/pom.xml | 11 +- .../user/user/AccountBindUserAuthTypeCmd.java | 2 +- .../app/dto/cmd/user/user/AccountQryCmd.java | 2 +- .../cmd/user/user/BankIdentityInfoCmd.java | 2 +- .../cmd/user/user/BindUserAuthTypeCmd.java | 2 +- .../dto/cmd/user/user/LanguageUploadCmd.java | 2 +- .../cmd/user/user/RemoveNotActionUserCmd.java | 2 +- .../cmd/user/user/UnBindUserAuthTypeCmd.java | 2 +- .../dto/cmd/user/user/UploadDeviceCmd.java | 2 +- .../cmd/user/user/UserBlacklistQueryCmd.java | 2 +- .../app/dto/cmd/user/user/UserCardQryCmd.java | 2 +- .../app/dto/cmd/user/user/UserLevelCmd.java | 2 +- .../dto/cmd/user/user/UserLogoutApplyCmd.java | 2 +- .../dto/cmd/user/user/UserLogoutLogCmd.java | 2 +- .../user/user/UserOnlineStatusUploadCmd.java | 2 +- .../cmd/user/user/UserProfileModifyCmd.java | 2 +- .../dto/cmd/user/user/UserProfileQryCmd.java | 2 +- .../cmd/user/user/UserShieldBlackUserCmd.java | 2 +- .../user/user/VoiceRoomUserCardQryCmd.java | 2 +- 35 files changed, 1360 insertions(+), 263 deletions(-) create mode 100644 rc-service/rc-service-external/external-adapter/src/main/java/com/red/circle/external/adapter/app/oss/LocalDiskFileRestController.java create mode 100644 rc-service/rc-service-external/external-application/src/main/java/com/red/circle/external/app/oss/LocalDiskStorageProperties.java create mode 100644 rc-service/rc-service-external/external-application/src/main/java/com/red/circle/external/app/oss/LocalDiskStorageService.java create mode 100644 rc-service/rc-service-external/external-application/src/main/java/com/red/circle/external/app/oss/TencentCosProperties.java create mode 100644 rc-service/rc-service-external/external-application/src/main/java/com/red/circle/external/app/oss/TencentCosStorageService.java create mode 100644 rc-service/rc-service-external/external-start/src/main/java/com/red/circle/RedisServiceFallbackConfiguration.java diff --git a/rc-auth/src/main/java/com/red/circle/auth/endpoint/EndpointRestController.java b/rc-auth/src/main/java/com/red/circle/auth/endpoint/EndpointRestController.java index 92ee1ff9..973741e9 100644 --- a/rc-auth/src/main/java/com/red/circle/auth/endpoint/EndpointRestController.java +++ b/rc-auth/src/main/java/com/red/circle/auth/endpoint/EndpointRestController.java @@ -25,22 +25,22 @@ import com.red.circle.other.inner.model.dto.sys.SysCountryCodeDTO; import com.red.circle.other.inner.model.dto.user.account.UserAccountDTO; import com.red.circle.tool.core.text.StringUtils; import jakarta.servlet.http.HttpServletRequest; - -import java.io.IOException; -import java.util.*; -import java.util.concurrent.TimeUnit; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.util.EntityUtils; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; + +import java.io.IOException; +import java.util.*; +import java.util.concurrent.TimeUnit; + +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @@ -55,13 +55,13 @@ import static com.red.circle.tool.core.text.StringPool.SYMBOL_COMMA; * @eo.groupName 认证服务 * @eo.path /auth */ -@Slf4j -@RestController -@RequiredArgsConstructor -public class EndpointRestController { - - private final ProcessToken processToken; - private final AppUserAccountClient appUserAccountClient; +@RestController +public class EndpointRestController { + + private static final Logger log = LoggerFactory.getLogger(EndpointRestController.class); + + private final ProcessToken processToken; + private final AppUserAccountClient appUserAccountClient; private final RedCircleCredentialService redCircleCredentialService; private final SysCountryCodeClient sysCountryCodeService; private final EnumConfigClient enumConfigClient; @@ -70,8 +70,22 @@ public class EndpointRestController { private final String APPCODE_CONFIG = "APPCODE ******"; private final String REQUEST_URL = "https://c2ba.api.huachen.cn/ip"; - - private final RedisService redisService; + + private final RedisService redisService; + + public EndpointRestController(ProcessToken processToken, + AppUserAccountClient appUserAccountClient, + RedCircleCredentialService redCircleCredentialService, + SysCountryCodeClient sysCountryCodeService, + EnumConfigClient enumConfigClient, + RedisService redisService) { + this.processToken = processToken; + this.appUserAccountClient = appUserAccountClient; + this.redCircleCredentialService = redCircleCredentialService; + this.sysCountryCodeService = sysCountryCodeService; + this.enumConfigClient = enumConfigClient; + this.redisService = redisService; + } /** * 检查token. @@ -300,23 +314,25 @@ public class EndpointRestController { String result = EntityUtils.toString(response.getEntity()); log.info("请求地址:{},返回信息:{}", REQUEST_URL + "?ip=" + ip, result); - JSONObject jsonObject = JSON.parseObject(result); - if (jsonObject.getInteger("ret").equals(200)) { - dataObject = jsonObject.getJSONObject("data"); - redisService.setString(redisKey, dataObject.toJSONString()); - } - } catch (Exception e) { - log.error("请求地址:{}, 异常信息:{}", REQUEST_URL + "?ip=" + ip, e.getMessage()); + JSONObject jsonObject = JSON.parseObject(result); + if (jsonObject != null && Integer.valueOf(200).equals(jsonObject.getInteger("ret"))) { + dataObject = jsonObject.getJSONObject("data"); + if (dataObject != null) { + redisService.setString(redisKey, dataObject.toJSONString()); + } + } + } catch (Exception e) { + log.error("请求地址:{}, 异常信息:{}", REQUEST_URL + "?ip=" + ip, e.getMessage()); } } log.info("IP:{}, 国家信息:{}", ip, dataObject); - if (dataObject != null && "中国".equals(dataObject.getString("country"))) { - if (!Arrays.asList("香港", "澳门", "台湾").contains(dataObject.getString("region"))) { - ResponseAssert.isTrue(UserErrorCode.REGISTRATION_FAILED, false); - } - } - return dataObject.getString("country_id"); - } + if (dataObject != null && "中国".equals(dataObject.getString("country"))) { + if (!Arrays.asList("香港", "澳门", "台湾").contains(dataObject.getString("region"))) { + ResponseAssert.isTrue(UserErrorCode.REGISTRATION_FAILED, false); + } + } + return dataObject != null ? dataObject.getString("country_id") : null; + } public void checkZone(String reqZone) { log.info("reqZone:{}", reqZone); diff --git a/rc-gateway/src/main/java/com/red/circle/gateway/filter/AuthGlobalFilter.java b/rc-gateway/src/main/java/com/red/circle/gateway/filter/AuthGlobalFilter.java index 7cb4a21b..12ddba1c 100644 --- a/rc-gateway/src/main/java/com/red/circle/gateway/filter/AuthGlobalFilter.java +++ b/rc-gateway/src/main/java/com/red/circle/gateway/filter/AuthGlobalFilter.java @@ -20,14 +20,14 @@ import com.red.circle.tool.core.text.StringPool; import com.red.circle.tool.core.text.StringUtils; import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.cloud.gateway.filter.GatewayFilterChain; -import org.springframework.cloud.gateway.filter.GlobalFilter; -import org.springframework.core.Ordered; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.core.Ordered; import org.springframework.core.io.buffer.DataBufferFactory; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatusCode; @@ -45,50 +45,60 @@ import reactor.core.publisher.Mono; * * @author pengliang on 2023/4/18 */ -@Slf4j -@Component -@RequiredArgsConstructor -public class AuthGlobalFilter implements GlobalFilter, Ordered { +@Component +public class AuthGlobalFilter implements GlobalFilter, Ordered { + + private static final Logger log = LoggerFactory.getLogger(AuthGlobalFilter.class); + private static final String ATYOU = "ATYOU"; + private static final String LIKEI = "LIKEI"; + private final ObjectMapper objectMapper; + private final GatewayProperties gatewayProperties; + private final AuthEndpointService authEndpointService; + private final PathMatcher pathMatcher = new AntPathMatcher(); + private final ResultResponse reqFailUserCredential = ResultResponse.failure(503, + "Request timed out", + "REQ_FAIL"); + + public AuthGlobalFilter(ObjectMapper objectMapper, GatewayProperties gatewayProperties, + AuthEndpointService authEndpointService) { + this.objectMapper = objectMapper; + this.gatewayProperties = gatewayProperties; + this.authEndpointService = authEndpointService; + } - private final ObjectMapper objectMapper; - private final GatewayProperties gatewayProperties; - private final AuthEndpointService authEndpointService; - private final PathMatcher pathMatcher = new AntPathMatcher(); - private final ResultResponse reqFailUserCredential = ResultResponse.failure(503, - "Request timed out", - "REQ_FAIL"); - - @Override - public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { - long nowTime = DateUtils.now().getTime(); - - if (isIgnoreMatcherPath(exchange)) { - return returnDefaultExchange(exchange, chain, nowTime); - } - - HttpHeaders reqHttpHeaders = exchange.getRequest().getHeaders(); - ResponseAssert.notEmpty(FrameworkWebErrorCode.REQ_SYS_ORIGIN, reqHttpHeaders); - - String authorization = getAuthorization(exchange); - if (checkAuthorizationNotPass(authorization)) { - return responseUnauthorized401(exchange); - } - - checkRequestRequiredHeader(exchange); - - exchange.getAttributes().put(ApiConstant.REQ_URL, ApiConstant.AUTH_SERVICE_API); - return authEndpointService.getTokenCredential(authorization) - .defaultIfEmpty(reqFailUserCredential) - .flatMap(response -> response.optionalBody().map(userCredential -> { - ServerHttpRequest request = exchange.getRequest().mutate() - .headers(httpHeaders -> addHeaders(httpHeaders, - createReqInternal(nowTime, userCredential))).build(); - exchange.getAttributes().put(ApiConstant.REQ_URL, request.getURI().getRawPath()); - return chain.filter(exchange.mutate().request(request).build()); - } - ).orElseGet(() -> responseUnauthorized401(exchange)) - ); - } + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + long nowTime = DateUtils.now().getTime(); + ServerWebExchange normalizedExchange = normalizeReqSysOrigin(exchange); + + if (isIgnoreMatcherPath(normalizedExchange)) { + return returnDefaultExchange(normalizedExchange, chain, nowTime); + } + + HttpHeaders reqHttpHeaders = normalizedExchange.getRequest().getHeaders(); + ResponseAssert.notEmpty(FrameworkWebErrorCode.REQ_SYS_ORIGIN, reqHttpHeaders); + + String authorization = getAuthorization(normalizedExchange); + if (checkAuthorizationNotPass(authorization)) { + return responseUnauthorized401(normalizedExchange); + } + + checkRequestRequiredHeader(normalizedExchange); + + normalizedExchange.getAttributes().put(ApiConstant.REQ_URL, ApiConstant.AUTH_SERVICE_API); + return authEndpointService.getTokenCredential(authorization) + .defaultIfEmpty(reqFailUserCredential) + .flatMap(response -> response.optionalBody().map(userCredential -> { + ServerHttpRequest request = normalizedExchange.getRequest().mutate() + .headers(httpHeaders -> addHeaders(httpHeaders, + createReqInternal(nowTime, userCredential))).build(); + normalizedExchange.getAttributes() + .put(ApiConstant.REQ_URL, request.getURI().getRawPath()); + return chain.filter(normalizedExchange.mutate().request(request).build()); + } + ).orElseGet(() -> responseUnauthorized401(normalizedExchange)) + ); + } private boolean checkAuthorizationNotPass(String authorization) { try { @@ -167,9 +177,42 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered { return reqInternal; } - private void addHeaders(HttpHeaders httpHeaders, ReqInternal reqInternal) { - httpHeaders.add(RequestHeaderConstant.REQ_INNER_INTERNAL, reqInternal.toTransferVal()); - } + private void addHeaders(HttpHeaders httpHeaders, ReqInternal reqInternal) { + httpHeaders.add(RequestHeaderConstant.REQ_INNER_INTERNAL, reqInternal.toTransferVal()); + } + + private ServerWebExchange normalizeReqSysOrigin(ServerWebExchange exchange) { + String rawReqSysOrigin = getHeaderFirstNotBankVal(exchange, RequestHeaderConstant.REQ_SYS_ORIGIN); + if (StringUtils.isBlank(rawReqSysOrigin)) { + return exchange; + } + + ReqSysOrigin reqSysOrigin = ReqSysOrigin.parse(rawReqSysOrigin); + if (Objects.isNull(reqSysOrigin)) { + return exchange; + } + + boolean changed = false; + if (Objects.equals(ATYOU, reqSysOrigin.getOrigin())) { + reqSysOrigin.setOrigin(LIKEI); + changed = true; + } + if (Objects.equals(ATYOU, reqSysOrigin.getOriginChild())) { + reqSysOrigin.setOriginChild(LIKEI); + changed = true; + } + if (!changed) { + return exchange; + } + + String normalizedReqSysOrigin = "origin=" + reqSysOrigin.getOrigin() + + ";originChild=" + reqSysOrigin.getOriginChild(); + ServerHttpRequest request = exchange.getRequest().mutate() + .headers(httpHeaders -> httpHeaders.set(RequestHeaderConstant.REQ_SYS_ORIGIN, + normalizedReqSysOrigin)) + .build(); + return exchange.mutate().request(request).build(); + } @Override diff --git a/rc-gateway/src/main/resources/bootstrap.yml b/rc-gateway/src/main/resources/bootstrap.yml index bebbf394..22e26b81 100644 --- a/rc-gateway/src/main/resources/bootstrap.yml +++ b/rc-gateway/src/main/resources/bootstrap.yml @@ -45,8 +45,8 @@ logging: --- spring: cloud: - gateway: - httpclient: - response-timeout: PT30S - pool: - max-idle-time: 5000 + gateway: + httpclient: + response-timeout: PT120S + pool: + max-idle-time: 5000 diff --git a/rc-service/rc-service-console/console-adapter/src/main/java/com/red/circle/console/adapter/app/party3rd/AliYunRestController.java b/rc-service/rc-service-console/console-adapter/src/main/java/com/red/circle/console/adapter/app/party3rd/AliYunRestController.java index cf6c8505..c3a1b2b5 100644 --- a/rc-service/rc-service-console/console-adapter/src/main/java/com/red/circle/console/adapter/app/party3rd/AliYunRestController.java +++ b/rc-service/rc-service-console/console-adapter/src/main/java/com/red/circle/console/adapter/app/party3rd/AliYunRestController.java @@ -1,31 +1,94 @@ -package com.red.circle.console.adapter.app.party3rd;//package com.sugartime.app.server.api.app.external; - -import com.red.circle.external.inner.endpoint.oss.OssServiceClient; -import com.red.circle.framework.core.asserts.ResponseAssert; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * 阿里云服务. - */ +package com.red.circle.console.adapter.app.party3rd;//package com.sugartime.app.server.api.app.external; + +import com.red.circle.external.inner.endpoint.oss.OssServiceClient; +import com.red.circle.framework.core.asserts.ResponseAssert; +import java.util.Map; +import java.util.Objects; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.multipart.MultipartFile; + +/** + * 阿里云服务. + */ @Slf4j @RequiredArgsConstructor @RestController @RequestMapping(value = "/ali-yun", produces = MediaType.APPLICATION_JSON_VALUE) -public class AliYunRestController { - - private final OssServiceClient ossServiceClient; - - /** - * 阿里云sts. - */ - @GetMapping("/oss/sts") - public Object sts() { - return ResponseAssert.requiredSuccess(ossServiceClient.sts()); - } - -} +public class AliYunRestController { + + private final OssServiceClient ossServiceClient; + @Value("${feign.external.url}") + private String externalBaseUrl; + + /** + * 阿里云sts. + */ + @GetMapping("/oss/sts") + public Object sts() { + return ResponseAssert.requiredSuccess(ossServiceClient.sts()); + } + + @PostMapping(value = "/oss/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public Map upload( + @RequestParam("file") MultipartFile file, + @RequestParam(value = "dir", required = false) String dir, + @RequestParam(value = "filename", required = false) String filename) { + try { + HttpHeaders requestHeaders = new HttpHeaders(); + requestHeaders.setContentType(MediaType.MULTIPART_FORM_DATA); + + HttpHeaders fileHeaders = new HttpHeaders(); + if (file.getContentType() != null) { + fileHeaders.setContentType(MediaType.parseMediaType(file.getContentType())); + } + + ByteArrayResource resource = new ByteArrayResource(file.getBytes()) { + @Override + public String getFilename() { + return Objects.toString(file.getOriginalFilename(), "upload.bin"); + } + }; + + MultiValueMap body = new LinkedMultiValueMap<>(); + body.add("file", new HttpEntity<>(resource, fileHeaders)); + + String uploadUrl = externalBaseUrl.replaceAll("/+$", "") + + "/oss/upload/general?dir=" + encode(dir) + + "&filename=" + encode(filename); + ResponseEntity response = new RestTemplate().postForEntity( + uploadUrl, + new HttpEntity<>(body, requestHeaders), + Map.class); + Map responseBody = response.getBody(); + if (responseBody == null || !Boolean.TRUE.equals(responseBody.get("status"))) { + String errorMsg = responseBody == null ? "upload failed" + : Objects.toString(responseBody.get("errorMsg"), "upload failed"); + throw new IllegalStateException(errorMsg); + } + return Map.of("name", Objects.toString(responseBody.get("body"), "")); + } catch (Exception e) { + log.error("console upload proxy failed dir={} filename={}", dir, filename, e); + throw new IllegalStateException("upload failed", e); + } + } + + private String encode(String value) { + return java.net.URLEncoder.encode(Objects.toString(value, ""), java.nio.charset.StandardCharsets.UTF_8); + } + +} diff --git a/rc-service/rc-service-external/external-adapter/src/main/java/com/red/circle/external/adapter/app/oss/LocalDiskFileRestController.java b/rc-service/rc-service-external/external-adapter/src/main/java/com/red/circle/external/adapter/app/oss/LocalDiskFileRestController.java new file mode 100644 index 00000000..f87ca767 --- /dev/null +++ b/rc-service/rc-service-external/external-adapter/src/main/java/com/red/circle/external/adapter/app/oss/LocalDiskFileRestController.java @@ -0,0 +1,49 @@ +package com.red.circle.external.adapter.app.oss; + +import com.red.circle.external.app.oss.LocalDiskStorageService; +import com.red.circle.framework.web.annotation.IgnoreResultResponse; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.http.CacheControl; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.util.AntPathMatcher; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.HandlerMapping; + +import java.time.Duration; + +/** + * 开发环境本地文件读取接口. + */ +@RestController +@RequestMapping("/oss/local") +public class LocalDiskFileRestController { + + private final AntPathMatcher pathMatcher = new AntPathMatcher(); + private final LocalDiskStorageService localDiskStorageService; + + public LocalDiskFileRestController(LocalDiskStorageService localDiskStorageService) { + this.localDiskStorageService = localDiskStorageService; + } + + @IgnoreResultResponse + @GetMapping("/**") + public ResponseEntity file(HttpServletRequest request) { + LocalDiskStorageService.StoredFile file = localDiskStorageService.load(resolveKey(request)); + return ResponseEntity.ok() + .contentType(MediaType.parseMediaType(file.contentType())) + .cacheControl(CacheControl.maxAge(Duration.ofDays(7)).cachePublic()) + .contentLength(file.contentLength()) + .body(file.resource()); + } + + private String resolveKey(HttpServletRequest request) { + String pathWithinMapping = + (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE); + String bestMatchPattern = + (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE); + return pathMatcher.extractPathWithinPattern(bestMatchPattern, pathWithinMapping); + } +} diff --git a/rc-service/rc-service-external/external-adapter/src/main/java/com/red/circle/external/adapter/app/oss/OssRestController.java b/rc-service/rc-service-external/external-adapter/src/main/java/com/red/circle/external/adapter/app/oss/OssRestController.java index 680dbae5..23f52149 100644 --- a/rc-service/rc-service-external/external-adapter/src/main/java/com/red/circle/external/adapter/app/oss/OssRestController.java +++ b/rc-service/rc-service-external/external-adapter/src/main/java/com/red/circle/external/adapter/app/oss/OssRestController.java @@ -1,37 +1,52 @@ package com.red.circle.external.adapter.app.oss; -import com.red.circle.component.oss.OssService; -import com.red.circle.component.oss.aliyun.service.AliYunStsResponse; -import com.red.circle.component.oss.aliyun.service.AliYunStsService; -import com.red.circle.external.response.OssErrorCode; -import com.red.circle.external.utils.FileUtils; -import com.red.circle.framework.dto.ResultResponse; -import com.red.circle.framework.web.annotation.IgnoreResultResponse; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; - -import java.io.IOException; -import java.util.UUID; +import com.red.circle.component.oss.OssService; +import com.red.circle.component.oss.aliyun.service.AliYunStsResponse; +import com.red.circle.component.oss.aliyun.service.AliYunStsService; +import com.red.circle.external.app.oss.LocalDiskStorageService; +import com.red.circle.external.app.oss.TencentCosStorageService; +import com.red.circle.external.response.OssErrorCode; +import com.red.circle.external.utils.FileUtils; +import com.red.circle.framework.dto.ResultResponse; +import com.red.circle.framework.web.annotation.IgnoreResultResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.MediaType; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.UUID; /** * 阿里云,OSS存储. * * @author pengliang on 2020/9/7 * @eo.api-type http - * @eo.groupName 第三方服务.OSS存储 - * @eo.path /external/oss - */ -@Slf4j -@RequiredArgsConstructor -@RestController -@RequestMapping(value = "/oss", produces = MediaType.APPLICATION_JSON_VALUE) -public class OssRestController { - - private final AliYunStsService aliYunStsService; - private final OssService ossService; + * @eo.groupName 第三方服务.OSS存储 + * @eo.path /external/oss + */ +@RestController +@RequestMapping(value = "/oss", produces = MediaType.APPLICATION_JSON_VALUE) +public class OssRestController { + + private static final Logger log = LoggerFactory.getLogger(OssRestController.class); + + private final AliYunStsService aliYunStsService; + private final OssService ossService; + private final LocalDiskStorageService localDiskStorageService; + private final TencentCosStorageService tencentCosStorageService; + + public OssRestController( + AliYunStsService aliYunStsService, + OssService ossService, + LocalDiskStorageService localDiskStorageService, + TencentCosStorageService tencentCosStorageService) { + this.aliYunStsService = aliYunStsService; + this.ossService = ossService; + this.localDiskStorageService = localDiskStorageService; + this.tencentCosStorageService = tencentCosStorageService; + } /** * sts临时令牌. @@ -55,8 +70,8 @@ public class OssRestController { * @eo.method Post */ @IgnoreResultResponse - @PostMapping("/upload") - public ResultResponse upload(@RequestPart("file") MultipartFile file) { + @PostMapping("/upload") + public ResultResponse upload(@RequestPart("file") MultipartFile file) { try { if (file.isEmpty()) { return ResultResponse.failure(OssErrorCode.FILE_IS_NULL); @@ -69,17 +84,115 @@ public class OssRestController { return ResultResponse.failure(OssErrorCode.FILE_TYPE_NOT_SUPPORTED); } log.warn(file.getOriginalFilename()); - log.warn(file.getName()); - log.warn(file.getOriginalFilename()); - String fileName = "avatar/" +UUID.randomUUID() + FileUtils.getSuffix(file.getOriginalFilename());; - ossService.uploadInputStream(file.getInputStream(), fileName); - return ResultResponse.success(ossService.getAccessUrl(fileName)); + log.warn(file.getName()); + log.warn(file.getOriginalFilename()); + String suffix = FileUtils.getSuffix(file.getOriginalFilename()); + if (localDiskStorageService.isEnabled()) { + return ResultResponse.success( + localDiskStorageService.uploadAvatar( + file.getInputStream(), + file.getContentType(), + suffix)); + } + if (tencentCosStorageService.isEnabled()) { + return ResultResponse.success( + tencentCosStorageService.uploadAvatar( + file.getInputStream(), + file.getSize(), + file.getContentType(), + suffix)); + } + String fileName = "avatar/" + UUID.randomUUID() + suffix; + ossService.uploadInputStream(file.getInputStream(), fileName); + return ResultResponse.success(ossService.getAccessUrl(fileName)); } catch (Exception e) { log.error(e.getMessage(), e); return ResultResponse.failure(OssErrorCode.NETWORK_ANOMALY); - } - } - - - -} + } + } + + @IgnoreResultResponse + @PostMapping("/upload/general") + public ResultResponse uploadGeneral( + @RequestPart("file") MultipartFile file, + @RequestParam(value = "dir", required = false) String dir, + @RequestParam(value = "filename", required = false) String filename) { + try { + if (file.isEmpty()) { + return ResultResponse.failure(OssErrorCode.FILE_IS_NULL); + } + if (file.getSize() > 10L * 1024 * 1024) { + return ResultResponse.failure(OssErrorCode.FILE_SIZE_GREATER_THAN_10M); + } + String storageKey = buildStorageKey(dir, filename, file.getOriginalFilename()); + if (localDiskStorageService.isEnabled()) { + return ResultResponse.success(localDiskStorageService.upload(storageKey, file.getInputStream())); + } + if (tencentCosStorageService.isEnabled()) { + tencentCosStorageService.upload( + storageKey, + file.getInputStream(), + file.getSize(), + file.getContentType()); + return ResultResponse.success(tencentCosStorageService.getAccessUrl(storageKey)); + } + ossService.uploadInputStream(file.getInputStream(), storageKey); + return ResultResponse.success(ossService.getAccessUrl(storageKey)); + } catch (Exception e) { + log.error("generic upload failed dir={} filename={}", dir, filename, e); + return ResultResponse.failure(OssErrorCode.NETWORK_ANOMALY); + } + } + + private String buildStorageKey(String dir, String filename, String originalFilename) { + String normalizedDir = normalizeDirectory(dir); + String targetFilename = buildFilename(filename, originalFilename); + return StringUtils.hasText(normalizedDir) ? normalizedDir + "/" + targetFilename : targetFilename; + } + + private String normalizeDirectory(String dir) { + if (!StringUtils.hasText(dir)) { + return "other"; + } + String normalized = dir.trim().replace("\\", "/"); + while (normalized.startsWith("/")) { + normalized = normalized.substring(1); + } + while (normalized.endsWith("/")) { + normalized = normalized.substring(0, normalized.length() - 1); + } + if (normalized.contains("..")) { + throw new IllegalArgumentException("invalid upload dir"); + } + return normalized; + } + + private String buildFilename(String filename, String originalFilename) { + String suffix = extractSuffix(originalFilename); + String target = StringUtils.hasText(filename) ? sanitizeFilename(filename.trim()) : UUID.randomUUID() + suffix; + if (!target.contains(".") && StringUtils.hasText(suffix)) { + target = target + suffix; + } + return target; + } + + private String sanitizeFilename(String filename) { + String normalized = filename.replace("\\", "/"); + int index = normalized.lastIndexOf('/'); + String target = index >= 0 ? normalized.substring(index + 1) : normalized; + if (target.contains("..")) { + throw new IllegalArgumentException("invalid upload filename"); + } + return target; + } + + private String extractSuffix(String originalFilename) { + if (!StringUtils.hasText(originalFilename) || !originalFilename.contains(".")) { + return ""; + } + return FileUtils.getSuffix(originalFilename); + } + + + +} diff --git a/rc-service/rc-service-external/external-application/pom.xml b/rc-service/rc-service-external/external-application/pom.xml index bcd9e1d9..458946b6 100644 --- a/rc-service/rc-service-external/external-application/pom.xml +++ b/rc-service/rc-service-external/external-application/pom.xml @@ -7,18 +7,24 @@ 应用层,服务实现 jar - - - com.red.circle - external-client - + + + com.red.circle + external-client + - - com.red.circle - external-infrastructure - - - + + com.red.circle + external-infrastructure + + + + com.qcloud + cos_api + 5.6.265 + + + rc-service-external diff --git a/rc-service/rc-service-external/external-application/src/main/java/com/red/circle/external/app/oss/LocalDiskStorageProperties.java b/rc-service/rc-service-external/external-application/src/main/java/com/red/circle/external/app/oss/LocalDiskStorageProperties.java new file mode 100644 index 00000000..4feb0556 --- /dev/null +++ b/rc-service/rc-service-external/external-application/src/main/java/com/red/circle/external/app/oss/LocalDiskStorageProperties.java @@ -0,0 +1,47 @@ +package com.red.circle.external.app.oss; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +/** + * 本地磁盘存储配置. + */ +@Component +@ConfigurationProperties(prefix = "red-circle.oss.local-disk") +public class LocalDiskStorageProperties { + + private boolean enabled; + private String basePath = "/application/uploads"; + private String accessUrl = "http://10.0.2.2:3000/oss/local"; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getBasePath() { + return basePath; + } + + public void setBasePath(String basePath) { + this.basePath = basePath; + } + + public String getAccessUrl() { + return accessUrl; + } + + public void setAccessUrl(String accessUrl) { + this.accessUrl = accessUrl; + } + + public boolean isConfigured() { + return enabled + && StringUtils.hasText(basePath) + && StringUtils.hasText(accessUrl); + } +} diff --git a/rc-service/rc-service-external/external-application/src/main/java/com/red/circle/external/app/oss/LocalDiskStorageService.java b/rc-service/rc-service-external/external-application/src/main/java/com/red/circle/external/app/oss/LocalDiskStorageService.java new file mode 100644 index 00000000..4f6b725c --- /dev/null +++ b/rc-service/rc-service-external/external-application/src/main/java/com/red/circle/external/app/oss/LocalDiskStorageService.java @@ -0,0 +1,204 @@ +package com.red.circle.external.app.oss; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.Resource; +import org.springframework.core.io.UrlResource; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.UUID; + +/** + * 开发环境本地磁盘存储服务. + */ +@Service +public class LocalDiskStorageService { + + private static final Logger log = LoggerFactory.getLogger(LocalDiskStorageService.class); + private static final String AVATAR_PREFIX = "avatar/"; + private static final String EXTERNAL_LOCAL_PREFIX = "/external/oss/local/"; + private static final String LOCAL_PREFIX = "/oss/local/"; + + private final LocalDiskStorageProperties properties; + + public LocalDiskStorageService(LocalDiskStorageProperties properties) { + this.properties = properties; + } + + public boolean isEnabled() { + return properties.isConfigured(); + } + + public String uploadAvatar(InputStream inputStream, String contentType, String suffix) { + String key = AVATAR_PREFIX + UUID.randomUUID() + normalizeSuffix(suffix); + writeFile(key, inputStream); + return buildAccessUrl(key); + } + + public String upload(String key, InputStream inputStream) { + writeFile(key, inputStream); + return buildAccessUrl(key); + } + + public StoredFile load(String keyOrUrl) { + String key = resolveKey(keyOrUrl); + if (!StringUtils.hasText(key)) { + throw new IllegalArgumentException("local disk key is empty"); + } + Path path = resolveStoragePath(key); + if (!Files.exists(path) || !Files.isRegularFile(path)) { + throw new IllegalArgumentException("local disk file does not exist: " + key); + } + try { + Resource resource = new UrlResource(path.toUri()); + String contentType = Files.probeContentType(path); + long contentLength = Files.size(path); + return new StoredFile( + resource, + StringUtils.hasText(contentType) ? contentType : "application/octet-stream", + contentLength); + } catch (IOException e) { + throw new IllegalStateException("load local file failed: " + key, e); + } + } + + public boolean isManagedUrl(String source) { + if (!StringUtils.hasText(source)) { + return false; + } + if (!looksLikeUrl(source)) { + return false; + } + String path = URI.create(source).getPath(); + return StringUtils.hasText(path) + && (path.startsWith(EXTERNAL_LOCAL_PREFIX) || path.startsWith(LOCAL_PREFIX)); + } + + public String getAccessUrl(String keyOrUrl) { + if (!StringUtils.hasText(keyOrUrl)) { + return keyOrUrl; + } + if (looksLikeUrl(keyOrUrl)) { + return keyOrUrl; + } + return buildAccessUrl(keyOrUrl); + } + + public void remove(String url) { + String key = resolveKey(url); + if (!StringUtils.hasText(key)) { + return; + } + try { + Files.deleteIfExists(resolveStoragePath(key)); + } catch (IOException e) { + log.error("remove local file failed url={}", url, e); + throw new IllegalStateException("remove local file failed", e); + } + } + + public void processFileSaveAs(String source, String target) { + if (!StringUtils.hasText(target)) { + return; + } + copy(source, target); + } + + public String processImgSaveAsCompressZoom(String source, String target, int height) { + if (!StringUtils.hasText(target)) { + return processImgSaveAsCompressZoom(source, height); + } + copy(source, target); + return buildAccessUrl(target); + } + + public String processImgSaveAsCompressZoom(String source, int height) { + return getAccessUrl(source); + } + + private void writeFile(String key, InputStream inputStream) { + Path target = resolveStoragePath(key); + try { + Files.createDirectories(target.getParent()); + Files.copy(inputStream, target, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + log.error("write local file failed key={}", key, e); + throw new IllegalStateException("write local file failed", e); + } + } + + private void copy(String source, String target) { + String sourceKey = resolveKey(source); + if (!StringUtils.hasText(sourceKey)) { + return; + } + Path sourcePath = resolveStoragePath(sourceKey); + Path targetPath = resolveStoragePath(target); + try { + Files.createDirectories(targetPath.getParent()); + Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + log.error("copy local file failed source={} target={}", source, target, e); + throw new IllegalStateException("copy local file failed", e); + } + } + + private Path resolveStoragePath(String key) { + Path basePath = Path.of(properties.getBasePath()).toAbsolutePath().normalize(); + Path resolved = basePath.resolve(key).normalize(); + if (!resolved.startsWith(basePath)) { + throw new IllegalArgumentException("invalid local disk key: " + key); + } + return resolved; + } + + private String resolveKey(String keyOrUrl) { + if (!StringUtils.hasText(keyOrUrl)) { + return keyOrUrl; + } + if (!looksLikeUrl(keyOrUrl)) { + return normalizeKey(keyOrUrl); + } + String path = URI.create(keyOrUrl).getPath(); + if (!StringUtils.hasText(path)) { + return null; + } + if (path.startsWith(EXTERNAL_LOCAL_PREFIX)) { + return normalizeKey(path.substring(EXTERNAL_LOCAL_PREFIX.length())); + } + if (path.startsWith(LOCAL_PREFIX)) { + return normalizeKey(path.substring(LOCAL_PREFIX.length())); + } + return null; + } + + private String buildAccessUrl(String key) { + String accessUrl = properties.getAccessUrl(); + return accessUrl.endsWith("/") ? accessUrl + key : accessUrl + "/" + key; + } + + private String normalizeKey(String key) { + return key.startsWith("/") ? key.substring(1) : key; + } + + private String normalizeSuffix(String suffix) { + if (!StringUtils.hasText(suffix)) { + return ""; + } + return suffix.startsWith(".") ? suffix : "." + suffix; + } + + private boolean looksLikeUrl(String value) { + return value.startsWith("http://") || value.startsWith("https://"); + } + + public record StoredFile(Resource resource, String contentType, long contentLength) { + } +} diff --git a/rc-service/rc-service-external/external-application/src/main/java/com/red/circle/external/app/oss/TencentCosProperties.java b/rc-service/rc-service-external/external-application/src/main/java/com/red/circle/external/app/oss/TencentCosProperties.java new file mode 100644 index 00000000..2783e318 --- /dev/null +++ b/rc-service/rc-service-external/external-application/src/main/java/com/red/circle/external/app/oss/TencentCosProperties.java @@ -0,0 +1,130 @@ +package com.red.circle.external.app.oss; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +/** + * 腾讯云 COS 配置. + */ +@Component +@ConfigurationProperties(prefix = "red-circle.oss.tencent-cos") +public class TencentCosProperties { + + private boolean enabled = true; + private String secretId = "IKID4FEAAyYv64nK1d2C6YnofMqCB0kLhq05"; + private String secretKey = "UwFJAmAKFwQhjWGn58vUotkMktoumQq2"; + private String bucketName = "app-release-1417798587"; + private String region = "me-saudi-arabia"; + private String accessUrl = "https://app-release-1417798587.cos.me-saudi-arabia.myqcloud.com"; + private int connectionTimeoutMs = 15000; + private int connectionRequestTimeoutMs = 15000; + private int socketTimeoutMs = 120000; + private int requestTimeoutMs = 120000; + private int shutdownTimeoutMs = 10000; + private int maxErrorRetry = 0; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getSecretId() { + return secretId; + } + + public void setSecretId(String secretId) { + this.secretId = secretId; + } + + public String getSecretKey() { + return secretKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + + public String getBucketName() { + return bucketName; + } + + public void setBucketName(String bucketName) { + this.bucketName = bucketName; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public String getAccessUrl() { + return accessUrl; + } + + public void setAccessUrl(String accessUrl) { + this.accessUrl = accessUrl; + } + + public int getConnectionTimeoutMs() { + return connectionTimeoutMs; + } + + public void setConnectionTimeoutMs(int connectionTimeoutMs) { + this.connectionTimeoutMs = connectionTimeoutMs; + } + + public int getConnectionRequestTimeoutMs() { + return connectionRequestTimeoutMs; + } + + public void setConnectionRequestTimeoutMs(int connectionRequestTimeoutMs) { + this.connectionRequestTimeoutMs = connectionRequestTimeoutMs; + } + + public int getSocketTimeoutMs() { + return socketTimeoutMs; + } + + public void setSocketTimeoutMs(int socketTimeoutMs) { + this.socketTimeoutMs = socketTimeoutMs; + } + + public int getRequestTimeoutMs() { + return requestTimeoutMs; + } + + public void setRequestTimeoutMs(int requestTimeoutMs) { + this.requestTimeoutMs = requestTimeoutMs; + } + + public int getShutdownTimeoutMs() { + return shutdownTimeoutMs; + } + + public void setShutdownTimeoutMs(int shutdownTimeoutMs) { + this.shutdownTimeoutMs = shutdownTimeoutMs; + } + + public int getMaxErrorRetry() { + return maxErrorRetry; + } + + public void setMaxErrorRetry(int maxErrorRetry) { + this.maxErrorRetry = maxErrorRetry; + } + + public boolean isConfigured() { + return enabled + && StringUtils.hasText(secretId) + && StringUtils.hasText(secretKey) + && StringUtils.hasText(bucketName) + && StringUtils.hasText(region); + } +} diff --git a/rc-service/rc-service-external/external-application/src/main/java/com/red/circle/external/app/oss/TencentCosStorageService.java b/rc-service/rc-service-external/external-application/src/main/java/com/red/circle/external/app/oss/TencentCosStorageService.java new file mode 100644 index 00000000..ec2debea --- /dev/null +++ b/rc-service/rc-service-external/external-application/src/main/java/com/red/circle/external/app/oss/TencentCosStorageService.java @@ -0,0 +1,190 @@ +package com.red.circle.external.app.oss; + +import com.qcloud.cos.COSClient; +import com.qcloud.cos.ClientConfig; +import com.qcloud.cos.auth.BasicCOSCredentials; +import com.qcloud.cos.auth.COSCredentials; +import com.qcloud.cos.http.HttpProtocol; +import com.qcloud.cos.model.CopyObjectRequest; +import com.qcloud.cos.model.ObjectMetadata; +import com.qcloud.cos.model.PutObjectRequest; +import com.qcloud.cos.region.Region; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.util.UUID; + +/** + * 腾讯云 COS 存储服务. + */ +@Service +public class TencentCosStorageService { + + private static final String AVATAR_PREFIX = "avatar/"; + private static final Logger log = LoggerFactory.getLogger(TencentCosStorageService.class); + + private final TencentCosProperties properties; + + public TencentCosStorageService(TencentCosProperties properties) { + this.properties = properties; + } + + public boolean isEnabled() { + return properties.isConfigured(); + } + + public String uploadAvatar(InputStream inputStream, long contentLength, String contentType, String suffix) { + String key = AVATAR_PREFIX + UUID.randomUUID() + suffix; + upload(key, inputStream, contentLength, contentType); + return buildAccessUrl(key); + } + + public void upload(String key, InputStream inputStream, long contentLength, String contentType) { + COSClient client = buildClient(); + try { + byte[] data = inputStream.readAllBytes(); + ObjectMetadata metadata = new ObjectMetadata(); + metadata.setContentLength(data.length); + if (StringUtils.hasText(contentType)) { + metadata.setContentType(contentType); + } + client.putObject( + new PutObjectRequest( + properties.getBucketName(), key, new ByteArrayInputStream(data), metadata)); + } catch (IOException e) { + log.error("tencent cos read upload stream failed key={}", key, e); + throw new IllegalStateException("read upload stream failed", e); + } catch (Exception e) { + log.error("tencent cos upload failed key={}", key, e); + throw e; + } finally { + client.shutdown(); + } + } + + public boolean isManagedUrl(String source) { + if (!isEnabled() || !StringUtils.hasText(source)) { + return false; + } + if (source.startsWith(getAccessUrlPrefix())) { + return true; + } + return source.contains(properties.getBucketName() + ".cos." + properties.getRegion() + ".myqcloud.com/"); + } + + public String getAccessUrl(String keyOrUrl) { + if (!StringUtils.hasText(keyOrUrl)) { + return keyOrUrl; + } + if (looksLikeUrl(keyOrUrl)) { + return keyOrUrl; + } + return buildAccessUrl(keyOrUrl); + } + + public void remove(String url) { + String key = resolveKey(url); + if (!StringUtils.hasText(key)) { + return; + } + COSClient client = buildClient(); + try { + client.deleteObject(properties.getBucketName(), key); + } catch (Exception e) { + log.error("tencent cos remove failed url={}", url, e); + throw e; + } finally { + client.shutdown(); + } + } + + public void processFileSaveAs(String source, String target) { + if (!StringUtils.hasText(target)) { + return; + } + copyObject(source, target); + } + + public String processImgSaveAsCompressZoom(String source, String target, int height) { + if (!StringUtils.hasText(target)) { + return processImgSaveAsCompressZoom(source, height); + } + copyObject(source, target); + return buildAccessUrl(target); + } + + public String processImgSaveAsCompressZoom(String source, int height) { + return getAccessUrl(source); + } + + private void copyObject(String source, String target) { + String sourceKey = resolveKey(source); + if (!StringUtils.hasText(sourceKey)) { + return; + } + COSClient client = buildClient(); + try { + CopyObjectRequest request = + new CopyObjectRequest(properties.getBucketName(), sourceKey, properties.getBucketName(), target); + client.copyObject(request); + } catch (Exception e) { + log.error("tencent cos copy failed source={} target={}", source, target, e); + throw e; + } finally { + client.shutdown(); + } + } + + private String resolveKey(String keyOrUrl) { + if (!StringUtils.hasText(keyOrUrl)) { + return keyOrUrl; + } + if (!looksLikeUrl(keyOrUrl)) { + return keyOrUrl; + } + if (!isManagedUrl(keyOrUrl)) { + return null; + } + String path = URI.create(keyOrUrl).getPath(); + if (!StringUtils.hasText(path)) { + return null; + } + return path.startsWith("/") ? path.substring(1) : path; + } + + private String buildAccessUrl(String key) { + return getAccessUrlPrefix() + key; + } + + private String getAccessUrlPrefix() { + String accessUrl = StringUtils.hasText(properties.getAccessUrl()) + ? properties.getAccessUrl() + : "https://" + properties.getBucketName() + ".cos." + properties.getRegion() + ".myqcloud.com"; + return accessUrl.endsWith("/") ? accessUrl : accessUrl + "/"; + } + + private boolean looksLikeUrl(String value) { + return value.startsWith("http://") || value.startsWith("https://"); + } + + private COSClient buildClient() { + COSCredentials credentials = + new BasicCOSCredentials(properties.getSecretId(), properties.getSecretKey()); + ClientConfig clientConfig = new ClientConfig(new Region(properties.getRegion())); + clientConfig.setHttpProtocol(HttpProtocol.https); + clientConfig.setConnectionTimeout(properties.getConnectionTimeoutMs()); + clientConfig.setConnectionRequestTimeout(properties.getConnectionRequestTimeoutMs()); + clientConfig.setSocketTimeout(properties.getSocketTimeoutMs()); + clientConfig.setRequestTimeOutEnable(true); + clientConfig.setRequestTimeout(properties.getRequestTimeoutMs()); + clientConfig.setShutdownTimeout(properties.getShutdownTimeoutMs()); + clientConfig.setMaxErrorRetry(properties.getMaxErrorRetry()); + return new COSClient(credentials, clientConfig); + } +} diff --git a/rc-service/rc-service-external/external-inner-endpoint/src/main/java/com/red/circle/external/inner/service/oss/impl/OssServiceClientServiceImpl.java b/rc-service/rc-service-external/external-inner-endpoint/src/main/java/com/red/circle/external/inner/service/oss/impl/OssServiceClientServiceImpl.java index 8294fbbe..a7a108f8 100644 --- a/rc-service/rc-service-external/external-inner-endpoint/src/main/java/com/red/circle/external/inner/service/oss/impl/OssServiceClientServiceImpl.java +++ b/rc-service/rc-service-external/external-inner-endpoint/src/main/java/com/red/circle/external/inner/service/oss/impl/OssServiceClientServiceImpl.java @@ -1,56 +1,103 @@ package com.red.circle.external.inner.service.oss.impl; -import com.red.circle.component.oss.OssService; -import com.red.circle.component.oss.aliyun.service.AliYunStsService; -import com.red.circle.external.inner.service.oss.OssServiceClientService; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; +import com.red.circle.component.oss.OssService; +import com.red.circle.component.oss.aliyun.service.AliYunStsService; +import com.red.circle.external.app.oss.LocalDiskStorageService; +import com.red.circle.external.app.oss.TencentCosStorageService; +import com.red.circle.external.inner.service.oss.OssServiceClientService; +import org.springframework.stereotype.Service; /** - * oss 服务api. - * - * @author pengliang on 2023/10/15 - */ -@Service -@RequiredArgsConstructor -public class OssServiceClientServiceImpl implements OssServiceClientService { - - private final OssService ossService; - private final AliYunStsService aliYunStsService; + * oss 服务api. + * + * @author pengliang on 2023/10/15 + */ +@Service +public class OssServiceClientServiceImpl implements OssServiceClientService { + + private final OssService ossService; + private final AliYunStsService aliYunStsService; + private final LocalDiskStorageService localDiskStorageService; + private final TencentCosStorageService tencentCosStorageService; + + public OssServiceClientServiceImpl( + OssService ossService, + AliYunStsService aliYunStsService, + LocalDiskStorageService localDiskStorageService, + TencentCosStorageService tencentCosStorageService) { + this.ossService = ossService; + this.aliYunStsService = aliYunStsService; + this.localDiskStorageService = localDiskStorageService; + this.tencentCosStorageService = tencentCosStorageService; + } @Override public Object sts() { return aliYunStsService.getAcsResponse(); } - @Override - public void remove(String url) { - ossService.remove(url); - } + @Override + public void remove(String url) { + if (localDiskStorageService.isManagedUrl(url)) { + localDiskStorageService.remove(url); + return; + } + if (tencentCosStorageService.isManagedUrl(url)) { + tencentCosStorageService.remove(url); + return; + } + ossService.remove(url); + } - @Override - public String getAccessUrl(String key) { - return ossService.getAccessUrl(key); - } + @Override + public String getAccessUrl(String key) { + if (localDiskStorageService.isManagedUrl(key)) { + return key; + } + if (tencentCosStorageService.isManagedUrl(key)) { + return key; + } + return ossService.getAccessUrl(key); + } @Override public String getVideoCover(String key) { return ossService.getVideoCover(key); } - @Override - public void processFileSaveAs(String source, String target, String styleType) { - ossService.processFileSaveAs(source, target, styleType); - } + @Override + public void processFileSaveAs(String source, String target, String styleType) { + if (localDiskStorageService.isManagedUrl(source)) { + localDiskStorageService.processFileSaveAs(source, target); + return; + } + if (tencentCosStorageService.isManagedUrl(source)) { + tencentCosStorageService.processFileSaveAs(source, target); + return; + } + ossService.processFileSaveAs(source, target, styleType); + } - @Override - public String processImgSaveAsCompressZoom(String source, String target, int height) { - return ossService.processImgSaveAsCompressZoom(source, target, height); - } + @Override + public String processImgSaveAsCompressZoom(String source, String target, int height) { + if (localDiskStorageService.isManagedUrl(source)) { + return localDiskStorageService.processImgSaveAsCompressZoom(source, target, height); + } + if (tencentCosStorageService.isManagedUrl(source)) { + return tencentCosStorageService.processImgSaveAsCompressZoom(source, target, height); + } + return ossService.processImgSaveAsCompressZoom(source, target, height); + } - @Override - public String processImgSaveAsCompressZoom(String source, int height) { - return ossService.processImgSaveAsCompressZoom(source, height); - } - -} + @Override + public String processImgSaveAsCompressZoom(String source, int height) { + if (localDiskStorageService.isManagedUrl(source)) { + return localDiskStorageService.processImgSaveAsCompressZoom(source, height); + } + if (tencentCosStorageService.isManagedUrl(source)) { + return tencentCosStorageService.processImgSaveAsCompressZoom(source, height); + } + return ossService.processImgSaveAsCompressZoom(source, height); + } + +} diff --git a/rc-service/rc-service-external/external-start/src/main/java/com/red/circle/RedisServiceFallbackConfiguration.java b/rc-service/rc-service-external/external-start/src/main/java/com/red/circle/RedisServiceFallbackConfiguration.java new file mode 100644 index 00000000..5684b23a --- /dev/null +++ b/rc-service/rc-service-external/external-start/src/main/java/com/red/circle/RedisServiceFallbackConfiguration.java @@ -0,0 +1,181 @@ +package com.red.circle; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; +import com.red.circle.component.redis.annotation.aspect.TaskCacheLockAspect; +import com.red.circle.component.redis.props.RedisConfigProperties; +import com.red.circle.component.redis.service.RedisService; +import com.red.circle.tool.core.text.StringUtils; +import io.lettuce.core.internal.HostAndPort; +import io.lettuce.core.resource.ClientResources; +import io.lettuce.core.resource.DnsResolvers; +import io.lettuce.core.resource.MappingSocketAddressResolver; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cache.CacheManager; +import org.springframework.cache.interceptor.KeyGenerator; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.cache.RedisCacheWriter; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.RedisStandaloneConfiguration; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.GenericToStringSerializer; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.RedisSerializationContext; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +@Configuration +@EnableConfigurationProperties({RedisConfigProperties.class, RedisProperties.class}) +public class RedisServiceFallbackConfiguration { + + @Bean + @Primary + public RedisTemplate redCircleRedisTemplate( + RedisConnectionFactory connectionFactory) { + RedisTemplate template = new RedisTemplate<>(); + template.setValueSerializer(new GenericToStringSerializer<>(Object.class)); + template.setKeySerializer(new StringRedisSerializer()); + template.setHashKeySerializer(new StringRedisSerializer()); + template.setConnectionFactory(connectionFactory); + return template; + } + + @Bean + @ConditionalOnMissingBean + public KeyGenerator simpleKeyGenerator() { + return (target, method, params) -> { + StringBuilder builder = new StringBuilder(); + builder.append(target.getClass().getSimpleName()); + builder.append("."); + builder.append(method.getName()); + builder.append("["); + for (Object param : params) { + builder.append(param); + } + builder.append("]"); + return builder.toString(); + }; + } + + @Bean + @ConditionalOnMissingBean + public CacheManager cacheManager( + RedisConnectionFactory redisConnectionFactory, + RedisConfigProperties redisConfigProperties) { + return new RedisCacheManager( + RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory), + getRedisCacheConfigurationWithTtl(1800), + getRedisCacheConfigurationMap(redisConfigProperties)); + } + + @Bean + @Primary + @ConditionalOnMissingBean + public RedisService redisService( + @Qualifier("redCircleRedisTemplate") RedisTemplate redisTemplate) { + return new RedisService(redisTemplate); + } + + @Bean + @ConditionalOnMissingBean + public TaskCacheLockAspect taskCacheLockAspect( + @Qualifier("redCircleRedisTemplate") RedisTemplate redisTemplate) { + return new TaskCacheLockAspect(redisTemplate.opsForValue()); + } + + @Bean + @ConditionalOnMissingBean + public LettuceConnectionFactory redisConnectionFactory(RedisProperties redisProperties) { + MappingSocketAddressResolver resolver = + MappingSocketAddressResolver.create( + DnsResolvers.UNRESOLVED, + port -> HostAndPort.of(redisProperties.getHost(), port.getPort())); + ClientResources clientResources = + ClientResources.builder().socketAddressResolver(resolver).build(); + + LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder builder = + LettucePoolingClientConfiguration.builder() + .poolConfig(getPoolConfig(redisProperties.getLettuce().getPool())) + .clientResources(clientResources); + + if (Objects.nonNull(redisProperties.getLettuce().getShutdownTimeout())) { + builder.shutdownTimeout(redisProperties.getLettuce().getShutdownTimeout()); + } + if (Objects.nonNull(redisProperties.getTimeout())) { + builder.commandTimeout(redisProperties.getTimeout()); + } + if (StringUtils.isNotBlank(redisProperties.getClientName())) { + builder.clientName(redisProperties.getClientName()); + } + + RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(); + configuration.setDatabase(redisProperties.getDatabase()); + configuration.setHostName(redisProperties.getHost()); + configuration.setPort(redisProperties.getPort()); + configuration.setPassword(redisProperties.getPassword()); + + LettucePoolingClientConfiguration clientConfiguration = + redisProperties.getSsl().isEnabled() + ? builder.useSsl().disablePeerVerification().build() + : builder.build(); + + return new LettuceConnectionFactory(configuration, clientConfiguration); + } + + private Map getRedisCacheConfigurationMap( + RedisConfigProperties redisConfigProperties) { + Map configurationMap = new HashMap<>(16); + redisConfigProperties + .getInitExpiry() + .forEach( + (cacheName, ttl) -> + configurationMap.put(cacheName, getRedisCacheConfigurationWithTtl(ttl))); + return configurationMap; + } + + private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds) { + Jackson2JsonRedisSerializer serializer = + new Jackson2JsonRedisSerializer<>(Object.class); + ObjectMapper mapper = new ObjectMapper(); + mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + mapper.activateDefaultTyping( + LaissezFaireSubTypeValidator.instance, + ObjectMapper.DefaultTyping.NON_FINAL, + JsonTypeInfo.As.PROPERTY); + + RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig(); + return configuration + .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer)) + .entryTtl(Duration.ofSeconds(seconds.longValue())); + } + + private GenericObjectPoolConfig getPoolConfig(RedisProperties.Pool properties) { + GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig<>(); + poolConfig.setMaxTotal(properties.getMaxActive()); + poolConfig.setMaxIdle(properties.getMaxIdle()); + poolConfig.setMinIdle(properties.getMinIdle()); + if (properties.getTimeBetweenEvictionRuns() != null) { + poolConfig.setTimeBetweenEvictionRuns(properties.getTimeBetweenEvictionRuns()); + } + if (properties.getMaxWait() != null) { + poolConfig.setMaxWait(properties.getMaxWait()); + } + return poolConfig; + } +} diff --git a/rc-service/rc-service-external/external-start/src/main/resources/application.yml b/rc-service/rc-service-external/external-start/src/main/resources/application.yml index eaed6931..e1301e62 100644 --- a/rc-service/rc-service-external/external-start/src/main/resources/application.yml +++ b/rc-service/rc-service-external/external-start/src/main/resources/application.yml @@ -29,6 +29,6 @@ management: health: show-details: always -rtc: - appId: f424387a480e41088239416e10030034 - certificate: c96d8494f80542bb83c843ad4045df03 +rtc: + appId: ceb9e2620d454bca9725f7a7f11d4019 + certificate: 1fe700671f1641a8b42a474d4ad990a7 diff --git a/rc-service/rc-service-live/live-application/src/main/java/com/red/circle/live/app/service/LiveMicrophoneServiceImpl.java b/rc-service/rc-service-live/live-application/src/main/java/com/red/circle/live/app/service/LiveMicrophoneServiceImpl.java index 5746e1f9..8b10852e 100644 --- a/rc-service/rc-service-live/live-application/src/main/java/com/red/circle/live/app/service/LiveMicrophoneServiceImpl.java +++ b/rc-service/rc-service-live/live-application/src/main/java/com/red/circle/live/app/service/LiveMicrophoneServiceImpl.java @@ -32,9 +32,10 @@ import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; -import org.apache.http.util.EntityUtils; -import org.springframework.beans.BeanUtils; -import org.springframework.stereotype.Service; +import org.apache.http.util.EntityUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; /** * 直播麦克风服务. @@ -56,12 +57,15 @@ public class LiveMicrophoneServiceImpl implements LiveMicrophoneService { private final RedisService redisService; private final RoomUserBlacklistClient roomUserBlacklistClient; - private final String authKey = "Basic N2Q0ZTRiZDYyODUyNDc3ZGI4Yzk3OGU1NTVmMDRiOGI6ODdkMjcxMTg2NzgxNGY4YjgzZTNkOWIyZmRjOTc3OWQ="; - - private final String killRoom = "https://api.sd-rtn.com/dev/v1/kicking-rule"; - private final String queryUserInfo = "https://api.sd-rtn.com/dev/v1/channel/user/"; - - private final String appId = ""; + @Value("${rtc.authKey}") + private String authKey; + + @Value("${rtc.killRoom}") + private String killRoom; + private final String queryUserInfo = "https://api.sd-rtn.com/dev/v1/channel/user/"; + + @Value("${rtc.appId}") + private String appId; private final UserProfileClient userProfileClient; diff --git a/rc-service/rc-service-live/live-infrastructure/src/main/java/com/red/circle/live/infra/repository/LiveMicrophoneGatewayImpl.java b/rc-service/rc-service-live/live-infrastructure/src/main/java/com/red/circle/live/infra/repository/LiveMicrophoneGatewayImpl.java index 7e077825..eebeebdc 100644 --- a/rc-service/rc-service-live/live-infrastructure/src/main/java/com/red/circle/live/infra/repository/LiveMicrophoneGatewayImpl.java +++ b/rc-service/rc-service-live/live-infrastructure/src/main/java/com/red/circle/live/infra/repository/LiveMicrophoneGatewayImpl.java @@ -58,15 +58,16 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; -import com.red.circle.tool.core.thread.ThreadPoolManager; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.util.EntityUtils; -import org.springframework.stereotype.Service; +import com.red.circle.tool.core.thread.ThreadPoolManager; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; /** * @author pengliang on 2023/12/12 @@ -93,13 +94,15 @@ public class LiveMicrophoneGatewayImpl implements LiveMicrophoneGateway { private final UserCpClient userCpClient; private final LiveRoomCacheService liveRoomCacheService; // private final RedissonClient redissonClient; - //临时处理,后续房子啊Nacos配置处理 - private final String authKey = "Basic MmIwZGFkOWQ0ZjEzNGQ2NmI5MmI2ZmY2MzljNmEwMTc6ZWRlMTQ1NTRjNTU0NDY2ZmE4OWNiYWFhNGNmZTM3YjA="; - - private final String killRoom = "https://api.sd-rtn.com/dev/v1/kicking-rule"; - private final String queryUserInfo = "https://api.sd-rtn.com/dev/v1/channel/user/"; - - private final String appId = ""; + @Value("${rtc.authKey}") + private String authKey; + + @Value("${rtc.killRoom}") + private String killRoom; + private final String queryUserInfo = "https://api.sd-rtn.com/dev/v1/channel/user/"; + + @Value("${rtc.appId}") + private String appId; @Override diff --git a/rc-service/rc-service-other/other-application/pom.xml b/rc-service/rc-service-other/other-application/pom.xml index b21d3c66..12a45710 100644 --- a/rc-service/rc-service-other/other-application/pom.xml +++ b/rc-service/rc-service-other/other-application/pom.xml @@ -55,11 +55,12 @@ 5.8.22 - - org.springframework.boot - spring-boot-starter-test - - + + org.springframework.boot + spring-boot-starter-test + test + + rc-service-other diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/AccountBindUserAuthTypeCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/AccountBindUserAuthTypeCmd.java index 8814c65c..40744bd6 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/AccountBindUserAuthTypeCmd.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/AccountBindUserAuthTypeCmd.java @@ -1,4 +1,4 @@ -package com.red.circle.other.app.dto.cmd.user.user;; +package com.red.circle.other.app.dto.cmd.user.user; import com.red.circle.common.business.dto.cmd.AppExtCommand; import jakarta.validation.constraints.NotBlank; diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/AccountQryCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/AccountQryCmd.java index 4a2c8569..44a4e235 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/AccountQryCmd.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/AccountQryCmd.java @@ -1,4 +1,4 @@ -package com.red.circle.other.app.dto.cmd.user.user;; +package com.red.circle.other.app.dto.cmd.user.user; import com.red.circle.common.business.dto.cmd.AppExtCommand; import jakarta.validation.constraints.NotBlank; diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/BankIdentityInfoCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/BankIdentityInfoCmd.java index 01a8396e..a9dcff69 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/BankIdentityInfoCmd.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/BankIdentityInfoCmd.java @@ -1,4 +1,4 @@ -package com.red.circle.other.app.dto.cmd.user.user;; +package com.red.circle.other.app.dto.cmd.user.user; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/BindUserAuthTypeCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/BindUserAuthTypeCmd.java index 998c2c1c..6cb90a00 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/BindUserAuthTypeCmd.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/BindUserAuthTypeCmd.java @@ -1,4 +1,4 @@ -package com.red.circle.other.app.dto.cmd.user.user;; +package com.red.circle.other.app.dto.cmd.user.user; import com.red.circle.common.business.dto.cmd.AppExtCommand; import com.red.circle.tool.core.text.StringUtils; diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/LanguageUploadCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/LanguageUploadCmd.java index 3e5a3fc5..e815f920 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/LanguageUploadCmd.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/LanguageUploadCmd.java @@ -1,4 +1,4 @@ -package com.red.circle.other.app.dto.cmd.user.user;; +package com.red.circle.other.app.dto.cmd.user.user; import com.red.circle.common.business.dto.cmd.AppExtCommand; import jakarta.validation.constraints.NotBlank; diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/RemoveNotActionUserCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/RemoveNotActionUserCmd.java index b564321a..42437a8b 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/RemoveNotActionUserCmd.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/RemoveNotActionUserCmd.java @@ -1,4 +1,4 @@ -package com.red.circle.other.app.dto.cmd.user.user;; +package com.red.circle.other.app.dto.cmd.user.user; import com.red.circle.common.business.dto.cmd.AppExtCommand; import jakarta.validation.constraints.NotBlank; diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UnBindUserAuthTypeCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UnBindUserAuthTypeCmd.java index f2582bc7..32f468d9 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UnBindUserAuthTypeCmd.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UnBindUserAuthTypeCmd.java @@ -1,4 +1,4 @@ -package com.red.circle.other.app.dto.cmd.user.user;; +package com.red.circle.other.app.dto.cmd.user.user; import com.red.circle.common.business.dto.cmd.AppExtCommand; import com.red.circle.other.inner.enums.user.AuthTypeEnum; diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UploadDeviceCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UploadDeviceCmd.java index b77a6b62..84122a78 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UploadDeviceCmd.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UploadDeviceCmd.java @@ -1,4 +1,4 @@ -package com.red.circle.other.app.dto.cmd.user.user;; +package com.red.circle.other.app.dto.cmd.user.user; import com.red.circle.common.business.dto.cmd.AppExtCommand; import lombok.Data; diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserBlacklistQueryCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserBlacklistQueryCmd.java index 135b2975..22fefe14 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserBlacklistQueryCmd.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserBlacklistQueryCmd.java @@ -1,4 +1,4 @@ -package com.red.circle.other.app.dto.cmd.user.user;; +package com.red.circle.other.app.dto.cmd.user.user; import com.red.circle.common.business.dto.cmd.AppExtCommand; import lombok.Data; diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserCardQryCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserCardQryCmd.java index 3c859ab4..55a578d6 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserCardQryCmd.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserCardQryCmd.java @@ -1,4 +1,4 @@ -package com.red.circle.other.app.dto.cmd.user.user;; +package com.red.circle.other.app.dto.cmd.user.user; import com.red.circle.common.business.dto.cmd.AppExtCommand; import lombok.Data; diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserLevelCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserLevelCmd.java index 37f2b77d..64f25965 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserLevelCmd.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserLevelCmd.java @@ -1,4 +1,4 @@ -package com.red.circle.other.app.dto.cmd.user.user;; +package com.red.circle.other.app.dto.cmd.user.user; import com.red.circle.common.business.dto.cmd.AppExtCommand; import jakarta.validation.constraints.NotNull; diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserLogoutApplyCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserLogoutApplyCmd.java index 8eb48111..9b408d54 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserLogoutApplyCmd.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserLogoutApplyCmd.java @@ -1,4 +1,4 @@ -package com.red.circle.other.app.dto.cmd.user.user;; +package com.red.circle.other.app.dto.cmd.user.user; import com.red.circle.common.business.dto.cmd.AppExtCommand; import java.io.Serial; diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserLogoutLogCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserLogoutLogCmd.java index c986f5de..e905e36e 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserLogoutLogCmd.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserLogoutLogCmd.java @@ -1,4 +1,4 @@ -package com.red.circle.other.app.dto.cmd.user.user;; +package com.red.circle.other.app.dto.cmd.user.user; import com.red.circle.common.business.dto.cmd.AppExtCommand; import java.io.Serial; diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserOnlineStatusUploadCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserOnlineStatusUploadCmd.java index 582535a1..1c7e5ae7 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserOnlineStatusUploadCmd.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserOnlineStatusUploadCmd.java @@ -1,4 +1,4 @@ -package com.red.circle.other.app.dto.cmd.user.user;; +package com.red.circle.other.app.dto.cmd.user.user; import com.red.circle.common.business.dto.cmd.AppExtCommand; import jakarta.validation.constraints.NotBlank; diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserProfileModifyCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserProfileModifyCmd.java index 3e77e2e0..1a358d82 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserProfileModifyCmd.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserProfileModifyCmd.java @@ -1,4 +1,4 @@ -package com.red.circle.other.app.dto.cmd.user.user;; +package com.red.circle.other.app.dto.cmd.user.user; import com.red.circle.common.business.dto.cmd.AppExtCommand; import com.red.circle.tool.core.date.AgeUtils; diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserProfileQryCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserProfileQryCmd.java index 351cdea3..f865a632 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserProfileQryCmd.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserProfileQryCmd.java @@ -1,4 +1,4 @@ -package com.red.circle.other.app.dto.cmd.user.user;; +package com.red.circle.other.app.dto.cmd.user.user; import com.red.circle.common.business.dto.cmd.AppExtCommand; import lombok.Data; diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserShieldBlackUserCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserShieldBlackUserCmd.java index 52cd0b3e..87bfc5ed 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserShieldBlackUserCmd.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/UserShieldBlackUserCmd.java @@ -1,4 +1,4 @@ -package com.red.circle.other.app.dto.cmd.user.user;; +package com.red.circle.other.app.dto.cmd.user.user; import com.red.circle.common.business.dto.cmd.AppExtCommand; import jakarta.validation.constraints.NotNull; diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/VoiceRoomUserCardQryCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/VoiceRoomUserCardQryCmd.java index ce5b6cff..492b9285 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/VoiceRoomUserCardQryCmd.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/user/user/VoiceRoomUserCardQryCmd.java @@ -1,4 +1,4 @@ -package com.red.circle.other.app.dto.cmd.user.user;; +package com.red.circle.other.app.dto.cmd.user.user; import com.red.circle.common.business.dto.cmd.AppExtCommand; import jakarta.validation.constraints.NotNull;