修复启动
This commit is contained in:
parent
0e74f899f0
commit
3493a78341
@ -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);
|
||||
|
||||
@ -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<UserCredential> 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<UserCredential> reqFailUserCredential = ResultResponse.failure(503,
|
||||
"Request timed out",
|
||||
"REQ_FAIL");
|
||||
|
||||
@Override
|
||||
public Mono<Void> 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<Void> 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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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<String, String> 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<String, Object> body = new LinkedMultiValueMap<>();
|
||||
body.add("file", new HttpEntity<>(resource, fileHeaders));
|
||||
|
||||
String uploadUrl = externalBaseUrl.replaceAll("/+$", "")
|
||||
+ "/oss/upload/general?dir=" + encode(dir)
|
||||
+ "&filename=" + encode(filename);
|
||||
ResponseEntity<Map> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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<String> upload(@RequestPart("file") MultipartFile file) {
|
||||
@PostMapping("/upload")
|
||||
public ResultResponse<String> 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<String> 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -7,18 +7,24 @@
|
||||
<description>应用层,服务实现</description>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.red.circle</groupId>
|
||||
<artifactId>external-client</artifactId>
|
||||
</dependency>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.red.circle</groupId>
|
||||
<artifactId>external-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.red.circle</groupId>
|
||||
<artifactId>external-infrastructure</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
<dependency>
|
||||
<groupId>com.red.circle</groupId>
|
||||
<artifactId>external-infrastructure</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.qcloud</groupId>
|
||||
<artifactId>cos_api</artifactId>
|
||||
<version>5.6.265</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<parent>
|
||||
<artifactId>rc-service-external</artifactId>
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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<String, Object> redCircleRedisTemplate(
|
||||
RedisConnectionFactory connectionFactory) {
|
||||
RedisTemplate<String, Object> 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<String, Object> redisTemplate) {
|
||||
return new RedisService(redisTemplate);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public TaskCacheLockAspect taskCacheLockAspect(
|
||||
@Qualifier("redCircleRedisTemplate") RedisTemplate<String, Object> 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<String, RedisCacheConfiguration> getRedisCacheConfigurationMap(
|
||||
RedisConfigProperties redisConfigProperties) {
|
||||
Map<String, RedisCacheConfiguration> configurationMap = new HashMap<>(16);
|
||||
redisConfigProperties
|
||||
.getInitExpiry()
|
||||
.forEach(
|
||||
(cacheName, ttl) ->
|
||||
configurationMap.put(cacheName, getRedisCacheConfigurationWithTtl(ttl)));
|
||||
return configurationMap;
|
||||
}
|
||||
|
||||
private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds) {
|
||||
Jackson2JsonRedisSerializer<Object> 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<Object> 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;
|
||||
}
|
||||
}
|
||||
@ -29,6 +29,6 @@ management:
|
||||
health:
|
||||
show-details: always
|
||||
|
||||
rtc:
|
||||
appId: f424387a480e41088239416e10030034
|
||||
certificate: c96d8494f80542bb83c843ad4045df03
|
||||
rtc:
|
||||
appId: ceb9e2620d454bca9725f7a7f11d4019
|
||||
certificate: 1fe700671f1641a8b42a474d4ad990a7
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -55,11 +55,12 @@
|
||||
<version>5.8.22</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<parent>
|
||||
<artifactId>rc-service-other</artifactId>
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user