update
This commit is contained in:
@@ -20,6 +20,7 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<java.version>21</java.version>
|
<java.version>21</java.version>
|
||||||
|
<tomcat.version>11.0.25</tomcat.version>
|
||||||
<netty.version>4.2.18.Final</netty.version>
|
<netty.version>4.2.18.Final</netty.version>
|
||||||
<httpclient5.version>5.6.4</httpclient5.version>
|
<httpclient5.version>5.6.4</httpclient5.version>
|
||||||
<httpclient5-win.version>5.2.3</httpclient5-win.version>
|
<httpclient5-win.version>5.2.3</httpclient5-win.version>
|
||||||
|
|||||||
+12
-6
@@ -1,10 +1,16 @@
|
|||||||
package com.mgm.mcrm.apigateway.common.services;
|
package com.mgm.mcrm.apigateway.common.services;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.net.ssl.X509TrustManager;
|
import javax.net.ssl.X509TrustManager;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
|
||||||
public class ConfigurableTrustHandler implements X509TrustManager {
|
public class ConfigurableTrustHandler implements X509TrustManager {
|
||||||
private final boolean skipValidation;
|
private final boolean skipValidation;
|
||||||
private final X509TrustManager defaultTrustManager;
|
private final X509TrustManager defaultTrustManager;
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(ConfigurableTrustHandler.class);
|
||||||
|
|
||||||
public ConfigurableTrustHandler(boolean skipValidation, X509TrustManager defaultTrustManager) {
|
public ConfigurableTrustHandler(boolean skipValidation, X509TrustManager defaultTrustManager) {
|
||||||
this.skipValidation = skipValidation;
|
this.skipValidation = skipValidation;
|
||||||
@@ -12,25 +18,25 @@ public class ConfigurableTrustHandler implements X509TrustManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
|
public X509Certificate[] getAcceptedIssuers() {
|
||||||
if (skipValidation) {
|
if (skipValidation) {
|
||||||
return new java.security.cert.X509Certificate[0];
|
return new java.security.cert.X509Certificate[0];
|
||||||
}else{
|
}else{
|
||||||
return defaultTrustManager != null ? defaultTrustManager.getAcceptedIssuers() : new java.security.cert.X509Certificate[0];
|
return defaultTrustManager != null ? defaultTrustManager.getAcceptedIssuers() : new X509Certificate[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void checkServerTrusted(java.security.cert.X509Certificate[] chain,
|
public void checkServerTrusted(X509Certificate[] chain,
|
||||||
String authType) throws java.security.cert.CertificateException {
|
String authType) throws CertificateException {
|
||||||
if (!skipValidation && defaultTrustManager != null) {
|
if (!skipValidation && defaultTrustManager != null) {
|
||||||
defaultTrustManager.checkServerTrusted(chain, authType);
|
defaultTrustManager.checkServerTrusted(chain, authType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void checkClientTrusted(java.security.cert.X509Certificate[] chain,
|
public void checkClientTrusted(X509Certificate[] chain,
|
||||||
String authType) throws java.security.cert.CertificateException {
|
String authType) throws CertificateException {
|
||||||
if (!skipValidation && defaultTrustManager != null) {
|
if (!skipValidation && defaultTrustManager != null) {
|
||||||
defaultTrustManager.checkClientTrusted(chain, authType);
|
defaultTrustManager.checkClientTrusted(chain, authType);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,33 +124,6 @@ public class HttpSslSupport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用自定义证书(trustStore)初始化 SSLContext
|
|
||||||
*/
|
|
||||||
public HttpSslSupport customSSL(String keyStorePath, String keyStorepass) {
|
|
||||||
FileInputStream instream = null;
|
|
||||||
try {
|
|
||||||
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
|
||||||
instream = new FileInputStream(new File(keyStorePath));
|
|
||||||
trustStore.load(instream, keyStorepass.toCharArray());
|
|
||||||
// 相信自己的 CA 和所有自签名证书
|
|
||||||
this.sc = SSLContexts.custom()
|
|
||||||
.loadTrustMaterial(trustStore, (chain, authType) -> true)
|
|
||||||
.build();
|
|
||||||
return this;
|
|
||||||
} catch (KeyManagementException | KeyStoreException |
|
|
||||||
NoSuchAlgorithmException | CertificateException | IOException e) {
|
|
||||||
throw new RuntimeException("初始化自定义 SSLContext 失败", e);
|
|
||||||
} finally {
|
|
||||||
if (instream != null) {
|
|
||||||
try {
|
|
||||||
instream.close();
|
|
||||||
} catch (IOException ignore) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取(或创建)指定协议版本的 {@link SSLContext}
|
* 获取(或创建)指定协议版本的 {@link SSLContext}
|
||||||
|
|||||||
+3
-2
@@ -94,9 +94,10 @@ public class DaylightConfigurationScheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 每天凌晨2点执行一次,拉取 Daylight 配置数据
|
* 按配置的时间和时区执行,拉取 Daylight 配置数据,默认北京时间每天凌晨2点
|
||||||
*/
|
*/
|
||||||
@Scheduled(cron = "0 0 2 * * ?")
|
@Scheduled(cron = "${daylight.scheduler.configuration-cron:0 0 2 * * ?}",
|
||||||
|
zone = "${daylight.scheduler.configuration-zone:Asia/Shanghai}")
|
||||||
public void fetchDaylightConfigurationDaily() {
|
public void fetchDaylightConfigurationDaily() {
|
||||||
LogUtil.info(DaylightConfigurationScheduler.class, "Start scheduled task: fetchDaylightAllData");
|
LogUtil.info(DaylightConfigurationScheduler.class, "Start scheduled task: fetchDaylightAllData");
|
||||||
try {
|
try {
|
||||||
|
|||||||
+48
-62
@@ -24,8 +24,9 @@ import org.springframework.http.ResponseEntity;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -37,6 +38,9 @@ import java.util.Optional;
|
|||||||
public class DaylightFetchConfigurationService {
|
public class DaylightFetchConfigurationService {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(DaylightFetchConfigurationService.class);
|
private static final Logger log = LoggerFactory.getLogger(DaylightFetchConfigurationService.class);
|
||||||
|
private static final DateTimeFormatter UTC_UPDATED_AT_FORMATTER = DateTimeFormatter
|
||||||
|
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS")
|
||||||
|
.withZone(ZoneOffset.UTC);
|
||||||
|
|
||||||
private final HttpProxyErrorHandler httpErrorHandler = new HttpProxyErrorHandler();
|
private final HttpProxyErrorHandler httpErrorHandler = new HttpProxyErrorHandler();
|
||||||
@Resource
|
@Resource
|
||||||
@@ -73,8 +77,6 @@ public class DaylightFetchConfigurationService {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
|
|
||||||
|
|
||||||
for (CfgProperties property : allProperties) {
|
for (CfgProperties property : allProperties) {
|
||||||
String dlPropertyId = property.getDlPropertyId();
|
String dlPropertyId = property.getDlPropertyId();
|
||||||
if (StringUtils.isBlank(dlPropertyId)) {
|
if (StringUtils.isBlank(dlPropertyId)) {
|
||||||
@@ -90,7 +92,8 @@ public class DaylightFetchConfigurationService {
|
|||||||
"Configuration", dlPropertyId, "SUCCESS");
|
"Configuration", dlPropertyId, "SUCCESS");
|
||||||
boolean hasSavedConfig = cfgDaylightConfigurationDao.existsSavedConfigurationByDlPropertyId(dlPropertyId);
|
boolean hasSavedConfig = cfgDaylightConfigurationDao.existsSavedConfigurationByDlPropertyId(dlPropertyId);
|
||||||
if (lastSync.isPresent() && hasSavedConfig) {
|
if (lastSync.isPresent() && hasSavedConfig) {
|
||||||
updatedAtParam = "&updatedAt=" + sdf.format(lastSync.get().getLastSyncAt());
|
updatedAtParam = "&updatedAt="
|
||||||
|
+ UTC_UPDATED_AT_FORMATTER.format(lastSync.get().getLastSyncAt().toInstant());
|
||||||
log.info("Property {} incremental sync, updatedAt: {}", dlPropertyId, updatedAtParam);
|
log.info("Property {} incremental sync, updatedAt: {}", dlPropertyId, updatedAtParam);
|
||||||
} else {
|
} else {
|
||||||
if (lastSync.isPresent() && !hasSavedConfig) {
|
if (lastSync.isPresent() && !hasSavedConfig) {
|
||||||
@@ -255,7 +258,7 @@ public class DaylightFetchConfigurationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从 Daylight API 拉取 properties 列表,存入 cfg_daylight_configuration 表
|
* 从 Daylight units API 拉取 units 列表,存入 cfg_daylight_configuration 表
|
||||||
*/
|
*/
|
||||||
public BaseApiResponse<Void> fetchDaylightProperties() {
|
public BaseApiResponse<Void> fetchDaylightProperties() {
|
||||||
BaseApiResponse<Void> response = new BaseApiResponse<>();
|
BaseApiResponse<Void> response = new BaseApiResponse<>();
|
||||||
@@ -269,71 +272,55 @@ public class DaylightFetchConfigurationService {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
String path = "/api-gateway/configuration/v1/properties";
|
String path = "/api-gateway/permission-management/v1/users/me/units";
|
||||||
String apiUrl = daylightApiSetting.getServerUrl() + path;
|
String apiUrl = daylightApiSetting.getServerUrl() + path;
|
||||||
int pageNumber = 1;
|
|
||||||
List<JSONObject> allResults = new ArrayList<>();
|
List<JSONObject> allResults = new ArrayList<>();
|
||||||
String pagingNext = null;
|
|
||||||
|
|
||||||
do {
|
HttpHeaders headers = new HttpHeaders();
|
||||||
HttpHeaders headers = new HttpHeaders();
|
headers.set("authorization", "Bearer " + daylightApiToken.getAccessToken());
|
||||||
headers.set("authorization", "Bearer " + daylightApiToken.getAccessToken());
|
|
||||||
|
|
||||||
String queryString = "pageSize=500&statusCode=Published&recursive=true&isActive=true&pageNumber=" + pageNumber;
|
String queryString = "pageSize=200";
|
||||||
log.info("Fetching properties page {}", pageNumber);
|
log.info("Fetching properties from current user units");
|
||||||
|
|
||||||
ResponseEntity<byte[]> requestResponse = webProxyService.invokeRequest(
|
ResponseEntity<byte[]> requestResponse = webProxyService.invokeRequest(
|
||||||
WebProxyService.DAYLIGHT_API,
|
WebProxyService.DAYLIGHT_API,
|
||||||
HttpMethod.GET,
|
HttpMethod.GET,
|
||||||
apiUrl,
|
apiUrl,
|
||||||
queryString,
|
queryString,
|
||||||
headers,
|
headers,
|
||||||
new byte[0],
|
new byte[0],
|
||||||
Duration.ofSeconds(daylightApiSetting.getApiTimeout()),
|
Duration.ofSeconds(daylightApiSetting.getApiTimeout()),
|
||||||
httpErrorHandler
|
httpErrorHandler
|
||||||
).block();
|
).block();
|
||||||
|
|
||||||
if (requestResponse == null) {
|
if (requestResponse == null) {
|
||||||
response.setSuccess(false);
|
response.setSuccess(false);
|
||||||
response.setMessage("Http request server can not visit.");
|
response.setMessage("Http request server can not visit.");
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
response.setStatusCode(requestResponse.getStatusCode().value());
|
response.setStatusCode(requestResponse.getStatusCode().value());
|
||||||
|
|
||||||
if (!requestResponse.getStatusCode().is2xxSuccessful()) {
|
if (!requestResponse.getStatusCode().is2xxSuccessful()) {
|
||||||
byte[] errorBody = requestResponse.getBody();
|
byte[] errorBody = requestResponse.getBody();
|
||||||
response.setSuccess(false);
|
response.setSuccess(false);
|
||||||
response.setMessage(errorBody != null ? new String(errorBody, StandardCharsets.UTF_8) : "Request failed");
|
response.setMessage(errorBody != null ? new String(errorBody, StandardCharsets.UTF_8) : "Request failed");
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] responseBody = requestResponse.getBody();
|
byte[] responseBody = requestResponse.getBody();
|
||||||
if (responseBody == null) {
|
if (responseBody == null) {
|
||||||
break;
|
throw new IllegalStateException("Daylight units response body is empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
String jsonStr = new String(responseBody, StandardCharsets.UTF_8);
|
String jsonStr = new String(responseBody, StandardCharsets.UTF_8);
|
||||||
JSONObject responseJson = JSONObject.parseObject(jsonStr);
|
JSONObject responseJson = JSONObject.parseObject(jsonStr);
|
||||||
|
if (responseJson == null || responseJson.getJSONArray("results") == null) {
|
||||||
|
throw new IllegalStateException("Daylight units response is missing results");
|
||||||
|
}
|
||||||
|
|
||||||
// 累积 results 数组
|
// 完整保存 results 数组,不筛选 unit 类型或发布状态
|
||||||
List<JSONObject> pageResults = responseJson.getJSONArray("results").toJavaList(JSONObject.class);
|
allResults.addAll(responseJson.getJSONArray("results").toJavaList(JSONObject.class));
|
||||||
if (pageResults != null) {
|
|
||||||
allResults.addAll(pageResults);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 判断是否有下一页
|
|
||||||
pagingNext = null;
|
|
||||||
JSONObject paging = responseJson.getJSONObject("paging");
|
|
||||||
if (paging != null) {
|
|
||||||
int totalCount = paging.getIntValue("totalCount");
|
|
||||||
int pageSize = paging.getIntValue("pageSize");
|
|
||||||
if (pageNumber * pageSize < totalCount) {
|
|
||||||
pagingNext = "next";
|
|
||||||
pageNumber++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (pagingNext != null);
|
|
||||||
|
|
||||||
// 保存为一条 CfgDaylightConfiguration,configName = "Property"
|
// 保存为一条 CfgDaylightConfiguration,configName = "Property"
|
||||||
if (!allResults.isEmpty()) {
|
if (!allResults.isEmpty()) {
|
||||||
@@ -504,8 +491,6 @@ public class DaylightFetchConfigurationService {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
|
|
||||||
|
|
||||||
for (CfgProperties property : allProperties) {
|
for (CfgProperties property : allProperties) {
|
||||||
dlPropertyId = property.getDlPropertyId();
|
dlPropertyId = property.getDlPropertyId();
|
||||||
if (StringUtils.isBlank(dlPropertyId)) {
|
if (StringUtils.isBlank(dlPropertyId)) {
|
||||||
@@ -520,7 +505,8 @@ public class DaylightFetchConfigurationService {
|
|||||||
CfgDaylightConfiguration existingConfig = cfgDaylightConfigurationDao
|
CfgDaylightConfiguration existingConfig = cfgDaylightConfigurationDao
|
||||||
.findByDlPropertyIdAndConfigName(dlPropertyId, "BlockCode");
|
.findByDlPropertyIdAndConfigName(dlPropertyId, "BlockCode");
|
||||||
if (lastSync.isPresent() && existingConfig != null) {
|
if (lastSync.isPresent() && existingConfig != null) {
|
||||||
updatedAtParam = "&updatedAt=" + sdf.format(lastSync.get().getLastSyncAt());
|
updatedAtParam = "&updatedAt="
|
||||||
|
+ UTC_UPDATED_AT_FORMATTER.format(lastSync.get().getLastSyncAt().toInstant());
|
||||||
log.info("Property {} BlockCode incremental sync, updatedAt: {}", dlPropertyId, updatedAtParam);
|
log.info("Property {} BlockCode incremental sync, updatedAt: {}", dlPropertyId, updatedAtParam);
|
||||||
} else {
|
} else {
|
||||||
if (lastSync.isPresent() && existingConfig == null) {
|
if (lastSync.isPresent() && existingConfig == null) {
|
||||||
|
|||||||
+1
-1
@@ -116,7 +116,7 @@ public class ReservationNotificationHandler implements DaylightWebhookHandler {
|
|||||||
BaseApiResponse<JSONObject> response =
|
BaseApiResponse<JSONObject> response =
|
||||||
daylightApiService.getDaylightReservationByDlId(eventData.getReservationId(), eventData.getPropertyId());
|
daylightApiService.getDaylightReservationByDlId(eventData.getReservationId(), eventData.getPropertyId());
|
||||||
|
|
||||||
if (response.isSuccess()) {
|
if (response.isSuccess() && Objects.nonNull(response.getData())) {
|
||||||
JSONObject embedded = response.getData().getJSONObject("_embedded");
|
JSONObject embedded = response.getData().getJSONObject("_embedded");
|
||||||
if (embedded != null) {
|
if (embedded != null) {
|
||||||
JSONArray customFields = embedded.getJSONArray("customFields");
|
JSONArray customFields = embedded.getJSONArray("customFields");
|
||||||
|
|||||||
-30
@@ -35,34 +35,4 @@ public class NotificationController {
|
|||||||
return ResponseEntity.status(HttpStatus.OK).body(result);
|
return ResponseEntity.status(HttpStatus.OK).body(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 接收后端A转发过来的邮件请求,字段名与 SendEmailRequest 不同,这里做转换。
|
|
||||||
* showTemp 为 HTML 正文,优先于 content;有 cc 时按群发模式发送。
|
|
||||||
*/
|
|
||||||
@PostMapping(value = "/proxy/send_email", produces = "application/json;charset=UTF-8")
|
|
||||||
public ResponseEntity<BaseApiResponse<Void>> handleSendEmailProxyRequest(
|
|
||||||
@RequestBody(required = true) EmailProxyRequest requestData,
|
|
||||||
HttpServletRequest request
|
|
||||||
) {
|
|
||||||
logger.info("handleSendEmailProxyRequest start, id={}, subject={}, to={}, cc={}, sender={}",
|
|
||||||
requestData.getId(), requestData.getSubject(), requestData.getTo(),
|
|
||||||
requestData.getCc(), requestData.getSender());
|
|
||||||
SendEmailRequest sendEmailRequest = new SendEmailRequest();
|
|
||||||
sendEmailRequest.setSendTo(requestData.getTo());
|
|
||||||
sendEmailRequest.setCc(requestData.getCc());
|
|
||||||
sendEmailRequest.setSubject(requestData.getSubject());
|
|
||||||
String bodyContent = StringUtils.isNotBlank(requestData.getShowTemp())
|
|
||||||
? requestData.getShowTemp()
|
|
||||||
: requestData.getContent();
|
|
||||||
sendEmailRequest.setBodyContent(bodyContent);
|
|
||||||
sendEmailRequest.setContentType("HTML");
|
|
||||||
sendEmailRequest.setSender(requestData.getSender());
|
|
||||||
// 有 cc 时用群发模式(false),让 to + cc 在同一封邮件里
|
|
||||||
sendEmailRequest.setSendSeparately(StringUtils.isBlank(requestData.getCc()));
|
|
||||||
|
|
||||||
BaseApiResponse<Void> result = emailNotificationService.sendEmailByRequest(sendEmailRequest, emailProxySetting);
|
|
||||||
logger.info("handleSendEmailProxyRequest end, id={}, success={}, statusCode={}, message={}",
|
|
||||||
requestData.getId(), result.isSuccess(), result.getStatusCode(), result.getMessage());
|
|
||||||
return ResponseEntity.status(HttpStatus.OK).body(result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import com.mgm.mcrm.apigateway.common.services.ConfigurableTrustHandler;
|
|||||||
import io.netty.channel.ChannelOption;
|
import io.netty.channel.ChannelOption;
|
||||||
import io.netty.handler.ssl.SslContext;
|
import io.netty.handler.ssl.SslContext;
|
||||||
import io.netty.handler.ssl.SslContextBuilder;
|
import io.netty.handler.ssl.SslContextBuilder;
|
||||||
|
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
||||||
import io.netty.handler.timeout.ReadTimeoutHandler;
|
import io.netty.handler.timeout.ReadTimeoutHandler;
|
||||||
import io.netty.handler.timeout.WriteTimeoutHandler;
|
import io.netty.handler.timeout.WriteTimeoutHandler;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@@ -16,8 +17,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.ssl.SslBundle;
|
import org.springframework.boot.ssl.*;
|
||||||
import org.springframework.boot.ssl.SslBundles;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||||
@@ -29,7 +29,9 @@ import reactor.netty.resources.ConnectionProvider;
|
|||||||
import reactor.netty.transport.ProxyProvider;
|
import reactor.netty.transport.ProxyProvider;
|
||||||
|
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLEngine;
|
||||||
import javax.net.ssl.SSLException;
|
import javax.net.ssl.SSLException;
|
||||||
|
import javax.net.ssl.SSLParameters;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@@ -64,7 +66,7 @@ public class WebClientConfig {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public WebClient daylightWebClient() {
|
public WebClient daylightWebClient() {
|
||||||
ConnectionProvider provider = ConnectionProvider.builder("proxy-pool")
|
ConnectionProvider provider = ConnectionProvider.builder("daylight-proxy-pool")
|
||||||
.maxConnections(maxConnectionPool)
|
.maxConnections(maxConnectionPool)
|
||||||
.pendingAcquireTimeout(Duration.ofSeconds(60))
|
.pendingAcquireTimeout(Duration.ofSeconds(60))
|
||||||
.maxIdleTime(Duration.ofSeconds(30))
|
.maxIdleTime(Duration.ofSeconds(30))
|
||||||
@@ -75,7 +77,13 @@ public class WebClientConfig {
|
|||||||
.responseTimeout(Duration.ofSeconds(readTimeout))
|
.responseTimeout(Duration.ofSeconds(readTimeout))
|
||||||
.secure(spec -> {
|
.secure(spec -> {
|
||||||
try {
|
try {
|
||||||
spec.sslContext(this.createDaylightSslContent());
|
spec.sslContext(this.createDaylightSslContent())
|
||||||
|
.handlerConfigurator(sslHandler -> {
|
||||||
|
SSLEngine engine = sslHandler.engine();
|
||||||
|
SSLParameters params = engine.getSSLParameters();
|
||||||
|
params.setEndpointIdentificationAlgorithm("");
|
||||||
|
engine.setSSLParameters(params);
|
||||||
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -103,7 +111,7 @@ public class WebClientConfig {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public WebClient esbWebClient() {
|
public WebClient esbWebClient() {
|
||||||
ConnectionProvider provider = ConnectionProvider.builder("proxy-pool")
|
ConnectionProvider provider = ConnectionProvider.builder("esb-proxy-pool")
|
||||||
.maxConnections(maxConnectionPool)
|
.maxConnections(maxConnectionPool)
|
||||||
.pendingAcquireTimeout(Duration.ofSeconds(60))
|
.pendingAcquireTimeout(Duration.ofSeconds(60))
|
||||||
.maxIdleTime(Duration.ofSeconds(30))
|
.maxIdleTime(Duration.ofSeconds(30))
|
||||||
@@ -114,7 +122,13 @@ public class WebClientConfig {
|
|||||||
.responseTimeout(Duration.ofSeconds(readTimeout))
|
.responseTimeout(Duration.ofSeconds(readTimeout))
|
||||||
.secure(spec -> {
|
.secure(spec -> {
|
||||||
try {
|
try {
|
||||||
spec.sslContext(this.createEsbSslContent());
|
spec.sslContext(this.createEsbSslContent())
|
||||||
|
.handlerConfigurator(sslHandler -> {
|
||||||
|
SSLEngine engine = sslHandler.engine();
|
||||||
|
SSLParameters params = engine.getSSLParameters();
|
||||||
|
params.setEndpointIdentificationAlgorithm("");
|
||||||
|
engine.setSSLParameters(params);
|
||||||
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -142,7 +156,7 @@ public class WebClientConfig {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public WebClient limoWebClient() {
|
public WebClient limoWebClient() {
|
||||||
ConnectionProvider provider = ConnectionProvider.builder("proxy-pool")
|
ConnectionProvider provider = ConnectionProvider.builder("limo-proxy-pool")
|
||||||
.maxConnections(maxConnectionPool)
|
.maxConnections(maxConnectionPool)
|
||||||
.pendingAcquireTimeout(Duration.ofSeconds(60))
|
.pendingAcquireTimeout(Duration.ofSeconds(60))
|
||||||
.maxIdleTime(Duration.ofSeconds(30))
|
.maxIdleTime(Duration.ofSeconds(30))
|
||||||
@@ -153,7 +167,13 @@ public class WebClientConfig {
|
|||||||
.responseTimeout(Duration.ofSeconds(readTimeout))
|
.responseTimeout(Duration.ofSeconds(readTimeout))
|
||||||
.secure(spec -> {
|
.secure(spec -> {
|
||||||
try {
|
try {
|
||||||
spec.sslContext(this.createLimoSslContent());
|
spec.sslContext(this.createLimoSslContent())
|
||||||
|
.handlerConfigurator(sslHandler -> {
|
||||||
|
SSLEngine engine = sslHandler.engine();
|
||||||
|
SSLParameters params = engine.getSSLParameters();
|
||||||
|
params.setEndpointIdentificationAlgorithm("");
|
||||||
|
engine.setSSLParameters(params);
|
||||||
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -181,7 +201,7 @@ public class WebClientConfig {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public WebClient operaWebClient() {
|
public WebClient operaWebClient() {
|
||||||
ConnectionProvider provider = ConnectionProvider.builder("proxy-pool")
|
ConnectionProvider provider = ConnectionProvider.builder("opera-proxy-pool")
|
||||||
.maxConnections(maxConnectionPool)
|
.maxConnections(maxConnectionPool)
|
||||||
.pendingAcquireTimeout(Duration.ofSeconds(60))
|
.pendingAcquireTimeout(Duration.ofSeconds(60))
|
||||||
.maxIdleTime(Duration.ofSeconds(30))
|
.maxIdleTime(Duration.ofSeconds(30))
|
||||||
@@ -192,7 +212,13 @@ public class WebClientConfig {
|
|||||||
.responseTimeout(Duration.ofSeconds(readTimeout))
|
.responseTimeout(Duration.ofSeconds(readTimeout))
|
||||||
.secure(spec -> {
|
.secure(spec -> {
|
||||||
try {
|
try {
|
||||||
spec.sslContext(this.createOperaSslContent());
|
spec.sslContext(this.createOperaSslContent())
|
||||||
|
.handlerConfigurator(sslHandler -> {
|
||||||
|
SSLEngine engine = sslHandler.engine();
|
||||||
|
SSLParameters params = engine.getSSLParameters();
|
||||||
|
params.setEndpointIdentificationAlgorithm("");
|
||||||
|
engine.setSSLParameters(params);
|
||||||
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -306,7 +332,6 @@ public class WebClientConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//----------
|
//----------
|
||||||
private void setProxySettingByConfig(ProxyProvider.TypeSpec proxy, String proxyHost, int proxyPort, String authUserName, String authPassword){
|
private void setProxySettingByConfig(ProxyProvider.TypeSpec proxy, String proxyHost, int proxyPort, String authUserName, String authPassword){
|
||||||
if (StringUtils.isNotBlank(authUserName) && StringUtils.isNotBlank(authPassword)) {
|
if (StringUtils.isNotBlank(authUserName) && StringUtils.isNotBlank(authPassword)) {
|
||||||
@@ -323,14 +348,14 @@ public class WebClientConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private SslContext createDefaultSslContext(ConfigurableTrustHandler trustHandler) throws SSLException {
|
private SslContext createDefaultSslContext(ConfigurableTrustHandler trustHandler) throws SSLException {
|
||||||
return SslContextBuilder.forClient().trustManager(trustHandler).build();
|
return SslContextBuilder.forClient().trustManager(trustHandler).endpointIdentificationAlgorithm("").build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private SslContext createSslContextByConfig(String sslBundleName) throws SSLException {
|
private SslContext createSslContextByConfig(String sslBundleName) throws SSLException {
|
||||||
SslBundle sslBundle = sslBundles.getBundle(sslBundleName);
|
SslBundle sslBundle = sslBundles.getBundle(sslBundleName);
|
||||||
SSLContext netSslContext = sslBundle.createSslContext();
|
SSLContext netSslContext = sslBundle.createSslContext();
|
||||||
return SslContextBuilder.forClient()
|
return SslContextBuilder.forClient()
|
||||||
.sslContextProvider(netSslContext.getProvider())
|
.sslContextProvider(netSslContext.getProvider()).endpointIdentificationAlgorithm("")
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+40
-1
@@ -2,6 +2,9 @@ package com.mgm.mcrm.apigateway.proxy.controllers;
|
|||||||
|
|
||||||
import com.mgm.mcrm.apigateway.common.dtos.BaseApiResponse;
|
import com.mgm.mcrm.apigateway.common.dtos.BaseApiResponse;
|
||||||
import com.mgm.mcrm.apigateway.common.dtos.config.EmailProxySetting;
|
import com.mgm.mcrm.apigateway.common.dtos.config.EmailProxySetting;
|
||||||
|
import com.mgm.mcrm.apigateway.notification.dtos.EmailProxyRequest;
|
||||||
|
import com.mgm.mcrm.apigateway.notification.dtos.SendEmailRequest;
|
||||||
|
import com.mgm.mcrm.apigateway.notification.services.EmailNotificationService;
|
||||||
import com.mgm.mcrm.apigateway.proxy.dtos.request.SendNotificationRequest;
|
import com.mgm.mcrm.apigateway.proxy.dtos.request.SendNotificationRequest;
|
||||||
import com.mgm.mcrm.apigateway.proxy.services.NotificationProxyService;
|
import com.mgm.mcrm.apigateway.proxy.services.NotificationProxyService;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
@@ -14,6 +17,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
@@ -29,7 +33,11 @@ public class NotificationProxyController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private EmailProxySetting emailProxySetting;
|
private EmailProxySetting emailProxySetting;
|
||||||
|
|
||||||
@RequestMapping(value="/api/notification/proxy/**",produces = "application/json;charset=UTF-8",consumes = MediaType.APPLICATION_JSON_VALUE)
|
@Resource
|
||||||
|
private EmailNotificationService emailNotificationService;
|
||||||
|
|
||||||
|
|
||||||
|
@RequestMapping(value="/api/notification/proxy/send_notification",produces = "application/json;charset=UTF-8",consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||||
public ResponseEntity<BaseApiResponse<Void>> invokeNotificationApiProxy(HttpServletRequest request, @RequestBody SendNotificationRequest notificationRequest) throws Exception {
|
public ResponseEntity<BaseApiResponse<Void>> invokeNotificationApiProxy(HttpServletRequest request, @RequestBody SendNotificationRequest notificationRequest) throws Exception {
|
||||||
//--Check authorization
|
//--Check authorization
|
||||||
String appId = request.getHeader("application-id");
|
String appId = request.getHeader("application-id");
|
||||||
@@ -40,6 +48,37 @@ public class NotificationProxyController {
|
|||||||
return ResponseEntity.status(HttpStatus.OK).body(notificationProxyService.sendNotificationByRequest(notificationRequest,notificationRequest.getRequestorId()));
|
return ResponseEntity.status(HttpStatus.OK).body(notificationProxyService.sendNotificationByRequest(notificationRequest,notificationRequest.getRequestorId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接收后端A转发过来的邮件请求,字段名与 SendEmailRequest 不同,这里做转换。
|
||||||
|
* showTemp 为 HTML 正文,优先于 content;有 cc 时按群发模式发送。
|
||||||
|
*/
|
||||||
|
@PostMapping(value = "/api/notification/proxy/send_email", produces = "application/json;charset=UTF-8")
|
||||||
|
public ResponseEntity<BaseApiResponse<Void>> handleSendEmailProxyRequest(
|
||||||
|
@RequestBody(required = true) EmailProxyRequest requestData,
|
||||||
|
HttpServletRequest request
|
||||||
|
) {
|
||||||
|
logger.info("handleSendEmailProxyRequest start, id={}, subject={}, to={}, cc={}, sender={}",
|
||||||
|
requestData.getId(), requestData.getSubject(), requestData.getTo(),
|
||||||
|
requestData.getCc(), requestData.getSender());
|
||||||
|
SendEmailRequest sendEmailRequest = new SendEmailRequest();
|
||||||
|
sendEmailRequest.setSendTo(requestData.getTo());
|
||||||
|
sendEmailRequest.setCc(requestData.getCc());
|
||||||
|
sendEmailRequest.setSubject(requestData.getSubject());
|
||||||
|
String bodyContent = StringUtils.isNotBlank(requestData.getShowTemp())
|
||||||
|
? requestData.getShowTemp()
|
||||||
|
: requestData.getContent();
|
||||||
|
sendEmailRequest.setBodyContent(bodyContent);
|
||||||
|
sendEmailRequest.setContentType("HTML");
|
||||||
|
sendEmailRequest.setSender(requestData.getSender());
|
||||||
|
// 有 cc 时用群发模式(false),让 to + cc 在同一封邮件里
|
||||||
|
sendEmailRequest.setSendSeparately(StringUtils.isBlank(requestData.getCc()));
|
||||||
|
|
||||||
|
BaseApiResponse<Void> result = emailNotificationService.sendEmailByRequest(sendEmailRequest, emailProxySetting);
|
||||||
|
logger.info("handleSendEmailProxyRequest end, id={}, success={}, statusCode={}, message={}",
|
||||||
|
requestData.getId(), result.isSuccess(), result.getStatusCode(), result.getMessage());
|
||||||
|
return ResponseEntity.status(HttpStatus.OK).body(result);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isAuthorizated(String appId, String securityKey) {
|
private boolean isAuthorizated(String appId, String securityKey) {
|
||||||
boolean isAuth=false;
|
boolean isAuth=false;
|
||||||
if(StringUtils.isNotBlank(appId) && StringUtils.isNotBlank(securityKey)){
|
if(StringUtils.isNotBlank(appId) && StringUtils.isNotBlank(securityKey)){
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.mgm.mcrm.apigateway.proxy.services;
|
package com.mgm.mcrm.apigateway.proxy.services;
|
||||||
|
|
||||||
import com.mgm.mcrm.apigateway.common.utils.NetworkUtil;
|
|
||||||
import com.mgm.mcrm.apigateway.common.utils.mockup.HttpUtilMockup;
|
import com.mgm.mcrm.apigateway.common.utils.mockup.HttpUtilMockup;
|
||||||
import com.mgm.mcrm.apigateway.proxy.exception.ProxyErrorHandler;
|
import com.mgm.mcrm.apigateway.proxy.exception.ProxyErrorHandler;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|||||||
@@ -178,5 +178,9 @@ apns:
|
|||||||
# host: api.push.apple.com
|
# host: api.push.apple.com
|
||||||
|
|
||||||
daylight:
|
daylight:
|
||||||
|
scheduler:
|
||||||
|
# Cron fields: second minute hour day-of-month month day-of-week. Restart after changes.
|
||||||
|
configuration-cron: "0 0 2 * * ?"
|
||||||
|
configuration-zone: "Asia/Shanghai"
|
||||||
url: http://localhost:9087/api/daylight/proxy
|
url: http://localhost:9087/api/daylight/proxy
|
||||||
system-id: 3a151ad3-46be-4644-b656-71d3b037b309
|
system-id: 3a151ad3-46be-4644-b656-71d3b037b309
|
||||||
|
|||||||
Reference in New Issue
Block a user