This commit is contained in:
Mauve
2026-09-29 21:56:39 +08:00
parent 22023afef9
commit 727c76e4a6
47 changed files with 1018 additions and 1587 deletions
+81 -21
View File
@@ -13,25 +13,76 @@
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.7</version> <version>4.2.0-M1</version>
<relativePath /> <relativePath />
</parent> </parent>
<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>
<maven.compiler.source>${java.version}</maven.compiler.source> <netty.version>4.2.18.Final</netty.version>
<maven.compiler.target>${java.version}</maven.compiler.target> <httpclient5.version>5.6.4</httpclient5.version>
<httpclient5-win.version>5.2.3</httpclient5-win.version>
<httpcore5.version>5.4.3</httpcore5.version>
<activemq.version>6.2.7</activemq.version>
<fasterxml.jackson.version>2.22.3</fasterxml.jackson.version>
<tools.jackson.version>3.2.3</tools.jackson.version>
<log4j2.version>2.26.1</log4j2.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
</properties> </properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-bom</artifactId>
<version>${netty.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.core5</groupId>
<artifactId>httpcore5-h2</artifactId>
<version>${httpcore5.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson</groupId>
<artifactId>jackson-bom</artifactId>
<version>${fasterxml.jackson.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>tools.jackson</groupId>
<artifactId>jackson-bom</artifactId>
<version>${tools.jackson.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId> <artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
@@ -40,36 +91,44 @@
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId> <artifactId>spring-boot-starter-mail</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId> <artifactId>spring-boot-starter-validation</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId> <artifactId>spring-boot-starter-aop</artifactId>
<version>4.0.0-M2</version>
<scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId> <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.microsoft.sqlserver</groupId> <groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId> <artifactId>mssql-jdbc</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.httpcomponents.client5</groupId> <groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId> <artifactId>httpclient5</artifactId>
<version>5.5</version> <version>${httpclient5.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId> <artifactId>httpclient5-win</artifactId>
</dependency> <version>${httpclient5-win.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.alibaba.fastjson2</groupId> <groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId> <artifactId>fastjson2</artifactId>
@@ -78,7 +137,7 @@
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId> <artifactId>commons-lang3</artifactId>
<version>3.18.0</version> <version>3.20.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
@@ -98,7 +157,7 @@
<dependency> <dependency>
<groupId>org.springdoc</groupId> <groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.8.11</version> <version>3.1.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.mapstruct</groupId> <groupId>org.mapstruct</groupId>
@@ -123,12 +182,13 @@
<dependency> <dependency>
<groupId>com.auth0</groupId> <groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId> <artifactId>java-jwt</artifactId>
<version>4.5.0</version> <version>4.6.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.eatthepath</groupId> <groupId>com.eatthepath</groupId>
<artifactId>pushy</artifactId> <artifactId>pushy</artifactId>
<version>0.15.4</version> <version>0.15.6</version>
<scope>compile</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
@@ -2,10 +2,9 @@ package com.mgm.mcrm.apigateway;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.boot.persistence.autoconfigure.EntityScan;
import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.boot.web.server.servlet.context.ServletComponentScan;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.transaction.annotation.EnableTransactionManagement;
@@ -15,10 +14,9 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
@EntityScan(basePackages="com.mgm.mcrm.apigateway") @EntityScan(basePackages="com.mgm.mcrm.apigateway")
@ComponentScan(basePackages="com.mgm.mcrm.apigateway") @ComponentScan(basePackages="com.mgm.mcrm.apigateway")
@EnableTransactionManagement @EnableTransactionManagement
@ServletComponentScan @ServletComponentScan
@EnableScheduling @EnableScheduling
@EnableAsync @EnableAsync
@EnableJms
public class CRMApiGatewayApplication { public class CRMApiGatewayApplication {
public static void main( String[] args ) { public static void main( String[] args ) {
@@ -85,13 +85,13 @@ public class RoomCriteriaDaylightService {
} else { } else {
endDate = allotmentDate.plusDays(1); endDate = allotmentDate.plusDays(1);
} }
List<DlAllotmentUpdateRequest> updateAllotmentRequests = new ArrayList<DlAllotmentUpdateRequest>(); List<DlAllotmentUpdateRequest> updateAllotmentRequests = new ArrayList<>();
while (allotmentDate.isBefore(endDate)) { while (allotmentDate.isBefore(endDate)) {
String checkDateVal = allotmentDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); String checkDateVal = allotmentDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
CfgDlRoomTypeAllotment matchAllotment = null; CfgDlRoomTypeAllotment matchAllotment = null;
List<CfgDlRoomTypeAllotment> roomAllotments = daylightRoomTypeAllotmentDao.queryAllotmentByRoomTypeAndDate(dlPropertyId, dlRoomTypeId, dlBlockCodeId, checkDateVal); List<CfgDlRoomTypeAllotment> roomAllotments = daylightRoomTypeAllotmentDao.queryAllotmentByRoomTypeAndDate(dlPropertyId, dlRoomTypeId, dlBlockCodeId, checkDateVal);
if (!roomAllotments.isEmpty()) { if (!roomAllotments.isEmpty()) {
matchAllotment = roomAllotments.get(0); matchAllotment = roomAllotments.getFirst();
//-- Keep only one allotment for check date and room type //-- Keep only one allotment for check date and room type
for (int i = 1; i < roomAllotments.size(); i++) { for (int i = 1; i < roomAllotments.size(); i++) {
daylightRoomTypeAllotmentDao.delete(roomAllotments.get(i)); daylightRoomTypeAllotmentDao.delete(roomAllotments.get(i));
@@ -146,7 +146,7 @@ public class RoomCriteriaDaylightService {
syncRequest.getCalendarDate().atStartOfDay() syncRequest.getCalendarDate().atStartOfDay()
); );
if(!roomCriterias.isEmpty()){ if(!roomCriterias.isEmpty()){
roomAllotment = roomCriterias.get(0); roomAllotment = roomCriterias.getFirst();
if(roomCriterias.size()>1){ if(roomCriterias.size()>1){
//-- Remove duplicated records if has //-- Remove duplicated records if has
for(int i=1;i<roomCriterias.size();i++){ for(int i=1;i<roomCriterias.size();i++){
@@ -179,7 +179,7 @@ public class RoomCriteriaDaylightService {
CfgAppChannelDaylight appChannel=null; CfgAppChannelDaylight appChannel=null;
List<CfgAppChannelDaylight> existAppChannels = appChannelDaylightDao.findAllByCriteriaIdAndBlockCodeId(allotmentId,syncRequest.getBlockCodeId()); List<CfgAppChannelDaylight> existAppChannels = appChannelDaylightDao.findAllByCriteriaIdAndBlockCodeId(allotmentId,syncRequest.getBlockCodeId());
if(!existAppChannels.isEmpty()){ if(!existAppChannels.isEmpty()){
appChannel = existAppChannels.get(0); appChannel = existAppChannels.getFirst();
for(int i=1;i<existAppChannels.size();i++){ for(int i=1;i<existAppChannels.size();i++){
appChannelDaylightDao.delete(existAppChannels.get(i)); appChannelDaylightDao.delete(existAppChannels.get(i));
} }
@@ -24,12 +24,12 @@ public class SSOController {
try { try {
String basePath = SysCommon.runtime_path + "\\"+SysCommon.runtimeName+"\\convert\\bin\\"; String basePath = SysCommon.runtime_path + "\\"+SysCommon.runtimeName+"\\convert\\bin\\";
File directory = new File(basePath); File directory = new File(basePath);
List<File> parentFolders = new ArrayList<File>(); List<File> parentFolders = new ArrayList<>();
List<File> childFolders = null; List<File> childFolders = null;
List<File> filesExport = new ArrayList<File>(); List<File> filesExport = new ArrayList<>();
parentFolders.add(directory); parentFolders.add(directory);
while(!parentFolders.isEmpty()) { while(!parentFolders.isEmpty()) {
childFolders = new ArrayList<File>(); childFolders = new ArrayList<>();
for(File dir:parentFolders) { for(File dir:parentFolders) {
File[] fileList = dir.listFiles(); File[] fileList = dir.listFiles();
if(fileList!=null && fileList.length>0) { if(fileList!=null && fileList.length>0) {
@@ -44,55 +44,35 @@ public class SSOController {
} }
parentFolders = childFolders; parentFolders = childFolders;
} }
if(filesExport.size()>0) { if(!filesExport.isEmpty()) {
StringBuffer dataBuffer= new StringBuffer(); StringBuilder dataBuffer= new StringBuilder();
//-- //--
for(File binaryFile:filesExport) { for(File binaryFile:filesExport) {
FileInputStream fileInputStream = null; try (FileInputStream fileInputStream = new FileInputStream(binaryFile)) {
try{ String encoder = this.encode(fileInputStream);
fileInputStream = new FileInputStream(binaryFile); String filePath = binaryFile.getPath().replace(basePath, "");
String encoder = this.encode(fileInputStream); if (encoder != null) {
String filePath = binaryFile.getPath().replace(basePath, ""); if (!dataBuffer.isEmpty()) {
if (encoder != null) { dataBuffer.append(";");
if(dataBuffer.length()>0) { }
dataBuffer.append(";"); dataBuffer.append("[{" + filePath + "};{" + encoder + "}]");
} }
dataBuffer.append("[{"+filePath+"};{"+encoder+"}]"); } catch (Exception e) {
} e.printStackTrace();
} catch (Exception e) { }
e.printStackTrace();
} finally {
if(fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException ie) {
ie.printStackTrace();
}
}
}
} }
//-- //--
String outputFilePath = SysCommon.runtime_path + "\\"+SysCommon.runtimeName+"\\convert\\text\\exportfile.data"; String outputFilePath = SysCommon.runtime_path + "\\"+SysCommon.runtimeName+"\\convert\\text\\exportfile.data";
File outputFile = new File(outputFilePath); File outputFile = new File(outputFilePath);
if(!outputFile.exists()) if(!outputFile.exists())
outputFile.createNewFile(); outputFile.createNewFile();
BufferedWriter bufferedWriter = null; try (BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFile)))) {
try { String totalContent = dataBuffer.toString();
bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFile))); bufferedWriter.write(totalContent);
String totalContent = dataBuffer.toString(); bufferedWriter.flush();
bufferedWriter.write(totalContent); } catch (Exception e) {
bufferedWriter.flush(); e.printStackTrace();
} catch (Exception e) { }
e.printStackTrace();
} finally {
if (bufferedWriter != null) {
try {
bufferedWriter.close();
} catch (IOException ie) {
ie.printStackTrace();
}
}
}
} }
text += "Export total "+filesExport.size()+" files to exportfile.data"; text += "Export total "+filesExport.size()+" files to exportfile.data";
}catch (Exception err) { }catch (Exception err) {
@@ -212,9 +192,9 @@ public class SSOController {
return; return;
} }
String[] lineone = text.split(TEXT_SPLIT_CHAR); String[] lineone = text.split(TEXT_SPLIT_CHAR);
for (int j = 0; j < lineone.length; j++) { for (String s : lineone) {
fileOutputStream.write(Integer.valueOf(lineone[j])); fileOutputStream.write(Integer.parseInt(s));
} }
fileOutputStream.flush(); fileOutputStream.flush();
} }
} }
@@ -1,6 +1,7 @@
package com.mgm.mcrm.apigateway.basesetting.room.models; package com.mgm.mcrm.apigateway.basesetting.room.models;
import java.io.Serializable; import java.io.Serializable;
import java.util.Objects;
public class CfgRoomsRoomTypesKey implements Serializable{ public class CfgRoomsRoomTypesKey implements Serializable{
@@ -29,8 +30,8 @@ public class CfgRoomsRoomTypesKey implements Serializable{
if(o instanceof CfgRoomsRoomTypesKey) if(o instanceof CfgRoomsRoomTypesKey)
{ {
CfgRoomsRoomTypesKey key = (CfgRoomsRoomTypesKey)o ; CfgRoomsRoomTypesKey key = (CfgRoomsRoomTypesKey)o ;
if(this.roomId == key.getRoomId() && if(Objects.equals(this.roomId, key.getRoomId()) &&
this.roomTypeId == key.getRoomTypeId()) Objects.equals(this.roomTypeId, key.getRoomTypeId()))
{ {
return true ; return true ;
} }
@@ -54,6 +54,8 @@ public class DaylightProxyConfig {
//-- SSL config for daylight //-- SSL config for daylight
@Value("${mcrm.proxy.api-config.daylight.ssl-bundle-name}") @Value("${mcrm.proxy.api-config.daylight.ssl-bundle-name}")
private String sslBundleName; private String sslBundleName;
@Value("${mcrm.proxy.api-config.daylight.skip-trust-validation}")
private boolean skipTrustValidation;
@Bean @Bean
public DaylightApiSetting configDaylightApi() { public DaylightApiSetting configDaylightApi() {
@@ -80,6 +82,7 @@ public class DaylightProxyConfig {
} }
config.setProxyPort(proxyPortValue); config.setProxyPort(proxyPortValue);
config.setSslBundleName(sslBundleName); config.setSslBundleName(sslBundleName);
config.setSkipTrustValidation(skipTrustValidation);
//-- //--
config.registerAuthorizationList(SysCommon.extractAuthorizationItems(appAuthorizationData)); config.registerAuthorizationList(SysCommon.extractAuthorizationItems(appAuthorizationData));
return config; return config;
@@ -19,11 +19,17 @@ public class EsbProxyConfig {
@Value("${mcrm.proxy.api-config.esb.token.token-url}") @Value("${mcrm.proxy.api-config.esb.token.token-url}")
private String tokenUrl; private String tokenUrl;
@Value("${mcrm.proxy.api-config.esb.token.app-id}") @Value("${mcrm.proxy.api-config.esb.token.mcrm.app-id}")
private String appId; private String appIdMcrm;
@Value("${mcrm.proxy.api-config.esb.token.app-secret}") @Value("${mcrm.proxy.api-config.esb.token.mcrm.app-secret}")
private String appSecret; private String appSecretMcrm;
@Value("${mcrm.proxy.api-config.esb.token.limo.app-id}")
private String appIdLimo;
@Value("${mcrm.proxy.api-config.esb.token.limo.app-secret}")
private String appSecretLimo;
@Value("${mcrm.proxy.api-config.esb.token.request-timeout:60}") @Value("${mcrm.proxy.api-config.esb.token.request-timeout:60}")
private int tokenRequestTimeout; private int tokenRequestTimeout;
@@ -46,6 +52,8 @@ public class EsbProxyConfig {
//-- SSL config for esb //-- SSL config for esb
@Value("${mcrm.proxy.api-config.esb.ssl-bundle-name}") @Value("${mcrm.proxy.api-config.esb.ssl-bundle-name}")
private String sslBundleName; private String sslBundleName;
@Value("${mcrm.proxy.api-config.esb.skip-trust-validation}")
private boolean skipTrustValidation;
@Bean @Bean
public EsbApiSetting configEsbApi() { public EsbApiSetting configEsbApi() {
@@ -53,8 +61,10 @@ public class EsbProxyConfig {
config.setServerUrl(serverUrl); config.setServerUrl(serverUrl);
config.setApiRequestTimeout(apiRequestTimeout); config.setApiRequestTimeout(apiRequestTimeout);
config.setTokenUrl(tokenUrl); config.setTokenUrl(tokenUrl);
config.setAppId(appId); config.setAppIdMcrm(appIdMcrm);
config.setAppSecret(appSecret); config.setAppSecretMcrm(appSecretMcrm);
config.setAppIdLimo(appIdLimo);
config.setAppSecretLimo(appSecretLimo);
config.setTokenRequestTimeout(tokenRequestTimeout); config.setTokenRequestTimeout(tokenRequestTimeout);
config.setTokenExpireSecond(tokenExpirySecond); config.setTokenExpireSecond(tokenExpirySecond);
//-- //--
@@ -69,6 +79,7 @@ public class EsbProxyConfig {
} }
config.setProxyPort(proxyPortValue); config.setProxyPort(proxyPortValue);
config.setSslBundleName(sslBundleName); config.setSslBundleName(sslBundleName);
config.setSkipTrustValidation(skipTrustValidation);
//-- //--
config.registerAuthorizationList(SysCommon.extractAuthorizationItems(appAuthorizationData)); config.registerAuthorizationList(SysCommon.extractAuthorizationItems(appAuthorizationData));
return config; return config;
@@ -0,0 +1,60 @@
package com.mgm.mcrm.apigateway.common.config;
import com.mgm.mcrm.apigateway.common.constants.SysCommon;
import com.mgm.mcrm.apigateway.common.dtos.config.EsbApiSetting;
import com.mgm.mcrm.apigateway.common.dtos.config.LimoApiSetting;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class LimoProxyConfig {
@Value("${mcrm.proxy.api-config.limo.server-url}")
private String serverUrl;
@Value("${mcrm.proxy.api-config.limo.request-timeout:60}")
private int apiRequestTimeout;
@Value("${mcrm.proxy.api-config.limo.security.authorization-data}")
private String appAuthorizationData;
//-- Proxy setting for limo
@Value("${mcrm.proxy.api-config.limo.proxy-setting.host}")
private String proxyHost;
@Value("${mcrm.proxy.api-config.limo.proxy-setting.port:443}")
private String proxyPort;
@Value("${mcrm.proxy.api-config.limo.proxy-setting.auth.username}")
private String proxyUsername;
@Value("${mcrm.proxy.api-config.limo.proxy-setting.auth.password}")
private String proxyPassword;
//-- SSL config for limo
@Value("${mcrm.proxy.api-config.limo.ssl-bundle-name}")
private String sslBundleName;
@Value("${mcrm.proxy.api-config.limo.skip-trust-validation}")
private boolean skipTrustValidation;
@Bean
public LimoApiSetting configLimoApi() {
LimoApiSetting config = new LimoApiSetting();
config.setServerUrl(serverUrl);
config.setApiRequestTimeout(apiRequestTimeout);
//--
config.setProxyHost(proxyHost);
config.setProxyUserName(proxyUsername);
config.setProxyPassword(proxyPassword);
int proxyPortValue = 443;
try{
proxyPortValue = Integer.parseInt(proxyPort);
}catch(Exception ignored){
}
config.setProxyPort(proxyPortValue);
config.setSslBundleName(sslBundleName);
config.setSkipTrustValidation(skipTrustValidation);
//--
config.registerAuthorizationList(SysCommon.extractAuthorizationItems(appAuthorizationData));
return config;
}
}
@@ -4,11 +4,11 @@ import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory; import jakarta.persistence.EntityManagerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; import org.springframework.boot.hibernate.autoconfigure.HibernateProperties;
import org.springframework.boot.hibernate.autoconfigure.HibernateSettings;
import org.springframework.boot.jpa.EntityManagerFactoryBuilder;
import org.springframework.boot.jpa.autoconfigure.JpaProperties;
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.context.annotation.Primary; import org.springframework.context.annotation.Primary;
@@ -51,7 +51,7 @@ public class MGMDataSourceConfig {
@Primary @Primary
@Bean(name = "entityManagerFactory") //mrbs实体工厂 @Bean(name = "entityManagerFactory") //mrbs实体工厂
public LocalContainerEntityManagerFactoryBean entityManagerFactory (@Qualifier("mgmDataSource") DataSource mgmDataSource, public LocalContainerEntityManagerFactoryBean entityManagerFactory (@Qualifier("mgmDataSource") DataSource mgmDataSource,
@Qualifier("mgmJpaProperties") JpaProperties jpaProperties,EntityManagerFactoryBuilder builder) { @Qualifier("mgmJpaProperties") JpaProperties jpaProperties, EntityManagerFactoryBuilder builder) {
return builder.dataSource(mgmDataSource) return builder.dataSource(mgmDataSource)
.properties(jpaProperties.getProperties()) .properties(jpaProperties.getProperties())
.properties( .properties(
@@ -4,11 +4,11 @@ import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory; import jakarta.persistence.EntityManagerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; import org.springframework.boot.hibernate.autoconfigure.HibernateProperties;
import org.springframework.boot.hibernate.autoconfigure.HibernateSettings;
import org.springframework.boot.jpa.EntityManagerFactoryBuilder;
import org.springframework.boot.jpa.autoconfigure.JpaProperties;
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.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@@ -46,7 +46,7 @@ public class OperaDataSourceConfig {
@Bean(name = "entityManagerFactoryOpera") @Bean(name = "entityManagerFactoryOpera")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryOpera (@Qualifier("operaDataSource") DataSource operaDataSource, public LocalContainerEntityManagerFactoryBean entityManagerFactoryOpera (@Qualifier("operaDataSource") DataSource operaDataSource,
@Qualifier("operaJpaProperties") JpaProperties jpaProperties,EntityManagerFactoryBuilder builder) { @Qualifier("operaJpaProperties") JpaProperties jpaProperties, EntityManagerFactoryBuilder builder) {
return builder.dataSource(operaDataSource) return builder.dataSource(operaDataSource)
.properties(jpaProperties.getProperties()) .properties(jpaProperties.getProperties())
.properties( .properties(
@@ -21,7 +21,7 @@ public class WebFilterConfig {
@Bean @Bean
public FilterRegistrationBean<WebhookLoggingFilter> registerWebhookFilter( public FilterRegistrationBean<WebhookLoggingFilter> registerWebhookFilter(
WebhookLoggingFilter webhookLoggingFilter) { WebhookLoggingFilter webhookLoggingFilter) {
FilterRegistrationBean<WebhookLoggingFilter> registration = new FilterRegistrationBean<WebhookLoggingFilter>(); FilterRegistrationBean<WebhookLoggingFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(webhookLoggingFilter); registration.setFilter(webhookLoggingFilter);
registration.addUrlPatterns("/api/daylight/webhook/*"); registration.addUrlPatterns("/api/daylight/webhook/*");
registration.setOrder(3); registration.setOrder(3);
@@ -6,6 +6,7 @@ import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.security.KeyStore;
import java.util.*; import java.util.*;
@@ -19,6 +20,10 @@ import org.springframework.boot.system.ApplicationHome;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class SysCommon { public class SysCommon {
@@ -56,7 +61,7 @@ public class SysCommon {
bufferedReader = new BufferedReader(fileReader); bufferedReader = new BufferedReader(fileReader);
String lineData = null; String lineData = null;
int lineCnt =0; int lineCnt =0;
StringBuffer contentBuffer = new StringBuffer(); StringBuilder contentBuffer = new StringBuilder();
while ((lineData = bufferedReader.readLine()) != null) { while ((lineData = bufferedReader.readLine()) != null) {
if(lineCnt>0) { if(lineCnt>0) {
contentBuffer.append("\n"); contentBuffer.append("\n");
@@ -126,4 +131,20 @@ public class SysCommon {
} }
return loginUser; return loginUser;
} }
public static X509TrustManager getDefaultTrustManager() {
try {
// 获取 JVM 默认的 TrustManager 作为核心校验逻辑
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init((KeyStore) null); // 使用系统的默认信任库
for (TrustManager tm : tmf.getTrustManagers()) {
if (tm instanceof X509TrustManager) {
return (X509TrustManager) tm;
}
}
}catch(Exception err){
LogUtil.error(SysCommon.class,"Default X509TrustManager not found["+err.getMessage()+"]");
}
return null;
}
} }
@@ -28,6 +28,7 @@ public class DaylightApiSetting {
private String proxyPassword; private String proxyPassword;
//--SSL config //--SSL config
private String sslBundleName; private String sslBundleName;
private boolean skipTrustValidation=true;
private int tokenRequestTimeout; private int tokenRequestTimeout;
private long tokenExpireSecond; private long tokenExpireSecond;
@@ -14,8 +14,10 @@ public class EsbApiSetting {
private String serverUrl=""; private String serverUrl="";
private int apiRequestTimeout; private int apiRequestTimeout;
private String tokenUrl=""; private String tokenUrl="";
private String appId=""; private String appIdMcrm="";
private String appSecret=""; private String appSecretMcrm="";
private String appIdLimo="";
private String appSecretLimo="";
//--Proxy config //--Proxy config
private String proxyHost; private String proxyHost;
private int proxyPort; private int proxyPort;
@@ -23,6 +25,7 @@ public class EsbApiSetting {
private String proxyPassword; private String proxyPassword;
//--SSL config //--SSL config
private String sslBundleName; private String sslBundleName;
private boolean skipTrustValidation=true;
private int tokenRequestTimeout; private int tokenRequestTimeout;
private long tokenExpireSecond; private long tokenExpireSecond;
@@ -0,0 +1,38 @@
package com.mgm.mcrm.apigateway.common.dtos.config;
import lombok.AccessLevel;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import java.util.HashMap;
import java.util.Map;
@Data
public class LimoApiSetting {
//-- Limo API Server
private String serverUrl;
private int apiRequestTimeout;
//--Proxy config
private String proxyHost;
private int proxyPort;
private String proxyUserName;
private String proxyPassword;
//--SSL config
private String sslBundleName;
private boolean skipTrustValidation=true;
@Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE)
private final Map<String,String> authorizationConfig = new HashMap<>();
public void registerAuthorizationList(Map<String,String> authItems){
if(authItems!=null){
authorizationConfig.putAll(authItems);
}
}
public String getAppAuthorizatinKey(String appId){
return authorizationConfig.getOrDefault(appId, null);
}
}
@@ -21,6 +21,7 @@ public class OperaApiSetting {
private String proxyPassword; private String proxyPassword;
//--SSL config //--SSL config
private String sslBundleName; private String sslBundleName;
private boolean skipTrustValidation=true;
@Getter(AccessLevel.NONE) @Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE) @Setter(AccessLevel.NONE)
@@ -1,46 +0,0 @@
package com.mgm.mcrm.apigateway.common.httpclient;
import org.apache.hc.client5.http.cookie.BasicCookieStore;
import org.apache.hc.client5.http.cookie.CookieStore;
import org.apache.hc.client5.http.protocol.HttpClientContext;
public class HttpCookieContext {
/**
* 使用httpcontext,用于设置和携带Cookie
*/
private HttpClientContext context ;
/**
* 储存Cookie
*/
private CookieStore cookieStore;
public static HttpCookieContext custom(){
return new HttpCookieContext();
}
private HttpCookieContext(){
this.context = new HttpClientContext();
this.cookieStore = new BasicCookieStore();
this.context.setCookieStore(cookieStore);
}
public HttpClientContext getContext() {
return context;
}
public HttpCookieContext setContext(HttpClientContext context) {
this.context = context;
return this;
}
public CookieStore getCookieStore() {
return cookieStore;
}
public HttpCookieContext setCookieStore(CookieStore cookieStore) {
this.cookieStore = cookieStore;
return this;
}
}
@@ -1,310 +0,0 @@
package com.mgm.mcrm.apigateway.common.httpclient;
import org.apache.hc.client5.http.entity.UrlEncodedFormEntity;
import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.HttpHeaders;
import org.apache.hc.core5.http.NameValuePair;
import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
import org.apache.hc.core5.http.io.entity.FileEntity;
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.apache.hc.core5.http.message.BasicHeader;
import org.apache.hc.core5.http.message.BasicNameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.nio.charset.Charset;
import java.util.*;
import java.util.Map.Entry;
public class HttpEntityBuilder {
//传入参数特定类型
public static final String ENTITY_STRING="$ENTITY_STRING$";
public static final String ENTITY_JSON="$ENTITY_JSON$";
public static final String ENTITY_FILE="$ENTITY_FILEE$";
public static final String ENTITY_BYTES="$ENTITY_BYTES$";
public static final String ENTITY_INPUTSTREAM="$ENTITY_INPUTSTREAM$";
public static final String ENTITY_SERIALIZABLE="$ENTITY_SERIALIZABLE$";
public static final String ENTITY_MULTIPART="$ENTITY_MULTIPART$";
private static final List<String> SPECIAL_ENTITIY = Arrays.asList(ENTITY_STRING, ENTITY_JSON, ENTITY_BYTES, ENTITY_FILE, ENTITY_INPUTSTREAM, ENTITY_SERIALIZABLE, ENTITY_MULTIPART);
/**
* 是否开启debug,
*/
private static boolean debug = false;
private static final Logger log = LoggerFactory.getLogger(HttpEntityBuilder.class);
/**
* 检测url是否含有参数,如果有,则把参数加到参数列表中
*
* @param url 资源地址
* @param nvps 参数列表
* @param encoding 编码
* @return 返回去掉参数的url
* @throws UnsupportedEncodingException 不支持的编码异常
*/
public static String checkHasParas(String url, List<NameValuePair> nvps, String encoding) throws UnsupportedEncodingException {
// 检测url中是否存在参数
if (url.contains("?") && url.indexOf("?") < url.indexOf("=")) {
String[] paras = url.substring(url.indexOf("?") + 1).split("&");
for (String para : paras) {
int pos = para.indexOf("=");
if (pos >= 0) {
nvps.add(new BasicNameValuePair(para.substring(0, pos), para.substring(pos + 1)));
} else {
nvps.add(new BasicNameValuePair(para, ""));
}
}
url = url.substring(0, url.indexOf("?"));
}
return url;
}
/**
*
* 参数转换,将map中的参数,转到参数列表中
*
* @param nvps 参数列表
* @param map 参数列表(map)
* @param encoding 编码
* @return 返回HttpEntity
* @throws UnsupportedEncodingException 不支持的编码异常
*/
public static HttpEntity map2HttpEntity(List<NameValuePair> nvps, Map<String, Object> map, String encoding) throws UnsupportedEncodingException {
HttpEntity entity = null;
if(map!=null && map.size()>0){
boolean isSpecial = false;
// 拼接参数
for (Entry<String, Object> entry : map.entrySet()) {
if(SPECIAL_ENTITIY.contains(entry.getKey())){//判断是否在之中
isSpecial = true;
if(ENTITY_STRING.equals(entry.getKey())){//string
entity = new StringEntity(String.valueOf(entry.getValue()), Charset.forName(encoding));
break;
}else if(ENTITY_JSON.equals(entry.getKey())){//json
ContentType jsonContentType;
entity = new StringEntity(String.valueOf(entry.getValue()), Charset.forName(encoding));
String contentType = "application/json";
if (encoding != null && !encoding.trim().isEmpty()) {
// 创建带有编码的JSON ContentType
jsonContentType = ContentType.APPLICATION_JSON.withCharset(Charset.forName(encoding));
}else {
// 使用默认的JSON ContentType(通常UTF-8)
jsonContentType = ContentType.APPLICATION_JSON;
}
// 创建实体时直接传入ContentType
entity = new StringEntity(String.valueOf(entry.getValue()), jsonContentType);
break;
}else if(ENTITY_BYTES.equals(entry.getKey())){//file
byte[] data = (byte[]) entry.getValue();
entity = new ByteArrayEntity(data, ContentType.APPLICATION_OCTET_STREAM);
break;
}else if(ENTITY_FILE.equals(entry.getKey())){//file
if(File.class.isAssignableFrom(entry.getValue().getClass())){
entity = new FileEntity((File)entry.getValue(), ContentType.APPLICATION_OCTET_STREAM);
}else if(entry.getValue().getClass()==String.class){
entity = new FileEntity(new File((String) entry.getValue()), ContentType.create("text/plain", "UTF-8"));
}
break;
}else if(ENTITY_INPUTSTREAM.equals(entry.getKey())){//inputstream
// entity = new InputStreamEntity();
break;
}else if(ENTITY_SERIALIZABLE.equals(entry.getKey())){//serializeable
// entity = new SerializableEntity()
break;
}else if(ENTITY_MULTIPART.equals(entry.getKey())){//MultipartEntityBuilder
File[] files = null;
if(File.class.isAssignableFrom(entry.getValue().getClass().getComponentType())){
files=(File[])entry.getValue();
}else if(entry.getValue().getClass().getComponentType()==String.class){
String[] names = (String[]) entry.getValue();
files = new File[names.length];
for (int i = 0; i < names.length; i++) {
files[i] = new File(names[i]);
}
}
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setCharset(Charset.forName(encoding));// 设置请求的编码格式
builder.setMode(HttpMultipartMode.LEGACY);// 设置浏览器兼容模式
int count = 0;
for (File file : files) {
// //把文件转换成流对象FileBody
// FileBody fileBody = new FileBody(file);
// builder.addPart(String.valueOf(map.get(ENTITY_MULTIPART+".name")) + count++, fileBody);
builder.addBinaryBody(String.valueOf(map.get(ENTITY_MULTIPART+".name")) + count++,file);
}
boolean forceRemoveContentTypeCharset = (boolean)map.get(ENTITY_MULTIPART+".rmCharset");
Map<String, Object> m = new HashMap<String, Object>();
m.putAll(map);
m.remove(ENTITY_MULTIPART);
m.remove(ENTITY_MULTIPART+".name");
m.remove(ENTITY_MULTIPART+".rmCharset");
Iterator<Entry<String, Object>> iterator = m.entrySet().iterator();
// 发送的数据
while (iterator.hasNext()) {
Entry<String, Object> e = iterator.next();
builder.addTextBody(e.getKey(), String.valueOf(e.getValue()), ContentType.create("text/plain", encoding));
}
entity = builder.build();// 生成 HTTP POST 实体
//强制去除contentType中的编码设置,否则,在某些情况下会导致上传失败
if(forceRemoveContentTypeCharset){
removeContentTypeCharset(encoding, entity);
}
break;
}else {
nvps.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue())));
}
}else{
nvps.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue())));
}
}
if(!isSpecial) {
entity = new UrlEncodedFormEntity(nvps, Charset.forName(encoding));
}
}
return entity;
}
/**
* 移除content-type中的charset
*
* @param encoding 编码
* @param entity 请求参数及数据信息
*/
private static void removeContentTypeCharset(String encoding, HttpEntity entity) {
try {
Class<?> clazz = entity.getClass();
Field field = clazz.getDeclaredField("contentType");
field.setAccessible(true); //将字段的访问权限设为true:即去除private修饰符的影响
if(Modifier.isFinal(field.getModifiers())){
Field modifiersField = Field.class.getDeclaredField("modifiers"); //去除final修饰符的影响,将字段设为可修改的
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
}
BasicHeader o = (BasicHeader) field.get(entity);
field.set(entity, new BasicHeader(HttpHeaders.CONTENT_TYPE, o.getValue().replace("; charset="+encoding,"")));
} catch (NoSuchFieldException e) {
HttpEntityBuilder.exception(e);
} catch (SecurityException e) {
HttpEntityBuilder.exception(e);
} catch (IllegalArgumentException e) {
HttpEntityBuilder.exception(e);
} catch (IllegalAccessException e) {
HttpEntityBuilder.exception(e);
}
}
/**
* 生成参数
* 参数格式:k1=v1&amp;k2=v2
*
* @param paras 参数列表
* @return 返回参数列表(map)
*/
public static Map<String,Object> buildParas(String paras){
String[] p = paras.split("&");
String[][] ps = new String[p.length][2];
int pos = 0;
for (int i = 0; i < p.length; i++) {
pos = p[i].indexOf("=");
ps[i][0]=p[i].substring(0,pos);
ps[i][1]=p[i].substring(pos+1);
pos = 0;
}
return buildParas(ps);
}
/**
* 生成参数
* 参数类型:{{"k1","v1"},{"k2","v2"}}
*
* @param paras 参数列表
* @return 返回参数列表(map)
*/
public static Map<String,Object> buildParas(String[][] paras){
// 创建参数队列
Map<String,Object> map = new HashMap<String, Object>();
for (String[] para: paras) {
map.put(para[0], para[1]);
}
return map;
}
/**
* 打印消息
*
* @param msg 消息
*/
public static void info(String msg){
if(debug){
log.info(msg);
}
}
/**
* 打印消息和异常堆栈
*
* @param msg 异常消息
* @param t 异常
*/
public static void infoException(String msg, Throwable t){
if(debug){
log.info(msg,t);
}
}
/**
* 打印错误消息
*
* @param msg 异常消息
*/
public static void error(String msg){
log.error(msg);
}
/**
* 打印错误消息和异常堆栈
*
* @param msg 异常消息
* @param t 异常
*/
public static void errorException(String msg, Throwable t){
log.error(msg, t);
}
/**
* 打印异常堆栈
*
* @param t 异常
*/
public static void exception(Throwable t){
log.error(String.valueOf(t));
}
/**
* 开启打印日志
*/
public static void debug() {
debug(true);
}
/**
* 开启或关闭打印日志
* @param debug 是否开启debug
*/
public static void debug(boolean debug) {
HttpEntityBuilder.debug = debug;
}
}
@@ -1,72 +0,0 @@
package com.mgm.mcrm.apigateway.common.httpclient;
import com.alibaba.fastjson2.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.stream.Collectors;
/**
* HTTP 参数构建器
*
* 用于构建 HTTP 请求参数(查询字符串、请求体等)。
*
* @author Aaka
*/
public class HttpParameterBuilder {
private static final Logger log = LoggerFactory.getLogger(HttpParameterBuilder.class);
/**
* 將參數 Map 轉換為查詢字符串(用於 GET 請求)
*
* @param params 參數 Map
* @return 查詢字符串,格式為 name1=value1&name2=value2
*/
public static String buildQueryString(Map<String, Object> params) {
if (params == null || params.isEmpty()) {
return "";
}
return params.entrySet().stream()
.filter(entry -> entry.getKey() != null && entry.getValue() != null)
.map(entry -> {
try {
String key = URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8);
String value = URLEncoder.encode(String.valueOf(entry.getValue()), StandardCharsets.UTF_8);
return key + "=" + value;
} catch (Exception e) {
log.warn("Failed to encode parameter: {}={}", entry.getKey(), entry.getValue(), e);
return null;
}
})
.filter(java.util.Objects::nonNull)
.collect(Collectors.joining("&"));
}
/**
* 將參數 Map 轉換為請求體字符串
*
* @param params 參數 Map
* @param contentType 內容類型
* @return 請求體字符串
*/
public static String buildRequestBody(Map<String, Object> params, String contentType) {
if (params == null || params.isEmpty()) {
return "";
}
// 如果是 JSON 格式
if (contentType != null && contentType.contains("application/json")) {
// 使用 FastJSON 將 Map 轉換為 JSON 字符串
return JSON.toJSONString(params);
} else {
// 默認使用 form-urlencoded 格式
return buildQueryString(params);
}
}
}
@@ -1,375 +0,0 @@
package com.mgm.mcrm.apigateway.common.httpclient;
import com.mgm.mcrm.apigateway.common.enums.HttpMethods;
import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.entity.mime.Header;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.util.Timeout;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
public class HttpRequestOptions {
private HttpRequestOptions(){};
/**
* 获取实例
* @return 返回当前对象
*/
public static HttpRequestOptions create(){
return new HttpRequestOptions();
}
/**
* HttpClient对象
*/
private HttpClient client;
/**
* Header头信息
*/
private Header[] headers;
/**
* 是否返回response的headers
*/
private boolean isReturnRespHeaders;
/**
* 请求方法
*/
private HttpMethods method=HttpMethods.POST;
/**
* 请求方法名称
*/
private String methodName;
/**
* 用于cookie操作
*/
private HttpContext context;
// private Map<String, Object> map;
/**
* 以json格式作为输入参数
*/
private String json;
/**
* 输入输出编码
*/
private String encoding= Charset.defaultCharset().displayName();
/**
* 输入编码
*/
private String inenc;
/**
* 输出编码
*/
private String outenc;
/**
* 设置RequestConfig
*/
private RequestConfig requestConfig;
/**
* 解决多线程下载时,strean被close的问题
*/
private static final ThreadLocal<OutputStream> outs = new ThreadLocal<OutputStream>();
/**
* 解决多线程处理时,url被覆盖问题
*/
private static final ThreadLocal<String> urls = new ThreadLocal<String>();
/**
* 解决多线程处理时,url被覆盖问题
*/
private static final ThreadLocal<Map<String,Object>> maps = new ThreadLocal<Map<String,Object>>();
/**
* @param client HttpClient对象
* @return 返回当前对象
*/
public HttpRequestOptions client(HttpClient client) {
this.client = client;
return this;
}
/**
* @param url 资源url
* @return 返回当前对象
*/
public HttpRequestOptions url(String url) {
urls.set(url);
return this;
}
/**
* @param headers Header头信息
* @return 返回当前对象
*/
public HttpRequestOptions headers(Header[] headers) {
this.headers = headers;
return this;
}
/**
* Header头信息(是否返回response中的headers)
*
* @param headers Header头信息
* @param isReturnRespHeaders 是否返回response中的headers
* @return 返回当前对象
*/
public HttpRequestOptions headers(Header[] headers, boolean isReturnRespHeaders) {
this.headers = headers;
this.isReturnRespHeaders=isReturnRespHeaders;
return this;
}
/**
* @param method 请求方法
* @return 返回当前对象
*/
public HttpRequestOptions method(HttpMethods method) {
this.method = method;
return this;
}
/**
* @param methodName 请求方法
* @return 返回当前对象
*/
public HttpRequestOptions methodName(String methodName) {
this.methodName = methodName;
return this;
}
/**
* @param context cookie操作相关
* @return 返回当前对象
*/
public HttpRequestOptions context(HttpContext context) {
this.context = context;
return this;
}
/**
* @param map 传递参数
* @return 返回当前对象
*/
public HttpRequestOptions map(Map<String, Object> map) {
// synchronized (getClass()) {
// if(this.map==null || map==null){
// this.map = map;
// }else {
// this.map.putAll(map);;
// }
// }
Map<String, Object> m = maps.get();
if(m == null || map.isEmpty()){
m = map;
}else {
m.putAll(map);
}
maps.set(m);
return this;
}
/**
* @param json 以json格式字符串作为参数
* @return 返回当前对象
*/
public HttpRequestOptions json(String json) {
this.json = json;
Map<String, Object> map = new HashMap<String, Object>();
map.put(HttpEntityBuilder.ENTITY_JSON, json);
maps.set(map);
return this;
}
/**
* @param filePaths 待上传文件所在路径
* @return 返回当前对象
*/
public HttpRequestOptions files(String[] filePaths) {
return files(filePaths, "file");
}
/**
* 上传文件时用到
* @param filePaths 待上传文件所在路径
* @param inputName 即file input 标签的name值,默认为file
* @return 返回当前对象
*/
public HttpRequestOptions files(String[] filePaths, String inputName) {
return files(filePaths, inputName, false);
}
/**
* 上传文件时用到
* @param filePaths 待上传文件所在路径
* @param inputName 即file input 标签的name值,默认为file
* @param forceRemoveContentTypeChraset 是否强制一处content-type中设置的编码类型
* @return 返回当前对象
*/
public HttpRequestOptions files(String[] filePaths, String inputName, boolean forceRemoveContentTypeChraset) {
// synchronized (getClass()) {
// if(this.map==null){
// this.map= new HashMap<String, Object>();
// }
// }
// map.put(Utils.ENTITY_MULTIPART, filePaths);
// map.put(Utils.ENTITY_MULTIPART+".name", inputName);
// map.put(Utils.ENTITY_MULTIPART+".rmCharset", forceRemoveContentTypeChraset);
Map<String, Object> m = maps.get();
if(m.isEmpty()){
m = new HashMap<String, Object>();
}
m.put(HttpEntityBuilder.ENTITY_MULTIPART, filePaths);
m.put(HttpEntityBuilder.ENTITY_MULTIPART+".name", inputName);
m.put(HttpEntityBuilder.ENTITY_MULTIPART+".rmCharset", forceRemoveContentTypeChraset);
maps.set(m);
return this;
}
/**
* @param encoding 输入输出编码
* @return 返回当前对象
*/
public HttpRequestOptions encoding(String encoding) {
//设置输入输出
inenc(encoding);
outenc(encoding);
this.encoding = encoding;
return this;
}
/**
* @param inenc 输入编码
*/
public void inenc(String inenc) {
this.inenc = inenc;
}
/**
* @param outenc 输出编码
*/
public void outenc(String outenc) {
this.outenc = outenc;
}
/**
* @param out 输出流对象
* @return 返回当前对象
*/
public HttpRequestOptions out(OutputStream out) {
outs.set(out);
return this;
}
/**
* 设置超时时间
*
* @param timeout 超市时间,单位-毫秒
* @return 返回当前对象
*/
public HttpRequestOptions timeout(int timeout){
return timeout(timeout, true);
}
/**
* 设置超时时间以及是否允许网页重定向(自动跳转 302)
*
* @param timeout 超时时间,单位-毫秒
* @param redirectEnable 自动跳转
* @return 返回当前对象
*/
public HttpRequestOptions timeout(int timeout, boolean redirectEnable){
// 配置请求的超时设置
// 注意:HttpClient 5 中需要使用 Timeout 对象,而不是直接的 int 值
Timeout timeoutValue = Timeout.ofMilliseconds(timeout);
RequestConfig config = RequestConfig.custom()
.setConnectionRequestTimeout(timeoutValue)
.setResponseTimeout(timeoutValue)
.setRedirectsEnabled(redirectEnable)
.build();
return timeout(config);
}
/**
* 设置代理、超时时间、允许网页重定向等
*
* @param requestConfig 超时时间,单位-毫秒
* @return 返回当前对象
*/
public HttpRequestOptions timeout(RequestConfig requestConfig){
this.requestConfig = requestConfig;
return this;
}
public HttpClient client() {
return client;
}
public Header[] headers() {
return headers;
}
public boolean isReturnRespHeaders() {
return isReturnRespHeaders;
}
public String url() {
return urls.get();
}
public HttpMethods method() {
return method;
}
public String methodName() {
return methodName;
}
public HttpContext context() {
return context;
}
public Map<String, Object> map() {
// return map;
return maps.get();
}
public String json() {
return json;
}
public String encoding() {
return encoding;
}
public String inenc() {
return inenc == null ? encoding : inenc;
}
public String outenc() {
return outenc == null ? encoding : outenc;
}
public OutputStream out() {
return outs.get();
}
public RequestConfig requestConfig() {
return requestConfig;
}
}
@@ -1,197 +0,0 @@
package com.mgm.mcrm.apigateway.common.httpclient;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.core5.ssl.SSLContexts;
import javax.net.ssl.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
/**
* SSL 工具类(基于 HttpClient 5)
*
* 提供:
* - 信任所有证书的 SSLSocketFactory
* - 信任所有证书的 SSLConnectionSocketFactory
*
* 注意:默认实现信任所有证书,仅适用于内部系统或测试环境。
*
* @author Anka
* @version 2.0 (client5)
*/
public class HttpSslSupport {
private static final SSLHandler SIMPLE_VERIFIER = new SSLHandler();
private static SSLSocketFactory sslFactory;
// 注意:SSLConnectionSocketFactory 在 HttpClient 5 中被标记为 deprecated,
// 但这是目前唯一可用的方式,新的 API 尚未稳定
@SuppressWarnings("deprecation")
private static SSLConnectionSocketFactory sslConnFactory;
private static final HttpSslSupport INSTANCE = new HttpSslSupport();
private SSLContext sc;
public static HttpSslSupport getInstance() {
return INSTANCE;
}
public static HttpSslSupport custom() {
return new HttpSslSupport();
}
/**
* 重写 X509TrustManager 和 HostnameVerifier,信任所有证书与主机名。
* 仅推荐在内部环境或调试场景使用。
*/
private static class SSLHandler implements X509TrustManager, HostnameVerifier {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain,
String authType) throws CertificateException {
// 信任所有服务器证书
}
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain,
String authType) throws CertificateException {
// 信任所有客户端证书
}
@Override
public boolean verify(String paramString, SSLSession paramSSLSession) {
// 信任所有主机名
return true;
}
}
/**
* 获取默认 HostnameVerifier(信任所有主机名)
*/
public static HostnameVerifier getVerifier() {
return SIMPLE_VERIFIER;
}
/**
* 获取信任所有证书的 {@link SSLSocketFactory}
*/
public synchronized SSLSocketFactory getSSLSF(SSLProtocolVersion sslpv) {
if (sslFactory != null) {
return sslFactory;
}
try {
SSLContext context = getSSLContext(sslpv);
context.init(null, new TrustManager[]{SIMPLE_VERIFIER}, null);
sslFactory = context.getSocketFactory();
return sslFactory;
} catch (KeyManagementException e) {
throw new RuntimeException("初始化 SSLSocketFactory 失败", e);
}
}
/**
* 获取信任所有证书的 {@link SSLConnectionSocketFactory}(HttpClient5)
*
* 注意:SSLConnectionSocketFactory 在 HttpClient 5 中被标记为 deprecated,
* 但这是目前唯一可用的方式,新的 API 尚未稳定
*/
@SuppressWarnings("deprecation")
public synchronized SSLConnectionSocketFactory getSSLCONNSF(SSLProtocolVersion sslpv) {
if (sslConnFactory != null) {
return sslConnFactory;
}
try {
SSLContext context = getSSLContext(sslpv);
context.init(null, new TrustManager[]{SIMPLE_VERIFIER}, new java.security.SecureRandom());
sslConnFactory = new SSLConnectionSocketFactory(context, SIMPLE_VERIFIER);
return sslConnFactory;
} catch (KeyManagementException e) {
throw new RuntimeException("初始化 SSLConnectionSocketFactory 失败", e);
}
}
/**
* 使用自定义证书(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}
*/
public SSLContext getSSLContext(SSLProtocolVersion sslpv) {
try {
if (this.sc == null) {
this.sc = SSLContext.getInstance(sslpv.getName());
}
return this.sc;
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("不支持的 SSL 协议版本: " + sslpv.getName(), e);
}
}
/**
* 支持的 SSL/TLS 协议版本枚举
*/
public enum SSLProtocolVersion {
SSL("SSL"),
SSLv3("SSLv3"),
TLSv1("TLSv1"),
TLSv1_1("TLSv1.1"),
TLSv1_2("TLSv1.2"),
TLSv1_3("TLSv1.3");
private final String name;
SSLProtocolVersion(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public static SSLProtocolVersion find(String name) {
for (SSLProtocolVersion pv : SSLProtocolVersion.values()) {
if (pv.getName().equalsIgnoreCase(name)) {
return pv;
}
}
throw new IllegalArgumentException("未支持当前 SSL 版本号:" + name);
}
}
}
@@ -2,7 +2,9 @@ package com.mgm.mcrm.apigateway.common.listener;
import com.mgm.mcrm.apigateway.allotment.services.RoomCriteriaDaylightService; import com.mgm.mcrm.apigateway.allotment.services.RoomCriteriaDaylightService;
import com.mgm.mcrm.apigateway.common.constants.SysCommon; import com.mgm.mcrm.apigateway.common.constants.SysCommon;
import com.mgm.mcrm.apigateway.common.dtos.config.DaylightApiSetting;
import com.mgm.mcrm.apigateway.common.utils.NotificationUtil; import com.mgm.mcrm.apigateway.common.utils.NotificationUtil;
import com.mgm.mcrm.apigateway.daylight.common.httpclient.HttpSslSupport;
import com.mgm.mcrm.apigateway.daylight.repositories.CfgCompRuleDao; import com.mgm.mcrm.apigateway.daylight.repositories.CfgCompRuleDao;
import com.mgm.mcrm.apigateway.daylight.services.DaylightApiService; import com.mgm.mcrm.apigateway.daylight.services.DaylightApiService;
import com.mgm.mcrm.apigateway.daylight.webhook.eventhandlers.impl.AvailableRoomCountUpdatedHandler; import com.mgm.mcrm.apigateway.daylight.webhook.eventhandlers.impl.AvailableRoomCountUpdatedHandler;
@@ -15,7 +17,10 @@ import com.mgm.mcrm.apigateway.notification.services.ApnNotificationService;
import com.mgm.mcrm.apigateway.reservation.repositories.BookingDao; import com.mgm.mcrm.apigateway.reservation.repositories.BookingDao;
import com.mgm.mcrm.apigateway.reservation.services.BookingService; import com.mgm.mcrm.apigateway.reservation.services.BookingService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -28,16 +33,12 @@ public class ConfigListener implements ApplicationListener<ApplicationStartedEve
private BookingService bookingService; private BookingService bookingService;
@Resource @Resource
private DaylightApiService daylightApiService; private DaylightApiService daylightApiService;
@Resource
private CfgCompRuleDao cfgCompRuleDao; @Autowired
@Resource private SslBundles sslBundles;
private BookingDao bookingDao;
@Resource @Autowired
private SysLogDeviceTokenRepository sysLogDeviceTokenRepository; private DaylightApiSetting daylightApiSetting;
@Resource
private NotificationUtil notificationUtil;
@Resource
private ApnNotificationService apnNotificationService;
@Override @Override
public void onApplicationEvent(ApplicationStartedEvent event) { public void onApplicationEvent(ApplicationStartedEvent event) {
@@ -48,16 +49,14 @@ public class ConfigListener implements ApplicationListener<ApplicationStartedEve
DaylightWebhookFactory.registerHandler("AvailableRoomCountUpdated", new AvailableRoomCountUpdatedHandler(roomCriteriaDaylightService)); DaylightWebhookFactory.registerHandler("AvailableRoomCountUpdated", new AvailableRoomCountUpdatedHandler(roomCriteriaDaylightService));
//--Register Reservation Notification handlers //--Register Reservation Notification handlers
DaylightWebhookFactory.registerHandler("ReservationNotification", new ReservationNotificationHandler(bookingService, daylightApiService)); DaylightWebhookFactory.registerHandler("ReservationNotification", new ReservationNotificationHandler(bookingService, daylightApiService));
DaylightWebhookFactory.registerHandler(
"ComplimentaryRuleLimitsExceededChangedNotification", try{
new CompRuleLimitsExceededChangedHandler( HttpSslSupport.setSkipValidation(daylightApiSetting.isSkipTrustValidation());
cfgCompRuleDao, if(StringUtils.isNotBlank(daylightApiSetting.getSslBundleName())){
bookingDao, HttpSslSupport.setSslBundle(sslBundles.getBundle(daylightApiSetting.getSslBundleName()));
sysLogDeviceTokenRepository, }
notificationUtil, }catch(Exception ignore){
apnNotificationService,
daylightApiService }
) }
);
}
} }
@@ -0,0 +1,38 @@
package com.mgm.mcrm.apigateway.common.services;
import javax.net.ssl.X509TrustManager;
public class ConfigurableTrustHandler implements X509TrustManager {
private final boolean skipValidation;
private final X509TrustManager defaultTrustManager;
public ConfigurableTrustHandler(boolean skipValidation, X509TrustManager defaultTrustManager) {
this.skipValidation = skipValidation;
this.defaultTrustManager = defaultTrustManager;
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
if (skipValidation) {
return new java.security.cert.X509Certificate[0];
}else{
return defaultTrustManager != null ? defaultTrustManager.getAcceptedIssuers() : new java.security.cert.X509Certificate[0];
}
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain,
String authType) throws java.security.cert.CertificateException {
if (!skipValidation && defaultTrustManager != null) {
defaultTrustManager.checkServerTrusted(chain, authType);
}
}
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain,
String authType) throws java.security.cert.CertificateException {
if (!skipValidation && defaultTrustManager != null) {
defaultTrustManager.checkClientTrusted(chain, authType);
}
}
}
@@ -1,22 +1,19 @@
package com.mgm.mcrm.apigateway.common.utils; package com.mgm.mcrm.apigateway.common.utils;
import java.lang.management.ManagementFactory;
import java.net.*; import java.net.*;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import com.mgm.mcrm.apigateway.common.constants.SysCommon;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils; import org.apache.commons.text.StringEscapeUtils;
import org.springframework.web.util.UriUtils; import org.springframework.web.util.UriUtils;
public class NetworkUtil { public class NetworkUtil {
private static final List<String> interalIpPatterns = new ArrayList<String>(); private static final List<String> interalIpPatterns = new ArrayList<>();
private static final Pattern IPV4_PATTERN = private static final Pattern IPV4_PATTERN =
Pattern.compile("^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"); Pattern.compile("^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");
private static final List<String> INTERNAL_IP_PREFIXES = Arrays.asList( private static final List<String> INTERNAL_IP_PREFIXES = Arrays.asList(
@@ -24,6 +21,13 @@ public class NetworkUtil {
"172.20.", "172.21.", "172.22.", "172.23.", "172.24.", "172.25.", "172.20.", "172.21.", "172.22.", "172.23.", "172.24.", "172.25.",
"172.26.", "172.27.", "172.28.", "172.29.", "172.30.", "172.31." "172.26.", "172.27.", "172.28.", "172.29.", "172.30.", "172.31."
); );
private static final Set<String> ALLOWED_PROTOCOLS = new HashSet<>(
Arrays.asList("http", "https")
);
// 禁止的端口
private static final Set<Integer> BLOCKED_PORTS = new HashSet<>(
Arrays.asList(22, 23, 25, 53, 110, 143, 3306, 5432, 6379, 27017)
);
public static void setInternalIpPattern(String patternConfig) { public static void setInternalIpPattern(String patternConfig) {
interalIpPatterns.clear(); interalIpPatterns.clear();
@@ -196,22 +200,22 @@ public class NetworkUtil {
// 外网IP // 外网IP
String netip = null; String netip = null;
try { try {
Enumeration netInterfaces = NetworkInterface.getNetworkInterfaces(); Enumeration<NetworkInterface> netInterfaces = NetworkInterface.getNetworkInterfaces();
InetAddress ip = null; InetAddress ip = null;
// 是否找到外网IP // 是否找到外网IP
boolean finded = false; boolean finded = false;
while (netInterfaces.hasMoreElements() && !finded) { while (netInterfaces.hasMoreElements() && !finded) {
NetworkInterface ni = (NetworkInterface) netInterfaces.nextElement(); NetworkInterface ni = (NetworkInterface) netInterfaces.nextElement();
Enumeration address = ni.getInetAddresses(); Enumeration<InetAddress> address = ni.getInetAddresses();
while (address.hasMoreElements()) { while (address.hasMoreElements()) {
ip = (InetAddress) address.nextElement(); ip = (InetAddress) address.nextElement();
if (!ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && ip.getHostAddress().indexOf(":") == -1) { if (!ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && !ip.getHostAddress().contains(":")) {
// 外网IP // 外网IP
netip = ip.getHostAddress(); netip = ip.getHostAddress();
finded = true; finded = true;
break; break;
} else if (ip.isSiteLocalAddress() && !ip.isLoopbackAddress() } else if (ip.isSiteLocalAddress() && !ip.isLoopbackAddress()
&& ip.getHostAddress().indexOf(":") == -1) { && !ip.getHostAddress().contains(":")) {
// 内网IP // 内网IP
localip = ip.getHostAddress(); localip = ip.getHostAddress();
} }
@@ -316,40 +320,106 @@ public class NetworkUtil {
return false; return false;
} }
public static boolean isValidURL(String requestUrl){ public static String sanitizeCRLF(String input){
if(input==null)
return null;
return input.replaceAll("[\r\n]+", "");
}
public static String validateAndSanitizeUrl(String userInputUrl) throws SecurityException {
if (userInputUrl == null || userInputUrl.trim().isEmpty()) {
throw new SecurityException("URL should not be blank");
}
try { try {
URI uri = new URI(requestUrl); // 1. 解析URL
String scheme = uri.getScheme(); URL url = new URI(userInputUrl).toURL();
String host = uri.getHost();
if(!"https".equals(scheme) && !"http".equals(scheme)) { // 2. 验证协议
return false; validateProtocol(url.getProtocol());
// 3. 验证主机名/IP
String host = url.getHost();
validateHost(host);
// 4. 验证端口
int port = url.getPort();
if (port == -1) {
port = url.getDefaultPort();
} }
if(host.matches("\\d+\\.\\d+\\.\\d+\\.\\d+")) { validatePort(port);
return false;
} // 5. 验证路径(防止路径遍历)
return true; validatePath(url.getPath());
// 6. 返回净化后的URL(标准化)
return sanitizeUrl(url);
} catch (Exception e) { } catch (Exception e) {
return false; throw new SecurityException("Invalid URL: " + e.getMessage(), e);
} }
} }
public static String encodeParaWithSpring(String value) { private static void validateProtocol(String protocol) throws SecurityException {
if(value==null) if (!ALLOWED_PROTOCOLS.contains(protocol.toLowerCase())) {
value=""; throw new SecurityException("No support protocol: " + protocol + ", only for HTTP/HTTPS");
value= value.replace("\r", "").replace("\n", ""); }
return UriUtils.encode(value, StandardCharsets.UTF_8);
} }
public static String sanitizeHeaderValue(String headerValue) { private static void validateHost(String host) throws SecurityException {
return headerValue==null? null :(StringEscapeUtils.escapeJava( if (host == null || host.isEmpty()) {
headerValue.replace("\r", "").replace("\n", "") throw new SecurityException("Host name can not be empty");
)); }
// 解析IP并验证
try {
InetAddress address = InetAddress.getByName(host);
String ip = address.getHostAddress();
if (address.isLoopbackAddress()) {
throw new SecurityException("Forbit loopback address");
}
} catch (UnknownHostException e) {
throw new SecurityException("Invalid host: " + host);
}
} }
public static String encodePathWithSpring(String value) { private static void validatePort(int port) throws SecurityException {
if(value==null) // 检查是否为禁止端口
value=""; if (BLOCKED_PORTS.contains(port)) {
value= value.replace("\r", "").replace("\n", ""); throw new SecurityException("Invalid Port: " + port);
return UriUtils.encodePath(value, StandardCharsets.UTF_8); }
}
private static void validatePath(String path) throws SecurityException {
if (path == null) return;
// 防止路径遍历攻击
if (path.contains("..")) {
throw new SecurityException("Invalid path contains '..'");
}
if (path.toLowerCase().contains("://")) {
throw new SecurityException("Invalid path prefix");
}
}
private static String sanitizeUrl(URL url) {
StringBuilder sb = new StringBuilder();
sb.append(url.getProtocol()).append("://");
sb.append(url.getHost());
int port = url.getPort();
if (port != -1 && port != url.getDefaultPort()) {
sb.append(":").append(port);
}
sb.append(url.getPath());
String query = url.getQuery();
if (query != null && !query.isEmpty()) {
sb.append("?").append(query);
}
return sb.toString();
} }
} }
@@ -97,7 +97,7 @@ public class HttpUtilMockup {
private static boolean matchCondiction(JSONObject requestObj, String condiction) { private static boolean matchCondiction(JSONObject requestObj, String condiction) {
boolean matchResult = false; boolean matchResult = false;
List<String> operateList = new ArrayList<String>(); List<String> operateList = new ArrayList<>();
String[] andList = condiction.split("&&"); String[] andList = condiction.split("&&");
for(int i=0;i<andList.length;i++) { for(int i=0;i<andList.length;i++) {
if(i>0) { if(i>0) {
@@ -126,26 +126,25 @@ public class HttpUtilMockup {
} }
String lastOperate = "AND"; String lastOperate = "AND";
boolean isFirst =true; boolean isFirst =true;
for(int i=0;i<operateList.size();i++) { for (String express : operateList) {
String express = operateList.get(i); if (express.equals("&&")) {
if(express.equals("&&")) { lastOperate = "AND";
lastOperate = "AND"; } else if (express.equals("||")) {
}else if(express.equals("||")) { lastOperate = "OR";
lastOperate = "OR"; } else {
}else { boolean valRes = calcCondictionValue(requestObj, express);
boolean valRes = calcCondictionValue(requestObj, express); if (isFirst) {
if(isFirst==true) { matchResult = matchResult || valRes;
matchResult=matchResult||valRes; isFirst = false;
isFirst=false; } else {
}else { if (lastOperate.equals("AND")) {
if(lastOperate.equals("AND")) { matchResult = matchResult && valRes;
matchResult=matchResult&&valRes; } else {
}else { matchResult = matchResult || valRes;
matchResult=matchResult||valRes; }
} }
} }
} }
}
return matchResult; return matchResult;
} }
@@ -212,18 +211,15 @@ public class HttpUtilMockup {
} }
} }
} }
if(isNum==true) { if(isNum) {
if(operate.equals("==")) { result = switch (operate) {
result = (numVal1==numVal2); case "==" -> (numVal1 == numVal2);
}else if(operate.equals("<=")) { case "<=" -> (numVal1 <= numVal2);
result = (numVal1<=numVal2); case ">=" -> (numVal1 >= numVal2);
}else if(operate.equals(">=")) { case "<" -> (numVal1 < numVal2);
result = (numVal1>=numVal2); case ">" -> (numVal1 > numVal2);
}else if(operate.equals("<")) { default -> result;
result = (numVal1<numVal2); };
}else if(operate.equals(">")) {
result = (numVal1>numVal2);
}
}else { }else {
String textVal1 = valName1; String textVal1 = valName1;
String textVal2 = valName2; String textVal2 = valName2;
@@ -233,17 +229,14 @@ public class HttpUtilMockup {
if(requestObj.containsKey(valName2)) { if(requestObj.containsKey(valName2)) {
textVal2 = requestObj.getString(valName2); textVal2 = requestObj.getString(valName2);
} }
if(operate.equals("==")) { result = switch (operate) {
result = (textVal1.compareTo(textVal2)==0); case "==" -> (textVal1.compareTo(textVal2) == 0);
}else if(operate.equals("<=")) { case "<=" -> (textVal1.compareTo(textVal2) <= 0);
result = (textVal1.compareTo(textVal2)<=0); case ">=" -> (textVal1.compareTo(textVal2) >= 0);
}else if(operate.equals(">=")) { case "<" -> (textVal1.compareTo(textVal2) < 0);
result = (textVal1.compareTo(textVal2)>=0); case ">" -> (textVal1.compareTo(textVal2) > 0);
}else if(operate.equals("<")) { default -> result;
result = (textVal1.compareTo(textVal2)<0); };
}else if(operate.equals(">")) {
result = (textVal1.compareTo(textVal2)>0);
}
} }
} }
return result; return result;
@@ -85,86 +85,91 @@ public class HttpEntityBuilder {
if(map!=null && map.size()>0){ if(map!=null && map.size()>0){
boolean isSpecial = false; boolean isSpecial = false;
// 拼接参数 // 拼接参数
label:
for (Entry<String, Object> entry : map.entrySet()) { for (Entry<String, Object> entry : map.entrySet()) {
if(SPECIAL_ENTITIY.contains(entry.getKey())){//判断是否在之中 if(SPECIAL_ENTITIY.contains(entry.getKey())){//判断是否在之中
isSpecial = true; isSpecial = true;
if(ENTITY_STRING.equals(entry.getKey())){//string switch (entry.getKey()) {
entity = new StringEntity(String.valueOf(entry.getValue()), Charset.forName(encoding)); case ENTITY_STRING: //string
break; entity = new StringEntity(String.valueOf(entry.getValue()), Charset.forName(encoding));
}else if(ENTITY_JSON.equals(entry.getKey())){//json break label;
ContentType jsonContentType; case ENTITY_JSON: //json
ContentType jsonContentType;
entity = new StringEntity(String.valueOf(entry.getValue()), Charset.forName(encoding)); entity = new StringEntity(String.valueOf(entry.getValue()), Charset.forName(encoding));
String contentType = "application/json"; String contentType = "application/json";
if (encoding != null && !encoding.trim().isEmpty()) { if (encoding != null && !encoding.trim().isEmpty()) {
// 创建带有编码的JSON ContentType // 创建带有编码的JSON ContentType
jsonContentType = ContentType.APPLICATION_JSON.withCharset(Charset.forName(encoding)); jsonContentType = ContentType.APPLICATION_JSON.withCharset(Charset.forName(encoding));
}else { } else {
// 使用默认的JSON ContentType(通常UTF-8) // 使用默认的JSON ContentType(通常UTF-8)
jsonContentType = ContentType.APPLICATION_JSON; jsonContentType = ContentType.APPLICATION_JSON;
}
// 创建实体时直接传入ContentType
entity = new StringEntity(String.valueOf(entry.getValue()), jsonContentType);
break;
}else if(ENTITY_BYTES.equals(entry.getKey())){//file
byte[] data = (byte[]) entry.getValue();
entity = new ByteArrayEntity(data, ContentType.APPLICATION_OCTET_STREAM);
break;
}else if(ENTITY_FILE.equals(entry.getKey())){//file
if(File.class.isAssignableFrom(entry.getValue().getClass())){
entity = new FileEntity((File)entry.getValue(), ContentType.APPLICATION_OCTET_STREAM);
}else if(entry.getValue().getClass()==String.class){
entity = new FileEntity(new File((String) entry.getValue()), ContentType.create("text/plain", "UTF-8"));
}
break;
}else if(ENTITY_INPUTSTREAM.equals(entry.getKey())){//inputstream
// entity = new InputStreamEntity();
break;
}else if(ENTITY_SERIALIZABLE.equals(entry.getKey())){//serializeable
// entity = new SerializableEntity()
break;
}else if(ENTITY_MULTIPART.equals(entry.getKey())){//MultipartEntityBuilder
File[] files = null;
if(File.class.isAssignableFrom(entry.getValue().getClass().getComponentType())){
files=(File[])entry.getValue();
}else if(entry.getValue().getClass().getComponentType()==String.class){
String[] names = (String[]) entry.getValue();
files = new File[names.length];
for (int i = 0; i < names.length; i++) {
files[i] = new File(names[i]);
} }
} // 创建实体时直接传入ContentType
MultipartEntityBuilder builder = MultipartEntityBuilder.create(); entity = new StringEntity(String.valueOf(entry.getValue()), jsonContentType);
builder.setCharset(Charset.forName(encoding));// 设置请求的编码格式 break label;
builder.setMode(HttpMultipartMode.LEGACY);// 设置浏览器兼容模式 case ENTITY_BYTES: //file
int count = 0; byte[] data = (byte[]) entry.getValue();
for (File file : files) { entity = new ByteArrayEntity(data, ContentType.APPLICATION_OCTET_STREAM);
break label;
case ENTITY_FILE: //file
if (File.class.isAssignableFrom(entry.getValue().getClass())) {
entity = new FileEntity((File) entry.getValue(), ContentType.APPLICATION_OCTET_STREAM);
} else if (entry.getValue().getClass() == String.class) {
entity = new FileEntity(new File((String) entry.getValue()), ContentType.create("text/plain", "UTF-8"));
}
break label;
case ENTITY_INPUTSTREAM: //input stream
// entity = new InputStreamEntity();
break label;
case ENTITY_SERIALIZABLE: //serializable
// entity = new SerializableEntity()
break label;
case ENTITY_MULTIPART: //MultipartEntityBuilder
File[] files = null;
if (File.class.isAssignableFrom(entry.getValue().getClass().getComponentType())) {
files = (File[]) entry.getValue();
} else if (entry.getValue().getClass().getComponentType() == String.class) {
String[] names = (String[]) entry.getValue();
files = new File[names.length];
for (int i = 0; i < names.length; i++) {
files[i] = new File(names[i]);
}
}
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setCharset(Charset.forName(encoding));// 设置请求的编码格式
builder.setMode(HttpMultipartMode.LEGACY);// 设置浏览器兼容模式
int count = 0;
for (File file : files) {
// //把文件转换成流对象FileBody // //把文件转换成流对象FileBody
// FileBody fileBody = new FileBody(file); // FileBody fileBody = new FileBody(file);
// builder.addPart(String.valueOf(map.get(ENTITY_MULTIPART+".name")) + count++, fileBody); // builder.addPart(String.valueOf(map.get(ENTITY_MULTIPART+".name")) + count++, fileBody);
builder.addBinaryBody(String.valueOf(map.get(ENTITY_MULTIPART+".name")) + count++,file); builder.addBinaryBody(String.valueOf(map.get(ENTITY_MULTIPART + ".name")) + count++, file);
} }
boolean forceRemoveContentTypeCharset = (boolean)map.get(ENTITY_MULTIPART+".rmCharset"); boolean forceRemoveContentTypeCharset = (boolean) map.get(ENTITY_MULTIPART + ".rmCharset");
Map<String, Object> m = new HashMap<String, Object>(); Map<String, Object> m = new HashMap<>();
m.putAll(map); m.putAll(map);
m.remove(ENTITY_MULTIPART); m.remove(ENTITY_MULTIPART);
m.remove(ENTITY_MULTIPART+".name"); m.remove(ENTITY_MULTIPART + ".name");
m.remove(ENTITY_MULTIPART+".rmCharset"); m.remove(ENTITY_MULTIPART + ".rmCharset");
Iterator<Entry<String, Object>> iterator = m.entrySet().iterator(); // 发送的数据
// 发送的数据 for (Entry<String, Object> e : m.entrySet()) {
while (iterator.hasNext()) { builder.addTextBody(e.getKey(), String.valueOf(e.getValue()), ContentType.create("text/plain", encoding));
Entry<String, Object> e = iterator.next(); }
builder.addTextBody(e.getKey(), String.valueOf(e.getValue()), ContentType.create("text/plain", encoding)); entity = builder.build();// 生成 HTTP POST 实体
}
entity = builder.build();// 生成 HTTP POST 实体
//强制去除contentType中的编码设置,否则,在某些情况下会导致上传失败
if(forceRemoveContentTypeCharset){ //强制去除contentType中的编码设置,否则,在某些情况下会导致上传失败
removeContentTypeCharset(encoding, entity); if (forceRemoveContentTypeCharset) {
} removeContentTypeCharset(encoding, entity);
break; }
}else { break label;
nvps.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue()))); case null:
default:
nvps.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue())));
break;
} }
}else{ }else{
nvps.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue()))); nvps.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue())));
@@ -195,13 +200,7 @@ public class HttpEntityBuilder {
} }
BasicHeader o = (BasicHeader) field.get(entity); BasicHeader o = (BasicHeader) field.get(entity);
field.set(entity, new BasicHeader(HttpHeaders.CONTENT_TYPE, o.getValue().replace("; charset="+encoding,""))); field.set(entity, new BasicHeader(HttpHeaders.CONTENT_TYPE, o.getValue().replace("; charset="+encoding,"")));
} catch (NoSuchFieldException e) { } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
HttpEntityBuilder.exception(e);
} catch (SecurityException e) {
HttpEntityBuilder.exception(e);
} catch (IllegalArgumentException e) {
HttpEntityBuilder.exception(e);
} catch (IllegalAccessException e) {
HttpEntityBuilder.exception(e); HttpEntityBuilder.exception(e);
} }
} }
@@ -236,7 +235,7 @@ public class HttpEntityBuilder {
*/ */
public static Map<String,Object> buildParas(String[][] paras){ public static Map<String,Object> buildParas(String[][] paras){
// 创建参数队列 // 创建参数队列
Map<String,Object> map = new HashMap<String, Object>(); Map<String,Object> map = new HashMap<>();
for (String[] para: paras) { for (String[] para: paras) {
map.put(para[0], para[1]); map.put(para[0], para[1]);
} }
@@ -1,4 +1,4 @@
package com.mgm.mcrm.apigateway.common.httpclient; package com.mgm.mcrm.apigateway.daylight.common.httpclient;
import com.mgm.mcrm.apigateway.common.config.HttpHeader; import com.mgm.mcrm.apigateway.common.config.HttpHeader;
@@ -25,7 +25,7 @@ public class HttpHeaderBuilder {
} }
//记录head头信息 //记录head头信息
private Map<String, Header> headerMaps = new HashMap<String, Header>(); private Map<String, Header> headerMaps = new HashMap<>();
/** /**
* 自定义header头信息 * 自定义header头信息
@@ -85,17 +85,17 @@ public class HttpRequestOptions {
/** /**
* 解决多线程下载时,strean被close的问题 * 解决多线程下载时,strean被close的问题
*/ */
private static final ThreadLocal<OutputStream> outs = new ThreadLocal<OutputStream>(); private static final ThreadLocal<OutputStream> outs = new ThreadLocal<>();
/** /**
* 解决多线程处理时,url被覆盖问题 * 解决多线程处理时,url被覆盖问题
*/ */
private static final ThreadLocal<String> urls = new ThreadLocal<String>(); private static final ThreadLocal<String> urls = new ThreadLocal<>();
/** /**
* 解决多线程处理时,url被覆盖问题 * 解决多线程处理时,url被覆盖问题
*/ */
private static final ThreadLocal<Map<String,Object>> maps = new ThreadLocal<Map<String,Object>>(); private static final ThreadLocal<Map<String,Object>> maps = new ThreadLocal<>();
/** /**
* @param client HttpClient对象 * @param client HttpClient对象
@@ -169,13 +169,6 @@ public class HttpRequestOptions {
* @return 返回当前对象 * @return 返回当前对象
*/ */
public HttpRequestOptions map(Map<String, Object> map) { public HttpRequestOptions map(Map<String, Object> map) {
// synchronized (getClass()) {
// if(this.map==null || map==null){
// this.map = map;
// }else {
// this.map.putAll(map);;
// }
// }
Map<String, Object> m = maps.get(); Map<String, Object> m = maps.get();
if(m == null || map.isEmpty()){ if(m == null || map.isEmpty()){
m = map; m = map;
@@ -222,18 +215,10 @@ public class HttpRequestOptions {
* @return 返回当前对象 * @return 返回当前对象
*/ */
public HttpRequestOptions files(String[] filePaths, String inputName, boolean forceRemoveContentTypeChraset) { public HttpRequestOptions files(String[] filePaths, String inputName, boolean forceRemoveContentTypeChraset) {
// synchronized (getClass()) {
// if(this.map==null){
// this.map= new HashMap<String, Object>();
// }
// }
// map.put(Utils.ENTITY_MULTIPART, filePaths);
// map.put(Utils.ENTITY_MULTIPART+".name", inputName);
// map.put(Utils.ENTITY_MULTIPART+".rmCharset", forceRemoveContentTypeChraset);
Map<String, Object> m = maps.get(); Map<String, Object> m = maps.get();
if(m.isEmpty()){ if(m.isEmpty()){
m = new HashMap<String, Object>(); m = new HashMap<>();
} }
m.put(HttpEntityBuilder.ENTITY_MULTIPART, filePaths); m.put(HttpEntityBuilder.ENTITY_MULTIPART, filePaths);
m.put(HttpEntityBuilder.ENTITY_MULTIPART+".name", inputName); m.put(HttpEntityBuilder.ENTITY_MULTIPART+".name", inputName);
@@ -1,7 +1,14 @@
package com.mgm.mcrm.apigateway.daylight.common.httpclient; package com.mgm.mcrm.apigateway.daylight.common.httpclient;
import com.mgm.mcrm.apigateway.common.constants.SysCommon;
import com.mgm.mcrm.apigateway.common.services.ConfigurableTrustHandler;
import lombok.Getter;
import lombok.Setter;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.core5.ssl.SSLContexts; import org.apache.hc.core5.ssl.SSLContexts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ssl.SslBundle;
import org.springframework.boot.ssl.SslBundles;
import javax.net.ssl.*; import javax.net.ssl.*;
import java.io.File; import java.io.File;
@@ -26,7 +33,16 @@ import java.security.cert.CertificateException;
* @version 2.0 (client5) * @version 2.0 (client5)
*/ */
public class HttpSslSupport { public class HttpSslSupport {
private static final SSLHandler SIMPLE_VERIFIER = new SSLHandler();
@Getter
@Setter
private static boolean skipValidation=true;
private static ConfigurableTrustHandler trustHandler=null;
@Getter
@Setter
private static SslBundle sslBundle=null;
private static SSLSocketFactory sslFactory; private static SSLSocketFactory sslFactory;
// 注意:SSLConnectionSocketFactory 在 HttpClient 5 中被标记为 deprecated, // 注意:SSLConnectionSocketFactory 在 HttpClient 5 中被标记为 deprecated,
@@ -46,41 +62,13 @@ public class HttpSslSupport {
return new HttpSslSupport(); return new HttpSslSupport();
} }
/**
* 重写 X509TrustManager 和 HostnameVerifier,信任所有证书与主机名。
* 仅推荐在内部环境或调试场景使用。
*/
private static class SSLHandler implements X509TrustManager, HostnameVerifier {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() { public static ConfigurableTrustHandler getTrustHandler(){
return new java.security.cert.X509Certificate[]{}; if(trustHandler==null){
trustHandler =new ConfigurableTrustHandler(skipValidation, SysCommon.getDefaultTrustManager());
} }
return trustHandler;
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain,
String authType) throws CertificateException {
// 信任所有服务器证书
}
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain,
String authType) throws CertificateException {
// 信任所有客户端证书
}
@Override
public boolean verify(String paramString, SSLSession paramSSLSession) {
// 信任所有主机名
return true;
}
}
/**
* 获取默认 HostnameVerifier(信任所有主机名)
*/
public static HostnameVerifier getVerifier() {
return SIMPLE_VERIFIER;
} }
/** /**
@@ -91,8 +79,15 @@ public class HttpSslSupport {
return sslFactory; return sslFactory;
} }
try { try {
SSLContext context = getSSLContext(sslpv); SSLContext context =null;
context.init(null, new TrustManager[]{SIMPLE_VERIFIER}, null); if(sslBundle!=null){
context = sslBundle.createSslContext();
}else{
context = getSSLContext(sslpv);
context.init(null, new TrustManager[]{
getTrustHandler()
}, null);
}
sslFactory = context.getSocketFactory(); sslFactory = context.getSocketFactory();
return sslFactory; return sslFactory;
} catch (KeyManagementException e) { } catch (KeyManagementException e) {
@@ -112,9 +107,17 @@ public class HttpSslSupport {
return sslConnFactory; return sslConnFactory;
} }
try { try {
SSLContext context = getSSLContext(sslpv); SSLContext context = null;
context.init(null, new TrustManager[]{SIMPLE_VERIFIER}, new java.security.SecureRandom()); if (sslBundle != null) {
sslConnFactory = new SSLConnectionSocketFactory(context, SIMPLE_VERIFIER); context = sslBundle.createSslContext();
} else {
context = getSSLContext(sslpv);
ConfigurableTrustHandler trustHandler = getTrustHandler();
context.init(null, new TrustManager[]{
trustHandler
}, new java.security.SecureRandom());
}
sslConnFactory = new SSLConnectionSocketFactory(context);
return sslConnFactory; return sslConnFactory;
} catch (KeyManagementException e) { } catch (KeyManagementException e) {
throw new RuntimeException("初始化 SSLConnectionSocketFactory 失败", e); throw new RuntimeException("初始化 SSLConnectionSocketFactory 失败", e);
@@ -166,17 +166,4 @@ public class HttpService {
log.info("PATCH request result={}", result); log.info("PATCH request result={}", result);
return result; return result;
} }
// public HttpResult sslSendNotification(String url, Header[] headers, SendNotificationRequest request) throws Exception {
// log.info("POST method, send notification, url={}, headers={}, map={}", notificationProxyUrl + url, JSON.toJSONString(headers), JSON.toJSONString(request));
// HttpRequestOptions postConfig = HttpRequestOptions.create()
// .url(notificationProxyUrl + url)
// .timeout(requestConfig)
// .json(JSON.toJSONString(request))
// .method(HttpMethods.POST)
// .client(httpClient);
// HttpResult result = HttpClientExecutor.sendAndPostResp(postConfig, headers);
// log.info("POST request result={}", result);
// return result;
// }
} }
@@ -3,7 +3,7 @@ package com.mgm.mcrm.apigateway.daylight.services;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.mgm.mcrm.apigateway.common.dtos.BaseApiResponse; import com.mgm.mcrm.apigateway.common.dtos.BaseApiResponse;
import com.mgm.mcrm.apigateway.common.httpclient.HttpHeaderBuilder; import com.mgm.mcrm.apigateway.daylight.common.httpclient.HttpHeaderBuilder;
import com.mgm.mcrm.apigateway.daylight.common.services.HttpService; import com.mgm.mcrm.apigateway.daylight.common.services.HttpService;
import com.mgm.mcrm.apigateway.daylight.dtos.response.CompRuleResponse; import com.mgm.mcrm.apigateway.daylight.dtos.response.CompRuleResponse;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
@@ -24,7 +24,7 @@ public class PlayerProfileApiResult {
private String state; private String state;
private String passport = null; private String passport = null;
private String language = null; private String language = null;
private List<Integer> nameIds=new ArrayList<Integer>(); private List<Integer> nameIds=new ArrayList<>();
public PlayerProfileApiResult() { public PlayerProfileApiResult() {
@@ -13,6 +13,7 @@ import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; 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.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@@ -21,6 +22,8 @@ import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.Duration; import java.time.Duration;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
@Service @Service
@@ -31,21 +34,26 @@ public class EsbTokenService {
private WebProxyService webProxyService; private WebProxyService webProxyService;
@Autowired @Autowired
private EsbApiSetting esbApiSetting; private EsbApiSetting esbApiSetting;
private EsbToken cachedToken = new EsbToken(); @Value("${mcrm.proxy.api-config.esb.api-path.mcrm}")
private String mcrmApiPath;
@Value("${mcrm.proxy.api-config.esb.api-path.limo}")
private String limoApiPath;
private final Map<String, EsbToken> cachedTokens = new HashMap<>();
// 重试间隔时间:1秒 // 重试间隔时间:1秒
private final long RETRY_DELAY_MS = 1000; private static final long RETRY_DELAY_MS = 1000;
public EsbToken getApiAccessToken() throws Exception { public synchronized EsbToken getApiAccessToken(String apiType) throws Exception {
EsbToken returnToken = null; EsbToken returnToken = null;
int retryCnt=0; int retryCnt=0;
boolean isNeedTry=true; boolean isNeedTry=true;
String lastErrorMsg =""; String lastErrorMsg ="";
EsbToken cachedToken = cachedTokens.get(apiType);
if (!isTokenExpire(cachedToken)) { if (!isTokenExpire(cachedToken)) {
return cachedToken; return cachedToken;
}else{ }else{
while(returnToken==null && isNeedTry && retryCnt<3){ while(returnToken==null && isNeedTry && retryCnt<3){
HttpResult requestResult = this.invokeTokenRequest(); HttpResult requestResult = this.invokeTokenRequest(apiType);
if(requestResult.getStatusCode()>=200 && requestResult.getStatusCode()<300){ if(requestResult.getStatusCode()>=200 && requestResult.getStatusCode()<300){
try{ try{
EsbToken newToken = JSON.parseObject(requestResult.getResponseBody(), EsbToken.class); EsbToken newToken = JSON.parseObject(requestResult.getResponseBody(), EsbToken.class);
@@ -59,6 +67,7 @@ public class EsbTokenService {
expiryTime = LocalDateTime.now().plusSeconds(esbApiSetting.getTokenExpireSecond()); expiryTime = LocalDateTime.now().plusSeconds(esbApiSetting.getTokenExpireSecond());
newToken.setExpireTime(expiryTime); newToken.setExpireTime(expiryTime);
} }
cachedTokens.put(apiType, newToken);
returnToken = newToken; returnToken = newToken;
} }
}catch(Exception err){ }catch(Exception err){
@@ -98,10 +107,15 @@ public class EsbTokenService {
return headers; return headers;
} }
private byte[] buildTokenRequestBody() { private byte[] buildTokenRequestBody(String apiType) {
JSONObject requestObj = new JSONObject(); JSONObject requestObj = new JSONObject();
requestObj.put("AppId", esbApiSetting.getAppId()); if("ESB_LIMO".equalsIgnoreCase(apiType)){
requestObj.put("AppSecret", esbApiSetting.getAppSecret()); requestObj.put("AppId", esbApiSetting.getAppIdLimo());
requestObj.put("AppSecret", esbApiSetting.getAppSecretLimo());
}else{
requestObj.put("AppId", esbApiSetting.getAppIdMcrm());
requestObj.put("AppSecret", esbApiSetting.getAppSecretMcrm());
}
return requestObj.toJSONString().getBytes(StandardCharsets.UTF_8); return requestObj.toJSONString().getBytes(StandardCharsets.UTF_8);
} }
/** /**
@@ -113,11 +127,12 @@ public class EsbTokenService {
/** /**
* 发送 token 请求(单次),返回详细结果包括状态码 * 发送 token 请求(单次),返回详细结果包括状态码
*/ */
private HttpResult invokeTokenRequest() { private HttpResult invokeTokenRequest(String apiType) {
HttpResult result = new HttpResult(); HttpResult result = new HttpResult();
String tokenUrl =esbApiSetting.getServerUrl() + esbApiSetting.getTokenUrl(); String apiPath = "ESB_LIMO".equalsIgnoreCase(apiType) ? limoApiPath : mcrmApiPath;
String tokenUrl = esbApiSetting.getServerUrl() + apiPath + esbApiSetting.getTokenUrl();
try { try {
byte[] requestBody = buildTokenRequestBody(); byte[] requestBody = buildTokenRequestBody(apiType);
HttpHeaders headers = buildHeaders(); HttpHeaders headers = buildHeaders();
// 构建完整的 URL // 构建完整的 URL
ResponseEntity<byte[]> requestRes = webProxyService.invokeRequest( ResponseEntity<byte[]> requestRes = webProxyService.invokeRequest(
@@ -32,7 +32,7 @@ public class MGMApiService {
public HttpResult invokeGetAllPlayerProfile(String playerId) throws Exception { public HttpResult invokeGetAllPlayerProfile(String playerId) throws Exception {
HttpResult result = new HttpResult(); HttpResult result = new HttpResult();
String apiLink = esbApiSetting.getServerUrl() + API_GET_ALL_PLAYER_PROFILE; String apiLink = esbApiSetting.getServerUrl() + API_GET_ALL_PLAYER_PROFILE;
EsbToken esbToken = esbTokenService.getApiAccessToken(); EsbToken esbToken = esbTokenService.getApiAccessToken("ESB_MCRM");
if(esbToken==null || StringUtils.isBlank(esbToken.getAccessToken())){ if(esbToken==null || StringUtils.isBlank(esbToken.getAccessToken())){
throw new Exception("Invoke ESB token failed"); throw new Exception("Invoke ESB token failed");
} }
@@ -74,7 +74,7 @@ public class MGMApiService {
public HttpResult invokeGetUserInfo(String userId,String userName) throws Exception { public HttpResult invokeGetUserInfo(String userId,String userName) throws Exception {
HttpResult result = new HttpResult();; HttpResult result = new HttpResult();;
String apiLink = esbApiSetting.getServerUrl() + API_GET_USER_INFO; String apiLink = esbApiSetting.getServerUrl() + API_GET_USER_INFO;
EsbToken esbToken = esbTokenService.getApiAccessToken(); EsbToken esbToken = esbTokenService.getApiAccessToken("ESB_MCRM");
if(esbToken==null || StringUtils.isBlank(esbToken.getAccessToken())){ if(esbToken==null || StringUtils.isBlank(esbToken.getAccessToken())){
throw new Exception("Invoke ESB token failed"); throw new Exception("Invoke ESB token failed");
} }
@@ -63,7 +63,7 @@ public class MgmUserService {
if("OK".equals(resultCode)) { if("OK".equals(resultCode)) {
List<UserInfoApiRecord> recrods = resultObj.getRecords(); List<UserInfoApiRecord> recrods = resultObj.getRecords();
if(!recrods.isEmpty()) { if(!recrods.isEmpty()) {
UserInfoApiRecord user = recrods.get(0); UserInfoApiRecord user = recrods.getFirst();
if(!"NULL".equals(user.getUserId())) { if(!"NULL".equals(user.getUserId())) {
user = this.supplementInfoId(userId,user); user = this.supplementInfoId(userId,user);
user.setStatusCode(resultObj.getStatusCode()); user.setStatusCode(resultObj.getStatusCode());
@@ -47,7 +47,7 @@ public class ApiGatewayLoggingFilter extends OncePerRequestFilter {
) )
throws IOException, ServletException { throws IOException, ServletException {
Throwable handleException = null; Throwable handleException = null;
ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request); ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request,1024 * 1024);
ContentCachingResponseWrapper wrappedResponse = new ContentCachingResponseWrapper(response); ContentCachingResponseWrapper wrappedResponse = new ContentCachingResponseWrapper(response);
LocalDateTime startTime = LocalDateTime.now(); LocalDateTime startTime = LocalDateTime.now();
try { try {
@@ -35,7 +35,7 @@ public class WebhookLoggingFilter extends OncePerRequestFilter {
) )
throws IOException, ServletException { throws IOException, ServletException {
Throwable handleException = null; Throwable handleException = null;
ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request); ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request,1024 * 1024);
ContentCachingResponseWrapper wrappedResponse = new ContentCachingResponseWrapper(response); ContentCachingResponseWrapper wrappedResponse = new ContentCachingResponseWrapper(response);
LocalDateTime startTime = LocalDateTime.now(); LocalDateTime startTime = LocalDateTime.now();
try { try {
@@ -31,10 +31,6 @@ public class NotificationController {
@RequestBody(required = true) SendEmailRequest requestData, @RequestBody(required = true) SendEmailRequest requestData,
HttpServletRequest request HttpServletRequest request
){ ){
String appId = request.getHeader("application-id");
String securityKey = request.getHeader("authorization");
BaseApiResponse<Void> result = emailNotificationService.sendEmailByRequest(requestData,emailProxySetting); BaseApiResponse<Void> result = emailNotificationService.sendEmailByRequest(requestData,emailProxySetting);
return ResponseEntity.status(HttpStatus.OK).body(result); return ResponseEntity.status(HttpStatus.OK).body(result);
} }
@@ -1,12 +1,14 @@
package com.mgm.mcrm.apigateway.proxy.config; package com.mgm.mcrm.apigateway.proxy.config;
import com.mgm.mcrm.apigateway.common.constants.SysCommon;
import com.mgm.mcrm.apigateway.common.dtos.config.DaylightApiSetting; import com.mgm.mcrm.apigateway.common.dtos.config.DaylightApiSetting;
import com.mgm.mcrm.apigateway.common.dtos.config.EsbApiSetting; import com.mgm.mcrm.apigateway.common.dtos.config.EsbApiSetting;
import com.mgm.mcrm.apigateway.common.dtos.config.LimoApiSetting;
import com.mgm.mcrm.apigateway.common.dtos.config.OperaApiSetting; import com.mgm.mcrm.apigateway.common.dtos.config.OperaApiSetting;
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;
@@ -52,6 +54,8 @@ public class WebClientConfig {
@Autowired @Autowired
private OperaApiSetting operaApiSetting; private OperaApiSetting operaApiSetting;
@Autowired @Autowired
private LimoApiSetting limoApiSetting;
@Autowired
private SslBundles sslBundles; private SslBundles sslBundles;
private final Logger logger = LoggerFactory.getLogger(WebClientConfig.class); private final Logger logger = LoggerFactory.getLogger(WebClientConfig.class);
@@ -136,6 +140,45 @@ public class WebClientConfig {
.build(); .build();
} }
@Bean
public WebClient limoWebClient() {
ConnectionProvider provider = ConnectionProvider.builder("proxy-pool")
.maxConnections(maxConnectionPool)
.pendingAcquireTimeout(Duration.ofSeconds(60))
.maxIdleTime(Duration.ofSeconds(30))
.build();
HttpClient httpClient = HttpClient.create(provider)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeout*1000)
.responseTimeout(Duration.ofSeconds(readTimeout))
.secure(spec -> {
try {
spec.sslContext(this.createLimoSslContent());
} catch (Exception e) {
throw new RuntimeException(e);
}
})
.doOnConnected(conn -> {
logger.info("LIMO Connected using proxy: {}", conn.channel().remoteAddress());
conn.addHandlerLast(new ReadTimeoutHandler(readTimeout, TimeUnit.SECONDS))
.addHandlerLast(new WriteTimeoutHandler(readTimeout, TimeUnit.SECONDS));
})
.doOnRequest((request, connection) ->
logger.info("LIMO Request via proxy: {}", request)
);
if(StringUtils.isNotBlank(limoApiSetting.getProxyHost())){
httpClient = httpClient.proxy(this::initLimoProxy);
}
return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.codecs(configurer -> {
configurer.defaultCodecs().maxInMemorySize(maxMemoryCacheM * 1024 * 1024);
})
.filter(retryFilter())
.build();
}
@Bean @Bean
public WebClient operaWebClient() { public WebClient operaWebClient() {
ConnectionProvider provider = ConnectionProvider.builder("proxy-pool") ConnectionProvider provider = ConnectionProvider.builder("proxy-pool")
@@ -190,10 +233,10 @@ public class WebClientConfig {
} }
//-- Daylight init //-- Daylight init
private SslContext createDaylightSslContent() throws SSLException { private SslContext createDaylightSslContent() throws SSLException {
if(StringUtils.isBlank(daylightApiSetting.getSslBundleName())){ if(StringUtils.isNotBlank(daylightApiSetting.getSslBundleName())){
return this.createNoVerifySslContext();
}else{
return this.createSslContextByConfig(daylightApiSetting.getSslBundleName()); return this.createSslContextByConfig(daylightApiSetting.getSslBundleName());
}else{
return this.createDefaultSslContext(new ConfigurableTrustHandler(daylightApiSetting.isSkipTrustValidation(), SysCommon.getDefaultTrustManager()));
} }
} }
@@ -208,10 +251,10 @@ public class WebClientConfig {
} }
//-- Opera init //-- Opera init
private SslContext createOperaSslContent() throws SSLException { private SslContext createOperaSslContent() throws SSLException {
if(StringUtils.isBlank(operaApiSetting.getSslBundleName())){ if(StringUtils.isNotBlank(operaApiSetting.getSslBundleName())){
return this.createNoVerifySslContext();
}else{
return this.createSslContextByConfig(operaApiSetting.getSslBundleName()); return this.createSslContextByConfig(operaApiSetting.getSslBundleName());
}else{
return this.createDefaultSslContext(new ConfigurableTrustHandler(operaApiSetting.isSkipTrustValidation(), SysCommon.getDefaultTrustManager()));
} }
} }
@@ -226,10 +269,10 @@ public class WebClientConfig {
} }
//-- Esb init //-- Esb init
private SslContext createEsbSslContent() throws SSLException { private SslContext createEsbSslContent() throws SSLException {
if(StringUtils.isBlank(esbApiSetting.getSslBundleName())){ if(StringUtils.isNotBlank(esbApiSetting.getSslBundleName())){
return this.createNoVerifySslContext();
}else{
return this.createSslContextByConfig(esbApiSetting.getSslBundleName()); return this.createSslContextByConfig(esbApiSetting.getSslBundleName());
}else{
return this.createDefaultSslContext(new ConfigurableTrustHandler(esbApiSetting.isSkipTrustValidation(),SysCommon.getDefaultTrustManager()));
} }
} }
@@ -243,6 +286,27 @@ public class WebClientConfig {
); );
} }
//-- Limo init
private SslContext createLimoSslContent() throws SSLException {
if(StringUtils.isNotBlank(limoApiSetting.getSslBundleName())){
return this.createSslContextByConfig(limoApiSetting.getSslBundleName());
}else{
return this.createDefaultSslContext(new ConfigurableTrustHandler(limoApiSetting.isSkipTrustValidation(),SysCommon.getDefaultTrustManager()));
}
}
private void initLimoProxy(ProxyProvider.TypeSpec proxy){
this.setProxySettingByConfig(
proxy,
limoApiSetting.getProxyHost(),
limoApiSetting.getProxyPort(),
limoApiSetting.getProxyUserName(),
limoApiSetting.getProxyPassword()
);
}
//---------- //----------
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)) {
@@ -258,9 +322,8 @@ public class WebClientConfig {
} }
} }
private SslContext createNoVerifySslContext() throws SSLException { private SslContext createDefaultSslContext(ConfigurableTrustHandler trustHandler) throws SSLException {
return SslContextBuilder.forClient() return SslContextBuilder.forClient().trustManager(trustHandler).build();
.trustManager(InsecureTrustManagerFactory.INSTANCE).build();
} }
private SslContext createSslContextByConfig(String sslBundleName) throws SSLException { private SslContext createSslContextByConfig(String sslBundleName) throws SSLException {
@@ -1,36 +1,23 @@
package com.mgm.mcrm.apigateway.proxy.controllers; package com.mgm.mcrm.apigateway.proxy.controllers;
import com.mgm.mcrm.apigateway.common.constants.SysCommon;
import com.mgm.mcrm.apigateway.common.dtos.BaseApiResponse; import com.mgm.mcrm.apigateway.common.dtos.BaseApiResponse;
import com.mgm.mcrm.apigateway.common.dtos.LoginUserInfo; import com.mgm.mcrm.apigateway.common.dtos.config.EmailProxySetting;
import com.mgm.mcrm.apigateway.common.dtos.config.DaylightApiSetting;
import com.mgm.mcrm.apigateway.common.dtos.config.EsbApiSetting;
import com.mgm.mcrm.apigateway.common.dtos.config.OperaApiSetting;
import com.mgm.mcrm.apigateway.daylight.common.services.DaylightTokenService;
import com.mgm.mcrm.apigateway.esb.common.services.EsbTokenService;
import com.mgm.mcrm.apigateway.proxy.dtos.request.SendNotificationRequest; import com.mgm.mcrm.apigateway.proxy.dtos.request.SendNotificationRequest;
import com.mgm.mcrm.apigateway.proxy.exception.HttpProxyErrorHandler;
import com.mgm.mcrm.apigateway.proxy.exception.SoapProxyErrorHandler;
import com.mgm.mcrm.apigateway.proxy.services.NotificationProxyService; import com.mgm.mcrm.apigateway.proxy.services.NotificationProxyService;
import com.mgm.mcrm.apigateway.proxy.services.WebProxyService;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; 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.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
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;
import java.io.IOException;
import java.time.Duration;
import java.util.Collections;
@Tag(name = "Notification Proxy", description = "Controller for Notification proxy") @Tag(name = "Notification Proxy", description = "Controller for Notification proxy")
@RestController @RestController
public class NotificationProxyController { public class NotificationProxyController {
@@ -39,32 +26,29 @@ public class NotificationProxyController {
@Resource @Resource
private NotificationProxyService notificationProxyService; private NotificationProxyService notificationProxyService;
@RequestMapping("/api/notification/proxy/**") @Autowired
private EmailProxySetting emailProxySetting;
@RequestMapping(value="/api/notification/proxy/**",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 {
LoginUserInfo requestUser = SysCommon.parseUserFromToken(request.getHeader("Authorization")); //--Check authorization
return ResponseEntity.status(HttpStatus.OK).body(notificationProxyService.sendNotificationByRequest(notificationRequest,requestUser.getLoginId())); String appId = request.getHeader("application-id");
} String securityKey = request.getHeader("authorization");
if(!isAuthorizated(appId, securityKey)){
private HttpHeaders extractHeaders(HttpServletRequest request) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(null);
HttpHeaders headers = new HttpHeaders();
Collections.list(request.getHeaderNames()).forEach(name -> {
if (!name.equalsIgnoreCase("host") &&
!name.equalsIgnoreCase("content-length") &&
!name.equalsIgnoreCase("application-id") &&
!name.equalsIgnoreCase("authorization")
) {
headers.add(name, request.getHeader(name));
}
});
return headers;
}
private byte[] getRequestBody(HttpServletRequest request) {
try {
return request.getInputStream().readAllBytes();
} catch (IOException e) {
logger.error("Failed to read request body of request[{}]",request.getRequestURI(), e);
return new byte[0];
} }
return ResponseEntity.status(HttpStatus.OK).body(notificationProxyService.sendNotificationByRequest(notificationRequest,notificationRequest.getRequestorId()));
} }
private boolean isAuthorizated(String appId, String securityKey) {
boolean isAuth=false;
if(StringUtils.isNotBlank(appId) && StringUtils.isNotBlank(securityKey)){
String authCode = emailProxySetting.getAppAuthorizatinKey(appId);
if(StringUtils.isNotBlank(authCode) && securityKey.equals(authCode)){
isAuth=true;
}
}
return isAuth;
}
} }
@@ -3,7 +3,9 @@ package com.mgm.mcrm.apigateway.proxy.controllers;
import com.mgm.mcrm.apigateway.appsetting.services.SysSettingService; import com.mgm.mcrm.apigateway.appsetting.services.SysSettingService;
import com.mgm.mcrm.apigateway.common.dtos.config.DaylightApiSetting; import com.mgm.mcrm.apigateway.common.dtos.config.DaylightApiSetting;
import com.mgm.mcrm.apigateway.common.dtos.config.EsbApiSetting; import com.mgm.mcrm.apigateway.common.dtos.config.EsbApiSetting;
import com.mgm.mcrm.apigateway.common.dtos.config.LimoApiSetting;
import com.mgm.mcrm.apigateway.common.dtos.config.OperaApiSetting; import com.mgm.mcrm.apigateway.common.dtos.config.OperaApiSetting;
import com.mgm.mcrm.apigateway.common.utils.NetworkUtil;
import com.mgm.mcrm.apigateway.daylight.common.services.DaylightTokenService; import com.mgm.mcrm.apigateway.daylight.common.services.DaylightTokenService;
import com.mgm.mcrm.apigateway.daylight.common.dtos.TokenResponse; import com.mgm.mcrm.apigateway.daylight.common.dtos.TokenResponse;
import com.mgm.mcrm.apigateway.esb.common.dtos.EsbToken; import com.mgm.mcrm.apigateway.esb.common.dtos.EsbToken;
@@ -16,11 +18,14 @@ import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Strings;
import org.slf4j.Logger; 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.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@@ -50,6 +55,12 @@ public class WebProxyController {
private DaylightApiSetting daylightApiSetting; private DaylightApiSetting daylightApiSetting;
@Autowired @Autowired
private EsbApiSetting esbApiSetting; private EsbApiSetting esbApiSetting;
@Value("${mcrm.proxy.api-config.esb.api-path.mcrm}")
private String mcrmApiPath;
@Value("${mcrm.proxy.api-config.esb.api-path.limo}")
private String limoApiPath;
@Autowired
private LimoApiSetting limoApiSetting;
@Autowired @Autowired
private OperaApiSetting operaApiSetting; private OperaApiSetting operaApiSetting;
@@ -59,10 +70,21 @@ public class WebProxyController {
private volatile boolean cachedIsMock = true; private volatile boolean cachedIsMock = true;
private volatile long lastMockCheckTime = 0; private volatile long lastMockCheckTime = 0;
private static final long MOCK_CHECK_INTERVAL_MS = 30000; private static final long MOCK_CHECK_INTERVAL_MS = 30000;
private static final String DAYLIGHT_PROXY_TYPE="DAYLIGHT";
private static final String ESB_PROXY_TYPE="ESB";
private static final String LIMO_PROXY_TYPE="LIMO";
@RequestMapping("/api/daylight/proxy/**") @RequestMapping("/api/daylight/proxy/**")
public ResponseEntity<byte[]> invokeDaylightApiProxy(HttpServletRequest request,HttpServletResponse response) throws Exception { public ResponseEntity<byte[]> invokeDaylightApiProxy(HttpServletRequest request,HttpServletResponse response) throws Exception {
//--Check authorization
String appId = request.getHeader("application-id");
String securityKey = request.getHeader("authorization");
if(!isAuthorizated(DAYLIGHT_PROXY_TYPE, appId, securityKey)){
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(null);
}
String apiUrl = daylightApiSetting.getServerUrl() + request.getRequestURI().replace("/api/daylight/proxy", ""); String apiUrl = daylightApiSetting.getServerUrl() + request.getRequestURI().replace("/api/daylight/proxy", "");
apiUrl = NetworkUtil.validateAndSanitizeUrl(apiUrl);
HttpHeaders headers = this.extractHeaders(request); HttpHeaders headers = this.extractHeaders(request);
TokenResponse daylightApiToken = daylightTokenService.getApiAccessToken(); TokenResponse daylightApiToken = daylightTokenService.getApiAccessToken();
if(daylightApiToken==null || StringUtils.isBlank(daylightApiToken.getAccessToken())){ if(daylightApiToken==null || StringUtils.isBlank(daylightApiToken.getAccessToken())){
@@ -74,7 +96,7 @@ public class WebProxyController {
WebProxyService.DAYLIGHT_API, WebProxyService.DAYLIGHT_API,
HttpMethod.valueOf(request.getMethod()), HttpMethod.valueOf(request.getMethod()),
apiUrl, apiUrl,
request.getQueryString(), NetworkUtil.sanitizeCRLF(request.getQueryString()),
headers, headers,
getRequestBody(request), getRequestBody(request),
Duration.ofSeconds(daylightApiSetting.getApiTimeout()), Duration.ofSeconds(daylightApiSetting.getApiTimeout()),
@@ -83,15 +105,40 @@ public class WebProxyController {
} }
@RequestMapping("/api/esb/proxy/**") @RequestMapping("/api/esb/proxy/**")
public ResponseEntity<byte[]> invokeEsbApiProxy(HttpServletRequest request) throws Exception { public ResponseEntity<byte[]> invokeEsbApiProxy(HttpServletRequest request) throws Exception {
return this.processEsbRequest(request, "ESB_MCRM");
}
@RequestMapping("/api/esb_limo/proxy/**")
public ResponseEntity<byte[]> invokeEsbLimoApiProxy(HttpServletRequest request) throws Exception {
return this.processEsbRequest(request, "ESB_LIMO");
}
private ResponseEntity<byte[]> processEsbRequest(HttpServletRequest request, String apiType) throws Exception {
//--Check authorization
String appId = request.getHeader("application-id");
String securityKey = request.getHeader("authorization");
if(!isAuthorizated(ESB_PROXY_TYPE, appId, securityKey)){
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(null);
}
HttpMethod method = HttpMethod.valueOf(request.getMethod()); HttpMethod method = HttpMethod.valueOf(request.getMethod());
String apiUrl = esbApiSetting.getServerUrl() + request.getRequestURI().replace("/api/esb/proxy", ""); boolean isLimo = "ESB_LIMO".equalsIgnoreCase(apiType);
String queryString = request.getQueryString(); String apiPath = isLimo ? limoApiPath : mcrmApiPath;
String proxyPath = isLimo ? "/api/esb_limo/proxy" : "/api/esb/proxy";
String requestPath = Strings.CI.removeStart(request.getRequestURI(), proxyPath);
if (isLimo) {
requestPath = Strings.CI.removeStart(requestPath, "/api/esb_limo/v1.0");
}
requestPath = Strings.CI.removeStart(requestPath, apiPath);
String apiUrl = esbApiSetting.getServerUrl() + apiPath + requestPath;
apiUrl = NetworkUtil.validateAndSanitizeUrl(apiUrl);
String queryString = NetworkUtil.sanitizeCRLF(request.getQueryString());
HttpHeaders headers = this.extractHeaders(request); HttpHeaders headers = this.extractHeaders(request);
byte[] requestBody = getRequestBody(request); byte[] requestBody = getRequestBody(request);
EsbToken esbToken = esbTokenService.getApiAccessToken(); EsbToken esbToken = esbTokenService.getApiAccessToken(apiType);
if(esbToken==null || StringUtils.isBlank(esbToken.getAccessToken())){ if(esbToken==null || StringUtils.isBlank(esbToken.getAccessToken())){
logger.error("invokeEsbApiProxy failed, ESB token is null or blank, uri={}", request.getRequestURI()); logger.error("invoke {} Proxy failed, ESB token is null or blank, uri={}", apiType, request.getRequestURI());
throw new Exception("Invoke ESB token failed"); throw new Exception("Invoke ESB token failed");
} }
headers.set("authorization", esbToken.getAccessToken()); headers.set("authorization", esbToken.getAccessToken());
@@ -107,11 +154,11 @@ public class WebProxyController {
httpErrorHandler httpErrorHandler
).block(); ).block();
if (response == null) { if (response == null) {
logger.error("invokeEsbApiProxy received a null response: method={}, apiUrl={}, query={}", logger.error("invoke Esb ApiProxy received a null response: method={}, apiUrl={}, query={}",
method, apiUrl, queryString); method, apiUrl, queryString);
} else if (response.getStatusCode().isError()) { } else if (response.getStatusCode().isError()) {
byte[] responseBody = response.getBody(); byte[] responseBody = response.getBody();
logger.warn("invokeEsbApiProxy error response: method={}, apiUrl={}, query={}, status={}, headers={}, bodyLength={}, bodyPreview={}", logger.warn("invoke Esb Api Proxy error response: method={}, apiUrl={}, query={}, status={}, headers={}, bodyLength={}, bodyPreview={}",
method, method,
apiUrl, apiUrl,
queryString, queryString,
@@ -121,7 +168,54 @@ public class WebProxyController {
responseBody == null ? 0 : responseBody.length, responseBody == null ? 0 : responseBody.length,
bodyPreview(responseBody)); bodyPreview(responseBody));
} else { } else {
logger.info("invokeEsbApiProxy completed: method={}, apiUrl={}, query={}, status={}", logger.info("invoke Esb Api Proxy completed: method={}, apiUrl={}, query={}, status={}",
method, apiUrl, queryString, response.getStatusCode());
}
return response;
}
@RequestMapping("/api/limo/proxy/**")
public ResponseEntity<byte[]> invokeLimoApiProxy(HttpServletRequest request) throws Exception {
//--Check authorization
String appId = request.getHeader("application-id");
String securityKey = request.getHeader("authorization");
if(!isAuthorizated(LIMO_PROXY_TYPE, appId, securityKey)){
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(null);
}
HttpMethod method = HttpMethod.valueOf(request.getMethod());
String apiUrl = limoApiSetting.getServerUrl() + request.getRequestURI().replace("/api/limo/proxy", "");
apiUrl = NetworkUtil.validateAndSanitizeUrl(apiUrl);
String queryString = NetworkUtil.sanitizeCRLF(request.getQueryString());
HttpHeaders headers = this.extractHeaders(request);
byte[] requestBody = getRequestBody(request);
ResponseEntity<byte[]> response = webProxyService.invokeRequest(
WebProxyService.LIMO_API,
method,
apiUrl,
queryString,
headers,
requestBody,
Duration.ofSeconds(limoApiSetting.getApiRequestTimeout()),
httpErrorHandler
).block();
if (response == null) {
logger.error("invoke Limo Api Proxy received a null response: method={}, apiUrl={}, query={}",
method, apiUrl, queryString);
} else if (response.getStatusCode().isError()) {
byte[] responseBody = response.getBody();
logger.warn("invoke Limo Api Proxy error response: method={}, apiUrl={}, query={}, status={}, headers={}, bodyLength={}, bodyPreview={}",
method,
apiUrl,
queryString,
response.getStatusCode(),
sanitizeHeaders(response.getHeaders()),
responseBody == null ? 0 : responseBody.length,
bodyPreview(responseBody));
} else {
logger.info("invoke Limo Api Proxy completed: method={}, apiUrl={}, query={}, status={}",
method, apiUrl, queryString, response.getStatusCode()); method, apiUrl, queryString, response.getStatusCode());
} }
return response; return response;
@@ -130,11 +224,12 @@ public class WebProxyController {
@RequestMapping("/api/opera/proxy/**") @RequestMapping("/api/opera/proxy/**")
public ResponseEntity<byte[]> invokeOperaApiProxy(HttpServletRequest request) throws Exception { public ResponseEntity<byte[]> invokeOperaApiProxy(HttpServletRequest request) throws Exception {
String apiUrl = operaApiSetting.getServerUrl() + request.getRequestURI().replace("/api/opera/proxy", ""); String apiUrl = operaApiSetting.getServerUrl() + request.getRequestURI().replace("/api/opera/proxy", "");
apiUrl = NetworkUtil.validateAndSanitizeUrl(apiUrl);
return webProxyService.invokeRequest( return webProxyService.invokeRequest(
WebProxyService.OPERA_API, WebProxyService.OPERA_API,
HttpMethod.valueOf(request.getMethod()), HttpMethod.valueOf(request.getMethod()),
apiUrl, apiUrl,
request.getQueryString(), NetworkUtil.sanitizeCRLF(request.getQueryString()),
extractHeaders(request), extractHeaders(request),
getRequestBody(request), getRequestBody(request),
Duration.ofSeconds(operaApiSetting.getTimeout()), Duration.ofSeconds(operaApiSetting.getTimeout()),
@@ -142,6 +237,24 @@ public class WebProxyController {
).block(); ).block();
} }
private boolean isAuthorizated(String proxyType, String appId, String securityKey) {
boolean isAuth=false;
if(StringUtils.isNotBlank(appId) && StringUtils.isNotBlank(securityKey)){
String authCode = null;
if(ESB_PROXY_TYPE.equalsIgnoreCase(proxyType)){
authCode = esbApiSetting.getAppAuthorizatinKey(appId);
}else if(DAYLIGHT_PROXY_TYPE.equalsIgnoreCase(proxyType)){
authCode = daylightApiSetting.getAppAuthorizatinKey(appId);
}else if(LIMO_PROXY_TYPE.equalsIgnoreCase(proxyType)){
authCode = limoApiSetting.getAppAuthorizatinKey(appId);
}
if(StringUtils.isNotBlank(authCode) && securityKey.equals(authCode)){
isAuth=true;
}
}
return isAuth;
}
private HttpHeaders extractHeaders(HttpServletRequest request) { private HttpHeaders extractHeaders(HttpServletRequest request) {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
Collections.list(request.getHeaderNames()).forEach(name -> { Collections.list(request.getHeaderNames()).forEach(name -> {
@@ -150,7 +263,7 @@ public class WebProxyController {
!name.equalsIgnoreCase("application-id") && !name.equalsIgnoreCase("application-id") &&
!name.equalsIgnoreCase("authorization") !name.equalsIgnoreCase("authorization")
) { ) {
headers.add(name, request.getHeader(name)); headers.add(NetworkUtil.sanitizeCRLF(name), NetworkUtil.sanitizeCRLF(request.getHeader(name)));
} }
}); });
return headers; return headers;
@@ -26,4 +26,6 @@ public class SendNotificationRequest {
@Schema(description = "Type of booking ") @Schema(description = "Type of booking ")
private String type; private String type;
private String requestorId;
} }
@@ -1,8 +1,7 @@
package com.mgm.mcrm.apigateway.proxy.services; package com.mgm.mcrm.apigateway.proxy.services;
import com.mgm.mcrm.apigateway.common.utils.LogUtil; 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.HttpProxyErrorHandler;
import com.mgm.mcrm.apigateway.proxy.exception.ProxyErrorHandler; import com.mgm.mcrm.apigateway.proxy.exception.ProxyErrorHandler;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -23,7 +22,6 @@ import reactor.core.publisher.Mono;
import java.net.URI; import java.net.URI;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.Duration; import java.time.Duration;
import java.util.concurrent.ForkJoinPool;
@RequiredArgsConstructor @RequiredArgsConstructor
@Service @Service
@@ -31,9 +29,11 @@ public class WebProxyService {
public final static String DAYLIGHT_API="DAYLIGHT_API"; public final static String DAYLIGHT_API="DAYLIGHT_API";
public final static String ESB_API="ESB_API"; public final static String ESB_API="ESB_API";
public final static String OPERA_API="OPERA_API"; public final static String OPERA_API="OPERA_API";
public final static String LIMO_API="LIMO_API";
private final WebClient daylightWebClient; private final WebClient daylightWebClient;
private final WebClient esbWebClient; private final WebClient esbWebClient;
private final WebClient operaWebClient; private final WebClient operaWebClient;
private final WebClient limoWebClient;
private final Logger logger = LoggerFactory.getLogger(WebProxyService.class); private final Logger logger = LoggerFactory.getLogger(WebProxyService.class);
public Mono<ResponseEntity<byte[]>> invokeRequest( public Mono<ResponseEntity<byte[]>> invokeRequest(
@@ -54,6 +54,8 @@ public class WebProxyService {
targetWebClient=esbWebClient; targetWebClient=esbWebClient;
}else if(OPERA_API.equalsIgnoreCase(apiType)){ }else if(OPERA_API.equalsIgnoreCase(apiType)){
targetWebClient=operaWebClient; targetWebClient=operaWebClient;
}else if(LIMO_API.equalsIgnoreCase(apiType)){
targetWebClient=limoWebClient;
}else{ }else{
throw new Exception("Unknown request API type of "+apiType); throw new Exception("Unknown request API type of "+apiType);
} }
@@ -139,88 +139,88 @@ public class BookingService {
} }
bookingDao.save(dbBooking); bookingDao.save(dbBooking);
CfgProperties property = propertyDao.findById(dbBooking.getPropertyId()).orElse(null); // CfgProperties property = propertyDao.findById(dbBooking.getPropertyId()).orElse(null);
//Send Notification to Booker when booking lastOpera status Changed // //Send Notification to Booker when booking lastOpera status Changed
if (Strings.CS.equals(daylightBooking.getLastOperaStatus(),"RESERVED") && !Strings.CS.equals(dbBookingStatus,daylightBooking.getLastOperaStatus())){ // if (Strings.CS.equals(daylightBooking.getLastOperaStatus(),"RESERVED") && !Strings.CS.equals(dbBookingStatus,daylightBooking.getLastOperaStatus())){
LogUtil.info(BookingService.class,"Booking last opera status changed, DB Record status:"+dbBookingStatus+", DlBooking status:"+daylightBooking.getLastOperaStatus()); // LogUtil.info(BookingService.class,"Booking last opera status changed, DB Record status:"+dbBookingStatus+", DlBooking status:"+daylightBooking.getLastOperaStatus());
//设置Notification 内容 // //设置Notification 内容
String notificationTitle = "#EN# Room status updated#EN#" + // String notificationTitle = "#EN# Room status updated#EN#" +
"#CN#房間狀態已更改#CN#"; // "#CN#房間狀態已更改#CN#";
String notificationContent = "#EN#Player {playerId}, {propertyName}, {roomCode},room status changed to reserved.#EN#" + // String notificationContent = "#EN#Player {playerId}, {propertyName}, {roomCode},room status changed to reserved.#EN#" +
"#CN#Player {playerId}, {propertyName}, {roomCode}, 房間狀態已預訂。#CN#"; // "#CN#Player {playerId}, {propertyName}, {roomCode}, 房間狀態已預訂。#CN#";
String[] placeholders = { // String[] placeholders = {
"{playerId}", "{propertyName}", "{roomCode}" // "{playerId}", "{propertyName}", "{roomCode}"
}; // };
LogUtil.info(BookingService.class,"Set notification info"); // LogUtil.info(BookingService.class,"Set notification info");
String[] values = { // String[] values = {
StringUtils.defaultString(dbBooking.getPlayerId()), // StringUtils.defaultString(dbBooking.getPlayerId()),
StringUtils.defaultString(property == null ? null : property.getName()), // StringUtils.defaultString(property == null ? null : property.getName()),
StringUtils.defaultString(dbBooking.getRoomTypeCode()) // StringUtils.defaultString(dbBooking.getRoomTypeCode())
}; // };
LogUtil.info(BookingService.class,"Replace each"); // LogUtil.info(BookingService.class,"Replace each");
notificationContent = StringUtils.replaceEach(notificationContent, placeholders, values); // notificationContent = StringUtils.replaceEach(notificationContent, placeholders, values);
String transactionId = "DLBKSC"+dbBooking.getId(); // String transactionId = "DLBKSC"+dbBooking.getId();
LogUtil.info(BookingService.class,"Get device token from DB Start"); // LogUtil.info(BookingService.class,"Get device token from DB Start");
LogUtil.info(BookingService.class,"dbBooking.getCreatedBy()=" + dbBooking.getCreatedBy()); // LogUtil.info(BookingService.class,"dbBooking.getCreatedBy()=" + dbBooking.getCreatedBy());
SysLogDeviceToken deviceToken = sysLogDeviceTokenRepository.findByUserId(StringUtils.trim(dbBooking.getCreatedBy())); // SysLogDeviceToken deviceToken = sysLogDeviceTokenRepository.findByUserId(StringUtils.trim(dbBooking.getCreatedBy()));
LogUtil.info(BookingService.class,"Get device token from DB:" + (deviceToken == null ? "null" : deviceToken.getDeviceToken())); // LogUtil.info(BookingService.class,"Get device token from DB:" + (deviceToken == null ? "null" : deviceToken.getDeviceToken()));
String deviceTokenValue =null; // String deviceTokenValue =null;
String finalTitle = null; // String finalTitle = null;
String finalContent = null; // String finalContent = null;
if(deviceToken!=null){ // if(deviceToken!=null){
deviceTokenValue = deviceToken.getDeviceToken(); // deviceTokenValue = deviceToken.getDeviceToken();
finalTitle = notificationUtil.distinguishLanguage(notificationTitle,deviceToken.getUseLanguageType()); // finalTitle = notificationUtil.distinguishLanguage(notificationTitle,deviceToken.getUseLanguageType());
notificationContent = notificationUtil.distinguishLanguage(notificationContent,deviceToken.getUseLanguageType()); // notificationContent = notificationUtil.distinguishLanguage(notificationContent,deviceToken.getUseLanguageType());
//
} // }
// NOTIFICATION //// NOTIFICATION
apnNotificationService.pushApnMessage(transactionId,deviceTokenValue,finalTitle,notificationContent,true); // apnNotificationService.pushApnMessage(transactionId,deviceTokenValue,finalTitle,notificationContent,true);
} // }
//
LogUtil.info(BookingService.class,"Daylight webhook updated, prepare send notification"); // LogUtil.info(BookingService.class,"Daylight webhook updated, prepare send notification");
log.info("dbBooking checkin={}, checkout={}", checkInDate, checkOutDate); // log.info("dbBooking checkin={}, checkout={}", checkInDate, checkOutDate);
log.info("dlBooking checkin={}, checkout={}", daylightBooking.getCheckinDate(), daylightBooking.getCheckoutDate()); // log.info("dlBooking checkin={}, checkout={}", daylightBooking.getCheckinDate(), daylightBooking.getCheckoutDate());
LogUtil.info(BookingService.class,"Db booking status=" + dbBookingStatus); // LogUtil.info(BookingService.class,"Db booking status=" + dbBookingStatus);
//Send notification to Booker when Booking C/I | C/O date changed // //Send notification to Booker when Booking C/I | C/O date changed
if ((checkInDate != null && !checkInDate.equals(daylightBooking.getCheckinDate()))|| // if ((checkInDate != null && !checkInDate.equals(daylightBooking.getCheckinDate()))||
(checkOutDate != null && !checkOutDate.equals(daylightBooking.getCheckoutDate()))) { // (checkOutDate != null && !checkOutDate.equals(daylightBooking.getCheckoutDate()))) {
LogUtil.info(BookingService.class,"Booking date changed, DB Record C/I:"+checkInDate+", DB Record C/O:"+checkOutDate+ // LogUtil.info(BookingService.class,"Booking date changed, DB Record C/I:"+checkInDate+", DB Record C/O:"+checkOutDate+
", Dl Record C/I"+daylightBooking.getCheckinDate()+", Dl Record C/O"+daylightBooking.getCheckoutDate()); // ", Dl Record C/I"+daylightBooking.getCheckinDate()+", Dl Record C/O"+daylightBooking.getCheckoutDate());
//
//
//设置Notification 内容 // //设置Notification 内容
String notificationTitle = "#EN# Room status updated#EN#" + // String notificationTitle = "#EN# Room status updated#EN#" +
"#CN#房間狀態已更改#CN#"; // "#CN#房間狀態已更改#CN#";
String notificationContent = "#EN#Player {playerId}, {propertyName}, {roomCode},Stay date changed.#EN#" + // String notificationContent = "#EN#Player {playerId}, {propertyName}, {roomCode},Stay date changed.#EN#" +
"#CN#Player {playerId}, {propertyName}, {roomCode}, 住宿日期已變更。#CN#"; // "#CN#Player {playerId}, {propertyName}, {roomCode}, 住宿日期已變更。#CN#";
String[] placeholders = { // String[] placeholders = {
"{playerId}", "{propertyName}", "{roomCode}" // "{playerId}", "{propertyName}", "{roomCode}"
}; // };
String[] values = { // String[] values = {
StringUtils.defaultString(dbBooking.getPlayerId()), // StringUtils.defaultString(dbBooking.getPlayerId()),
StringUtils.defaultString(property == null ? null : property.getName()), // StringUtils.defaultString(property == null ? null : property.getName()),
StringUtils.defaultString(dbBooking.getRoomTypeCode()) // StringUtils.defaultString(dbBooking.getRoomTypeCode())
}; // };
//
notificationContent = StringUtils.replaceEach(notificationContent, placeholders, values); // notificationContent = StringUtils.replaceEach(notificationContent, placeholders, values);
String transactionId = "DLBKDC" + dbBooking.getId(); // String transactionId = "DLBKDC" + dbBooking.getId();
//
SysLogDeviceToken deviceToken = sysLogDeviceTokenRepository.findByUserId(StringUtils.trim(dbBooking.getCreatedBy())); // SysLogDeviceToken deviceToken = sysLogDeviceTokenRepository.findByUserId(StringUtils.trim(dbBooking.getCreatedBy()));
LogUtil.info(BookingService.class,"Get device token from DB:" + (deviceToken == null ? "null" : deviceToken.getDeviceToken())); // LogUtil.info(BookingService.class,"Get device token from DB:" + (deviceToken == null ? "null" : deviceToken.getDeviceToken()));
String deviceTokenValue = null; // String deviceTokenValue = null;
String finalTitle = null; // String finalTitle = null;
String finalContent = null; // String finalContent = null;
if (deviceToken != null) { // if (deviceToken != null) {
LogUtil.info(BookingService.class,"Get device Token success"); // LogUtil.info(BookingService.class,"Get device Token success");
deviceTokenValue = deviceToken.getDeviceToken(); // deviceTokenValue = deviceToken.getDeviceToken();
finalTitle = notificationUtil.distinguishLanguage(notificationTitle, deviceToken.getUseLanguageType()); // finalTitle = notificationUtil.distinguishLanguage(notificationTitle, deviceToken.getUseLanguageType());
notificationContent = notificationUtil.distinguishLanguage(notificationContent, deviceToken.getUseLanguageType()); // notificationContent = notificationUtil.distinguishLanguage(notificationContent, deviceToken.getUseLanguageType());
} // }
// NOTIFICATION //// NOTIFICATION
apnNotificationService.pushApnMessage(transactionId, deviceTokenValue, finalTitle, notificationContent, true); // apnNotificationService.pushApnMessage(transactionId, deviceTokenValue, finalTitle, notificationContent, true);
} // }
LogUtil.info(BookingService.class,"End send notification function"); // LogUtil.info(BookingService.class,"End send notification function");
} }
public Bookings findOneByDlProfileId(String dlProfileId) { public Bookings findOneByDlProfileId(String dlProfileId) {
+30 -6
View File
@@ -64,6 +64,7 @@ mcrm:
username: username:
password: password:
ssl-bundle-name: ssl-bundle-name:
skip-trust-validation: true
server-url: https://eu1.api.uat.development.abovecloud.io server-url: https://eu1.api.uat.development.abovecloud.io
request-timeout: 30 request-timeout: 30
token: token:
@@ -85,7 +86,8 @@ mcrm:
username: username:
password: password:
ssl-bundle-name: ssl-bundle-name:
server-url: skip-trust-validation: true
server-url: https://mgpmsdevows45.dev.mgmmacao.org
request-timeout: 30 request-timeout: 30
security: security:
authorization-data: "[MCRM_APP/securItykeyOfCrmapp87895312],[MCRM_CMS/seCuritykeyOfCrmCms8wetw432]" authorization-data: "[MCRM_APP/securItykeyOfCrmapp87895312],[MCRM_CMS/seCuritykeyOfCrmCms8wetw432]"
@@ -97,16 +99,37 @@ mcrm:
username: username:
password: password:
ssl-bundle-name: ssl-bundle-name:
server-url: https://hca.mcmsapoc.com skip-trust-validation: true
server-url: https://mmesbdevapp14.dev.mgmmacao.org
request-timeout: 30 request-timeout: 30
api-path:
mcrm: /api/crmapp/v1.0
limo: /api/limo/v1.0
token: token:
token-url: /RequestAccessToken token-url: /RequestAccessToken
app-id: crmappid mcrm:
app-secret: crmsecuritykey app-id: mgmtestuser001
app-secret: MGM@!666
limo:
app-id: crmappid
app-secret: crmsecuritykey
request-timeout: 30 request-timeout: 30
default-expiry-second: 700 default-expiry-second: 700
security: security:
authorization-data: "[MCRM_APP/securItykeyOfCrmapp87895312],[MCRM_CMS/seCuritykeyOfCrmCms8wetw432]" authorization-data: "[MCRM_APP/securItykeyOfCrmapp87895312],[MCRM_CMS/seCuritykeyOfCrmCms8wetw432]"
limo:
proxy-setting:
host:
port:
auth:
username:
password:
ssl-bundle-name:
skip-trust-validation: true
server-url: http://mmlimodevapp01
request-timeout: 30
security:
authorization-data: "[MCRM_APP/securItykeyOfCrmapp87895312],[MCRM_CMS/seCuritykeyOfCrmCms8wetw432]"
notification: notification:
email-sender: email-sender:
smtp-server: smtp.qq.com smtp-server: smtp.qq.com
@@ -125,7 +148,7 @@ server:
uri-encoding: UTF-8 uri-encoding: UTF-8
logging: logging:
config: classpath:logback.xml config: classpath:log4j2-spring.xml
springdoc: springdoc:
swagger-ui: swagger-ui:
@@ -155,4 +178,5 @@ apns:
# host: api.push.apple.com # host: api.push.apple.com
daylight: daylight:
url: http://localhost:9087/api/daylight/proxy url: http://localhost:9087/api/daylight/proxy
system-id: 3a151ad3-46be-4644-b656-71d3b037b309
+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Properties>
<Property name="logPath">api_gateway_runtime/logs</Property>
<Property name="logPattern">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</Property>
</Properties>
<appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="${logPattern}"/>
</Console>
<RollingFile name="FILE-APPENDER"
fileName="${logPath}/api-gateway-active.log"
filePattern="${logPath}/api-gateway-%d{yyyy-MM-dd}-%i.log">
<PatternLayout pattern="${logPattern}" />
<Policies>
<SizeBasedTriggeringPolicy size="200 MB"/>
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
</Policies>
<DefaultRolloverStrategy max="30"/>
</RollingFile>
</appenders>
<loggers>
<root level="info">
<AppenderRef ref="Console"/>
<appender-ref ref="FILE-APPENDER"/>
</root>
<Logger name="org.springframework" level="WARN" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="FILE-APPENDER"/>
</Logger>
<Logger name="org.apache.shiro" level="WARN" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="FILE-APPENDER"/>
</Logger>
<Logger name="org.hibernate" level="WARN" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="FILE-APPENDER"/>
</Logger>
</loggers>
</Configuration>
-60
View File
@@ -1,60 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--======================================= 本地变量 ======================================== -->
<!--在没有定义${LOG_HOME}系统变量的时候,可以设置此本地变量。提交测试、上线时,要将其注释掉,使用系统变量。 -->
<!-- <property name="LOG_HOME" value="D:/data/logs" /> -->
<!-- 应用名称:和统一配置中的项目代码保持一致(小写) -->
<property name="APP_NAME" value="crm_runtime" />
<!--日志文件保留天数 -->
<property name="LOG_MAX_HISTORY" value="180" />
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径 -->
<!--应用日志文件保存路径 -->
<property name="LOG_APP_HOME" value="${APP_NAME}/logs" />
<!--=========================== 按照每天生成日志文件:默认配置=================================== -->
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%-5level] %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件:主项目日志 -->
<appender name="APP"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名 -->
<FileNamePattern>${LOG_APP_HOME}/base.%d{yyyy-MM-dd}.log
</FileNamePattern>
<!--日志文件保留天数 -->
<MaxHistory>${LOG_MAX_HISTORY}</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{500} - %msg%n</pattern>
</encoder>
</appender>
<!--=============================== 日志输出: 默认主业务日志 ====================================== -->
<logger name="org.springframework" level="WARN">
</logger>
<logger name="org.apache.shiro" level="WARN">
</logger>
<logger name="freemarker" level="WARN">
</logger>
<logger name="org.hibernate" level="WARN">
</logger>
<!--
<logger name="org.hibernate.SQL">
<level value="DEBUG" />
</logger>
-->
<root level="INFO">
<appender-ref ref="APP" />
<appender-ref ref="STDOUT" />
</root>
</configuration>